From 3f2d6be7dd2ca2411f04b22fdbdab80578bb5f9b Mon Sep 17 00:00:00 2001 From: brent s Date: Tue, 12 May 2020 01:21:52 -0400 Subject: [PATCH] adding some config stuff --- utils/example.he_tunnelbroker.ini | 31 --------- utils/he_ipv6/config.py | 100 ++++++++++++++++++++++++++++++ utils/he_ipv6/example.he_ipv6.xml | 60 ++++++++++++++++-- 3 files changed, 156 insertions(+), 35 deletions(-) delete mode 100644 utils/example.he_tunnelbroker.ini create mode 100644 utils/he_ipv6/config.py diff --git a/utils/example.he_tunnelbroker.ini b/utils/example.he_tunnelbroker.ini deleted file mode 100644 index fb799c7..0000000 --- a/utils/example.he_tunnelbroker.ini +++ /dev/null @@ -1,31 +0,0 @@ -# This is a sample INI file to use with he_ipv6.py. -# If you do not yet have an IPv6 Tunnelbroker.net allocation, you can get one (for free!) at: -# https://www.tunnelbroker.net/tunnel_detail.php?tid=584532 -## -# This is the tunnel ID. To get it, log into your tunnelbroker.net account and click on the tunnel you wish to use. -# The tunnel ID is the numerical string in the URL. e.g.: -# https://www.tunnelbroker.net/tunnel_detail.php?tid=12345 -# The tunnel ID would be 12345 in the above example. -[12345] -# This is your tunnelbroker.net username. -user = ipv6user -# This is your update key for the above user. You can find it in the "Advanced" tab. -update_key = xXxXxXxXxXxXxXXX -# This is the server IP ("IPv6 Tunnel Endpoints" section). *Be sure to use the IPv4 address!* ("Server IPv4 Address") -server = 192.0.2.1 -# And these are all the allocations you wish to add to this machine. Be sure to add the prefix (e.g. /64, /48)! -# You can specify multiple allocations with a comma-separated list. -# ("Routed IPv6 Prefixes") -allocations = 2001:DB8:1::/64,2001:DB8:2::/64 -# This is the address to actually set on the interface. There should be only one here. Be sure to include the prefix! -# ("Client IPv6 Address") -address = 2001:DB8:3::1/64 - -# You can specify multiple tunnel profiles for your machine. -[54321] -# And you can even reference values from other sections. -user = ${12345:user} -update_key = ${12345:update_key} -server = 192.0.2.2 -allocations = 2001:DB8:4::/64 -address = 2001:DB8:5::2/64 diff --git a/utils/he_ipv6/config.py b/utils/he_ipv6/config.py new file mode 100644 index 0000000..88feaa3 --- /dev/null +++ b/utils/he_ipv6/config.py @@ -0,0 +1,100 @@ +import os +import re +## +import requests +from lxml import etree + + +class Config(object): + 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') + 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 = {} + self.creds = {} + self.parse_raw() + self.get_xsd() + self.populate_defaults() + self.validate() + + def get_xsd(self): + raw_xsd = None + base_url = None + xsi = self.xml.nsmap.get('xsi', 'http://www.w3.org/2001/XMLSchema-instance') + schemaLocation = '{{{0}}}schemaLocation'.format(xsi) + schemaURL = self.xml.attrib.get(schemaLocation, self.default_xsd) + split_url = schemaURL.split() + if len(split_url) == 2: # a properly defined schemaLocation + schemaURL = split_url[1] + else: + schemaURL = split_url[0] # a LAZY schemaLocation + if schemaURL.startswith('file://'): + schemaURL = re.sub(r'^file://', r'', schemaURL) + with open(schemaURL, 'rb') as fh: + raw_xsd = fh.read() + base_url = os.path.dirname(schemaURL) + '/' + else: + req = requests.get(schemaURL) + if not req.ok: + raise RuntimeError('Could not download XSD') + raw_xsd = req.content + base_url = os.path.split(req.url)[0] + '/' # This makes me feel dirty. + self.xsd = etree.XMLSchema(etree.XML(raw_xsd, base_url = base_url)) + 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() + self.ns_tree = self.ns_xml.getroottree() + self.tree.xinclude() + self.ns_tree.xinclude() + self.strip_ns() + return(None) + + def populate_defaults(self): + if not self.xsd: + self.get_xsd() + if not self.defaults_parser: + self.defaults_parser = etree.XMLParser(schema = self.xsd, attribute_defaults = True) + self.parse_raw(parser = self.defaults_parser) + return(None) + + def remove_defaults(self): + self.parse_raw() + return(None) + + def strip_ns(self, obj = None): + # https://stackoverflow.com/questions/30232031/how-can-i-strip-namespaces-out-of-an-lxml-tree/30233635#30233635 + xpathq = "descendant-or-self::*[namespace-uri()!='']" + if not obj: + for x in (self.tree, self.xml): + for e in x.xpath(xpathq): + e.tag = etree.QName(e).localname + elif isinstance(obj, (etree._Element, etree._ElementTree)): + obj = copy.deepcopy(obj) + for e in obj.xpath(xpathq): + e.tag = etree.QName(e).localname + return(obj) + else: + raise ValueError('Did not know how to parse obj parameter') + return(None) + + def validate(self): + if not self.xsd: + self.get_xsd() + self.xsd.assertValid(self.ns_tree) + return(None) diff --git a/utils/he_ipv6/example.he_ipv6.xml b/utils/he_ipv6/example.he_ipv6.xml index db1d5b9..7b2c685 100644 --- a/utils/he_ipv6/example.he_ipv6.xml +++ b/utils/he_ipv6/example.he_ipv6.xml @@ -2,7 +2,19 @@ + + ipv6user xXxXxXxXxXxXxXXX @@ -13,19 +25,59 @@ + + 192.0.2.1 + + - 2001:DB8:1:2: - 2001:DB8:2:: + + 2001:DB8:1:2:: + + 2001:DB8:2:: + 2001:DB8:3::2 + 192.0.2.1 - 2001:DB8:4:2: - 2001:DB8:5:: + 2001:DB8:4:2: + 2001:DB8:5:: 2001:DB8:6::2