Add support for unified Bird daemons

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.
This commit is contained in:
Zhaofeng Li 2018-11-28 10:49:44 -08:00 committed by Simon Marsh
parent daaf981b32
commit ddf86d02fb
5 changed files with 71 additions and 30 deletions

4
lg.cfg
View File

@ -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" ],

80
lg.py
View File

@ -32,7 +32,7 @@ from urllib import quote, unquote
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
@ -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):
@ -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 = {}
@ -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 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 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 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

View File

@ -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 }}

View File

@ -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">
@ -74,7 +76,7 @@
{% 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 %}

View File

@ -31,6 +31,14 @@ resolv.lifetime = 1
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
@ -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)