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_FILE="/var/log/lg.log"
LOG_LEVEL="WARNING" LOG_LEVEL="WARNING"
DOMAIN = "tetaneutral.net"
# Used to optionally restrict access to lgproxy based on a shared secret. # Used to optionally restrict access to lgproxy based on a shared secret.
SHARED_SECRET="ThisTokenIsNotSecret" SHARED_SECRET="ThisTokenIsNotSecret"
BIND_IP = "0.0.0.0" BIND_IP = "0.0.0.0"
BIND_PORT = 5000 BIND_PORT = 5000
PROXY = { # List of hosts to query (each one is a lgproxy instances)
"gw": 5000, HOSTS = {
"h3": 5000, "r1": {
} # Endpoint at which lgproxy can be queried
"endpoint": "http://r1.example.com:5000",
# Used for bgpmap # ASN and Router IP are optional, they are used to make the bgpmap more pretty
ROUTER_IP = { "asn": "65551",
"gw" : [ "91.224.148.2", "2a01:6600:8000::175" ], "routerip": ["198.51.100.99", "192.0.2.12", "2001:db8:42:cafe::175"],
"h3" : [ "91.224.148.3", "2a01:6600:8000::131" ] },
} "r2": {
# Using a plain IP address as endpoint is possible
AS_NUMBER = { "endpoint": "http://203.0.113.42:5000",
"gw" : "197422", # It is fine to provide no "routerip" or "asn" field
"h3" : "197422" },
"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" #WHOIS_SERVER = "whois.foo.bar"
@ -32,4 +40,5 @@ AS_NUMBER = {
# DNS zone to query for ASN -> name mapping # DNS zone to query for ASN -> name mapping
ASN_ZONE = "asn.cymru.com" 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' 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": elif proto == "ipv4":
path = service path = service
port = app.config["PROXY"].get(host, "") if not path:
if not port:
return False, 'Host "%s" invalid' % host
elif not path:
return False, 'Proto "%s" invalid' % proto return False, 'Proto "%s" invalid' % proto
url = "http://%s" % (host) if host not in app.config["HOSTS"]:
if "DOMAIN" in app.config: return False, 'Host "%s" invalid' % host
url = "%s.%s" % (url, app.config["DOMAIN"])
url = "%s:%d/%s?" % (url, port, path) endpoint = app.config["HOSTS"][host]["endpoint"]
url = "%s/%s?" % (endpoint, path)
if "SHARED_SECRET" in app.config: if "SHARED_SECRET" in app.config:
url = "%ssecret=%s&" % (url, app.config["SHARED_SECRET"]) url = "%ssecret=%s&" % (url, app.config["SHARED_SECRET"])
url = "%sq=%s" % (url, quote(query)) url = "%sq=%s" % (url, quote(query))
@ -158,7 +155,7 @@ def bird_proxy(host, proto, service, query):
resultat = f.read() resultat = f.read()
status = True # retreive remote status status = True # retreive remote status
except IOError: 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) app.logger.warning("Failed to retrieve URL for host %s: %s", host, url)
status = False status = False
@ -188,12 +185,12 @@ def inject_commands():
@app.context_processor @app.context_processor
def inject_all_host(): def inject_all_host():
return dict(all_hosts="+".join(app.config["PROXY"].keys())) return dict(all_hosts="+".join(app.config["HOSTS"].keys()))
@app.route("/") @app.route("/")
def hello(): 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): def error_page(text):
@ -455,17 +452,16 @@ def show_bgpmap():
return edges[edge_tuple] return edges[edge_tuple]
for host, asmaps in data.iteritems(): for host, asmaps in data.iteritems():
if "DOMAIN" in app.config: add_node(host, label= "%s" % (host.upper()), shape="box", fillcolor="#F5A9A9")
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")
as_number = app.config["AS_NUMBER"].get(host, None) host_config = app.config["HOSTS"].get(host)
if as_number: if host_config:
node = add_node(as_number, fillcolor="#F5A9A9") as_number = host_config.get("asn")
edge = add_edge(as_number, nodes[host]) if as_number:
edge.set_color("red") node = add_node(as_number, fillcolor="#F5A9A9")
edge.set_style("bold") edge = add_edge(as_number, nodes[host])
edge.set_color("red")
edge.set_style("bold")
#colors = [ "#009e23", "#1a6ec1" , "#d05701", "#6f879f", "#939a0e", "#0e9a93", "#9a0e85", "#56d8e1" ] #colors = [ "#009e23", "#1a6ec1" , "#d05701", "#6f879f", "#939a0e", "#0e9a93", "#9a0e85", "#56d8e1" ]
previous_as = None previous_as = None
@ -569,11 +565,10 @@ def build_as_tree_from_raw_bird_ouput(host, proto, text):
peer_ip = expr2.group(2).strip() peer_ip = expr2.group(2).strip()
if expr2.group(4): if expr2.group(4):
peer_protocol_name = expr2.group(4).strip() peer_protocol_name = expr2.group(4).strip()
# Check if via line is a internal route # Check if via line is an internal route (special case for internal routing)
for rt_host, rt_ips in app.config["ROUTER_IP"].iteritems(): for other_host in app.config["HOSTS"].keys():
# Special case for internal routing if peer_ip in app.config["HOSTS"][other_host].get("routerip", []):
if peer_ip in rt_ips: path = [other_host]
path = [rt_host]
break break
else: else:
# ugly hack for good printing # ugly hack for good printing

View File

@ -24,7 +24,7 @@
<li class="navbar-text">Nodes:&nbsp;&nbsp;</li> <li class="navbar-text">Nodes:&nbsp;&nbsp;</li>
<li class="hosts"><a id="{{all_hosts}}" href="#">all</a></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> <li class="hosts"><a id="{{host}}" href="#">{{host}}</a></li>
{% endfor %} {% endfor %}