Created
January 31, 2015 09:32
-
-
Save pierky/59f995bf98f3c8a87e41 to your computer and use it in GitHub Desktop.
Python script used to analyze data for my blog post "DNSSEC: ECDSA-aware resolvers seen by RIPE Atlas"
This file contains 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
import urllib2 | |
import json | |
import os.path | |
import sys | |
from ripe.atlas.sagan import DnsResult | |
from pprint import pprint | |
RIPE_ATLAS_KEY = "" | |
def GetRIPEAtlasLatestMsmResults( MsmID, RIPEAtlasKey = "", CacheFile = None ): | |
if os.path.isfile( CacheFile or "%d.json" % MsmID ): | |
MsmFile = open( CacheFile or "%d.json" % MsmID, "r" ) | |
JSONResponseData = MsmFile.read() | |
MsmFile.close() | |
else: | |
HTTPRequest = urllib2.Request( "https://atlas.ripe.net/api/v1/measurement-latest/%d/?key=%s" % ( MsmID, RIPEAtlasKey ) ) | |
HTTPRequest.add_header( "Content-Type", "application/json" ) | |
HTTPRequest.add_header( "Accept", "application/json" ) | |
JSONResponseData = urllib2.urlopen( HTTPRequest ).read() | |
LatestResults = json.loads( JSONResponseData ) | |
if not os.path.isfile( CacheFile or "%d.json" % MsmID ): | |
MsmFile = open( CacheFile or "%d.json" % MsmID, "w" ) | |
MsmFile.write( JSONResponseData ) | |
MsmFile.close | |
Results = [] | |
for ProbeID in LatestResults: | |
Results.append( LatestResults[ProbeID][0] ) | |
return Results | |
Measurements = { | |
"West": { "MsmID_RIPE": 1849609, "MsmID_CF": 1849622 }, | |
"North-Central": { "MsmID_RIPE": 1849610, "MsmID_CF": 1849623 }, | |
"South-Central": { "MsmID_RIPE": 1849611, "MsmID_CF": 1849624 }, | |
"North-East": { "MsmID_RIPE": 1849612, "MsmID_CF": 1849625 }, | |
"South-East": { "MsmID_RIPE": 1849613, "MsmID_CF": 1849626 } | |
} | |
""" | |
Probes = { | |
"<probe_id>": { | |
"Area": "<area>", | |
"<target>": { | |
"Status": "<OK|malformed|error (<err_descr>)>", | |
"AtLeastOneAD": <bool>, | |
... | |
} | |
"Destinations": { | |
"<dest_addr>": { | |
"RIPE": { "AD": <bool>, "Answers": "<answers>" }, | |
"CF": { "AD": <bool>, "Answers": "<answers>" } | |
} | |
} | |
}, | |
"<probe_id>": { ... } | |
} | |
""" | |
Probes = {} | |
def DoArea( Area ): | |
DoTarget( Area, "RIPE" ) | |
DoTarget( Area, "CF" ) | |
def DoTarget( Area, Target ): | |
MsmID = Measurements[Area]["MsmID_%s" % Target] | |
MsmResults = GetRIPEAtlasLatestMsmResults( MsmID, RIPE_ATLAS_KEY ) | |
for JSONResult in MsmResults: | |
Result = DnsResult( JSONResult, on_malformation=DnsResult.ACTION_FAIL, on_error=DnsResult.ACTION_FAIL ) | |
ProbeID = str(Result.probe_id) | |
if not ProbeID in Probes: | |
Probes[ProbeID] = {} | |
Probes[ProbeID]["Area"] = Area | |
Probes[ProbeID][Target] = {} | |
if Result.is_malformed: | |
Probes[ProbeID][Target]["Status"] = "malformed" | |
elif Result.is_error: | |
Probes[ProbeID][Target]["Status"] = "error (%s)" % Result.error_message | |
else: | |
Probes[ProbeID][Target]["Status"] = "parsing error" # changed later if everything is OK | |
Probes[ProbeID][Target]["AtLeastOneAD"] = False | |
Probes[ProbeID][Target]["Responses"] = [] | |
if not "Destinations" in Probes[ProbeID]: | |
Probes[ProbeID]["Destinations"] = {} | |
for Response in Result.responses: | |
try: | |
if Response.abuf.header: | |
NewResponse = {} | |
NewResponse["DstAddr"] = Response.destination_address | |
if Response.abuf.header.ad: | |
Probes[ProbeID][Target]["AtLeastOneAD"] = True | |
NewResponse["Header"] = "%s, AN %s" % ( str( Response.abuf.header ), Response.abuf.header.ancount ) | |
NewResponse["AD"] = Response.abuf.header.ad | |
NewResponse["Answers"] = "" | |
Answers = [] | |
for Answer in Response.abuf.answers: | |
NewAnswer = Answer.type | |
try: | |
NewAnswer = NewAnswer + " " + Answer.address | |
except: | |
pass | |
try: | |
NewAnswer = NewAnswer + " " + Answer.target | |
except: | |
pass | |
Answers.append( NewAnswer ) | |
NewResponse["Answers"] = ",".join( Answers ) | |
if not Response.destination_address in Probes[ProbeID]["Destinations"]: | |
Probes[ProbeID]["Destinations"][Response.destination_address] = {} | |
Probes[ProbeID]["Destinations"][Response.destination_address][Target] = { | |
"Header": NewResponse["Header"], | |
"AD": NewResponse["AD"], | |
"Answers": NewResponse["Answers"] } | |
Probes[ProbeID][Target]["Status"] = "OK" | |
Probes[ProbeID][Target]["Responses"].append( NewResponse ) | |
except: | |
pass | |
for Area in Measurements.keys(): | |
DoArea( Area ) | |
sys.stdout.write("ProbeID;Area;RIPE Status;CF Status;RIPE AD; CF AD") | |
for DestN in [ 1, 2, 3 ]: | |
sys.stdout.write(";Dest%s IP" % DestN) | |
for Target in [ "RIPE", "CF" ]: | |
sys.stdout.write(";Dest%s %s Header" % ( DestN, Target ) ) | |
sys.stdout.write(";Dest%s %s AD" % ( DestN, Target ) ) | |
sys.stdout.write(";Dest%s %s Answers" % ( DestN, Target ) ) | |
print("") | |
for ProbeID in Probes.keys(): | |
Probe = Probes[ProbeID] | |
sys.stdout.write("%s;%s" % ( ProbeID, Probe["Area"] ) ) | |
for Target in [ "RIPE", "CF" ]: | |
if Target in Probe: | |
sys.stdout.write(";%s" % Probe[Target]["Status"] ) | |
else: | |
sys.stdout.write(";no data") | |
if "RIPE" in Probe and "CF" in Probe and Probe["RIPE"]["Status"] == "OK" and Probe["CF"]["Status"] == "OK": | |
sys.stdout.write(";%s;%s" % ( Probe["RIPE"]["AtLeastOneAD"], Probe["CF"]["AtLeastOneAD"] ) ) | |
for DestinationID in Probe["Destinations"].keys(): | |
Destination = Probe["Destinations"][DestinationID] | |
sys.stdout.write(";%s" % DestinationID) | |
for Target in [ "RIPE", "CF" ]: | |
if Target in Destination: | |
try: | |
sys.stdout.write(";%s;%s;%s" % ( Destination[Target]["Header"], Destination[Target]["AD"], Destination[Target]["Answers"] ) ) | |
except: | |
print("") | |
print("ERROR") | |
pprint(Probe) | |
raise | |
else: | |
sys.stdout.write(";no data;no data;no data") | |
print("") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment