mirror of
				https://git.dn42.dev/dn42/registry.git
				synced 2025-10-31 03:30:49 +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__ | ||||
| .index | ||||
| .links | ||||
| .netindex | ||||
| .nettree | ||||
|  |  | |||
|  | @ -7,3 +7,7 @@ network-owner:    inet6num route | |||
| network-owner:    inet6num inetnum | ||||
| network-owner:    inetnum  inetnum | ||||
| 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 | ||||
| ref:                dn42.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 | ||||
|  |  | |||
							
								
								
									
										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 sys | ||||
| 
 | ||||
| from ipaddress import ip_network, IPv6Network | ||||
| from dataclasses import dataclass | ||||
| from typing import TypeVar, Dict, Generator, List, Tuple | ||||
| from typing import Dict, Generator, List | ||||
| 
 | ||||
| from dom.filedom import FileDOM, read_file | ||||
| 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]: | ||||
|     """generate list of dom files""" | ||||
|  | @ -26,87 +25,6 @@ def index_files(path: str) -> Generator[FileDOM, None, None]: | |||
|             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 = "."): | ||||
|     """run main script""" | ||||
|     if not os.path.isdir(os.path.join(path, "schema")): | ||||
|  | @ -155,7 +73,7 @@ def run(path: str = "."): | |||
|         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(".links", 'w') as link_out: | ||||
|             for dom in files: | ||||
|  | @ -169,32 +87,29 @@ def run(path: str = "."): | |||
|                       dom.get(s.primary), | ||||
|                       dom.src, | ||||
|                       ",".join(dom.mntner), | ||||
|                       sep="\t", | ||||
|                       sep="|", | ||||
|                       file=out) | ||||
| 
 | ||||
|                 for (link, refs) in s.links.items(): | ||||
|                     d = dom.get(link) | ||||
|                     refs_join = ','.join(refs) | ||||
|                     if d is not None: | ||||
|                         print( | ||||
|                             f"{dom.name}\t{link}\t{d}\t{','.join(refs)}", | ||||
|                             f"{dom.rel}|{dom.name}|{link}|{d}|{refs_join}", | ||||
|                             file=link_out) | ||||
| 
 | ||||
|     print("Generate .netindex", file=sys.stderr) | ||||
|     tree = make_tree({n.network for n in nets}) | ||||
|     print("Generate .nettree", file=sys.stderr) | ||||
|     tree = NetTree(nets) | ||||
| 
 | ||||
|     netindex = [] | ||||
|     for net in nets: | ||||
|         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 .nettree", file=sys.stderr) | ||||
|     tree.write_csv(".nettree") | ||||
| 
 | ||||
|     print("Writing .netindex", file=sys.stderr) | ||||
|     with open(".netindex", "w") as out: | ||||
|         for row in sorted(netindex, key=lambda x: x[0]): | ||||
|             print("\t".join([str(i) for i in row]), file=out) | ||||
|     print("Writing .schema", file=sys.stderr) | ||||
|     s = TransactDOM() | ||||
|     s.mntner = "DN42-MNT" | ||||
|     s.files = schemas.values() | ||||
|     with open(".schema", "w") as out: | ||||
|         print(s, file=out) | ||||
| 
 | ||||
|     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._spec = {}  # type: Dict[str, str] | ||||
|         self._links = {}  # type: Dict[str, List[str]] | ||||
|         self._dom = dom | ||||
| 
 | ||||
|         if dom is not None: | ||||
|             self.parse(dom) | ||||
|  | @ -82,6 +83,7 @@ class SchemaDOM: | |||
|     def parse(self, f: FileDOM): | ||||
|         """Parse a FileDOM into a SchemaDOM""" | ||||
|         self.src = self.src if f.src is None else f.src | ||||
|         self._dom = f | ||||
| 
 | ||||
|         schema = {} | ||||
|         for row in f.dom: | ||||
|  | @ -225,6 +227,9 @@ class SchemaDOM: | |||
|                         f"in {refs} but does not exist.") | ||||
|         return state | ||||
| 
 | ||||
|     def __str__(self) -> str: | ||||
|         return self._dom.__str__() | ||||
| 
 | ||||
| 
 | ||||
| def read_file(src: str) -> SchemaDOM: | ||||
|     """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 | ||||
| 
 | ||||
|             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
	
	 Jonathan Lundy
						Jonathan Lundy