diff --git a/lg.cfg b/lg.cfg index 92ca327..a8cd3a7 100644 --- a/lg.cfg +++ b/lg.cfg @@ -6,4 +6,15 @@ PROXY = { "h3": 5000, } +# Used for bgpmap +ROUTER_IP = { + "gw" : [ "91.224.148.2", "2a01:6600:8000::175" ], + "h3" : [ "91.224.148.3", "2a01:6600:8000::131" ] +} + +AS_NUMBER = { + "gw" : "197422", + "h3" : "197422" +} + SESSION_KEY = '\xd77\xf9\xfa\xc2\xb5\xcd\x85)`+H\x9d\xeeW\\%\xbe/\xbaT\x89\xe8\xa7' diff --git a/lg.py b/lg.py index fcb05c3..8b2ab68 100755 --- a/lg.py +++ b/lg.py @@ -34,327 +34,492 @@ from flask import Flask, render_template, jsonify, redirect, session, request, a app = Flask(__name__) app.config.from_pyfile('lg.cfg') + def add_links(text): - """Browser a string and replace ipv4, ipv6, as number, with a whois link """ + """Browser a string and replace ipv4, ipv6, as number, with a + whois link """ - if type(text) in [ str, unicode ]: - text = text.split("\n") + if type(text) in [str, unicode]: + text = text.split("\n") - ret_text = [] - for line in text: - # 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)) - 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) - line = re.sub(r'(\d+\.\d+\.\d+\.\d+)', r'\1',line) - hosts = "/".join(request.path.split("/")[2:]) - line = re.sub(r'\[(\w+)\s+((|\d\d\d\d-\d\d-\d\d\s)(|\d\d:)\d\d:\d\d|\w\w\w\d\d)', r'[\1 \2' % hosts, line) - line = re.sub(r'(^|\s+)(([a-f\d]{0,4}:){3,10}[a-f\d]{0,4})', r'\1\2',line , re.I) - ret_text.append(line) - return "\n".join(ret_text) + ret_text = [] + for line in text: + # 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)) + 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) + line = re.sub(r'(\d+\.\d+\.\d+\.\d+)', r'\1', line) + hosts = "/".join(request.path.split("/")[2:]) + line = re.sub(r'\[(\w+)\s+((|\d\d\d\d-\d\d-\d\d\s)(|\d\d:)\d\d:\d\d|\w\w\w\d\d)', r'[\1 \2' % hosts, line) + line = re.sub(r'(^|\s+)(([a-f\d]{0,4}:){3,10}[a-f\d]{0,4})', r'\1\2', line, re.I) + ret_text.append(line) + return "\n".join(ret_text) -def extract_paths(text): - paths = [] - for line in text: - line = line.strip() - if line.startswith("BGP.as_path:"): - paths.append(line.replace("BGP.as_path:", "").strip().split(" ")) - - return paths def set_session(request_type, hosts, proto, request_args): - """ Store all data from user in the user session """ - session.permanent = True - session.update( { - "request_type": request_type, - "hosts": hosts, - "proto": proto, - "request_args": request_args, - }) - history = session.get("history", []) + """ Store all data from user in the user session """ + session.permanent = True + session.update({ + "request_type": request_type, + "hosts": hosts, + "proto": proto, + "request_args": request_args, + }) + history = session.get("history", []) - # erase old format history - if type(history) != type(list()): history = [] + # erase old format history + if type(history) != type(list()): + history = [] + + t = (hosts, proto, request_type, request_args) + if t in history: + del history[history.index(t)] + history.insert(0, t) + session["history"] = history[:20] - t = (hosts, proto, request_type, request_args) - if t in history: - del history[history.index(t)] - history.insert(0, t) - session["history"] = history[:20] def whois_command(query): - return subprocess.Popen( [ 'whois', query], stdout=subprocess.PIPE).communicate()[0].decode('utf-8', 'ignore') + return subprocess.Popen(['whois', query], stdout=subprocess.PIPE).communicate()[0].decode('utf-8', 'ignore') + def bird_command(host, proto, query): - """Alias to bird_proxy for bird service""" - return bird_proxy(host, proto, "bird", query) + """Alias to bird_proxy for bird service""" + return bird_proxy(host, proto, "bird", query) + def bird_proxy(host, proto, service, query): - """Retreive data of a service from a running lg-proxy on a remote node - - First and second arguments are the node and the port of the running lg-proxy - Third argument is the service, can be "traceroute" or "bird" - Last argument, the query to pass to the service + """Retreive data of a service from a running lg-proxy on a remote node + + First and second arguments are the node and the port of the running lg-proxy + Third argument is the service, can be "traceroute" or "bird" + Last argument, the query to pass to the service + + return tuple with the success of the command and the returned data + """ + + path = "" + if proto == "ipv6": + path = service + "6" + elif proto == "ipv4": + path = service + + port = app.config["PROXY"].get(host, "") + + if not port or not path: + return False, "Host/Proto not allowed" + 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 - return tuple with the success of the command and the returned data - """ - path = "" - if proto == "ipv6": path = service + "6" - elif proto == "ipv4": path = service - port = app.config["PROXY"].get(host,"") - if not port or not path: - return False, "Host/Proto not allowed" - 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 - @app.context_processor def inject_commands(): - commands = [ - ("traceroute","traceroute ..."), - ("summary","show protocols"), - ("detail","show protocols ... all"), - ("prefix","show route for ..."), - ("prefix_detail","show route for ... all"), - ("where","show route where net ~ [ ... ]"), - ("where_detail","show route where net ~ [ ... ] all"), - ("adv","show route ..."), - ] - commands_dict = {} - for id, text in commands: - commands_dict[id] = text - return dict(commands=commands, commands_dict=commands_dict) + commands = [ + ("traceroute", "traceroute ..."), + ("summary", "show protocols"), + ("detail", "show protocols ... all"), + ("prefix", "show route for ..."), + ("prefix_detail", "show route for ... all"), + ("prefix_bgpmap", "show route for ... (bgpmap)"), + ("where", "show route where net ~ [ ... ]"), + ("where_detail", "show route where net ~ [ ... ] all"), + ("where_bgpmap", "show route where net ~ [ ... ] (bgpmap)"), + ("adv", "show route ..."), + ("adv_bgpmap", "show route ... (bgpmap)"), + ] + commands_dict = {} + for id, text in commands: + commands_dict[id] = text + return dict(commands=commands, commands_dict=commands_dict) + @app.context_processor def inject_all_host(): - return dict(all_hosts="+".join(app.config["PROXY"].keys())) + return dict(all_hosts="+".join(app.config["PROXY"].keys())) + @app.route("/") def hello(): - return redirect("/summary/%s/ipv4" % "+".join(app.config["PROXY"].keys()) ) + return redirect("/summary/%s/ipv4" % "+".join(app.config["PROXY"].keys())) + def error_page(text): - return render_template('error.html', error = text ), 500 + return render_template('error.html', error=text), 500 + @app.errorhandler(400) def incorrect_request(e): - return render_template('error.html', warning="The server could not understand the request"), 400 + return render_template('error.html', warning="The server could not understand the request"), 400 + @app.errorhandler(404) def page_not_found(e): - return render_template('error.html', warning="The requested URL was not found on the server."), 404 + return render_template('error.html', warning="The requested URL was not found on the server."), 404 + @app.route("/whois/") def whois(query): - if not query.strip(): abort(400) - try: - asnum = int(query) - query = "as%d"%asnum - except: - m = re.match(r"[\w\d-]*\.(?P[\d\w-]+\.[\d\w-]+)$", query) - if m: query = query.groupdict()["domain"] - output = whois_command(query).replace("\n","
") - return jsonify(output=output, title=query) + if not query.strip(): + abort(400) + + try: + asnum = int(query) + query = "as%d" % asnum + except: + m = re.match(r"[\w\d-]*\.(?P[\d\w-]+\.[\d\w-]+)$", query) + if m: + query = query.groupdict()["domain"] + + output = whois_command(query).replace("\n", "
") + return jsonify(output=output, title=query) + SUMMARY_UNWANTED_PROTOS = ["Kernel", "Static", "Device"] SUMMARY_RE_MATCH = r"(?P[\w_]+)\s+(?P\w+)\s+(?P\w+)\s+(?P\w+)\s+(?P((|\d\d\d\d-\d\d-\d\d\s)(|\d\d:)\d\d:\d\d|\w\w\w\d\d))($|\s+(?P.*))" + @app.route("/summary/") @app.route("/summary//") def summary(hosts, proto="ipv4"): - set_session("summary", hosts, proto, "") - command = "show protocols" - - summary = {} - error = [] - for host in hosts.split("+"): - ret, res = bird_command(host, proto, command) - res = res.split("\n") - if len(res) > 1: #if ret: - data = [] - for line in res[1:]: - line = line.strip() - if line and ( line.split() + [""] )[1] not in SUMMARY_UNWANTED_PROTOS: - m = re.match(SUMMARY_RE_MATCH ,line) - if m: - data.append(m.groupdict()) - else: - app.logger.warning("couldn't parse: %s" , line) + set_session("summary", hosts, proto, "") + command = "show protocols" - summary[host] = data - else: - error.append("%s: bird command failed with error, %s" % (host,"\n".join(res))) + summary = {} + error = [] + for host in hosts.split("+"): + ret, res = bird_command(host, proto, command) + res = res.split("\n") + if len(res) > 1: + data = [] + for line in res[1:]: + line = line.strip() + if line and (line.split() + [""])[1] not in SUMMARY_UNWANTED_PROTOS: + m = re.match(SUMMARY_RE_MATCH, line) + if m: + data.append(m.groupdict()) + else: + app.logger.warning("couldn't parse: %s", line) + + summary[host] = data + else: + error.append("%s: bird command failed with error, %s" % (host, "\n".join(res))) + + return render_template('summary.html', summary=summary, command=command, error="
".join(error)) - return render_template('summary.html', summary=summary, command=command, error="
".join(error)) @app.route("/detail//") def detail(hosts, proto): - name = request.args.get('q', '') - if not name.strip(): abort(400) + name = request.args.get('q', '').strip() + if not name: + abort(400) - set_session("detail", hosts, proto, name) - command = "show protocols all %s" % name + set_session("detail", hosts, proto, name) + command = "show protocols all %s" % name + + detail = {} + error = [] + for host in hosts.split("+"): + ret, res = bird_command(host, proto, command) + res = res.split("\n") + if len(res) > 1: + detail[host] = {"status": res[1], "description": add_links(res[2:])} + else: + error.append("%s: bird command failed with error, %s" % (host, "\n".join(res))) + + return render_template('detail.html', detail=detail, command=command, error="
".join(error)) - detail = {} - error = [] - for host in hosts.split("+"): - ret, res = bird_command(host, proto, command) - res = res.split("\n") - if len(res) > 1 : #if ret: - detail[host] = { "status": res[1], "description": add_links(res[2:]) } - else: - error.append("%s: bird command failed with error, %s" % (host,"\n".join(res))) - - return render_template('detail.html', detail=detail, command=command, error="
".join(error)) @app.route("/traceroute//") def traceroute(hosts, proto): - q = request.args.get('q', '') - if not q.strip(): abort(400) - set_session("traceroute", hosts, proto, q) + q = request.args.get('q', '').strip() + if not q: + abort(400) - if proto == "ipv6" and not ipv6_is_valid(q): - try: q = resolve(q, "AAAA") - except: return error_page("%s is unresolvable or invalid for %s" % (q, proto)) - if proto == "ipv4" and not ipv4_is_valid(q): - try: q = resolve(q, "A") - except: return error_page("%s is unresolvable or invalid for %s" % (q, proto)) + set_session("traceroute", hosts, proto, q) + + if proto == "ipv6" and not ipv6_is_valid(q): + try: + q = resolve(q, "AAAA") + except: + return error_page("%s is unresolvable or invalid for %s" % (q, proto)) + if proto == "ipv4" and not ipv4_is_valid(q): + try: + q = resolve(q, "A") + except: + return error_page("%s is unresolvable or invalid for %s" % (q, proto)) + + infos = {} + for host in hosts.split("+"): + status, resultat = bird_proxy(host, proto, "traceroute", q) + infos[host] = add_links(resultat) + return render_template('traceroute.html', infos=infos) - infos = {} - for host in hosts.split("+"): - status, resultat = bird_proxy(host, proto, "traceroute", q) - infos[host] = add_links(resultat) - return render_template('traceroute.html', infos=infos) @app.route("/adv//") def show_route_filter(hosts, proto): - return show_route("adv", hosts, proto) + return show_route("adv", hosts, proto) + + +@app.route("/adv_bgpmap//") +def show_route_filter_bgpmap(hosts, proto): + return show_route("adv_bgpmap", hosts, proto) + @app.route("/where//") def show_route_where(hosts, proto): - return show_route("where", hosts, proto) + return show_route("where", hosts, proto) + @app.route("/where_detail//") def show_route_where_detail(hosts, proto): - return show_route("where_detail", hosts, proto) + return show_route("where_detail", hosts, proto) + + +@app.route("/where_bgpmap//") +def show_route_where_bgpmap(hosts, proto): + return show_route("where_bgpmap", hosts, proto) + @app.route("/prefix//") def show_route_for(hosts, proto): - return show_route("prefix", hosts, proto) + return show_route("prefix", hosts, proto) + @app.route("/prefix_detail//") def show_route_for_detail(hosts, proto): - return show_route("prefix_detail", hosts, proto) + return show_route("prefix_detail", hosts, proto) + + +@app.route("/prefix_bgpmap//") +def show_route_for_bgpmap(hosts, proto): + return show_route("prefix_bgpmap", hosts, proto) + ASNAME_CACHE_FILE = "/tmp/asname_cache.pickle" ASNAME_CACHE = load_cache_pickle(ASNAME_CACHE_FILE, {}) + def get_as_name(_as): - if not ASNAME_CACHE.has_key(_as): - whois_answer = whois_command("as%s" % _as) - as_name = re.search('(as-name|ASName): (.*)', whois_answer) - if as_name: - ASNAME_CACHE[_as] = as_name.group(2).strip() - else: - ASNAME_CACHE[_as] = _as - save_cache_pickle(ASNAME_CACHE_FILE, ASNAME_CACHE) - if ASNAME_CACHE[_as] == _as: - return "AS%s" % _as - else: - return "AS%s\r%s" % (_as, ASNAME_CACHE[_as]) + """return a string that contain the as number following by the as name -@app.route("/bgpmap/") -def show_bgpmap(data): - data = json.loads(unquote(data)) - graph = pydot.Dot('BGPMAP', graph_type='digraph') - nodes = {} - edges = {} - for host, asmaps in data.iteritems(): - nodes[host] = pydot.Node(host, shape="box", style="filled", fillcolor="#F5A9A9") - graph.add_node(nodes[host]) - for host, asmaps in data.iteritems(): - first = True - for asmap in asmaps: - previous_as = host - for _as in asmap: - _as = get_as_name(_as) - if _as == previous_as: - continue - if not nodes.has_key(_as): - nodes[_as] = pydot.Node(_as, label=_as, style="filled", fillcolor=(first and "#F5A9A9" or "white")) - graph.add_node(nodes[_as]) - - edge_tuple = (nodes[previous_as], nodes[_as]) - if not edges.has_key(edge_tuple): - edge = pydot.Edge(*edge_tuple) - graph.add_edge(edge) - edges[edge_tuple] = edge + It's the use whois database informations + # Warning, the server can be blacklisted from ripe is too many requests are done + """ - if edge.get_color() != "red" and first: - edge.set_color("red") - - previous_as = _as - first = False + if not _as.isdigit(): + return _as + + if _as not in ASNAME_CACHE: + whois_answer = whois_command("as%s" % _as) + as_name = re.search('(as-name|ASName): (.*)', whois_answer) + if as_name: + ASNAME_CACHE[_as] = as_name.group(2).strip() + else: + ASNAME_CACHE[_as] = _as + save_cache_pickle(ASNAME_CACHE_FILE, ASNAME_CACHE) + if ASNAME_CACHE[_as] == _as: + return "AS%s" % _as + else: + return "AS%s\r%s" % (_as, ASNAME_CACHE[_as]) + + +@app.route("/bgpmap/") +def show_bgpmap(): + """return a bgp map in a png file, from the json tree in q argument""" + + data = request.args.get('q', '').strip() + if not data: + abort(400) + + data = json.loads(unquote(data)) + + graph = pydot.Dot('BGPMAP', graph_type='digraph') + + nodes = {} + edges = {} + + def add_node(_as, **kwargs): + if _as not in nodes: + kwargs["label"] = kwargs.get("label", get_as_name(_as)) + nodes[_as] = pydot.Node(_as, style="filled", fontsize="10", **kwargs) + graph.add_node(nodes[_as]) + return nodes[_as] + + def add_edge(_previous_as, _as, **kwargs): + kwargs["splines"] = "true" + force = kwargs.get("force", False) + + edge_tuple = (_previous_as, _as) + if force or edge_tuple not in edges: + edge = pydot.Edge(*edge_tuple, **kwargs) + graph.add_edge(edge) + edges[edge_tuple] = edge + 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") + + as_number = app.config["AS_NUMBER"].get(host, None) + if as_number: + node = add_node(as_number, fillcolor="#F5A9A9") + edge = add_edge(as_number, nodes[host]) + edge.set_color("red") + edge.set_style("bold") + + colors = [ "#009e23", "#1a6ec1" , "#d05701", "#6f879f", "#939a0e", "#0e9a93" ] + color_index = 0 + hosts = data.keys() + + for host, asmaps in data.iteritems(): + first = True + for asmap in asmaps: + previous_as = host + color_index = color_index + 1 + for _as in asmap: + if _as == previous_as: + continue + + add_node(_as, fillcolor=(first and "#F5A9A9" or "white")) + edge = add_edge(nodes[previous_as], nodes[_as] ) + + if first: + edge.set_style("bold") + edge.set_color("red") + elif edge.get_color() != "red": + edge.set_style("dashed") + edge.set_color(colors[color_index]) + + previous_as = _as + first = False + + node = add_node(previous_as) + node.set_shape("box") + #return Response("
" + graph.create_dot() + "
") + return Response(graph.create_png(), mimetype='image/png') + + +def build_as_tree_from_raw_bird_ouput(host, proto, text): + """Extract the as path from the raw bird "show route all" command""" + + path = None + paths = [] + net_dest = None + for line in text: + line = line.strip() + + expr = re.search(r'(.*)via\s+([0-9:\.]+)\s+on.*\[(\w+)\s+', line) + if expr: + if path: + path.append(net_dest) + paths.append(path) + path = None + + if expr.group(1).strip(): + net_dest = expr.group(1).strip() + + peer_ip = expr.group(2).strip() + peer_protocol_name = expr.group(3).strip() + # Check if via line is a internal route + for rt_host, rt_ips in app.config["ROUTER_IP"].iteritems(): + if peer_ip in rt_ips: + path = [rt_host] + break + else: # retreive as number from bird + ret, res = bird_command(host, proto, "show protocols all %s" % peer_protocol_name) + re_asnumber = re.search("Neighbor AS:\s*(\d*)", res) + if re_asnumber: + path = [re_asnumber.group(1)] + else: + print "Missing retreive some information for the path" + path = ["as?????"] + + if line.startswith("BGP.as_path:"): + path.extend(line.replace("BGP.as_path:", "").strip().split(" ")) + + if path: + path.append(net_dest) + paths.append(path) + + return paths - #return Response("
" + graph.create_dot() + "
") - return Response(graph.create_png(), mimetype='image/png') def show_route(request_type, hosts, proto): - expression = unquote(request.args.get('q', '')) - if not expression.strip(): abort(400) - set_session(request_type, hosts, proto, expression) + expression = unquote(request.args.get('q', '')).strip() + if not expression: + abort(400) - all = (request_type.endswith("detail") and " all" or "" ) + set_session(request_type, hosts, proto, expression) - if request_type.startswith("adv"): - command = "show route " + expression - elif request_type.startswith("where"): - command = "show route where net ~ [ " + expression + " ]" + all - else: - mask = "" - if len(expression.split("/")) > 1: - expression, mask = (expression.split("/")) + bgpmap = request_type.endswith("bgpmap") - if not mask and proto == "ipv4" : mask = "32" - if not mask and proto == "ipv6" : mask = "128" - if not mask_is_valid(mask): - return error_page("mask %s is invalid" % mask) - if proto == "ipv6" and not ipv6_is_valid(expression): - try: expression = resolve(expression, "AAAA") - except: return error_page("%s is unresolvable or invalid for %s" % (expression, proto)) - if proto == "ipv4" and not ipv4_is_valid(expression): - try: expression = resolve(expression, "A") - except: return error_page("%s is unresolvable or invalid for %s" % (expression, proto)) + all = (request_type.endswith("detail") and " all" or "") + if bgpmap: + all = " all" - if mask: expression += "/" + mask - command = "show route for " + expression + all + if request_type.startswith("adv"): + command = "show route " + expression.strip() + if bgpmap and not command.endswith("all"): + command = command + " all" + elif request_type.startswith("where"): + command = "show route where net ~ [ " + expression + " ]" + all + else: + mask = "" + if len(expression.split("/")) > 1: + expression, mask = (expression.split("/")) - detail = {} - error = [] - bgpmap = {} - for host in hosts.split("+"): - ret, res = bird_command(host, proto, command) + if not mask and proto == "ipv4": + mask = "32" + if not mask and proto == "ipv6": + mask = "128" + if not mask_is_valid(mask): + return error_page("mask %s is invalid" % mask) + + if proto == "ipv6" and not ipv6_is_valid(expression): + try: + expression = resolve(expression, "AAAA") + except: + return error_page("%s is unresolvable or invalid for %s" % (expression, proto)) + if proto == "ipv4" and not ipv4_is_valid(expression): + try: + expression = resolve(expression, "A") + except: + return error_page("%s is unresolvable or invalid for %s" % (expression, proto)) + + if mask: + expression += "/" + mask + + command = "show route for " + expression + all + + detail = {} + error = [] + for host in hosts.split("+"): + ret, res = bird_command(host, proto, command) + + res = res.split("\n") + if len(res) > 1: + if bgpmap: + detail[host] = build_as_tree_from_raw_bird_ouput(host, proto, res) + else: + detail[host] = add_links(res) + else: + error.append("%s: bird command failed with error, %s" % (host, "\n".join(res))) + + if bgpmap: + detail = json.dumps(detail) + + return render_template((bgpmap and 'bgpmap.html' or 'route.html'), detail=detail, command=command, expression=expression, error="
".join(error)) - res = res.split("\n") - if len(res) > 1 : #if ret: - detail[host] = add_links(res) - bgpmap[host] = extract_paths(res) - else: - error.append("%s: bird command failed with error, %s" % (host,"\n".join(res))) - - return render_template('route.html', detail=detail, command=command, expression=expression, bgpmap=json.dumps(bgpmap), error="
".join(error) ) app.secret_key = app.config["SESSION_KEY"] app.debug = True if __name__ == "__main__": - app.run("0.0.0.0") + app.run("0.0.0.0") diff --git a/static/js/lg.js b/static/js/lg.js index 55e72ca..990d2be 100644 --- a/static/js/lg.js +++ b/static/js/lg.js @@ -80,7 +80,7 @@ $(function(){ reload(); }); $(".request_type ul a").click(function(){ - if ( request_type.replace("_detail","") != $(this).attr('id').replace("_detail","") ){ + if ( request_type.split("_")[0] != $(this).attr('id').split("_")[0] ){ request_args = "" $(".request_args").val(""); } diff --git a/templates/bgpmap.html b/templates/bgpmap.html new file mode 100644 index 0000000..0b0ca7b --- /dev/null +++ b/templates/bgpmap.html @@ -0,0 +1,9 @@ +{% extends "layout.html" %} +{% block body %} +

{{session.hosts}}: {{command}}

+{% if session.request_args != expression|replace("/32","")|replace("/128","") %} +DNS: {{session.request_args}} => {{expression|replace("/32","")|replace("/128","")}}
+{% endif %}
+ +
+{% endblock %} diff --git a/templates/route.html b/templates/route.html index 75fc313..4e11ecc 100644 --- a/templates/route.html +++ b/templates/route.html @@ -1,7 +1,10 @@ {% extends "layout.html" %} {% block body %} {% for host in detail %} -

{{host}}: {{command}}

+

+ {{host}}: {{command}} + View the BGP map +

{% if session.request_args != expression|replace("/32","")|replace("/128","") %} DNS: {{session.request_args}} => {{expression|replace("/32","")|replace("/128","")}}
{% endif %}
@@ -9,6 +12,5 @@ {{ detail[host]|trim|safe }} {% endfor %} -
{% endblock %}