Created
August 14, 2022 19:09
-
-
Save silvio2402/22bc8929ba82c1d9c4a12503f86eb45b to your computer and use it in GitHub Desktop.
Query RDAP information using a server from IANA's bootstrap file
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 http.client | |
import urllib.parse | |
import json | |
import ipaddress | |
def rdap_fetch_bootstrap( | |
obj_type: str, bootstrap_server_base="https://data.iana.org/rdap", fetch_url=None | |
): | |
if not fetch_url: | |
fetch_url = "".join([bootstrap_server_base, "/", obj_type, ".json"]) | |
url_parse = urllib.parse.urlparse(fetch_url) | |
https = url_parse.scheme == "https" | |
port = http.client.HTTPS_PORT if https else http.client.HTTP_PORT | |
conn = http.client.HTTPSConnection(url_parse.netloc, port) | |
# Send HTTPS request | |
conn.request("GET", url_parse.path) | |
res = conn.getresponse() | |
if res.status != 200: | |
raise Exception() | |
data = json.loads(res.read()) | |
return data | |
def rdap_find_in_bootstrap(obj_type: str, obj_query: str, bootstrap: dict): | |
if obj_type == "asn": | |
for service in bootstrap["services"]: | |
for value in service[0]: | |
range: list[str] = value.split("-") | |
range0 = int(range[0]) | |
obj_int = int(obj_query) | |
if len(range) > 1: | |
range1 = int(range[1]) | |
if not (range0 <= obj_int and obj_int <= range1): | |
continue | |
else: | |
if obj_int != range0: | |
continue | |
return service[1] | |
elif obj_type == "dns": | |
tld = obj_query.split(".")[-1] | |
for service in bootstrap["services"]: | |
for value in service[0]: | |
if value != tld: | |
continue | |
return service[1] | |
elif obj_type == "ipv4" or obj_type == "ipv6": | |
for service in bootstrap["services"]: | |
for value in service[0]: | |
value_net = ipaddress.ip_network(value) | |
query_ip = ipaddress.ip_address(obj_query) | |
if query_ip not in value_net: | |
continue | |
return service[1] | |
return [] | |
def rdap( | |
obj_type: str, | |
obj_query: str, | |
rdap_server_base="https://rdap.org", | |
redirects=0, | |
query_url=None, | |
): | |
if not query_url: | |
# The query URL is constructed by concatenating the base URL with the entity path segment | |
query_url = "".join([rdap_server_base, obj_type, "/", obj_query]) | |
url_parse = urllib.parse.urlparse(query_url) | |
https = url_parse.scheme == "https" | |
HTTP_SConn = http.client.HTTPSConnection if https else http.client.HTTPConnection | |
port = http.client.HTTPS_PORT if https else http.client.HTTP_PORT | |
conn = HTTP_SConn(url_parse.netloc, port) | |
# Send HTTP/S request | |
conn.request("GET", url_parse.path) | |
res = conn.getresponse() | |
if res.status == 301 or res.status == 302 or res.status == 303 or res.status == 307: | |
# Server knows of an RDAP service which is authoritative for the requested resource. | |
# Follow the URL listed in the Location header. | |
if redirects > 10: | |
# Limit max redirects to 10 | |
raise Exception() | |
elif res.headers["Location"] == query_url: | |
# Prevent redirecting to same server | |
raise Exception() | |
else: | |
return rdap( | |
obj_type, | |
obj_query, | |
redirects=redirects + 1, | |
query_url=res.headers["Location"], | |
) | |
elif res.status == 400: | |
# Server received an invalid request (malformed path, unsupported object type, invalid IP address, etc). | |
raise Exception() | |
elif res.status == 404: | |
# Server didn't know of an RDAP service which is authoritative for the requested resource. | |
raise Exception() | |
elif res.status == 429: | |
# Exceeded the server's rate limit. | |
raise Exception() | |
elif res.status == 500: | |
# Server is broken in some way. | |
raise Exception() | |
elif res.status == 504: | |
# Server needed to refresh the IANA bootstrap registry, but couldn't. | |
raise Exception() | |
elif res.status != 200: | |
raise Exception() | |
data = json.loads(res.read()) | |
return data | |
if __name__ == "__main__": | |
dns_boostrap = rdap_fetch_bootstrap("dns") | |
server_list = rdap_find_in_bootstrap("dns", "google.com", dns_boostrap) | |
s = rdap("domain", "google.com", server_list[0]) | |
print(json.dumps(s, indent=4)) |
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
{ | |
"objectClassName": "domain", | |
"handle": "2138514_DOMAIN_COM-VRSN", | |
"ldhName": "GOOGLE.COM", | |
"links": [ | |
{ | |
"value": "https://rdap.verisign.com/com/v1/domain/GOOGLE.COM", | |
"rel": "self", | |
"href": "https://rdap.verisign.com/com/v1/domain/GOOGLE.COM", | |
"type": "application/rdap+json" | |
}, | |
{ | |
"value": "https://rdap.markmonitor.com/rdap/domain/GOOGLE.COM", | |
"rel": "related", | |
"href": "https://rdap.markmonitor.com/rdap/domain/GOOGLE.COM", | |
"type": "application/rdap+json" | |
} | |
], | |
"status": [ | |
"client delete prohibited", | |
"client transfer prohibited", | |
"client update prohibited", | |
"server delete prohibited", | |
"server transfer prohibited", | |
"server update prohibited" | |
], | |
"entities": [ | |
{ | |
"objectClassName": "entity", | |
"handle": "292", | |
"roles": [ | |
"registrar" | |
], | |
"publicIds": [ | |
{ | |
"type": "IANA Registrar ID", | |
"identifier": "292" | |
} | |
], | |
"vcardArray": [ | |
"vcard", | |
[ | |
[ | |
"version", | |
{}, | |
"text", | |
"4.0" | |
], | |
[ | |
"fn", | |
{}, | |
"text", | |
"MarkMonitor Inc." | |
] | |
] | |
], | |
"entities": [ | |
{ | |
"objectClassName": "entity", | |
"roles": [ | |
"abuse" | |
], | |
"vcardArray": [ | |
"vcard", | |
[ | |
[ | |
"version", | |
{}, | |
"text", | |
"4.0" | |
], | |
[ | |
"fn", | |
{}, | |
"text", | |
"" | |
], | |
[ | |
"tel", | |
{ | |
"type": "voice" | |
}, | |
"uri", | |
"tel:+1.2086851750" | |
], | |
[ | |
"email", | |
{}, | |
"text", | |
"abusecomplaints@markmonitor.com" | |
] | |
] | |
] | |
} | |
] | |
} | |
], | |
"events": [ | |
{ | |
"eventAction": "registration", | |
"eventDate": "1997-09-15T04:00:00Z" | |
}, | |
{ | |
"eventAction": "expiration", | |
"eventDate": "2028-09-14T04:00:00Z" | |
}, | |
{ | |
"eventAction": "last changed", | |
"eventDate": "2019-09-09T15:39:04Z" | |
}, | |
{ | |
"eventAction": "last update of RDAP database", | |
"eventDate": "2022-08-14T23:07:40Z" | |
} | |
], | |
"secureDNS": { | |
"delegationSigned": false | |
}, | |
"nameservers": [ | |
{ | |
"objectClassName": "nameserver", | |
"ldhName": "NS1.GOOGLE.COM" | |
}, | |
{ | |
"objectClassName": "nameserver", | |
"ldhName": "NS2.GOOGLE.COM" | |
}, | |
{ | |
"objectClassName": "nameserver", | |
"ldhName": "NS3.GOOGLE.COM" | |
}, | |
{ | |
"objectClassName": "nameserver", | |
"ldhName": "NS4.GOOGLE.COM" | |
} | |
], | |
"rdapConformance": [ | |
"rdap_level_0", | |
"icann_rdap_technical_implementation_guide_0", | |
"icann_rdap_response_profile_0" | |
], | |
"notices": [ | |
{ | |
"title": "Terms of Use", | |
"description": [ | |
"Service subject to Terms of Use." | |
], | |
"links": [ | |
{ | |
"href": "https://www.verisign.com/domain-names/registration-data-access-protocol/terms-service/index.xhtml", | |
"type": "text/html" | |
} | |
] | |
}, | |
{ | |
"title": "Status Codes", | |
"description": [ | |
"For more information on domain status codes, please visit https://icann.org/epp" | |
], | |
"links": [ | |
{ | |
"href": "https://icann.org/epp", | |
"type": "text/html" | |
} | |
] | |
}, | |
{ | |
"title": "RDDS Inaccuracy Complaint Form", | |
"description": [ | |
"URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf" | |
], | |
"links": [ | |
{ | |
"href": "https://icann.org/wicf", | |
"type": "text/html" | |
} | |
] | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment