From eaf531eee213ec0bb5936f982497b6a8b548d614 Mon Sep 17 00:00:00 2001 From: tamihiro Date: Sun, 9 Jun 2019 18:35:20 +0900 Subject: [PATCH 01/25] Correctly parse aspath for both bird 1.x and 2.0. Due to the change in the output of `show route for all` since bird-2.0, this patch is necessary to correctly parse aspaths. Without this patch, `build_as_tree_from_raw_bird_ouput()` fails with the following exception if the backend is bird-2.0. ``` Traceback (most recent call last): File "/usr/lib/python2.7/dist-packages/flask/app.py", line 1836, in __call__ return self.wsgi_app(environ, start_response) File "/usr/lib/python2.7/dist-packages/flask/app.py", line 1820, in wsgi_app response = self.make_response(self.handle_exception(e)) File "/usr/lib/python2.7/dist-packages/flask/app.py", line 1403, in handle_exception reraise(exc_type, exc_value, tb) File "/usr/lib/python2.7/dist-packages/flask/app.py", line 1817, in wsgi_app response = self.full_dispatch_request() File "/usr/lib/python2.7/dist-packages/flask/app.py", line 1477, in full_dispatch_request rv = self.handle_user_exception(e) File "/usr/lib/python2.7/dist-packages/flask/app.py", line 1381, in handle_user_exception reraise(exc_type, exc_value, tb) File "/usr/lib/python2.7/dist-packages/flask/app.py", line 1475, in full_dispatch_request rv = self.dispatch_request() File "/usr/lib/python2.7/dist-packages/flask/app.py", line 1461, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) File "./lg.py", line 522, in show_bgpmap response = Response(graph.create_png(), mimetype='image/png') File "/usr/lib/python2.7/dist-packages/pydot.py", line 1735, in lambda f=frmt, prog=self.prog: self.create(format=f, prog=prog) File "/usr/lib/python2.7/dist-packages/pydot.py", line 1905, in create self.write(tmp_name) File "/usr/lib/python2.7/dist-packages/pydot.py", line 1830, in write data = self.to_string() File "/usr/lib/python2.7/dist-packages/pydot.py", line 1600, in to_string graph.append(node.to_string() + '\n') File "/usr/lib/python2.7/dist-packages/pydot.py", line 865, in to_string node += ' [' + node_attr + ']' TypeError: unsupported operand type(s) for +=: 'NoneType' and 'str' ``` Consequently, `show route for (bgpmap)` shows an error icon. --- lg.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/lg.py b/lg.py index 40caa95..daf3973 100644 --- a/lg.py +++ b/lg.py @@ -538,21 +538,29 @@ def build_as_tree_from_raw_bird_ouput(host, proto, text): path = None paths = [] net_dest = None + peer_protocol_name = None for line in text: line = line.strip() - expr = re.search(r'(.*)via\s+([0-9a-fA-F:\.]+)\s+on.*\[(\w+)\s+', line) + expr = re.search(r'(.*)unicast\s+\[(\w+)\s+', line) if expr: + if expr.group(1).strip(): + net_dest = expr.group(1).strip() + peer_protocol_name = expr.group(2).strip() + + expr2 = re.search(r'(.*)via\s+([0-9a-fA-F:\.]+)\s+on\s+\w+(\s+\[(\w+)\s+)?', line) + if expr2: if path: path.append(net_dest) paths.append(path) path = None - if expr.group(1).strip(): - net_dest = expr.group(1).strip() + if expr2.group(1).strip(): + net_dest = expr2.group(1).strip() - peer_ip = expr.group(2).strip() - peer_protocol_name = expr.group(3).strip() + peer_ip = expr2.group(2).strip() + if expr2.group(4): + peer_protocol_name = expr2.group(4).strip() # Check if via line is a internal route for rt_host, rt_ips in app.config["ROUTER_IP"].iteritems(): # Special case for internal routing @@ -564,15 +572,18 @@ def build_as_tree_from_raw_bird_ouput(host, proto, text): path = [ peer_protocol_name ] # path = ["%s\r%s" % (peer_protocol_name, get_as_name(get_as_number_from_protocol_name(host, proto, peer_protocol_name)))] - expr2 = re.search(r'(.*)unreachable\s+\[(\w+)\s+', line) - if expr2: + expr3 = re.search(r'(.*)unreachable\s+\[(\w+)\s+', line) + if expr3: if path: path.append(net_dest) paths.append(path) path = None - if expr2.group(1).strip(): - net_dest = expr2.group(1).strip() + if path is None: + path = [ expr3.group(2).strip() ] + + if expr3.group(1).strip(): + net_dest = expr3.group(1).strip() if line.startswith("BGP.as_path:"): ASes = line.replace("BGP.as_path:", "").strip().split(" ") From 2c0d5ac2737e0666ffc42bbf4501d61a3c5f0869 Mon Sep 17 00:00:00 2001 From: tamihiro Date: Sun, 9 Jun 2019 21:35:59 +0900 Subject: [PATCH 02/25] Correctly display each of multiple destination prefixes with a box shape. Without this patch, `show route where net ~ [ prefix+ ] (bgpmap)` erroneously returns only one prefix with a box shape, and all the other prefixes with a oval shape as if they were multipath intermediate ASes. --- lg.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lg.py b/lg.py index 40caa95..ad36a2f 100644 --- a/lg.py +++ b/lg.py @@ -491,7 +491,10 @@ def show_bgpmap(): hop_label = "" - add_node(_as, fillcolor=(first and "#F5A9A9" or "white")) + if _as == asmap[-1]: + add_node(_as, fillcolor="#F5A9A9", shape="box", ) + else: + add_node(_as, fillcolor=(first and "#F5A9A9" or "white"), ) if hop_label: edge = add_edge(nodes[previous_as], nodes[_as], label=hop_label, fontsize="7") else: @@ -499,20 +502,16 @@ def show_bgpmap(): hop_label = "" - if first: + if first or _as == asmap[-1]: edge.set_style("bold") edge.set_color("red") - elif edge.get_color() != "red": + elif edge.get_style() != "bold": edge.set_style("dashed") edge.set_color(color) previous_as = _as first = False - if previous_as: - node = add_node(previous_as) - node.set_shape("box") - for _as in prepend_as: graph.add_edge(pydot.Edge(*(_as, _as), label=" %dx" % prepend_as[_as], color="grey", fontcolor="grey")) From 648197da2403c81145438d63f27bd023cac1e677 Mon Sep 17 00:00:00 2001 From: tamihiro Date: Sun, 9 Jun 2019 21:41:35 +0900 Subject: [PATCH 03/25] Correct AS path prepend count in bgpmap. Without this patch, show_bgpmap() method does duplicate counts of aspath prepends, and returns a larger prepend count than it actually is. --- lg.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lg.py b/lg.py index 40caa95..56873a6 100644 --- a/lg.py +++ b/lg.py @@ -477,7 +477,13 @@ def show_bgpmap(): hop_label = "" for _as in asmap: if _as == previous_as: - prepend_as[_as] = prepend_as.get(_as, 1) + 1 + if not prepend_as.get(_as, None): + prepend_as[_as] = {} + if not prepend_as[_as].get(host, None): + prepend_as[_as][host] = {} + if not prepend_as[_as][host].get(asmap[0], None): + prepend_as[_as][host][asmap[0]] = 1 + prepend_as[_as][host][asmap[0]] += 1 continue if not hop: @@ -514,7 +520,8 @@ def show_bgpmap(): node.set_shape("box") for _as in prepend_as: - graph.add_edge(pydot.Edge(*(_as, _as), label=" %dx" % prepend_as[_as], color="grey", fontcolor="grey")) + for n in set([ n for h, d in prepend_as[_as].iteritems() for p, n in d.iteritems() ]): + graph.add_edge(pydot.Edge(*(_as, _as), label=" %dx" % n, color="grey", fontcolor="grey")) fmt = request.args.get('fmt', 'png') #response = Response("
" + graph.create_dot() + "
") From 86c4cf296569db823b527d0737c82451110f118f Mon Sep 17 00:00:00 2001 From: netfreak98 <31798580+netfreak98@users.noreply.github.com> Date: Sun, 1 Mar 2020 19:57:01 +0100 Subject: [PATCH 04/25] Update README.mkd Added our LG to the list (AS49697) :) --- README.mkd | 1 + 1 file changed, 1 insertion(+) diff --git a/README.mkd b/README.mkd index 1b14ac5..cd7bcb3 100644 --- a/README.mkd +++ b/README.mkd @@ -83,3 +83,4 @@ Happy users * https://lg.fullsave.net/ * http://lg.catnix.net/ * https://lg.worldstream.nl/ +* https://route-server.netshelter.de/ From 1a13a41db73c433201177b0b527551fb97801195 Mon Sep 17 00:00:00 2001 From: vidister Date: Wed, 29 Apr 2020 13:59:42 +0200 Subject: [PATCH 05/25] Add shebang to lgproxy.py --- lgproxy.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lgproxy.py b/lgproxy.py index e6018f0..ef3b06e 100644 --- a/lgproxy.py +++ b/lgproxy.py @@ -1,3 +1,4 @@ +#!/usr/bin/python # -*- coding: utf-8 -*- # vim: ts=4 ### From 9d9d93805eea07b9b099a6b937069c3fa468cc57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lteri=C5=9F=20Ero=C4=9Flu?= Date: Wed, 29 Apr 2020 18:51:25 +0300 Subject: [PATCH 06/25] Removed br tag replacer on whois endpoint --- lg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lg.py b/lg.py index 2db377f..4db3b9c 100644 --- a/lg.py +++ b/lg.py @@ -218,7 +218,7 @@ def whois(): if m: query = query.groupdict()["domain"] - output = whois_command(query).replace("\n", "
") + output = whois_command(query) return jsonify(output=output, title=query) From 95fd86238889017e8513a5aa4525c7084e4e464d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lteri=C5=9F=20Ero=C4=9Flu?= Date: Wed, 29 Apr 2020 18:52:24 +0300 Subject: [PATCH 07/25] Added css to whois modal to handle newlines --- static/js/lg.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/js/lg.js b/static/js/lg.js index 358fc95..1a8b496 100644 --- a/static/js/lg.js +++ b/static/js/lg.js @@ -58,7 +58,7 @@ $(function(){ link = $(this).attr('href'); $.getJSON(link, function(data) { $(".modal h3").html(data.title); - $(".modal .modal-body > p").html(data.output); + $(".modal .modal-body > p").css("white-space", "pre-line").text(data.output); $(".modal").modal('show'); }); }); From d3e9d5c6b9c7badfedf95dd7b1b1c962b8a0689c Mon Sep 17 00:00:00 2001 From: Guillaume Marsay Date: Mon, 15 Jun 2020 09:57:59 +0200 Subject: [PATCH 08/25] DOMAIN is now optional --- lg.py | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/lg.py b/lg.py index 3616c58..3be6307 100644 --- a/lg.py +++ b/lg.py @@ -148,16 +148,23 @@ def bird_proxy(host, proto, service, query): return False, 'Host "%s" invalid' % host elif not path: return False, 'Proto "%s" invalid' % proto - else: - url = "http://%s.%s:%d/%s?q=%s" % (host, app.config["DOMAIN"], port, path, quote(query)) - try: - f = urlopen(url) - resultat = f.read() - status = True # retreive remote status - except IOError: - resultat = "Failed retreive url: %s" % url - status = False - return status, resultat + + url = "http://%s" % (host) + if "DOMAIN" in app.config: + url = "%s.%s" % (url, app.config["DOMAIN"]) + url = "%s:%d/%s?" % (url, port, path) + + url = "%sq=%s" % (url, quote(query)) + + try: + f = urlopen(url) + resultat = f.read() + status = True # retreive remote status + except IOError: + resultat = "Failed retreive url: %s" % url + status = False + + return status, resultat @app.context_processor @@ -459,7 +466,10 @@ def show_bgpmap(): return edges[edge_tuple] for host, asmaps in data.iteritems(): - add_node(host, label= "%s\r%s" % (host.upper(), app.config["DOMAIN"].upper()), shape="box", fillcolor="#F5A9A9") + if "DOMAIN" in app.config: + add_node(host, label= "%s\r%s" % (host.upper(), app.config["DOMAIN"].upper()), shape="box", fillcolor="#F5A9A9") + else: + add_node(host, label= "%s" % (host.upper()), shape="box", fillcolor="#F5A9A9") as_number = app.config["AS_NUMBER"].get(host, None) if as_number: From 96c33da44690adba5c257863ffcf993bcffe7ab5 Mon Sep 17 00:00:00 2001 From: Guillaume Marsay Date: Mon, 15 Jun 2020 13:27:26 +0200 Subject: [PATCH 09/25] Add SHARED_SECRET --- lg.cfg | 3 +++ lg.py | 3 ++- lgproxy.cfg | 9 +++++++++ lgproxy.py | 13 +++++++++---- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/lg.cfg b/lg.cfg index 2cc3388..5ddfc5d 100644 --- a/lg.cfg +++ b/lg.cfg @@ -5,6 +5,9 @@ LOG_LEVEL="WARNING" DOMAIN = "tetaneutral.net" +# Used for restrict access on lgproxy - must be same in lgproxy.cfg +SHARED_SECRET="ThisTokenIsNotSecret" + BIND_IP = "0.0.0.0" BIND_PORT = 5000 diff --git a/lg.py b/lg.py index 3be6307..e9ea3e5 100644 --- a/lg.py +++ b/lg.py @@ -153,7 +153,8 @@ def bird_proxy(host, proto, service, query): if "DOMAIN" in app.config: url = "%s.%s" % (url, app.config["DOMAIN"]) url = "%s:%d/%s?" % (url, port, path) - + if "SHARED_SECRET" in app.config: + url = "%ssecret=%s&" % (url, app.config["SHARED_SECRET"]) url = "%sq=%s" % (url, quote(query)) try: diff --git a/lgproxy.cfg b/lgproxy.cfg index e7a6e8a..7019e52 100644 --- a/lgproxy.cfg +++ b/lgproxy.cfg @@ -1,12 +1,21 @@ DEBUG=False + LOG_FILE="/var/log/lg-proxy/lg-proxy.log" LOG_LEVEL="WARNING" + BIND_IP = "0.0.0.0" BIND_PORT = 5000 + +# Used for restrict access on lgproxy - Empty list = all allowed ACCESS_LIST = ["91.224.149.206", "178.33.111.110", "2a01:6600:8081:ce00::1"] + +# Used for restrict access on lgproxy - Must be same in lg.cfg +SHARED_SECRET="ThisTokenIsNotSecret" + IPV4_SOURCE="" IPV6_SOURCE="" + BIRD_SOCKET="/var/run/bird/bird.ctl" BIRD6_SOCKET="/var/run/bird/bird6.ctl" diff --git a/lgproxy.py b/lgproxy.py index e1b3cdb..a81abb9 100644 --- a/lgproxy.py +++ b/lgproxy.py @@ -54,14 +54,19 @@ def access_log_after(response, *args, **kwargs): app.logger.info("[%s] reponse %s, %s", request.remote_addr, request.url, response.status_code) return response -def check_accesslist(): - if app.config["ACCESS_LIST"] and request.remote_addr not in app.config["ACCESS_LIST"]: +def check_security(): + if app.config["ACCESS_LIST"] and request.remote_addr not in app.config["ACCESS_LIST"]: + app.logger.info("Your remote address is not valid") + abort(401) + + if app.config.get('SHARED_SECRET') and request.args.get("secret") != app.config["SHARED_SECRET"]: + app.logger.info("Your shared secret is not valid") abort(401) @app.route("/traceroute") @app.route("/traceroute6") def traceroute(): - check_accesslist() + check_security() if sys.platform.startswith('freebsd') or sys.platform.startswith('netbsd') or sys.platform.startswith('openbsd'): traceroute4 = [ 'traceroute' ] @@ -100,7 +105,7 @@ def traceroute(): @app.route("/bird") @app.route("/bird6") def bird(): - check_accesslist() + check_security() if request.path == "/bird": b = BirdSocket(file=app.config.get("BIRD_SOCKET")) elif request.path == "/bird6": b = BirdSocket(file=app.config.get("BIRD6_SOCKET")) From f87719956a156e200112b200545590b71133f884 Mon Sep 17 00:00:00 2001 From: Guillaume Marsay Date: Mon, 15 Jun 2020 13:13:05 +0200 Subject: [PATCH 10/25] Add WEBSITE_TITLE - Issue #69 --- lg.cfg | 2 +- templates/layout.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lg.cfg b/lg.cfg index 2cc3388..b40f4d1 100644 --- a/lg.cfg +++ b/lg.cfg @@ -1,4 +1,4 @@ - +WEBSITE_TITLE="Bird-LG / Looking Glass" DEBUG = False LOG_FILE="/var/log/lg.log" LOG_LEVEL="WARNING" diff --git a/templates/layout.html b/templates/layout.html index 34071b0..aa57f29 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -1,6 +1,6 @@ - {{config.DOMAIN|capitalize}} looking glass + {{config.WEBSITE_TITLE|default("Bird-LG / Looking Glass") }} @@ -18,7 +18,7 @@ - {{config.DOMAIN|capitalize}} / Looking Glass + {{config.WEBSITE_TITLE|default("Bird-LG / Looking Glass") }}