checking in
This commit is contained in:
parent
c596a4d341
commit
7170f61160
5
utils/he_ipv6/__init__.py
Normal file
5
utils/he_ipv6/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from . import args
|
||||||
|
from . import config
|
||||||
|
from . import logger
|
||||||
|
from . import tunnelbroker
|
||||||
|
from . import main
|
32
utils/he_ipv6/args.py
Normal file
32
utils/he_ipv6/args.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
def parseArgs():
|
||||||
|
args = argparse.ArgumentParser(description = ('Dynamically update and enable/disable '
|
||||||
|
'Hurricane Electric Tunnelbroker'))
|
||||||
|
args.add_argument('-i', '--no-wan-ip',
|
||||||
|
dest = 'wan_ip',
|
||||||
|
action = 'store_false',
|
||||||
|
help = ('If specified, use the RFC1918 IP address assigned to this machine instead of the WAN '
|
||||||
|
'IP (necessary if this machine is behind NAT)'))
|
||||||
|
args.add_argument('-c', '--config',
|
||||||
|
dest = 'conf',
|
||||||
|
default = '~/.config/he_tunnelbroker.ini',
|
||||||
|
help = ('The path to the config. '
|
||||||
|
'Default: ~/.config/he_tunnelbroker.ini'))
|
||||||
|
args.add_argument('-t', '--tunnel-id',
|
||||||
|
dest = 'tun_id',
|
||||||
|
help = ('The tunnel profile ID/name to use in -c/--config. '
|
||||||
|
'Default is to use the first one found.'))
|
||||||
|
args.add_argument('-u', '--no-update',
|
||||||
|
dest = 'update',
|
||||||
|
action = 'store_false',
|
||||||
|
help = ('If specified, do not perform the automatic update for start operations. Has no effect '
|
||||||
|
'for other operations'))
|
||||||
|
args.add_argument('oper',
|
||||||
|
metavar = 'OPERATION',
|
||||||
|
choices = ('update', 'start', 'stop'),
|
||||||
|
help = ('The operation to perform ("start", "stop", or "update"). "update" is performed '
|
||||||
|
'automatically by "start", but otherwise will just update the IPv4 address on record '
|
||||||
|
'at tunnelbroker'))
|
||||||
|
return(args)
|
@ -1,3 +1,4 @@
|
|||||||
|
import collections
|
||||||
import copy
|
import copy
|
||||||
import ipaddress
|
import ipaddress
|
||||||
import os
|
import os
|
||||||
@ -6,6 +7,7 @@ import re
|
|||||||
import netaddr
|
import netaddr
|
||||||
import requests
|
import requests
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
from pyroute2 import IPRoute
|
||||||
|
|
||||||
|
|
||||||
class IP(object):
|
class IP(object):
|
||||||
@ -56,11 +58,15 @@ class Allocation(object):
|
|||||||
self.prefix = None
|
self.prefix = None
|
||||||
self.ip = None
|
self.ip = None
|
||||||
self.iface = None
|
self.iface = None
|
||||||
|
self.iface_idx = None
|
||||||
self.parse()
|
self.parse()
|
||||||
|
|
||||||
def _iface(self):
|
def _iface(self):
|
||||||
_iface_txt = self.xml.attrib['iface']
|
_iface_txt = self.xml.attrib['iface']
|
||||||
self.iface = _iface_txt.strip()
|
self.iface = _iface_txt.strip()
|
||||||
|
ipr = IPRoute()
|
||||||
|
self.iface_idx = ipr.link_lookup(ifname = self.iface)[0]
|
||||||
|
ipr.close()
|
||||||
return(None)
|
return(None)
|
||||||
|
|
||||||
def _ip(self):
|
def _ip(self):
|
||||||
@ -173,7 +179,7 @@ class Config(object):
|
|||||||
self.xsd = None
|
self.xsd = None
|
||||||
self.defaults_parser = None
|
self.defaults_parser = None
|
||||||
self.obj = None
|
self.obj = None
|
||||||
self.tunnels = {}
|
self.tunnels = collections.OrderedDict()
|
||||||
self.creds = {}
|
self.creds = {}
|
||||||
self.parse()
|
self.parse()
|
||||||
|
|
||||||
|
49
utils/he_ipv6/logger.py
Normal file
49
utils/he_ipv6/logger.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import logging
|
||||||
|
import logging.handlers
|
||||||
|
import os
|
||||||
|
try:
|
||||||
|
# https://www.freedesktop.org/software/systemd/python-systemd/journal.html#journalhandler-class
|
||||||
|
from systemd import journal
|
||||||
|
_has_journald = True
|
||||||
|
except ImportError:
|
||||||
|
_has_journald = False
|
||||||
|
|
||||||
|
|
||||||
|
logfile = '/var/log/tunnelbroker_manager.log'
|
||||||
|
# Prep the log file.
|
||||||
|
logfile = os.path.abspath(os.path.expanduser(logfile))
|
||||||
|
os.makedirs(os.path.dirname(logfile), exist_ok = True, mode = 0o0700)
|
||||||
|
if not os.path.isfile(logfile):
|
||||||
|
with open(logfile, 'w') as fh:
|
||||||
|
fh.write('')
|
||||||
|
os.chmod(logfile, 0o0600)
|
||||||
|
|
||||||
|
# And set up logging.
|
||||||
|
_cfg_args = {'handlers': [],
|
||||||
|
'level': logging.DEBUG}
|
||||||
|
if _has_journald:
|
||||||
|
# There were some weird changes somewhere along the line.
|
||||||
|
try:
|
||||||
|
# But it's *probably* this one.
|
||||||
|
h = journal.JournalHandler()
|
||||||
|
except AttributeError:
|
||||||
|
h = journal.JournaldLogHandler()
|
||||||
|
# Systemd includes times, so we don't need to.
|
||||||
|
h.setFormatter(logging.Formatter(style = '{',
|
||||||
|
fmt = ('{name}:{levelname}:{name}:{filename}:'
|
||||||
|
'{funcName}:{lineno}: {message}')))
|
||||||
|
_cfg_args['handlers'].append(h)
|
||||||
|
h = logging.handlers.RotatingFileHandler(logfile,
|
||||||
|
encoding = 'utf8',
|
||||||
|
# Disable rotating for now.
|
||||||
|
# maxBytes = 50000000000,
|
||||||
|
# backupCount = 30
|
||||||
|
)
|
||||||
|
h.setFormatter(logging.Formatter(style = '{',
|
||||||
|
fmt = ('{asctime}:'
|
||||||
|
'{levelname}:{name}:{filename}:'
|
||||||
|
'{funcName}:{lineno}: {message}')))
|
||||||
|
_cfg_args['handlers'].append(h)
|
||||||
|
logging.basicConfig(**_cfg_args)
|
||||||
|
logger = logging.getLogger('HE Tunnelbroker Manager')
|
||||||
|
logger.info('Logging initialized.')
|
24
utils/he_ipv6/main.py
Executable file
24
utils/he_ipv6/main.py
Executable file
@ -0,0 +1,24 @@
|
|||||||
|
import logging
|
||||||
|
##
|
||||||
|
from . import args
|
||||||
|
from . import tunnelbroker
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
_args = args.parseArgs().parse_args()
|
||||||
|
logger.debug('Invoked with args: {0}'.format(vars(_args)))
|
||||||
|
tb = tunnelbroker.TunnelBroker(**vars(_args))
|
||||||
|
if _args.oper == 'start':
|
||||||
|
tb.start()
|
||||||
|
elif _args.oper == 'stop':
|
||||||
|
tb.stop()
|
||||||
|
elif _args.oper == 'update':
|
||||||
|
tb.update(oneshot = True)
|
||||||
|
return(None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
4
utils/he_ipv6/ref
Normal file
4
utils/he_ipv6/ref
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# https://wiki.archlinux.org/index.php/IPv6_tunnel_broker_setup
|
||||||
|
# https://forums.he.net/index.php?topic=3153.0
|
||||||
|
# https://gist.github.com/pklaus/960672
|
||||||
|
# https://shorewall.org/6to4.htm#idm143
|
48
utils/he_ipv6/tunnelbroker.py
Normal file
48
utils/he_ipv6/tunnelbroker.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import socket
|
||||||
|
logger = logging.getLogger()
|
||||||
|
##
|
||||||
|
import requests
|
||||||
|
from pyroute2 import IPRoute
|
||||||
|
##
|
||||||
|
from . import config
|
||||||
|
|
||||||
|
|
||||||
|
class TunnelBroker(object):
|
||||||
|
url_ip = 'https://ipv4.clientinfo.square-r00t.net/'
|
||||||
|
params_ip = {'raw': '1'}
|
||||||
|
url_api = 'https://ipv4.tunnelbroker.net/nic/update'
|
||||||
|
|
||||||
|
def __init__(self, conf_xml, tun_id = None, wan_ip = True, update = True, *args, **kwargs):
|
||||||
|
self.conf_file = os.path.abspath(os.path.expanduser(conf_xml))
|
||||||
|
logger.debug('Using config path: {0}'.format(self.conf_file))
|
||||||
|
self._conf = config.Config(self.conf_file)
|
||||||
|
if tun_id:
|
||||||
|
self.cfg = self._conf.tunnels[int(tun_id)]
|
||||||
|
else:
|
||||||
|
tun_id = list(self._conf.tunnels.keys())[0]
|
||||||
|
self.cfg = self._conf.tunnels[tun_id]
|
||||||
|
self.wan = wan_ip
|
||||||
|
self.update = update
|
||||||
|
self.my_ip = None
|
||||||
|
|
||||||
|
def _get_my_ip(self):
|
||||||
|
if self.wan:
|
||||||
|
logger.debug('WAN IP tunneling enabled; fetching WAN IP.')
|
||||||
|
req = requests.get(self.url_ip, params = self.params_ip)
|
||||||
|
if not req.ok:
|
||||||
|
logger.error('Could not fetch self IP. Request returned {0}.'.format(req.status_code))
|
||||||
|
raise RuntimeError('Could not fetch self IP')
|
||||||
|
self.my_ip = config.IP4(req.json()['ip'], 32)
|
||||||
|
logger.debug('Set my_ip to {0}.'.format(self.my_ip.str))
|
||||||
|
else:
|
||||||
|
logger.debug('WAN IP tunneling disabled; fetching LAN IP.')
|
||||||
|
ipr = IPRoute()
|
||||||
|
_defrt = ipr.get_default_routes(family = socket.AF_INET)
|
||||||
|
if len(_defrt) != 1: # This (probably) WILL fail on multipath systems.
|
||||||
|
logger.error('Could not determine default route. Does this machine have a single default route?')
|
||||||
|
raise RuntimeError('Could not determine default IPv4 route')
|
||||||
|
self.my_ip = config.IP4(_defrt[0]['attrs']['RTA_PREFSRC'], 32)
|
||||||
|
logger.debug('Set my_ip to {0}.'.format(self.my_ip.str))
|
||||||
|
return(None)
|
Loading…
Reference in New Issue
Block a user