Commit f8f4ffe4 authored by Jondy Zhao's avatar Jondy Zhao

Merge branch 'cygwin' of https://git.erp5.org/repos/re6stnet into cygwin

parents 32588808 cf991b97
...@@ -95,17 +95,19 @@ class PeerDB(object): ...@@ -95,17 +95,19 @@ class PeerDB(object):
return bootpeer return bootpeer
logging.warning('Buggy registry sent us our own address') 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) logging.debug('Adding peer %s: %s', prefix, address)
with self._db: with self._db:
q = self._db.execute q = self._db.execute
try: try:
(a,), = q("SELECT address FROM peer WHERE prefix=?", (prefix,)) (a,), = q("SELECT address FROM peer WHERE prefix=?", (prefix,))
a = a != address if force else \
set(a.split(';')) != set(address.split(';'))
except ValueError: except ValueError:
q("DELETE FROM peer WHERE prefix IN (SELECT peer" q("DELETE FROM peer WHERE prefix IN (SELECT peer"
" FROM volatile.stat ORDER BY try, RANDOM() LIMIT ?,-1)", " FROM volatile.stat ORDER BY try, RANDOM() LIMIT ?,-1)",
(self._db_size,)) (self._db_size,))
a = None a = True
if a != address: if a:
q("INSERT OR REPLACE INTO peer VALUES (?,?)", (prefix, address)) q("INSERT OR REPLACE INTO peer VALUES (?,?)", (prefix, address))
q("INSERT OR REPLACE INTO volatile.stat VALUES (?,0)", (prefix,)) q("INSERT OR REPLACE INTO volatile.stat VALUES (?,0)", (prefix,))
import logging, random, socket, subprocess, time import logging, random, socket, subprocess, sys, time
from collections import deque from collections import deque
from itertools import chain from itertools import chain
from . import plib, utils from . import plib, utils
...@@ -58,14 +58,30 @@ class Connection(object): ...@@ -58,14 +58,30 @@ class Connection(object):
self._remote_ip_set.add(ip) self._remote_ip_set.add(ip)
return iter(self._remote_ip_set) return iter(self._remote_ip_set)
def open(self, write_pipe, timeout, encrypt, ovpn_args): def open(self, write_pipe, timeout, encrypt, ovpn_args, _retry=0):
self.process = plib.client(self.iface, self.address_list, encrypt, self.process = plib.client(
self.iface, (self.address_list[_retry],), encrypt,
'--tls-remote', '%u/%u' % (int(self._prefix, 2), len(self._prefix)), '--tls-remote', '%u/%u' % (int(self._prefix, 2), len(self._prefix)),
'--resolv-retry', '0', '--resolv-retry', '0',
'--connect-retry-max', '3', '--tls-exit', '--connect-retry-max', '3', '--tls-exit',
'--ping-exit', str(timeout), '--ping-exit', str(timeout),
'--route-up', '%s %u' % (plib.ovpn_client, write_pipe), '--route-up', '%s %u' % (plib.ovpn_client, write_pipe),
*ovpn_args) *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): def close(self):
try: try:
...@@ -78,7 +94,11 @@ class Connection(object): ...@@ -78,7 +94,11 @@ class Connection(object):
if self.process.poll() != None: if self.process.poll() != None:
logging.info('Connection with %s has failed with return code %s', logging.info('Connection with %s has failed with return code %s',
self._prefix, self.process.returncode) 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 return True
...@@ -283,24 +303,30 @@ class TunnelManager(object): ...@@ -283,24 +303,30 @@ class TunnelManager(object):
if self._makeTunnel(*peer): if self._makeTunnel(*peer):
break break
def _get_win32_ipv6_route_table(self): if sys.platform == 'cygwin':
cmd = ['netsh', 'interface ipv6 show route verbose'] def _iterRoutes(self):
rttable = [] routing_table = subprocess.check_output(
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) ('netsh', 'interface', 'ipv6', 'show', 'route', 'verbose'),
s, _x = p.communicate() stderr=subprocess.OUTPUT)
if p.returncode != 0: for line in routing_table.splitlines():
return [] # Or raise exception? fs = line.split(':', 1)
for line in s.splitlines(): test = fs[0].startswith
fs = line.split(':', 1) if test('Prefix'):
if fs == []: prefix, prefix_len = fs[1].split('/', 1)
continue elif test('Interface'):
if fs[0].startswith('Prefix'): yield (fs[1].strip(),
prefix, prefix_len = fs[1].split('/', 1) utils.binFromIp(prefix),
elif fs[0].startswith('Interface'): int(prefix_len))
iface = fs[1].strip() else:
elif fs[0].startswith('Site Prefix Length'): def _iterRoutes(self):
rttable.append([utils.binFromIp(prefix), int(prefix_len), iface]) with open('/proc/net/ipv6_route') as f:
return rttable routing_table = f.read()
for line in routing_table.splitlines():
line = line.split()
iface = line[-1]
if iface != 'lo' and not (int(line[-2], 16) & RTF_CACHE):
yield (iface, bin(int(line[0], 16))[2:].rjust(128, '0'),
int(line[1], 16))
def _countRoutes(self): def _countRoutes(self):
logging.debug('Starting to count the routes on each interface...') logging.debug('Starting to count the routes on each interface...')
...@@ -310,38 +336,8 @@ class TunnelManager(object): ...@@ -310,38 +336,8 @@ class TunnelManager(object):
a = len(self._network) a = len(self._network)
b = a + len(self._prefix) b = a + len(self._prefix)
other = [] other = []
try: for iface, ip, prefix_len in self._iterRoutes():
with open('/proc/net/ipv6_route') as f: if ip[:a] == self._network and ip[a:b] != self._prefix:
self._last_routing_table = f.read()
for line in self._last_routing_table.splitlines():
line = line.split()
iface = line[-1]
if iface == 'lo' or int(line[-2], 16) & RTF_CACHE:
continue
ip = bin(int(line[0], 16))[2:].rjust(128, '0')
if ip[:a] != self._network or ip[a:b] == self._prefix:
continue
prefix_len = int(line[1], 16)
prefix = ip[a:prefix_len]
logging.trace('Route on iface %s detected to %s/%u',
iface, utils.ipFromBin(ip), prefix_len)
nexthop = self._iface_to_prefix.get(iface)
if nexthop:
self._connection_dict[nexthop].routes += 1
if prefix in self._served or prefix in self._connection_dict:
continue
if iface in self._iface_list:
other.append(prefix)
else:
self._distant_peers.append(prefix)
except IOError:
self._last_routing_table = self._get_win32_ipv6_route_table()
for rtline in self._last_routing_table:
iface = rtline[2]
ip = rtline[0]
if ip[:a] != self._network or ip[a:b] == self._prefix:
continue
prefix_len = rtline[1]
prefix = ip[a:prefix_len] prefix = ip[a:prefix_len]
logging.trace('Route on iface %s detected to %s/%u', logging.trace('Route on iface %s detected to %s/%u',
iface, utils.ipFromBin(ip), prefix_len) iface, utils.ipFromBin(ip), prefix_len)
...@@ -407,7 +403,11 @@ class TunnelManager(object): ...@@ -407,7 +403,11 @@ class TunnelManager(object):
self._gateway_manager.remove(trusted_ip) self._gateway_manager.remove(trusted_ip)
def _ovpn_route_up(self, common_name, 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: if self._ip_changed:
self._address = utils.dump_address(self._ip_changed(ip)) 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