For a while now, some of us have been bitching about how firewall vendors don't provide a method for blocking entire ASNs. Which is fucking lazy. So here's a python script so you can help yourself out. It'll accept a list of ASNs ( without the AS prefix ) as STDIN, input file, or both. It then outputs an aggregated list of network prefixes to either STDOUT or an output file. It also has a flag to include the ASN-DROP list from Spamhaus.
Don't bother mocking the code though. We know it's not good. It's not labeled. It's a hack job by someone trying to slap it together on a Friday afternoon. So feel free to hack it up yourself. License free. Though we do appreciate hearing about it being used or modified since it's apparently so difficult that billion dollar security vendors can't figure it the fuck out.
#!/usr/bin/env python3
from netaddr import cidr_merge
import sys
import requests
import json
import argparse
prefix_buffer = []
asn_buffer = []
usage_example = '''Examples:
python3 %(prog)s -i badAsnList1.txt badAsnList2.txt
python3 %(prog)s -s -i badAsnList3.txt
python3 %(prog)s -i badAsnList* -s -o badPrefixes.txt
'''
description = '''
Convert lists of ASNs into aggregated network prefixes. Also accepts STDIN.
Be sure to specify the ASNs as numbers only without the "AS" prefix.
'''
parser = argparse.ArgumentParser(prog = 'asnsToPrefixes.py', description = description, epilog = usage_example, formatter_class = argparse.RawDescriptionHelpFormatter)
parser.add_argument('-i', '--input', nargs='+', help='List(s) of ASNs to convert')
parser.add_argument('-o', '--output', help='Output results to a file')
parser.add_argument('-s', '--spamhaus', action='store_true', help='Include Spamhaus ASN-DROP in the results')
args = parser.parse_args()
if not sys.stdin.isatty():
for line in sys.stdin:
asn_buffer.append(line.strip())
if args.input:
for asn_file in args.input:
with open(asn_file) as asn:
for line in asn.readlines():
asn_buffer.append(line.strip())
if args.spamhaus:
sh_resp = requests.get('https://www.spamhaus.org/drop/asndrop.json')
sh_resp_str = sh_resp.content.decode('utf-8')
sh_resp_spl = sh_resp_str.splitlines()
for line in sh_resp_spl:
sh_resp_json = json.loads(line)
if "asn" in sh_resp_json:
asn_buffer.append(sh_resp_json['asn'])
for line in asn_buffer:
req = "https://stat.ripe.net/data/announced-prefixes/data.json?resource=AS" + str(line)
res = requests.get(req)
res_dict = res.json()
res_json = json.dumps(res_dict)
asns = json.loads(res_json)
prefixes = asns['data']['prefixes']
for item in prefixes:
prefix_buffer.append(item['prefix'])
for prefix in cidr_merge(prefix_buffer):
if args.output:
with open(args.output, "a", encoding="utf-8") as file:
file.write(str(prefix.cidr) + "\n")
else:
print(prefix.cidr)
Updated: 19 September 2025