diff options
Diffstat (limited to 'rpki')
-rw-r--r-- | rpki/http_simple.py | 78 | ||||
-rw-r--r-- | rpki/irdbd.py | 18 | ||||
-rw-r--r-- | rpki/old_irdbd.py | 25 | ||||
-rw-r--r-- | rpki/pubd.py | 41 | ||||
-rw-r--r-- | rpki/publication_control.py | 52 | ||||
-rw-r--r-- | rpki/xml_utils.py | 14 |
6 files changed, 138 insertions, 90 deletions
diff --git a/rpki/http_simple.py b/rpki/http_simple.py new file mode 100644 index 00000000..d50fd993 --- /dev/null +++ b/rpki/http_simple.py @@ -0,0 +1,78 @@ +# $Id$ + +# Copyright (C) 2014 Dragon Research Labs ("DRL") +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND DRL DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL DRL BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +""" +HTTP using Python standard libraries, for RPKI programs that don't +need the full-blown rpki.http asynchronous code. +""" + +import logging +import BaseHTTPServer + +logger = logging.getLogger(__name__) + + +rpki_content_type = "application/x-rpki" + + +class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): + """ + HTTP request handler simple RPKI servers. + """ + + def do_POST(self): + try: + content_type = self.headers.get("Content-Type") + content_length = self.headers.get("Content-Length") + if content_type != rpki_content_type: + self.send_error(415, "No handler for Content-Type %s" % content_type) + else: + for prefix, handler in self.rpki_handlers: + if self.path.startswith(prefix): + handler(self, (self.rfile.read() + if content_length is None else + self.rfile.read(int(content_length)))) + break + else: + self.send_error(404, "No handler for path %s" % self.path) + except Exception, e: + logger.exception("Unhandled exception") + self.send_error(501, "Unhandled exception") + + def send_cms_response(self, der): + self.send_response(200) + self.send_header("Content-Type", rpki_content_type) + self.send_header("Content-Length", str(len(der))) + self.end_headers() + self.wfile.write(der) + + def log_message(self, *args): + # Might want to use LogAdapter for connection info here? + logger.info(*args) + + +def server(handlers, port, host = ""): + """ + Run an HTTP server and wait (forever) for connections. + """ + + if not isinstance(handlers, (tuple, list)): + handlers = (("/", handlers),) + + class RequestHandler(HTTPRequestHandler): + rpki_handlers = handlers + + BaseHTTPServer.HTTPServer((host, port), RequestHandler).serve_forever() diff --git a/rpki/irdbd.py b/rpki/irdbd.py index d53ae67c..bfc48d87 100644 --- a/rpki/irdbd.py +++ b/rpki/irdbd.py @@ -26,7 +26,7 @@ import time import logging import argparse import urlparse -import rpki.http +import rpki.http_simple import rpki.config import rpki.resource_set import rpki.relaxng @@ -104,7 +104,7 @@ class main(object): r_pdu.pkcs10 = ee_req.pkcs10 r_msg.append(r_pdu) - def handler(self, query, path, cb): + def handler(self, request, q_der): try: q_pdu = None r_msg = rpki.left_right.msg.reply() @@ -114,15 +114,13 @@ class main(object): serverCA = rpki.irdb.ServerCA.objects.get() rpkid = serverCA.ee_certificates.get(purpose = "rpkid") try: - q_cms = rpki.left_right.cms_msg(DER = query) + q_cms = rpki.left_right.cms_msg(DER = q_der) q_msg = q_cms.unwrap((serverCA.certificate, rpkid.certificate)) - self.cms_timestamp = q_cms.check_replay(self.cms_timestamp, path) + self.cms_timestamp = q_cms.check_replay(self.cms_timestamp, request.path) if not isinstance(q_msg, rpki.left_right.msg) or not q_msg.is_query(): raise rpki.exceptions.BadQuery("Unexpected %r PDU" % q_msg) for q_pdu in q_msg: self.dispatch(q_pdu, r_msg) - except (rpki.async.ExitNow, SystemExit): - raise except Exception, e: logger.exception("Exception while handling HTTP request") if q_pdu is None: @@ -130,12 +128,10 @@ class main(object): else: r_msg.append(rpki.left_right.report_error_elt.from_exception(e, q_pdu.self_handle, q_pdu.tag)) irdbd = serverCA.ee_certificates.get(purpose = "irdbd") - cb(200, body = rpki.left_right.cms_msg().wrap(r_msg, irdbd.private_key, irdbd.certificate)) - except (rpki.async.ExitNow, SystemExit): - raise + request.send_cms_response(rpki.left_right.cms_msg().wrap(r_msg, irdbd.private_key, irdbd.certificate)) except Exception, e: logger.exception("Unhandled exception while processing HTTP request") - cb(500, reason = "Unhandled exception %s: %s" % (e.__class__.__name__, e)) + request.send_error(500, "Unhandled exception %s: %s" % (e.__class__.__name__, e)) def dispatch(self, q_pdu, r_msg): try: @@ -261,7 +257,7 @@ class main(object): self.cms_timestamp = None - rpki.http.server( + rpki.http_simple.server( host = self.http_server_host, port = self.http_server_port, handlers = self.handler) diff --git a/rpki/old_irdbd.py b/rpki/old_irdbd.py index 6c026a31..a2ce4e94 100644 --- a/rpki/old_irdbd.py +++ b/rpki/old_irdbd.py @@ -30,7 +30,7 @@ import time import logging import argparse import urlparse -import rpki.http +import rpki.http_simple import rpki.config import rpki.resource_set import rpki.relaxng @@ -226,7 +226,7 @@ class main(object): rpki.left_right.list_ghostbuster_requests_elt : handle_list_ghostbuster_requests, rpki.left_right.list_ee_certificate_requests_elt : handle_list_ee_certificate_requests } - def handler(self, query, path, cb): + def handler(self, request, q_der): try: self.db.ping(True) @@ -235,7 +235,7 @@ class main(object): try: - q_msg = rpki.left_right.cms_msg(DER = query).unwrap((self.bpki_ta, self.rpkid_cert)) + q_msg = rpki.left_right.cms_msg(DER = q_der).unwrap((self.bpki_ta, self.rpkid_cert)) if not isinstance(q_msg, rpki.left_right.msg) or not q_msg.is_query(): raise rpki.exceptions.BadQuery("Unexpected %r PDU" % q_msg) @@ -251,28 +251,19 @@ class main(object): else: h(self, q_pdu, r_msg) - except (rpki.async.ExitNow, SystemExit): - raise - except Exception, e: logger.exception("Exception serving PDU %r", q_pdu) r_msg.append(rpki.left_right.report_error_elt.from_exception(e, q_pdu.self_handle, q_pdu.tag)) - except (rpki.async.ExitNow, SystemExit): - raise - except Exception, e: logger.exception("Exception decoding query") r_msg.append(rpki.left_right.report_error_elt.from_exception(e)) - cb(200, body = rpki.left_right.cms_msg().wrap(r_msg, self.irdbd_key, self.irdbd_cert)) - - except (rpki.async.ExitNow, SystemExit): - raise + request.send_cms_response(rpki.left_right.cms_msg().wrap(r_msg, self.irdbd_key, self.irdbd_cert)) except Exception, e: logger.exception("Unhandled exception, returning HTTP failure") - cb(500, reason = "Unhandled exception %s: %s" % (e.__class__.__name__, e)) + request.send_error(500, "Unhandled exception %s: %s" % (e.__class__.__name__, e)) def __init__(self): @@ -319,6 +310,6 @@ class main(object): u.query == "" and \ u.fragment == "" - rpki.http.server(host = u.hostname or "localhost", - port = u.port or 443, - handlers = ((u.path, self.handler),)) + rpki.http_simple.server(host = u.hostname or "localhost", + port = u.port or 443, + handlers = ((u.path, self.handler),)) diff --git a/rpki/pubd.py b/rpki/pubd.py index b6788ebd..a2f996b6 100644 --- a/rpki/pubd.py +++ b/rpki/pubd.py @@ -28,11 +28,11 @@ import time import socket import logging import argparse + import rpki.resource_set import rpki.up_down import rpki.x509 import rpki.sql -import rpki.http import rpki.config import rpki.exceptions import rpki.relaxng @@ -40,6 +40,7 @@ import rpki.log import rpki.publication import rpki.publication_control import rpki.daemonize +import rpki.http_simple from lxml.etree import Element, SubElement, tostring as ElementToString @@ -50,6 +51,8 @@ rrdp_xmlns = rpki.relaxng.rrdp.xmlns rrdp_nsmap = rpki.relaxng.rrdp.nsmap rrdp_version = "1" +rpki_content_type = "application/x-rpki" + def DERSubElement(elt, name, der, attrib = None, **kwargs): """ @@ -133,7 +136,7 @@ class main(object): self.session = session_obj.fetch(self) - rpki.http.server( + rpki.http_simple.server( host = self.http_server_host, port = self.http_server_port, handlers = (("/control", self.control_handler), @@ -144,44 +147,41 @@ class main(object): return "%s/%s" % (self.rrdp_uri_base.rstrip("/"), fn) - def control_handler(self, query, path, cb): + def control_handler(self, request, q_der): """ Process one PDU from the IRBE. """ def done(r_msg): self.sql.sweep() - cb(code = 200, - body = rpki.publication_control.cms_msg().wrap(r_msg, self.pubd_key, self.pubd_cert)) + request.send_cms_response(rpki.publication_control.cms_msg().wrap(r_msg, self.pubd_key, self.pubd_cert)) try: - q_cms = rpki.publication_control.cms_msg(DER = query) + q_cms = rpki.publication_control.cms_msg(DER = q_der) q_msg = q_cms.unwrap((self.bpki_ta, self.irbe_cert)) self.irbe_cms_timestamp = q_cms.check_replay(self.irbe_cms_timestamp, "control") q_msg.serve_top_level(self, done) - except (rpki.async.ExitNow, SystemExit): - raise except Exception, e: - logger.exception("Unhandled exception processing control query, path %r", path) - cb(code = 500, reason = "Unhandled exception %s: %s" % (e.__class__.__name__, e)) + logger.exception("Unhandled exception processing control query, path %r", request.path) + request.send_error(500, "Unhandled exception %s: %s" % (e.__class__.__name__, e)) client_url_regexp = re.compile("/client/([-A-Z0-9_/]+)$", re.I) - def client_handler(self, query, path, cb): + def client_handler(self, request, q_der): """ Process one PDU from a client. """ try: - match = self.client_url_regexp.search(path) + match = self.client_url_regexp.search(request.path) if match is None: - raise rpki.exceptions.BadContactURL("Bad path: %s" % path) + raise rpki.exceptions.BadContactURL("Bad path: %s" % request.path) client_handle = match.group(1) client = rpki.publication_control.client_elt.sql_fetch_where1(self, "client_handle = %s", (client_handle,)) if client is None: raise rpki.exceptions.ClientNotFound("Could not find client %s" % client_handle) - q_cms = rpki.publication.cms_msg(DER = query) + q_cms = rpki.publication.cms_msg(DER = q_der) q_msg = q_cms.unwrap((self.bpki_ta, client.bpki_cert, client.bpki_glue)) q_cms.check_replay_sql(client, client.client_handle) if not q_msg.is_query(): @@ -209,8 +209,6 @@ class main(object): r_pdu.tag = q_pdu.tag r_pdu.uri = q_pdu.uri r_msg.append(r_pdu) - except (rpki.async.ExitNow, SystemExit): - raise except Exception, e: if not isinstance(e, rpki.exceptions.NotFound): logger.exception("Exception processing PDU %r", q_pdu) @@ -246,14 +244,11 @@ class main(object): # database of record. This may require doing the filesystem # updates from the delta, but that should be straightforward. - cb(code = 200, - body = rpki.publication.cms_msg().wrap(r_msg, self.pubd_key, self.pubd_cert, self.pubd_crl)) - except (rpki.async.ExitNow, SystemExit): - raise + request.send_cms_response(rpki.publication.cms_msg().wrap(r_msg, self.pubd_key, self.pubd_cert, self.pubd_crl)) + except Exception, e: - logger.exception("Unhandled exception processing client query, path %r", path) - cb(code = 500, - reason = "Could not process PDU: %s" % e) + logger.exception("Unhandled exception processing client query, path %r", request.path) + request.send_error(500, "Could not process PDU: %s" % e) def uri_to_filename(self, uri): """ diff --git a/rpki/publication_control.py b/rpki/publication_control.py index 95751336..ab56f95f 100644 --- a/rpki/publication_control.py +++ b/rpki/publication_control.py @@ -1,32 +1,21 @@ # $Id$ # -# Copyright (C) 2009--2012 Internet Systems Consortium ("ISC") -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, -# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -# PERFORMANCE OF THIS SOFTWARE. -# +# Copyright (C) 2013--2014 Dragon Research Labs ("DRL") +# Portions copyright (C) 2009--2012 Internet Systems Consortium ("ISC") # Portions copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. +# copyright notices and this permission notice appear in all copies. # -# THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT, -# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -# PERFORMANCE OF THIS SOFTWARE. +# THE SOFTWARE IS PROVIDED "AS IS" AND DRL, ISC, AND ARIN DISCLAIM ALL +# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL, +# ISC, OR ARIN BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """ RPKI publication control protocol. @@ -208,26 +197,25 @@ class msg(rpki.xml_utils.msg, publication_control_namespace): raise rpki.exceptions.BadQuery("Message type is not query") r_msg = self.__class__.reply() - def loop(iterator, q_pdu): + for q_pdu in self: + + def next(): + # Relic of asynch I/O structure, clean up eventually + pass def fail(e): if not isinstance(e, rpki.exceptions.NotFound): logger.exception("Exception processing PDU %r", q_pdu) r_msg.append(report_error_elt.from_exception(e, q_pdu.tag)) - cb(r_msg) + return cb(r_msg) try: q_pdu.gctx = gctx - q_pdu.serve_dispatch(r_msg, iterator, fail) - except (rpki.async.ExitNow, SystemExit): - raise + q_pdu.serve_dispatch(r_msg, next, fail) except Exception, e: - fail(e) - - def done(): - cb(r_msg) + return fail(e) - rpki.async.iterator(self, loop, done) + return cb(r_msg) class sax_handler(rpki.xml_utils.sax_handler): diff --git a/rpki/xml_utils.py b/rpki/xml_utils.py index 3a7b919a..9b443d0b 100644 --- a/rpki/xml_utils.py +++ b/rpki/xml_utils.py @@ -32,11 +32,15 @@ XML utilities. """ +import logging import xml.sax import lxml.sax import lxml.etree import rpki.exceptions +logger = logging.getLogger(__name__) + + class sax_handler(xml.sax.handler.ContentHandler): """ SAX handler for RPKI protocols. @@ -435,14 +439,10 @@ class data_elt(base_elt): Action dispatch handler. """ - dispatch = { "create" : self.serve_create, - "set" : self.serve_set, - "get" : self.serve_get, - "list" : self.serve_list, - "destroy" : self.serve_destroy } - if self.action not in dispatch: + method = getattr(self, "serve_" + self.action, None) + if method is None: raise rpki.exceptions.BadQuery("Unexpected query: action %s" % self.action) - dispatch[self.action](r_msg, cb, eb) + method(r_msg, cb, eb) def unimplemented_control(self, *controls): """ |