mirror of
				https://git.dn42.dev/dn42/registry.git
				synced 2025-10-31 11:40:40 +08:00 
			
		
		
		
	add policy checks
This commit is contained in:
		
							parent
							
								
									e407b0195c
								
							
						
					
					
						commit
						0689c8bb82
					
				
					 1 changed files with 311 additions and 0 deletions
				
			
		|  | @ -8,6 +8,8 @@ import sys | |||
| import argparse | ||||
| import log | ||||
| import glob | ||||
| import random | ||||
| from pprint import pprint | ||||
| 
 | ||||
| 
 | ||||
| SCHEMA_NAMESPACE = "dn42." | ||||
|  | @ -335,6 +337,218 @@ def index_files(path): | |||
|         print("%s\t%s\t%s\t%s" % i) | ||||
| 
 | ||||
| 
 | ||||
| def http_get(server, url, query=None, headers=None): | ||||
|     import urllib.parse | ||||
|     import http.client | ||||
|     import json | ||||
| 
 | ||||
|     if headers is None: | ||||
|         headers = {} | ||||
|     if 'User-Agent' not in headers: | ||||
|         headers['User-Agent'] = "curl" | ||||
|     if 'Accept' not in headers: | ||||
|         headers['Accept'] = 'application/json' | ||||
| 
 | ||||
|     if query is None: | ||||
|         query = {} | ||||
| 
 | ||||
|     http_client = http.client.HTTPSConnection(server) | ||||
| 
 | ||||
|     full_url = url + '?' + urllib.parse.urlencode(query) | ||||
|     log.debug("GET " + full_url) | ||||
| 
 | ||||
|     http_client.request('GET', full_url, headers=headers) | ||||
|     req = http_client.getresponse() | ||||
|     log.debug("HTTP Response: %d %s" % (req.status, req.reason)) | ||||
| 
 | ||||
|     if "application/json" in req.getheader("Content-Type", "application/json"): | ||||
|         if req.status > 299: | ||||
|             return {} | ||||
|         return json.loads(req.read()) | ||||
| 
 | ||||
|     if req.status > 299: | ||||
|         return "" | ||||
| 
 | ||||
|     return req.read() | ||||
| 
 | ||||
| def find(fields=None, filter=None): | ||||
|     server = "util.sour.is" | ||||
|     url    = "/v1/reg/reg.objects" | ||||
|     if fields is None: | ||||
|         fields = [] | ||||
|     if filter is None: | ||||
|         filter = {} | ||||
|     query = {"fields": ",".join(fields), "filter": ",".join([k + "=" + v for k, v in filter.items()])} | ||||
|     return http_get(server, url, query) | ||||
| 
 | ||||
| def test_policy(obj_type, name, mntner): | ||||
|     log.debug([obj_type, name, mntner]) | ||||
| 
 | ||||
|     if obj_type in ["organisation", "mntner", "person", "role", "as-set", "schema", "dns"]: | ||||
|         if obj_type == "organisation" and not name.startswith("ORG-"): | ||||
|             log.error("%s does not start with 'ORG-'" %(name)) | ||||
|             return "FAIL" | ||||
|         elif obj_type == "mntner" and not name.endswith("-MNT"): | ||||
|             log.error("%s does not end with '-MNT'" %(name)) | ||||
|             return "FAIL" | ||||
|         elif obj_type == "dns" and not name.endswith(".dn42"): | ||||
|             log.error("%s does not end with '.dn42'" %(name)) | ||||
|             return "FAIL" | ||||
|         elif obj_type == "dns" and len(name.strip(".").split(".")) != 2: | ||||
|             log.error("%s is not a second level domain" %(name)) | ||||
|             return "FAIL" | ||||
|         elif obj_type in ["person", "role"] and not name.endswith("-DN42"): | ||||
|             log.error("%s does not end with '-DN42'" %(name)) | ||||
|             return "FAIL" | ||||
| 
 | ||||
|         lis = find(["mnt-by"], {"@type": obj_type, "@name": name}) | ||||
| 
 | ||||
|         if len(lis) == 0: | ||||
|             log.notice("%s does not currently exist" %(name)) | ||||
|             return "PASS" | ||||
| 
 | ||||
|         status = 'FAIL' | ||||
|         for o in lis: | ||||
|             for n in o: | ||||
|                 if n[0] == "mnt-by" and n[1] == mntner: | ||||
|                     status = 'PASS' | ||||
|                     log.error("%s does not have mnt for object" %(mntner)) | ||||
|                     return status | ||||
| 
 | ||||
|         return status | ||||
| 
 | ||||
|     elif args["type"] in ["inetnum","inet6num"]: | ||||
|         lis = find(["mnt-by"], {"@type": "aut-num", "@name": name}) | ||||
|         log.info(lis) | ||||
| 
 | ||||
|         pass | ||||
|     elif args["type"] in ["route","route6"]: | ||||
|         lis = find(["mnt-by"], {"@type": "aut-num", "@name": name}) | ||||
|         log.info(lis) | ||||
| 
 | ||||
|         pass | ||||
|     elif args["type"] == "aut-num": | ||||
|         if not name.startswith("AS"): | ||||
|             log.error("%s does not start with AS" %(name)) | ||||
|             return "FAIL" | ||||
| 
 | ||||
|         # 1. Check if they already have an object | ||||
|         lis = find(["mnt-by"], {"@type": "aut-num", "@name": name}) | ||||
|         log.info(lis) | ||||
| 
 | ||||
|         if len(lis) > 0: | ||||
|             status = 'FAIL' | ||||
|             for o in lis: | ||||
|                 for n in o: | ||||
|                     if n[0] == "mnt-by" and n[1] == mntner: | ||||
|                         status = 'PASS' | ||||
|                         log.notice("%s has mnt for current object" %(mntner)) | ||||
|                         return status | ||||
|             log.error("%s does not have mnt for current object" %(mntner)) | ||||
|             return status | ||||
| 
 | ||||
|         # 2. Check if the as-block has an open policy | ||||
|         asn = "AS{:0>9}".format(name[2:]) | ||||
|         lis = find(["as-block","policy","@as-min","@as-max","mnt-by","mnt-lower"], {"@type": "as-block","@as-min":"le=" + asn,"@as-max": "ge=" + asn}) | ||||
|         log.info(lis) | ||||
| 
 | ||||
|         policy = {} | ||||
|         select = None | ||||
|         mntners = [] | ||||
| 
 | ||||
|         for n in lis: | ||||
|             obj = {} | ||||
|             for o in n: | ||||
|                 obj[o[0]] = o[1] | ||||
|                 if o[0].startswith("mnt-"): | ||||
|                     mntners.append(o[1]) | ||||
| 
 | ||||
|             k = (obj["@as-min"],obj["@as-max"]) | ||||
|             policy[k] = obj | ||||
| 
 | ||||
|             if select is None: | ||||
|                 select = k | ||||
|             elif select[0]<=k[0] or select[1]>=k[1]: | ||||
|                 select = k | ||||
| 
 | ||||
|         if policy[select]["policy"] == "open": | ||||
|             log.notice("Policy is open for parent object") | ||||
|             return "PASS" | ||||
|          | ||||
|         # 3. Check if mntner or mnt-lower for any as-block in the tree. | ||||
|         elif mntner in mntners: | ||||
|             log.notice("%s has mnt in parent object" %(mntner)) | ||||
|             return "PASS" | ||||
| 
 | ||||
|     elif args["type"] == "as-block": | ||||
|         Lname, Hname = name.split("-") | ||||
|         Lname, Hname = Lname.strip(), Hname.strip() | ||||
| 
 | ||||
|         if not Lname.startswith("AS") or not Hname.startswith("AS"): | ||||
|             log.error("%s does not start with AS for min and max" %(name)) | ||||
|             return "FAIL" | ||||
| 
 | ||||
|         # 1. Check if they already have an object | ||||
|         lis = find(["mnt-by"], {"@type": "as-block", "@name": name}) | ||||
|         log.info(lis) | ||||
| 
 | ||||
|         if len(lis) > 0: | ||||
|             status = 'FAIL' | ||||
|             for o in lis: | ||||
|                 for n in o: | ||||
|                     if n[0] == "mnt-by" and n[1] == mntner: | ||||
|                         status = 'PASS' | ||||
|                         log.notice("%s has mnt for current object" %(mntner)) | ||||
|                         return status | ||||
|             log.notice("%s does not have mnt for current object" %(mntner)) | ||||
|             return status | ||||
| 
 | ||||
|         # 2. Check if the parent as-blocks have an open policy | ||||
|         Lasn = "AS{:0>9}".format(Lname[2:]) | ||||
|         Hasn = "AS{:0>9}".format(Hname[2:]) | ||||
|          | ||||
|         if Lasn > Hasn: | ||||
|             log.error("%s should come before %s" %(Lname, Hname)) | ||||
| 
 | ||||
| 
 | ||||
|         lis = find(["as-block","policy","@as-min","@as-max","mnt-by","mnt-lower"], {"@type": "as-block","@as-min":"le=" + Lasn,"@as-max": "ge=" + Hasn}) | ||||
|         log.info(lis) | ||||
| 
 | ||||
|         policy = {} | ||||
|         select = None | ||||
|         mntners = [] | ||||
| 
 | ||||
|         for n in lis: | ||||
|             obj = {} | ||||
|             for o in n: | ||||
|                 obj[o[0]] = o[1] | ||||
|                 if o[0].startswith("mnt-"): | ||||
|                     mntners.append(o[1]) | ||||
| 
 | ||||
|             k = (obj["@as-min"],obj["@as-max"]) | ||||
|             policy[k] = obj | ||||
| 
 | ||||
|             if select is None: | ||||
|                 select = k | ||||
|             elif select[0]<=k[0] or select[1]>=k[1]: | ||||
|                 select = k | ||||
| 
 | ||||
| #        Policy Open only applies to aut-nums. as-blocks must be defined by parent mntners only. | ||||
| # | ||||
| #        if policy[select]["policy"] == "open": | ||||
| #            log.notice("Policy is open for parent object") | ||||
| #            return "PASS" | ||||
|          | ||||
|         # 3. Check if mntner or mnt-lower for any as-block in the tree. | ||||
|         if mntner in mntners: | ||||
|             log.notice("%s has mnt in parent object" %(mntner))             | ||||
|             return "PASS" | ||||
| 
 | ||||
|         pass | ||||
| 
 | ||||
|     log.error("%s does not pass checks for %s %s" %(mntner, obj_type, name)) | ||||
|     return "FAIL"  | ||||
| 
 | ||||
| def get_args(): | ||||
|     """Get and parse command line arguments""" | ||||
| 
 | ||||
|  | @ -384,6 +598,13 @@ def get_args(): | |||
|     parser_fmt.add_argument('-i',  '--in-place', | ||||
|                              help="Format file in place", action="store_true") | ||||
| 
 | ||||
|     parser_pol = subparsers.add_parser('policy', help='Format file') | ||||
|     parser_pol.add_argument('type',   nargs="?", type=str, help="dn42 object type") | ||||
|     parser_pol.add_argument('name',   nargs="?", type=str, help="dn42 object name") | ||||
|     parser_pol.add_argument('mntner', nargs="?", type=str, help="dn42 object mntner") | ||||
| 
 | ||||
|     parser_mroute = subparsers.add_parser('match-routes', help='Match routes to inetnums') | ||||
| 
 | ||||
|     return vars(parser.parse_args()) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -437,3 +658,93 @@ if __name__ == '__main__': | |||
|                 f.write(str(dom)) | ||||
| 
 | ||||
|         print(str(dom)) | ||||
| 
 | ||||
|     elif args["command"] == "policy": | ||||
| 
 | ||||
|         if args["type"] is None: | ||||
|             log.fatal("Type should be provided") | ||||
| 
 | ||||
|         if args["name"] is None: | ||||
|             log.fatal("Name should be provided") | ||||
| 
 | ||||
|         if args["mntner"] is None: | ||||
|             log.fatal("Mntner should be provided") | ||||
|              | ||||
| 
 | ||||
|         status = test_policy(args["type"], args["name"], args["mntner"])         | ||||
| 
 | ||||
|         print(status) | ||||
|         if status != "PASS": | ||||
|             sys.exit(1) | ||||
| 
 | ||||
|     elif args["command"] == "match-routes": | ||||
|         lis = find(["mnt-by","cidr","route","@netlevel", "@netmin", "@netmax", "@uri"], {"@family":"ipv4"}) | ||||
| 
 | ||||
|         def field(x, field): | ||||
|             for i in x: | ||||
|                 if i[0] == field: | ||||
|                     return i[1] | ||||
|             return None | ||||
| 
 | ||||
|         def lvl(x): | ||||
|             for i in x: | ||||
|                 if i[0] == "@netlevel": | ||||
|                     return i[1] | ||||
| 
 | ||||
|         def net(x): | ||||
|             for i in x: | ||||
|                 if i[0] == "@netmin": | ||||
|                     return i[1] | ||||
| 
 | ||||
|         def is_net(x): | ||||
|             i = field(x, "cidr") | ||||
|             if i is not None: | ||||
|                     return True | ||||
|             return False | ||||
| 
 | ||||
|         def obj(x): | ||||
|             d = {} | ||||
|             for k,v in x: | ||||
|                 if k in d: | ||||
|                     d[k].append(v) | ||||
|                 else: | ||||
|                     d[k] = [v] | ||||
|             return d | ||||
| 
 | ||||
|         inet = None | ||||
|         first = True | ||||
|         for n in sorted(sorted(lis, key=lvl), key=net): | ||||
|             o = obj(n) | ||||
| 
 | ||||
|             if is_net(n): | ||||
|                 if not first: | ||||
|                     print() | ||||
|                 first = True | ||||
|                 inet = o | ||||
|                 continue | ||||
| 
 | ||||
|             ilvl = int(inet["@netlevel"][0]) | ||||
|             rlvl = int(o["@netlevel"][0]) | ||||
| 
 | ||||
|             if ilvl + 1 != rlvl: | ||||
|                 print("\nNo Parent > ", o["route"][0], " ", rlvl, " ", ",".join(o["mnt-by"]), \ | ||||
|                       "Nearest INET ", inet["cidr"][0], " ", ilvl, " ", ",".join(inet["mnt-by"])) | ||||
| 
 | ||||
|                 first = True | ||||
|                 continue | ||||
| 
 | ||||
|             if inet["@netmin"][0] > o["@netmin"][0] or inet["@netmax"][0] < o["@netmax"][0]: | ||||
|                 print("\nNo Parent > ", o["route"][0], " ", rlvl, " ", ",".join(o["mnt-by"]), \ | ||||
|                       "Nearest INET ", inet["cidr"][0], " ", ilvl, " ", ",".join(inet["mnt-by"])) | ||||
| 
 | ||||
|                 first = True | ||||
|                 continue | ||||
| 
 | ||||
|             continue | ||||
|             if first: | ||||
|                 first = False | ||||
|                 print(inet["cidr"]," ", ilvl, ",".join(inet["mnt-by"]))  | ||||
|                 print("            > ", o["route"][0], " ", rlvl, " ", ",".join(o["mnt-by"]))  | ||||
|             else: | ||||
|                 print("            > ", o["route"][0], " ", rlvl, " ", ",".join(o["mnt-by"]))  | ||||
|                  | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 xuu
						xuu