def sent_with_spf(self, ipv4, sender, hostname): ''' Given a sender email address, the IP address of an Outbound server, and its hostname, It will check if it complies with the SPF policy (if any) :param ipv4: IP address of the Outbound server delivering the email :param sender: email address of the sender :param hostname: hostname of the Outbound server. :return: Boolean, SPF compliant? YES:NO String, code returned bt the validation function String, text returned by the validation function ''' try: spfsupport, spfcode, spfdesc = spf.check(i=ipv4, s=sender, h=hostname) self.logger.debug('SPDF: ' + str(spfsupport) + ', ' + str(spfcode) + ', ' + str(spfdesc)) if (spfsupport == 'pass' or spfsupport == 'softfail' or spfsupport == 'neutral') and 250 == spfcode: return True, spfcode, (spfsupport + ' : ' + spfdesc) except Exception as ex: self.logger.error("Error validating compliance with SPF! " + str(ex)) return False, spfcode, spfdesc
def auth(self, message_data=None, peer_ip=None, message=None): mailfrom = Contact.create_contacts_from_message_field('from', message)[0] host = re.match('[^@]*@(.*)', mailfrom.email).group(1) result_status = spf.check(i=peer_ip, s=mailfrom.email, h=host)[0] if 'pass' in result_status: return True return False
def check_spf(self): """ Check if sender is authorised by sender policy framework """ if not ENABLE_SPF: return False return spf.check(i=socket.gethostbyname(DNS_NAME.get_fqdn()),s=self.email,h=DNS_NAME.get_fqdn())
def check(self, ip, sender): """ Perform an SPF check for the given IP address against the given sender email address. """ status, code, msg = spf.check(ip, sender, None) result = (ip, status, code, msg) self.results.append(result) return result
def check_spf(self): """ Check if sender is authorised by sender policy framework """ if not ENABLE_SPF: return False return spf.check(i=socket.gethostbyname(DNS_NAME.get_fqdn()), s=self.email, h=DNS_NAME.get_fqdn())
def run(self): # Get standard input 'email' email = self.getInput('email') # Get input from the execution of the MXRecord plugin records = self.getInput('MXRecord') # First information messages to say test is underway self.result.info('Starting SPF-test') results = [] statusCounts = {Plugin.STATUS_OK: 0, Plugin.STATUS_WARNING: 0, Plugin.STATUS_ERROR: 0} star = False # Loop through all MX records and perform the SPF test for record in records['mx_record']: host = record['host'] ip = record['ip'] passCode = 250 code = Plugin.STATUS_OK error = "" try: # Perform the actual SPF control using the spf module spf_res_ret, spf_res_code, spf_res_desc = spf.check(ip, email, host) # Check if the returned code is 250 and up the warning counter if it's not if spf_res_code != passCode: statusCounts[Plugin.STATUS_WARNING] += 1 # elif spf_res_code == 250 and spf_res_ret != 'none' and star == False: star = True except socket.error, e: code = Plugin.STATUS_WARNING if e[0] == 101: error = "network unreachable" elif e[0] == 111: error = "connection refused" elif e[0] == 110 or e[0] == 'timed out' or e == 'timed out': error = "connection timed out" else: error = "unable to connect" # Add information message if the test failed for this MX. We only see SPF # as a bonus feature, that's why we don't add a warning here if error != '': self.result.info('SPF-test failed for %s (%s)', (host, ip)) # We add a warning here bacause SPF exists but is not configured correctly elif spf_res_code != passCode: self.result.warning('SPF-test returned: %s (%s), %s for %s (%s), email: %s', (spf_res_ret, spf_res_code, spf_res_desc, host, ip, email)) else: self.result.info('SPF-test returned: %s (%s), %s for %s (%s), email: %s', (spf_res_ret, spf_res_code, spf_res_desc, host, ip, email)) # Add this test to the result from the SPF plugin results.append([host, ip, email, spf_res_ret, spf_res_code, spf_res_desc]) statusCounts[code] += 1
def check_spf(self,domain,addr): if "_spf" not in self.results[domain]: self.results[domain]["_spf"] = {} mxs = self.results[domain][addr]["mx"] for mx in mxs: if mx not in self.results[domain]["_spf"]: asd = spf.check(i=addr, s=domain, h=mx) self.results[domain]["_spf"][mx] = asd[0]
def do_test(self): if 'client_address' and 'helo_name' and 'sender' in self.headers: results = spf.check(i=self.headers['client_address'], h=self.headers['helo_name'], s=self.headers['sender'], receiver=socket.gethostname()) self.result['action'] = results[0] self.result['code'] = results[1] self.result['message'] = results[2] log.write("SPF check returns action='%s', code='%s', message='%s'"\ % (results[0], results[1], results[2]), LOG_DEBUG) return results else: log.write("Client address, helo name or sender missing from headers.", LOG_WARNING) raise GLPluginException, "Incomplete headers."
def main(): """ main function assigns arguments from docopt and calls spf.check() function """ # gets arguments from docopt arguments = docopt(__doc__) # assigns docopt arguments ipaddr = arguments['<ipaddr>'] host = arguments['<host>'] sender = arguments['<sender>'] verbose = arguments.get('--verbose') if verbose: print "script called with: " print arguments result = spf.check(i=ipaddr, s=sender, h=host) pprint(result)
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') return DUNNO starttime=time.time() clientinfo=suspect.get_client_info(self.config) if clientinfo==None: suspect.debug("pyspf not available, can not check") self._logger().warning("%s: SPF Check skipped, could not get client info"%(suspect.id)) suspect.set_tag('SPF.status','skipped') return DUNNO helo,ip,revdns=clientinfo tag,code,info=spf.check(i=ip,s=suspect.from_address,h=helo) suspect.set_tag("SPF.status",tag) suspect.debug("SPF status: %s (%s)"%(tag,info)) endtime=time.time() difftime=endtime-starttime suspect.tags['SPFCheck.time']="%.4f"%difftime return DUNNO
def auth(self, message_data=None, peer_ip=None, message=None): result_status = spf.check(i=peer_ip, s='@gmail.com', h='google.com')[0] if 'pass' in result_status: return True return False
if spfResult == 'Fail' or spfResult == 'Permerror': if action == 'quarantine': return(( 'QUARANTINE', 'SPF detected this as spam.' )) return(( 'REJECT', 'Sender failed SPF check' )) if spfResult == 'Temperror': if self.mode == 'smtp': return(( 'DEFER_IF_PERMIT', 'SPF temporary failure: "%s"' % spfReason )) else: return(( 'DUNNO', '' )) # SPF version 1 check else: try: res = spf.check(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', '' )) self.addHeaders.append('X-vPostMaster-SPF-Result: ' 'domain="%s" address="%s" result="%s"' % ( self.data['sender_domain'], self.data['client_address'], res[0] )) if res[0] not in [ 'pass', 'unknown', 'error' ]: if self.debug >= 3: syslog.syslog(syslog.LOG_DEBUG, 'checkSPF: Unknown response: "%s".' % repr(res)) if action == 'quarantine': return(( 'QUARANTINE', 'SPF detected this as spam.' )) return(( 'REJECT', 'Sender failed SPF check' ))
def _evaluate_spf(self): return spf.check( h=self.user.helo[0], i=self.user.helo[1], s=self.user.orig.addrstr[1:-1]) #cut off < and >
def check_spf(ip, mail_from, helo): res, _, reason = spf.check(ip, mail_from, helo) return SPFAuthenticationResult(result=res, reason=reason, smtp_mailfrom=mail_from, smtp_helo=helo)
def checkMail (message): outputFileHandle = None try: outputFileHandle = open('dmarcCheck.html', 'w') except: print "file error" sys.exit() htmlDMARCBox = "" htmlDKIMBox = "" htmlSPFBox = "" receivedHeader = "" fromHeader = "" #Read the message from the inbox headers = email.parser.Parser().parsestr(message) for field in headers.items(): if field[0] == "Received" and "[" in field[1] and "]" in field[1]: receivedHeader = field[1] pattern = re.compile(r'\[.*]') result = re.search(pattern, receivedHeader).group(0) pattern = re.compile(r'from .*? ') result2 = re.search(pattern, receivedHeader).group(0) subject = headers['subject'] #Variables needed for spf check #We need only the email address if "<" in headers['from'] and ">" in headers['from']: pattern = re.compile(r'\<.*>') fromHeader = re.search(pattern, headers['from']).group(0) fromHeader = fromHeader[1:-1] else: fromHeader = headers['from'] ipaddr = result[1:-1] host = result2[5:-1] # Perfom SPF and DKIM checks spfResult = spf.check(i=ipaddr,s=fromHeader,h=host) dkimResult = dkim.verify(message ,None) #Create HTML conentent according to the results of the test if (spfResult[0] == 'pass'): htmlSPFBox = """<tr class="success"> <td>SPF check passed <br><strong>↳</strong>""" + spfResult[2] + """</td> </tr>""" else: htmlSPFBox = """<tr class="danger"> <td>SPF check failed <br><strong>↳</strong>""" + spfResult[2] + """</td> </tr>""" if (dkimResult == True): htmlDKIMBox = """<tr class="success"> <td>DKIM check passed</td> </tr>""" else: htmlDKIMBox = """<tr class="danger"> <td>DKIM check failed</td> </tr>""" if (spfResult[0] == 'pass' or dkimResult == True): htmlDMARCBox = """<tr class="success"> <td>DMARC check passed</td> </tr>""" else: htmlDMARCBox = """<tr class="danger"> <td>DMARC check failed</td> </tr>""" html = """ <div class="well well-lg"> <h4><p class="text-center"><strong>DMARC test</strong></p></h4> <table class="table table-condensed"> <thead> <tr> <th>Result</th> </tr> <tr></tr> </thead> <tbody> <tr> <td>Subject: """ + subject + """</td> </tr> <tr><td></td></tr> """ + htmlDKIMBox + htmlSPFBox + """<tr><td></td></tr>""" + htmlDMARCBox + """ </tbody> </table> </div> """ outputFileHandle.write(html) outputFileHandle.close()
def run(self): # Get standard input 'email' email = self.getInput('email') # Get input from the execution of the MXRecord plugin records = self.getInput('MXRecord') # First information messages to say test is underway self.result.info('Starting SPF-test') results = [] statusCounts = { Plugin.STATUS_OK: 0, Plugin.STATUS_WARNING: 0, Plugin.STATUS_ERROR: 0 } star = False # Loop through all MX records and perform the SPF test for record in records['mx_record']: host = record['host'] ip = record['ip'] passCode = 250 code = Plugin.STATUS_OK error = "" try: # Perform the actual SPF control using the spf module spf_res_ret, spf_res_code, spf_res_desc = spf.check( ip, email, host) # Check if the returned code is 250 and up the warning counter if it's not if spf_res_code != passCode: statusCounts[Plugin.STATUS_WARNING] += 1 # elif spf_res_code == 250 and spf_res_ret != 'none' and star == False: star = True except socket.error, e: code = Plugin.STATUS_WARNING if e[0] == 101: error = "network unreachable" elif e[0] == 111: error = "connection refused" elif e[0] == 110 or e[0] == 'timed out' or e == 'timed out': error = "connection timed out" else: error = "unable to connect" # Add information message if the test failed for this MX. We only see SPF # as a bonus feature, that's why we don't add a warning here if error != '': self.result.info('SPF-test failed for %s (%s)', (host, ip)) # We add a warning here bacause SPF exists but is not configured correctly elif spf_res_code != passCode: self.result.warning( 'SPF-test returned: %s (%s), %s for %s (%s), email: %s', (spf_res_ret, spf_res_code, spf_res_desc, host, ip, email)) else: self.result.info( 'SPF-test returned: %s (%s), %s for %s (%s), email: %s', (spf_res_ret, spf_res_code, spf_res_desc, host, ip, email)) # Add this test to the result from the SPF plugin results.append( [host, ip, email, spf_res_ret, spf_res_code, spf_res_desc]) statusCounts[code] += 1
def checkMail (mailbox, outputFileHandle): htmlDMARCBox = "" htmlDKIMBox = "" htmlSPFBox = "" #Read the message from the inbox mailBoxFileHandle = open(mailbox,'r+') message = mailBoxFileHandle.read() headers = Parser().parsestr(message) receivedHeader = headers['Received'] #print headers.items() pattern = re.compile(r'\[.*]') result = re.search(pattern, receivedHeader).group(0) pattern = re.compile(r'from .*? ') result2 = re.search(pattern, receivedHeader).group(0) subject = headers['subject'] #Variables needed for spf check fromHeader = headers['from'] ipaddr = result[1:-1] host = result2[5:-1] # Perfom SPF and DKIM checks spfResult = spf.check(i=ipaddr,s=fromHeader,h=host) dkimResult = dkim.verify(message ,None) #Create HTML conentent according to the results of the test if (spfResult[0] == 'pass'): htmlSPFBox = """<tr class="success"> <td>SPF check passed <br><strong>↳</strong>""" + spfResult[2] + """</td> </tr>""" else: htmlSPFBox = """<tr class="danger"> <td>SPF check failed <br><strong>↳</strong>""" + spfResult[2] + """</td> </tr>""" if (dkimResult == True): htmlDKIMBox = """<tr class="success"> <td>DKIM check passed</td> </tr>""" else: htmlDKIMBox = """<tr class="danger"> <td>DKIM check failed</td> </tr>""" if (spfResult[0] == 'pass' or dkimResult == True): htmlDMARCBox = """<tr class="success"> <td>DMARC check passed</td> </tr>""" else: htmlDMARCBox = """<tr class="danger"> <td>DMARC check failed</td> </tr>""" html = """ <div class="well well-lg"> <h4><p class="text-center"><strong>DMARC test</strong></p></h4> <table class="table table-condensed"> <thead> <tr> <th>Result</th> </tr> <tr></tr> </thead> <tbody> <tr> <td>Subject: """ + subject + """</td> </tr> <tr><td></td></tr> """ + htmlDKIMBox + htmlSPFBox + """<tr><td></td></tr>""" + htmlDMARCBox + """ </tbody> </table> </div> """ outputFileHandle.write(html) outputFileHandle.close() # Empty the mail box for the the next test, remove this line if # you whish to keep the email. # (Hackish way of emtying the file contents) open(mailbox, 'w').close()