In simulation : we can now see the effects of the tunnel manager
[re6stnet.git] / vifibnet.py
1 #!/usr/bin/env python
2 import argparse, errno, os, select, subprocess, time
3 from argparse import ArgumentParser
4 import db, plib, upnpigd, utils, tunnel
5
6 class ArgParser(ArgumentParser):
7
8 def convert_arg_line_to_args(self, arg_line):
9 arg_line = arg_line.split('#')[0].rstrip()
10 if arg_line:
11 for arg in ('--' + arg_line.lstrip('--')).split():
12 if arg.strip():
13 yield arg
14
15 def ovpnArgs(optional_args, ca_path, cert_path):
16 # Treat openvpn arguments
17 if optional_args[0] == "--":
18 del optional_args[0]
19 optional_args.append('--ca')
20 optional_args.append(ca_path)
21 optional_args.append('--cert')
22 optional_args.append(cert_path)
23 return optional_args
24
25 def getConfig():
26 parser = ArgParser(fromfile_prefix_chars='@',
27 description='Resilient virtual private network application')
28 _ = parser.add_argument
29
30 # General Configuration options
31 _('--ip', default=None, dest='address', action='append', nargs=3,
32 help='Ip address, port and protocol advertised to other vpn nodes')
33 _('--internal-port', default=1194,
34 help='Port on the machine to listen on for incomming connections')
35 _('--peers-db-refresh', default=3600, type=int,
36 help='the time (seconds) to wait before refreshing the peers db')
37 _('-l', '-log', default='/var/log', dest='log',
38 help='Path to vifibnet logs directory')
39 _('-s', '--state', default='/var/lib/vifibnet',
40 help='Path to VPN state directory')
41 _('--verbose', '-v', default=0, type=int,
42 help='Defines the verbose level')
43 #_('--babel-state', default='/var/lib/vifibnet/babel_state',
44 # help='Path to babeld state-file')
45 #_('--db', default='/var/lib/vifibnet/peers.db',
46 # help='Path to peers database')
47 _('--server', required=True,
48 help="VPN address of the discovery peer server")
49 _('--server-port', required=True, type=int,
50 help="VPN port of the discovery peer server")
51
52 # Routing algorithm options
53 _('--hello', type=int, default=30,
54 help='Hello interval for babel, in seconds')
55 _('-w', '--wireless', action='store_true',
56 help='''Set all interfaces to be treated as wireless interfaces
57 for the routing protocol''')
58
59 # Tunnel options
60 _('--proto', choices=['udp', 'tcp-server'], nargs='+', default=['udp'],
61 help='Protocol(s) to be used by other peers to connect')
62 _('--tunnel-refresh', default=300, type=int,
63 help='the time (seconds) to wait before changing the connections')
64 _('--dh', required=True,
65 help='Path to dh file')
66 _('--ca', required=True,
67 help='Path to the certificate authority file')
68 _('--cert', required=True,
69 help='Path to the certificate file')
70 # args to be removed ?
71 _('--connection-count', default=20, type=int,
72 help='Number of tunnels')
73 _('--refresh-rate', default=0.05, type=float,
74 help='''The ratio of connections to drop when refreshing the
75 connections''')
76 # Openvpn options
77 _('openvpn_args', nargs=argparse.REMAINDER,
78 help="Common OpenVPN options (e.g. certificates)")
79 return parser.parse_args()
80
81 def main():
82 # Get arguments
83 config = getConfig()
84 manual = bool(config.address)
85 network = utils.networkFromCa(config.ca)
86 internal_ip, prefix = utils.ipFromCert(network, config.cert)
87 openvpn_args = ovpnArgs(config.openvpn_args, config.ca, config.cert)
88
89 # Set global variables
90 tunnel.log = config.log
91 utils.verbose = plib.verbose = config.verbose
92
93 # Create and open read_only pipe to get server events
94 utils.log('Creating pipe for server events', 3)
95 r_pipe, write_pipe = os.pipe()
96 read_pipe = os.fdopen(r_pipe)
97
98 # Init db and tunnels
99 if manual:
100 utils.log('Manual external configuration', 3)
101 else:
102 utils.log('Attempting automatic configuration via UPnP', 4)
103 try:
104 ext_ip, ext_port = upnpigd.ForwardViaUPnP(config.internal_port, config.proto)
105 config.address = list([ext_ip, str(ext_port), proto]
106 for proto in config.proto)
107 except Exception:
108 utils.log('An atempt to forward a port via UPnP failed', 4)
109
110 peer_db = db.PeerManager(config.state, config.server, config.server_port,
111 config.peers_db_refresh, config.address, internal_ip, prefix,
112 manual, config.proto, 200)
113 tunnel_manager = tunnel.TunnelManager(write_pipe, peer_db, openvpn_args,
114 config.hello, config.tunnel_refresh, config.connection_count,
115 config.refresh_rate)
116
117 # Launch routing protocol. WARNING : you have to be root to start babeld
118 interface_list = ['vifibnet'] + list(tunnel_manager.free_interface_set)
119 router = plib.router(network, internal_ip, interface_list, config.wireless,
120 config.hello, os.path.join(config.state, 'vifibnet.babeld.state'),
121 stdout=os.open(os.path.join(config.log, 'vifibnet.babeld.log'),
122 os.O_WRONLY|os.O_CREAT|os.O_TRUNC), stderr=subprocess.STDOUT)
123
124 # Establish connections
125 server_process = list(plib.server(internal_ip, network,
126 config.connection_count, config.dh, write_pipe, config.internal_port,
127 proto, config.hello, '--dev', 'vifibnet', *openvpn_args,
128 stdout=os.open(os.path.join(config.log,
129 'vifibnet.server.%s.log' % (proto,)),
130 os.O_WRONLY | os.O_CREAT | os.O_TRUNC)) for proto in config.proto)
131 tunnel_manager.refresh()
132
133 # main loop
134 try:
135 while True:
136 ready, tmp1, tmp2 = select.select([read_pipe], [], [],
137 max(0, min(tunnel_manager.next_refresh,
138 peer_db.next_refresh) - time.time()))
139 if ready:
140 peer_db.handle_message(read_pipe.readline())
141 if time.time() >= peer_db.next_refresh:
142 peer_db.refresh()
143 if time.time() >= tunnel_manager.next_refresh:
144 tunnel_manager.refresh()
145 except KeyboardInterrupt:
146 return 0
147
148 if __name__ == "__main__":
149 main()
150