")
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):
"""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
"""
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", "#9a0e85", "#56d8e1" ]
hosts = data.keys()
for host, asmaps in data.iteritems():
first = True
for asmap in asmaps:
previous_as = host
color = "#%x" % random.randint(0, 16777215)
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(color)
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
def show_route(request_type, hosts, proto):
expression = unquote(request.args.get('q', '')).strip()
if not expression:
abort(400)
set_session(request_type, hosts, proto, expression)
bgpmap = request_type.endswith("bgpmap")
all = (request_type.endswith("detail") and " all" or "")
if bgpmap:
all = " 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("/"))
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))
app.secret_key = app.config["SESSION_KEY"]
app.debug = True
if __name__ == "__main__":
app.run("0.0.0.0")