Skip to content
This repository has been archived by the owner on Apr 28, 2024. It is now read-only.

Commit

Permalink
Add support for unified Bird daemons
Browse files Browse the repository at this point in the history
Bird 2.0 includes IPv4 and IPv6 support in a single daemon.
When UNIFIED_DAEMON is set to True, queries are always done with the
"ipv4" backend (which handles both protocols), and distinctions between
IPv4 and IPv4 are removed in the UI.
  • Loading branch information
zhaofengli authored and Simon Marsh committed Jan 11, 2019
1 parent daaf981 commit ddf86d0
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 31 deletions.
4 changes: 4 additions & 0 deletions lg.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ PROXY = {
"h3": "h3.some.network:5000",
}

# If True, queries are always done with the "ipv4" backend,
# and the distinction between IPv4 and IPv6 is removed from the UI.
UNIFIED_DAEMON = True

# Used for bgpmap
ROUTER_IP = {
"gw" : [ "91.224.148.2", "2a01:6600:8000::175" ],
Expand Down
82 changes: 53 additions & 29 deletions lg.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import json
import random

from toolbox import mask_is_valid, ipv6_is_valid, ipv4_is_valid, resolve, save_cache_pickle, load_cache_pickle, unescape
from toolbox import mask_is_valid, ip_is_valid, ipv6_is_valid, ipv4_is_valid, resolve, resolve_any, save_cache_pickle, load_cache_pickle, unescape
#from xml.sax.saxutils import escape


Expand Down Expand Up @@ -119,7 +119,10 @@ def whois_command(query):

def bird_command(host, proto, query):
"""Alias to bird_proxy for bird service"""
return bird_proxy(host, proto, "bird", query)
if app.config.get("UNIFIED_DAEMON", False):
return bird_proxy(host, "ipv4", "bird", query)
else:
return bird_proxy(host, proto, "bird", query)


def bird_proxy(host, proto, service, query):
Expand Down Expand Up @@ -305,16 +308,23 @@ def traceroute(hosts, 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))
if app.config.get("UNIFIED_DAEMON", False):
if not ip_is_valid(q):
try:
q = resolve_any(q)
except:
return error_page("%s is unresolvable" % q)
else:
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))

errors = []
infos = {}
Expand Down Expand Up @@ -608,23 +618,37 @@ def show_route(request_type, hosts, proto):
if len(expression.split("/")) == 2:
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 app.config.get("UNIFIED_DAEMON", False):
if not ip_is_valid(expression):
try:
expression = resolve_any(expression)
except:
return error_page("%s is unresolvable" % expression)

if not mask and ipv4_is_valid(expression):
mask = "32"
if not mask and ipv6_is_valid(expression):
mask = "128"
if not mask_is_valid(mask):
return error_page("mask %s is invalid" % mask)
else:
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
Expand Down
2 changes: 1 addition & 1 deletion templates/detail.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% extends "layout.html" %}
{% block body %}
{% for host in detail %}
<h3>{{host}}/{{session.proto}}: {{command}}</h3>
<h3>{{host}}{% if not config.UNIFIED_DAEMON %}/{{session.proto}}{% endif %}: {{command}}</h3>
<i>{{ detail[host].status }}</i><br /><br />
<pre>
{{ detail[host].description|trim|safe }}
Expand Down
4 changes: 3 additions & 1 deletion templates/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
{% endfor %}
</ul>

{% if not config.UNIFIED_DAEMON %}
<div class="btn-group">
<a class="btn btn-primary proto" id="ipv4" href="#">ipv4</a>
<a class="btn btn-primary proto" id="ipv6" href="#">ipv6</a>
</div>
{% endif %}

<ul class="nav">
<li class="nav-item dropdown request_type">
Expand Down Expand Up @@ -74,7 +76,7 @@ <h4>Request history</h4>
{% for hosts, proto, request_type, request_args in session.history %}
<a class="list-group-item list-group-item-action {% if loop.first %}active{% endif %}"
href="/{{ [request_type, hosts, proto]|join("/") }}{% if request_args %}?q={{request_args}}{% endif %}">
{{hosts}}/{{proto}}: {{ commands_dict[request_type]|replace("...", request_args) }}
{{hosts}}{% if not config.UNIFIED_DAEMON %}/{{proto}}{% endif %}: {{ commands_dict[request_type]|replace("...", request_args) }}
</a>

{% endfor %}
Expand Down
11 changes: 11 additions & 0 deletions toolbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@
def resolve(n, q):
return str(resolv.query(n,q)[0])

def resolve_any(h):
try:
return resolve(h, "AAAA")
except:
pass
return resolve(h, "A")


def mask_is_valid(n):
if not n:
return True
Expand All @@ -40,6 +48,9 @@ def mask_is_valid(n):
except:
return False

def ip_is_valid(n):
return ipv4_is_valid(n) or ipv6_is_valid(n)

def ipv4_is_valid(n):
try:
socket.inet_pton(socket.AF_INET, n)
Expand Down

0 comments on commit ddf86d0

Please sign in to comment.