Commit 620b9e98 authored by Julien Muchembled's avatar Julien Muchembled

Fix use of alternate addresses

When a peer advertised several addresses, a node trying to create a tunnel to
it never tried any other address than the first one.

Before, we wrongly assumed OpenVPN would try all addresses before aborting
(--ping-exit). New code reexecutes OpenVPN until all addresses are tried
and update the peer db to reorder addresses if the first one failed.
parent 94e8a309
......@@ -95,17 +95,19 @@ class PeerDB(object):
return bootpeer
logging.warning('Buggy registry sent us our own address')
def addPeer(self, prefix, address):
def addPeer(self, prefix, address, force=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(';'))
except ValueError:
q("DELETE FROM peer WHERE prefix IN (SELECT peer"
" FROM volatile.stat ORDER BY try, RANDOM() LIMIT ?,-1)",
(self._db_size,))
a = None
if a != address:
a = True
if a:
q("INSERT OR REPLACE INTO peer VALUES (?,?)", (prefix, address))
q("INSERT OR REPLACE INTO volatile.stat VALUES (?,0)", (prefix,))
......@@ -58,14 +58,30 @@ class Connection(object):
self._remote_ip_set.add(ip)
return iter(self._remote_ip_set)
def open(self, write_pipe, timeout, encrypt, ovpn_args):
self.process = plib.client(self.iface, self.address_list, encrypt,
def open(self, write_pipe, timeout, encrypt, ovpn_args, _retry=0):
self.process = plib.client(
self.iface, (self.address_list[_retry],), encrypt,
'--tls-remote', '%u/%u' % (int(self._prefix, 2), len(self._prefix)),
'--resolv-retry', '0',
'--connect-retry-max', '3', '--tls-exit',
'--ping-exit', str(timeout),
'--route-up', '%s %u' % (plib.ovpn_client, write_pipe),
*ovpn_args)
_retry += 1
self._retry = _retry < len(self.address_list) and (
write_pipe, timeout, encrypt, ovpn_args, _retry)
def connected(self, db):
try:
i = self._retry[-1] - 1
self._retry = None
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)
else:
db.connecting(self._prefix, 0)
def close(self):
try:
......@@ -78,7 +94,11 @@ class Connection(object):
if self.process.poll() != None:
logging.info('Connection with %s has failed with return code %s',
self._prefix, self.process.returncode)
return False
if not self._retry:
return False
logging.info('Retrying with alternate address')
self.close()
self.open(*self._retry)
return True
......@@ -367,7 +387,11 @@ class TunnelManager(object):
self._gateway_manager.remove(trusted_ip)
def _ovpn_route_up(self, common_name, ip):
self._peer_db.connecting(utils.binFromSubnet(common_name), 0)
prefix = utils.binFromSubnet(common_name)
try:
self._connection_dict[prefix].connected(self._peer_db)
except KeyError:
pass
if self._ip_changed:
self._address = utils.dump_address(self._ip_changed(ip))
......
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