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