RPKI Engine  1.0
irdbd.py (4014)
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 4014 2011-10-05 16:30:24Z 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 import sys, os, time, getopt, urlparse, warnings
00038 import rpki.http, rpki.config, rpki.resource_set, rpki.relaxng
00039 import rpki.exceptions, rpki.left_right, rpki.log, rpki.x509
00040 
00041 from rpki.mysql_import import MySQLdb
00042 
00043 class main(object):
00044 
00045 
00046   def handle_list_resources(self, q_pdu, r_msg):
00047 
00048     r_pdu = rpki.left_right.list_resources_elt()
00049     r_pdu.tag = q_pdu.tag
00050     r_pdu.self_handle = q_pdu.self_handle
00051     r_pdu.child_handle = q_pdu.child_handle
00052 
00053     self.cur.execute(
00054       "SELECT registrant_id, valid_until FROM registrant WHERE registry_handle = %s AND registrant_handle = %s",
00055       (q_pdu.self_handle, q_pdu.child_handle))
00056 
00057     if self.cur.rowcount != 1:
00058       raise rpki.exceptions.NotInDatabase, \
00059             "This query should have produced a single exact match, something's messed up (rowcount = %d, self_handle = %s, child_handle = %s)" \
00060             % (self.cur.rowcount, q_pdu.self_handle, q_pdu.child_handle)
00061 
00062     registrant_id, valid_until = self.cur.fetchone()
00063 
00064     r_pdu.valid_until = valid_until.strftime("%Y-%m-%dT%H:%M:%SZ")
00065 
00066     r_pdu.asn  = rpki.resource_set.resource_set_as.from_sql(
00067       self.cur,
00068       "SELECT start_as, end_as FROM registrant_asn WHERE registrant_id = %s",
00069       (registrant_id,))
00070 
00071     r_pdu.ipv4 = rpki.resource_set.resource_set_ipv4.from_sql(
00072       self.cur,
00073       "SELECT start_ip, end_ip FROM registrant_net WHERE registrant_id = %s AND version = 4",
00074       (registrant_id,))
00075 
00076     r_pdu.ipv6 = rpki.resource_set.resource_set_ipv6.from_sql(
00077       self.cur,
00078       "SELECT start_ip, end_ip FROM registrant_net WHERE registrant_id = %s AND version = 6",
00079       (registrant_id,))
00080 
00081     r_msg.append(r_pdu)
00082 
00083 
00084   def handle_list_roa_requests(self, q_pdu, r_msg):
00085 
00086     self.cur.execute(
00087       "SELECT roa_request_id, asn FROM roa_request WHERE roa_request_handle = %s",
00088       (q_pdu.self_handle,))
00089 
00090     for roa_request_id, asn in self.cur.fetchall():
00091 
00092       r_pdu = rpki.left_right.list_roa_requests_elt()
00093       r_pdu.tag = q_pdu.tag
00094       r_pdu.self_handle = q_pdu.self_handle
00095       r_pdu.asn = asn
00096 
00097       r_pdu.ipv4 = rpki.resource_set.roa_prefix_set_ipv4.from_sql(
00098         self.cur,
00099         "SELECT prefix, prefixlen, max_prefixlen FROM roa_request_prefix WHERE roa_request_id = %s AND version = 4",
00100         (roa_request_id,))
00101 
00102       r_pdu.ipv6 = rpki.resource_set.roa_prefix_set_ipv6.from_sql(
00103         self.cur,
00104         "SELECT prefix, prefixlen, max_prefixlen FROM roa_request_prefix WHERE roa_request_id = %s AND version = 6",
00105         (roa_request_id,))
00106 
00107       r_msg.append(r_pdu)
00108 
00109 
00110   def handle_list_ghostbuster_requests(self, q_pdu, r_msg):
00111 
00112     self.cur.execute(
00113       "SELECT vcard  FROM ghostbuster_request WHERE self_handle = %s AND parent_handle = %s",
00114       (q_pdu.self_handle, q_pdu.parent_handle))
00115 
00116     vcards = [result[0] for result in self.cur.fetchall()]
00117 
00118     if not vcards:
00119 
00120       self.cur.execute(
00121         "SELECT vcard  FROM ghostbuster_request WHERE self_handle = %s AND parent_handle IS NULL",
00122         (q_pdu.self_handle,))
00123 
00124       vcards = [result[0] for result in self.cur.fetchall()]
00125 
00126     for vcard in vcards:
00127       r_pdu = rpki.left_right.list_ghostbuster_requests_elt()
00128       r_pdu.tag = q_pdu.tag
00129       r_pdu.self_handle = q_pdu.self_handle
00130       r_pdu.parent_handle = q_pdu.parent_handle
00131       r_pdu.vcard = vcard
00132       r_msg.append(r_pdu)
00133 
00134 
00135   handle_dispatch = {
00136     rpki.left_right.list_resources_elt            : handle_list_resources,
00137     rpki.left_right.list_roa_requests_elt         : handle_list_roa_requests,
00138     rpki.left_right.list_ghostbuster_requests_elt : handle_list_ghostbuster_requests}
00139 
00140 
00141   def handler(self, query, path, cb):
00142     try:
00143 
00144       self.db.ping(True)
00145 
00146       r_msg = rpki.left_right.msg.reply()
00147 
00148       try:
00149 
00150         q_msg = rpki.left_right.cms_msg(DER = query).unwrap((self.bpki_ta, self.rpkid_cert))
00151 
00152         if not isinstance(q_msg, rpki.left_right.msg) or not q_msg.is_query():
00153           raise rpki.exceptions.BadQuery, "Unexpected %r PDU" % q_msg
00154 
00155         for q_pdu in q_msg:
00156 
00157           try:
00158 
00159             try:
00160               h = self.handle_dispatch[type(q_pdu)]
00161             except KeyError:
00162               raise rpki.exceptions.BadQuery, "Unexpected %r PDU" % q_pdu
00163             else:
00164               h(self, q_pdu, r_msg)
00165 
00166           except (rpki.async.ExitNow, SystemExit):
00167             raise
00168 
00169           except Exception, e:
00170             rpki.log.traceback()
00171             r_msg.append(rpki.left_right.report_error_elt.from_exception(e, q_pdu.self_handle, q_pdu.tag))
00172 
00173       except (rpki.async.ExitNow, SystemExit):
00174         raise
00175 
00176       except Exception, e:
00177         rpki.log.traceback()
00178         r_msg.append(rpki.left_right.report_error_elt.from_exception(e))
00179 
00180       cb(200, body = rpki.left_right.cms_msg().wrap(r_msg, self.irdbd_key, self.irdbd_cert))
00181 
00182     except (rpki.async.ExitNow, SystemExit):
00183       raise
00184 
00185     except Exception, e:
00186       rpki.log.traceback()
00187 
00188       # We only get here in cases where we couldn't or wouldn't generate
00189       # <report_error/>, so just return HTTP failure.
00190 
00191       cb(500, reason = "Unhandled exception %s: %s" % (e.__class__.__name__, e))
00192 
00193 
00194   def __init__(self):
00195 
00196     os.environ["TZ"] = "UTC"
00197     time.tzset()
00198 
00199     cfg_file = None
00200 
00201     opts, argv = getopt.getopt(sys.argv[1:], "c:dh?", ["config=", "debug", "help"])
00202     for o, a in opts:
00203       if o in ("-h", "--help", "-?"):
00204         print __doc__
00205         sys.exit(0)
00206       if o in ("-c", "--config"):
00207         cfg_file = a
00208       elif o in ("-d", "--debug"):
00209         rpki.log.use_syslog = False
00210     if argv:
00211       raise rpki.exceptions.CommandParseFailure, "Unexpected arguments %s" % argv
00212 
00213     rpki.log.init("irdbd")
00214 
00215     self.cfg = rpki.config.parser(cfg_file, "irdbd")
00216 
00217     startup_msg = self.cfg.get("startup-message", "")
00218     if startup_msg:
00219       rpki.log.info(startup_msg)
00220 
00221     self.cfg.set_global_flags()
00222 
00223     self.db = MySQLdb.connect(user   = self.cfg.get("sql-username"),
00224                               db     = self.cfg.get("sql-database"),
00225                               passwd = self.cfg.get("sql-password"))
00226 
00227     self.cur = self.db.cursor()
00228     self.db.autocommit(True)
00229 
00230     self.bpki_ta         = rpki.x509.X509(Auto_update = self.cfg.get("bpki-ta"))
00231     self.rpkid_cert      = rpki.x509.X509(Auto_update = self.cfg.get("rpkid-cert"))
00232     self.irdbd_cert      = rpki.x509.X509(Auto_update = self.cfg.get("irdbd-cert"))
00233     self.irdbd_key       = rpki.x509.RSA( Auto_update = self.cfg.get("irdbd-key"))
00234 
00235     u = urlparse.urlparse(self.cfg.get("http-url"))
00236 
00237     assert u.scheme in ("", "http") and \
00238            u.username is None and \
00239            u.password is None and \
00240            u.params   == "" and \
00241            u.query    == "" and \
00242            u.fragment == ""
00243 
00244     rpki.http.server(host         = u.hostname or "localhost",
00245                      port         = u.port or 443,
00246                      handlers     = ((u.path, self.handler),))
 All Classes Namespaces Files Functions Variables Properties