-
-
Save beppe9000/546a648335f5f04186264942ac66258e to your computer and use it in GitHub Desktop.
Extract the IP addresses from SPF records.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# Purpose: Print the list of ip addresses from SPF records | |
# Author: beppe9000 | |
import dns | |
from dns import resolver | |
from collections import defaultdict | |
import re | |
import sys | |
RE_PARSE = re.compile(r'(ip4|ip6|include|redirect)[:=](.*)', re.IGNORECASE) | |
MAX_RECURSION = 5 | |
def dns_txt(domain): | |
response = [] | |
try: | |
answers = dns.resolver.resolve(domain, 'TXT') | |
except dns.exception.DNSException as err: | |
print(err, file=sys.stderr) | |
return None | |
#print (' query qname:', answers.qname, ' num ans.', len(answers)) | |
for rdata in answers: | |
for txt_string in rdata.strings: | |
#print (' TXT: ', txt_string) | |
if (txt_string.decode().startswith('v=spf1')): | |
#print (' SPF: ', str(txt_string)) | |
response.append(txt_string.decode()) | |
#print(dir(answers)) | |
#return "FUCKU" | |
return response | |
def dns_parse(txt_field): | |
# print("Parsing...") | |
resp = defaultdict(set) | |
for rec in txt_field: | |
fields = rec.split() | |
for field in fields: | |
match = RE_PARSE.match(field) | |
if match: | |
resp[match.group(1)].add(match.group(2) if not match.group(1).startswith("ipv6") else '"'+match.group(2)+'"') | |
#print("MATCH [",match.group(1),"] => ",match.group(2)) | |
return resp | |
def process(domain): | |
domains = [domain] | |
ip_addresses = set() | |
for cnt in range(MAX_RECURSION): | |
includes = set() | |
for dom in domains: | |
txt = dns_txt(dom) | |
if not txt: | |
continue | |
spf = dns_parse(txt) | |
ip_addresses |= spf.get('ip4', set()) | |
ip_addresses |= spf.get('ip6', set()) | |
includes |= spf.get('include', set()) | |
includes |= spf.get('redirect', set()) | |
if not includes: | |
break | |
domains = includes | |
return ip_addresses | |
def test(): | |
#for v in dns_txt("_spf.google.com"): | |
# print('VAL: ', v.to_text()) | |
r1 = dns_txt("_spf.google.com") | |
for txt_string in r1: | |
print (' SPF: ', txt_string) | |
spf = dns_parse(r1) | |
#for item in spf.items(): | |
# print(item) | |
includes = set() | |
ip_addresses = set() | |
ip_addresses |= spf.get('ip4', set()) | |
includes |= spf.get('include', set()) | |
print("INCLUDES: ",str(includes)) | |
print("IP ADDRS: ",str(ip_addresses)) | |
#print (' PARSED: ', str(txt_string)) | |
process("_spf.google.com") | |
if __name__ == '__main__': | |
whitelist=set() | |
if(len(sys.argv)>1): | |
with open(sys.argv[1]) as fd: | |
for line in fd: | |
line = line.strip() | |
for ip in process(line): | |
whitelist.add(ip) | |
else: | |
for ip in process("_spf.google.com"): | |
whitelist.add(ip) | |
for ip in sorted(whitelist): | |
print(ip) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment