00001 """ 00002 RPKI publication engine. 00003 00004 Usage: python pubd.py [ { -c | --config } configfile ] 00005 [ { -h | --help } ] 00006 [ { -p | --profile } outputfile ] 00007 00008 Default configuration file is pubd.conf, override with --config option. 00009 00010 $Id: pubd.py 3449 2010-09-16 21:30:30Z sra $ 00011 00012 Copyright (C) 2009--2010 Internet Systems Consortium ("ISC") 00013 00014 Permission to use, copy, modify, and distribute this software for any 00015 purpose with or without fee is hereby granted, provided that the above 00016 copyright notice and this permission notice appear in all copies. 00017 00018 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 00019 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 00020 AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 00021 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 00022 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 00023 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00024 PERFORMANCE OF THIS SOFTWARE. 00025 00026 Portions copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") 00027 00028 Permission to use, copy, modify, and distribute this software for any 00029 purpose with or without fee is hereby granted, provided that the above 00030 copyright notice and this permission notice appear in all copies. 00031 00032 THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH 00033 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 00034 AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT, 00035 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 00036 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 00037 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00038 PERFORMANCE OF THIS SOFTWARE. 00039 """ 00040 00041 import os, time, getopt, sys, re 00042 import rpki.resource_set, rpki.up_down, rpki.x509, rpki.sql 00043 import rpki.http, rpki.config, rpki.exceptions, rpki.relaxng 00044 import rpki.log, rpki.publication 00045 00046 class pubd_context(object): 00047 """ 00048 A container for various pubd parameters. 00049 """ 00050 00051 def __init__(self, cfg): 00052 00053 self.sql = rpki.sql.session(cfg) 00054 00055 self.bpki_ta = rpki.x509.X509(Auto_update = cfg.get("bpki-ta")) 00056 self.irbe_cert = rpki.x509.X509(Auto_update = cfg.get("irbe-cert")) 00057 self.pubd_cert = rpki.x509.X509(Auto_update = cfg.get("pubd-cert")) 00058 self.pubd_key = rpki.x509.RSA( Auto_update = cfg.get("pubd-key")) 00059 00060 self.http_server_host = cfg.get("server-host", "") 00061 self.http_server_port = int(cfg.get("server-port", "4434")) 00062 00063 self.publication_base = cfg.get("publication-base", "publication/") 00064 00065 self.publication_multimodule = cfg.getboolean("publication-multimodule", False) 00066 00067 def handler_common(self, query, client, cb, certs, crl = None): 00068 """ 00069 Common PDU handler code. 00070 """ 00071 00072 def done(r_msg): 00073 reply = rpki.publication.cms_msg().wrap(r_msg, self.pubd_key, self.pubd_cert, crl) 00074 self.sql.sweep() 00075 cb(reply) 00076 00077 q_msg = rpki.publication.cms_msg(DER = query).unwrap(certs) 00078 q_msg.serve_top_level(self, client, done) 00079 00080 def control_handler(self, query, path, cb): 00081 """ 00082 Process one PDU from the IRBE. 00083 """ 00084 00085 def done(x): 00086 cb(200, x) 00087 00088 rpki.log.trace() 00089 try: 00090 self.sql.ping() 00091 self.handler_common(query, None, done, (self.bpki_ta, self.irbe_cert)) 00092 except (rpki.async.ExitNow, SystemExit): 00093 raise 00094 except Exception, data: 00095 rpki.log.traceback() 00096 cb(500, "Unhandled exception %s" % data) 00097 00098 client_url_regexp = re.compile("/client/([-A-Z0-9_/]+)$", re.I) 00099 00100 def client_handler(self, query, path, cb): 00101 """ 00102 Process one PDU from a client. 00103 """ 00104 00105 def done(x): 00106 cb(200, x) 00107 00108 rpki.log.trace() 00109 try: 00110 self.sql.ping() 00111 match = self.client_url_regexp.search(path) 00112 if match is None: 00113 raise rpki.exceptions.BadContactURL, "Bad path: %s" % path 00114 client_handle = match.group(1) 00115 client = rpki.publication.client_elt.sql_fetch_where1(self, "client_handle = %s", (client_handle,)) 00116 if client is None: 00117 raise rpki.exceptions.ClientNotFound, "Could not find client %s" % client_handle 00118 config = rpki.publication.config_elt.fetch(self) 00119 if config is None or config.bpki_crl is None: 00120 raise rpki.exceptions.CMSCRLNotSet 00121 self.handler_common(query, client, done, (self.bpki_ta, client.bpki_cert, client.bpki_glue), config.bpki_crl) 00122 except (rpki.async.ExitNow, SystemExit): 00123 raise 00124 except Exception, data: 00125 rpki.log.traceback() 00126 cb(500, "Could not process PDU: %s" % data) 00127 00128 os.environ["TZ"] = "UTC" 00129 time.tzset() 00130 00131 cfg_file = "pubd.conf" 00132 profile = False 00133 00134 opts, argv = getopt.getopt(sys.argv[1:], "c:dhp:?", ["config=", "debug", "help"]) 00135 for o, a in opts: 00136 if o in ("-h", "--help", "-?"): 00137 print __doc__ 00138 sys.exit(0) 00139 elif o in ("-c", "--config"): 00140 cfg_file = a 00141 elif o in ("-d", "--debug"): 00142 rpki.log.use_syslog = False 00143 elif o in ("-p", "--profile"): 00144 profile = a 00145 if argv: 00146 raise rpki.exceptions.CommandParseFailure, "Unexpected arguments %s" % argv 00147 00148 rpki.log.init("pubd") 00149 00150 def main(): 00151 00152 cfg = rpki.config.parser(cfg_file, "pubd") 00153 00154 if profile: 00155 rpki.log.info("Running in profile mode with output to %s" % profile) 00156 00157 cfg.set_global_flags() 00158 00159 pctx = pubd_context(cfg) 00160 00161 rpki.http.server( 00162 host = pctx.http_server_host, 00163 port = pctx.http_server_port, 00164 handlers = (("/control", pctx.control_handler), 00165 ("/client/", pctx.client_handler))) 00166 00167 if profile: 00168 import cProfile 00169 cProfile.run("main()", profile) 00170 else: 00171 main()