RPKI Engine 1.0

irdbd.py (3793)

Go to the documentation of this file.
00001 """
00002 IR database daemon.
00003 
00004 Usage: python irdbd.py [ { -c | --config } configfile ] [ { -h | --help } ]
00005 
00006 $Id: irdbd.py 3793 2011-04-27 04:34:52Z sra $
00007 
00008 Copyright (C) 2009--2011  Internet Systems Consortium ("ISC")
00009 
00010 Permission to use, copy, modify, and distribute this software for any
00011 purpose with or without fee is hereby granted, provided that the above
00012 copyright notice and this permission notice appear in all copies.
00013 
00014 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00015 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00016 AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00017 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00018 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00019 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00020 PERFORMANCE OF THIS SOFTWARE.
00021 
00022 Portions copyright (C) 2007--2008  American Registry for Internet Numbers ("ARIN")
00023 
00024 Permission to use, copy, modify, and distribute this software for any
00025 purpose with or without fee is hereby granted, provided that the above
00026 copyright notice and this permission notice appear in all copies.
00027 
00028 THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH
00029 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00030 AND FITNESS.  IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT,
00031 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00032 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00033 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00034 PERFORMANCE OF THIS SOFTWARE.
00035 """
00036 
00037 from __future__ import with_statement
00038 
00039 import sys, os, time, getopt, urlparse, warnings
00040 import rpki.http, rpki.config, rpki.resource_set, rpki.relaxng
00041 import rpki.exceptions, rpki.left_right, rpki.log, rpki.x509
00042 
00043 # Silence warning while loading MySQLdb in Python 2.6, sigh
00044 if hasattr(warnings, "catch_warnings"):
00045   with warnings.catch_warnings():
00046     warnings.simplefilter("ignore", DeprecationWarning)
00047     import MySQLdb
00048 else:
00049   import MySQLdb
00050 
00051 class main(object):
00052 
00053 
00054   def handle_list_resources(self, q_pdu, r_msg):
00055 
00056     r_pdu = rpki.left_right.list_resources_elt()
00057     r_pdu.tag = q_pdu.tag
00058     r_pdu.self_handle = q_pdu.self_handle
00059     r_pdu.child_handle = q_pdu.child_handle
00060 
00061     self.cur.execute(
00062       "SELECT registrant_id, valid_until FROM registrant WHERE registry_handle = %s AND registrant_handle = %s",
00063       (q_pdu.self_handle, q_pdu.child_handle))
00064 
00065     if self.cur.rowcount != 1:
00066       raise rpki.exceptions.NotInDatabase, \
00067             "This query should have produced a single exact match, something's messed up (rowcount = %d, self_handle = %s, child_handle = %s)" \
00068             % (self.cur.rowcount, q_pdu.self_handle, q_pdu.child_handle)
00069 
00070     registrant_id, valid_until = self.cur.fetchone()
00071 
00072     r_pdu.valid_until = valid_until.strftime("%Y-%m-%dT%H:%M:%SZ")
00073 
00074     r_pdu.asn  = rpki.resource_set.resource_set_as.from_sql(
00075       self.cur,
00076       "SELECT start_as, end_as FROM registrant_asn WHERE registrant_id = %s",
00077       (registrant_id,))
00078 
00079     r_pdu.ipv4 = rpki.resource_set.resource_set_ipv4.from_sql(
00080       self.cur,
00081       "SELECT start_ip, end_ip FROM registrant_net WHERE registrant_id = %s AND version = 4",
00082       (registrant_id,))
00083 
00084     r_pdu.ipv6 = rpki.resource_set.resource_set_ipv6.from_sql(
00085       self.cur,
00086       "SELECT start_ip, end_ip FROM registrant_net WHERE registrant_id = %s AND version = 6",
00087       (registrant_id,))
00088 
00089     r_msg.append(r_pdu)
00090 
00091 
00092   def handle_list_roa_requests(self, q_pdu, r_msg):
00093 
00094     self.cur.execute(
00095       "SELECT roa_request_id, asn FROM roa_request WHERE roa_request_handle = %s",
00096       (q_pdu.self_handle,))
00097 
00098     for roa_request_id, asn in self.cur.fetchall():
00099 
00100       r_pdu = rpki.left_right.list_roa_requests_elt()
00101       r_pdu.tag = q_pdu.tag
00102       r_pdu.self_handle = q_pdu.self_handle
00103       r_pdu.asn = asn
00104 
00105       r_pdu.ipv4 = rpki.resource_set.roa_prefix_set_ipv4.from_sql(
00106         self.cur,
00107         "SELECT prefix, prefixlen, max_prefixlen FROM roa_request_prefix WHERE roa_request_id = %s AND version = 4",
00108         (roa_request_id,))
00109 
00110       r_pdu.ipv6 = rpki.resource_set.roa_prefix_set_ipv6.from_sql(
00111         self.cur,
00112         "SELECT prefix, prefixlen, max_prefixlen FROM roa_request_prefix WHERE roa_request_id = %s AND version = 6",
00113         (roa_request_id,))
00114 
00115       r_msg.append(r_pdu)
00116 
00117 
00118   def handle_list_ghostbuster_requests(self, q_pdu, r_msg):
00119 
00120     self.cur.execute(
00121       "SELECT vcard  FROM ghostbuster_request WHERE self_handle = %s AND parent_handle = %s",
00122       (q_pdu.self_handle, q_pdu.parent_handle))
00123 
00124     vcards = [result[0] for result in self.cur.fetchall()]
00125 
00126     if not vcards:
00127 
00128       self.cur.execute(
00129         "SELECT vcard  FROM ghostbuster_request WHERE self_handle = %s AND parent_handle IS NULL",
00130         (q_pdu.self_handle,))
00131 
00132       vcards = [result[0] for result in self.cur.fetchall()]
00133 
00134     for vcard in vcards:
00135       r_pdu = rpki.left_right.list_ghostbuster_requests_elt()
00136       r_pdu.tag = q_pdu.tag
00137       r_pdu.self_handle = q_pdu.self_handle
00138       r_pdu.parent_handle = q_pdu.parent_handle
00139       r_pdu.vcard = vcard
00140       r_msg.append(r_pdu)
00141 
00142 
00143   handle_dispatch = {
00144     rpki.left_right.list_resources_elt            : handle_list_resources,
00145     rpki.left_right.list_roa_requests_elt         : handle_list_roa_requests,
00146     rpki.left_right.list_ghostbuster_requests_elt : handle_list_ghostbuster_requests}
00147 
00148 
00149   def handler(self, query, path, cb):
00150     try:
00151 
00152       self.db.ping(True)
00153 
00154       r_msg = rpki.left_right.msg.reply()
00155 
00156       try:
00157 
00158         q_msg = rpki.left_right.cms_msg(DER = query).unwrap((self.bpki_ta, self.rpkid_cert))
00159 
00160         if not isinstance(q_msg, rpki.left_right.msg) or not q_msg.is_query():
00161           raise rpki.exceptions.BadQuery, "Unexpected %r PDU" % q_msg
00162 
00163         for q_pdu in q_msg:
00164 
00165           try:
00166 
00167             try:
00168               h = self.handle_dispatch[type(q_pdu)]
00169             except KeyError:
00170               raise rpki.exceptions.BadQuery, "Unexpected %r PDU" % q_pdu
00171             else:
00172               h(self, q_pdu, r_msg)
00173 
00174           except (rpki.async.ExitNow, SystemExit):
00175             raise
00176 
00177           except Exception, data:
00178             rpki.log.traceback()
00179             r_msg.append(rpki.left_right.report_error_elt.from_exception(data, q_pdu.self_handle, q_pdu.tag))
00180 
00181       except (rpki.async.ExitNow, SystemExit):
00182         raise
00183 
00184       except Exception, data:
00185         rpki.log.traceback()
00186         r_msg.append(rpki.left_right.report_error_elt.from_exception(data))
00187 
00188       cb(200, body = rpki.left_right.cms_msg().wrap(r_msg, self.irdbd_key, self.irdbd_cert))
00189 
00190     except (rpki.async.ExitNow, SystemExit):
00191       raise
00192 
00193     except Exception, data:
00194       rpki.log.traceback()
00195 
00196       # We only get here in cases where we couldn't or wouldn't generate
00197       # <report_error/>, so just return HTTP failure.
00198 
00199       cb(500, reason = "Unhandled exception %s: %s" % (data.__class__.__name__, data))
00200 
00201 
00202   def __init__(self):
00203 
00204     os.environ["TZ"] = "UTC"
00205     time.tzset()
00206 
00207     cfg_file = None
00208 
00209     opts, argv = getopt.getopt(sys.argv[1:], "c:dh?", ["config=", "debug", "help"])
00210     for o, a in opts:
00211       if o in ("-h", "--help", "-?"):
00212         print __doc__
00213         sys.exit(0)
00214       if o in ("-c", "--config"):
00215         cfg_file = a
00216       elif o in ("-d", "--debug"):
00217         rpki.log.use_syslog = False
00218     if argv:
00219       raise rpki.exceptions.CommandParseFailure, "Unexpected arguments %s" % argv
00220 
00221     rpki.log.init("irdbd")
00222 
00223     self.cfg = rpki.config.parser(cfg_file, "irdbd")
00224 
00225     startup_msg = self.cfg.get("startup-message", "")
00226     if startup_msg:
00227       rpki.log.info(startup_msg)
00228 
00229     self.cfg.set_global_flags()
00230 
00231     self.db = MySQLdb.connect(user   = self.cfg.get("sql-username"),
00232                               db     = self.cfg.get("sql-database"),
00233                               passwd = self.cfg.get("sql-password"))
00234 
00235     self.cur = self.db.cursor()
00236     self.db.autocommit(True)
00237 
00238     self.bpki_ta         = rpki.x509.X509(Auto_update = self.cfg.get("bpki-ta"))
00239     self.rpkid_cert      = rpki.x509.X509(Auto_update = self.cfg.get("rpkid-cert"))
00240     self.irdbd_cert      = rpki.x509.X509(Auto_update = self.cfg.get("irdbd-cert"))
00241     self.irdbd_key       = rpki.x509.RSA( Auto_update = self.cfg.get("irdbd-key"))
00242 
00243     u = urlparse.urlparse(self.cfg.get("http-url"))
00244 
00245     assert u.scheme in ("", "http") and \
00246            u.username is None and \
00247            u.password is None and \
00248            u.params   == "" and \
00249            u.query    == "" and \
00250            u.fragment == ""
00251 
00252     rpki.http.server(host         = u.hostname or "localhost",
00253                      port         = u.port or 443,
00254                      handlers     = ((u.path, self.handler),))
 All Classes Namespaces Files Functions Variables