Skip to content

Instantly share code, notes, and snippets.

@silvio2402
Created August 14, 2022 19:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save silvio2402/22bc8929ba82c1d9c4a12503f86eb45b to your computer and use it in GitHub Desktop.
Save silvio2402/22bc8929ba82c1d9c4a12503f86eb45b to your computer and use it in GitHub Desktop.
Query RDAP information using a server from IANA's bootstrap file
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))
{
"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