A small utility to fetch information about IPv6 addresses and possibly also any associated IPv4 address.
リビジョン | 6ef79e378e58aa3a729278cfd88ba86d60a7cf89 (tree) |
---|---|
日時 | 2013-02-27 02:19:18 |
作者 | Eric Hopper <hopper@omni...> |
コミッター | Eric Hopper |
Initial script checkin. Could probably use a distutils setup.py.
@@ -0,0 +1,129 @@ | ||
1 | +#!/usr/bin/python | |
2 | + | |
3 | +import socket | |
4 | +import sys | |
5 | +import struct | |
6 | +import dns.reversename | |
7 | +import dns.resolver | |
8 | +import dns.exception | |
9 | +import dns.rdatatype as dnstype | |
10 | + | |
11 | +TYPE_6TO4 = 0 | |
12 | +TYPE_TEREDOSERVER = 1 | |
13 | +TYPE_TEREDONAT = 2 | |
14 | +TYPE_PLAINIPv4 = 3 | |
15 | + | |
16 | +class BadAddress(RuntimeError): | |
17 | + def __init__(self, addr): | |
18 | + super(BadAddress, self).__init__( | |
19 | + "I'm expecting a numeric IPv4 or IPv6 address, got %s", (addr,), addr | |
20 | + ) | |
21 | + self.addr = addr | |
22 | + | |
23 | +def analyze_addr(s): | |
24 | + try: | |
25 | + raw = socket.inet_pton(socket.AF_INET, s) | |
26 | + return analyze_ipv4(s, raw, TYPE_PLAINIPv4) | |
27 | + except socket.error: | |
28 | + pass | |
29 | + try: | |
30 | + raw = socket.inet_pton(socket.AF_INET6, s) | |
31 | + return analyze_ipv6(s, raw) | |
32 | + except socket.error: | |
33 | + pass | |
34 | + raise BadAddress(s) | |
35 | + | |
36 | +def analyze_ipv4(s, raw, addrtype): | |
37 | + numaddr = struct.unpack('!L', raw)[0] | |
38 | + print "Got IPv4 address: %s\n - in raw hex 0x%08x" % (s, numaddr) | |
39 | + if addrtype == TYPE_TEREDONAT: | |
40 | + print " - in obfuscated hex 0x%08x" % (numaddr ^ 0xffffffff,) | |
41 | + canon = socket.inet_ntop(socket.AF_INET, raw) | |
42 | + if canon != s: | |
43 | + print " - Canonical %s" % (canon,) | |
44 | + else: | |
45 | + canon = s | |
46 | + revname = dns.reversename.from_address(canon) | |
47 | + answer = None | |
48 | + try: | |
49 | + answer = dns.resolver.query(revname, 'PTR') | |
50 | + except dns.exception.DNSException: | |
51 | + pass | |
52 | + if addrtype == TYPE_6TO4: | |
53 | + print " - The 6to4 IPv6 prefix is 2002:%x:%x::/48" % \ | |
54 | + (numaddr >> 16, numaddr & 0xffff) | |
55 | + while (answer is None) and (len(revname) > 4): | |
56 | + revname = revname.parent() | |
57 | + try: | |
58 | + answer = dns.resolver.query(revname, 'NS') | |
59 | + except dns.exception.DNSException: | |
60 | + pass | |
61 | + if answer is None: | |
62 | + print " - *** Reverse lookup failed for %s ***" % (revname,) | |
63 | + else: | |
64 | + if len(revname) != 7: | |
65 | + print " - *** The initial PTR lookup failed ***" | |
66 | + print " - %s" % (revname,) | |
67 | + for result in answer.rrset: | |
68 | + print " - %s: %s" % (dnstype.to_text(result.rdtype), result) | |
69 | + | |
70 | +def analyze_ipv6(s, raw): | |
71 | + numaddr = struct.unpack('!QQ', raw) | |
72 | + numaddr = numaddr[0] * 2**64 + numaddr[1] | |
73 | + print "Got IPv6 address: %s\n - in raw hex 0x%016x" % (s, numaddr) | |
74 | + canon = socket.inet_ntop(socket.AF_INET6, raw) | |
75 | + if canon != s: | |
76 | + print " - Canonical %s" % (canon,) | |
77 | + else: | |
78 | + canon = s | |
79 | + if ((numaddr >> 125) & 0x7) != 1: | |
80 | + print " - === Not a globally routable address" | |
81 | + return | |
82 | + revname = dns.reversename.from_address(canon) | |
83 | + answer = None | |
84 | + try: | |
85 | + answer = dns.resolver.query(revname, 'PTR') | |
86 | + except dns.exception.DNSException: | |
87 | + pass | |
88 | + while (answer is None) and (len(revname) > 7): | |
89 | + revname = revname.parent() | |
90 | + try: | |
91 | + answer = dns.resolver.query(revname, 'NS') | |
92 | + except dns.exception.DNSException: | |
93 | + pass | |
94 | + if answer is not None: | |
95 | + if len(revname) != 35: | |
96 | + print " - *** The initial PTR lookup failed ***" | |
97 | + print " - %s" % (revname,) | |
98 | + for result in answer.rrset: | |
99 | + print " - %s: %s" % (dnstype.to_text(result.rdtype), result) | |
100 | + else: | |
101 | + print " - *** Unable to reverse lookup any information ***" | |
102 | + if (numaddr >> 112) == 0x2002: | |
103 | + raw4 = struct.pack('!L', (numaddr >> 80) & 0xffffffff) | |
104 | + s4 = socket.inet_ntop(socket.AF_INET, raw4) | |
105 | + print " - 6to4 address %s" % (s4,) | |
106 | + print "-+-+-+-" | |
107 | + analyze_ipv4(s4, raw4, TYPE_6TO4) | |
108 | + print "-+-+-+-" | |
109 | + elif (numaddr >> 96) == 0x20010000: | |
110 | + rawnat4 = struct.pack('!L', (numaddr & 0xffffffff) ^ 0xffffffff) | |
111 | + rawserv4 = struct.pack('!L', (numaddr >> 64) & 0xffffffff) | |
112 | + snat4 = socket.inet_ntop(socket.AF_INET, rawnat4) | |
113 | + sserv4 = socket.inet_ntop(socket.AF_INET, rawserv4) | |
114 | + print " - Teredo NAT (the public IPv4 address): %s" % (snat4,) | |
115 | + print " - Teredo server (assigner of the IPv6 address): %s" % (sserv4,) | |
116 | + print "-+-+-+- (Teredo NAT (the public IPv4 address of the system))" | |
117 | + analyze_ipv4(snat4, rawnat4, TYPE_TEREDONAT) | |
118 | + print "-+-+-+- (Teredo server (probably not important))" | |
119 | + analyze_ipv4(sserv4, rawserv4, TYPE_TEREDOSERVER) | |
120 | + | |
121 | +if __name__ == '__main__': | |
122 | + if len(sys.argv) > 1: | |
123 | + print "===========" | |
124 | + for x in sys.argv[1:]: | |
125 | + try: | |
126 | + analyze_addr(x) | |
127 | + except BadAddress, a: | |
128 | + print >>sys.stderr, "%s doesn't appear to be a valid numeric IPv4 or IPv6 address." % (x, ) | |
129 | + print "===========" |