diff --git a/.gitignore b/.gitignore index 52e4e61..ce38835 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ *.pyc *.pyo +lg.cfg +lgproxy.cfg diff --git a/README.mkd b/README.mkd index cd7bcb3..4150e46 100644 --- a/README.mkd +++ b/README.mkd @@ -1,6 +1,9 @@ BIRD-LG ======= +Overview +-------- + This is a looking glass for the Internet Routing Daemon "Bird". Software is split in two parts: @@ -8,7 +11,8 @@ Software is split in two parts: - lgproxy.py: It must be installed and started on all bird nodes. It act as a proxy to make traceroute and bird query on the node. - Access restriction to this web service can be done in file "lgproxy.cfg" (only IP address based restriction for now). + Access restriction to this web service can be done in file "lgproxy.cfg". Two access restriction methods can be configured: + based on source IP address or based on a shared secret. Both methods can be used at the same time. - lg.py: @@ -33,17 +37,42 @@ Software is split in two parts: ``` -bird-lg depends on : +Installation +------------ + +The web service (lg.py) depends on: - python-flask >= 0.8 - python-dnspython - python-pydot - - python-memcache - graphviz - whois - - traceroute -Each services can be embedded in any webserver by following regular python-flask configuration. +The proxy running on routers (lgproxy.py) depends on: + + - python-flask >= 0.8 + - traceroute + - ping + +Each service can be embedded in any webserver by following regular python-flask configuration. +It is also possible to run the services directly with python for developping / testing: + + python2 lg.py + python2 lgproxy.py + +Systemd unit files are provided in the `init/` subdirectory. + + +Configuration +------------- + +On your routers, copy `lgproxy.cfg.example` to `lgproxy.cfg` and edit the values. + +On the web host, copy `lg.cfg.example` to `lg.cfg` and edit the values. + + +License +------- Source code is under GPL 3.0, powered by Flask, jQuery and Bootstrap. @@ -67,7 +96,8 @@ Happy users * https://lg.man-da.de/ * http://route-server.belwue.net/ * https://lg.exn.uk/ -* http://lg.meerfarbig.net/ +* https://meerblick.io/ +* https://lg.as49697.net/ * http://lg.netnation.com/ * http://lg.edxnetwork.eu/ * https://lg.hivane.net/ @@ -83,4 +113,4 @@ Happy users * https://lg.fullsave.net/ * http://lg.catnix.net/ * https://lg.worldstream.nl/ -* https://route-server.netshelter.de/ +* https://lg.angolacables.co.ao/ diff --git a/bird.py b/bird.py index 5f6d546..a55deb9 100644 --- a/bird.py +++ b/bird.py @@ -25,153 +25,150 @@ import sys BUFSIZE = 4096 SUCCESS_CODES = { - "0000" : "OK", - "0001" : "Welcome", - "0002" : "Reading configuration", - "0003" : "Reconfigured", - "0004" : "Reconfiguration in progress", - "0005" : "Reconfiguration already in progress, queueing", - "0006" : "Reconfiguration ignored, shutting down", - "0007" : "Shutdown ordered", - "0008" : "Already disabled", - "0009" : "Disabled", - "0010" : "Already enabled", - "0011" : "Enabled", - "0012" : "Restarted", - "0013" : "Status report", - "0014" : "Route count", - "0015" : "Reloading", - "0016" : "Access restricted", + "0000" : "OK", + "0001" : "Welcome", + "0002" : "Reading configuration", + "0003" : "Reconfigured", + "0004" : "Reconfiguration in progress", + "0005" : "Reconfiguration already in progress, queueing", + "0006" : "Reconfiguration ignored, shutting down", + "0007" : "Shutdown ordered", + "0008" : "Already disabled", + "0009" : "Disabled", + "0010" : "Already enabled", + "0011" : "Enabled", + "0012" : "Restarted", + "0013" : "Status report", + "0014" : "Route count", + "0015" : "Reloading", + "0016" : "Access restricted", } TABLES_ENTRY_CODES = { - "1000" : "BIRD version", - "1001" : "Interface list", - "1002" : "Protocol list", - "1003" : "Interface address", - "1004" : "Interface flags", - "1005" : "Interface summary", - "1006" : "Protocol details", - "1007" : "Route list", - "1008" : "Route details", - "1009" : "Static route list", - "1010" : "Symbol list", - "1011" : "Uptime", - "1012" : "Route extended attribute list", - "1013" : "Show ospf neighbors", - "1014" : "Show ospf", - "1015" : "Show ospf interface", - "1016" : "Show ospf state/topology", - "1017" : "Show ospf lsadb", - "1018" : "Show memory", + "1000" : "BIRD version", + "1001" : "Interface list", + "1002" : "Protocol list", + "1003" : "Interface address", + "1004" : "Interface flags", + "1005" : "Interface summary", + "1006" : "Protocol details", + "1007" : "Route list", + "1008" : "Route details", + "1009" : "Static route list", + "1010" : "Symbol list", + "1011" : "Uptime", + "1012" : "Route extended attribute list", + "1013" : "Show ospf neighbors", + "1014" : "Show ospf", + "1015" : "Show ospf interface", + "1016" : "Show ospf state/topology", + "1017" : "Show ospf lsadb", + "1018" : "Show memory", } ERROR_CODES = { - "8000" : "Reply too long", - "8001" : "Route not found", - "8002" : "Configuration file error", - "8003" : "No protocols match", - "8004" : "Stopped due to reconfiguration", - "8005" : "Protocol is down => cannot dump", - "8006" : "Reload failed", - "8007" : "Access denied", + "8000" : "Reply too long", + "8001" : "Route not found", + "8002" : "Configuration file error", + "8003" : "No protocols match", + "8004" : "Stopped due to reconfiguration", + "8005" : "Protocol is down => cannot dump", + "8006" : "Reload failed", + "8007" : "Access denied", - "9000" : "Command too long", - "9001" : "Parse error", - "9002" : "Invalid symbol type", + "9000" : "Command too long", + "9001" : "Parse error", + "9002" : "Invalid symbol type", } END_CODES = ERROR_CODES.keys() + SUCCESS_CODES.keys() -global bird_sockets +global bird_sockets bird_sockets = {} def BirdSocketSingleton(host, port): - global bird_sockets - s = bird_sockets.get((host,port), None) - if not s: - s = BirdSocket(host,port) - bird_sockets[(host,port)] = s - return s + global bird_sockets + s = bird_sockets.get((host,port), None) + if not s: + s = BirdSocket(host,port) + bird_sockets[(host,port)] = s + return s class BirdSocket: - def __init__(self, host="", port="", file=""): - self.__file = file - self.__host = host - self.__port = port - self.__sock = None + def __init__(self, host="", port="", file=""): + self.__file = file + self.__host = host + self.__port = port + self.__sock = None - def __connect(self): - if self.__sock: return + def __connect(self): + if self.__sock: return - if not file: - self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.__sock.settimeout(3.0) - self.__sock.connect((self.__host, self.__port)) - else: - self.__sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.__sock.settimeout(3.0) - self.__sock.connect(self.__file) + if not file: + self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.__sock.settimeout(3.0) + self.__sock.connect((self.__host, self.__port)) + else: + self.__sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.__sock.settimeout(3.0) + self.__sock.connect(self.__file) - # read welcome message - self.__sock.recv(1024) - self.cmd("restrict") + # read welcome message + self.__sock.recv(1024) + self.cmd("restrict") - def close(self): - if self.__sock: - try: self.__sock.close() - except: pass - self.__sock = None - - def cmd(self, cmd): - try: - self.__connect() - self.__sock.send(cmd + "\n") - data = self.__read() - return data - except socket.error: - why = sys.exc_info()[1] - self.close() - return False, "Bird connection problem: %s" % why + def close(self): + if self.__sock: + try: self.__sock.close() + except: pass + self.__sock = None - def __read(self): - code = "7000" # Not used in bird - parsed_string = "" - lastline = "" + def cmd(self, cmd): + try: + self.__connect() + self.__sock.send(cmd + "\n") + data = self.__read() + return data + except socket.error: + why = sys.exc_info()[1] + self.close() + return False, "Bird connection problem: %s" % why - while code not in END_CODES: - data = self.__sock.recv(BUFSIZE) - - lines = (lastline + data).split("\n") - if len(data) == BUFSIZE: - lastline = lines[-1] - lines = lines[:-1] + def __read(self): + code = "7000" # Not used in bird + parsed_string = "" + lastline = "" - for line in lines: - code = line[0:4] + while code not in END_CODES: + data = self.__sock.recv(BUFSIZE) - if not line.strip(): - continue - elif code == "0000": - return True, parsed_string - elif code in SUCCESS_CODES.keys(): - return True, SUCCESS_CODES.get(code) - elif code in ERROR_CODES.keys(): - return False, ERROR_CODES.get(code) - elif code[0] in [ "1", "2"] : - parsed_string += line[5:] + "\n" - elif code[0] == " ": - parsed_string += line[1:] + "\n" - elif code[0] == "+": - parsed_string += line[1:] - else: - parsed_string += "<<>>\n"%line + lines = (lastline + data).split("\n") + if len(data) == BUFSIZE: + lastline = lines[-1] + lines = lines[:-1] - return True, parsed_string - - -__all__ = ['BirdSocketSingleton' , 'BirdSocket' ] - + for line in lines: + code = line[0:4] + + if not line.strip(): + continue + elif code == "0000": + return True, parsed_string + elif code in SUCCESS_CODES.keys(): + return True, SUCCESS_CODES.get(code) + elif code in ERROR_CODES.keys(): + return False, ERROR_CODES.get(code) + elif code[0] in [ "1", "2"] : + parsed_string += line[5:] + "\n" + elif code[0] == " ": + parsed_string += line[1:] + "\n" + elif code[0] == "+": + parsed_string += line[1:] + else: + parsed_string += "<<>>\n"%line + + return True, parsed_string +__all__ = ['BirdSocketSingleton', 'BirdSocket'] diff --git a/lg.cfg b/lg.cfg.example similarity index 64% rename from lg.cfg rename to lg.cfg.example index 7a89a3f..b5a5e8f 100644 --- a/lg.cfg +++ b/lg.cfg.example @@ -1,10 +1,19 @@ +# Configuration file example for lg.py +# Adapt and copy to lg.cfg +WEBSITE_TITLE="Bird-LG / Looking Glass" DEBUG = False LOG_FILE="/var/log/lg.log" LOG_LEVEL="WARNING" +# Keep log history indefinitely by default. +LOG_NUM_DAYS=0 DOMAIN = "tetaneutral.net" +# Used to optionally restrict access to lgproxy based on a shared secret. +# Empty string or unset = no shared secret is used to run queries on lgproxies. +SHARED_SECRET="ThisTokenIsNotSecret" + BIND_IP = "0.0.0.0" BIND_PORT = 5000 @@ -29,6 +38,7 @@ AS_NUMBER = { # DNS zone to query for ASN -> name mapping ASN_ZONE = "asn.cymru.com" +# Used for secure session storage, change this SESSION_KEY = '\xd77\xf9\xfa\xc2\xb5\xcd\x85)`+H\x9d\xeeW\\%\xbe/\xbaT\x89\xe8\xa7' # specifies an alternative start page template for the "/" route. diff --git a/lg.py b/lg.py index ca25321..206632d 100644 --- a/lg.py +++ b/lg.py @@ -22,7 +22,6 @@ import base64 from datetime import datetime -import memcache import subprocess import logging from logging.handlers import TimedRotatingFileHandler @@ -43,18 +42,16 @@ parser = argparse.ArgumentParser() parser.add_argument('-c', dest='config_file', help='path to config file', default='lg.cfg') args = parser.parse_args() + app = Flask(__name__) app.config.from_pyfile(args.config_file) app.secret_key = app.config["SESSION_KEY"] app.debug = app.config["DEBUG"] -file_handler = TimedRotatingFileHandler(filename=app.config["LOG_FILE"], when="midnight") +file_handler = TimedRotatingFileHandler(filename=app.config["LOG_FILE"], when="midnight", backupCount=app.config.get("LOG_NUM_DAYS", 0)) file_handler.setLevel(getattr(logging, app.config["LOG_LEVEL"].upper())) app.logger.addHandler(file_handler) -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 get_asn_from_as(n): asn_zone = app.config.get("ASN_ZONE", "asn.cymru.com") @@ -148,16 +145,25 @@ 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) + if "SHARED_SECRET" in app.config: + url = "%ssecret=%s&" % (url, app.config["SHARED_SECRET"]) + url = "%sq=%s" % (url, quote(query)) + + try: + f = urlopen(url) + resultat = f.read() + status = True # retreive remote status + except IOError: + resultat = "Failed to retrieve URL for host %s" % host + app.logger.warning("Failed to retrieve URL for host %s: %s", host, url) + status = False + + return status, resultat @app.context_processor @@ -175,6 +181,8 @@ def inject_commands(): ("adv", "show route ..."), ("adv_bgpmap", "show route ... (bgpmap)"), ] + + commands = [i for i in commands if i[0] not in app.config.get("BLACKLIST_COMMANDS", [])] commands_dict = {} for id, text in commands: commands_dict[id] = text @@ -242,6 +250,8 @@ SUMMARY_UNWANTED_PROTOS = ["Kernel", "Static", "Device", "Direct"] @app.route("/summary/") @app.route("/summary//") def summary(hosts, proto="ipv4"): + if 'summary' not in iter(inject_commands()['commands_dict']): + return render_template('error.html', errors=["Access denied"]), 403 set_session("summary", hosts, proto, "") command = "show protocols" @@ -284,6 +294,9 @@ def summary(hosts, proto="ipv4"): @app.route("/detail//") def detail(hosts, proto): + if 'detail' not in iter(inject_commands()['commands_dict']): + return render_template('error.html', errors=["Access denied"]), 403 + name = get_query() if not name: @@ -313,6 +326,9 @@ def detail(hosts, proto): @app.route("/traceroute//") def traceroute(hosts, proto): + if 'traceroute' not in iter(inject_commands()['commands_dict']): + return render_template('error.html', errors=["Access denied"]), 403 + q = get_query() if not q: @@ -346,49 +362,70 @@ def traceroute(hosts, proto): @app.route("/adv//") def show_route_filter(hosts, proto): + if 'adv' not in iter(inject_commands()['commands_dict']): + return render_template('error.html', errors=["Access denied"]), 403 + return show_route("adv", hosts, proto) @app.route("/adv_bgpmap//") def show_route_filter_bgpmap(hosts, proto): + if 'adv_bgpmap' not in iter(inject_commands()['commands_dict']): + return render_template('error.html', errors=["Access denied"]), 403 + return show_route("adv_bgpmap", hosts, proto) @app.route("/where//") def show_route_where(hosts, proto): + if 'where' not in iter(inject_commands()['commands_dict']): + return render_template('error.html', errors=["Access denied"]), 403 + return show_route("where", hosts, proto) @app.route("/where_detail//") def show_route_where_detail(hosts, proto): + if 'where_detail' not in iter(inject_commands()['commands_dict']): + return render_template('error.html', errors=["Access denied"]), 403 + return show_route("where_detail", hosts, proto) @app.route("/where_bgpmap//") def show_route_where_bgpmap(hosts, proto): + if 'where_bgpmap' not in iter(inject_commands()['commands_dict']): + return render_template('error.html', errors=["Access denied"]), 403 + return show_route("where_bgpmap", hosts, proto) @app.route("/prefix//") def show_route_for(hosts, proto): + if 'prefix' not in iter(inject_commands()['commands_dict']): + return render_template('error.html', errors=["Access denied"]), 403 + return show_route("prefix", hosts, proto) @app.route("/prefix_detail//") def show_route_for_detail(hosts, proto): + if 'prefix_detail' not in iter(inject_commands()['commands_dict']): + return render_template('error.html', errors=["Access denied"]), 403 + return show_route("prefix_detail", hosts, proto) @app.route("/prefix_bgpmap//") def show_route_for_bgpmap(hosts, proto): + if 'prefix_bgpmap' not in iter(inject_commands()['commands_dict']): + return render_template('error.html', errors=["Access denied"]), 403 + return show_route("prefix_bgpmap", hosts, proto) def get_as_name(_as): - """return a string that contain the as number following by the as name - - It's the use whois database informations - # Warning, the server can be blacklisted from ripe is too many requests are done + """Returns a string that contain the as number following by the as name """ if not _as: return "AS?????" @@ -396,12 +433,7 @@ def get_as_name(_as): if not _as.isdigit(): return _as.strip() - name = mc.get(str('lg_%s' % _as)) - if not name: - app.logger.info("asn for as %s not found in memcache", _as) - name = get_asn_from_as(_as)[-1].replace(" ","\r",1) - if name: - mc.set(str("lg_%s" % _as), str(name), memcache_expiration) + name = get_asn_from_as(_as)[-1].replace(" ", "\r", 1) return "AS%s | %s" % (_as, name) @@ -458,19 +490,21 @@ def show_bgpmap(): label_without_star = kwargs["label"].replace("*", "") if e.get_label() is not None: - labels = e.get_label().split("\r") + labels = e.get_label().split("\r") else: return edges[edge_tuple] if "%s*" % label_without_star not in labels: - labels = [ kwargs["label"] ] + [ l for l in labels if not l.startswith(label_without_star) ] + labels = [ kwargs["label"] ] + [ l for l in labels if not l.startswith(label_without_star) ] labels = sorted(labels, cmp=lambda x,y: x.endswith("*") and -1 or 1) - label = escape("\r".join(labels)) e.set_label(label) 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: @@ -478,7 +512,7 @@ def show_bgpmap(): edge = add_edge(as_number, nodes[host]) edge.set_color("red") edge.set_style("bold") - + #colors = [ "#009e23", "#1a6ec1" , "#d05701", "#6f879f", "#939a0e", "#0e9a93", "#9a0e85", "#56d8e1" ] previous_as = None hosts = data.keys() @@ -504,14 +538,13 @@ def show_bgpmap(): if not hop: hop = True if _as not in hosts: - hop_label = _as + hop_label = _as if first: hop_label = hop_label + "*" continue else: hop_label = "" - if _as == asmap[-1]: add_node(_as, fillcolor="#F5A9A9", shape="box", ) else: @@ -559,7 +592,7 @@ def build_as_tree_from_raw_bird_ouput(host, proto, text): path = None paths = [] net_dest = None - peer_protocol_name = None + peer_protocol_name = "" for line in text: line = line.strip() @@ -569,7 +602,7 @@ def build_as_tree_from_raw_bird_ouput(host, proto, text): 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) + expr2 = re.search(r'(.*)via\s+([0-9a-fA-F:\.]+)\s+on\s+\S+(\s+\[(\w+)\s+)?', line) if expr2: if path: path.append(net_dest) @@ -592,7 +625,7 @@ def build_as_tree_from_raw_bird_ouput(host, proto, text): # ugly hack for good printing 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)))] - + expr3 = re.search(r'(.*)unreachable\s+\[(\w+)\s+', line) if expr3: if path: @@ -612,7 +645,7 @@ def build_as_tree_from_raw_bird_ouput(host, proto, text): path.extend(ASes) else: path = ASes - + if path: path.append(net_dest) paths.append(path) diff --git a/lgproxy.cfg b/lgproxy.cfg deleted file mode 100644 index e7a6e8a..0000000 --- a/lgproxy.cfg +++ /dev/null @@ -1,12 +0,0 @@ - -DEBUG=False -LOG_FILE="/var/log/lg-proxy/lg-proxy.log" -LOG_LEVEL="WARNING" -BIND_IP = "0.0.0.0" -BIND_PORT = 5000 -ACCESS_LIST = ["91.224.149.206", "178.33.111.110", "2a01:6600:8081:ce00::1"] -IPV4_SOURCE="" -IPV6_SOURCE="" -BIRD_SOCKET="/var/run/bird/bird.ctl" -BIRD6_SOCKET="/var/run/bird/bird6.ctl" - diff --git a/lgproxy.cfg.example b/lgproxy.cfg.example new file mode 100644 index 0000000..e238d42 --- /dev/null +++ b/lgproxy.cfg.example @@ -0,0 +1,28 @@ +# Configuration file example for lgproxy.py +# Adapt and copy to lgproxy.cfg + +DEBUG=False + +LOG_FILE="/var/log/lg-proxy/lg-proxy.log" +LOG_LEVEL="WARNING" +# Keep log history indefinitely by default. +LOG_NUM_DAYS=0 + +BIND_IP = "0.0.0.0" +BIND_PORT = 5000 + +# Used to restrict access to lgproxy based on source IP address. +# Empty list = any IP is allowed to run queries. +ACCESS_LIST = ["91.224.149.206", "178.33.111.110", "2a01:6600:8081:ce00::1"] + +# Used to restrict access to lgproxy based on a shared secret (must also be configured in lg.cfg) +# Empty string or unset = no shared secret is required to run queries. +SHARED_SECRET="ThisTokenIsNotSecret" + +# Used as source address when running traceroute (optional) +IPV4_SOURCE="198.51.100.42" +IPV6_SOURCE="2001:db8:42::1" + +BIRD_SOCKET="/var/run/bird/bird.ctl" +BIRD6_SOCKET="/var/run/bird/bird6.ctl" + diff --git a/lgproxy.py b/lgproxy.py index e1b3cdb..0d0ad2d 100644 --- a/lgproxy.py +++ b/lgproxy.py @@ -41,7 +41,7 @@ app = Flask(__name__) app.debug = app.config["DEBUG"] app.config.from_pyfile(args.config_file) -file_handler = TimedRotatingFileHandler(filename=app.config["LOG_FILE"], when="midnight") +file_handler = TimedRotatingFileHandler(filename=app.config["LOG_FILE"], when="midnight", backupCount=app.config.get("LOG_NUM_DAYS", 0)) app.logger.setLevel(getattr(logging, app.config["LOG_LEVEL"].upper())) app.logger.addHandler(file_handler) @@ -54,15 +54,20 @@ 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' ] traceroute6 = [ 'traceroute6' ] @@ -71,15 +76,14 @@ def traceroute(): traceroute6 = [ 'traceroute', '-6' ] src = [] - if request.path == '/traceroute6': - traceroute = traceroute6 - if app.config.get("IPV6_SOURCE",""): - src = [ "-s", app.config.get("IPV6_SOURCE") ] - + if request.path == '/traceroute6': + traceroute = traceroute6 + if app.config.get("IPV6_SOURCE", ""): + src = [ "-s", app.config.get("IPV6_SOURCE") ] else: - traceroute = traceroute4 - if app.config.get("IPV4_SOURCE",""): - src = [ "-s", app.config.get("IPV4_SOURCE") ] + traceroute = traceroute4 + if app.config.get("IPV4_SOURCE",""): + src = [ "-s", app.config.get("IPV4_SOURCE") ] query = request.args.get("q","") query = unquote(query) @@ -92,15 +96,13 @@ def traceroute(): options = [ '-A', '-q1', '-N32', '-w1', '-m15' ] command = traceroute + src + options + [ query ] result = subprocess.Popen( command , stdout=subprocess.PIPE).communicate()[0].decode('utf-8', 'ignore').replace("\n","
") - return result - @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")) @@ -113,7 +115,7 @@ def bird(): b.close() # FIXME: use status return result - + if __name__ == "__main__": app.logger.info("lgproxy start") diff --git a/static/js/lg.js b/static/js/lg.js index 1a8b496..26de696 100644 --- a/static/js/lg.js +++ b/static/js/lg.js @@ -1,4 +1,4 @@ - +const noArgReqs = ["summary"]; $(window).unload(function(){ $(".progress").show() @@ -12,7 +12,7 @@ function change_url(loc){ function reload(){ loc = "/" + request_type + "/" + hosts + "/" + proto; - if (request_type != "summary" ){ + if (!noArgReqs.includes(request_type)){ if( request_args != undefined && request_args != ""){ loc = loc + "?q=" + encodeURIComponent(request_args); change_url(loc) @@ -22,7 +22,7 @@ function reload(){ } } function update_view(){ - if (request_type == "summary") + if (noArgReqs.includes(request_type)) $(".navbar-search").hide(); else $(".navbar-search").show(); diff --git a/templates/layout.html b/templates/layout.html index 34071b0..c0b7281 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -1,7 +1,7 @@ - {{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") }}