Add basic AS200351 aut-num and routing policy

This commit is contained in:
Quantum 2024-06-16 01:13:52 -04:00
parent a4710940eb
commit 633a168ac8
4 changed files with 242 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.api-key

80
AS200351.rpsl Normal file
View file

@ -0,0 +1,80 @@
aut-num: AS200351
as-name: DQN-AS-ANYCAST
descr: Dynamic Quantum Networks
descr: https://as200351.net
descr: https://quantum5.ca
remarks: +-------------------------------------------------------------+
remarks: | ____ _ |
remarks: | / __ \__ ______ ____ _____ ___ (_)____ |
remarks: | / / / / / / / __ \/ __ `/ __ `__ \/ / ___/ |
remarks: | / /_/ / /_/ / / / / /_/ / / / / / / / /__ |
remarks: | /_____/\__, /_/ /_/\__,_/_/ /_/ /_/_/\___/ |
remarks: | /____/ ____ __ |
remarks: | / __ \__ ______ _____ / /___ ______ ___ |
remarks: | / / / / / / / __ `/ __ \/ __/ / / / __ `__ \ |
remarks: | / /_/ / /_/ / /_/ / / / / /_/ /_/ / / / / / / |
remarks: | \___\_\__,_/\__,_/_/ /_/\__/\__,_/_/ /_/ /_/ |
remarks: | _ __ __ __ |
remarks: | / | / /__ / /__ ______ _____/ /_______ |
remarks: | / |/ / _ \/ __/ | /| / / __ \/ ___/ //_/ ___/ |
remarks: | / /| / __/ /_ | |/ |/ / /_/ / / / ,< (__ ) |
remarks: | /_/ |_/\___/\__/ |__/|__/\____/_/ /_/|_/____/ |
remarks: | |
remarks: +-------------------------------------------------------------+
remarks:
remarks: ===================== ROUTING INFORMATION =====================
remarks: ====== upstreams ======
import: from AS200351:as-upstreams accept ANY
mp-import: afi any.unicast from AS200351:as-upstreams accept ANY
export: to AS200351:as-upstreams announce AS200351:as-all
mp-export: afi any.unicast to AS200351:as-upstreams announce AS200351:as-all
remarks:
remarks: ====== IXP: ONIX ======
remarks: * IPv4: 149.112.50.51
remarks: * IPv6: 2001:504:125:e1::51
import: from AS57369 accept AS57369:AS-ONIX
mp-import: afi any.unicast from AS57369 accept AS57369:AS-ONIX
export: to AS57369 announce AS200351:as-all
mp-export: afi any.unicast to AS57369 announce AS200351:as-all
remarks:
remarks: ===== IXP: FogIXP =====
remarks: * IPv4: 185.1.147.210
remarks: * IPv6: 2001:7f8:ca:1:0:20:0351:1
import: from AS47498 accept AS-FOGIXP
mp-import: afi any.unicast from AS47498 accept AS-FOGIXP
export: to AS47498 announce AS200351:as-all
mp-export: afi any.unicast to AS47498 announce AS200351:as-all
remarks:
remarks: ===== IXP: AccurIX ====
remarks: * IPv4: 149.112.74.8
remarks: * IPv6: 2001:504:132::8
import: from AS57194 accept AS57194:as-accurix-members
mp-import: afi any.unicast from AS57194 accept AS57194:as-accurix-members
export: to AS57194 announce AS200351:as-all
mp-export: afi any.unicast to AS57194 announce AS200351:as-all
remarks:
remarks: ===== IXP: FrysIX =====
remarks: * IPv4: 185.1.203.229
remarks: * IPv6: 2001:7f8:10f::3:e9f:229
import: from AS56393 accept AS-FRYS-IX-CONNECTED
mp-import: afi any.unicast from AS56393 accept AS-FRYS-IX-CONNECTED
export: to AS56393 announce AS200351:as-all
mp-export: afi any.unicast to AS56393 announce AS200351:as-all
remarks:
remarks: ====== IXP: KCIX ======
remarks: * IPv4: 206.51.7.216
remarks: * IPv6: 2001:504:1b:1::216
remarks:
remarks: ===== IXP: STLIX ======
remarks: * IPv4: 206.83.12.70
remarks: * IPv6: 2001:504:98::70
remarks:
remarks: ===== IXP: HOUIX ======
remarks: * IPv4: 206.83.136.41
remarks: * IPv6: 2001:504:9E::41
remarks:
remarks: ==================== OWNERSHIP INFORMATION ====================
admin-c: DQNA-ARIN
tech-c: DQNOC-ARIN
mnt-by: MNT-GC-1348
source: ARIN

View file

@ -0,0 +1,37 @@
as-set: AS200351:AS-UPSTREAMS
descr: AS200351's Upstreams
remarks: ==== Frantech Solutions ====
members: AS53667
remarks: ===== Constant / Vultr =====
members: AS20473
remarks: ===== Cloudie Networks =====
members: AS924
remarks: === Accuris Technologies ===
members: AS52210
remarks: ==== Hurricane Electric ====
members: AS6939
remarks: ======== iFog GmbH =========
members: AS34927, AS209533
remarks: ======= FreeTransit ========
members: AS41051
remarks: === F4 Networks / Rozint ===
members: AS21738, AS25759
remarks: ========== Suble ===========
members: AS199545
remarks: ======== Tschajera =========
members: AS209022
remarks: ========= HyeHost ==========
members: AS47272
remarks: ========= Diederik =========
members: AS50917
remarks: ==== Snaju / DartNode ======
members: AS399646
remarks: ===== Jon Arve Vanvik ======
members: AS210475
remarks: ========= FlowVPS ==========
members: AS37988
remarks: ============================
admin-c: DQNA-ARIN
tech-c: DQNOC-ARIN
mnt-by: MNT-GC-1348
source: ARIN

124
update-irr.py Executable file
View file

@ -0,0 +1,124 @@
#!/usr/bin/env python3
import argparse
import getpass
import os
import re
import sys
from abc import ABC, abstractmethod
from pathlib import Path
import requests
REGISTRY = 'https://reg.arin.net/rest/irr'
class BaseResource(ABC):
type: str
def __init__(self, name, rpsl):
self.name = name
self.rpsl = rpsl
@abstractmethod
def validate(self): ...
@abstractmethod
def get_create_url(self): ...
@abstractmethod
def get_update_url(self): ...
class AsSetResource(BaseResource):
def __init__(self, name, rpsl):
self.type = 'as-set'
super().__init__(name, rpsl)
def validate(self):
if not re.match(f'^as-set:\s+{re.escape(self.name)}$', self.rpsl, re.M):
raise ValueError(f'Expected aut-num: {self.name} in RPSL')
def get_create_url(self):
return f'{REGISTRY}/as-set'
def get_update_url(self):
return f'{REGISTRY}/as-set/{self.name}'
class AutNumResource(BaseResource):
def __init__(self, name, rpsl):
self.type = 'aut-num'
super().__init__(name, rpsl)
def validate(self):
if not re.match(f'^aut-num:\s+{re.escape(self.name)}$', self.rpsl, re.M):
raise ValueError(f'Expected aut-num: {self.name} in RPSL')
def get_create_url(self):
return f'{REGISTRY}/aut-num/{self.name}'
def get_update_url(self):
return f'{REGISTRY}/aut-num/{self.name}'
def get_resource(path, rpsl):
if (m := re.match('^(AS\d+)\.rpsl$', path)):
return AutNumResource(m.group(1), rpsl)
elif (m := re.match('^((?:AS\d+@)?(AS-[A-Z0-9-]+@)*AS-[A-Z0-9-]+)\.rpsl$', path)):
return AsSetResource(m.group(1).replace('@', ':'), rpsl)
def get_api_key():
key_file = Path(__file__).parent / '.api-key'
if key_file.exists():
with open(key_file) as f:
return f.read().strip()
return getpass.getpass('ARIN api key: ')
def main():
parser = argparse.ArgumentParser(
prog=sys.argv[0],
description='Updates the ARIN IRR database with RPSL files'
)
parser.add_argument('filename', type=argparse.FileType('r'))
parser.add_argument('-c', '--create', action='store_true')
parser.add_argument(
'-o', '--org',
help='Organization handle (e.g. when creating an as-set)'
)
args = parser.parse_args()
with args.filename as f:
rpsl = f.read()
resource = get_resource(args.filename.name, rpsl)
if not resource:
print(f"Can't identify resource type from {args.filename.name}")
raise SystemExit(1)
resource.validate()
params = {'apikey': get_api_key()}
if args.org:
params['orgHandle'] = args.org
if args.create:
verb = 'POST'
url = resource.get_create_url()
else:
verb = 'PUT'
url = resource.get_update_url()
r = requests.request(verb, url=url, params=params, data=resource.rpsl, headers={
'Accept': 'application/rpsl',
'Content-Type': 'application/rpsl',
})
print(r.content.decode('utf-8', 'replace'))
if __name__ == '__main__':
main()