Commit f3ccd7a2 authored by Jondy Zhao's avatar Jondy Zhao

Merge branch 'master' into cygwin

Conflicts:
	re6stnet
parents b04b2b95 6e443638
......@@ -23,3 +23,8 @@
use --main-interface option on it.
- Is it useful that each node regenerates its own DH parameter ?
- Filter non-routable IPs. Add an option not to do it.
- Abort in case of import child process failure (babel, openvpn server,
openvpn client if run with --client).
\ No newline at end of file
-----BEGIN CERTIFICATE-----
MIIDTTCCAjWgAwIBAgIHASABDbgAQjANBgkqhkiG9w0BAQUFADA+MRowGAYDVQQD
DBFyZTZzdC5leGFtcGxlLmNvbTEgMB4GCSqGSIb3DQEJARYRcmU2c3RAZXhhbXBs
ZS5jb20wHhcNMTIwOTA2MTI0MTM0WhcNMjAwMTAxMTI0MTM0WjA+MRowGAYDVQQD
DBFyZTZzdC5leGFtcGxlLmNvbTEgMB4GCSqGSIb3DQEJARYRcmU2c3RAZXhhbXBs
ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzKdaI1gddt8iN
5MTNMe+bKuVt0Cfq34OUh0y73NQm1HjUMDHiU/5djkBuw+Y8q8OMIwCuN8Pgyp6C
fFivLH3a42ebgxJn2kfU7078gibCEuIPWD9GXQjSgP+7MJVv3q24g4YZTsa6lKJ8
Y1OfP2i2uNR3v7/3BBIsob8pial2kbLgz96L+czDjPOVsV+VH91Mkq6kO7jfNpNo
BHVSXzkQpVupxi86wEFIrkzlAYZRmY0fRcprhovI1iDLpdsJsY/yyPgfXNJk9xhT
lPUoNxyH0EPhGv0KArJZkwlzdDj5RVYYcLTEge374gr1EIMyzex/kN5y1as2tX9l
wXTROc5pAgMBAAGjUDBOMB0GA1UdDgQWBBSgDNnHOCF5xSGbmA9SCujCLRs0nTAf
BgNVHSMEGDAWgBSgDNnHOCF5xSGbmA9SCujCLRs0nTAMBgNVHRMEBTADAQH/MA0G
CSqGSIb3DQEBBQUAA4IBAQBZQvMkCSCrrJoS432kJUg//iB0+c1mftbYTez+wqHq
NzEPnv5EWJtYsYvZUx6huNvrv5UR9S9MkGyH1u8kw3mW5lRKTPBC9NdAgywhsDES
VTDx02EZhsKEA2VaxhirGyJEDSgXADQNZNtB0Mw+M8/tociZKOiih6gwJw3sYcDz
9mTQFG44YG2nSmxEqP2m+32km0gvxLNIyoCnZN1x25dcRcJ5H9AbbIfSZxC02rqc
Wy0HLmfa7ZPLYD5Qz/TuCXXRXxyy5AYasVsz2GdXDNXRwiEmYqfM69EDtwZqTPZj
cfJdgSNqrysIXYE6SgBi6RUtOlmBubdxke4EZZ4ImdGo
-----END CERTIFICATE-----
......@@ -5,6 +5,7 @@ IPTABLES = 'iptables'
SCREEN = 'screen'
VERBOSE = 4
REGISTRY='10.0.0.2'
CA_DAYS = 1000
# registry
# |.2
......@@ -154,6 +155,10 @@ gateway1.screen('miniupnpd -d -f miniupnpd.conf -P miniupnpd.pid -a 10.1.1.1'
' -i %s' % g1_if_0_name)
if 1:
import sqlite3
os.path.exists('ca.crt') or subprocess.check_call(
"openssl req -nodes -new -x509 -key registry/ca.key -out ca.crt"
" -subj /CN=re6st.example.com/emailAddress=re6st@example.com"
" -set_serial 0x120010db80042 -days %u" % CA_DAYS, shell=True)
db_path = 'registry/registry.db'
registry.screen('../re6st-registry @registry/re6st-registry.conf --db %s'
' --mailhost %s -v%u' % (db_path, os.path.abspath('mbox'), VERBOSE))
......@@ -189,7 +194,7 @@ if 1:
p.communicate(str(token[0]))
os.remove(dh_path)
os.remove(folder + '/ca.crt')
node.screen('../re6stnet @%s/re6stnet.conf --table 0 -v%u --registry %s %s'
node.screen('../re6stnet @%s/re6stnet.conf -v%u --registry %s %s'
% (folder, VERBOSE, registry, args))
re6stnet(registry, 'registry', '--ip ' + REGISTRY, registry='http://localhost/')
re6stnet(machine1, 'm1', '-I%s' % m1_if_0.name)
......@@ -278,8 +283,9 @@ if len(sys.argv) > 1:
elif self.path == '/tunnel.html':
other = 'route'
gv = registry.Popen(('python', '-c', r"""if 1:
import math, xmlrpclib
g = xmlrpclib.ServerProxy('http://localhost/').topology()
import math
from re6st.registry import RegistryClient
g = eval(RegistryClient('http://localhost/').topology())
print 'digraph {'
a = 2 * math.pi / len(g)
z = 4
......@@ -293,7 +299,7 @@ if len(sys.argv) > 1:
for p in p or ():
print '"%s" -> "%s";' % (n, title(p))
print '}'
"""), stdout=subprocess.PIPE).communicate()[0]
"""), stdout=subprocess.PIPE, cwd="..").communicate()[0]
if gv:
svg = subprocess.Popen(('neato', '-Tsvg'),
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
......
......@@ -7,5 +7,6 @@ dh dh2048.pem
ca ca.crt
cert m1/cert.crt
key m1/cert.key
table 0
client-count 2
tunnel-refresh 100
......@@ -7,5 +7,6 @@ dh dh2048.pem
ca ca.crt
cert m2/cert.crt
key m2/cert.key
table 0
client-count 2
tunnel-refresh 100
......@@ -7,5 +7,6 @@ dh dh2048.pem
ca ca.crt
cert m3/cert.crt
key m3/cert.key
table 0
client-count 2
tunnel-refresh 100
......@@ -7,5 +7,6 @@ dh dh2048.pem
ca ca.crt
cert m4/cert.crt
key m4/cert.key
table 0
client-count 2
tunnel-refresh 100
......@@ -5,5 +5,6 @@ hello 4
ca ca.crt
cert m5/cert.crt
key m5/cert.key
table 0
client-count 0
max-clients 0
......@@ -7,6 +7,7 @@ dh dh2048.pem
ca ca.crt
cert m6/cert.crt
key m6/cert.key
table 0
client-count 2
tunnel-refresh 100
# TODO: Run a DHCPv4 client on machine9. Unfortunately, isc-dhcp-client 4.2.4
......
......@@ -7,5 +7,6 @@ dh dh2048.pem
ca ca.crt
cert m7/cert.crt
key m7/cert.key
table 0
client-count 2
tunnel-refresh 100
......@@ -5,4 +5,5 @@ hello 4
ca ca.crt
cert m8/cert.crt
key m8/cert.key
table 0
client 10.0.1.2,1194,udp;10.0.1.3,1194,udp
......@@ -6,5 +6,6 @@ dh dh2048.pem
ca ca.crt
cert registry/cert.crt
key registry/cert.key
gateway
client-count 2
tunnel-refresh 100
#!/usr/bin/python
import argparse, atexit, errno, os, subprocess, sqlite3, sys, xmlrpclib
import argparse, atexit, errno, os, subprocess, sqlite3, sys, time
from OpenSSL import crypto
from re6st import utils
from re6st import registry, utils
def create(path, text=None, mode=0666):
fd = os.open(path, os.O_CREAT | os.O_WRONLY | os.O_TRUNC, mode)
......@@ -10,6 +10,9 @@ def create(path, text=None, mode=0666):
finally:
os.close(fd)
def loadCert(pem):
return crypto.load_certificate(crypto.FILETYPE_PEM, pem)
def main():
parser = argparse.ArgumentParser(
description="Setup script for re6stnet.",
......@@ -47,11 +50,11 @@ def main():
dh_path = 'dh2048.pem'
# Establish connection with server
s = xmlrpclib.ServerProxy(config.registry, allow_none=True)
s = registry.RegistryClient(config.registry)
# Get CA
ca = s.getCa()
network = utils.networkFromCa(ca)
network = utils.networkFromCa(loadCert(ca))
if config.is_needed:
route, err = subprocess.Popen(('ip', '-6', '-o', 'route', 'get',
utils.ipFromBin(network)),
......@@ -72,7 +75,7 @@ def main():
req = crypto.X509Req()
try:
with open(cert_path) as f:
cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
cert = loadCert(f.read())
components = dict(cert.get_subject().get_components())
components.pop('CN', None)
except IOError, e:
......@@ -136,7 +139,12 @@ def main():
os.ftruncate(cert_fd, len(cert))
os.close(cert_fd)
print "Certificate setup complete."
cert = loadCert(cert)
not_after = utils.notAfter(cert)
print("Setup complete. Certificate is valid until %s UTC"
" and will be automatically renewed after %s UTC" % (
time.asctime(time.gmtime(not_after)),
time.asctime(time.gmtime(not_after - registry.RENEW_PERIOD))))
if not os.path.lexists(conf_path):
create(conf_path, """\
......
This diff is collapsed.
import logging, sqlite3, socket, subprocess, xmlrpclib, time
from urllib import splittype, splithost, splitport
import utils
import logging, sqlite3, socket, subprocess, time
from . import utils
class PeerDB(object):
# internal ip = temp arg/attribute
def __init__(self, db_path, registry, key_path, prefix, db_size=200):
def __init__(self, db_path, registry, key_path, network, prefix,
db_size=200):
self._prefix = prefix
self._db_size = db_size
self._key_path = key_path
self._proxy = xmlrpclib.ServerProxy(registry)
self._registry = registry
logging.info('Initialize cache ...')
self._db = sqlite3.connect(db_path, isolation_level=None)
......@@ -25,28 +25,36 @@ class PeerDB(object):
value text)""")
q('ATTACH DATABASE ":memory:" AS volatile')
q("""CREATE TABLE volatile.stat (
peer TEXT PRIMARY KEY REFERENCES peer(prefix) ON DELETE CASCADE,
peer TEXT PRIMARY KEY,
try INTEGER NOT NULL DEFAULT 0)""")
q("CREATE INDEX volatile.stat_try ON stat(try)")
q("INSERT INTO volatile.stat (peer) SELECT prefix FROM peer")
try:
a = q("SELECT value FROM config WHERE name='registry'").next()[0]
except StopIteration:
logging.info("Private IP of registry not in cache."
" Asking registry via its public IP ...")
retry = 1
while True:
try:
a = self._proxy.getPrivateAddress()
break
except socket.error, e:
logging.warning(e)
time.sleep(retry)
retry = min(60, retry * 2)
q("INSERT INTO config VALUES ('registry',?)", (a,))
self.registry_ip = utils.binFromIp(a)
a = self._updateRegistryIP()
else:
self.registry_ip = utils.binFromIp(a)
if not self.registry_ip.startswith(network):
a = self._updateRegistryIP()
logging.info("Cache initialized. Registry IP is %s", a)
def _updateRegistryIP(self):
logging.info("Asking registry its private IP...")
retry = 1
while True:
try:
a = self._registry.getPrivateAddress(self._prefix)
break
except socket.error, e:
logging.warning(e)
time.sleep(retry)
retry = min(60, retry * 2)
self._db.execute("INSERT OR REPLACE INTO config VALUES ('registry',?)",
(a,))
self.registry_ip = utils.binFromIp(a)
return a
def log(self):
if logging.getLogger().isEnabledFor(5):
logging.trace("Cache:")
......@@ -83,31 +91,41 @@ class PeerDB(object):
def getBootstrapPeer(self):
logging.info('Getting Boot peer...')
try:
bootpeer = self._proxy.getBootstrapPeer(self._prefix).data
except (socket.error, xmlrpclib.Fault), e:
bootpeer = self._registry.getBootstrapPeer(self._prefix)
prefix, address = utils.decrypt(self._key_path, bootpeer).split()
except (socket.error, subprocess.CalledProcessError, ValueError), e:
logging.warning('Failed to bootstrap (%s)', e)
else:
p = subprocess.Popen(('openssl', 'rsautl', '-decrypt', '-inkey', self._key_path),
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
bootpeer = p.communicate(bootpeer)[0].split()
if bootpeer[0] != self._prefix:
self.addPeer(*bootpeer)
return bootpeer
if prefix != self._prefix:
self.addPeer(prefix, address)
return prefix, address
logging.warning('Buggy registry sent us our own address')
def addPeer(self, prefix, address, force=False):
def addPeer(self, prefix, address, set_preferred=False):
logging.debug('Adding peer %s: %s', prefix, address)
with self._db:
q = self._db.execute
try:
(a,), = q("SELECT address FROM peer WHERE prefix=?", (prefix,))
a = a != address if force else \
set(a.split(';')) != set(address.split(';'))
if set_preferred:
preferred = address.split(';')
address = a
else:
preferred = a.split(';')
def key(a):
try:
return preferred.index(a)
except ValueError:
return len(preferred)
address = ';'.join(sorted(address.split(';'), key=key))
except ValueError:
q("DELETE FROM peer WHERE prefix IN (SELECT peer"
" FROM volatile.stat ORDER BY try, RANDOM() LIMIT ?,-1)",
(self._db_size,))
a = True
if a:
a = q("SELECT peer FROM volatile.stat ORDER BY try, RANDOM()"
" LIMIT ?,-1", (self._db_size,)).fetchall()
if a:
qq = self._db.executemany
qq("DELETE FROM peer WHERE prefix IN (?)", a)
qq("DELETE FROM volatile.stat WHERE peer IN (?)", a)
# 'a != address' will evaluate to True because types differs
if a != address:
q("INSERT OR REPLACE INTO peer VALUES (?,?)", (prefix, address))
q("INSERT OR REPLACE INTO volatile.stat VALUES (?,0)", (prefix,))
This diff is collapsed.
......@@ -41,8 +41,8 @@ class MultiGatewayManager(dict):
class Connection(object):
def __init__(self, address, iface, prefix):
self.address_list = list(utils.parse_address(address))
def __init__(self, address_list, iface, prefix):
self.address_list = address_list
self.iface = iface
self.routes = 0
self._prefix = prefix
......@@ -78,8 +78,7 @@ class Connection(object):
except TypeError:
i = len(self.address_list) - 1
if i:
db.addPeer(self._prefix, utils.dump_address(
self.address_list[i:] + self.address_list[:i]), True)
db.addPeer(self._prefix, ','.join(self.address_list[i]), True)
else:
db.connecting(self._prefix, 0)
......@@ -106,7 +105,7 @@ class TunnelManager(object):
def __init__(self, write_pipe, peer_db, openvpn_args, timeout,
refresh, client_count, iface_list, network, prefix,
address, ip_changed, encrypt, remote_gateway):
address, ip_changed, encrypt, remote_gateway, disable_proto):
self._write_pipe = write_pipe
self._peer_db = peer_db
self._connecting = set()
......@@ -125,6 +124,7 @@ class TunnelManager(object):
self._encrypt = encrypt
self._gateway_manager = MultiGatewayManager(remote_gateway) \
if remote_gateway else None
self._disable_proto = disable_proto
self._served = set()
self.sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
......@@ -216,6 +216,11 @@ class TunnelManager(object):
if prefix in self._served or prefix in self._connection_dict:
return False
assert prefix != self._prefix, self.__dict__
address = [x for x in utils.parse_address(address)
if x[2] not in self._disable_proto]
self._peer_db.connecting(prefix, 1)
if not address:
return False
logging.info('Establishing a connection with %u/%u',
int(prefix, 2), len(prefix))
iface = self.getFreeInterface(prefix)
......@@ -224,7 +229,6 @@ class TunnelManager(object):
for ip in c:
self._gateway_manager.add(ip, True)
c.open(self._write_pipe, self._timeout, self._encrypt, self._ovpn_args)
self._peer_db.connecting(prefix, 1)
return True
def _makeNewTunnels(self, route_counted):
......@@ -435,10 +439,13 @@ class TunnelManager(object):
return
code = ord(msg[0])
if code == 1: # answer
# TODO: do not fail if message contains garbage
# We parse the message in a way to discard a truncated line.
for peer in msg[1:].split('\n')[:-1]:
prefix, address = peer.split()
try:
prefix, address = peer.split()
int(prefix, 2)
except ValueError:
break
if prefix != self._prefix:
self._peer_db.addPeer(prefix, address)
try:
......
import argparse, errno, logging, os, shlex, signal, socket
import struct, subprocess, textwrap, threading, time
from OpenSSL import crypto
import argparse, calendar, errno, logging, os, shlex, signal, socket
import struct, subprocess, sys, textwrap, threading, time, traceback
logging_levels = logging.WARNING, logging.INFO, logging.DEBUG, 5
......@@ -45,6 +44,10 @@ def setupLog(log_level, filename=None, **kw):
logging.addLevelName(5, 'TRACE')
logging.trace = lambda *args, **kw: logging.log(5, *args, **kw)
def log_exception():
f = traceback.format_exception(*sys.exc_info())
logging.error('%s%s', f.pop(), ''.join(f))
class HelpFormatter(argparse.ArgumentDefaultsHelpFormatter):
......@@ -128,13 +131,14 @@ def ipFromBin(ip, suffix=''):
struct.pack('>QQ', int(ip[:64], 2), int(ip[64:], 2)))
def networkFromCa(ca):
ca = crypto.load_certificate(crypto.FILETYPE_PEM, ca)
return bin(ca.get_serial_number())[3:]
def subnetFromCert(cert):
cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
return cert.get_subject().CN
def notAfter(cert):
return calendar.timegm(time.strptime(cert.get_notAfter(),'%Y%m%d%H%M%SZ'))
def dump_address(address):
return ';'.join(map(','.join, address))
......@@ -150,3 +154,27 @@ def parse_address(address_list):
def binFromSubnet(subnet):
p, l = subnet.split('/')
return bin(int(p))[2:].rjust(int(l), '0')
def decrypt(key_path, data):
p = subprocess.Popen(
('openssl', 'rsautl', '-decrypt', '-inkey', key_path),
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
out, err = p.communicate(data)
if p.returncode:
raise subprocess.CalledProcessError(p.returncode, 'openssl', err)
return out
def encrypt(cert, data):
r, w = os.pipe()
try:
threading.Thread(target=os.write, args=(w, cert)).start()
p = subprocess.Popen(('openssl', 'rsautl', '-encrypt', '-certin',
'-inkey', '/proc/self/fd/%u' % r),
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
out, err = p.communicate(data)
finally:
os.close(r)
os.close(w)
if p.returncode:
raise subprocess.CalledProcessError(p.returncode, 'openssl', err)
return out
#!/usr/bin/python
import atexit, errno, logging, os, select, signal
import sqlite3, subprocess, sys, time, traceback
import sqlite3, subprocess, sys, time, threading
from collections import deque
from re6st import plib, utils, db, tunnel
from OpenSSL import crypto
from re6st import db, plib, tunnel, utils
from re6st.registry import RegistryClient, RENEW_PERIOD
class ReexecException(Exception):
pass
def getConfig():
parser = utils.ArgParser(fromfile_prefix_chars='@',
......@@ -61,12 +65,14 @@ def getConfig():
" hello interval for Babel to re-establish connection with a"
" node for which the direct connection has been cut.")
_('--table', type=int, default=42,
help="Use given table id. Set 0 to use the main table, if:\n"
"- you are a gateway of this network (the default route will be"
" exported)\n"
"- or you want to use the default route of this network for all"
" communications (in this case, make sure you don't already have"
" a default route).\n")
help="Use given table id. Set 0 to use the main table, if you want to"
" access internet via this network (in this case, make sure you"
" don't already have a default route). Don't use this option with"
" --gateway (main table is automatically used).")
_('--gateway', action='store_true',
help="Act as a gateway for this network (the default route will be"
" exported). Do never use it if you don't know what it means.")
_ = parser.add_argument_group('tunnelling').add_argument
_('-O', dest='openvpn_args', metavar='ARG', action='append', default=[],
help="Extra arguments to forward to both server and client OpenVPN"
......@@ -101,6 +107,8 @@ def getConfig():
_('--remote-gateway', action='append', dest='gw_list',
help="Force each tunnel to be created through one the given gateways,"
" in a round-robin fashion.")
_('--disable-proto', action='append', choices=('udp', 'tcp'), default=[],
help="Do never try to create tunnels using given protocols.")
_('--client', metavar='HOST,PORT,PROTO[;...]',
help="Do not run any OpenVPN server, but only 1 OpenVPN client,"
" with specified remotes. Any other option not required in this"
......@@ -108,14 +116,43 @@ def getConfig():
return parser.parse_args()
def maybe_renew(path, cert, info, renew):
while True:
next_renew = utils.notAfter(cert) - RENEW_PERIOD
if time.time() < next_renew:
return cert, next_renew
try:
pem = renew()
if not pem or pem == crypto.dump_certificate(
crypto.FILETYPE_PEM, cert):
exc_info = 0
break
cert = crypto.load_certificate(crypto.FILETYPE_PEM, pem)
except Exception:
exc_info = 1
break
new_path = path + '.new'
with open(new_path, 'w') as f:
f.write(pem)
os.rename(new_path, path)
logging.info("%s renewed until %s UTC",
info, time.asctime(time.gmtime(utils.notAfter(cert))))
logging.error("%s not renewed. Will retry tomorrow.",
info, exc_info=exc_info)
return cert, time.time() + 86400
def exit(status):
exit.status = status
os.kill(os.getpid(), signal.SIGTERM)
def main():
# Get arguments
config = getConfig()
with open(config.ca) as f:
network = utils.networkFromCa(f.read())
ca = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
with open(config.cert) as f:
prefix = utils.binFromSubnet(utils.subnetFromCert(f.read()))
cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
prefix = utils.binFromSubnet(utils.subnetFromCert(cert))
config.openvpn_args += (
'--ca', config.ca,
'--cert', config.cert,
......@@ -136,7 +173,16 @@ def main():
plib.ovpn_log = config.log
signal.signal(signal.SIGHUP, lambda *args: sys.exit(-1))
signal.signal(signal.SIGTERM, lambda *args: sys.exit())
signal.signal(signal.SIGTERM, lambda *args:
sys.exit(getattr(exit, 'status', None)))
registry = RegistryClient(config.registry, config.key, ca)
cert, next_renew = maybe_renew(config.cert, cert, "Certificate",
lambda: registry.renewCertificate(prefix))
ca, ca_renew = maybe_renew(config.ca, ca, "CA Certificate", registry.getCa)
if next_renew > ca_renew:
next_renew = ca_renew
network = utils.networkFromCa(ca)
if config.max_clients is None:
config.max_clients = config.client_count * 2
......@@ -220,21 +266,23 @@ def main():
# Init db and tunnels
tunnel_interfaces = server_tunnels.keys()
timeout = 4 * config.hello
cleanup = []
if config.client_count and not config.client:
required('registry')
# Create and open read_only pipe to get server events
r_pipe, write_pipe = os.pipe()
read_pipe = os.fdopen(r_pipe)
peer_db = db.PeerDB(db_path, config.registry, config.key, prefix)
peer_db = db.PeerDB(db_path, registry, config.key, network, prefix)
tunnel_manager = tunnel.TunnelManager(write_pipe, peer_db,
config.openvpn_args, timeout, config.tunnel_refresh,
config.client_count, config.iface_list, network, prefix,
address, ip_changed, config.encrypt, remote_gateway)
address, ip_changed, config.encrypt, remote_gateway,
config.disable_proto)
cleanup.append(tunnel_manager.sock.close)
tunnel_interfaces += tunnel_manager.new_iface_list
else:
tunnel_manager = write_pipe = None
cleanup = []
try:
# Source address selection is defined by RFC 6724, and in most
# applications, it usually works thanks to rule 5 (prefer outgoing
......@@ -277,7 +325,9 @@ def main():
cleanup.append(lambda: subprocess.call(if_rt))
x = [my_network]
if config.table:
if config.gateway:
config.table = 0
elif config.table:
x += 'table', str(config.table)
try:
ip('rule', 'from', *x)
......@@ -292,6 +342,26 @@ def main():
if_rt += x[1:]
call(if_rt[:3] + ['add', 'proto', 'static'] + if_rt[4:])
else:
def check_no_default_route():
try:
while True:
for route in call(('ip', '-6', 'route', 'show',
'default')).splitlines():
if ' proto 42 ' not in route:
logging.fatal("Detected default route (%s)"
" whereas you specified --table=0."
" Fix your configuration.", route)
return
time.sleep(60)
except:
utils.log_exception()
finally:
exit(1)
t = threading.Thread(target=check_no_default_route)
t.daemon = True
t.start()
# adding tap-windows driver will break others, so we add
# all drivers here
if sys.platform == 'cygwin':
......@@ -314,7 +384,8 @@ def main():
# main loop
if tunnel_manager is None:
sys.exit(os.WEXITSTATUS(os.wait()[1]))
time.sleep(max(0, next_renew - time.time()))
raise ReexecException("Restart to renew certificate")
cleanup += tunnel_manager.delInterfaces, tunnel_manager.killAll
while True:
next = tunnel_manager.next_refresh
......@@ -334,6 +405,8 @@ def main():
t = time.time()
if t >= tunnel_manager.next_refresh:
tunnel_manager.refresh()
if t >= next_renew:
raise ReexecException("Restart to renew certificate")
if forwarder and t >= forwarder.next_refresh:
forwarder.refresh()
finally:
......@@ -345,16 +418,17 @@ def main():
except sqlite3.Error:
logging.exception("Restarting with empty cache")
os.rename(db_path, db_path + '.bak')
try:
sys.exitfunc()
finally:
os.execvp(sys.argv[0], sys.argv)
except ReexecException, e:
logging.info(e)
except KeyboardInterrupt:
return 0
except Exception:
f = traceback.format_exception(*sys.exc_info())
logging.error('%s%s', f.pop(), ''.join(f))
utils.log_exception()
sys.exit(1)
try:
sys.exitfunc()
finally:
os.execvp(sys.argv[0], sys.argv)
if __name__ == "__main__":
main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment