Skip to content

Instantly share code, notes, and snippets.

@lanbugs
Created June 22, 2018 22:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lanbugs/b223e16ae52e681bb5c9401c36fd5f1a to your computer and use it in GitHub Desktop.
Save lanbugs/b223e16ae52e681bb5c9401c36fd5f1a to your computer and use it in GitHub Desktop.
Resolve all known ip addresses from spf record and generate cidr map for postfix
#!/usr/bin/env python
#
# get_subnets_of_spf_record_mynetwoks.py
# Resolve all known ip addresses from spf record and generate cidr map for postfix
#
# Version 1.0
# Written by Maximilian Thoma (http://www.lanbugs.de)
#
# Checkout blog article:
# https://lanbugs.de/howtos/linux/subnetze-und-ip-adressen-extrahieren-aus-spf-records-z-b-office365-oder-google-apps-for-business/
#
# The generated files can be used in postfix config with for example mynetworks = cidr:/etc/postfix/<generated_file>
#
# This program is free software; you can redistribute it and/or modify it under the terms of the
# GNU General Public License as published by the Free Software Foundation;
# either version 2 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program;
# if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
# MA 02110, USA
#
#
# Requirements:
# dnspython module -> pip install dnspython
#
import dns.resolver
from dns.exception import DNSException
import re
import sys
# Look for DNS Record at:
#
# "jobname": {
# "domain": "domainname",
# "file": "output_file",
# }
#
#
lookup_spf = {
# Google Apps for Business
"google": {
"domain": "google.com",
"file" : "/etc/postfix/networks/google",
},
# Office365
"office365": {
"domain": "spf.protection.outlook.com",
"file" : "/etc/postfix/networks/office365",
},
}
############################################################################################
def getspf(record, filehandler):
# Init Resolver
myResolver = dns.resolver.Resolver()
try:
# Try to lookup TXT record
myAnswer = myResolver.query(record,"TXT")
except DNSException:
sys.stderr.write("Failed to query record, SPF broken.")
return
results = []
for rdata in myAnswer:
# Get string out of records
for txt_string in rdata.strings:
# Append to SPF Records buffer if "spf" in string
if "spf" in txt_string:
results.append(txt_string)
# If results >=1
if len(results) >= 1:
# Work on records
for spf in results:
# Split parts
parts = spf.split(" ")
# Check parts
for part in parts:
s_include = re.match(r"^include:(?P<domain>.*)$", part)
s_ip4 = re.match(r"^ip4:(?P<ip4>.*)$", part)
s_ip6 = re.match(r"^ip6:(?P<ip6>.*)$", part)
# If in part "include" found, next round
if s_include:
getspf(s_include.group('domain'), filehandler)
# elif ip4 found
elif s_ip4:
filehandler.write(s_ip4.group('ip4') + " OK\n")
# elif ip6 found
elif s_ip6:
filehandler.write("[" + s_ip6.group('ip6').replace("/","]/") + " OK\n")
# else no valid record
else:
pass
# no results
else:
sys.stderr.write("No results")
pass
def main():
# Working on jobs
for jobname, config in lookup_spf.iteritems():
print "Working on job %s" % jobname
# open file
filehandler = open(config['file'], 'w')
# start query spf records
getspf(config['domain'], filehandler)
# close file
filehandler.close()
#getspf(lookup_spf)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment