def test_no_policy_match(self):
        espf = EnforceSpf()
        espf.set_enforcement('fail', match_code='550')

        class TestSession(object):
            address = ('1.2.3.4', 56789)
            envelope = None
            ehlo_as = 'testehlo'

        class TestValidators(object):
            def __init__(self):
                self.session = TestSession()

            @espf.check
            def validate_mail(self, reply, sender):
                pass

        spf.check2(i='1.2.3.4', s='*****@*****.**',
                   h='testehlo').AndReturn(('none', 'the reason'))
        self.mox.ReplayAll()
        validators = TestValidators()
        reply = Reply('250', '2.0.0 Ok')
        validators.validate_mail(reply, '*****@*****.**')
        self.assertEqual('250', reply.code)
        self.assertEqual('2.0.0 Ok', reply.message)
    def test_on_validate_rcpt(self):
        espf = EnforceSpf()
        espf.set_enforcement('fail', match_code='550')

        class TestSession(object):
            address = ('1.2.3.4', 56789)
            envelope = Envelope('*****@*****.**')
            ehlo_as = 'testehlo'

        class TestValidators(object):
            def __init__(self):
                self.session = TestSession()

            @espf.check
            def validate_rcpt(self, reply, recipient):
                pass

        spf.check2(i='1.2.3.4', s='*****@*****.**',
                   h='testehlo').AndReturn(('fail', 'the reason'))
        self.mox.ReplayAll()
        validators = TestValidators()
        reply = Reply('250', '2.0.0 Ok')
        validators.validate_rcpt(reply, 'asdf')
        self.assertEqual('550', reply.code)
        self.assertEqual('5.7.1 Access denied', reply.message)
예제 #3
0
 def examine(self,suspect):
     if not have_spf:
         return DUNNO
     
     client_address=suspect.get_value('client_address')
     if client_address is None:
         self.logger.error('No client address found')
         return DUNNO
     if have_netaddr:
         ip_whitelist=self.config.get('SPFPlugin','ip_whitelist')
         ip_whitelist=[IPNetwork(i.strip()) for i in ip_whitelist.split(',')]
         for net in ip_whitelist:
             if IPAddress(client_address) in net:
                 return DUNNO
     
     sender=suspect.get_value('sender')
     if sender is None:
         self.logger.warning('No RCPT address found')
         return DEFER_IF_PERMIT,'internal policy error (no from address)'
     sender_email = strip_address(sender)
     sender_domain = extract_domain(sender_email)
     domain_whitelist=self.config.get('SPFPlugin','domain_whitelist')
     domain_whitelist=[i.strip() for i in domain_whitelist.split(',')]
     if sender_domain in domain_whitelist:
         return DUNNO
     
     helo_name=suspect.get_value('helo_name')
     if helo_name is None:
         self.logger.error('No SMTP HELO name found')
         return DUNNO
     
     on_softfail=self.config.get('SPFPlugin','on_softfail')
     softfail = DUNNO
     if on_softfail == 'DEFER':
         softfail =  DEFER_IF_PERMIT
     on_softerror=self.config.get('SPFPlugin','on_softerror')
     softerror = DUNNO
     if on_softerror == 'REJECT':
         softerror = REJECT
     
     result, explanation = spf.check2(client_address, sender_email, helo_name)
     self.logger.debug('Postomaat SPF check: ip: %s, from: %s, helo: %s, result: %s' % (client_address, sender_email, helo_name, result))
     
     action = DUNNO
     message = None
     
     if result == 'fail':
         action = REJECT
         message = explanation
     elif result == 'temperror':
         action = DEFER_IF_PERMIT
         message = explanation
     elif result == 'softfail' and softfail != DUNNO:
         action = softfail
         message = explanation
     elif result == 'softerror' and softerror != DUNNO:
         action = softerror
         message = explanation
     
     return action, message
예제 #4
0
def check_spf(domain, mx, record):
    """Test the SPF records on a given domain."""
    results = {
        'test': 'spf',
        'passed': None,
        'records': [{'domain': domain, 'type': 'TXT', 'value': record}],
        'messages': []
    }
    try:
        for ip, helo in mx:
            spf_result, message = spf.check2(i=ip, s='admin@%s' % domain, h=helo)
            results['succeeded'] = True
            if spf_result == "none" and message == "":
                message = "No SPF record set! Please set one"
            results['messages'].append("(%s/%s) %s: %s" % (ip, helo, spf_result, message))
            if spf_result == "pass" and results['passed'] in (None, True):
                results['passed'] = True
            else:
                results['passed'] = False
    except spf.AmbiguityWarning as ex:
        results['succeeded'] = True
        results['passed'] = False
        results['message'] = str(ex)
    except (spf.TempError, spf.PermError) as ex:
        results['succeeded'] = False
        results['message'] = str(ex)
    return results
예제 #5
0
파일: spf.py 프로젝트: sorinsrn7/SpamPAD
 def _query_spf(self, timeout, ip, mx, sender_address):
     self.ctxt.log.debug("SPF::Plugin %s",
                         "Querying the dns server(%s, %s, %s)..."
                         % (ip, mx, sender_address))
     result, comment = spf.check2(i=ip, s=sender_address,
                                  h=mx, timeout=timeout)
     return result
예제 #6
0
    def examine(self, suspect):
        if not PYSPF_AVAILABLE:
            suspect.debug("pyspf not available, can not check")
            self._logger().warning(
                "%s: SPF Check skipped, pyspf unavailable" % (suspect.id))
            suspect.set_tag('SPF.status', 'skipped')
            suspect.set_tag("SPF.explanation", 'missing dependency')
            return DUNNO

        clientinfo = suspect.get_client_info(self.config)
        if clientinfo is None:
            suspect.debug("client info not available for SPF check")
            self._logger().warning(
                "%s: SPF Check skipped, could not get client info" % (suspect.id))
            suspect.set_tag('SPF.status', 'skipped')
            suspect.set_tag(
                "SPF.explanation", 'could not extract client information')
            return DUNNO

        helo, ip, revdns = clientinfo
        result, explanation = spf.check2(ip, suspect.from_address, helo)
        suspect.set_tag("SPF.status", result)
        suspect.set_tag("SPF.explanation", explanation)
        suspect.debug("SPF status: %s (%s)" % (result, explanation))
        return DUNNO
예제 #7
0
파일: domainauth.py 프로젝트: steigr/fuglu
    def examine(self, suspect):
        if not PYSPF_AVAILABLE:
            suspect.debug("pyspf not available, can not check")
            self._logger().warning(
                "%s: SPF Check skipped, pyspf unavailable" % (suspect.id))
            suspect.set_tag('SPF.status', 'skipped')
            suspect.set_tag("SPF.explanation", 'missing dependency')
            return DUNNO

        clientinfo = suspect.get_client_info(self.config)
        if clientinfo == None:
            suspect.debug("client info not available for SPF check")
            self._logger().warning(
                "%s: SPF Check skipped, could not get client info" % (suspect.id))
            suspect.set_tag('SPF.status', 'skipped')
            suspect.set_tag(
                "SPF.explanation", 'could not extract client information')
            return DUNNO

        helo, ip, revdns = clientinfo
        result, explanation = spf.check2(ip, suspect.from_address, helo)
        suspect.set_tag("SPF.status", result)
        suspect.set_tag("SPF.explanation", explanation)
        suspect.debug("SPF status: %s (%s)" % (result, explanation))
        return DUNNO
예제 #8
0
파일: email_utils.py 프로젝트: wwwK/app
def spf_pass(
    envelope,
    mailbox: Mailbox,
    user: User,
    alias: Alias,
    contact_email: str,
    msg: Message,
) -> bool:
    ip = msg[_IP_HEADER]
    if ip:
        LOG.d("Enforce SPF on %s %s", ip, envelope.mail_from)
        try:
            r = spf.check2(i=ip, s=envelope.mail_from, h=None)
        except Exception:
            LOG.exception("SPF error, mailbox %s, ip %s", mailbox.email, ip)
        else:
            # TODO: Handle temperr case (e.g. dns timeout)
            # only an absolute pass, or no SPF policy at all is 'valid'
            if r[0] not in ["pass", "none"]:
                LOG.w(
                    "SPF fail for mailbox %s, reason %s, failed IP %s",
                    mailbox.email,
                    r[0],
                    ip,
                )
                subject = get_header_unicode(msg["Subject"])
                send_email_with_rate_control(
                    user,
                    ALERT_SPF,
                    mailbox.email,
                    f"SimpleLogin Alert: attempt to send emails from your alias {alias.email} from unknown IP Address",
                    render(
                        "transactional/spf-fail.txt",
                        alias=alias.email,
                        ip=ip,
                        mailbox_url=URL + f"/dashboard/mailbox/{mailbox.id}#spf",
                        to_email=contact_email,
                        subject=subject,
                        time=arrow.now(),
                    ),
                    render(
                        "transactional/spf-fail.html",
                        ip=ip,
                        mailbox_url=URL + f"/dashboard/mailbox/{mailbox.id}#spf",
                        to_email=contact_email,
                        subject=subject,
                        time=arrow.now(),
                    ),
                )
                return False

    else:
        LOG.w(
            "Could not find %s header %s -> %s",
            _IP_HEADER,
            mailbox.email,
            contact_email,
        )

    return True
예제 #9
0
    async def handle_MAIL(self, server, session, envelope, address,
                          mail_options):
        ip = session.peer[0]
        result, description = spf.check2(ip, address, session.host_name)

        envelope.mail_from = address
        envelope.mail_options.extend(mail_options)

        return "250 OK"
예제 #10
0
파일: spf.py 프로젝트: sorinsrn7/SpamPAD
 def _query_spf(self, timeout, ip, mx, sender_address):
     self.ctxt.log.debug(
         "SPF::Plugin %s", "Querying the dns server(%s, %s, %s)..." %
         (ip, mx, sender_address))
     result, comment = spf.check2(i=ip,
                                  s=sender_address,
                                  h=mx,
                                  timeout=timeout)
     return result
예제 #11
0
파일: domainauth.py 프로젝트: danBLA/fuglu
 def _spf_lookup(self, ip, from_address, helo, retries=3):
     spf.MAX_LOOKUP = self.config.getint(self.section, 'max_lookups')
     result, explanation = spf.check2(ip, from_address, helo)
     if result == 'temperror' and retries > 0:
         time.sleep(self.config.getint(self.section, 'temperror_sleep'))
         retries -= 1
         result, explanation = self._spf_lookup(ip, from_address, helo,
                                                retries)
     return result, explanation
예제 #12
0
def main():
    if len(sys.argv) != 4:
        print('[' + os.path.basename(__file__) +
              '] invalid number of arguments.')
        sys.exit(1)

    result, explanation = spf.check2(sys.argv[1], sys.argv[2], sys.argv[3])
    print(result + ',' + explanation)
    sys.exit(0)
예제 #13
0
    def test_reason_in_message(self):
        espf = EnforceSpf()
        espf.set_enforcement('pass', match_code='250', match_message='{reason}')
        class TestSession(object):
            address = ('1.2.3.4', 56789)
            envelope = None
            ehlo_as = 'testehlo'
        class TestValidators(object):
            def __init__(self):
                self.session = TestSession()
            @espf.check
            def validate_mail(self, reply, sender):
                pass

        spf.check2(i='1.2.3.4', s='*****@*****.**', h='testehlo').AndReturn(('pass', 'the reason'))
        self.mox.ReplayAll()
        validators = TestValidators()
        reply = Reply('250', '2.0.0 Ok')
        validators.validate_mail(reply, '*****@*****.**')
        self.assertEqual('250', reply.code)
        self.assertEqual('2.0.0 the reason', reply.message)
예제 #14
0
    def test_on_validate_rcpt(self):
        espf = EnforceSpf()
        espf.set_enforcement('fail', match_code='550')
        class TestSession(object):
            address = ('1.2.3.4', 56789)
            envelope = Envelope('*****@*****.**')
            ehlo_as = 'testehlo'
        class TestValidators(object):
            def __init__(self):
                self.session = TestSession()
            @espf.check
            def validate_rcpt(self, reply, recipient):
                pass

        spf.check2(i='1.2.3.4', s='*****@*****.**', h='testehlo').AndReturn(('fail', 'the reason'))
        self.mox.ReplayAll()
        validators = TestValidators()
        reply = Reply('250', '2.0.0 Ok')
        validators.validate_rcpt(reply, 'asdf')
        self.assertEqual('550', reply.code)
        self.assertEqual('5.7.1 Access denied', reply.message)
예제 #15
0
파일: verifyspf.py 프로젝트: 01-/mailin
def main():
    if len(sys.argv) != 4:
        print('[' + os.path.basename(__file__) + '] invalid number of arguments.')
        sys.exit(64)

    result, explanation = spf.check2(sys.argv[1], sys.argv[2], sys.argv[3])
    print('[' + os.path.basename(__file__) + '] (' + result + ', ' + explanation + ')')

    if result == 'pass':
        sys.exit(0)
    else:
        # Invalid spf, exit with code 11.
        sys.exit(11)
예제 #16
0
    def query(self, sender, ip, ehlo_as):
        """Performs a direct query to check the sender's domain to see if the
        given IP and EHLO string are authorized to send for that domain.

        :param sender: The sender address.
        :param ip: The IP address string of the sending client.
        :param ehlo_as: The EHLO string given by the sending client.
        :returns: A tuple of the result and reason strings.

        """
        result, reason = 'temperror', 'Timed out'
        with gevent.Timeout(self.timeout, False):
            result, reason = spf.check2(i=ip, s=sender, h=ehlo_as)
        return result, reason
예제 #17
0
    def query(self, sender, ip, ehlo_as):
        """Performs a direct query to check the sender's domain to see if the
        given IP and EHLO string are authorized to send for that domain.

        :param sender: The sender address.
        :param ip: The IP address string of the sending client.
        :param ehlo_as: The EHLO string given by the sending client.
        :returns: A tuple of the result and reason strings.

        """
        result, reason = 'temperror', 'Timed out'
        with gevent.Timeout(self.timeout, False):
            result, reason = spf.check2(i=ip, s=sender, h=ehlo_as)
        return result, reason
예제 #18
0
    def examine(self, suspect):
        if not HAVE_SPF:
            return DUNNO

        client_address = suspect.get_value('client_address')
        helo_name = suspect.get_value('helo_name')
        sender = suspect.get_value('sender')
        if client_address is None or helo_name is None or sender is None:
            self.logger.error('missing client_address or helo or sender')
            return DUNNO

        if self.ip_whitelisted(client_address):
            self.logger.info("Client %s is whitelisted - no SPF check" %
                             client_address)
            return DUNNO

        sender_email = strip_address(sender)
        if sender_email == '' or sender_email is None:
            return DUNNO

        sender_domain = extract_domain(sender_email)
        if sender_domain is None:
            self.logger.error('no domain found in sender address %s' %
                              sender_email)
            return DUNNO

        if not self.check_this_domain(sender_domain):
            self.logger.debug('skipping SPF check for %s' % sender_domain)
            return DUNNO

        result, explanation = spf.check2(client_address, sender_email,
                                         helo_name)
        suspect.tags['spf'] = result
        if result != 'none':
            self.logger.info(
                'SPF client=%s, sender=%s, h=%s result=%s : %s' %
                (client_address, sender_email, helo_name, result, explanation))

        action = DUNNO
        message = apply_template(
            self.config.get(self.section, 'messagetemplate'), suspect,
            dict(result=result, explanation=explanation))

        configopt = 'on_%s' % result
        if self.config.has_option(self.section, configopt):
            action = string_to_actioncode(
                self.config.get(self.section, configopt))

        return action, message
예제 #19
0
def main():
    if len(sys.argv) != 4:
        print('[' + os.path.basename(__file__) +
              '] invalid number of arguments.')
        sys.exit(64)

    result, explanation = spf.check2(sys.argv[1], sys.argv[2], sys.argv[3])
    print('[' + os.path.basename(__file__) + '] (' + result + ', ' +
          explanation + ')')

    if result == 'pass':
        sys.exit(0)
    else:
        # Invalid spf, exit with code 11.
        sys.exit(11)
예제 #20
0
    def examine(self,suspect):
        if not have_spf:
            return DUNNO
        
        client_address=suspect.get_value('client_address')
        helo_name=suspect.get_value('helo_name')
        sender=suspect.get_value('sender')
        if client_address is None or helo_name is None or sender is None:
            self.logger.error('missing client_address or helo or sender')
            return DUNNO

        if self.ip_whitelisted(client_address):
            self.logger.info("Client %s is whitelisted - no SPF check"%client_address)
            return DUNNO

        sender_email = strip_address(sender)
        if sender_email=='' or sender_email is None:
            return DUNNO

        selective_sender_domain_file=self.config.get(self.section,'domain_selective_spf_file')
        if selective_sender_domain_file!='':
            if self.selective_domain_loader is None:
                self.selective_domain_loader=FileList(selective_sender_domain_file,lowercase=True)
            try:
                sender_domain = extract_domain(sender_email)
                if sender_domain is None:
                    return DUNNO
            except ValueError as e:
                self.logger.warning(str(e))
                return DUNNO
            if not sender_domain.lower() in self.selective_domain_loader.get_list():
                return DUNNO

        result, explanation = spf.check2(client_address, sender_email, helo_name)
        suspect.tags['spf']=result
        if result!='none':
            self.logger.info('SPF client=%s, sender=%s, h=%s result=%s : %s' % (client_address, sender_email, helo_name, result,explanation))
        
        action = DUNNO
        message = apply_template(self.config.get(self.section,'messagetemplate'),suspect,dict(result=result,explanation=explanation))

        configopt='on_%s'%result
        if self.config.has_option(self.section,configopt):
            action=self.config.get(self.section,configopt)

        return action, message
예제 #21
0
    def get_info(self, data):
        try:
            ip = ''
            sender = ''
            helo = ''

            inputs = data.split('|')

            ip = inputs[0]
            sender = inputs[1]
            if (len(inputs) == 3):
                helo = inputs[2]

            result = spf.check2(i=ip, s=sender, h=helo)
        except SyntaxError:
            print("Syntax Error")
        return {"SpfCheck": result}
예제 #22
0
def doFilter(bodyFile, controlFileList):
    """Use the SPF mechanism to blacklist email."""
    try:
        sendersMta = courier.control.getSendersMta(controlFileList)
        sendersIp = courier.control.getSendersIP(controlFileList)
        sender = courier.control.getSender(controlFileList)
    except:
        return '451 Internal failure locating control files'

    # Don't waste time on DSNs.
    if sender == '':
        return ''

    helo = sendersMta.split(' ')[1]
    (spfResult, spfExplanation) = spf.check2(sendersIp, sender, helo)
    if spfResult == 'fail':
        return '517 SPF returns deny'
    return ''
예제 #23
0
    async def handle_MAIL(self, server: SMTP, session: Session,
                          envelope: Envelope, address: str,
                          mail_options: list):

        ip = session.peer[0]
        result, description = spf.check2(ip, address, session.host_name)
        valid_spf = result == 'pass'
        envelope.spf = valid_spf

        log.info("SPF: %s, %s", result, description)

        if self.verify_spf and not valid_spf:
            return '550 SPF validation failed'

        envelope.mail_from = address
        envelope.mail_options.extend(mail_options)

        return '250 OK'
예제 #24
0
def joomla_version(target, port, timeout_sec, log_in_file, language,
                   time_sleep, thread_tmp_filename, socks_proxy, scan_id,
                   scan_cmd):
    try:
        s = conn(target, port, timeout_sec, socks_proxy)
        if not s:
            return False
        else:
            try:
                global result
                host_ip = socket.gethostbyname(target)
                if version() is 2:
                    host_ip = host_ip.decode("utf-8")
                result = spf.check2(host_ip, "admin@" + target, target)
                return True
            except Exception:
                return False
    except Exception as e:
        return False
예제 #25
0
파일: spfcheck.py 프로젝트: ledgr/postomaat
    def examine(self,suspect):
        if not HAVE_SPF:
            return DUNNO
        
        client_address=suspect.get_value('client_address')
        helo_name=suspect.get_value('helo_name')
        sender=suspect.get_value('sender')
        if client_address is None or helo_name is None or sender is None:
            self.logger.error('missing client_address or helo or sender')
            return DUNNO

        if self.ip_whitelisted(client_address):
            self.logger.info("Client %s is whitelisted - no SPF check"%client_address)
            return DUNNO

        sender_email = strip_address(sender)
        if sender_email=='' or sender_email is None:
            return DUNNO
        
        sender_domain = extract_domain(sender_email)
        if sender_domain is None:
            self.logger.error('no domain found in sender address %s' % sender_email)
            return DUNNO
        
        if not self.check_this_domain(sender_domain):
            self.logger.debug('skipping SPF check for %s' % sender_domain)
            return DUNNO

        result, explanation = spf.check2(client_address, sender_email, helo_name)
        suspect.tags['spf'] = result
        if result != 'none':
            self.logger.info('SPF client=%s, sender=%s, h=%s result=%s : %s' % (client_address, sender_email, helo_name, result,explanation))
        
        action = DUNNO
        message = apply_template(self.config.get(self.section, 'messagetemplate'), suspect, dict(result=result, explanation=explanation))

        configopt = 'on_%s' % result
        if self.config.has_option(self.section, configopt):
            action=string_to_actioncode(self.config.get(self.section, configopt))

        return action, message
예제 #26
0
    if up_srv_helo == up_srv_hostn[0]:
        iprev_res = "pass"
        iprev_hn = up_srv_hostn[0]
    else:
        iprev_res = "fail"
except:
    iprev_res = "temperror"

iprev_result = authres.IPRevAuthenticationResult(result=iprev_res,
                                                 policy_iprev=up_srv_ip,
                                                 policy_iprev_comment=iprev_hn)
results_list += [iprev_result]

### SPF CHECK

spf_result = spf.check2(i=up_srv_ip, s=sender_address, h=up_srv_helo)
spf_res = authres.SPFAuthenticationResult(result=spf_result[0],
                                          smtp_mailfrom=sender_address,
                                          smtp_helo=up_srv_helo,
                                          reason=spf_result[1])
results_list += [spf_res]

# Write Received-SPF header (must be added ABOVE Received: lines for this server)
sys.stdout.write(
    'Received-SPF: {0} ({1}) receiver={2}; client-ip={3}; helo={4}; envelope-from={5};'
    .format(spf_result[0], spf_result[1], AUTHSERV_HOSTNAME, up_srv_ip,
            up_srv_helo, sender_address).encode("utf-8") + linesep)

### ARC SIGNATURE
#import logging
#logging.basicConfig(level=10)
예제 #27
0
파일: main.py 프로젝트: Eros/Graveyard
def runCheck(ip, s, h):
    result = []
    return result.append(spf.check2(ip, s, h))
예제 #28
0
파일: spfcheck.py 프로젝트: stevemeier/qbox
# Exit if we can not get client IP
if len(remoteip) == 0:
    print
    exit()

# Exit if the host did not say hel(l)o
if not os.environ.get('SMTPHELOHOST'):
    print
    exit()

# Exit if there is no sender
if not os.environ.get('SMTPMAILFROM'):
    print
    exit()

# Run the SPF check
result, explanation = spf.check2(i=remoteip,
                                 s=os.environ['SMTPMAILFROM'],
                                 h=os.environ['SMTPHELOHOST'])

# Only fails will be rejected
if result == "fail":
    print >> sys.stderr, "%d SPF check failed for %s" % (
        os.getppid(), os.environ['SMTPMAILFROM'])
    print "E451 SPF check failed [%s]" % explanation
else:
    print

exit()
예제 #29
0
			return(( 'DUNNO', '' ))
		try:
			import spf
		except Exception, e:
			syslog.syslog('ERROR: Unable to import SPF module.')
			return(( 'DUNNO', '' ))

		if self.debug >= 3:
			syslog.syslog(syslog.LOG_DEBUG, 'SPF info: %s,%s,%s'
					% ( self.data['client_address'], self.data['sender_domain'],
						'unknown' ))

		#  SPF version 2 check
		if hasattr(spf, 'check2'):
			try:
				ret = spf.check2(i = self.data['client_address'],
						s = self.data['sender_domain'], h = 'unknown')
			except Exception, e:
				syslog.syslog('ERROR: SPF check failed: %s' % str(e))
				return(( 'DUNNO', '' ))
			spfResult = string.strip(ret[0])
			spfReason = string.strip(ret[1])
			spfResult = spfResult.lower()
			spfResult = spfResult.capitalize()
			if self.data.get('sender_domain'): identity = 'identity=mailfrom; '
			else: identity = 'identity=helo; '
			spfDetail = (identity + 'client-ip=%s; helo=%s; envelope-from=%s; '
					'receiver=%s; '
					% ( self.data.get('client_address', '<UNKNOWN>'),
						self.data.get('helo_name', '<UNKNOWN>'),
						self.data.get('sender', '<UNKNOWN>'),
						self.data.get('recipient', '<UNKNOWN>'),
예제 #30
0
def email_analysis(filename, exclude_private_ip, check_spf):
    urlList = []
    hopList = []
    hopListIP = []
    domainList = []
    attachmentsList = []
    hopListIPnoPrivate = []

    resultmeioc = {
        "filename": os.path.basename(filename),
        "from": None,
        "sender": None,
        "x-sender": None,
        "to": None,
        "cc": None,
        "bcc": None,
        "envelope-to": None,
        "delivered-to": None,
        "subject": None,
        "x-originating-ip": None,
        "relay_full": None,
        "relay_ip": None,
        "spf": None,
        "urls": None,
        "domains": None,
        "attachments": None
    }

    with open(filename, "rb") as fp:
        msg = BytesParser(policy=policy.default).parse(fp)

    if msg:

        #
        # Header analysis
        #

        if msg["From"]:
            # A sender obfuscation technique involves entering two e-mails. Only the last one is the real one. Example:
            #
            # Sender Name: Mario Rossi <*****@*****.**>
            # Sender Mail: [email protected]
            mail_from = re.findall(
                "[A-Za-z0-9.!#$%&'*+\/=?^_`{|}~\-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}",
                msg["From"], re.IGNORECASE)

            if mail_from:
                resultmeioc["from"] = mail_from[-1]

        if msg["Sender"]:
            mail_sender = re.findall(
                "[A-Za-z0-9.!#$%&'*+\/=?^_`{|}~\-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}",
                msg["Sender"], re.IGNORECASE)

            if mail_sender:
                resultmeioc["sender"] = mail_sender[-1]

        if msg["X-Sender"]:
            mail_xsender = re.findall(
                "[A-Za-z0-9.!#$%&'*+\/=?^_`{|}~\-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}",
                msg["X-Sender"], re.IGNORECASE)

            if mail_xsender:
                resultmeioc["x-sender"] = mail_xsender[-1]

        if msg["To"]:
            mail_to = re.findall(
                "[A-Za-z0-9.!#$%&'*+\/=?^_`{|}~\-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}",
                msg["To"], re.IGNORECASE)

            if mail_to:
                # Remove possible duplicates and create a numbered dictionary
                mail_to = dict(
                    zip(range(len(list(set(mail_to)))), list(set(mail_to))))
                resultmeioc["to"] = mail_to

        if msg["Bcc"]:
            resultmeioc["bcc"] = msg["Bcc"]

        if msg["Cc"]:
            mail_cc = re.findall(
                "[A-Za-z0-9.!#$%&'*+\/=?^_`{|}~\-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}",
                msg["Cc"], re.IGNORECASE)

            if mail_cc:
                # Remove possible duplicates and create a numbered dictionary
                mail_cc = dict(
                    zip(range(len(list(set(mail_cc)))), list(set(mail_cc))))
                resultmeioc["cc"] = mail_cc

        if msg["Envelope-to"]:

            mail_envelopeto = re.findall(
                "[A-Za-z0-9.!#$%&'*+\/=?^_`{|}~\-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}",
                msg["Envelope-to"], re.IGNORECASE)

            if mail_envelopeto:
                # Remove possible duplicates and create a numbered dictionary
                mail_envelopeto = dict(
                    zip(range(len(list(set(mail_envelopeto)))),
                        list(set(mail_envelopeto))))
                resultmeioc["envelope-to"] = mail_envelopeto

        if msg["Delivered-To"]:
            resultmeioc["delivered-to"] = msg["Delivered-To"]

        if msg["X-Originating-IP"]:
            # Usually the IP is in square brackets, I remove them if present.
            mail_xorigip = msg["X-Originating-IP"].replace("[", "").replace(
                "]", "")
            resultmeioc["x-originating-ip"] = mail_xorigip

        if msg["Subject"]:
            resultmeioc["subject"] = msg["Subject"]

        # Identify each relay
        received = msg.get_all("Received")
        if received:
            received.reverse()
            for line in received:
                hops = re.findall(
                    "from\s+(.*?)\s+by(.*?)(?:(?:with|via)(.*?)(?:id|$)|id|$)",
                    line, re.DOTALL | re.X)
                for hop in hops:

                    ipv4_address = re.findall(r"[0-9]+(?:\.[0-9]+){3}", hop[0],
                                              re.DOTALL | re.X)

                    # https://gist.github.com/dfee/6ed3a4b05cfe7a6faf40a2102408d5d8
                    ipv6_address = re.findall(
                        r"(?:(?:(?:(?:[0-9a-fA-F]){1,4}):){1,4}:[^\s:](?:(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])))|(?:::(?:ffff(?::0{1,4}){0,1}:){0,1}[^\s:](?:(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])))|(?:fe80:(?::(?:(?:[0-9a-fA-F]){1,4})){0,4}%[0-9a-zA-Z]{1,})|(?::(?:(?::(?:(?:[0-9a-fA-F]){1,4})){1,7}|:))|(?:(?:(?:[0-9a-fA-F]){1,4}):(?:(?::(?:(?:[0-9a-fA-F]){1,4})){1,6}))|(?:(?:(?:(?:[0-9a-fA-F]){1,4}):){1,2}(?::(?:(?:[0-9a-fA-F]){1,4})){1,5})|(?:(?:(?:(?:[0-9a-fA-F]){1,4}):){1,3}(?::(?:(?:[0-9a-fA-F]){1,4})){1,4})|(?:(?:(?:(?:[0-9a-fA-F]){1,4}):){1,4}(?::(?:(?:[0-9a-fA-F]){1,4})){1,3})|(?:(?:(?:(?:[0-9a-fA-F]){1,4}):){1,5}(?::(?:(?:[0-9a-fA-F]){1,4})){1,2})|(?:(?:(?:(?:[0-9a-fA-F]){1,4}):){1,6}:(?:(?:[0-9a-fA-F]){1,4}))|(?:(?:(?:(?:[0-9a-fA-F]){1,4}):){1,7}:)|(?:(?:(?:(?:[0-9a-fA-F]){1,4}):){7,7}(?:(?:[0-9a-fA-F]){1,4}))",
                        hop[0], re.DOTALL | re.X)

                    if ipv4_address:
                        for ipv4 in ipv4_address:
                            if ipaddress.ip_address(ipv4):
                                hopListIP.append(ipv4)
                                if not ipaddress.ip_address(ipv4).is_private:
                                    hopListIPnoPrivate.append(ipv4)

                    if ipv6_address:
                        for ipv6 in ipv6_address:
                            if ipaddress.ip_address(ipv6) and not "6::":
                                hopListIP.append(ipv6)

                                if not ipaddress.ip_address(ipv6).is_private:
                                    hopListIPnoPrivate.append(ipv6)

                    if hop[0]:
                        hopList.append(hop[0])

        if hopList:
            resultmeioc["relay_full"] = dict(zip(range(len(hopList)), hopList))

        if hopListIP:
            if exclude_private_ip:
                resultmeioc["relay_ip"] = dict(
                    zip(range(len(hopListIPnoPrivate)), hopListIPnoPrivate))
            else:
                resultmeioc["relay_ip"] = dict(
                    zip(range(len(hopListIP)), hopListIP))

        #
        # Body analysis
        #
        for part in msg.walk():
            if part.get_content_type() == "text/plain":
                # https://gist.github.com/dperini/729294
                urlList.extend(
                    re.findall(
                        "(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?",
                        part.get_content(),
                        re.UNICODE | re.IGNORECASE | re.MULTILINE))

            if part.get_content_type() == "text/html":
                # The try/except is necessary, if the body of the eMail contains an incorrect or unencoded HTML code the script freeezes.
                try:
                    soup = BeautifulSoup(part.get_content(), "html.parser")
                    tags = soup.find_all("a", href=True)
                    for url in tags:
                        urlList.append(url.get("href"))
                except:
                    pass

            if part.get_filename():
                if part.get_payload(decode=True):
                    filename = part.get_filename()
                    filemd5 = hashlib.md5(
                        part.get_payload(decode=True)).hexdigest()
                    filesha1 = hashlib.sha1(
                        part.get_payload(decode=True)).hexdigest()
                    filesha256 = hashlib.sha256(
                        part.get_payload(decode=True)).hexdigest()

                    attachmentsList.append({
                        "filename": filename,
                        "MD5": filemd5,
                        "SHA1": filesha1,
                        "SHA256": filesha256
                    })

        # Identify each domain reported in the eMail body
        for url in urlList:
            analyzeddomain = tldcache(url).registered_domain
            if analyzeddomain:
                domainList.append(analyzeddomain)

        # Remove Duplicate
        urlList = list(set(urlList))
        domainList = list(set(domainList))

        if urlList:
            resultmeioc["urls"] = dict(zip(range(len(urlList)), urlList))
            resultmeioc["domains"] = dict(
                zip(range(len(domainList)), domainList))

        if attachmentsList:
            resultmeioc["attachments"] = attachmentsList

        #
        # Verify the SPF record if requested
        #
        if check_spf:
            testspf = False
            resultspf = ""
            for ip in hopListIPnoPrivate:
                if not testspf and "mail_from" in locals():
                    resultspf = spf.check2(ip, mail_from[-1],
                                           mail_from[-1].split("@")[1])[0]
                    try:
                        resultspf = spf.check2(ip, mail_from[-1],
                                               mail_from[-1].split("@")[1])[0]
                    except:
                        pass

                    if resultspf == "pass":
                        testspf = True
                    else:
                        testspf = False

            resultmeioc["spf"] = testspf

        print(json.dumps(resultmeioc, indent=4))
예제 #31
0
def check_spf(ip, mail_from, helo):
    res, reason = spf.check2(ip, mail_from, helo)
    return SPFAuthenticationResult(result=res,
                                   reason=reason,
                                   smtp_mailfrom=mail_from,
                                   smtp_helo=helo)
예제 #32
0
            logger_1.debug("The CustomerNumber:" + k + " has no domains associated with it")

        TeamDictonary[CustomerNumber] = ParsingList
        x += 1

    for k, v in TeamDictonary.items():
        z = 0
        eachcounter = 0
        ValuesLength = len(v)
        if ValuesLength > 0:

            while z < ValuesLength:
                for each in IPList:
                    if v[z] != "" and v[z] != None:
                        result = spf.check2(
                            each, "test@" + v[z], v[z]
                        )  ##This is where we will call to check this specific domain result should return true/false
                        logger_1.debug("trying " + each)
                        if result[0] != "pass":
                            newresult = spf.check2(each, "test@" + v[z], v[z])  ##double check
                            if newresult[0] != "pass":
                                logger_1.debug(
                                    "The domain "
                                    + v[z]
                                    + " has failed validation on "
                                    + each
                                    + ". Located in CustomerNumber:"
                                    + k
                                )
                        else:
                            logger_1.debug(
예제 #33
0
    error = True

if sender is None:
    print("No sender (-s) passed!")
    error = True

if code is None:
    print("No RFC4408-compliant validation response (-r) passed!")
    error = True

if error:
    print("Exiting because of errors...\n")
    exit(EXIT_UNKNOWN)

try:
    results = spf.check2(i=ip,s=sender,h=domain,timeout=float(timeout))
except:
    print "Exception ocurred when trying to check SPF record: ", sys.exc_info()
    exit(EXIT_UNKNOWN)

real_code = results[0]
msg = results[1]

detail = Template(detail_template).substitute(ip=ip,sender=sender,domain=domain,code=real_code)
if code == real_code:
    print "CHECK_SPF OK:",detail
    exit(EXIT_OK)
elif warning_mode:
    print "CHECK_SPF WARNING:",detail
    exit(EXIT_WARNING)
else: