Commit 6bb407b9 authored by Guillaume Bury's avatar Guillaume Bury

Changed database structure, introduced address to replace ip, port, proto tuples

parent bef61ec6
...@@ -3,13 +3,17 @@ import utils ...@@ -3,13 +3,17 @@ import utils
class PeerManager: class PeerManager:
def __init__(self, db_path, server, server_port, refresh_time, external_ip, internal_ip, port, proto, db_size): # internal ip = temp arg/attribute
def __init__(self, db_path, server, server_port, refresh_time, address, internal_ip, prefix, manual, db_size):
self._refresh_time = refresh_time self._refresh_time = refresh_time
self._external_ip = external_ip self._address = address
self._internal_ip = internal_ip self._internal_ip = internal_ip
self._external_port = port self._prefix = prefix
self._proto = proto self._server = server
self._server_port = server_port
self._db_size = db_size self._db_size = db_size
self._manual = manual
self._proxy = xmlrpclib.ServerProxy('http://%s:%u' % (server, server_port)) self._proxy = xmlrpclib.ServerProxy('http://%s:%u' % (server, server_port))
utils.log('Connectiong to peers database', 4) utils.log('Connectiong to peers database', 4)
...@@ -30,31 +34,30 @@ class PeerManager: ...@@ -30,31 +34,30 @@ class PeerManager:
self.next_refresh = time.time() + self._refresh_time self.next_refresh = time.time() + self._refresh_time
def _declare(self): def _declare(self):
if self._external_ip != None: if self._address != None:
utils.log('Sendin connection info to server', 3) utils.log('Sending connection info to server', 3)
self._proxy.declare((self._internal_ip, self._external_ip, self._external_port, self._proto)) self._proxy.declare((self._internal_ip, utils.address_list(self._address)))
else: else:
utils.log('Warning : could not send the external ip because it is unknown', 4) utils.log("Warning : couldn't advertise to server, external config not known", 4)
def _populate(self): def _populate(self):
utils.log('Populating the peers DB', 2) utils.log('Populating the peers DB', 2)
new_peer_list = self._proxy.getPeerList(self._db_size, self._internal_ip) new_peer_list = self._proxy.getPeerList(self._db_size, self._internal_ip)
self._db.executemany("INSERT OR IGNORE INTO peers (ip, port, proto, used) VALUES (?,?,?,0)", new_peer_list) self._db.executemany("INSERT OR IGNORE INTO peers (prefix, address) VALUES (?,?)", new_peer_list)
if self._external_ip != None: self._db.execute("DELETE FROM peers WHERE prefix = ?", (self._prefix,))
self._db.execute("DELETE FROM peers WHERE ip = ?", (self._external_ip,))
utils.log('New peers : %s' % ', '.join(map(str, new_peer_list)), 5) utils.log('New peers : %s' % ', '.join(map(str, new_peer_list)), 5)
def getUnusedPeers(self, peer_count): def getUnusedPeers(self, peer_count):
return self._db.execute("SELECT id, ip, port, proto FROM peers WHERE used = 0 " return self._db.execute("""SELECT prefix, address FROM peers WHERE used = 0
"ORDER BY RANDOM() LIMIT ?", (peer_count,)) ORDER BY RANDOM() LIMIT ?""", (peer_count,))
def usePeer(self, id): def usePeer(self, prefix):
utils.log('Updating peers database : using peer ' + str(id), 5) utils.log('Updating peers database : using peer ' + str(prefix), 5)
self._db.execute("UPDATE peers SET used = 1 WHERE id = ?", (id,)) self._db.execute("UPDATE peers SET used = 1 WHERE prefix = ?", (prefix,))
def unusePeer(self, id): def unusePeer(self, prefix):
utils.log('Updating peers database : unusing peer ' + str(id), 5) utils.log('Updating peers database : unusing peer ' + str(prefix), 5)
self._db.execute("UPDATE peers SET used = 0 WHERE id = ?", (id,)) self._db.execute("UPDATE peers SET used = 0 WHERE id = ?", (prefix,))
def handle_message(self, msg): def handle_message(self, msg):
script_type, arg = msg.split() script_type, arg = msg.split()
...@@ -63,9 +66,13 @@ class PeerManager: ...@@ -63,9 +66,13 @@ class PeerManager:
elif script_type == 'client-disconnect': elif script_type == 'client-disconnect':
utils.log('%s has disconnected' % (arg,), 3) utils.log('%s has disconnected' % (arg,), 3)
elif script_type == 'route-up': elif script_type == 'route-up':
if arg != self._external_ip: if not self._manual:
self._external_ip = arg external_ip, external_port = arg.split(',')
utils.log('External Ip : ' + arg, 3) new_address = [[external_ip, external_port, 'udp'],
self._declare() [external_ip, external_port, 'tcp-client']]
if self._address != new_address:
self._address = new_address
utils.log('Received new external configuration : %:%s' % (external_ip, external_port), 3)
self._declare()
else: else:
utils.log('Unknow message recieved from the openvpn pipe : ' + msg, 1) utils.log('Unknow message recieved from the openvpn pipe : ' + msg, 1)
...@@ -5,4 +5,4 @@ if os.environ['script_type'] == 'up': ...@@ -5,4 +5,4 @@ if os.environ['script_type'] == 'up':
os.execlp('ip', 'ip', 'link', 'set', os.environ['dev'], 'up') os.execlp('ip', 'ip', 'link', 'set', os.environ['dev'], 'up')
# Write into pipe external ip address received # Write into pipe external ip address received
os.write(int(sys.argv[1]), '%(script_type)s %(OPENVPN_external_ip)s\n' % os.environ) os.write(int(sys.argv[1]), '%(script_type)s %(OPENVPN_external_ip)s,%(OPENVPN_external_port)s\n' % os.environ)
...@@ -49,6 +49,8 @@ if script_type == 'client-connect': ...@@ -49,6 +49,8 @@ if script_type == 'client-connect':
with open(sys.argv[2], 'w') as f: with open(sys.argv[2], 'w') as f:
f.write('push "setenv-safe external_ip %s"\n' f.write('push "setenv-safe external_ip %s"\n'
% os.environ['trusted_ip']) % os.environ['trusted_ip'])
f.write('push "setenv-safe external_port %s"\n'
% os.environ['trusted_port'])
# Write into pipe connect/disconnect events # Write into pipe connect/disconnect events
os.write(int(sys.argv[1]), '%(script_type)s %(common_name)s\n' % os.environ) os.write(int(sys.argv[1]), '%(script_type)s %(common_name)s\n' % os.environ)
...@@ -17,8 +17,7 @@ def openvpn(hello_interval, *args, **kw): ...@@ -17,8 +17,7 @@ def openvpn(hello_interval, *args, **kw):
utils.log(str(args), 5) utils.log(str(args), 5)
return subprocess.Popen(args, **kw) return subprocess.Popen(args, **kw)
def server(server_ip, network, max_clients, dh_path, pipe_fd, port, proto, def server(server_ip, network, max_clients, dh_path, pipe_fd, port, proto, hello_interval, *args, **kw):
hello_interval, *args, **kw):
utils.log('Starting server', 3) utils.log('Starting server', 3)
return openvpn(hello_interval, return openvpn(hello_interval,
'--tls-server', '--tls-server',
...@@ -32,15 +31,16 @@ def server(server_ip, network, max_clients, dh_path, pipe_fd, port, proto, ...@@ -32,15 +31,16 @@ def server(server_ip, network, max_clients, dh_path, pipe_fd, port, proto,
'--proto', proto, '--proto', proto,
*args, **kw) *args, **kw)
def client(server_ip, pipe_fd, hello_interval, *args, **kw): def client(server_address, pipe_fd, hello_interval, *args, **kw):
utils.log('Starting client', 5) utils.log('Starting client', 5)
return openvpn(hello_interval, remote= ['--nobind',
'--nobind', '--client',
'--client', '--up', 'ovpn-client',
'--remote', server_ip, '--route-up', 'ovpn-client ' + str(pipe_fd) ]
'--up', 'ovpn-client', for ip, port, proto in utils.address_set(server_address):
'--route-up', 'ovpn-client ' + str(pipe_fd), remote += '--remote', ip, port, proto
*args, **kw) remote += args
return openvpn(hello_interval, *remote, **kw)
def router(network, internal_ip, interface_list, def router(network, internal_ip, interface_list,
wireless, hello_interval, **kw): wireless, hello_interval, **kw):
...@@ -69,11 +69,3 @@ def router(network, internal_ip, interface_list, ...@@ -69,11 +69,3 @@ def router(network, internal_ip, interface_list,
utils.log(str(args), 5) utils.log(str(args), 5)
return subprocess.Popen(args, **kw) return subprocess.Popen(args, **kw)
def watch(interface):
return ( subprocess.call(['ip6tables', '-I', 'INPUT', '-i', interface]) and
subprocess.call(['ip6tables', '-I', 'OUTPUT', '-o', interface]))
def unwatch(interface):
return ( subprocess.call(['ip6tables', '-D', 'INPUT', '-i', interface]) and
subprocess.call(['ip6tables', '-D', 'OUTPUT', '-o', interface]))
...@@ -52,9 +52,7 @@ class main(object): ...@@ -52,9 +52,7 @@ class main(object):
self.db = sqlite3.connect(self.config.db, isolation_level=None) self.db = sqlite3.connect(self.config.db, isolation_level=None)
self.db.execute("""CREATE TABLE IF NOT EXISTS peers ( self.db.execute("""CREATE TABLE IF NOT EXISTS peers (
prefix text primary key not null, prefix text primary key not null,
ip text not null, address text not null,
port integer not null,
proto text not null,
date integer default (strftime('%s','now')))""") date integer default (strftime('%s','now')))""")
self.db.execute("""CREATE TABLE IF NOT EXISTS tokens ( self.db.execute("""CREATE TABLE IF NOT EXISTS tokens (
token text primary key not null, token text primary key not null,
...@@ -62,22 +60,22 @@ class main(object): ...@@ -62,22 +60,22 @@ class main(object):
prefix_len integer not null, prefix_len integer not null,
date integer not null)""") date integer not null)""")
try: try:
self.db.execute("""CREATE TABLE vifib ( self.db.execute("""CREATE TABLE vpn (
prefix text primary key not null, prefix text primary key not null,
email text, email text,
cert text)""") cert text)""")
except sqlite3.OperationalError, e: except sqlite3.OperationalError, e:
if e.args[0] != 'table vifib already exists': if e.args[0] != 'table vpn already exists':
raise RuntimeError raise RuntimeError
else: else:
self.db.execute("INSERT INTO vifib VALUES ('',null,null)") self.db.execute("INSERT INTO vpn VALUES ('',null,null)")
# Loading certificates # Loading certificates
with open(self.config.ca) as f: with open(self.config.ca) as f:
self.ca = crypto.load_certificate(crypto.FILETYPE_PEM, f.read()) self.ca = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
with open(self.config.key) as f: with open(self.config.key) as f:
self.key = crypto.load_privatekey(crypto.FILETYPE_PEM, f.read()) self.key = crypto.load_privatekey(crypto.FILETYPE_PEM, f.read())
# Get vifib network prefix # Get vpn network prefix
self.network = bin(self.ca.get_serial_number())[3:] self.network = bin(self.ca.get_serial_number())[3:]
print "Network prefix : %s/%u" % (self.network, len(self.network)) print "Network prefix : %s/%u" % (self.network, len(self.network))
...@@ -121,12 +119,12 @@ class main(object): ...@@ -121,12 +119,12 @@ class main(object):
def _getPrefix(self, prefix_len): def _getPrefix(self, prefix_len):
assert 0 < prefix_len <= 128 - len(self.network) assert 0 < prefix_len <= 128 - len(self.network)
for prefix, in self.db.execute("""SELECT prefix FROM vifib WHERE length(prefix) <= ? AND cert is null for prefix, in self.db.execute("""SELECT prefix FROM vpn WHERE length(prefix) <= ? AND cert is null
ORDER BY length(prefix) DESC""", (prefix_len,)): ORDER BY length(prefix) DESC""", (prefix_len,)):
while len(prefix) < prefix_len: while len(prefix) < prefix_len:
self.db.execute("UPDATE vifib SET prefix = ? WHERE prefix = ?", (prefix + '1', prefix)) self.db.execute("UPDATE vpn SET prefix = ? WHERE prefix = ?", (prefix + '1', prefix))
prefix += '0' prefix += '0'
self.db.execute("INSERT INTO vifib VALUES (?,null,null)", (prefix,)) self.db.execute("INSERT INTO vpn VALUES (?,null,null)", (prefix,))
return prefix return prefix
raise RuntimeError # TODO: raise better exception raise RuntimeError # TODO: raise better exception
...@@ -158,7 +156,7 @@ class main(object): ...@@ -158,7 +156,7 @@ class main(object):
cert = crypto.dump_certificate(crypto.FILETYPE_PEM, cert) cert = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
# Insert certificate into db # Insert certificate into db
self.db.execute("UPDATE vifib SET email = ?, cert = ? WHERE prefix = ?", (email, cert, prefix) ) self.db.execute("UPDATE vpn SET email = ?, cert = ? WHERE prefix = ?", (email, cert, prefix) )
return cert return cert
except: except:
...@@ -172,19 +170,19 @@ class main(object): ...@@ -172,19 +170,19 @@ class main(object):
# TODO: Insert a flag column for bootstrap ready servers in peers # TODO: Insert a flag column for bootstrap ready servers in peers
# ( servers which shouldn't go down or change ip and port as opposed to servers owned by particulars ) # ( servers which shouldn't go down or change ip and port as opposed to servers owned by particulars )
# that way, we also ascertain that the server sent is not the new node.... # that way, we also ascertain that the server sent is not the new node....
ip, port, proto = self.db.execute("SELECT ip, port, proto FROM peers ORDER BY random() LIMIT 1").next() prefix, address = self.db.execute("SELECT prefix, address FROM peers ORDER BY random() LIMIT 1").next()
print "Sending bootstrap peer ( %s, %s, %s)" % (ip, port, proto) print "Sending bootstrap peer (%s, %s)" % (prefix, str(address))
return ip, port, proto return prefix, address
def declare(self, handler, address): def declare(self, handler, address):
print "declaring new node" print "declaring new node"
client_address, ip, port, proto = address client_address, address = address
#client_address, _ = handler.client_address #client_address, _ = handler.client_address
client_ip = utils.binFromIp(client_address) client_ip = utils.binFromIp(client_address)
if client_ip.startswith(self.network): if client_ip.startswith(self.network):
prefix = client_ip[len(self.network):] prefix = client_ip[len(self.network):]
prefix, = self.db.execute("SELECT prefix FROM vifib WHERE prefix <= ? ORDER BY prefix DESC LIMIT 1", (prefix,)).next() prefix, = self.db.execute("SELECT prefix FROM vpn WHERE prefix <= ? ORDER BY prefix DESC LIMIT 1", (prefix,)).next()
self.db.execute("INSERT OR REPLACE INTO peers (prefix, ip, port, proto) VALUES (?,?,?,?)", (prefix, ip, port, proto)) self.db.execute("INSERT OR REPLACE INTO peers (prefix, address) VALUES (?,?)", (prefix, address))
return True return True
else: else:
# TODO: use log + DO NOT PRINT BINARY IP # TODO: use log + DO NOT PRINT BINARY IP
...@@ -196,7 +194,7 @@ class main(object): ...@@ -196,7 +194,7 @@ class main(object):
client_ip = utils.binFromIp(client_address) client_ip = utils.binFromIp(client_address)
if client_ip.startswith(self.network): if client_ip.startswith(self.network):
print "sending peers" print "sending peers"
return self.db.execute("SELECT ip, port, proto FROM peers ORDER BY random() LIMIT ?", (n,)).fetchall() return self.db.execute("SELECT prefix, address FROM peers ORDER BY random() LIMIT ?", (n,)).fetchall()
else: else:
# TODO: use log + DO NOT PRINT BINARY IP # TODO: use log + DO NOT PRINT BINARY IP
print "Unauthorized connection from %s which does not start with %s" % (client_ip, self.network) print "Unauthorized connection from %s which does not start with %s" % (client_ip, self.network)
......
...@@ -18,13 +18,9 @@ def main(): ...@@ -18,13 +18,9 @@ def main():
help='Port to which connect on the server') help='Port to which connect on the server')
_('-d', '--dir', default='/etc/vifib', _('-d', '--dir', default='/etc/vifib',
help='Directory where the key and certificate will be stored') help='Directory where the key and certificate will be stored')
_('-r', '--req', nargs='+', _('-r', '--req', nargs=2, action='append',
help='''Certificate request additional arguments. For example : help='Name and value of certificate request additional arguments')
--req name1 value1 name2 value2, to add attributes name1 and name2''')
config = parser.parse_args() config = parser.parse_args()
if config.req and len(config.req) % 2 == 1:
print "Sorry, request argument was incorrect, there must be an even number of request arguments"
sys.exit(1)
# Establish connection with server # Establish connection with server
s = xmlrpclib.ServerProxy('http://%s:%u' % (config.server, config.port)) s = xmlrpclib.ServerProxy('http://%s:%u' % (config.server, config.port))
...@@ -41,17 +37,14 @@ def main(): ...@@ -41,17 +37,14 @@ def main():
db = sqlite3.connect(os.path.join(config.dir, 'peers.db'), isolation_level=None) db = sqlite3.connect(os.path.join(config.dir, 'peers.db'), isolation_level=None)
try: try:
db.execute("""CREATE TABLE peers ( db.execute("""CREATE TABLE peers (
id INTEGER PRIMARY KEY AUTOINCREMENT, prefix TEXT PRIMARY KEY,
ip TEXT NOT NULL, address TEXT NOT NULL,
port INTEGER NOT NULL, used INTEGER NOT NULL DEFAULT 0,
proto TEXT NOT NULL,
used INTEGER NOT NULL default 0,
date INTEGER DEFAULT (strftime('%s', 'now')))""") date INTEGER DEFAULT (strftime('%s', 'now')))""")
db.execute("CREATE INDEX _peers_used ON peers(used)") db.execute("CREATE INDEX _peers_used ON peers(used)")
db.execute("CREATE UNIQUE INDEX _peers_address ON peers(ip, port, proto)")
if not config.no_boot: if not config.no_boot:
boot_ip, boot_port, boot_proto = s.getBootstrapPeer() prefix, address = s.getBootstrapPeer()
db.execute("INSERT INTO peers (ip, port, proto) VALUES (?,?,?)", (boot_ip, boot_port, boot_proto)) db.execute("INSERT INTO peers (prefix, address) VALUES (?,?)", (prefix, address))
except sqlite3.OperationalError, e: except sqlite3.OperationalError, e:
if e.args[0] == 'table peers already exists': if e.args[0] == 'table peers already exists':
print "Table peers already exists, leaving it as it is" print "Table peers already exists, leaving it as it is"
...@@ -75,10 +68,8 @@ def main(): ...@@ -75,10 +68,8 @@ def main():
req = crypto.X509Req() req = crypto.X509Req()
subj = req.get_subject() subj = req.get_subject()
if config.req: if config.req:
while len(config.req) > 1: for arg in config.req:
key = config.req.pop(0) setattr(subj, arg[0], arg[1])
value = config.req.pop(0)
setattr(subj, key, value)
req.set_pubkey(pkey) req.set_pubkey(pkey)
req.sign(pkey, 'sha1') req.sign(pkey, 'sha1')
req = crypto.dump_certificate_request(crypto.FILETYPE_PEM, req) req = crypto.dump_certificate_request(crypto.FILETYPE_PEM, req)
......
...@@ -5,24 +5,24 @@ log = None ...@@ -5,24 +5,24 @@ log = None
smooth = 0.3 smooth = 0.3
class Connection: class Connection:
def __init__(self, ip, write_pipe, hello, port, proto, iface, peer_id, def __init__(self, address, write_pipe, hello, iface, prefix,
ovpn_args): ovpn_args):
self.process = plib.client(ip, write_pipe, hello, self.process = plib.client(address, write_pipe, hello,
'--dev', iface, '--proto', proto, '--rport', str(port), '--dev', iface, '--proto', proto, '--rport', str(port),
*ovpn_args, stdout=os.open(os.path.join(log, *ovpn_args, stdout=os.open(os.path.join(log,
'vifibnet.client.%s.log' % (peer_id,)), 'vifibnet.client.%s.log' % (prefix,)),
os.O_WRONLY|os.O_CREAT|os.O_TRUNC) ) os.O_WRONLY|os.O_CREAT|os.O_TRUNC) )
self.iface = iface self.iface = iface
self._lastTrafic = self._getTrafic() self._lastTrafic = self._getTrafic()
self._bandwidth = None self._bandwidth = None
# TODO : update the stats # TODO : update the stats
def refresh(self): def refresh(self):
# Check that the connection is alive # Check that the connection is alive
if self.process.poll() != None: if self.process.poll() != None:
utils.log('Connection with %s has failed with return code %s' utils.log('Connection with %s has failed with return code %s'
% (id, self.process.returncode), 3) % (prefix, self.process.returncode), 3)
return False return False
trafic = self._getTrafic() trafic = self._getTrafic()
...@@ -45,7 +45,7 @@ class Connection: ...@@ -45,7 +45,7 @@ class Connection:
class TunnelManager: class TunnelManager:
def __init__(self, write_pipe, peer_db, openvpn_args, hello_interval, def __init__(self, write_pipe, peer_db, openvpn_args, hello_interval,
refresh, connection_count, refresh_rate): refresh, connection_count, refresh_rate):
self._write_pipe = write_pipe self._write_pipe = write_pipe
self._peer_db = peer_db self._peer_db = peer_db
...@@ -53,9 +53,9 @@ class TunnelManager: ...@@ -53,9 +53,9 @@ class TunnelManager:
self._ovpn_args = openvpn_args self._ovpn_args = openvpn_args
self._hello = hello_interval self._hello = hello_interval
self._refresh_time = refresh self._refresh_time = refresh
self.free_interface_set = set(('client1', 'client2', 'client3', self.free_interface_set = set(('client1', 'client2', 'client3',
'client4', 'client5', 'client6', 'client4', 'client5', 'client6',
'client7', 'client8', 'client9', 'client7', 'client8', 'client9',
'client10', 'client11', 'client12')) 'client10', 'client11', 'client12'))
self.next_refresh = time.time() self.next_refresh = time.time()
...@@ -70,42 +70,41 @@ class TunnelManager: ...@@ -70,42 +70,41 @@ class TunnelManager:
self.next_refresh = time.time() + self._refresh_time self.next_refresh = time.time() + self._refresh_time
def _cleanDeads(self): def _cleanDeads(self):
for id in self._connection_dict.keys(): for prefix in self._connection_dict.keys():
if not self._connection_dict[id].refresh(): if not self._connection_dict[prefix].refresh():
self._kill(id) self._kill(prefix)
def _removeSomeTunnels(self): def _removeSomeTunnels(self):
for i in range(0, max(0, len(self._connection_dict) - for i in range(0, max(0, len(self._connection_dict) -
self._client_count + self._refresh_count)): self._client_count + self._refresh_count)):
peer_id = random.choice(self._connection_dict.keys()) prefix = random.choice(self._connection_dict.keys())
self._kill(peer_id) self._kill(prefix)
def _kill(self, peer_id): def _kill(self, prefix):
utils.log('Killing the connection with id ' + str(peer_id), 2) utils.log('Killing the connection with ' + prefix, 2)
connection = self._connection_dict.pop(peer_id) connection = self._connection_dict.pop(prefix)
try: try:
connection.process.kill() connection.process.kill()
except OSError: except OSError:
# If the process is already exited # If the process is already exited
pass pass
self.free_interface_set.add(connection.iface) self.free_interface_set.add(connection.iface)
self._peer_db.unusePeer(peer_id) self._peer_db.unusePeer(prefix)
def _makeNewTunnels(self): def _makeNewTunnels(self):
utils.log('Trying to make %i new tunnels' % utils.log('Trying to make %i new tunnels' %
(self._client_count - len(self._connection_dict)), 3) (self._client_count - len(self._connection_dict)), 5)
try: try:
for peer_id, ip, port, proto in self._peer_db.getUnusedPeers( for prefix, address in self._peer_db.getUnusedPeers(
self._client_count - len(self._connection_dict)): self._client_count - len(self._connection_dict)):
utils.log('Establishing a connection with id %s (%s:%s)' utils.log('Establishing a connection with %s (%s:%s)' % prefix, 2)
% (peer_id, ip, port), 2)
iface = self.free_interface_set.pop() iface = self.free_interface_set.pop()
self._connection_dict[peer_id] = Connection(ip, self._connection_dict[prefix] = Connection(address,
self._write_pipe, self._hello, port, proto, iface, self._write_pipe, self._hello, iface,
peer_id, self._ovpn_args) prefix, self._ovpn_args)
self._peer_db.usePeer(peer_id) self._peer_db.usePeer(prefix)
except KeyError: except KeyError:
utils.log("Can't establish connection with %s" utils.log("""Can't establish connection with %s
": no available interface" % ip, 2) : no available interface""" % prefix, 2)
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
...@@ -21,7 +21,7 @@ def ipFromBin(prefix): ...@@ -21,7 +21,7 @@ def ipFromBin(prefix):
def ipFromPrefix(vifibnet, prefix, prefix_len): def ipFromPrefix(vifibnet, prefix, prefix_len):
prefix = bin(int(prefix))[2:].rjust(prefix_len, '0') prefix = bin(int(prefix))[2:].rjust(prefix_len, '0')
ip_t = (vifibnet + prefix).ljust(128, '0') ip_t = (vifibnet + prefix).ljust(128, '0')
return ipFromBin(ip_t) return ipFromBin(ip_t), prefix
def networkFromCa(ca_path): def networkFromCa(ca_path):
# Get network prefix from ca.crt # Get network prefix from ca.crt
...@@ -37,13 +37,9 @@ def ipFromCert(network, cert_path): ...@@ -37,13 +37,9 @@ def ipFromCert(network, cert_path):
prefix, prefix_len = subject.CN.split('/') prefix, prefix_len = subject.CN.split('/')
return ipFromPrefix(network, prefix, int(prefix_len)) return ipFromPrefix(network, prefix, int(prefix_len))
def ovpnArgs(optional_args, ca_path, cert_path): def address_list(address_set):
# Treat openvpn arguments return ';'.join(map(','.join, address_set))
if optional_args[0] == "--":
del optional_args[0]
optional_args.append('--ca')
optional_args.append(ca_path)
optional_args.append('--cert')
optional_args.append(cert_path)
return optional_args
def address_set(address_list):
return set(tuple(address.split(','))
for address in address_list.split(';'))
#!/usr/bin/env python #!/usr/bin/env python
import argparse, errno, math, os, select, subprocess, sys, time, traceback, upnpigd import argparse, errno, math, os, select, subprocess, sys, time, traceback
from argparse import ArgumentParser
from OpenSSL import crypto from OpenSSL import crypto
import db, plib, upnpigd, utils, tunnel import db, plib, upnpigd, utils, tunnel
def ArgParser(ArgumentParser):
def convert_arg_line_to_args(self, arg_line):
for arg in ('--' + arg_line.strip()).split():
if arg.strip():
yield arg
def ovpnArgs(optional_args, ca_path, cert_path):
# Treat openvpn arguments
if optional_args[0] == "--":
del optional_args[0]
optional_args.append('--ca')
optional_args.append(ca_path)
optional_args.append('--cert')
optional_args.append(cert_path)
return optional_args
def getConfig(): def getConfig():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='Resilient virtual private network application') description='Resilient virtual private network application')
_ = parser.add_argument _ = parser.add_argument
# Server address SHOULD be a vifib address ( else requests will be denied ) # Server address SHOULD be a vifib address ( else requests will be denied )
_('--server', required=True, _('--server', required=True,
help='Address for peer discovery server') help="VPN address of the discovery peer server")
_('--server-port', required=True, type=int, _('--server-port', required=True, type=int,
help='Peer discovery server port') help="VPN port of the discovery peer server")
_('-log', '-l', default='/var/log', _('-log', '-l', default='/var/log',
help='Path to vifibnet logs directory') help='Path to vifibnet logs directory')
_('--tunnel-refresh', default=300, type=int, _('--tunnel-refresh', default=300, type=int,
...@@ -34,15 +52,15 @@ def getConfig(): ...@@ -34,15 +52,15 @@ def getConfig():
help='Path to the certificate authority file') help='Path to the certificate authority file')
_('--cert', required=True, _('--cert', required=True,
help='Path to the certificate file') help='Path to the certificate file')
_('--ip', default=None, dest='external_ip', ipconfig = parser.add_mutually_exclusive_group()
help='Ip address of the machine on the internet') __ = ipconfig.add_argument
_('--internal-port', default=1194, __('--ip', default=None, dest='address', action='append', nargs=3,
help='The internal port to listen on for incomming connections') help='Ip address, port and protocol advertised to other vpn nodes')
_('--external-port', default=1194, __('--internal-port', default=1194,
help='The external port to advertise for other peers to connect') help='Internal port to listen on for incomming connections')
_('--proto', default='udp',
help='The protocol to use for the others peers to connect')
# args to be removed ? # args to be removed ?
_('--proto', default='udp',
help='The protocol used by other peers to connect')
_('--connection-count', default=30, type=int, _('--connection-count', default=30, type=int,
help='Number of client connections') help='Number of client connections')
_('--refresh-rate', default=0.05, type=float, _('--refresh-rate', default=0.05, type=float,
...@@ -55,9 +73,10 @@ def getConfig(): ...@@ -55,9 +73,10 @@ def getConfig():
def main(): def main():
# Get arguments # Get arguments
config = getConfig() config = getConfig()
manual = bool(config.address)
network = utils.networkFromCa(config.ca) network = utils.networkFromCa(config.ca)
internal_ip = utils.ipFromCert(network, config.cert) internal_ip, prefix = utils.ipFromCert(network, config.cert)
openvpn_args = utils.ovpnArgs(config.openvpn_args, config.ca, config.cert) openvpn_args = ovpnArgs(config.openvpn_args, config.ca, config.cert)
# Set global variables # Set global variables
tunnel.log = config.log tunnel.log = config.log
...@@ -69,14 +88,20 @@ def main(): ...@@ -69,14 +88,20 @@ def main():
read_pipe = os.fdopen(r_pipe) read_pipe = os.fdopen(r_pipe)
# Init db and tunnels # Init db and tunnels
if config.external_ip == None: if manual:
utils.log('Manual external configuration', 3)
else:
utils.log('Attempting automatic configuration via UPnP', 3)
try: try:
config.external_ip, config.external_port = upnpigd.ForwardViaUPnP(config.internal_port) external_ip, external_port = upnpigd.ForwardViaUPnP(config.internal_port)
config.address = [[external_ip, external_port, 'udp'],
[external_ip, external_port, 'tcp-client']]
except Exception: except Exception:
utils.log('An atempt to forward a port via UPnP failed', 5) utils.log('An atempt to forward a port via UPnP failed', 3)
raise RuntimeError
peer_db = db.PeerManager(config.db, config.server, config.server_port, config.peers_db_refresh, peer_db = db.PeerManager(config.db, config.server, config.server_port,
config.external_ip, internal_ip, config.external_port, config.proto, 200) config.peers_db_refresh, config.address, internal_ip, prefix, manual, 200)
tunnel_manager = tunnel.TunnelManager(write_pipe, peer_db, openvpn_args, config.hello, tunnel_manager = tunnel.TunnelManager(write_pipe, peer_db, openvpn_args, config.hello,
config.tunnel_refresh, config.connection_count, config.refresh_rate) config.tunnel_refresh, config.connection_count, config.refresh_rate)
...@@ -84,7 +109,7 @@ def main(): ...@@ -84,7 +109,7 @@ def main():
interface_list = ['vifibnet'] + list(tunnel_manager.free_interface_set) interface_list = ['vifibnet'] + list(tunnel_manager.free_interface_set)
router = plib.router(network, internal_ip, interface_list, config.wireless, config.hello, router = plib.router(network, internal_ip, interface_list, config.wireless, config.hello,
stdout=os.open(os.path.join(config.log, 'vifibnet.babeld.log'), stdout=os.open(os.path.join(config.log, 'vifibnet.babeld.log'),
os.O_WRONLY | os.O_CREAT | os.O_TRUNC), stderr=subprocess.STDOUT) os.O_WRONLY | os.O_CREAT | os.O_TRUNC), stderr=subprocess.STDOUT)
# Establish connections # Establish connections
server_process = plib.server(internal_ip, network, config.connection_count, config.dh, write_pipe, server_process = plib.server(internal_ip, network, config.connection_count, config.dh, write_pipe,
......
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