re6st-registry 6.11 KB
Newer Older
1
#!/usr/bin/python
2
import httplib, logging, socket
3 4 5
from BaseHTTPServer import BaseHTTPRequestHandler
from SocketServer import ThreadingTCPServer
from urlparse import parse_qsl
6
from re6st import ctl, registry, utils, version
7

8
# To generate server ca and key with serial for 2001:db8:42::/48
9
#  openssl req -nodes -new -x509 -key ca.key -set_serial 0x120010db80042 -days 3650 -out ca.crt
10 11 12 13 14

IPV6_V6ONLY = 26
SOL_IPV6 = 41


15
class RequestHandler(BaseHTTPRequestHandler):
Guillaume Bury's avatar
Guillaume Bury committed
16

17 18
    if __import__("sys").version_info < (2, 7, 4):
      def address_string(self):
Julien Muchembled's avatar
Julien Muchembled committed
19 20 21
        # Workaround for http://bugs.python.org/issue6085
        return self.client_address[0]

22 23 24 25 26 27 28 29 30 31 32
    def do_GET(self):
        try:
            try:
                path, query = self.path.split('?', 1)
            except ValueError:
                path = self.path
                query = {}
            else:
                query = dict(parse_qsl(query, keep_blank_values=1,
                                              strict_parsing=1))
            _, path = path.split('/')
33 34
            if not _:
                return self.server.handle_request(self, path, query)
35 36 37 38 39 40 41
        except Exception:
            logging.info(self.requestline, exc_info=1)
        self.send_error(httplib.BAD_REQUEST)

    def log_error(*args):
        pass

Guillaume Bury's avatar
Guillaume Bury committed
42

43
class HTTPServer4(ThreadingTCPServer):
44 45

    allow_reuse_address = True
46
    daemon_threads = True
47

48

49
class HTTPServer6(HTTPServer4):
50 51 52 53 54

    address_family = socket.AF_INET6

    def server_bind(self):
        self.socket.setsockopt(SOL_IPV6, IPV6_V6ONLY, 1)
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
        HTTPServer4.server_bind(self)


def main():
    parser = utils.ArgParser(fromfile_prefix_chars='@',
        description="re6stnet registry used to bootstrap nodes"
                    " and deliver certificates.")
    _ = parser.add_argument
    _('--port', type=int, default=80,
        help="Port on which the server will listen.")
    _('-4', dest='bind4', default='0.0.0.0',
        help="Bind server to this IPv4.")
    _('-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.")
72 73
    _('--dh',
        help='File containing Diffie-Hellman parameters in .pem format')
74 75 76 77 78 79 80 81 82 83 84 85
    _('--ca', required=True, help=parser._ca_help)
    _('--key', required=True,
            help="CA private key in .pem format.")
    _('--mailhost', required=True,
            help="SMTP host to send confirmation emails. For debugging"
                 " purpose, it can also be an absolute or existing path to"
                 " a mailbox file")
    _('--prefix-length', default=16, type=int,
            help="Default length of allocated prefixes.")
    _('--anonymous-prefix-length', type=int,
            help="Length of allocated anonymous prefixes."
                 " If 0 or unset, registration by email is required")
86 87 88
    _('--ipv4', nargs=2, metavar=("IP/N", "PLEN"),
        help="Enable ipv4. Each node is assigned a subnet of length PLEN"
             " inside network IP/N.")
89 90
    _('-l', '--logfile', default='/var/log/re6stnet/registry.log',
            help="Path to logging file.")
91 92 93
    _('-r', '--run', default='/var/run/re6stnet',
        help="Path to re6stnet runtime directory:\n"
             "- babeld.sock (option -R of babeld)\n")
94 95 96
    _('-v', '--verbose', default=1, type=int,
            help="Log level. 0 disables logging."
                 " Use SIGUSR1 to reopen log.")
97 98 99
    _('--min-protocol', default=version.min_protocol, type=int,
        help="Reject nodes that are too old. Current is %s." % version.protocol)

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
    _ = parser.add_argument_group('routing').add_argument
    _('--hello', type=int, default=15,
        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.")

    _ = parser.add_argument_group('tunnelling').add_argument
    _('--encrypt', action='store_true',
        help='Specify that tunnels should be encrypted.')
    _('--client-count', default=10, type=int,
        help="Number of client tunnels to set up.")
    _('--max-clients', type=int,
        help="Maximum number of accepted clients per OpenVPN server. (default:"
             " client-count * 2, which actually represents the average number"
             " of tunnels to other peers)")
    _('--tunnel-refresh', default=300, type=int,
        help="Interval in seconds between two tunnel refresh: the worst"
             " tunnel is closed if the number of client tunnels has reached"
             " its maximum number (client-count).")

122 123
    config = parser.parse_args()

124 125 126 127
    if not version.min_protocol <= config.min_protocol <= version.protocol:
        parser.error("--min-protocol: value must between %s and %s (included)"
                     % (version.min_protocol, version.protocol))

128 129 130 131 132 133 134 135 136
    if config.ipv4:
        ipv4, plen = config.ipv4
        try:
            ip, n = ipv4.split('/')
            config.ipv4 = "%s/%s" % (socket.inet_ntoa(socket.inet_aton(ip)),
                                     int(n)), int(plen)
        except (socket.error, ValueError):
            parser.error("invalid argument --ipv4")

137 138
    utils.setupLog(config.verbose, config.logfile)

139 140 141
    if config.max_clients is None:
        config.max_clients = config.client_count * 2

142 143 144 145
    server = registry.RegistryServer(config)
    def requestHandler(request, client_address, _):
        RequestHandler(request, client_address, server)

146
    server_dict = {}
147
    if config.bind4:
148 149
        r = HTTPServer4((config.bind4, config.port), requestHandler)
        server_dict[r.fileno()] = r._handle_request_noblock
150
    if config.bind6:
151 152 153
        r = HTTPServer6((config.bind6, config.port), requestHandler)
        server_dict[r.fileno()] = r._handle_request_noblock
    if server_dict:
154
        while True:
155
            args = server_dict.copy(), {}, []
156 157
            server.select(*args)
            utils.select(*args)
158

159

160 161
if __name__ == "__main__":
    main()