Update TODO
[re6stnet.git] / re6st-registry
1 #!/usr/bin/python
2 import httplib, logging, socket
3 from BaseHTTPServer import BaseHTTPRequestHandler
4 from SocketServer import ThreadingTCPServer
5 from urlparse import parse_qsl
6 from re6st import ctl, registry, utils
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 IPV6_V6ONLY = 26
12 SOL_IPV6 = 41
13
14
15 class RequestHandler(BaseHTTPRequestHandler):
16
17     if __import__("sys").version_info < (2, 7, 4):
18       def address_string(self):
19         # Workaround for http://bugs.python.org/issue6085
20         return self.client_address[0]
21
22     def do_GET(self):
23         try:
24             try:
25                 path, query = self.path.split('?', 1)
26             except ValueError:
27                 path = self.path
28                 query = {}
29             else:
30                 query = dict(parse_qsl(query, keep_blank_values=1,
31                                               strict_parsing=1))
32             _, path = path.split('/')
33             if not _:
34                 return self.server.handle_request(self, path, query)
35         except Exception:
36             logging.info(self.requestline, exc_info=1)
37         self.send_error(httplib.BAD_REQUEST)
38
39     def log_error(*args):
40         pass
41
42
43 class HTTPServer4(ThreadingTCPServer):
44
45     allow_reuse_address = True
46     daemon_threads = True
47
48
49 class HTTPServer6(HTTPServer4):
50
51     address_family = socket.AF_INET6
52
53     def server_bind(self):
54         self.socket.setsockopt(SOL_IPV6, IPV6_V6ONLY, 1)
55         HTTPServer4.server_bind(self)
56
57
58 def main():
59     parser = utils.ArgParser(fromfile_prefix_chars='@',
60         description="re6stnet registry used to bootstrap nodes"
61                     " and deliver certificates.")
62     _ = parser.add_argument
63     _('--port', type=int, default=80,
64         help="Port on which the server will listen.")
65     _('-4', dest='bind4', default='0.0.0.0',
66         help="Bind server to this IPv4.")
67     _('-6', dest='bind6', default='::',
68         help="Bind server to this IPv6.")
69     _('--db', default='/var/lib/re6stnet/registry.db',
70         help="Path to SQLite database file. It is automatically initialized"
71              " if the file does not exist.")
72     _('--ca', required=True, help=parser._ca_help)
73     _('--key', required=True,
74             help="CA private key in .pem format.")
75     _('--mailhost', required=True,
76             help="SMTP host to send confirmation emails. For debugging"
77                  " purpose, it can also be an absolute or existing path to"
78                  " a mailbox file")
79     _('--prefix-length', default=16, type=int,
80             help="Default length of allocated prefixes.")
81     _('--anonymous-prefix-length', type=int,
82             help="Length of allocated anonymous prefixes."
83                  " If 0 or unset, registration by email is required")
84     _('--control-socket', metavar='CTL_SOCK', default=ctl.SOCK_PATH,
85         help="Socket path to use for communication between re6stnet and babeld"
86              " (option -R of Babel).")
87     _('-l', '--logfile', default='/var/log/re6stnet/registry.log',
88             help="Path to logging file.")
89     _('-v', '--verbose', default=1, type=int,
90             help="Log level. 0 disables logging."
91                  " Use SIGUSR1 to reopen log.")
92     config = parser.parse_args()
93
94     utils.setupLog(config.verbose, config.logfile)
95
96     server = registry.RegistryServer(config)
97     def requestHandler(request, client_address, _):
98         RequestHandler(request, client_address, server)
99
100     server_dict = {}
101     if config.bind4:
102         r = HTTPServer4((config.bind4, config.port), requestHandler)
103         server_dict[r.fileno()] = r._handle_request_noblock
104     if config.bind6:
105         r = HTTPServer6((config.bind6, config.port), requestHandler)
106         server_dict[r.fileno()] = r._handle_request_noblock
107     if server_dict:
108         while True:
109             args = server_dict.copy(), {}, []
110             server.select(*args)
111             utils.select(*args)
112
113
114 if __name__ == "__main__":
115     main()