Commit 6a8fa1f1 authored by Ulysse Beaugnon's avatar Ulysse Beaugnon

DB and tunnel now have a separate refresh timer

Changes in the number of connection per peers
parent 4369892b
vifibnet is a daemon setting up a resilient virtual private network over the internet Vsifibnet is a daemon setting up a resilient virtual private network over the internet
The organisation of the code
vifibnet.py Just contain the main loop and the init
plib.py To launch server/client/routing processes
utils.py Small functions to do some usefull job
db.py Function to manage peers
tunnel.py To choose wich connection delete/keep/...
upnpigd.py To open a port
\ No newline at end of file
...@@ -9,25 +9,24 @@ To be done : ...@@ -9,25 +9,24 @@ To be done :
Replace comments at the beginning of functions with docstrings & give all fn docstrings Replace comments at the beginning of functions with docstrings & give all fn docstrings
Do a clean-up in the import Do a clean-up in the import
Remove the parameters to choose the number of clients Remove the parameters to choose the number of clients
Use the server events ( client connection/deconnection ) to do something useful Use the server events ( client connection/deconnection ) to do something usefull
In peers DB, remove some peers when they are too many of them
Contact the server using vifibnet and not the underlying network when possible
To be discuss: To be discuss:
Remove the --no-boot option since we know when no node is avalaible U : Remove the --no-boot option since we know when no node is avalaible
\=> the no-boot option is only useful when the server knows no peer, G : the no-boot option is only useful when the server knows no peer,
irl it should never happen, no-boot is a debug option irl it should never happen, no-boot is a debug option
U : Ok, but the server knows when no peers is avalaible, doesn't he ?
The organisation of the code
vifibnet.py Just contain the main loop and the init
plib.py To launch server/client/routing processes
utils.py Small functions to do some usefull job
db.py Function to manage peers
tunnelmanager.py To choose wich connection delete/keep/...
upnpigd.py To open a port and find the external IP
How we choose which protocol we use : How we choose which protocol we use :
IMO, we should use UDP. I've read many times than TCP other TCP can be catastrophic in terme of performance IMO, we should use UDP. I've read many times than TCP other TCP can be catastrophic in terme of performance
Every time a packet is lost, it is resend 2 times, one for each TCP tunnel Every time a packet is lost, it is resend 2 times, one for each TCP tunnel
And many GW allow UDP port forwarding (for bittorent, Xbox, ...) but not TCP port forwarding And many GW allow UDP port forwarding (for bittorent, Xbox, ...) but not TCP port forwarding
Use peers_db.populate(100) every once in a while ? -> yes but be warry of the refresh time ( populate Use peers_db.populate(100) every once in a while ?
the db once every 20s is bad.. ) G : yes but be warry of the refresh time ( populate the db once every 20s is bad.. )
U : I agree. Once evry hours should be sufficient, and when their too few peers avalaible.
G : don't reconnect to server each time we repopulate in peers_db ?
U : we might recontact the server evry 1H or even less. So i think it is a good thing not to keep the connection alive
#!/usr/bin/env python #!/usr/bin/env python
import sqlite3, xmlrpclib import sqlite3, xmlrpclib, time
import utils import utils
class PeerManager: class PeerManager:
def __init__(self, dbPath, server, port): def __init__(self, dbPath, server, port, refresh_time):
utils.log('Connectiong to peers database', 4) utils.log('Connectiong to peers database', 4)
self._db = sqlite3.connect(dbPath, isolation_level=None) self._db = sqlite3.connect(dbPath, isolation_level=None)
self._server = server self._server = server
self._port = port self._port = port
self._refresh_time = refresh_time
utils.log('Preparing peers database', 4) utils.log('Preparing peers database', 4)
try: try:
self._db.execute("UPDATE peers SET used = 0") self._db.execute("UPDATE peers SET used = 0")
except sqlite3.OperationalError, e: except sqlite3.OperationalError, e:
if e.args[0] == 'no such table: peers': if e.args[0] == 'no such table: peers':
raise RuntimeError raise RuntimeError
self.next_refresh = time.time()
def populate(self, n, address): def populate(self, n, address):
# address = (internal_ip, external_ip, port, proto) # address = (internal_ip, external_ip, port, proto)
# TODO: don't reconnect to server each time ?
utils.log('Connecting to remote server', 3) utils.log('Connecting to remote server', 3)
self._proxy = xmlrpclib.ServerProxy('http://%s:%u' % (self._server, self._port)) self._proxy = xmlrpclib.ServerProxy('http://%s:%u' % (self._server, self._port))
utils.log('Updating peers database : populating', 2) utils.log('Updating peers database : populating', 2)
_, external_ip, _, _ = address _, external_ip, _, _ = address
new_peer_list = self._proxy.getPeerList(n, address) new_peer_list = self._proxy.getPeerList(n, address)
utils.log('New peers recieved from %s' % self._server, 5)
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 (ip, port, proto, used) VALUES (?,?,?,0)", new_peer_list)
self._db.execute("DELETE FROM peers WHERE ip = ?", (external_ip,)) self._db.execute("DELETE FROM peers WHERE ip = ?", (external_ip,))
self.next_refresh = time.time() + self._refresh_time
utils.log('New peers : %s' % ', '.join(map(str, new_peer_list)), 5)
def getUnusedPeers(self, nPeers): def getUnusedPeers(self, nPeers):
return self._db.execute("SELECT id, ip, port, proto FROM peers WHERE used = 0 " return self._db.execute("SELECT id, ip, port, proto FROM peers WHERE used = 0 "
......
#!/usr/bin/env python #!/usr/bin/env python
import os, random, traceback import os, random, traceback, time
import plib, utils, db import plib, utils, db
log = None log = None
class TunnelManager: class TunnelManager:
def __init__(self, write_pipe, peer_db, client_count, refresh_count, openvpn_args): def __init__(self, write_pipe, peer_db, openvpn_args, 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
self._connection_dict = {} self._connection_dict = {}
self._client_count = client_count
self._refresh_count = refresh_count
self._ovpn_args = openvpn_args self._ovpn_args = openvpn_args
self._refresh_time = refresh
self.free_interface_set = set(('client1', 'client2', 'client3', 'client4', 'client5', self.free_interface_set = set(('client1', 'client2', 'client3', 'client4', 'client5',
'client6', 'client7', 'client8', 'client9', 'client10')) 'client6', 'client7', 'client8', 'client9', 'client10'))
self.next_refresh = time.time()
# TODO : choose this automatically
self._client_count = connection_count/2
self._refresh_count = refresh_rate*self._client_count
def refresh(self): def refresh(self):
utils.log('Refreshing the tunnels', 2)
self._cleanDeads() self._cleanDeads()
self._removeSomeTunnels() self._removeSomeTunnels()
self._makeNewTunnels() self._makeNewTunnels()
self.next_refresh = time.time() + self._refresh_time
def _cleanDeads(self): def _cleanDeads(self):
for id in self._connection_dict.keys(): for id in self._connection_dict.keys():
...@@ -43,6 +49,7 @@ class TunnelManager: ...@@ -43,6 +49,7 @@ class TunnelManager:
self._peer_db.unusePeer(peer_id) self._peer_db.unusePeer(peer_id)
def _makeNewTunnels(self): def _makeNewTunnels(self):
utils.log('Making %i new tunnels' % (self._client_count - len(self._connection_dict)), 3)
try: try:
for peer_id, ip, port, proto in self._peer_db.getUnusedPeers(self._client_count - len(self._connection_dict)): for peer_id, ip, port, proto in self._peer_db.getUnusedPeers(self._client_count - len(self._connection_dict)):
utils.log('Establishing a connection with id %s (%s:%s)' % (peer_id, ip, port), 2) utils.log('Establishing a connection with id %s (%s:%s)' % (peer_id, ip, port), 2)
......
...@@ -14,15 +14,10 @@ def getConfig(): ...@@ -14,15 +14,10 @@ def getConfig():
help='Peer discovery server port') help='Peer discovery server port')
_('-l', '--log', default='/var/log', _('-l', '--log', default='/var/log',
help='Path to vifibnet logs directory') help='Path to vifibnet logs directory')
_('--client-count', default=2, type=int, _('--tunnel-refresh', default=300, type=int,
help='Number of client connections')
# TODO: use maxpeer
_('--max-clients', default=10, type=int,
help='the number of peers that can connect to the server')
_('--refresh-time', default=300, type=int,
help='the time (seconds) to wait before changing the connections') help='the time (seconds) to wait before changing the connections')
_('--refresh-count', default=1, type=int, _('--peers-db-refresh', default=3600, type=int,
help='The number of connections to drop when refreshing the connections') help='the time (seconds) to wait before refreshing the peers db')
_('--db', default='/var/lib/vifibnet/peers.db', _('--db', default='/var/lib/vifibnet/peers.db',
help='Path to peers database') help='Path to peers database')
_('--dh', required=True, _('--dh', required=True,
...@@ -37,6 +32,11 @@ def getConfig(): ...@@ -37,6 +32,11 @@ def getConfig():
help='Path to the certificate file') help='Path to the certificate file')
_('--ip', required=True, dest='external_ip', _('--ip', required=True, dest='external_ip',
help='Ip address of the machine on the internet') help='Ip address of the machine on the internet')
# args to be removed ?
_('--connection-count', default=30, type=int,
help='Number of client connections')
_('--refresh-rate', default=0.05, type=float,
help='The ratio of connections to drop when refreshing the connections')
# Openvpn options # Openvpn options
_('openvpn_args', nargs=argparse.REMAINDER, _('openvpn_args', nargs=argparse.REMAINDER,
help="Common OpenVPN options (e.g. certificates)") help="Common OpenVPN options (e.g. certificates)")
...@@ -63,8 +63,8 @@ def main(): ...@@ -63,8 +63,8 @@ def main():
read_pipe = os.fdopen(r_pipe) read_pipe = os.fdopen(r_pipe)
# Init db and tunnels # Init db and tunnels
peer_db = db.PeerManager(config.db, config.server, config.server_port) peer_db = db.PeerManager(config.db, config.server, config.server_port, config.peers_db_refresh)
tunnel_manager = tunnel.TunnelManager(write_pipe, peer_db, config.client_count, config.refresh_count, openvpn_args) tunnel_manager = tunnel.TunnelManager(write_pipe, peer_db, openvpn_args, config.tunnel_refresh, config.connection_count, config.refresh_rate)
# Launch babel on all interfaces. WARNING : you have to be root to start babeld # Launch babel on all interfaces. WARNING : you have to be root to start babeld
interface_list = ['vifibnet'] + list(tunnel_manager.free_interface_set) interface_list = ['vifibnet'] + list(tunnel_manager.free_interface_set)
...@@ -73,25 +73,21 @@ def main(): ...@@ -73,25 +73,21 @@ def main():
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.max_clients, config.dh, write_pipe, server_process = plib.server(internal_ip, network, config.connection_count, config.dh, write_pipe,
'--dev', 'vifibnet', *openvpn_args, '--dev', 'vifibnet', *openvpn_args,
stdout=os.open(os.path.join(config.log, 'vifibnet.server.log'), os.O_WRONLY | os.O_CREAT | os.O_TRUNC)) stdout=os.open(os.path.join(config.log, 'vifibnet.server.log'), os.O_WRONLY | os.O_CREAT | os.O_TRUNC))
tunnel_manager.refresh()
# Timed refresh initializing
next_refresh = time.time() + config.refresh_time
# main loop # main loop
try: try:
while True: while True:
ready, tmp1, tmp2 = select.select([read_pipe], [], [], ready, tmp1, tmp2 = select.select([read_pipe], [], [],
max(0, next_refresh - time.time())) max(0, min(tunnel_manager.next_refresh, peer_db.next_refresh) - time.time()))
if ready: if ready:
peer_db.handle_message(read_pipe.readline()) peer_db.handle_message(read_pipe.readline())
if time.time() >= next_refresh: if time.time() >= peer_db.next_refresh:
peer_db.populate(100, (internal_ip, config.external_ip, port, proto)) peer_db.populate(200, (internal_ip, config.external_ip, port, proto))
if time.time() >= tunnel_manager.next_refresh:
tunnel_manager.refresh() tunnel_manager.refresh()
next_refresh = time.time() + config.refresh_time
except KeyboardInterrupt: except KeyboardInterrupt:
return 0 return 0
......
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