mirror of
https://git.dn42.dev/dn42/registry.git
synced 2025-07-19 00:46:59 +08:00
move nettree to its own place. various other changes
This commit is contained in:
parent
078f1f10ae
commit
da617f195b
10 changed files with 599 additions and 106 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -4,4 +4,4 @@ whoisd/
|
||||||
__pycache__
|
__pycache__
|
||||||
.index
|
.index
|
||||||
.links
|
.links
|
||||||
.netindex
|
.nettree
|
||||||
|
|
|
@ -5,5 +5,9 @@ default-owner: DN42-MNT
|
||||||
network-owner: inet6num inet6num
|
network-owner: inet6num inet6num
|
||||||
network-owner: inet6num route
|
network-owner: inet6num route
|
||||||
network-owner: inet6num inetnum
|
network-owner: inet6num inetnum
|
||||||
network-owner: inetnum inetnum
|
network-owner: inetnum inetnum
|
||||||
network-owner: inetnum route
|
network-owner: inetnum route
|
||||||
|
primary-key: inetnum cidr
|
||||||
|
primary-key: inet6num cidr
|
||||||
|
primary-key: person nic-hdl
|
||||||
|
primary-key: role nic-hdl
|
|
@ -1,9 +1,10 @@
|
||||||
schema: NAMESPACE-SCHEMA
|
schema: NAMESPACE-SCHEMA
|
||||||
ref: dn42.schema
|
ref: dn42.namespace
|
||||||
key: namespace required single primary schema > [name]
|
key: namespace required single primary schema > [name]
|
||||||
key: ns-schema required single > [schema]
|
key: ns-schema required single > [schema]
|
||||||
key: ns-owner required single > [schema]
|
key: ns-owner required single > [schema]
|
||||||
key: default-owner optional single lookup=dn42.mntner > [mntner]
|
key: default-owner optional single lookup=dn42.mntner > [mntner]
|
||||||
key: network-owner optional multiple > [parent-schema] [child-schema]
|
key: network-owner optional multiple > [parent-schema] [child-schema]
|
||||||
|
key: primary-key optional multiple > [schema] [primary]
|
||||||
mnt-by: DN42-MNT
|
mnt-by: DN42-MNT
|
||||||
source: DN42
|
source: DN42
|
||||||
|
|
363
utils/registry/.schema
Normal file
363
utils/registry/.schema
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
.BEGIN DN42-MNT
|
||||||
|
schema: AUT-NUM-SCHEMA
|
||||||
|
ref: dn42.aut-num
|
||||||
|
key: aut-num required single primary schema
|
||||||
|
key: as-name required single
|
||||||
|
key: descr optional single
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: member-of optional multiple lookup=dn42.as-set,dn42.route-set
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: org optional single lookup=dn42.organisation
|
||||||
|
key: import deprecate multiple
|
||||||
|
key: export deprecate multiple
|
||||||
|
key: default deprecate multiple
|
||||||
|
key: mp-peer deprecate multiple
|
||||||
|
key: mp-group deprecate multiple
|
||||||
|
key: mp-import optional multiple
|
||||||
|
key: mp-export optional multiple
|
||||||
|
key: mp-default optional multiple
|
||||||
|
key: geo-loc optional multiple > [lat-c] [long-c] [name]
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: AS-SET-SCHEMA
|
||||||
|
ref: dn42.as-set
|
||||||
|
key: as-set required single primary schema
|
||||||
|
key: descr optional single
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: members optional multiple lookup=dn42.aut-num,dn42.as-set
|
||||||
|
key: mbrs-by-ref optional multiple lookup=dn42.mntner
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: ROUTE6-SCHEMA
|
||||||
|
ref: dn42.route6
|
||||||
|
key: route6 required single primary schema
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: origin required multiple lookup=dn42.aut-num
|
||||||
|
key: member-of optional multiple lookup=dn42.route-set
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: descr optional multiple
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
key: pingable optional multiple
|
||||||
|
key: max-length optional single
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: TINC-KEYSET-SCHEMA
|
||||||
|
ref: dn42.tinc-keyset
|
||||||
|
key: tinc-keyset required single primary schema
|
||||||
|
key: descr optional single
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: member required multiple lookup=dn42.tinc-key
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: ROLE-SCHEMA
|
||||||
|
ref: dn42.role
|
||||||
|
key: role required single schema
|
||||||
|
key: nic-hdl required single primary
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: org optional multiple lookup=dn42.organisation
|
||||||
|
key: admin-c optional multiple lookup=dn42.person
|
||||||
|
key: tech-c optional multiple lookup=dn42.person
|
||||||
|
key: abuse-c optional multiple lookup=dn42.person
|
||||||
|
key: abuse-mailbox optional multiple
|
||||||
|
key: descr optional single
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: INET6NUM-SCHEMA
|
||||||
|
ref: dn42.inet6num
|
||||||
|
key: inet6num required single schema
|
||||||
|
key: cidr required single primary
|
||||||
|
key: netname required single
|
||||||
|
key: nserver optional multiple > [domain-name]
|
||||||
|
key: country optional multiple
|
||||||
|
key: descr optional single
|
||||||
|
key: status optional single > {ALLOCATED|ASSIGNED} {PI|PA|}
|
||||||
|
key: policy optional single > {open|closed|ask|reserved}
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: zone-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: ds-rdata optional multiple
|
||||||
|
key: mnt-by optional multiple lookup=dn42.mntner
|
||||||
|
key: mnt-lower optional multiple lookup=dn42.mntner
|
||||||
|
key: mnt-routes optional multiple lookup=dn42.mntner
|
||||||
|
key: org optional single lookup=dn42.organisation
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
network-owner: inet6num
|
||||||
|
network-owner: inetnum
|
||||||
|
network-owner: route6
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: MNTNER-SCHEMA
|
||||||
|
ref: dn42.mntner
|
||||||
|
key: mntner required single primary schema
|
||||||
|
key: descr optional single
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: auth optional multiple > [method] [value]...
|
||||||
|
key: org optional multiple lookup=dn42.organisation
|
||||||
|
key: abuse-mailbox optional single
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: ORGANISATION-SCHEMA
|
||||||
|
ref: dn42.organisation
|
||||||
|
key: organisation required single primary schema
|
||||||
|
key: org-name required single
|
||||||
|
key: descr optional single
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: abuse-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: mnt-ref optional multiple lookup=dn42.mntner
|
||||||
|
key: phone optional multiple
|
||||||
|
key: fax-no optional multiple
|
||||||
|
key: www optional multiple
|
||||||
|
key: abuse-mailbox optional multiple
|
||||||
|
key: e-mail optional multiple
|
||||||
|
key: geoloc optional multiple
|
||||||
|
key: language optional multiple
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: address optional multiple
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: TINC-KEY-SCHEMA
|
||||||
|
ref: dn42.tinc-key
|
||||||
|
key: tinc-key required single primary schema
|
||||||
|
key: tinc-host required single
|
||||||
|
key: tinc-file required single
|
||||||
|
key: descr optional single
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: compression optional single
|
||||||
|
key: subnet optional multiple
|
||||||
|
key: tinc-address optional single
|
||||||
|
key: port optional single
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: AS-BLOCK-SCHEMA
|
||||||
|
ref: dn42.as-block
|
||||||
|
key: as-block required single primary schema
|
||||||
|
key: descr optional single
|
||||||
|
key: policy required single > {open|ask|closed}
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: SCHEMA-SCHEMA
|
||||||
|
ref: dn42.schema
|
||||||
|
key: schema required single primary schema > [name]
|
||||||
|
key: ref required single > [schema]
|
||||||
|
key: key required multiple > [key-name]
|
||||||
|
{required|optional|recommend|deprecate}
|
||||||
|
{single|multiple} {primary|} {schema|}
|
||||||
|
lookup=str '>' [spec]...
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner > [mntner]
|
||||||
|
key: remarks optional multiple > [text]...
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
key: network-owner optional multiple > [child-schema]
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
remarks: # option descriptions
|
||||||
|
Attribute names must match /[a-zA-Z]([a-zA-Z0-9_\-]*[a-zA-Z0-9])?/.
|
||||||
|
+
|
||||||
|
required
|
||||||
|
: object required to have at least one
|
||||||
|
optional
|
||||||
|
: object not required to have at least one
|
||||||
|
+
|
||||||
|
single
|
||||||
|
: only one of this type allowed
|
||||||
|
multiple
|
||||||
|
: more than one of this type allowed
|
||||||
|
+
|
||||||
|
primary
|
||||||
|
: use field as lookup key for lookup
|
||||||
|
* only one allowed per schema
|
||||||
|
* does not allow newlines
|
||||||
|
+
|
||||||
|
schema
|
||||||
|
: use field name as the name of the schema
|
||||||
|
* only one allowed per schema
|
||||||
|
* does not allow newlines
|
||||||
|
+
|
||||||
|
lookup
|
||||||
|
: schema match to use for related record
|
||||||
|
+
|
||||||
|
\> option specs
|
||||||
|
: defines the option specifications for the key.
|
||||||
|
* must come last in option list
|
||||||
|
+
|
||||||
|
[label] string value. A positional string argument required.
|
||||||
|
Text inside brackets represent a label for the string and must match the same rules as attribute names.
|
||||||
|
If follwed by '...' values are gathered as an array.
|
||||||
|
+
|
||||||
|
{enum1|enum2|} enumeration. One option in pipe('|') deliniation is allowed.
|
||||||
|
If there is a trailing pipe it means the enum is optional. Enum values must match the same rules as attribute names.
|
||||||
|
+
|
||||||
|
'literal' Literal value. literal text value which must not contain any whitespace or single quotes.
|
||||||
|
...
|
||||||
|
schema: ROUTE-SET-SCHEMA
|
||||||
|
ref: dn42.route-set
|
||||||
|
key: route-set required single primary schema
|
||||||
|
key: descr optional single
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: members deprecate multiple
|
||||||
|
key: mp-members optional multiple
|
||||||
|
key: mbrs-by-ref optional multiple lookup=dn42.mntner
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: REGISTRY-SCHEMA
|
||||||
|
ref: dn42.registry
|
||||||
|
key: registry required single primary schema
|
||||||
|
key: url required multiple
|
||||||
|
key: descr optional multiple
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: KEY-CERT-SCHEMA
|
||||||
|
ref: dn42.key-cert
|
||||||
|
key: key-cert required single primary schema
|
||||||
|
key: method required single > {PGP|X509|MTN}
|
||||||
|
key: owner required multiple
|
||||||
|
key: fingerpr required single
|
||||||
|
key: certif required multiple
|
||||||
|
key: org optional multiple lookup=dn42.organisation
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: source required single
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: ROUTE-SCHEMA
|
||||||
|
ref: dn42.route
|
||||||
|
key: route required single primary schema
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: origin required multiple lookup=dn42.aut-num
|
||||||
|
key: member-of optional multiple lookup=dn42.route-set
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: descr optional single
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
key: pingable optional multiple
|
||||||
|
key: max-length optional single
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: PERSON-SCHEMA
|
||||||
|
ref: dn42.person
|
||||||
|
key: person required single schema
|
||||||
|
key: nic-hdl required single primary
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: org optional multiple lookup=dn42.organisation
|
||||||
|
key: nick optional multiple
|
||||||
|
key: pgp-fingerprint optional multiple
|
||||||
|
key: www optional multiple
|
||||||
|
key: e-mail optional multiple
|
||||||
|
key: contact optional multiple
|
||||||
|
key: abuse-mailbox optional multiple
|
||||||
|
key: phone optional multiple
|
||||||
|
key: fax-no optional multiple
|
||||||
|
key: address optional multiple
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: INETNUM-SCHEMA
|
||||||
|
ref: dn42.inetnum
|
||||||
|
key: inetnum required single schema
|
||||||
|
key: cidr required single primary
|
||||||
|
key: netname required single
|
||||||
|
key: nserver optional multiple > [domain-name]
|
||||||
|
key: country optional multiple
|
||||||
|
key: descr optional single
|
||||||
|
key: status optional single > {ALLOCATED|ASSIGNED} {PI|PA|}
|
||||||
|
key: policy optional single > {open|closed|ask|reserved}
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: zone-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: ds-rdata optional multiple
|
||||||
|
key: mnt-by optional multiple lookup=dn42.mntner
|
||||||
|
key: mnt-lower optional multiple lookup=dn42.mntner
|
||||||
|
key: mnt-routes optional multiple lookup=dn42.mntner
|
||||||
|
key: org optional single lookup=dn42.organisation
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
network-owner: inetnum
|
||||||
|
network-owner: route
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: NAMESPACE-SCHEMA
|
||||||
|
ref: dn42.namespace
|
||||||
|
key: namespace required single primary schema > [name]
|
||||||
|
key: ns-schema required single > [schema]
|
||||||
|
key: ns-owner required single > [schema]
|
||||||
|
key: default-owner optional single lookup=dn42.mntner > [mntner]
|
||||||
|
key: network-owner optional multiple > [parent-schema] [child-schema]
|
||||||
|
key: primary-key optional multiple > [schema] [primary]
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
...
|
||||||
|
schema: DNS-SCHEMA
|
||||||
|
ref: dn42.domain
|
||||||
|
key: domain required single primary schema
|
||||||
|
key: nserver required multiple > [domain-name] [ip-addr]
|
||||||
|
key: descr optional single
|
||||||
|
key: mnt-by required multiple lookup=dn42.mntner
|
||||||
|
key: admin-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: tech-c optional multiple lookup=dn42.person,dn42.role
|
||||||
|
key: org optional multiple lookup=dn42.organisation
|
||||||
|
key: country optional single
|
||||||
|
key: ds-rdata optional multiple
|
||||||
|
key: remarks optional multiple
|
||||||
|
key: source required single lookup=dn42.registry
|
||||||
|
mnt-by: DN42-MNT
|
||||||
|
source: DN42
|
||||||
|
.END
|
|
@ -4,13 +4,12 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from ipaddress import ip_network, IPv6Network
|
from typing import Dict, Generator, List
|
||||||
from dataclasses import dataclass
|
|
||||||
from typing import TypeVar, Dict, Generator, List, Tuple
|
|
||||||
|
|
||||||
from dom.filedom import FileDOM, read_file
|
from dom.filedom import FileDOM, read_file
|
||||||
from dom.schema import SchemaDOM
|
from dom.schema import SchemaDOM
|
||||||
|
from dom.nettree import NetTree, NetRecord
|
||||||
|
from dom.transact import TransactDOM
|
||||||
|
|
||||||
def index_files(path: str) -> Generator[FileDOM, None, None]:
|
def index_files(path: str) -> Generator[FileDOM, None, None]:
|
||||||
"""generate list of dom files"""
|
"""generate list of dom files"""
|
||||||
|
@ -26,87 +25,6 @@ def index_files(path: str) -> Generator[FileDOM, None, None]:
|
||||||
yield dom
|
yield dom
|
||||||
|
|
||||||
|
|
||||||
NET = IPv6Network
|
|
||||||
NET_LIST = TypeVar('NET_LIST', int, List[NET])
|
|
||||||
NET_TREE = Dict[NET, NET_LIST]
|
|
||||||
V6_NET = ip_network("::/0")
|
|
||||||
V4_NET = ip_network("::0.0.0.0/96")
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class NetRecord:
|
|
||||||
"Network Record"
|
|
||||||
network: NET
|
|
||||||
mnters: List[str]
|
|
||||||
policy: str
|
|
||||||
status: str
|
|
||||||
|
|
||||||
@property
|
|
||||||
def object_type(self) -> str:
|
|
||||||
"""object type"""
|
|
||||||
return "inetnum" if V4_NET.supernet_of(self.network) \
|
|
||||||
else "inet6num"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def object_name(self) -> str:
|
|
||||||
"""object name"""
|
|
||||||
return self.network.with_prefixlen.replace("/", "_")
|
|
||||||
|
|
||||||
|
|
||||||
def in_net(i: NET, nets: List[NET]) -> Tuple[bool, NET]:
|
|
||||||
"find a network within a list of networks"
|
|
||||||
found = False
|
|
||||||
net = None
|
|
||||||
for n in nets:
|
|
||||||
if n.supernet_of(i):
|
|
||||||
found = True
|
|
||||||
net = n
|
|
||||||
break
|
|
||||||
|
|
||||||
return found, net
|
|
||||||
|
|
||||||
|
|
||||||
def find_tree(ip: NET, nets: NET_TREE):
|
|
||||||
"""Find net in tree"""
|
|
||||||
net = V6_NET
|
|
||||||
current = nets[net]
|
|
||||||
while True:
|
|
||||||
found, net = in_net(ip, current[1])
|
|
||||||
if not found:
|
|
||||||
return True, current[0] + 1
|
|
||||||
|
|
||||||
if ip.network == net.network:
|
|
||||||
return True, current[0] + 2
|
|
||||||
|
|
||||||
current = nets[net]
|
|
||||||
continue
|
|
||||||
|
|
||||||
|
|
||||||
def make_tree(nets: List[NET]) -> Dict[NET, NET_LIST]:
|
|
||||||
"""build a network tree index"""
|
|
||||||
root = V6_NET
|
|
||||||
tree = {root: [-1, []]}
|
|
||||||
for i in sorted(
|
|
||||||
sorted(nets, key=lambda x: x.exploded),
|
|
||||||
key=lambda x: x.prefixlen):
|
|
||||||
current = tree[root]
|
|
||||||
|
|
||||||
while True:
|
|
||||||
found, n = in_net(i, current[1])
|
|
||||||
|
|
||||||
if found:
|
|
||||||
current = tree[n]
|
|
||||||
continue
|
|
||||||
|
|
||||||
if current[0] >= 0:
|
|
||||||
current[1].append(i)
|
|
||||||
|
|
||||||
tree[i] = [current[0] + 1, []]
|
|
||||||
break
|
|
||||||
|
|
||||||
return tree
|
|
||||||
|
|
||||||
|
|
||||||
def run(path: str = "."):
|
def run(path: str = "."):
|
||||||
"""run main script"""
|
"""run main script"""
|
||||||
if not os.path.isdir(os.path.join(path, "schema")):
|
if not os.path.isdir(os.path.join(path, "schema")):
|
||||||
|
@ -155,7 +73,7 @@ def run(path: str = "."):
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
|
|
||||||
print("Writing .index", file=sys.stderr)
|
print("Writing .index", file=sys.stderr)
|
||||||
print("Writing .linkindex", file=sys.stderr)
|
print("Writing .links", file=sys.stderr)
|
||||||
with open(".index", 'w') as out:
|
with open(".index", 'w') as out:
|
||||||
with open(".links", 'w') as link_out:
|
with open(".links", 'w') as link_out:
|
||||||
for dom in files:
|
for dom in files:
|
||||||
|
@ -169,32 +87,29 @@ def run(path: str = "."):
|
||||||
dom.get(s.primary),
|
dom.get(s.primary),
|
||||||
dom.src,
|
dom.src,
|
||||||
",".join(dom.mntner),
|
",".join(dom.mntner),
|
||||||
sep="\t",
|
sep="|",
|
||||||
file=out)
|
file=out)
|
||||||
|
|
||||||
for (link, refs) in s.links.items():
|
for (link, refs) in s.links.items():
|
||||||
d = dom.get(link)
|
d = dom.get(link)
|
||||||
|
refs_join = ','.join(refs)
|
||||||
if d is not None:
|
if d is not None:
|
||||||
print(
|
print(
|
||||||
f"{dom.name}\t{link}\t{d}\t{','.join(refs)}",
|
f"{dom.rel}|{dom.name}|{link}|{d}|{refs_join}",
|
||||||
file=link_out)
|
file=link_out)
|
||||||
|
|
||||||
print("Generate .netindex", file=sys.stderr)
|
print("Generate .nettree", file=sys.stderr)
|
||||||
tree = make_tree({n.network for n in nets})
|
tree = NetTree(nets)
|
||||||
|
|
||||||
netindex = []
|
print("Writing .nettree", file=sys.stderr)
|
||||||
for net in nets:
|
tree.write_csv(".nettree")
|
||||||
v = tree[net.network]
|
|
||||||
netindex.append((v[0],
|
|
||||||
net.network.network_address.exploded,
|
|
||||||
net.network.broadcast_address.exploded,
|
|
||||||
net.network.prefixlen,
|
|
||||||
net.policy, net.status, ",".join(net.mnters)))
|
|
||||||
|
|
||||||
print("Writing .netindex", file=sys.stderr)
|
print("Writing .schema", file=sys.stderr)
|
||||||
with open(".netindex", "w") as out:
|
s = TransactDOM()
|
||||||
for row in sorted(netindex, key=lambda x: x[0]):
|
s.mntner = "DN42-MNT"
|
||||||
print("\t".join([str(i) for i in row]), file=out)
|
s.files = schemas.values()
|
||||||
|
with open(".schema", "w") as out:
|
||||||
|
print(s, file=out)
|
||||||
|
|
||||||
print("done.", file=sys.stderr)
|
print("done.", file=sys.stderr)
|
||||||
|
|
||||||
|
|
136
utils/registry/dom/nettree.py
Normal file
136
utils/registry/dom/nettree.py
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
"Net Tree"
|
||||||
|
|
||||||
|
from ipaddress import ip_network, IPv6Network
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Dict, List, Tuple, Optional
|
||||||
|
|
||||||
|
NET = IPv6Network
|
||||||
|
V6_NET = ip_network("::/0")
|
||||||
|
V4_NET = ip_network("::ffff:0.0.0.0/96")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class NetRecord:
|
||||||
|
"Network Record"
|
||||||
|
network: NET
|
||||||
|
mnters: List[str]
|
||||||
|
policy: str
|
||||||
|
status: str
|
||||||
|
|
||||||
|
@property
|
||||||
|
def object_type(self) -> str:
|
||||||
|
"""object type"""
|
||||||
|
return "inetnum" if V4_NET.supernet_of(self.network) \
|
||||||
|
else "inet6num"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def object_name(self) -> str:
|
||||||
|
"""object name"""
|
||||||
|
if V4_NET.supernet_of(self.network):
|
||||||
|
n = self.network.network_address.exploded.replace(":", "")[-8:]
|
||||||
|
return ip_network((
|
||||||
|
bytes.fromhex(n),
|
||||||
|
self.network.prefixlen - 96,
|
||||||
|
)).with_prefixlen.replace("/", "_")
|
||||||
|
|
||||||
|
return self.network.with_prefixlen.replace("/", "_")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class NetList:
|
||||||
|
"Network List"
|
||||||
|
index: int
|
||||||
|
parent: Optional[int]
|
||||||
|
level: int
|
||||||
|
net: Optional[NetRecord]
|
||||||
|
nets: List[NET]
|
||||||
|
|
||||||
|
def in_net(self, i: NET) -> Tuple[bool, NET]:
|
||||||
|
"find a network within a list of networks"
|
||||||
|
found = False
|
||||||
|
net = None
|
||||||
|
for n in self.nets:
|
||||||
|
if n.supernet_of(i):
|
||||||
|
found = True
|
||||||
|
net = n
|
||||||
|
break
|
||||||
|
|
||||||
|
return found, net
|
||||||
|
|
||||||
|
|
||||||
|
class NetTree:
|
||||||
|
"Network Tree"
|
||||||
|
def __init__(self, nets: Optional[List[NET]] = None):
|
||||||
|
self.tree = {} # type: Dict[NET, NetList]
|
||||||
|
if nets is not None:
|
||||||
|
self.make_tree(nets)
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self.tree[key]
|
||||||
|
|
||||||
|
def find_tree(self, ip: NET) -> Tuple[bool, int]:
|
||||||
|
"""Find net in tree"""
|
||||||
|
net = V6_NET
|
||||||
|
current = self.tree[net]
|
||||||
|
|
||||||
|
while True:
|
||||||
|
found, net = current.in_net(ip)
|
||||||
|
if not found:
|
||||||
|
return True, current.level + 1
|
||||||
|
|
||||||
|
if ip == net:
|
||||||
|
return True, current.level + 2
|
||||||
|
|
||||||
|
current = self.tree[net]
|
||||||
|
continue
|
||||||
|
|
||||||
|
return False, 0
|
||||||
|
|
||||||
|
def make_tree(self, nets: List[NetRecord]):
|
||||||
|
"""build a network tree index"""
|
||||||
|
root = V6_NET
|
||||||
|
self.tree = {root: NetList(0, None, -1, None, [])}
|
||||||
|
for index, net in enumerate(sorted(
|
||||||
|
sorted(nets, key=lambda x: x.network),
|
||||||
|
key=lambda x: x.network.prefixlen)):
|
||||||
|
|
||||||
|
current = self.tree[root]
|
||||||
|
|
||||||
|
while True:
|
||||||
|
found, n = current.in_net(net.network)
|
||||||
|
|
||||||
|
if found:
|
||||||
|
current = self.tree[n]
|
||||||
|
continue
|
||||||
|
|
||||||
|
if current.level >= 0:
|
||||||
|
current.nets.append(net.network)
|
||||||
|
|
||||||
|
self.tree[net.network] = NetList(
|
||||||
|
index, current.index, current.level + 1, net, [])
|
||||||
|
break
|
||||||
|
|
||||||
|
def write_csv(self, fn: str = ".netindex"):
|
||||||
|
"write tree to csv"
|
||||||
|
with open(fn, "w") as f:
|
||||||
|
f.writelines({line+"\n" for line in self._lines()})
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return "\n".join(self._lines())
|
||||||
|
|
||||||
|
def _lines(self) -> List[str]:
|
||||||
|
for v in self.tree.values():
|
||||||
|
yield (
|
||||||
|
"|".join([str(i) for i in (
|
||||||
|
v.index,
|
||||||
|
v.parent,
|
||||||
|
v.level,
|
||||||
|
v.net.network.network_address.exploded,
|
||||||
|
v.net.network.prefixlen,
|
||||||
|
v.net.object_type,
|
||||||
|
v.net.object_name,
|
||||||
|
v.net.policy,
|
||||||
|
v.net.status,
|
||||||
|
",".join(v.net.mnters),
|
||||||
|
)])
|
||||||
|
)
|
|
@ -70,6 +70,7 @@ class SchemaDOM:
|
||||||
self._schema = {} # type: Dict[str, Set[str]]
|
self._schema = {} # type: Dict[str, Set[str]]
|
||||||
self._spec = {} # type: Dict[str, str]
|
self._spec = {} # type: Dict[str, str]
|
||||||
self._links = {} # type: Dict[str, List[str]]
|
self._links = {} # type: Dict[str, List[str]]
|
||||||
|
self._dom = dom
|
||||||
|
|
||||||
if dom is not None:
|
if dom is not None:
|
||||||
self.parse(dom)
|
self.parse(dom)
|
||||||
|
@ -82,6 +83,7 @@ class SchemaDOM:
|
||||||
def parse(self, f: FileDOM):
|
def parse(self, f: FileDOM):
|
||||||
"""Parse a FileDOM into a SchemaDOM"""
|
"""Parse a FileDOM into a SchemaDOM"""
|
||||||
self.src = self.src if f.src is None else f.src
|
self.src = self.src if f.src is None else f.src
|
||||||
|
self._dom = f
|
||||||
|
|
||||||
schema = {}
|
schema = {}
|
||||||
for row in f.dom:
|
for row in f.dom:
|
||||||
|
@ -225,6 +227,9 @@ class SchemaDOM:
|
||||||
f"in {refs} but does not exist.")
|
f"in {refs} but does not exist.")
|
||||||
return state
|
return state
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self._dom.__str__()
|
||||||
|
|
||||||
|
|
||||||
def read_file(src: str) -> SchemaDOM:
|
def read_file(src: str) -> SchemaDOM:
|
||||||
"""Parses SchemaDOM from file"""
|
"""Parses SchemaDOM from file"""
|
||||||
|
|
62
utils/registry/dom/test_nettree.py
Normal file
62
utils/registry/dom/test_nettree.py
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
"Testing NetTree"
|
||||||
|
import unittest
|
||||||
|
from ipaddress import ip_network
|
||||||
|
|
||||||
|
from .nettree import NetTree, NetRecord
|
||||||
|
|
||||||
|
records = [
|
||||||
|
NetRecord(
|
||||||
|
ip_network("::/0"),
|
||||||
|
["DN42-MNT"],
|
||||||
|
"closed",
|
||||||
|
"ALLOCATED"),
|
||||||
|
NetRecord(
|
||||||
|
ip_network("::ffff:0.0.0.0/96"),
|
||||||
|
["DN42-MNT"],
|
||||||
|
"closed",
|
||||||
|
"ALLOCATED"),
|
||||||
|
NetRecord(
|
||||||
|
ip_network("::ffff:172.21.64.0/125"),
|
||||||
|
["XUU-MNT"],
|
||||||
|
"closed",
|
||||||
|
"ALLOCATED"),
|
||||||
|
NetRecord(
|
||||||
|
ip_network("fdea:a15a:77b9::/48"),
|
||||||
|
["XUU-MNT"],
|
||||||
|
"closed",
|
||||||
|
"ALLOCATED"),
|
||||||
|
]
|
||||||
|
|
||||||
|
text = [
|
||||||
|
"0|0|0|0000:0000:0000:0000:0000:0000:0000:0000|0|inet6num|::_0|closed|ALLOCATED|DN42-MNT", # noqa: E501
|
||||||
|
"1|0|1|fdea:a15a:77b9:0000:0000:0000:0000:0000|48|inet6num|fdea:a15a:77b9::_48|closed|ALLOCATED|XUU-MNT", # noqa: E501
|
||||||
|
"2|0|1|0000:0000:0000:0000:0000:ffff:0000:0000|96|inetnum|0.0.0.0_0|closed|ALLOCATED|DN42-MNT", # noqa: E501
|
||||||
|
"3|2|2|0000:0000:0000:0000:0000:ffff:ac15:4000|125|inetnum|172.21.64.0_29|closed|ALLOCATED|XUU-MNT" # noqa: E501
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class TestNetTree(unittest.TestCase):
|
||||||
|
"testing NetTree"
|
||||||
|
def test_nettree(self):
|
||||||
|
"test NetTree"
|
||||||
|
tree = NetTree(records)
|
||||||
|
for (left, right) in zip(str(tree).splitlines(), text):
|
||||||
|
self.assertEqual(left, right)
|
||||||
|
|
||||||
|
def test_find(self):
|
||||||
|
"test NetTree"
|
||||||
|
tree = NetTree(records)
|
||||||
|
tt = [
|
||||||
|
("fdea:a15a:77b9:ffff::/64", (True, 2)),
|
||||||
|
("fdea:a15a:77ba:ffff::/64", (True, 1)),
|
||||||
|
("::ffff:172.21.64.0/126", (True, 3)),
|
||||||
|
("::ffff:172.21.64.4/126", (True, 3)),
|
||||||
|
("::ffff:172.21.64.8/126", (True, 2)),
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
for (net, expect) in tt:
|
||||||
|
self.assertEqual(
|
||||||
|
tree.find_tree(ip_network(net)),
|
||||||
|
expect,
|
||||||
|
msg="network "+net)
|
|
@ -53,3 +53,10 @@ class TransactDOM():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
buffer.append(line)
|
buffer.append(line)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
s = f".BEGIN {self.mntner}\n"
|
||||||
|
s += "\n".join({f"DELETE {i}" for i in self.delete})
|
||||||
|
s += "...\n".join({str(record) for record in self.files})
|
||||||
|
s += ".END"
|
||||||
|
return s
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue