00001 """
00002 IR database daemon.
00003
00004 Usage: python irdbd.py [ { -c | --config } configfile ] [ { -h | --help } ]
00005
00006 Default configuration file is irdbd.conf, override with --config option.
00007
00008 $Id: irdbd.py 2510 2009-06-09 20:25:16Z sra $
00009
00010 Copyright (C) 2009 Internet Systems Consortium ("ISC")
00011
00012 Permission to use, copy, modify, and distribute this software for any
00013 purpose with or without fee is hereby granted, provided that the above
00014 copyright notice and this permission notice appear in all copies.
00015
00016 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00017 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00018 AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00019 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00020 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00021 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00022 PERFORMANCE OF THIS SOFTWARE.
00023
00024 Portions copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN")
00025
00026 Permission to use, copy, modify, and distribute this software for any
00027 purpose with or without fee is hereby granted, provided that the above
00028 copyright notice and this permission notice appear in all copies.
00029
00030 THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH
00031 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00032 AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT,
00033 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00034 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00035 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00036 PERFORMANCE OF THIS SOFTWARE.
00037 """
00038
00039 import sys, os, time, getopt, urlparse, traceback, MySQLdb
00040 import rpki.https, rpki.config, rpki.resource_set, rpki.relaxng
00041 import rpki.exceptions, rpki.left_right, rpki.log, rpki.x509
00042
00043 def handle_list_resources(q_pdu, r_msg):
00044
00045 r_pdu = rpki.left_right.list_resources_elt()
00046 r_pdu.tag = q_pdu.tag
00047 r_pdu.self_handle = q_pdu.self_handle
00048 r_pdu.child_handle = q_pdu.child_handle
00049
00050 cur.execute(
00051 "SELECT registrant_id, valid_until FROM registrant WHERE registry_handle = %s AND registrant_handle = %s",
00052 (q_pdu.self_handle, q_pdu.child_handle))
00053
00054 if cur.rowcount != 1:
00055 raise rpki.exceptions.NotInDatabase, \
00056 "This query should have produced a single exact match, something's messed up (rowcount = %d, self_handle = %s, child_handle = %s)" \
00057 % (cur.rowcount, q_pdu.self_handle, q_pdu.child_handle)
00058
00059 registrant_id, valid_until = cur.fetchone()
00060
00061 r_pdu.valid_until = valid_until.strftime("%Y-%m-%dT%H:%M:%SZ")
00062
00063 r_pdu.asn = rpki.resource_set.resource_set_as.from_sql(
00064 cur,
00065 "SELECT start_as, end_as FROM registrant_asn WHERE registrant_id = %s",
00066 (registrant_id,))
00067
00068 r_pdu.ipv4 = rpki.resource_set.resource_set_ipv4.from_sql(
00069 cur,
00070 "SELECT start_ip, end_ip FROM registrant_net WHERE registrant_id = %s AND version = 4",
00071 (registrant_id,))
00072
00073 r_pdu.ipv6 = rpki.resource_set.resource_set_ipv6.from_sql(
00074 cur,
00075 "SELECT start_ip, end_ip FROM registrant_net WHERE registrant_id = %s AND version = 6",
00076 (registrant_id,))
00077
00078 r_msg.append(r_pdu)
00079
00080 def handle_list_roa_requests(q_pdu, r_msg):
00081
00082 cur.execute(
00083 "SELECT roa_request_id, asn FROM roa_request WHERE roa_request_handle = %s",
00084 (q_pdu.self_handle,))
00085
00086 for roa_request_id, asn in cur.fetchmany():
00087
00088 r_pdu = rpki.left_right.list_roa_requests_elt()
00089 r_pdu.tag = q_pdu.tag
00090 r_pdu.self_handle = q_pdu.self_handle
00091 r_pdu.asn = asn
00092
00093 r_pdu.ipv4 = rpki.resource_set.roa_prefix_set_ipv4.from_sql(
00094 cur,
00095 "SELECT prefix, prefixlen, max_prefixlen FROM roa_request_prefix WHERE roa_request_id = %s AND version = 4",
00096 (roa_request_id,))
00097
00098 r_pdu.ipv6 = rpki.resource_set.roa_prefix_set_ipv6.from_sql(
00099 cur,
00100 "SELECT prefix, prefixlen, max_prefixlen FROM roa_request_prefix WHERE roa_request_id = %s AND version = 6",
00101 (roa_request_id,))
00102
00103 r_msg.append(r_pdu)
00104
00105 handle_dispatch = {
00106 rpki.left_right.list_resources_elt : handle_list_resources,
00107 rpki.left_right.list_roa_requests_elt : handle_list_roa_requests }
00108
00109 def handler(query, path, cb):
00110 try:
00111
00112 db.ping()
00113
00114 q_msg = rpki.left_right.cms_msg.unwrap(query, (bpki_ta, rpkid_cert))
00115
00116 if not isinstance(q_msg, rpki.left_right.msg) or q_msg.type != "query":
00117 raise rpki.exceptions.BadQuery, "Unexpected %s PDU" % repr(q_msg)
00118
00119 r_msg = rpki.left_right.msg()
00120 r_msg.type = "reply"
00121
00122 for q_pdu in q_msg:
00123
00124 try:
00125 if type(q_pdu) in handle_dispatch:
00126 handle_dispatch[type(q_pdu)](q_pdu, r_msg)
00127 else:
00128 raise rpki.exceptions.BadQuery, "Unexpected %s PDU" % repr(q_pdu)
00129
00130 except Exception, data:
00131 rpki.log.error(traceback.format_exc())
00132 r_msg.append(rpki.left_right.report_error_elt.from_exception(data, q_pdu.self_handle))
00133
00134 cb(200, rpki.left_right.cms_msg.wrap(r_msg, irdbd_key, irdbd_cert))
00135
00136 except (rpki.async.ExitNow, SystemExit):
00137 raise
00138
00139 except Exception, data:
00140 rpki.log.error(traceback.format_exc())
00141
00142
00143
00144
00145 cb(500, "Unhandled exception %s: %s" % (data.__class__.__name__, data))
00146
00147 os.environ["TZ"] = "UTC"
00148 time.tzset()
00149
00150 rpki.log.init("irdbd")
00151
00152 cfg_file = "irdbd.conf"
00153
00154 opts, argv = getopt.getopt(sys.argv[1:], "c:h?", ["config=", "help"])
00155 for o, a in opts:
00156 if o in ("-h", "--help", "-?"):
00157 print __doc__
00158 sys.exit(0)
00159 if o in ("-c", "--config"):
00160 cfg_file = a
00161 if argv:
00162 raise RuntimeError, "Unexpected arguments %s" % argv
00163
00164 cfg = rpki.config.parser(cfg_file, "irdbd")
00165
00166 startup_msg = cfg.get("startup-message", "")
00167 if startup_msg:
00168 rpki.log.info(startup_msg)
00169
00170 db = MySQLdb.connect(user = cfg.get("sql-username"),
00171 db = cfg.get("sql-database"),
00172 passwd = cfg.get("sql-password"))
00173
00174 cur = db.cursor()
00175 db.autocommit(True)
00176
00177 bpki_ta = rpki.x509.X509(Auto_file = cfg.get("bpki-ta"))
00178 rpkid_cert = rpki.x509.X509(Auto_file = cfg.get("rpkid-cert"))
00179 irdbd_cert = rpki.x509.X509(Auto_file = cfg.get("irdbd-cert"))
00180 irdbd_key = rpki.x509.RSA( Auto_file = cfg.get("irdbd-key"))
00181
00182 u = urlparse.urlparse(cfg.get("https-url"))
00183
00184 assert u.scheme in ("", "https") and \
00185 u.username is None and \
00186 u.password is None and \
00187 u.params == "" and \
00188 u.query == "" and \
00189 u.fragment == ""
00190
00191 rpki.https.server(server_key = irdbd_key,
00192 server_cert = irdbd_cert,
00193 client_ta = (bpki_ta, rpkid_cert),
00194 host = u.hostname or "localhost",
00195 port = u.port or 443,
00196 handlers = ((u.path, handler),))