restructuring and removing HEConfig
This commit is contained in:
		
							parent
							
								
									676aa8d5b6
								
							
						
					
					
						commit
						315af935ac
					
				@ -1,5 +1,6 @@
 | 
			
		||||
from . import args
 | 
			
		||||
from . import radvd
 | 
			
		||||
from . import tunnel
 | 
			
		||||
from . import config
 | 
			
		||||
from . import logger
 | 
			
		||||
from . import tunnelbroker
 | 
			
		||||
 | 
			
		||||
@ -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):
 | 
			
		||||
 | 
			
		||||
@ -12,17 +12,14 @@
 | 
			
		||||
  <creds>
 | 
			
		||||
    <!--
 | 
			
		||||
    Credentials are kept separate from tunnel configuration because you can have multiple (up to 5) tunnels per user.
 | 
			
		||||
    You can find the updateKey in the "Advanced" tab of your tunnel's configuration on your tunnelbroker.net panel.
 | 
			
		||||
    -->
 | 
			
		||||
    <cred id="ipv6user">
 | 
			
		||||
      <user>ipv6user</user>
 | 
			
		||||
      <password>someSecretPassword</password>
 | 
			
		||||
      <updateKey>xXxXxXxXxXxXxXXX</updateKey>
 | 
			
		||||
    </cred>
 | 
			
		||||
    <cred id="anotheruser">
 | 
			
		||||
      <user>someotheruser</user>
 | 
			
		||||
      <password>anotherPassword</password>
 | 
			
		||||
      <updateKey>0000000000000000</updateKey>
 | 
			
		||||
    </cred>
 | 
			
		||||
  </creds>
 | 
			
		||||
  <tunnels>
 | 
			
		||||
@ -36,6 +33,10 @@
 | 
			
		||||
    be "12345".
 | 
			
		||||
    -->
 | 
			
		||||
    <tunnel id="12345" creds="ipv6user">
 | 
			
		||||
      <!--
 | 
			
		||||
      You can find the updateKey in the "Advanced" tab of your tunnel's configuration on your tunnelbroker.net panel.
 | 
			
		||||
      -->
 | 
			
		||||
      <updateKey>xXxXxXxXxXxXxXXX</updateKey>
 | 
			
		||||
      <!--
 | 
			
		||||
      Where to assign your allocations. The default allocation prefix is a /64 (prefix="64"), since that's what SLAAC
 | 
			
		||||
      recommends.
 | 
			
		||||
@ -68,6 +69,7 @@
 | 
			
		||||
    And you can, of course, specify multiple tunnels.
 | 
			
		||||
    -->
 | 
			
		||||
    <tunnel id="54321" creds="anotheruser">
 | 
			
		||||
      <updateKey>0000000000000000</updateKey>
 | 
			
		||||
      <assignments>
 | 
			
		||||
        <!--
 | 
			
		||||
        Uses the default prefix of /64 from your standard /64 allocation from Hurricane Electric.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										171
									
								
								utils/he_ipv6/tunnel.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								utils/he_ipv6/tunnel.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,171 @@
 | 
			
		||||
import ipaddress
 | 
			
		||||
##
 | 
			
		||||
import netaddr
 | 
			
		||||
from pyroute2 import IPRoute
 | 
			
		||||
##
 | 
			
		||||
from . import utils
 | 
			
		||||
from . import radvd
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 = utils.xml2bool(_assigns_xml.attrib.get('radvd', 'false'))
 | 
			
		||||
        self.radvd_dns = utils.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)
 | 
			
		||||
							
								
								
									
										10
									
								
								utils/he_ipv6/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								utils/he_ipv6/utils.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
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')
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user