Zend Validate Email Address and Deep MX Checking

流过昼夜 提交于 2019-12-22 00:32:58

问题


I have started using Zend_Validate_EmailAddress with the mx and deep options set to true. I think I am getting some false negatives when it comes to MX records that have IP addresses in the reserved IP ranges.

A good example is the MX records for harn.ufl.edu. It appear that it's failing because of IP addresses in the 128.0.0.0/16 range. It does however have one record that uses 8.6.245.30, which is not in the reserved range.

Another example is the MX record for martinhealth.org. It's MX record domain uses 198.136.38.2.

Is this a case of something that's technically incorrect but actually works?


回答1:


As the comments on my post allude, there is a bug in Zend_Validate_EmailAddress::_isReserved. Not only is it buggy, but it's difficult to understand the logic flow. It was a private function, so I changed it to protected so I could override it in my sub-class. There were also some incorrect ranges in the $_invalidIp array.

For my logic check, I decided that the simplest (clearest?) way to compare IP addresses was to convert them to their decimal integer equivalents.

Here's my sub-class:

class My_Validate_EmailAddressDeep extends Zend_Validate_EmailAddress
{
    /**
     * @var array
     */
    protected $_messageTemplates = array(
        self::INVALID            => "Invalid type given. String expected",
        self::INVALID_FORMAT     => "'%value%' is not a valid email address in the basic [user]@[hostname] format",
        self::INVALID_HOSTNAME   => "The '%hostname%' part of '%value%' is not a valid hostname",
        self::INVALID_MX_RECORD  => "'%hostname%' does not appear to be configured to accept email",
        self::INVALID_SEGMENT    => "'%hostname%' does not appear to be configured to accept external email",
        self::DOT_ATOM           => null,
        self::QUOTED_STRING      => null,
        self::INVALID_LOCAL_PART => "The '%localPart%' part of '%value%' is not valid",
        self::LENGTH_EXCEEDED    => "'%value%' is longer than the allowed length for an email address",
    );

    /**
     * Internal options array
     * @var array
     */
    protected $_options = array(
        'allow' => Zend_Validate_Hostname::ALLOW_DNS,
        'deep' => true,
        'domain' => true,
        'hostname' => null,
        'mx' => true,
    );

    /**
     * @see http://en.wikipedia.org/wiki/Reserved_IP_addresses#Reserved_IPv4_addresses
     * @var array [first octet] => [[CIDR] => [[range start], [range end]]]
     */
    protected $_reservedIps = array(
        '0' => array('0.0.0.0/8' => array('0.0.0.0', '0.255.255.255',),),
        '10' => array('10.0.0.0/8' => array('10.0.0.0', '10.255.255.255',),),
        '127' => array('127.0.0.0/8' => array('127.0.0.0', '127.255.255.255',),),
        '169' => array('169.254.0.0/16' => array('169.254.0.0', '169.254.255.255',),),
        '172' => array('172.16.0.0/12' => array('172.16.0.0', '172.31.255.255',),),
        '192' => array(
            '192.0.2.0/24' => array('192.0.2.0', '192.0.2.255',),
            '192.88.99.0/24' => array('192.88.99.0', '192.88.99.255',),
            '192.168.0.0/16' => array('192.168.0.0', '192.168.255.255',),
        ),
        '198' => array(
            '198.18.0.0/15' => array('198.18.0.0', '198.19.255.255',),
            '198.51.100.0/24' => array('198.51.100.0', '198.51.100.255',),
        ),
        '203' => array('203.0.113.0/24' => array('203.0.113.0', '203.0.113.255',),),
        '224' => array('224.0.0.0/4' => array('224.0.0.0', '239.255.255.255',),),
        '240' => array('240.0.0.0/4' => array('240.0.0.0', '255.255.255.255',),),
    );

    /**
     * Returns if the given host is reserved
     *
     * @param string $host
     * @return boolean
     */
    protected function _isReserved($host)
    {
        if (!preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $host)) {
            $host = gethostbyname($host);
        }

        $octets = explode('.', $host);
        if (224 <= (int) $octets[0]) {
            // IP Addresses beginning with 224 or greater are all reserved, short-circuit range checks
            return true;
        } elseif (array_key_exists($octets[0], $this->_reservedIps)) {
            // for integer comparisons
            $intIp = $this->_ipToInt($host);

            // loop over reserved IP addresses
            foreach ($this->_reservedIps as $ranges) {
                foreach ($ranges as $range) {
                    if (($this->_ipToInt($range[0]) <= $intIp)
                            && ($this->_ipToInt($range[1]) >= $intIp)) {
                        // the IP address falls in a reserved range
                        return true;
                    }
                }
            }

            // the IP address did not fall in a reserved range
            return false;
        } else {
            return false;
        }
    }

    /**
     * Convert a dot-decimal IP address to it's decimal integer equivalent
     *
     * @param string $ip
     * @return integer
     */
    protected function _ipToInt($ip)
    {
        $octets = explode('.', $ip);
        foreach ($octets as $key => $octet) {
            $octets[$key] = str_pad(decbin($octet), 8, '0', STR_PAD_LEFT);
        }
        $bin = implode('', $octets);
        return bindec($bin);
    }
}


来源:https://stackoverflow.com/questions/9824449/zend-validate-email-address-and-deep-mx-checking

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!