From fb89feb046c97c7b45664b5d03fe702167f8802b Mon Sep 17 00:00:00 2001 From: brent s Date: Thu, 14 May 2020 03:46:55 -0400 Subject: [PATCH] i'm an idiot. i spent like 15 minutes debugging this. --- utils/he_ipv6/config.py | 125 ++++++++++++++++++------- utils/he_ipv6/example.tunnelbroker.xml | 10 +- utils/he_ipv6/ref | 7 +- utils/he_ipv6/tunnelbroker.py | 28 +++++- 4 files changed, 122 insertions(+), 48 deletions(-) diff --git a/utils/he_ipv6/config.py b/utils/he_ipv6/config.py index 6ebd174..0567b59 100644 --- a/utils/he_ipv6/config.py +++ b/utils/he_ipv6/config.py @@ -6,6 +6,7 @@ import re ## import netaddr import requests +import requests.auth from lxml import etree from pyroute2 import IPRoute ## @@ -182,7 +183,7 @@ class Allocation(object): class Tunnel(object): - def __init__(self, tun_xml): + def __init__(self, tun_xml, he_config): self.xml = tun_xml self.id = None self.client = None @@ -194,6 +195,7 @@ class Tunnel(object): self.radvd_dns = None self.allocations = {} # This is a dict of {}[alloc.id] = Allocation obj self.assignments = [] # This is a list of Assignment objs + self.heconf = he_config self.parse() def _allocations(self): @@ -251,39 +253,19 @@ class Tunnel(object): return(None) -class Config(object): - default_xsd = 'http://schema.xml.r00t2.io/projects/he_ipv6.xsd' +class BaseConfig(object): + default_xsd = None - def __init__(self, xml_path, *args, **kwargs): - self.xml_path = os.path.abspath(os.path.expanduser(xml_path)) - if not os.path.isfile(self.xml_path): - raise ValueError('xml_path does not exist') + def __init__(self, xml_raw, *args, **kwargs): + self.raw = xml_raw self.tree = None self.ns_tree = None self.xml = None self.ns_xml = None - self.raw = None self.xsd = None self.defaults_parser = None self.obj = None - self.tunnels = collections.OrderedDict() - self.creds = {} - self.parse() - - def _creds(self): - creds_xml = self.xml.find('creds') - for cred_xml in creds_xml.findall('cred'): - cred = Credential(cred_xml) - self.creds[cred.id] = cred - return(None) - - def _tunnels(self): - tunnels_xml = self.xml.find('tunnels') - for tun_xml in tunnels_xml.findall('tunnel'): - tun = Tunnel(tun_xml) - tun.creds = self.creds.get(tun.creds_id) - self.tunnels[tun.id] = tun - return(None) + self.parse_xml() def get_xsd(self): raw_xsd = None @@ -310,18 +292,14 @@ class Config(object): self.xsd = etree.XMLSchema(etree.XML(raw_xsd, base_url = base_url)) return(None) - def parse(self): + def parse_xml(self): self.parse_raw() self.get_xsd() self.populate_defaults() self.validate() - self.subparse() return(None) def parse_raw(self, parser = None): - if not self.raw: - with open(self.xml_path, 'rb') as fh: - self.raw = fh.read() self.xml = etree.fromstring(self.raw, parser = parser) self.ns_xml = etree.fromstring(self.raw, parser = parser) self.tree = self.xml.getroottree() @@ -359,13 +337,88 @@ class Config(object): raise ValueError('Did not know how to parse obj parameter') return(None) - def subparse(self): - self._creds() - self._tunnels() - return(None) - def validate(self): if not self.xsd: self.get_xsd() self.xsd.assertValid(self.ns_tree) return(None) + + +class Config(BaseConfig): + default_xsd = 'http://schema.xml.r00t2.io/projects/he_ipv6.xsd' + + def __init__(self, xml_path, *args, **kwargs): + self.xml_path = os.path.abspath(os.path.expanduser(xml_path)) + if not os.path.isfile(self.xml_path): + raise ValueError('xml_path does not exist') + else: + with open(xml_path, 'rb') as fh: + raw_xml = fh.read() + super().__init__(raw_xml, *args, **kwargs) + self.heconf = None + self.creds = {} + self.tunnels = collections.OrderedDict() + self.subparse() + + def _creds(self): + creds_xml = self.xml.find('creds') + for cred_xml in creds_xml.findall('cred'): + cred = Credential(cred_xml) + self.creds[cred.id] = cred + return(None) + + def _heconf(self): + self.heconf = HEConfig(self.creds) + return(None) + + def _tunnels(self): + tunnels_xml = self.xml.find('tunnels') + for tun_xml in tunnels_xml.findall('tunnel'): + tun_id = int(tun_xml.attrib['id'].strip()) + tun = Tunnel(tun_xml, self.heconf.tunnels[tun_id]) + tun.creds = self.creds.get(tun.creds_id) + self.tunnels[tun_id] = tun + return(None) + + def subparse(self): + self._creds() + self._heconf() + self._tunnels() + return(None) + + +class HEConfig(BaseConfig): + default_xsd = 'http://schema.xml.r00t2.io/projects/tunnelbroker.xsd' + nsmap = {None: 'https://tunelbroker.net/tunnelInfo.php', + 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'} + attr_qname = etree.QName('http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation') + schema_loc = 'https://tunnelbroker.net/tunnelInfo.php {0}'.format(default_xsd) + + def __init__(self, creds, xml_url = 'https://tunnelbroker.net/tunnelInfo.php', *args, **kwargs): + self.creds = creds + self.url = xml_url + req = requests.get(self.url, + auth = requests.auth.HTTPBasicAuth(self.creds.user, self.creds.password)) + if not req.ok: + raise RuntimeError('Could not fetch remote tunnel information') + raw_xml = self._add_ns(req.content) + super().__init__(raw_xml, *args, **kwargs) + self.tunnels = collections.OrderedDict() + self.subparse() + + def subparse(self): + pass + + def _add_ns(self, raw_xml): + # https://mailman-mail5.webfaction.com/pipermail/lxml/20100323/013260.html + _xml = etree.fromstring(raw_xml) + _nsmap = copy.deepcopy(_xml.nsmap) + _nsmap.update(self.nsmap) + mod_xml = etree.Element(_xml.tag, {self.attr_qname: self.schema_loc}, nsmap = _nsmap) + mod_xml[:] = _xml[:] + return(etree.tostring(mod_xml, + encoding = 'UTF-8', + xml_declaration = True, + pretty_print = True, + with_tail = True, + with_comments = True)) diff --git a/utils/he_ipv6/example.tunnelbroker.xml b/utils/he_ipv6/example.tunnelbroker.xml index 1a13420..34dbfe1 100644 --- a/utils/he_ipv6/example.tunnelbroker.xml +++ b/utils/he_ipv6/example.tunnelbroker.xml @@ -12,15 +12,16 @@ ipv6user + someSecretPassword xXxXxXxXxXxXxXXX someotheruser + anotherPassword 0000000000000000 @@ -28,14 +29,11 @@