From 9df351a4fb5a0f02734fb51e83c3f823bbc70668 Mon Sep 17 00:00:00 2001 From: Fabien VINCENT Date: Mon, 16 Jul 2018 14:37:17 +0200 Subject: [PATCH] Allo to show route as JSON value Example : https://[[LG_MASTER]]/api/[[LG_NODES_LIST]]/ipv4?q=8.8.8.8 Return : { "[[LG_NODES_LIST]]": { "result": [ { "origin": "IGP", "med": 0, "via": "1.1.1.2", "last": "2018-07-10", "network": "8.8.8.0", "localPref": 350, "asPath": "15169", "originatorId": { "addr": "4.4.4.4", "reverse": "router.fr.eu" }, "community": [ "65000:65000" ], "clusterList": [ "9.89.6.6", "9.89.8.8" ], "netmask": "24", "fromPeer": "bird", "from": "4.4.4.4", "nextHop": { "addr": "1.1.1.2", "reverse": "google.fr.eu" }, "ipType": "IPv4" } ] } } --- lg.py | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/lg.py b/lg.py index 7bace5e..b97fe91 100644 --- a/lg.py +++ b/lg.py @@ -52,6 +52,13 @@ memcache_server = app.config.get("MEMCACHE_SERVER", "127.0.0.1:11211") memcache_expiration = int(app.config.get("MEMCACHE_EXPIRATION", "1296000")) # 15 days by default mc = memcache.Client([memcache_server]) +def reverse(ip): + try: + name, alias, addresslist = socket.gethostbyaddr(ip) + return name + except socket.herror: + return "" + def get_asn_from_as(n): asn_zone = app.config.get("ASN_ZONE", "asn.cymru.com") try: @@ -64,16 +71,31 @@ def get_asn_from_as(n): def add_links(text): """Browser a string and replace ipv4, ipv6, as number, with a whois link """ + ipv4_re = re.compile('(BGP.next_hop|BGP.originator_id):\s+(\d+\.\d+\.\d+\.\d+).*') + ipv6_re = re.compile('(BGP.next_hop|BGP.originator_id):\s+(([0-9a-fA-F]{1,4}:)*:?(?:([0-9a-fA-F]{1,4}))).*') if type(text) in [str, unicode]: text = text.split("\n") ret_text = [] for line in text: + reverse = None + mipv4 = ipv4_re.match(line.strip()) + mipv6 = ipv6_re.match(line.strip()) # Some heuristic to create link if line.strip().startswith("BGP.as_path:") or \ line.strip().startswith("Neighbor AS:"): ret_text.append(re.sub(r'(\d+)', r'\1', line)) + elif mipv4: + ipv4 = mipv4.group(2) + reverse = dns(ipv4) + line = re.sub(ipv4,r''+ipv4+' '+reverse+'', line) + ret_text.append(line) + elif mipv6: + ipv6 = mipv6.group(2) + reverse = dns(ipv6) + line = re.sub(ipv6,r''+ipv6+' '+reverse+'', line) + ret_text.append(line) else: line = re.sub(r'([a-zA-Z0-9\-]*\.([a-zA-Z]{2,3}){1,2})(\s|$)', r'\1\3', line) line = re.sub(r'AS(\d+)', r'AS\1', line) @@ -87,6 +109,94 @@ def add_links(text): ret_text.append(line) return "\n".join(ret_text) +def add_json(text): + """Browser a string and replace ipv4, ipv6, as number, with a + whois link """ + ipv4_re = re.compile('^(\d+\.\d+\.\d+\.\d+).*') + ipv6_re = re.compile('^(([0-9a-fA-F]{1,4}:)*:?(?:([0-9a-fA-F]{1,4}))).*') + + if type(text) in [str, unicode]: + text = text.split("\n") + + q = {} + data = [] + current = {} + current['asPath'] = "" + current['med'] = 0 + peer = "" + for line in text: + reverse = None + mipv4 = ipv4_re.match(line.strip()) + mipv6 = ipv6_re.match(line.strip()) + # Some heuristic to create link + m = re.search(r'^((?:\d+\.\d+\.\d+\.\d+)|(?:[0-9a-fA-F]{1,4}:)*:?(?:(?:[0-9a-fA-F]{1,4})?))?\/?(\d+)?\s+via\s+((?:\d+\.\d+\.\d+\.\d+)|(?:[0-9a-fA-F]{1 +,4}:)*:?(?:(?:[0-9a-fA-F]{1,4})?))\son\seth\d+\s\[([a-z0-9_]+)\s(\d+-\d+-\d+)\sfrom\s((?:\d+\.\d+\.\d+\.\d+)|(?:[0-9a-fA-F]{1,4}:)*:?(?:(?:[0-9a-fA-F]{1,4})?) +)\].*$', line.strip()) + if m is not None: + if peer != m.group(4): + data.append(current) + if m.group(1): + current['network'] = m.group(1) + current['netmask'] = m.group(2) + peer = m.group(4) + current['fromPeer'] = m.group(4) + current['last'] = m.group(5) + current['via'] = m.group(3) + current['from'] = m.group(6) + if re.match(r"\d+\.\d+\.\d+\.\d+", current['network']): + current["ipType"] = "IPv4" + elif re.match(r"(?:[0-9a-fA-F]{1,4}:)*:?(?:(?:[0-9a-fA-F]{1,4})?)", current['network']): + current["ipType"] = "IPv6" + if line.strip().startswith("BGP.as_path:"): + m = re.search(r"BGP.as_path: (?P\d+\s*)*", line.strip()) + if m is not None: + current['asPath'] = m.group('asPath') + elif line.strip().startswith("BGP.origin:"): + m = re.search(r"BGP.origin: (?P\w+\s*)*", line.strip()) + if m is not None: + current['origin'] = m.group('origin') + else: + current['origin'] = "" + elif line.strip().startswith("BGP.next_hop:"): + m = re.search(r"BGP.next_hop: (?P((([a-f\d]{0,4}:){3,10}[a-f\d]{0,4})|(\d+\.\d+\.\d+\.\d+))\s*)*", line.strip()) + if m is not None: + current['nextHop'] = {'addr': m.group('nextHop'), "reverse": reverse(m.group('nextHop'))} + else: + current['nextHop'] = {'addr': "", "reverse": ""} + elif line.strip().startswith("BGP.med:"): + m = re.search(r"BGP.med: (?P\d+\s*)*", line.strip()) + if m is not None: + current['med'] = int(m.group('med')) + else: + current['med'] = 0 + elif line.strip().startswith("BGP.local_pref:"): + m = re.search(r"BGP.local_pref: (?P\d+\s*)*", line.strip()) + if m is not None: + current['localPref'] = int(m.group('localPref')) + else: + current['localPref'] = 0 + elif line.strip().startswith("BGP.originator_id:"): + m = re.search(r"BGP.originator_id: (?P((([a-f\d]{0,4}:){3,10}[a-f\d]{0,4})|(\d+\.\d+\.\d+\.\d+))\s*)*", line.strip()) + if m is not None: + current['originatorId'] = {'addr': m.group('origin'), "reverse": reverse(m.group('origin'))} + else: + current['originator'] = {'addr': "", "reverse": ""} + elif line.strip().startswith("BGP.community:"): + current['community'] = [] + for m in re.findall(r"(\d+,\d+)", line.strip()): + if m is not None: + community = m + current['community'].append(community.replace(',',':')) + else: + current['community'] = "" + elif line.strip().startswith("BGP.cluster_list:"): + current['clusterList'] = [] + for m in re.findall(r"(\d+\.\d+\.\d+\.\d+)", line.strip()): + if m is not None: + current['clusterList'].append(m) + data.append(current) + return {'result':data} + def set_session(request_type, hosts, proto, request_args): """ Store all data from user in the user session """ @@ -656,6 +766,7 @@ def show_route(request_type, hosts, proto): return render_template((bgpmap and 'bgpmap.html' or 'route.html'), detail=detail, command=command, expression=expression, errors=errors) + def show_route_api(request_type, hosts, proto): expression = get_query() if not expression: