85 lines
1.8 KiB
Python
Executable File
85 lines
1.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import functools
|
|
import json
|
|
import socket
|
|
import sys
|
|
|
|
'''
|
|
Takes as input a list of domain names to test. Return wether they are
|
|
IPv4/IPv6-compatible.
|
|
|
|
Usage:
|
|
|
|
> cat test.txt
|
|
baionet.fr
|
|
google.com
|
|
|
|
> cat test.txt | ./dns-sacha.py | jq
|
|
|
|
[
|
|
{
|
|
"host": "baionet.fr",
|
|
"v4": true,
|
|
"v6": false
|
|
},
|
|
{
|
|
"host": "google.com",
|
|
"v4": true,
|
|
"v6": true
|
|
}
|
|
]
|
|
'''
|
|
|
|
class UrlIp:
|
|
'''
|
|
Struct wrapping a single record entry. Does it have IPv4 support?
|
|
IPv6 support?
|
|
'''
|
|
def __init__(self, host, v4, v6):
|
|
self.host = host
|
|
self.v4 = v4
|
|
self.v6 = v6
|
|
|
|
def get_host_records(host):
|
|
'''
|
|
Folds all the DNS entries of a Host and looks whether or not we
|
|
can find v4 and v6 records.
|
|
|
|
reduce == left fold in the python world btw...
|
|
'''
|
|
records = socket.getaddrinfo(host, 80)
|
|
return(functools.reduce(_test_record,records,UrlIp(host,False,False)))
|
|
|
|
def _test_record(urlip, rec):
|
|
'''
|
|
Fold function for get_host_records. Too big for a lambda not to
|
|
get messy.
|
|
|
|
Gotta love Python...
|
|
'''
|
|
(family, _rtype, proto, _canonname, _sockaddr) = rec
|
|
if family == socket.AF_INET:
|
|
urlip.v4 = True
|
|
elif family == socket.AF_INET6:
|
|
urlip.v6 = True
|
|
return urlip
|
|
|
|
def parse_hosts(file_name):
|
|
with open(file_name, 'r') as f:
|
|
return f.readlines()
|
|
|
|
def render_results(results):
|
|
'''
|
|
Takes an array of UrlIp and renders that to json.
|
|
|
|
Python's json.dumps only works with dictionnaries, not classes.
|
|
Extracting the dictionnary representation of the class.
|
|
'''
|
|
return(json.dumps([r.__dict__ for r in results]))
|
|
|
|
if __name__ == '__main__':
|
|
entries = [l.strip() for l in sys.stdin.readlines()]
|
|
test_results = [get_host_records(entry) for entry in entries]
|
|
print(render_results(test_results))
|