Ejemplo n.º 1
0
    def _evaluate_mechanism(self, ip, domain, sender, mechanism, rvalue):
        if rvalue is None:
            rvalue = domain
        else:
            rvalue = self.expand_macros(rvalue, ip, domain, sender)

        if mechanism == 'a':
            if self._hostname_matches_ip(ip, rvalue):
                return True
        elif mechanism == 'all':
            return True
        elif mechanism == 'exists':
            if len(self._dns_query(rvalue, 'A')):
                return True
        elif mechanism == 'include':
            # pass results in match per https://tools.ietf.org/html/rfc7208#section-5.2
            return self._check_host(ip, rvalue, sender,
                                    top_level=False) == SPFResult.PASS
        elif mechanism == 'ip4':
            try:
                if its.py_v2 and isinstance(rvalue, str):
                    rvalue = rvalue.decode('utf-8')
                ip_network = ipaddress.IPv4Network(rvalue, strict=False)
            except ipaddress.AddressValueError:
                raise SPFParseError('invalid IPv4 network: ' + rvalue)
            if ip in ip_network:
                return True
        elif mechanism == 'ip6':
            try:
                if its.py_v2 and isinstance(rvalue, str):
                    rvalue = rvalue.decode('utf-8')
                ip_network = ipaddress.IPv6Network(rvalue, strict=False)
            except ipaddress.AddressValueError:
                raise SPFParseError('invalid IPv6 network: ' + rvalue)
            if ip in ip_network:
                return True
        elif mechanism == 'mx':
            for mx_record in self._dns_query(rvalue, 'MX'):
                mx_record = str(mx_record.exchange).rstrip('.')
                if self._hostname_matches_ip(ip, mx_record):
                    return True
        elif mechanism == 'ptr':
            if isinstance(ip, ipaddress.IPv4Address):
                ip = str(ip)
                suffix = 'in-addr'
            else:
                ip = '.'.join(ip.exploded.replace(':', ''))
                suffix = 'ip6'
            ptr_domain = (rvalue or domain)
            ip = ip.split('.')
            ip.reverse()
            ip = '.'.join(ip)
            for ptr_record in self._dns_query(ip + '.' + suffix + '.arpa',
                                              'PTR'):
                ptr_record = str(ptr_record.target).rstrip('.')
                if ptr_domain == ptr_record or ptr_domain.endswith('.' +
                                                                   ptr_record):
                    return True
        else:
            raise SPFPermError(
                "unsupported mechanism type: '{0}'".format(mechanism))
        return False
Ejemplo n.º 2
0
	def _evaluate_mechanism(self, ip, domain, sender, mechanism, rvalue):
		if rvalue is None:
			rvalue = domain
		else:
			rvalue = self.expand_macros(rvalue, ip, domain, sender)

		if mechanism == 'a':
			if self._hostname_matches_ip(ip, rvalue):
				return True
		elif mechanism == 'all':
			return True
		elif mechanism == 'exists':
			answers, _ = self._dns_query(rvalue, 'A')
			if len(answers):
				return True
		elif mechanism == 'include':
			# pass results in match per https://tools.ietf.org/html/rfc7208#section-5.2
			return self._check_host(ip, rvalue, sender, top_level=False) == SPFResult.PASS
		elif mechanism == 'ip4':
			try:
				if its.py_v2 and isinstance(rvalue, str):
					rvalue = rvalue.decode('utf-8')
				ip_network = ipaddress.IPv4Network(rvalue, strict=False)
			except ipaddress.AddressValueError:
				raise SPFParseError('invalid IPv4 network: ' + rvalue)
			if ip in ip_network:
				return True
		elif mechanism == 'ip6':
			try:
				if its.py_v2 and isinstance(rvalue, str):
					rvalue = rvalue.decode('utf-8')
				ip_network = ipaddress.IPv6Network(rvalue, strict=False)
			except ipaddress.AddressValueError:
				raise SPFParseError('invalid IPv6 network: ' + rvalue)
			if ip in ip_network:
				return True
		elif mechanism == 'mx':
			answers, additional = self._dns_query(rvalue, 'MX')
			for answer in answers:
				hostname = None
				if answer.rdtype == dns.rdatatype.MX:
					hostname = _to_hostname(answer.exchange)
				elif answer.rdtype == dns.rdatatype.CNAME:
					hostname = _to_hostname(answer.target)
				else:
					raise ValueError('answer is not an MX or CNAME record')
				found, matches = self._hostname_matches_additional(ip, hostname, additional)
				if matches:
					return True
				if not found and self._hostname_matches_ip(ip, hostname):
					return True
		elif mechanism == 'ptr':
			if isinstance(ip, ipaddress.IPv4Address):
				ip = str(ip)
				suffix = 'in-addr'
			else:
				ip = '.'.join(ip.exploded.replace(':', ''))
				suffix = 'ip6'
			ptr_domain = (rvalue or domain)
			ip = ip.split('.')
			ip.reverse()
			ip = '.'.join(ip)
			answers, _ = self._dns_query(ip + '.' + suffix + '.arpa', 'PTR')
			for ptr_record in answers:
				hostname = _to_hostname(ptr_record.target)
				if ptr_domain == hostname or ptr_domain.endswith('.' + hostname):
					return True
		else:
			raise SPFPermError("unsupported mechanism type: '{0}'".format(mechanism))
		return False