Commit 212242ff authored by Julien Muchembled's avatar Julien Muchembled

Documentation

parent 1c70c3ed
...@@ -15,32 +15,28 @@ re6stnet creates a resilient, scalable, ipv6 network on top of an existing ipv4 ...@@ -15,32 +15,28 @@ re6stnet creates a resilient, scalable, ipv6 network on top of an existing ipv4
network, by creating tunnels on the fly, and then routing targeted traffic network, by creating tunnels on the fly, and then routing targeted traffic
through these tunnels. through these tunnels.
re6stnet can be used to : re6stnet can be used to:
- guarantee connectedness between computers connected to the - guarantee connectedness between computers connected to the
internet, for which there exists a working route ( in case the direct route internet, for which there exists a working route (in case the direct route
isn't available ). isn't available).
- create very large networks - create large networks
- give ipv6 addresses to machines with only ipv4 available - give ipv6 addresses to machines with only ipv4 available
HOW IT WORKS HOW IT WORKS
============ ============
A re6stnet networks consists of at least one server ( re6st-registry ) and many A re6stnet network consists of at least one server (re6st-registry) and many
clients or nodes ( re6stnet ). The server delivers certificates for secure nodes (re6stnet). The server is only used to deliver certificates for secure
authentification in establishing tunnels, and - for now - store the complete authentification in establishing tunnels, and to bootstrap new nodes.
list of nodes running. re6stnet can detect and take into account nodes present on the local network.
re6stnet detects and take into accounts nodes present on the local network.
Resilience Resilience
---------- ----------
re6stnet can guarantee that if there exists a route between two machines, re6stnet guarantees that if there exists a route between two machines,
traffic will be correctly routed between these two machines. traffic will be correctly routed between these two machines.
Since the destination of established connection are random, there can be no Even if the registry node is down, the probability that the network isn't
guarantee that such a route exists given which tunnels are established, but connected is very low for big enough networks (more than a hundred nodes).
for big enough networks ( more than a hundred nodes ), the probability that
the network isn't connected is very low.
Scalability Scalability
----------- -----------
...@@ -51,30 +47,23 @@ scalable to tens of thousand of nodes ...@@ -51,30 +47,23 @@ scalable to tens of thousand of nodes
Requirements Requirements
============ ============
- Python 2.7 or later - Python 2.6 or 2.7
- OpenSSL binary and development libraries - OpenSSL binary and development libraries
- OpenVPN - OpenVPN
- Babel_
- python-miniupnpc for UPnP support (optional)
- for the demo: miniupnpd_, Graphviz, Screen, Nemu_
- Babel ( http://www.pps.univ-paris-diderot.fr/~jch/software/babel/ ) See also `setup.py` for Python dependencies.
.. _Babel: http://www.pps.univ-paris-diderot.fr/~jch/software/babel/
_Nemu: http://code.google.com/p/nemu/
_miniupnpd: http://miniupnp.free.fr/
Installation Installation
============ ============
Let's explain how to install the egg re6stnet is distributed as an Python egg, and is also packaged for Debian.
Commercial Support
==================
Later....
.. The organisation of the code See `re6stnet-registry` to set up a re6st network
re6stnet.py Client : Init and main loop and `re6stnet-conf` to join an existing network.
re6st/plib.py Launch server/client/routing processes
re6st/utils.py Small functions to do useful jobs
re6st/db.py Manage the peer database
re6st/tunnel.py Manage the tunnels
re6st/upnpigd.py Forward ports
re6st-conf.py Get certificates from server
re6st-registry.py Server : deliver certificates and distribute peers
...@@ -12,67 +12,21 @@ Configuration tool for re6stnet ...@@ -12,67 +12,21 @@ Configuration tool for re6stnet
SYNOPSIS SYNOPSIS
======== ========
``re6st-conf`` ``--server`` `server-url` ``--port`` `server-port` [`command`] ``re6st-conf`` ``--registry`` `url` [`options`...]
[`options`...]
DESCRIPTION DESCRIPTION
=========== ===========
re6st-conf is a tool generating the files necessary for re6stnet to run. It re6st-conf is a tool generating the files necessary to add a node to a re6st
connects to a distant server to generate the certificates files used by openvpn network. It connects to the re6st registry to get a signed certificate with
in re6stnet. an allocated IPv6 subnet.
USAGE USAGE
===== =====
re6st-conf needs address of node running re6st-registry. Use ``re6st-conf --help`` to get the complete list of options.
--registry address
Public HTTP URL of the registry, which is used for bootstrapping
and delivering certificates.
Commands
--------
You may give at most one of the following commands. Giving the two commands
will not raise any errors, but does not have any meaning.
--email email-address
The email address to associate with your certificates. Refrain
re6st-conf from asking you your email address in a prompt. Useful
for automatizing the configuration process.
re6st-conf will ask you the token you received by email.
--token token
Give your token if you have already received one but did not
complete the configuration process. re6st-conf will not ask you
anything. If you use this option, you do not need to give your
email address.
Options
-------
-d, ``--dir`` `directory`
Path of a directory where will be stored the files generated by the
setup. The Setup genereates the following files, in the explicit
order :
- ca.pem : certificate authority file downloaded from the server
- cert.key : private key generated by the script
- cert.crt : individual certificate file generated by the server
- dh2048.pem : dh file for oenvpn server
-r, ``--req`` `name` `value`
Specify an attribute to add to the certificate request sent to the
server. Can be used multiple times.
Each use of the --req name value, will add the attribute name with
the associated value in the sugbject of the certificate request.
--ca-only
Stop the script after downloading the certificate authority file
from the server
SEE ALSO SEE ALSO
======== ========
``re6stnet``\ (1), ``re6st-registry``\ (1) ``re6stnet``\ (8)
...@@ -12,55 +12,28 @@ ...@@ -12,55 +12,28 @@
SYNOPSIS SYNOPSIS
======== ========
``re6st-registry`` `port` ``--db`` `db-path` ``--ca`` `ca-path` ``re6st-registry`` ``--db`` `db-path` ``--ca`` `ca-path` ``--key`` `key-path`
``--key`` `key-path` ``--mailhost`` `mailhost` ``--private`` `private-ip` ``--mailhost`` `mailhost` ``--private`` `re6st-ip` [`options`...]
[`options`...]
DESCRIPTION DESCRIPTION
=========== ===========
re6st-registry is a server for the re6st network. Its role is to deliver re6st-registry is a server for the re6st network. Its role is to deliver
certificates to new nodes, and to maintain the complete table of peers, so it certificates to new nodes, and to bootstrap nodes that don't know any address
can send part of it to nodes asking for new peers. of other nodes.
Only one re6st-registry per re6st network should run. The node
running the re6st-registry must also have a client ( re6stnet ) running. The network can host only one registry, which should run on a re6st node.
USAGE USAGE
===== =====
The re6st-registry will automatically listen on both ipv4 and ipv6 for incoming Use ``re6st-registry --help`` to get the complete list of options.
request.
--port port
The port on which the server will listen
Default: 80
--db path
Path to the server Database file. A new DB file will be created
and correctly initialized if the file doesn't exists.
One can give ":memory" as path, the database is then temporary
--ca path
Path to the certificate authority file. The certificate authority
MUST contain the VPN network prefix in its serial number. To
generate correct ca and key files for the 2001:db8:42:: prefix,
the following command can be used :
openssl req -nodes -new -x509 -key ca.key -set_serial \
0x120010db80042 -days 365 -out ca.crt
--key path
Path to the server key file. To generate a key file, see the --ca
option
--mailhost mailhost
Mailhost to be used to send email containing token for registration
--private ip The network prefix can be changed by renewing the Certificate authority with
Ipv6 address of the re6stnet client running on the machine. This a different serial number, but keeping the existing key. Then all nodes of the
address will be advertised only to nodes having a valid network must fetch the new CA with `re6st-conf` and restart `re6stnet`.
certificate.
SEE ALSO SEE ALSO
======== ========
``re6stnet``\ (1), ``re6st-conf``\ (1) ``re6stnet``\ (8)
...@@ -7,273 +7,78 @@ Resilient, Scalable, IPv6 Network application ...@@ -7,273 +7,78 @@ Resilient, Scalable, IPv6 Network application
--------------------------------------------- ---------------------------------------------
:Author: Nexedi :Author: Nexedi
:Manual section: 1 :Manual section: 8
SYNOPSIS SYNOPSIS
======== ========
``re6stnet`` ``--registry`` `registry-url` ``--dh`` `dh-path` ``--ca`` `ca-path` ``re6stnet`` ``--registry`` `registry-url` ``--dh`` `dh-path`
``--cert`` `cert-path` ``--key`` `key-path` [`options`...] ``--ca`` `ca-path` ``--cert`` `cert-path` ``--key`` `key-path`
[``--`` [`openvpn-options`...]] [`options`...] [``--`` [`openvpn-options`...]]
DESCRIPTION DESCRIPTION
=========== ===========
re6stnet is a client connecting to the re6st network. It establishes connections `re6stnet` runs a node of a re6st network. It establishes connections
with other nodes and create a resilient network, whose nodes all have ipv6 with other nodes by creating OpenVPN tunnels and uses Babel for routing.
addresses. The goal of re6stnet is to create very large networks, guaranteeing
bandwidth between nodes and giving ipv6 to computers.
USAGE USAGE
===== =====
re6stnet needs information about certificates to start, as they contain data Use ``re6stnet --help`` to get the complete list of options.
about the network and the ipv6 address of the node. These certificates can be
obtained with the re6st-conf tool.
--registry address
Complete public ( reachable from the internet ) address of the machine
running a registry. Will be used to get the pirvate address of the
registry and/or bootstrap peers
Examples : http://192.0.2.42:80, http://[2001:db8:42::1]:80
--dh path
Path to the dh file to be used by the openvpn server
(for more information see the openvpn man page)
--ca path
Path to the certificate authority file delivered by the re6stnet
server. The prefix of the re6st network is included in the serial
number of the file.
--cert path
Path to the individual certificate file delivered by the re6stnet
server. The prefix of the machine's re6stnet ip is included in the
certificate's subject common name.
--key path
Path to the private key file generated by the re6st-conf tool.
Options
-------
Generic options
~~~~~~~~~~~~~~~
-h, --help Display a summary help about the options
@file
You can give to re6stnet a config file as a regular argument
(meaning before giving optional openvpn arguments)
The file should contain one option per line, possibly ommitting
the '--'. Only long option are allowed (i.e "v 3" will not work
while "verbose 3" will)
You can give a file ( with the @ prefix ) as an argument within a
file ( since it is an optioin, it must be alone on the line ).
--ip address port proto
IP address advertised to other nodes. Special values:
- upnp: force autoconfiguration via UPnP
- any: ask peers our IP
Default: ask peers if UPnP fails
-l, ``--log`` `directory`
Path to the directory used for log files. Will create one file
for babel logging and one file for each openvpn server and client
started.
Default : /var/log
-s, ``--state`` `directory`
Path to the directory used for state files. State files include :
- peers.db : the peers db used to establish connection ( created
if does not exists )
- re6stnet.babeld.state : babeld state file ( created if does not
exists, overriden if exists )
Default : /var/lib/re6stnet
-v, ``--verbose`` `level`
Defines the verbose level, level should be an integer between 0
and 3 ( including ). There is no precise convention for verbode
level for now, except an increased number means more log messages.
This parameter is also given to babel for its log.
To adjust verbose level for openvpn, add an openvpn optional
arguments at the end of the command line.
Default : 0
Babel options
~~~~~~~~~~~~~
--babel-pidfile
Specify a file to write our process id to (option -I of Babel).
--babel-verb
Babel verbosity (option -d of Babel).
-i, ``--interface`` `interface`
Give one interface name for each use of the argument. The interface
will be used to detect other nodes on the local network.
--hello duration
Set hello interval, in seconds, for both wired and wireless
connections. Openvpn ping-exit option is set to 4 times the hello
interval. Argument passed down to the babel daemon, equivalent
to :
-h duration -H duration
in babeld ( for more information, see babeld man page )
It takes between 3 times and 4 times the hello interval for babel
to re-establish connection with a node for which the direct
connection has been cut
Default : 15
-w, --wireless
Consider all interfaces as being wireless interfaces. Argument
directly passed down to the babeld daemon.
Tunnel & Peers options
~~~~~~~~~~~~~~~~~~~~~~
--peers-db-refresh duration
Duration in seconds of the peers DB refresh interval. At each
refresh, a re6st node will declare itself to the re6st-registry,
and request a list of peers to connect to. A list of peers is also
queried when tying to make a connection and no peers is available
in the database.
Default : 3600 ( 1 hour )
--pp port proto
Port and protocol to be announced to other peers, ordered by
preference. For each protocol, start one openvpn server on the
first given port.
Protocols: udp, tcp
Default : --pp 1194 udp --pp 1194 tcp
--tunnel-refresh duration
Interval in seconds between two tunnel refresh. Refreshing tunnels
mean replace the worst tunnel if the number of tunnels has reach
its maximum number.
Default : 300
--connection-count number
The average number of connections per peer
Default : 20
Openvpn-options
---------------
-- `openvpn_args`
Additional arguments to be passed down to all openvpn processes
can be given at the end of the command line.
In that case, insert '--' to delimit re6stnet regular options
from the additional openvpn arguments. The list of arguments will
be passed down to ALL openvpn processes ( including servers )
exactly as they are given.
HOW TO HOW TO
====== ======
Here's an example how to deploy your re6st network. Joining an existing network
---------------------------
Normal node
-----------
In most cases, you only have to start the re6stnet daemon for you to join
the re6st network. Since the number of options to set is currently quite high,
I advise you to use a configuration file. Here is an example of such a
configuration file::
# Configuration file for re6stnet
# You have to give the complete url of the re6st-registry.
# If you have the ip address and the port of the registry, enter the url as
# following :
# registry http://ipv4:port
# registry http://[ipv6]:port
registry http://localhost:8000
# Here are information about your certificates.
# These options are mandatory.
dh dh2048.pem
ca ca.pem
cert cert.crt
key cert.key
# You can give the external configuration ( ip, port and protocol )
# advertised to other nodes. These information are used by the openvpn
# daemon to connect to your servers. If no --ip otion is given, re6stnet
# will automatically attempt to forward ports vie UPnP.
# You can give as many --ip options you want.
# ip 192.0.2.130 1194 udp
# ip 192.0.2.130 1194 tcp-client
# You can specify the directory you want the state files ( peer database,
# babel state file ), to be in. The default is :
# state /var/lib/re6stnet
# Verbose level ( default: 0 )
# 1 is a good verbose level if you want to see what's happening in re6st.
# level 2 and 3 display a whole lot of messages, so it should only be used
# as a debug tool
verbose 1
You can then start re6stnet :
``re6stnet @command_file``
First Node Once you know the registry URL of an existing network, use `re6st-conf` to get
---------- a certificate::
First, generate the ceritifcates for your network with the following command. re6st-conf --registry http://re6st.example.com/
For that, you have to give the address for your network, here we took an
address starting with the ipv6 example prefix `2001:db8::`, and adding a random
number to create a /48 network. Once you have decided on your network ip
address, you have to translate it into hexadecimal, and add a **1** as the
most significant digit. So the network ip address 2001:db8:42::/48 translate
into ``0x120010db80042``. Put that number as the serial umber of your
certificate.
``openssl req -nodes -new -x509 -key ca.key -set_serial 0x120010db80042 Use `-r` option to add public information to your certificate.
-days 365 -out ca.crt`` A token will be sent to the email you specify, in order to confirm your
subscription.
Files will be created by default in current directory and they are all
required for `re6stnet`::
With this, you now have a ca.crt and a ca.key file in your current directory. re6stnet --dh dh2048.pem --ca ca.crt --cert cert.crt --key cert.key \
Then, you have to start a re6st-registry to acquire an ipv6 address for your --registry http://re6st.example.com/
first node. In order to do that, you need to run the following command.
You can give any path you like for the --db option, if the file does not
exists, it will be created. The mailhost will be used to send tokens by mail,
so you should make sure it works.
``re6st-registry port_number --db db_path --ca path_to_ca.crt Setting a new network
--key path_to_ca.key --mailhost yourmailhost`` ---------------------
You are now ready to use the re6st configuration tool to generate the First you need to know the prefix of your network: let's suppose it is
certificates for the first node of your network, i.e. you. This should do the `2001:db8:42::/48`. From it, you computes the serial number of the Certificate
trick : authority (CA) that will be used by the registry node to sign delivered
certificates, as follows: translate the significant part to hexadecimal
(ie. 20010db80042) add a **1** as the most significant digit::
``re6st-conf --server localhost --port 8000`` openssl req -nodes -new -x509 -key ca.key -set_serial 0x120010db80042 \
-days 365 -out ca.crt
It will generate in your local directory (you can change it with the -d option) The CA email will be used as sender for mails containing tokens.
four files (ca.crt, cert.crt, cert.key, dh2048.pem). It is recommanded to put
these files in a different directory than the certificates for the registry,
although the names shouldn't conflict.
Now here's the tricky part. For your network to work, you need to restart the Now start the registry in order to setup the main re6st node, which should be
registry with more information than the last time. You need to get your hands on the same machine::
on the re6st ipv6 address associated with your node. These should have been
printed at the end of re6st-conf. If you have missed them, for one reason or
another, you can get it in the python interpreter::
from re6st import utils re6st-registry --ca ca.crt --key ca.key --mailhost smtp.example.com
network = utils.networkFromCa('ca.pem') re6st-conf --registry http://localhost/
re6st_ip, _ = utils.ipFromCert(network, 'cert.crt')
print re6st_ip
Now you can restart your re6st-registry with two more options: If `re6st-conf` is run in the directory containing CA files, ca.crt will
overridden without harm.
``re6st-registry port_number --db db_path --ca path_to_ca.crt Note that the registry was started without specifying the re6st IP of the main
--key path_to_ca.key --mailhost yourmailhost --private 2001:db8:42:3::1 node, because it was not known yet. For your network to work, it has to be
restarted with appropriate --private option.
Finally, you can start your own re6st node following the instructions in the Let's suppose your first node is allocated subnet 2001:db8:42::/64.
precedent section. Its IP is the first unicast address::
re6st-registry --private 2001:db8:42::1 ...
re6stnet --registry http://localhost/ --ip re6st.example.com ...
SEE ALSO SEE ALSO
======== ========
......
#!/usr/bin/env python #!/usr/bin/env python
import argparse, os, subprocess, sqlite3, sys, xmlrpclib import argparse, atexit, os, subprocess, sqlite3, sys, xmlrpclib
from OpenSSL import crypto from OpenSSL import crypto
from re6st import utils from re6st import utils
def create(path, text, mode=0666): def create(path, text=None, mode=0666):
fd = os.open(path, os.O_CREAT | os.O_WRONLY | os.O_EXCL, mode) fd = os.open(path, os.O_CREAT | os.O_WRONLY | os.O_TRUNC, mode)
if text is None:
return fd
try: try:
os.write(fd, text) os.write(fd, text)
finally: finally:
...@@ -12,18 +14,24 @@ def create(path, text, mode=0666): ...@@ -12,18 +14,24 @@ def create(path, text, mode=0666):
def main(): def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='Setup script for re6stnet') description="Setup script for re6stnet.",
formatter_class=utils.HelpFormatter)
_ = parser.add_argument _ = parser.add_argument
_('--registry', required=True, metavar='URL',
help="HTTP URL of the server delivering certificates.")
_('--ca-only', action='store_true', _('--ca-only', action='store_true',
help='To only get CA form server') help='Only fetch CA from registry and exit.')
_('--registry', required=True, _('-d', '--dir',
help='HTTP URL of the server delivering certificates') help="Directory where the key and certificate will be stored.")
_('-d', '--dir', default='/etc/re6stnet', _('-r', '--req', nargs=2, action='append', metavar=('KEY', 'VALUE'),
help='Directory where the key and certificate will be stored') help="The registry only sets the Common Name of your certificate,"
_('-r', '--req', nargs=2, action='append', " which actually encodes your allocated prefix in the network."
help='Name and value of certificate request additional arguments') " You can repeat this option to add any field you want to its"
_('--email', help='Your email address') " subject.")
_('--token', help='The token you received') _('--email',
help="Email address where your token is sent. Use -r option if you"
" want to show an email in your certificate.")
_('--token', help="The token you received.")
config = parser.parse_args() config = parser.parse_args()
if config.dir: if config.dir:
os.chdir(config.dir) os.chdir(config.dir)
...@@ -36,45 +44,60 @@ def main(): ...@@ -36,45 +44,60 @@ def main():
s = xmlrpclib.ServerProxy(config.registry) s = xmlrpclib.ServerProxy(config.registry)
# Get CA # Get CA
ca = s.getCa() create(ca_path, s.getCa())
create(ca_path, ca)
if config.ca_only: if config.ca_only:
sys.exit() sys.exit()
# Get token # Generating dh file
if not os.access(dh_path, os.F_OK):
r = subprocess.call(('openssl', 'dhparam', '-out', dh_path, '2048'))
if r:
sys.exit(r)
req = crypto.X509Req()
subj = req.get_subject()
if config.req:
for k, v in config.req:
if k == 'CN':
sys.exit("CN field is reserved.")
setattr(subj, k, v)
cert_fd = token_advice = None
try:
if not config.token: if not config.token:
if not config.email: if not config.email:
config.email = raw_input('Please enter your email address : ') config.email = raw_input('Please enter your email address: ')
_ = s.requestToken(config.email) s.requestToken(config.email)
config.token = raw_input('Please enter your token : ') token_advice = "Use --token to retry without asking a new token\n"
config.token = raw_input('Please enter your token: ')
# Generate key and cert request # First make sure we can store private key and open certificate file
# for writing, to avoid using our token for nothing.
print "Generating key and cert requests ..."
cert_fd = create(cert_path)
pkey = crypto.PKey() pkey = crypto.PKey()
pkey.generate_key(crypto.TYPE_RSA, 2048) pkey.generate_key(crypto.TYPE_RSA, 2048)
key = crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey) key = crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)
req = crypto.X509Req()
subj = req.get_subject()
if config.req:
for arg in config.req:
setattr(subj, arg[0], arg[1])
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)
# Get certificate
cert = s.requestCertificate(config.token, req)
# Store cert and key
create(key_path, key, 0600) create(key_path, key, 0600)
create(cert_path, cert) print "Requesting certificate ..."
cert = s.requestCertificate(config.token, req)
# Generating dh file if not cert:
if not os.access(dh_path, os.F_OK): token_advice = None
r = subprocess.call(('openssl', 'dhparam', '-out', dh_path, '2048')) sys.exit("Error: invalid or expired token")
if r: except:
sys.exit(r) if cert_fd:
os.remove(cert_path)
if token_advice:
atexit.register(sys.stdout.write, token_advice)
raise
os.write(cert_fd, cert)
os.close(cert_fd)
print "Certificate setup complete." print "Certificate setup complete."
......
...@@ -50,26 +50,35 @@ class main(object): ...@@ -50,26 +50,35 @@ class main(object):
# Command line parsing # Command line parsing
parser = utils.ArgParser(fromfile_prefix_chars='@', parser = utils.ArgParser(fromfile_prefix_chars='@',
description='Peer discovery http server for re6stnet') description="re6stnet registry used to bootstrap nodes"
" and deliver certificates.")
_ = parser.add_argument _ = parser.add_argument
_('--port', type=int, default=80, help='Port of the host server') _('--port', type=int, default=80,
_('--db', required=True, help="Port on which the server will listen.")
help='Path to database file') _('-4', dest='bind4', default='0.0.0.0',
_('--ca', required=True, help="Bind server to this IPv4.")
help='Path to ca.crt file') _('-6', dest='bind6', default='::',
help="Bind server to this IPv6.")
_('--db', default='/var/lib/re6stnet/registry.db',
help="Path to SQLite database file. It is automatically initialized"
" if the file does not exist.")
_('--ca', required=True, help=parser._ca_help)
_('--key', required=True, _('--key', required=True,
help='Path to certificate key') help="CA private key in .pem format.")
_('--mailhost', required=True, _('--mailhost', required=True,
help='SMTP server mail host; for debugging purpose, it can also' help="SMTP host to send confirmation emails. For debugging"
' be an absolute or existing path to a mailbox file') " purpose, it can also be an absolute or existing path to"
" a mailbox file")
_('--private', _('--private',
help='VPN IP of the node on which runs the registry') help="re6stnet IP of the node on which runs the registry."
" Required for normal operation.")
_('--prefix-length', default=16, _('--prefix-length', default=16,
help='Default length of allocated prefixes') help="Default length of allocated prefixes.")
_('-l', '--logfile', default='/var/log/re6stnet/registry.log', _('-l', '--logfile', default='/var/log/re6stnet/registry.log',
help='Path to logging file') help="Path to logging file.")
_('-v', '--verbose', default=1, type=int, _('-v', '--verbose', default=1, type=int,
help='Log level') help="Log level. 0 disables logging."
" Use SIGUSR1 to reopen log.")
self.config = parser.parse_args() self.config = parser.parse_args()
utils.setupLog(self.config.verbose, self.config.logfile) utils.setupLog(self.config.verbose, self.config.logfile)
...@@ -82,6 +91,7 @@ class main(object): ...@@ -82,6 +91,7 @@ class main(object):
'check you configuration') 'check you configuration')
# Database initializing # Database initializing
utils.makedirs(os.path.dirname(self.config.db))
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 token ( self.db.execute("""CREATE TABLE IF NOT EXISTS token (
token text primary key not null, token text primary key not null,
...@@ -111,15 +121,24 @@ class main(object): ...@@ -111,15 +121,24 @@ class main(object):
self._email = self.ca.get_subject().emailAddress self._email = self.ca.get_subject().emailAddress
# Starting server # Starting server
server4 = SimpleXMLRPCServer4(('0.0.0.0', self.config.port), requestHandler=RequestHandler, allow_none=True) server_list = []
if self.config.bind4:
server4 = SimpleXMLRPCServer4((self.config.bind4, self.config.port),
requestHandler=RequestHandler, allow_none=True)
server4.register_instance(self) server4.register_instance(self)
server6 = SimpleXMLRPCServer6(('::', self.config.port), requestHandler=RequestHandler, allow_none=True) server_list.append(server4)
if self.config.bind6:
server6 = SimpleXMLRPCServer6((self.config.bind6, self.config.port),
requestHandler=RequestHandler, allow_none=True)
server6.register_instance(self) server6.register_instance(self)
server_list.append(server6)
# Main loop if len(server_list) == 1:
server_list[0].serve_forever()
else:
while True: while True:
try: try:
r = select.select([server4, server6], [], [])[0] r = select.select(server_list[:], [], [])[0]
except select.error as e: except select.error as e:
if e.args[0] != errno.EINTR: if e.args[0] != errno.EINTR:
raise raise
...@@ -183,8 +202,7 @@ class main(object): ...@@ -183,8 +202,7 @@ class main(object):
try: try:
token, email, prefix_len, _ = self.db.execute("SELECT * FROM token WHERE token = ?", (token,)).next() token, email, prefix_len, _ = self.db.execute("SELECT * FROM token WHERE token = ?", (token,)).next()
except StopIteration: except StopIteration:
logging.exception('Bad token (%s) in request', token) return
raise
self.db.execute("DELETE FROM token WHERE token = ?", (token,)) self.db.execute("DELETE FROM token WHERE token = ?", (token,))
# Get a new prefix # Get a new prefix
......
import argparse, errno, logging, os, signal, struct, socket, time import argparse, errno, logging, os, signal, struct, socket, textwrap, time
from OpenSSL import crypto from OpenSSL import crypto
logging_levels = logging.WARNING, logging.INFO, logging.DEBUG, 5 logging_levels = logging.WARNING, logging.INFO, logging.DEBUG, 5
...@@ -44,8 +44,38 @@ def setupLog(log_level, filename=None, **kw): ...@@ -44,8 +44,38 @@ def setupLog(log_level, filename=None, **kw):
logging.addLevelName(5, 'TRACE') logging.addLevelName(5, 'TRACE')
logging.trace = lambda *args, **kw: logging.log(5, *args, **kw) logging.trace = lambda *args, **kw: logging.log(5, *args, **kw)
class HelpFormatter(argparse.ArgumentDefaultsHelpFormatter):
def _get_help_string(self, action):
return super(HelpFormatter, self)._get_help_string(action) \
if action.default else action.help
def _split_lines(self, text, width):
"""Preserves new lines in option descriptions"""
lines = []
for text in text.splitlines():
lines += textwrap.wrap(text, width)
return lines
def _fill_text(self, text, width, indent):
"""Preserves new lines in other descriptions"""
kw = dict(width=width, initial_indent=indent, subsequent_indent=indent)
return '\n'.join(textwrap.fill(t, **kw) for t in text.splitlines())
class ArgParser(argparse.ArgumentParser): class ArgParser(argparse.ArgumentParser):
class _HelpFormatter(HelpFormatter):
def _format_actions_usage(self, actions, groups):
r = HelpFormatter._format_actions_usage(self, actions, groups)
if actions and actions[0].option_strings:
r = '[@OPTIONS_FILE] ' + r
return r
_ca_help = "Certificate authority (CA) file in .pem format." \
" Serial number defines the prefix of the network."
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:
...@@ -56,6 +86,13 @@ class ArgParser(argparse.ArgumentParser): ...@@ -56,6 +86,13 @@ class ArgParser(argparse.ArgumentParser):
if arg.strip(): if arg.strip():
yield arg yield arg
def __init__(self, **kw):
super(ArgParser, self).__init__(formatter_class=self._HelpFormatter,
epilog="""Options can be read from a file. For example:
$ cat OPTIONS_FILE
ca /etc/re6stnet/ca.crt""", **kw)
def makedirs(path): def makedirs(path):
try: try:
os.makedirs(path) os.makedirs(path)
......
...@@ -18,56 +18,75 @@ def ovpnArgs(optional_args, ca_path, cert_path, key_path): ...@@ -18,56 +18,75 @@ def ovpnArgs(optional_args, ca_path, cert_path, key_path):
def getConfig(): def getConfig():
parser = utils.ArgParser(fromfile_prefix_chars='@', parser = utils.ArgParser(fromfile_prefix_chars='@',
description='Resilient virtual private network application') description="Resilient virtual private network application.")
_ = parser.add_argument _ = parser.add_argument
# General Configuration options
_('--ip', _('--ip',
help='IP address advertised to other nodes') help="IP address advertised to other nodes. Special values:\n"
_('--registry', required=True, "- upnp: force autoconfiguration via UPnP\n"
help="HTTP URL of the discovery peer server," "- any: ask peers our IP\n"
" with public host (default port: 80)") " (default: ask peers if UPnP fails)")
_('--registry', required=True, metavar='URL',
help="Public HTTP URL of the registry, for bootstrapping.")
_('-l', '--log', default='/var/log/re6stnet', _('-l', '--log', default='/var/log/re6stnet',
help='Path to re6stnet logs directory') help="Path to the directory used for log files:\n"
"- re6stnet.log: log file of re6stnet itself\n"
"- babeld.log: log file of router\n"
"- <iface>.log: 1 file per spawned OpenVPN\n")
_('-s', '--state', default='/var/lib/re6stnet', _('-s', '--state', default='/var/lib/re6stnet',
help='Path to re6stnet state directory') help="Path to re6stnet state directory:\n"
_('-v', '--verbose', default=1, type=int, "- peers.db: cache of peer addresses\n"
help='Log level of re6stnet itself') "- babeld.state: see option -S of babeld\n")
_('-v', '--verbose', default=1, type=int, metavar='LEVEL',
help="Log level of re6stnet itself. 0 disables logging."
" Use SIGUSR1 to reopen log."
" See also --babel-verb and --verb for logs of spawned processes.")
_('-i', '--interface', action='append', dest='iface_list', default=[], _('-i', '--interface', action='append', dest='iface_list', default=[],
help='Extra interface for LAN discovery') help="Extra interface for LAN discovery. Highly recommanded if there"
" are other re6st node on the same network segment.")
# Routing algorithm options
_('--babel-pidfile', _ = parser.add_argument_group('routing').add_argument
help='Specify a file to write our process id to') _('--babel-pidfile', metavar='PID',
_('--babel-verb', default=0, help="Specify a file to write our process id to"
help='Babel verbosity') " (option -I of Babel).")
_('--babel-verb', default=0, metavar='LEVEL',
help="Log level of Babel (option -d of Babel).")
_('--hello', type=int, default=15, _('--hello', type=int, default=15,
help='Hello interval for babel, in seconds') help="Hello interval in seconds, for both wired and wireless"
" connections. OpenVPN ping-exit option is set to 4 times the"
" hello interval. It takes between 3 and 4 times the"
" hello interval for Babel to re-establish connection with a"
" node for which the direct connection has been cut.")
_('-w', '--wireless', action='store_true', _('-w', '--wireless', action='store_true',
help='''Set all interfaces to be treated as wireless interfaces help="Assume all interfaces are wireless (option -w of Babel).")
for the routing protocol''')
# Tunnel options _ = parser.add_argument_group('tunnelling').add_argument
_('--encrypt', action='store_true', _('--encrypt', action='store_true',
help='specify that tunnels should be encrypted') help='Specify that tunnels should be encrypted.')
_('--pp', nargs=2, action='append', _('--pp', nargs=2, action='append', metavar=('PORT', 'PROTO'),
help='Port and protocol to be used by other peers to connect') help="Port and protocol to be announced to other peers, ordered by"
" preference. For each protocol (either udp or tcp), start one"
" openvpn server on the first given port."
" (default: --pp 1194 udp --pp 1194 tcp)")
_('--dh', required=True, _('--dh', required=True,
help='Path to dh file') help='File containing Diffie-Hellman parameters in .pem format')
_('--ca', required=True, _('--ca', required=True, help=parser._ca_help)
help='Path to the certificate authority file')
_('--cert', required=True, _('--cert', required=True,
help='Path to the certificate file') help="Local peer's signed certificate in .pem format."
" Common name defines the allocated prefix in the network.")
_('--key', required=True, _('--key', required=True,
help='Path to the private key file') help="Local peer's private key in .pem format.")
_('--connection-count', default=20, type=int, _('--connection-count', default=20, type=int,
help='Number of tunnels') help="Maximum number of accepted clients per OpenVPN server."
" Also represents the average number of tunnels to peers.")
_('--tunnel-refresh', default=300, type=int, _('--tunnel-refresh', default=300, type=int,
help='time (seconds) to wait before changing the connections') help="Interval in seconds between two tunnel refresh: the worst"
" tunnel is closed if the number of client tunnels has reached"
" its maximum number (half of connection-count).")
# Openvpn options
_('openvpn_args', nargs=argparse.REMAINDER, _('openvpn_args', nargs=argparse.REMAINDER,
help="Common OpenVPN options") help="Use pseudo-argument '--' to forward positional arguments as extra"
" arguments to both server and client OpenVPN subprocesses.")
return parser.parse_args() return parser.parse_args()
......
...@@ -8,6 +8,7 @@ Environment :: Console ...@@ -8,6 +8,7 @@ Environment :: Console
License :: OSI Approved :: GNU General Public License (GPL) License :: OSI Approved :: GNU General Public License (GPL)
Natural Language :: English Natural Language :: English
Operating System :: POSIX :: Linux Operating System :: POSIX :: Linux
Programming Language :: Python :: 2.6
Programming Language :: Python :: 2.7 Programming Language :: Python :: 2.7
Topic :: Internet Topic :: Internet
Topic :: System :: Networking Topic :: System :: Networking
......
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