From 315af935ac63702d02c9b33f2e06df30eac95fc0 Mon Sep 17 00:00:00 2001 From: brent s Date: Thu, 14 May 2020 17:11:47 -0400 Subject: [PATCH] restructuring and removing HEConfig --- utils/he_ipv6/__init__.py | 1 + utils/he_ipv6/config.py | 284 +++++-------------------- utils/he_ipv6/example.tunnelbroker.xml | 8 +- utils/he_ipv6/tunnel.py | 171 +++++++++++++++ utils/he_ipv6/utils.py | 10 + 5 files changed, 242 insertions(+), 232 deletions(-) create mode 100644 utils/he_ipv6/tunnel.py create mode 100644 utils/he_ipv6/utils.py diff --git a/utils/he_ipv6/__init__.py b/utils/he_ipv6/__init__.py index 3e859d4..ca2774b 100644 --- a/utils/he_ipv6/__init__.py +++ b/utils/he_ipv6/__init__.py @@ -1,5 +1,6 @@ from . import args from . import radvd +from . import tunnel from . import config from . import logger from . import tunnelbroker diff --git a/utils/he_ipv6/config.py b/utils/he_ipv6/config.py index 0eceb9c..61bbcd2 100644 --- a/utils/he_ipv6/config.py +++ b/utils/he_ipv6/config.py @@ -10,62 +10,9 @@ import requests.auth from lxml import etree from pyroute2 import IPRoute ## +from . import tunnel from . import radvd - - -def xml2bool(xml_str): - if xml_str is None: - return(None) - xml_str = xml_str.lower()[0] - if xml_str in ('t', '1'): - return(True) - elif xml_str in ('f', '0'): - return(False) - else: - raise ValueError('Not a boolean value') - - -class IP(object): - type = None - version = None - _ip = ipaddress.ip_address - _net = ipaddress.ip_network - _net_ip = netaddr.IPAddress - _net_net = netaddr.IPNetwork - - def __init__(self, ip, prefix, *args, **kwargs): - self.str = ip - self.prefix = int(prefix) - self.net_ip = self._net_ip(self.str) - self.net_net = self._net_net('{0}/{1}'.format(self.str, self.prefix)) - - def _ext_init(self): - self.ip = self._ip(self.str) - self.net = self._net('{0}/{1}'.format(self.str, self.prefix), strict = False) - return(None) - - -class IP4(IP): - type = 'IPv4' - version = 4 - _ip = ipaddress.IPv4Address - _net = ipaddress.IPv4Network - - def __init__(self, ip, prefix, *args, **kwargs): - super().__init__(ip, prefix, *args, **kwargs) - self._ext_init() - - -class IP6(IP): - type = 'IPv6' - version = 6 - _ip = ipaddress.IPv6Address - _net = ipaddress.IPv6Network - - def __init__(self, ip, prefix, *args, **kwargs): - super().__init__(ip, prefix, *args, **kwargs) - self._ext_init() - self.alloc_block = netaddr.SubnetSplitter(self.net_net) +from . import utils class Credential(object): @@ -110,125 +57,9 @@ class Credential(object): return(None) -class Assignment(object): - def __init__(self, assign_xml, radvd = False, dns = False): - self.xml = assign_xml - self.do_radvd = radvd - self.radvd_dns = dns - self.iface = None - self.iface_idx = None - self.iface_addrs = [] - self.iface_blocks = [] - self.alloc = None # This must be set externally to a mapped Allocation instance - self.alloc_id = None - self.prefix = None - self.alloc_block = None - self.parse() - - def _alloc(self): - self.alloc_id = int(self.xml.attrib['alloc'].strip()) - return(None) - - def _iface(self): - _iface_txt = self.xml.attrib['iface'].strip() - self.iface = _iface_txt.strip() - ipr = IPRoute() - self.iface_idx = ipr.link_lookup(ifname = self.iface)[0] - ipr.close() - return(None) - - def _prefix(self): - self.prefix = int(self.xml.attrib.get('prefix', 64).strip()) - return(None) - - def parse(self): - self._iface() - self._alloc() - self._prefix() - return(None) - - def parse_alloc(self): - self.alloc_block = self.alloc.ip.alloc_block - self.iface_blocks = self.alloc_block.extract_subnet(self.prefix, count = 1) - for i in self.iface_blocks: - self.iface_addrs.append(IP6(str(next(i.iter_hosts())), 128)) - return(None) - - -class Allocation(object): - def __init__(self, alloc_net): - _ip, _prefix = alloc_net.split('/') - self.id = int(_prefix.strip()) - self.prefix = self.id - self.ip = IP6(_ip.strip(), self.prefix) - - -class Tunnel(object): - def __init__(self, tun_xml, he_tunnels): - self.xml = tun_xml - self.id = None - self.client = None - self.server = None - self.creds = None - self.creds_id = None - self.radvd = None - self.enable_radvd = None - 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_tunnels - self.parse() - - def _allocations(self): - self.allocations = self.heconf[self.id].allocations - return(None) - - def _assignments(self): - _assigns_xml = self.xml.find('assignments') - self.enable_radvd = xml2bool(_assigns_xml.attrib.get('radvd', 'false')) - self.radvd_dns = xml2bool(_assigns_xml.attrib.get('radvdDns', 'false')) - for _assign_xml in _assigns_xml.findall('assign'): - assign = Assignment(_assign_xml, radvd = self.enable_radvd, dns = self.radvd_dns) - assign.alloc = self.allocations[assign.alloc_id] - assign.parse_alloc() - self.assignments.append(assign) - return(None) - - def _client(self): - _client_xml = self.xml.find('client') - _ip_txt = _client_xml.text.strip() - _prefix_txt = _client_xml.attrib['prefix'].strip() - self.client = IP6(_ip_txt, _prefix_txt) - return(None) - - def _creds(self): - self.creds_id = self.xml.attrib['creds'].strip() - return(None) - - def _id(self): - self.id = int(self.xml.attrib['id'].strip()) - return(None) - - def _radvd(self): - self.radvd = radvd.RADVD() - self.radvd.conf.generate(self.assignments) - return(None) - - def _server(self): - _server_xml = self.xml.find('server') - _ip_text = _server_xml.text.strip() - self.server = IP4(_ip_text, 32) - return(None) - - def parse(self): - self._id() - self._creds() - self._client() - self._server() - self._allocations() - self._assignments() - self._radvd() - return(None) +class HETunnel(object): + def __init__(self, tun_xml): + pass class BaseConfig(object): @@ -333,7 +164,6 @@ class Config(BaseConfig): 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() @@ -345,67 +175,62 @@ class Config(BaseConfig): 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) + tun_creds_id = tun_xml.attrib['creds'] + tun = tunnel.Tunnel(tun_xml, self.creds[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): - # Creds are unique per tunnel... but we don't know the ID yet so we don't know which creds to use. - # TODO. - 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) - # In the format of: {tun_id: HETunnel()} - self.tunnels = collections.OrderedDict() - self.subparse() - - def subparse(self): - for tun_xml in self.xml.findall('tunnel'): - tun = HETunnel(tun_xml) - self.tunnels[tun.id] = tun - return(None) - - 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)) +# class HEConfig(BaseConfig): +# # This is unused. Kept mostly for reference. +# +# 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) +# # In the format of: {tun_id: HETunnel()} +# self.tunnels = collections.OrderedDict() +# self.subparse() +# +# def subparse(self): +# for tun_xml in self.xml.findall('tunnel'): +# tun = HETunnel(tun_xml) +# self.tunnels[tun.id] = tun +# return(None) +# +# 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)) class HETunnelConfig(BaseConfig): @@ -416,8 +241,9 @@ class HETunnelConfig(BaseConfig): attr_qname = etree.QName('http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation') schema_loc = 'https://tunnelbroker.net/tunnelInfo.php?tid {0}'.format(default_xsd) - def __init__(self, tun_xml): + def __init__(self, tun_xml, creds): self.xml = tun_xml + self.creds = creds self.id = None self.description = None self.client = None # Client IPv6 @@ -432,13 +258,13 @@ class HETunnelConfig(BaseConfig): for a in ('64', '48'): _alloc = self.xml.find('routed{0}'.format(a)) if _alloc is not None and _alloc.text.strip() != '': - self.allocations[int(a)] = Allocation(_alloc.text.strip()) + self.allocations[int(a)] = tunnel.Allocation(_alloc.text.strip()) return(None) def _client(self): _client = self.xml.find('clientv4').text if _client is not None and _client.strip() != '': - self.client = IP4(_client.strip(), 32) + self.client = tunnel.IP4(_client.strip(), 32) return(None) def _desc(self): @@ -448,7 +274,7 @@ class HETunnelConfig(BaseConfig): return(None) def _endpoint(self): - self.endpoint = IP4(self.xml.find('serverv4').text.strip(), 32) + self.endpoint = tunnel.IP4(self.xml.find('serverv4').text.strip(), 32) return(None) def _id(self): @@ -458,7 +284,7 @@ class HETunnelConfig(BaseConfig): def _my_ip(self): _ip = self.xml.find('clientv4').text if _ip is not None and _ip.strip() != '': - self.my_ip = IP4(_ip.strip(), 32) + self.my_ip = tunnel.IP4(_ip.strip(), 32) return(None) def _rdns(self): @@ -471,7 +297,7 @@ class HETunnelConfig(BaseConfig): return(None) def _server(self): - self.server = IP6(self.xml.find('serverv6'), 128) + self.server = tunnel.IP6(self.xml.find('serverv6'), 128) return(None) def parse(self): diff --git a/utils/he_ipv6/example.tunnelbroker.xml b/utils/he_ipv6/example.tunnelbroker.xml index 863362b..26a7ddd 100644 --- a/utils/he_ipv6/example.tunnelbroker.xml +++ b/utils/he_ipv6/example.tunnelbroker.xml @@ -12,17 +12,14 @@ ipv6user someSecretPassword - xXxXxXxXxXxXxXXX someotheruser anotherPassword - 0000000000000000 @@ -36,6 +33,10 @@ be "12345". --> + + xXxXxXxXxXxXxXXX + 0000000000000000