lg: Change configuration of proxied hosts (not backward compatible)

This simplifies and clarify the configuration, while making it more
generic and getting rid of the "DOMAIN" variable.

Proxied hosts can now be reached over HTTP or HTTPS, through any DNS name,
and even through IP literals to avoid dependency on DNS.  With the
previous code, proxied hosts needed to be reachable with the fixed scheme
`http://<host>.<DOMAIN>:<port>`, and this was a big limitation for some
deployments.

This is not backwards compatible, users will have to adapt their
configuration.  We rename the `PROXY` variable to `HOSTS` to make that
extra-clear.
This commit is contained in:
Baptiste Jonglez 2020-06-16 10:56:21 +02:00
parent 3d90c14bfa
commit 8777b73bb7
3 changed files with 48 additions and 44 deletions

41
lg.cfg
View File

@ -3,28 +3,36 @@ DEBUG = False
LOG_FILE="/var/log/lg.log"
LOG_LEVEL="WARNING"
DOMAIN = "tetaneutral.net"
# Used to optionally restrict access to lgproxy based on a shared secret.
SHARED_SECRET="ThisTokenIsNotSecret"
BIND_IP = "0.0.0.0"
BIND_PORT = 5000
PROXY = {
"gw": 5000,
"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"
# List of hosts to query (each one is a lgproxy instances)
HOSTS = {
"r1": {
# Endpoint at which lgproxy can be queried
"endpoint": "http://r1.example.com:5000",
# ASN and Router IP are optional, they are used to make the bgpmap more pretty
"asn": "65551",
"routerip": ["198.51.100.99", "192.0.2.12", "2001:db8:42:cafe::175"],
},
"r2": {
# Using a plain IP address as endpoint is possible
"endpoint": "http://203.0.113.42:5000",
# It is fine to provide no "routerip" or "asn" field
},
"r3": {
# IPv6 litterals are supported too
"endpoint": "http://[2001:db8:ffff::42]:5000",
"asn": "65551",
},
"r4": {
# Example with HTTPS
"endpoint": "https://r5.example.com",
"asn": "64498",
},
}
#WHOIS_SERVER = "whois.foo.bar"
@ -32,4 +40,5 @@ AS_NUMBER = {
# DNS zone to query for ASN -> name mapping
ASN_ZONE = "asn.cymru.com"
# Change this to random data
SESSION_KEY = '\xd77\xf9\xfa\xc2\xb5\xcd\x85)`+H\x9d\xeeW\\%\xbe/\xbaT\x89\xe8\xa7'

49
lg.py
View File

@ -138,17 +138,14 @@ def bird_proxy(host, proto, service, query):
elif proto == "ipv4":
path = service
port = app.config["PROXY"].get(host, "")
if not port:
return False, 'Host "%s" invalid' % host
elif not path:
if not path:
return False, 'Proto "%s" invalid' % proto
url = "http://%s" % (host)
if "DOMAIN" in app.config:
url = "%s.%s" % (url, app.config["DOMAIN"])
url = "%s:%d/%s?" % (url, port, path)
if host not in app.config["HOSTS"]:
return False, 'Host "%s" invalid' % host
endpoint = app.config["HOSTS"][host]["endpoint"]
url = "%s/%s?" % (endpoint, path)
if "SHARED_SECRET" in app.config:
url = "%ssecret=%s&" % (url, app.config["SHARED_SECRET"])
url = "%sq=%s" % (url, quote(query))
@ -158,7 +155,7 @@ def bird_proxy(host, proto, service, query):
resultat = f.read()
status = True # retreive remote status
except IOError:
resultat = "Failed to retrieve URL for host %s" % host
resultat = "Failed to retrieve data from host %s" % host
app.logger.warning("Failed to retrieve URL for host %s: %s", host, url)
status = False
@ -188,12 +185,12 @@ def inject_commands():
@app.context_processor
def inject_all_host():
return dict(all_hosts="+".join(app.config["PROXY"].keys()))
return dict(all_hosts="+".join(app.config["HOSTS"].keys()))
@app.route("/")
def hello():
return redirect("/summary/%s/ipv4" % "+".join(app.config["PROXY"].keys()))
return redirect("/summary/%s/ipv4" % "+".join(app.config["HOSTS"].keys()))
def error_page(text):
@ -455,17 +452,16 @@ def show_bgpmap():
return edges[edge_tuple]
for host, asmaps in data.iteritems():
if "DOMAIN" in app.config:
add_node(host, label= "%s\r%s" % (host.upper(), app.config["DOMAIN"].upper()), shape="box", fillcolor="#F5A9A9")
else:
add_node(host, label= "%s" % (host.upper()), shape="box", fillcolor="#F5A9A9")
add_node(host, label= "%s" % (host.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")
host_config = app.config["HOSTS"].get(host)
if host_config:
as_number = host_config.get("asn")
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" ]
previous_as = None
@ -569,11 +565,10 @@ def build_as_tree_from_raw_bird_ouput(host, proto, text):
peer_ip = expr2.group(2).strip()
if expr2.group(4):
peer_protocol_name = expr2.group(4).strip()
# Check if via line is a internal route
for rt_host, rt_ips in app.config["ROUTER_IP"].iteritems():
# Special case for internal routing
if peer_ip in rt_ips:
path = [rt_host]
# Check if via line is an internal route (special case for internal routing)
for other_host in app.config["HOSTS"].keys():
if peer_ip in app.config["HOSTS"][other_host].get("routerip", []):
path = [other_host]
break
else:
# ugly hack for good printing

View File

@ -24,7 +24,7 @@
<li class="navbar-text">Nodes:&nbsp;&nbsp;</li>
<li class="hosts"><a id="{{all_hosts}}" href="#">all</a></li>
{% for host in config.PROXY %}
{% for host in config.HOSTS %}
<li class="hosts"><a id="{{host}}" href="#">{{host}}</a></li>
{% endfor %}