Commit 81f49fab authored by Guillaume Bury's avatar Guillaume Bury

Added some logs, added blacklist in db, added lan discovery through babel +...

Added some logs, added blacklist in db, added lan discovery through babel + automatic blacklisting of node routed through the LAN
parent 23f47592
...@@ -15,28 +15,36 @@ class PeerManager: ...@@ -15,28 +15,36 @@ class PeerManager:
self._server_port = server_port self._server_port = server_port
self._db_size = db_size self._db_size = db_size
self._pp = pp self._pp = pp
self._blacklist = [(prefix,)]
self._manual = manual self._manual = manual
self._proxy = xmlrpclib.ServerProxy('http://%s:%u' self._proxy = xmlrpclib.ServerProxy('http://%s:%u'
% (server, server_port)) % (server, server_port))
utils.log('Connectiong to peers database', 4) utils.log('Connectiong to peers database...', 4)
self._db = sqlite3.connect(os.path.join(db_dir_path, 'peers.db'), self._db = sqlite3.connect(os.path.join(db_dir_path, 'peers.db'),
isolation_level=None) isolation_level=None)
utils.log('Preparing peers database', 4) utils.log('Database opened', 5)
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
utils.log('Database prepared', 5)
self.next_refresh = time.time() self.next_refresh = time.time()
def blacklist(self, prefix):
utils.log('Blacklisting %s' % (prefix,), 4)
self._blacklist = list(set(self._blacklist + [(prefix,)]))
def refresh(self): def refresh(self):
utils.log('Refreshing the peers DB', 2) utils.log('Refreshing the peers DB...', 2)
try: try:
self._declare() self._declare()
self._populate() self._populate()
utils.log('DB refreshed', 3)
self.next_refresh = time.time() + self._refresh_time self.next_refresh = time.time() + self._refresh_time
except socket.error, e: except socket.error, e:
utils.log(str(e), 4) utils.log(str(e), 4)
...@@ -45,14 +53,15 @@ class PeerManager: ...@@ -45,14 +53,15 @@ class PeerManager:
def _declare(self): def _declare(self):
if self._address != None: if self._address != None:
utils.log('Sending connection info to server', 3) utils.log('Sending connection info to server...', 3)
self._proxy.declare((self._internal_ip, self._proxy.declare((self._internal_ip,
utils.address_list(self._address))) utils.address_list(self._address)))
utils.log('Info sent', 5)
else: else:
utils.log("Warning : couldn't send ip, unknown external config", 4) utils.log("Warning : couldn't send ip, unknown external config", 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, new_peer_list = self._proxy.getPeerList(self._db_size,
self._internal_ip) self._internal_ip)
self._db.execute("""DELETE FROM peers WHERE used <= 0 ORDER BY used, self._db.execute("""DELETE FROM peers WHERE used <= 0 ORDER BY used,
...@@ -61,7 +70,9 @@ class PeerManager: ...@@ -61,7 +70,9 @@ class PeerManager:
(str(len(new_peer_list) - self._db_size),)) (str(len(new_peer_list) - self._db_size),))
self._db.executemany("""INSERT OR IGNORE INTO peers (prefix, address) self._db.executemany("""INSERT OR IGNORE INTO peers (prefix, address)
VALUES (?,?)""", new_peer_list) VALUES (?,?)""", new_peer_list)
self._db.execute("DELETE FROM peers WHERE prefix = ?", (self._prefix,)) self._db.executemany("DELETE FROM peers WHERE prefix = ?",
self._blacklist)
utils.log('DB populated', 3)
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):
...@@ -73,16 +84,19 @@ class PeerManager: ...@@ -73,16 +84,19 @@ class PeerManager:
utils.log('Updating peers database : using peer ' + str(prefix), 5) utils.log('Updating peers database : using peer ' + str(prefix), 5)
self._db.execute("UPDATE peers SET used = 1 WHERE prefix = ?", self._db.execute("UPDATE peers SET used = 1 WHERE prefix = ?",
(prefix,)) (prefix,))
utils.log('DB updated', 5)
def unusePeer(self, prefix): def unusePeer(self, prefix):
utils.log('Updating peers database : unusing peer ' + str(prefix), 5) utils.log('Updating peers database : unusing peer ' + str(prefix), 5)
self._db.execute("UPDATE peers SET used = 0 WHERE prefix = ?", self._db.execute("UPDATE peers SET used = 0 WHERE prefix = ?",
(prefix,)) (prefix,))
utils.log('DB updated', 5)
def flagPeer(self, prefix): def flagPeer(self, prefix):
utils.log('Updating peers database : flagging peer ' + str(prefix), 5) utils.log('Updating peers database : flagging peer ' + str(prefix), 5)
self._db.execute("UPDATE peers SET used = -1 WHERE prefix = ?", self._db.execute("UPDATE peers SET used = -1 WHERE prefix = ?",
(prefix,)) (prefix,))
utils.log('DB updated', 5)
def handle_message(self, msg): def handle_message(self, msg):
script_type, arg = msg.split() script_type, arg = msg.split()
......
...@@ -18,7 +18,7 @@ def openvpn(hello_interval, *args, **kw): ...@@ -18,7 +18,7 @@ def openvpn(hello_interval, *args, **kw):
return subprocess.Popen(args, **kw) return subprocess.Popen(args, **kw)
def server(server_ip, ip_length, max_clients, dh_path, pipe_fd, port, proto, hello_interval, *args, **kw): def server(server_ip, ip_length, max_clients, dh_path, pipe_fd, port, proto, 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',
'--mode', 'server', '--mode', 'server',
...@@ -32,7 +32,7 @@ def server(server_ip, ip_length, max_clients, dh_path, pipe_fd, port, proto, hel ...@@ -32,7 +32,7 @@ def server(server_ip, ip_length, max_clients, dh_path, pipe_fd, port, proto, hel
*args, **kw) *args, **kw)
def client(server_address, 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)
remote= ['--nobind', remote= ['--nobind',
'--client', '--client',
'--up', 'ovpn-client', '--up', 'ovpn-client',
...@@ -44,7 +44,7 @@ def client(server_address, pipe_fd, hello_interval, *args, **kw): ...@@ -44,7 +44,7 @@ def client(server_address, pipe_fd, hello_interval, *args, **kw):
def router(network, internal_ip, interface_list, def router(network, internal_ip, interface_list,
wireless, hello_interval, state_path, **kw): wireless, hello_interval, state_path, **kw):
utils.log('Starting babel', 3) utils.log('Starting babel...', 3)
args = ['babeld', args = ['babeld',
'-C', 'redistribute local ip %s' % (internal_ip), '-C', 'redistribute local ip %s' % (internal_ip),
'-C', 'redistribute local deny', '-C', 'redistribute local deny',
......
import os, random, traceback, time, struct import os, random, traceback, time, struct, subprocess
import plib, utils, db import plib, utils, db
log = None log = None
smooth = 0.3 smooth = 0.3
class Connection: class Connection:
def __init__(self, address, write_pipe, hello, iface, prefix, def __init__(self, address, write_pipe, hello, iface, prefix,
...@@ -12,7 +11,8 @@ class Connection: ...@@ -12,7 +11,8 @@ class Connection:
self.process = plib.client(address, write_pipe, hello, '--dev', iface, self.process = plib.client(address, write_pipe, hello, '--dev', iface,
*ovpn_args, stdout=os.open(os.path.join(log, *ovpn_args, stdout=os.open(os.path.join(log,
'vifibnet.client.%s.log' % (prefix,)), 'vifibnet.client.%s.log' % (prefix,)),
os.O_WRONLY | os.O_CREAT | os.O_TRUNC)) os.O_WRONLY | os.O_CREAT | os.O_TRUNC),
stderr=subprocess.STDOUT)
self.iface = iface self.iface = iface
self.routes = 0 self.routes = 0
...@@ -64,7 +64,7 @@ class Connection: ...@@ -64,7 +64,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, iface_list, network):
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 = {}
...@@ -72,6 +72,10 @@ class TunnelManager: ...@@ -72,6 +72,10 @@ 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._network = network
self._net_len = len(network)
self._iface_list = iface_list
self.__indirect_connect = []
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',
...@@ -82,11 +86,12 @@ class TunnelManager: ...@@ -82,11 +86,12 @@ class TunnelManager:
self._refresh_count = refresh_rate * self._client_count self._refresh_count = refresh_rate * self._client_count
def refresh(self): def refresh(self):
utils.log('Refreshing the tunnels', 2) utils.log('Refreshing the tunnels...', 2)
self._cleanDeads() self._cleanDeads()
self._countRoutes() self._countRoutes()
self._removeSomeTunnels() self._removeSomeTunnels()
self._makeNewTunnels() self._makeNewTunnels()
utils.log('Tunnels refreshed', 2)
self.next_refresh = time.time() + self._refresh_time self.next_refresh = time.time() + self._refresh_time
def _cleanDeads(self): def _cleanDeads(self):
...@@ -102,7 +107,7 @@ class TunnelManager: ...@@ -102,7 +107,7 @@ class TunnelManager:
self._kill(prefix) self._kill(prefix)
def _kill(self, prefix): def _kill(self, prefix):
utils.log('Killing the connection with ' + prefix, 2) utils.log('Killing the connection with %s...' % (prefix,), 2)
connection = self._connection_dict.pop(prefix) connection = self._connection_dict.pop(prefix)
try: try:
connection.process.kill() connection.process.kill()
...@@ -112,9 +117,11 @@ class TunnelManager: ...@@ -112,9 +117,11 @@ class TunnelManager:
self.free_interface_set.add(connection.iface) self.free_interface_set.add(connection.iface)
self._peer_db.unusePeer(prefix) self._peer_db.unusePeer(prefix)
del self._iface_to_prefix[connection.iface] del self._iface_to_prefix[connection.iface]
utils.log('Connection with %s killed' % (prefix,), 2)
def _makeNewTunnels(self): def _makeNewTunnels(self):
utils.log('Trying to make %i new tunnels' % i = 0
utils.log('Trying to make %i new tunnels...' %
(self._client_count - len(self._connection_dict)), 5) (self._client_count - len(self._connection_dict)), 5)
try: try:
for prefix, address in self._peer_db.getUnusedPeers( for prefix, address in self._peer_db.getUnusedPeers(
...@@ -126,6 +133,8 @@ class TunnelManager: ...@@ -126,6 +133,8 @@ class TunnelManager:
prefix, self._ovpn_args) prefix, self._ovpn_args)
self._iface_to_prefix[iface] = prefix self._iface_to_prefix[iface] = prefix
self._peer_db.usePeer(prefix) self._peer_db.usePeer(prefix)
i += 1
utils.log('%u new tunnels established' %(i,), 3)
except KeyError: except KeyError:
utils.log("""Can't establish connection with %s utils.log("""Can't establish connection with %s
: no available interface""" % prefix, 2) : no available interface""" % prefix, 2)
...@@ -133,7 +142,8 @@ class TunnelManager: ...@@ -133,7 +142,8 @@ class TunnelManager:
traceback.print_exc() traceback.print_exc()
def _countRoutes(self): def _countRoutes(self):
utils.log('Starting to count the routes on each interface', 3) utils.log('Starting to count the routes on each interface...', 3)
self._indirect_connect = []
for iface in self._iface_to_prefix.keys(): for iface in self._iface_to_prefix.keys():
self._connection_dict[self._iface_to_prefix[iface]].routes = 0 self._connection_dict[self._iface_to_prefix[iface]].routes = 0
f = open('/proc/net/ipv6_route', 'r') f = open('/proc/net/ipv6_route', 'r')
...@@ -141,9 +151,21 @@ class TunnelManager: ...@@ -141,9 +151,21 @@ class TunnelManager:
ip, subnet_size, iface = struct.unpack('32s x 2s 106x %ss x' ip, subnet_size, iface = struct.unpack('32s x 2s 106x %ss x'
% (len(line) - 142), line) % (len(line) - 142), line)
iface = iface.replace(' ', '') iface = iface.replace(' ', '')
utils.log('Route on iface %s detected to %s/%s'
% (iface,ip, subnet_size), 8)
if iface in self._iface_to_prefix.keys(): if iface in self._iface_to_prefix.keys():
self._connection_dict[self._iface_to_prefix[iface]].routes += 1 self._connection_dict[self._iface_to_prefix[iface]].routes += 1
if iface in self._iface_list:
subnet_size = int(subnet_size,16)
ip = bin(int(ip, 16))[2:].rjust(128, '0')
if self._net_len < subnet_size < 128 and ip.startswith(self._network):
prefix = ip[self._net_len:subnet_size]
utils.log('A route to %s has been discovered on the LAN'
% (prefix,), 3)
self._peer_db.blacklist(prefix)
utils.log("Routes have been counted", 3)
for p in self._connection_dict.keys(): for p in self._connection_dict.keys():
utils.log('Routes on iface %s : %s' % ( utils.log('Routes on iface %s : %s' % (
self._connection_dict[p].iface, self._connection_dict[p].iface,
self._connection_dict[p].routes), 5) self._connection_dict[p].routes), 5)
...@@ -3,17 +3,18 @@ import argparse, errno, os, select, subprocess, time ...@@ -3,17 +3,18 @@ import argparse, errno, os, select, subprocess, time
from argparse import ArgumentParser from argparse import ArgumentParser
import db, plib, upnpigd, utils, tunnel import db, plib, upnpigd, utils, tunnel
class ArgParser(ArgumentParser): class ArgParser(ArgumentParser):
def convert_arg_line_to_args(self, arg_line): def convert_arg_line_to_args(self, arg_line):
arg_line = arg_line.split('#')[0].rstrip() arg_line = arg_line.split('#')[0].rstrip()
if arg_line: if arg_line:
if arg_line.startswith('@'):
yield arg_line
return
for arg in ('--' + arg_line.lstrip('--')).split(): for arg in ('--' + arg_line.lstrip('--')).split():
if arg.strip(): if arg.strip():
yield arg yield arg
def ovpnArgs(optional_args, ca_path, cert_path): def ovpnArgs(optional_args, ca_path, cert_path):
# Treat openvpn arguments # Treat openvpn arguments
if optional_args[0] == "--": if optional_args[0] == "--":
...@@ -41,6 +42,8 @@ def getConfig(): ...@@ -41,6 +42,8 @@ def getConfig():
help='Path to VPN state directory') help='Path to VPN state directory')
_('--verbose', '-v', default=0, type=int, _('--verbose', '-v', default=0, type=int,
help='Defines the verbose level') help='Defines the verbose level')
_('-i', '--interface', action='append', dest='iface_list', default=[],
help='Extra interface for LAN discovery')
#_('--babel-state', default='/var/lib/vifibnet/babel_state', #_('--babel-state', default='/var/lib/vifibnet/babel_state',
# help='Path to babeld state-file') # help='Path to babeld state-file')
#_('--db', default='/var/lib/vifibnet/peers.db', #_('--db', default='/var/lib/vifibnet/peers.db',
...@@ -94,22 +97,26 @@ def main(): ...@@ -94,22 +97,26 @@ def main():
tunnel.log = config.log tunnel.log = config.log
utils.verbose = plib.verbose = config.verbose utils.verbose = plib.verbose = config.verbose
utils.log(str(config), 5)
# Create and open read_only pipe to get server events # Create and open read_only pipe to get server events
utils.log('Creating pipe for server events', 3) utils.log('Creating pipe for server events...', 3)
r_pipe, write_pipe = os.pipe() r_pipe, write_pipe = os.pipe()
read_pipe = os.fdopen(r_pipe) read_pipe = os.fdopen(r_pipe)
utils.log('Pipe created', 5)
# Init db and tunnels # Init db and tunnels
if manual: if manual:
utils.log('Manual external configuration', 3) utils.log('Detected manual external configuration', 3)
forward = None forward = None
else: else:
utils.log('Attempting automatic configuration via UPnP', 4) utils.log('Attempting automatic configuration via UPnP...', 4)
try: try:
forward = list([upnpigd.UpnpForward(int(port), proto), proto] forward = list([upnpigd.UpnpForward(int(port), proto), proto]
for port, proto in config.pp) for port, proto in config.pp)
config.address = list([ext.external_ip, str(ext.external_port), config.address = list([ext.external_ip, str(ext.external_port),
proto] for ext, proto in forward) proto] for ext, proto in forward)
utils.log('Automatic configuration succeeded', 5)
except Exception: except Exception:
forward = None forward = None
utils.log('An atempt to forward a port via UPnP failed', 4) utils.log('An atempt to forward a port via UPnP failed', 4)
...@@ -119,10 +126,11 @@ def main(): ...@@ -119,10 +126,11 @@ def main():
manual, config.pp, 200) manual, config.pp, 200)
tunnel_manager = tunnel.TunnelManager(write_pipe, peer_db, openvpn_args, tunnel_manager = tunnel.TunnelManager(write_pipe, peer_db, openvpn_args,
config.hello, config.tunnel_refresh, config.connection_count, config.hello, config.tunnel_refresh, config.connection_count,
config.refresh_rate) config.refresh_rate, config.iface_list, network)
# Launch routing protocol. WARNING : you have to be root to start babeld # Launch routing protocol. 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) \
+ config.iface_list
router = plib.router(network, internal_ip, interface_list, config.wireless, router = plib.router(network, internal_ip, interface_list, config.wireless,
config.hello, os.path.join(config.state, 'vifibnet.babeld.state'), config.hello, os.path.join(config.state, 'vifibnet.babeld.state'),
stdout=os.open(os.path.join(config.log, 'vifibnet.babeld.log'), stdout=os.open(os.path.join(config.log, 'vifibnet.babeld.log'),
...@@ -134,7 +142,8 @@ def main(): ...@@ -134,7 +142,8 @@ def main():
proto, config.hello, '--dev', 'vifibnet', *openvpn_args, proto, config.hello, '--dev', 'vifibnet', *openvpn_args,
stdout=os.open(os.path.join(config.log, stdout=os.open(os.path.join(config.log,
'vifibnet.server.%s.log' % (proto,)), 'vifibnet.server.%s.log' % (proto,)),
os.O_WRONLY | os.O_CREAT | os.O_TRUNC)) os.O_WRONLY | os.O_CREAT | os.O_TRUNC),
stderr=subprocess.STDOUT)
for port, proto in config.pp) for port, proto in config.pp)
tunnel_manager.refresh() tunnel_manager.refresh()
......
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