Skip to content

Instantly share code, notes, and snippets.

@agostof
Last active February 3, 2024 17:33
Show Gist options
  • Save agostof/118d8320a75d9bd2d13a7ca42aed6aaf to your computer and use it in GitHub Desktop.
Save agostof/118d8320a75d9bd2d13a7ca42aed6aaf to your computer and use it in GitHub Desktop.
Fetches ISP CIDR ranges from IP addresses using ARIN RDAP, aiding network analysis, useful for setting up firewall rules.
# There are resources
# https://www.arin.net/resources/registry/whois/rdap/
# +
# There are several ways to getting the CIDR that one IP belongs to.
# A quick way is by using whois for a given a IP. # The CIRD will be on the record:
# For example for IP Address 8.8.8.1:
# whois 8.8.8.1
# ... LINES OMITTED ...
# NetRange: 8.8.8.0 - 8.8.8.255
# CIDR: 8.8.8.0/24
# ... LINES OMITTED ...
# For geting the CIDRs assigned to an organization, we can also use whois
# to extract the ARIN records. We would need to grab the arin entry from the record.
# We need to locate the NetName, OrgID, then grab registry URL for the entity.
# For example:
# whois 8.8.8.1
#
# NetRange: 8.8.8.0 - 8.8.8.255
# CIDR: 8.8.8.0/24
# NetName: GOGL
# ... LINES OMITTED ...
# Ref: https://rdap.arin.net/registry/ip/8.8.8.0
# ...
# OrgName: Google LLC
# OrgId: GOGL
# Ref: https://rdap.arin.net/registry/entity/GOGL
#
# On this example we would use `https://rdap.arin.net/registry/entity/GOGL`
# on the script below.
#
# The oher option is to run the `get_arin_rdap_url` included in this gist e.g.
# rdap_url = get_arin_rdap_url("8.8.8.8")
#
# You can also query multiple IPS based on the ip addresses of interest.
# Setting `ip_addresses_of_interest` to a list of IPs e.g.
# ip_addresses_of_interest = ['YOUR_IP', 'SOME_OTHER_IP', 'SOME_OTHER_IP2']
# This will result on the script finding the entities who control those IPs.
# Please be judicious of the number of queries. Some rate limitting will might be needed.
isps = {'ATT Mobility':'https://rdap.arin.net/registry/entity/ATTMO-3',
'Digital Ocean':'https://rdap.arin.net/registry/entity/DO-13',
}
ip_addresses_of_interest = ['199.4.240.1', '8.8.8.8']
import requests
#import urllib.request
import json
import time
from pprint import pprint
def parse_cidr(data, isp_name=None):
out = {}
handle = data['handle']
if isp_name:
full_isp_name = f'{isp_name}:{handle}'
else:
full_isp_name = f'{isp_name}'
out[full_isp_name] = {'ipv4':[], 'ipv6':[]}
for i in data['networks']:
cidrs = i['cidr0_cidrs']
for o in cidrs:
if 'v4prefix' in o:
out[full_isp_name]['ipv4'].append( "{v4prefix}/{length}".format(**o))
elif 'v6prefix' in o:
out[full_isp_name]['ipv6'].append( "{v6prefix}/{length}".format(**o))
else:
raise
return out
def query_arin_api(ip):
try:
url = f"https://rdap.arin.net/registry/ip/{ip}"
# using the requests module
arin_res = requests.get(url)
data = json.loads(arin_res.text)
return data
# to use without the reques module use this:
# with urllib.request.urlopen(url) as response:
# data = json.loads(response.read().decode())
# return data
except Exception as e:
print(f"Error querying ARIN API for IP {ip}: {e}")
return None
def parse_arin_data(arin_data):
rdap_urls = []
for entity in arin_data['entities']:
if 'registrant' not in entity['roles']:
# will keep only the registrant records
# skip the rest
continue
handle = entity['handle']
entity_long_name = entity['vcardArray'][1][1][3]
for link in entity['links']:
if link['type'] == 'application/rdap+json':
rdap_url = link["href"]
#rdap_urls.append( f'{handle}@{link["href"]}' )
#print(f'{entity_long_name},{handle},{rdap_url}')
#rdap_urls.append(link["href"])
rdap_urls.append(f'{entity_long_name},{handle},{rdap_url}')
# just in case there are other records
out_name, out_handle, out_url = list(set(rdap_urls))[0].split(",")
return {'entity_long_name': out_name, 'handle': out_handle, 'rdap_url': out_url}
def get_arin_rdap_url(ip):
arin_data = query_arin_api(ip)
out = parse_arin_data(arin_data)
return out
for ip in ip_addresses_of_interest:
record = get_arin_rdap_url(ip)
isps[ record['entity_long_name']] = record['rdap_url']
print(record)
results = {}
for isp_name, url in isps.items():
isp_res = requests.get(url)
if isp_res.ok:
data = json.loads(isp_res.text)
results[isp_name] = data
else:
results[isp_name] = None
time.sleep(0.25)
out = {}
for isp_name,data in results.items():
out.update(parse_cidr(data, isp_name))
#pprint(parse_cidr(data))
pprint(out)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment