")
-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}}
+
{% 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 %}