#!/usr/bin/python import errno, httplib, logging, select, socket from BaseHTTPServer import BaseHTTPRequestHandler from SocketServer import ThreadingTCPServer from urlparse import parse_qsl from re6st import registry, utils # To generate server ca and key with serial for 2001:db8:42::/48 # openssl req -nodes -new -x509 -key ca.key -set_serial 0x120010db80042 -days 3650 -out ca.crt # TODO: There is currently no mechanism so that client automatically get # a renewed CA certificate. IPV6_V6ONLY = 26 SOL_IPV6 = 41 class RequestHandler(BaseHTTPRequestHandler): def address_string(self): # Workaround for http://bugs.python.org/issue6085 return self.client_address[0] 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('/') if not _ and path[0] != '_': return self.server._handle_request(self, path, query) except Exception: logging.info(self.requestline, exc_info=1) self.send_error(httplib.BAD_REQUEST) def log_error(*args): pass class HTTPServer4(ThreadingTCPServer): allow_reuse_address = True daemon_threads = True class HTTPServer6(HTTPServer4): address_family = socket.AF_INET6 def server_bind(self): self.socket.setsockopt(SOL_IPV6, IPV6_V6ONLY, 1) 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.") _('--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") _('--private', help="re6stnet IP of the node on which runs the registry." " Required for normal operation.") _('--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") _('-l', '--logfile', default='/var/log/re6stnet/registry.log', help="Path to logging file.") _('-v', '--verbose', default=1, type=int, help="Log level. 0 disables logging." " Use SIGUSR1 to reopen log.") config = parser.parse_args() utils.setupLog(config.verbose, config.logfile) server = registry.RegistryServer(config) def requestHandler(request, client_address, _): RequestHandler(request, client_address, server) server_list = [] if config.bind4: server_list.append(HTTPServer4((config.bind4, config.port), requestHandler)) if config.bind6: server_list.append(HTTPServer6((config.bind6, config.port), requestHandler)) if server_list: empty_list = [] while True: try: r = select.select(server_list[:], empty_list, empty_list)[0] except select.error as e: if e.args[0] != errno.EINTR: raise else: for r in r: r._handle_request_noblock() if __name__ == "__main__": main()