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