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 2573 2009-07-04 20:24:08Z 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, 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 not q_msg.is_query():
00117 raise rpki.exceptions.BadQuery, "Unexpected %s PDU" % repr(q_msg)
00118
00119 r_msg = rpki.left_right.msg.reply()
00120
00121 for q_pdu in q_msg:
00122
00123 try:
00124 if type(q_pdu) in handle_dispatch:
00125 handle_dispatch[type(q_pdu)](q_pdu, r_msg)
00126 else:
00127 raise rpki.exceptions.BadQuery, "Unexpected %s PDU" % repr(q_pdu)
00128
00129 except Exception, data:
00130 rpki.log.traceback()
00131 r_msg.append(rpki.left_right.report_error_elt.from_exception(data, q_pdu.self_handle, q_pdu.tag))
00132
00133 cb(200, rpki.left_right.cms_msg.wrap(r_msg, irdbd_key, irdbd_cert))
00134
00135 except (rpki.async.ExitNow, SystemExit):
00136 raise
00137
00138 except Exception, data:
00139 rpki.log.traceback()
00140
00141
00142
00143
00144 cb(500, "Unhandled exception %s: %s" % (data.__class__.__name__, data))
00145
00146 os.environ["TZ"] = "UTC"
00147 time.tzset()
00148
00149 rpki.log.init("irdbd")
00150
00151 cfg_file = "irdbd.conf"
00152
00153 opts, argv = getopt.getopt(sys.argv[1:], "c:h?", ["config=", "help"])
00154 for o, a in opts:
00155 if o in ("-h", "--help", "-?"):
00156 print __doc__
00157 sys.exit(0)
00158 if o in ("-c", "--config"):
00159 cfg_file = a
00160 if argv:
00161 raise RuntimeError, "Unexpected arguments %s" % argv
00162
00163 cfg = rpki.config.parser(cfg_file, "irdbd")
00164
00165 startup_msg = cfg.get("startup-message", "")
00166 if startup_msg:
00167 rpki.log.info(startup_msg)
00168
00169 db = MySQLdb.connect(user = cfg.get("sql-username"),
00170 db = cfg.get("sql-database"),
00171 passwd = cfg.get("sql-password"))
00172
00173 cur = db.cursor()
00174 db.autocommit(True)
00175
00176 bpki_ta = rpki.x509.X509(Auto_file = cfg.get("bpki-ta"))
00177 rpkid_cert = rpki.x509.X509(Auto_file = cfg.get("rpkid-cert"))
00178 irdbd_cert = rpki.x509.X509(Auto_file = cfg.get("irdbd-cert"))
00179 irdbd_key = rpki.x509.RSA( Auto_file = cfg.get("irdbd-key"))
00180
00181 u = urlparse.urlparse(cfg.get("https-url"))
00182
00183 assert u.scheme in ("", "https") and \
00184 u.username is None and \
00185 u.password is None and \
00186 u.params == "" and \
00187 u.query == "" and \
00188 u.fragment == ""
00189
00190 rpki.https.server(server_key = irdbd_key,
00191 server_cert = irdbd_cert,
00192 client_ta = (bpki_ta, rpkid_cert),
00193 host = u.hostname or "localhost",
00194 port = u.port or 443,
00195 handlers = ((u.path, handler),))