Changeset 158
- Timestamp:
- 04/03/10 23:11:14 (5 months ago)
- Files:
-
- 1 modified
-
trunk/misc/dns-o-matic.py (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/misc/dns-o-matic.py
r157 r158 17 17 import DNS 18 18 from netaddr import IPNetwork, IPAddress 19 from pprint import PrettyPrinter 19 20 20 21 DNS.DiscoverNameServers() … … 34 35 35 36 36 def RecursiveLookup(data,record,type,nameserver,astart=None,ptrstart=None): 37 r = None 38 new_data = {'record':record, 'results':[], 'status':None} 39 37 def RecursiveLookup(data,rec_lookup,type,nameserver,astart=None,ptrstart=None): 40 38 # exit when a request loop is detected 41 39 if type == 'PTR': 42 40 if ptrstart == None: 43 ptrstart = record 44 elif ptrstart == record: 45 data['results'].append(new_data) 46 return data 47 else: 48 ptrstart = record 41 ptrstart = rec_lookup 42 elif ptrstart == rec_lookup: 43 return 44 else: 45 ptrstart = rec_lookup 49 46 else: 50 47 if astart == None: 51 astart = record 52 elif astart == record: 53 data['results'].append(new_data) 54 return data 55 else: 56 astart = record 57 58 # reverse lookup request gives you all the hostnames that the given ip address resolves to 48 astart = rec_lookup 49 elif astart == rec_lookup: 50 return 51 else: 52 astart = rec_lookup 53 54 r = None 59 55 if type == 'PTR': 60 rec = IPAddress(record) 56 # reverse lookup request gives you all the hostnames that the given ip address resolves to 57 rec = IPAddress(rec_lookup) 61 58 r = Request(rec.reverse_dns,type,nameserver) 62 63 # forward lookup request gives you all the ip addresses that the given hostname resolves to 64 else: 65 r = Request(record,type,nameserver) 66 67 # make note of status message and recurse if there were answers 59 else: 60 # forward lookup request gives you all the ip addresses that the given hostname resolves to 61 r = Request(rec_lookup,type,nameserver) 62 63 # we shouldn't ever time out 68 64 if r == None: 69 new_data['status'] = 'TIMEOUT' 70 data['results'].append(new_data) 71 else: 72 new_data['status'] = r.header['status'] 73 for rec,rec_type in [(x['data'],x['type']) for x in r.answers]: 65 sys.stderr.write("ERROR: Timed out querying for %s records from %s\n" % (type, nameserver)) 66 sys.exit(1) 67 68 # loop through all the answers 69 if r.header['status'] == 'NOERROR': 70 for rec_result,rec_type in [(x['data'],x['type']) for x in r.answers]: 74 71 75 72 # despite only ever asking for PTR or A records, we sometimes get CNAMEs, so discard them 76 73 if rec_type not in set([DNS.Type.A, DNS.Type.PTR]): 77 74 continue 75 76 # add to the list of answers 77 answer = { 78 'ns' : nameserver, 79 'lookup_of' : rec_lookup, 80 'lookup_type' : type, 81 'resolves_to' : rec_result, 82 'status' : r.header['status'], 83 'subrecords' : [], 84 } 85 data.append(answer) 86 87 # rinse and repeat 78 88 if type == 'PTR': 79 RecursiveLookup( new_data,rec,'A',nameserver,astart,ptrstart)89 RecursiveLookup(answer['subrecords'],rec_result,'A', nameserver,astart,ptrstart) 80 90 else: 81 RecursiveLookup(new_data,rec,'PTR',nameserver,astart,ptrstart) 82 data['results'].append(new_data) 91 RecursiveLookup(answer['subrecords'],rec_result,'PTR',nameserver,astart,ptrstart) 92 else: 93 # add the error to the list of answers 94 answer = { 95 'ns' : nameserver, 96 'lookup_of' : rec_lookup, 97 'lookup_type' : type, 98 'resolves_to' : '', 99 'status' : r.header['status'], 100 'subrecords' : [], 101 } 102 data.append(answer) 83 103 84 104 … … 130 150 131 151 def GetSubnetAnalysis(nameservers,subnet): 132 data = {'subnet':subnet, 'nameservers':[], 'addresses':[]} 133 primary = -1 134 for i,(ns,pri) in enumerate(nameservers): 152 data = {'subnet':str(subnet), 'nameservers':[], 'addresses':[]} 153 154 # make a note of which is the primary nameserver 155 primary = '' 156 for ns,pri in nameservers: 135 157 data['nameservers'].append({'name':ns, 'primary':pri}) 136 158 if pri: 137 primary = i159 primary = ns 138 160 139 161 # iterate through all valid addresses in the subnet 140 sys.stderr.write(" Subnet %s...\n" % str(subnet));162 sys.stderr.write("Processing Subnet: %s\n" % str(subnet)) 141 163 for ip in [str(x) for x in list(subnet) if x != subnet.broadcast and x != subnet.ip]: 142 sys.stderr.write("Processing %s\n" % ip); 164 sys.stderr.write(".") 165 166 # request the crap out of the DNS servers 143 167 address = {'ip':ip, 'results':[]} 144 168 for ns,pri in nameservers: 145 RecursiveLookup(address ,ip,'PTR',ns)169 RecursiveLookup(address['results'],ip,'PTR',ns) 146 170 147 171 # forget about addresses that don't have records in *any* nameservers 148 172 for result in address['results']: 149 if result['status'] == 'NOERROR':173 if result['status'] != 'NXDOMAIN': 150 174 data['addresses'].append(address) 151 175 break 176 sys.stderr.write("\n") 152 177 153 178 # iterate through all addresses for which we have results 154 for address in data['addresses']:155 for ns_result in address['results']:156 FindValidLoops(ns_result)179 # for address in data['addresses']: 180 # for ns_result in address['results']: 181 # FindValidLoops(ns_result) 157 182 return data 158 183 … … 160 185 def RecursivePrintResults(data,level=0): 161 186 # display the record we're looking up 162 if data['valid']: 163 style = "class='good'" 164 else: 165 style = "" 166 if not data['status'] and len(data['results']) == 0: 167 print " <p %s style='padding-left:%spx'><span class='record'>%s</span></p>" % (style, `level * 20`, data['record']) 168 else: 169 print " <p %s style='padding-left:%spx'><span class='record'>%s</span> resolves to:</p>" % (style, `level * 20`, data['record']) 170 171 # recursively display lookup results or show error 172 next_level = level + 1 173 if len(data['results']) > 0: 174 for result in data['results']: 175 RecursivePrintResults(result,next_level) 176 elif data['status']: 177 print " <p style='padding-left:%spx'><span class='record'>%s</span></p>" % (`next_level * 20`, data['status']) 187 if data['resolves_to'] != '': 188 print " <p style='padding-left:%spx'><span class='record'>%s</span> resolves to: <span class='record'>%s</span></p>" % (`level * 20`, data['lookup_of'], data['resolves_to']) 189 else: 190 print " <p style='padding-left:%spx'><span class='record'>%s</span> does not resolve to anything!</p>" % (`level * 20`, data['lookup_of']) 191 192 # recursively display subrecords 193 if len(data['subrecords']) > 0: 194 for rec in data['subrecords']: 195 RecursivePrintResults(rec,level + 1) 178 196 179 197 180 198 def PrintSubnetAnalysis(data): 181 print "<h2>Analysis of the %s subnet</h2>" % data['subnet'] 182 print "<table border='1'>" 199 subnet_id = "subnet-" + data['subnet'].replace('/','-').replace('.','-') 200 print "<h2 id='%s_heading'>Analysis of the %s subnet</h2>" % (subnet_id, data['subnet']) 201 print "<p><a class='debugs_on' id='%s_on' href='#%s_heading'>Show Debugs</a>" % (subnet_id, subnet_id) + \ 202 "<a class='debugs_off' id='%s_off' href='#%s_heading'>Hide Debugs</a></p>" % (subnet_id, subnet_id) 203 print "<table id='%s_table' border='1'>" % subnet_id 183 204 184 205 heading = "<tr><th>address</th>" … … 189 210 heading += "<th>%s</th>" % ns['name'] 190 211 heading += "</tr>" 191 212 192 213 for i,address in enumerate(data['addresses']): 193 214 if i % 25 == 0: 194 215 print heading 195 216 print "<tr>\n <td><p>%s</p></td>" % address['ip'] 196 for ns _result in address['results']:217 for ns in data['nameservers']: 197 218 print " <td>" 198 RecursivePrintResults(ns_result) 219 for result in [x for x in address['results'] if x['ns'] == ns['name']]: 220 RecursivePrintResults(result) 199 221 print " </td>" 200 222 print "</tr>" 201 223 print "</table>" 202 224 203 # for debugging 204 import pprint 205 print "<pre style='display:none;'>" 206 pp = pprint.PrettyPrinter(indent=2) 225 # print the raw data structure for debugging 226 print "<pre id='%s_debugs' style='display:none;'>" % subnet_id 227 pp = PrettyPrinter(indent=2) 207 228 pp.pprint(data) 208 229 print "</pre>" … … 216 237 <script type="text/javascript"> 217 238 jQuery(document).ready(function($) { 218 $("a#debugs_on").css('display', 'inline'); 219 $("a#debugs_on").click(function() { 220 $("pre").css('display', 'block'); 221 $("table").css('display', 'none'); 222 $("a#debugs_on").css('display', 'none'); 223 $("a#debugs_off").css('display', 'inline'); 239 /* display the show debugs buttons by default */ 240 $("a.debugs_on").css('display', 'inline'); 241 242 /* show debugs button click event callback */ 243 $("a.debugs_on").click(function() { 244 var subnet = "#" + $(this).attr('id').split('_')[0]; 245 $(subnet+"_debugs").css('display', 'block'); 246 $(subnet+"_table").css('display', 'none'); 247 $(subnet+"_on").css('display', 'none'); 248 $(subnet+"_off").css('display', 'inline'); 224 249 }); 225 $("a#debugs_off").click(function() { 226 $("pre").css('display', 'none'); 227 $("table").css('display', 'block'); 228 $("a#debugs_on").css('display', 'inline'); 229 $("a#debugs_off").css('display', 'none'); 250 251 /* hide debugs button click event callback */ 252 $("a.debugs_off").click(function() { 253 var subnet = "#" + $(this).attr('id').split('_')[0]; 254 $(subnet+"_debugs").css('display', 'none'); 255 $(subnet+"_table").css('display', 'table'); 256 $(subnet+"_on").css('display', 'inline'); 257 $(subnet+"_off").css('display', 'none'); 230 258 }); 231 259 }); … … 234 262 th { 235 263 font-family:sans-serif; 264 padding:5px 0px; 236 265 } 237 266 td { … … 240 269 font-size:0.75em; 241 270 color:#666; 271 padding:5px; 242 272 } 243 273 td p { … … 249 279 color:black; 250 280 } 251 .good { 252 background-color:#cec; 253 } 254 .good .record { 255 color:#393; 256 } 257 .bad { 258 background-color:#d99; 281 .debugs_on, .debugs_off { 282 display:none; 259 283 } 260 284 </style> … … 262 286 <body> 263 287 <h1>DNS-o-Matic Report</h1> 264 <a id='debugs_on' href='#' style='display:none;'>Show Debugs</a>265 <a id='debugs_off' href='#' style='display:none;'>Hide Debugs</a>266 288 """ 267 289 268 290 domain = 'cse-servelec.com' 269 subnets = [IPNetwork('194.62.153.0/24'), 291 subnets = [ 292 IPNetwork('194.62.153.0/24'), 270 293 IPNetwork('194.62.154.0/24'), 271 294 ]