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 2913 2009-12-28 20:55:38Z 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 from __future__ import with_statement
00040
00041 import sys, os, time, getopt, urlparse, warnings
00042 import rpki.https, rpki.config, rpki.resource_set, rpki.relaxng
00043 import rpki.exceptions, rpki.left_right, rpki.log, rpki.x509
00044
00045
00046 if hasattr(warnings, "catch_warnings"):
00047 with warnings.catch_warnings():
00048 warnings.simplefilter("ignore", DeprecationWarning)
00049 import MySQLdb
00050 else:
00051 import MySQLdb
00052
00053 def handle_list_resources(q_pdu, r_msg):
00054
00055 r_pdu = rpki.left_right.list_resources_elt()
00056 r_pdu.tag = q_pdu.tag
00057 r_pdu.self_handle = q_pdu.self_handle
00058 r_pdu.child_handle = q_pdu.child_handle
00059
00060 cur.execute(
00061 "SELECT registrant_id, valid_until FROM registrant WHERE registry_handle = %s AND registrant_handle = %s",
00062 (q_pdu.self_handle, q_pdu.child_handle))
00063
00064 if cur.rowcount != 1:
00065 raise rpki.exceptions.NotInDatabase, \
00066 "This query should have produced a single exact match, something's messed up (rowcount = %d, self_handle = %s, child_handle = %s)" \
00067 % (cur.rowcount, q_pdu.self_handle, q_pdu.child_handle)
00068
00069 registrant_id, valid_until = cur.fetchone()
00070
00071 r_pdu.valid_until = valid_until.strftime("%Y-%m-%dT%H:%M:%SZ")
00072
00073 r_pdu.asn = rpki.resource_set.resource_set_as.from_sql(
00074 cur,
00075 "SELECT start_as, end_as FROM registrant_asn WHERE registrant_id = %s",
00076 (registrant_id,))
00077
00078 r_pdu.ipv4 = rpki.resource_set.resource_set_ipv4.from_sql(
00079 cur,
00080 "SELECT start_ip, end_ip FROM registrant_net WHERE registrant_id = %s AND version = 4",
00081 (registrant_id,))
00082
00083 r_pdu.ipv6 = rpki.resource_set.resource_set_ipv6.from_sql(
00084 cur,
00085 "SELECT start_ip, end_ip FROM registrant_net WHERE registrant_id = %s AND version = 6",
00086 (registrant_id,))
00087
00088 r_msg.append(r_pdu)
00089
00090 def handle_list_roa_requests(q_pdu, r_msg):
00091
00092 cur.execute(
00093 "SELECT roa_request_id, asn FROM roa_request WHERE roa_request_handle = %s",
00094 (q_pdu.self_handle,))
00095
00096 for roa_request_id, asn in cur.fetchall():
00097
00098 r_pdu = rpki.left_right.list_roa_requests_elt()
00099 r_pdu.tag = q_pdu.tag
00100 r_pdu.self_handle = q_pdu.self_handle
00101 r_pdu.asn = asn
00102
00103 r_pdu.ipv4 = rpki.resource_set.roa_prefix_set_ipv4.from_sql(
00104 cur,
00105 "SELECT prefix, prefixlen, max_prefixlen FROM roa_request_prefix WHERE roa_request_id = %s AND version = 4",
00106 (roa_request_id,))
00107
00108 r_pdu.ipv6 = rpki.resource_set.roa_prefix_set_ipv6.from_sql(
00109 cur,
00110 "SELECT prefix, prefixlen, max_prefixlen FROM roa_request_prefix WHERE roa_request_id = %s AND version = 6",
00111 (roa_request_id,))
00112
00113 r_msg.append(r_pdu)
00114
00115 handle_dispatch = {
00116 rpki.left_right.list_resources_elt : handle_list_resources,
00117 rpki.left_right.list_roa_requests_elt : handle_list_roa_requests }
00118
00119 def handler(query, path, cb):
00120 try:
00121
00122 db.ping()
00123
00124 r_msg = rpki.left_right.msg.reply()
00125
00126 try:
00127
00128 q_msg = rpki.left_right.cms_msg.unwrap(query, (bpki_ta, rpkid_cert))
00129
00130 if not isinstance(q_msg, rpki.left_right.msg) or not q_msg.is_query():
00131 raise rpki.exceptions.BadQuery, "Unexpected %r PDU" % q_msg
00132
00133 for q_pdu in q_msg:
00134
00135 try:
00136 if type(q_pdu) not in handle_dispatch:
00137 raise rpki.exceptions.BadQuery, "Unexpected %r PDU" % q_pdu
00138 handle_dispatch[type(q_pdu)](q_pdu, r_msg)
00139
00140 except (rpki.async.ExitNow, SystemExit):
00141 raise
00142
00143 except Exception, data:
00144 rpki.log.traceback()
00145 r_msg.append(rpki.left_right.report_error_elt.from_exception(data, q_pdu.self_handle, q_pdu.tag))
00146
00147 except (rpki.async.ExitNow, SystemExit):
00148 raise
00149
00150 except Exception, data:
00151 rpki.log.traceback()
00152 r_msg.append(rpki.left_right.report_error_elt.from_exception(data))
00153
00154 cb(200, rpki.left_right.cms_msg.wrap(r_msg, irdbd_key, irdbd_cert))
00155
00156 except (rpki.async.ExitNow, SystemExit):
00157 raise
00158
00159 except Exception, data:
00160 rpki.log.traceback()
00161
00162
00163
00164
00165 cb(500, "Unhandled exception %s: %s" % (data.__class__.__name__, data))
00166
00167 os.environ["TZ"] = "UTC"
00168 time.tzset()
00169
00170 cfg_file = "irdbd.conf"
00171
00172 opts, argv = getopt.getopt(sys.argv[1:], "c:dh?", ["config=", "debug", "help"])
00173 for o, a in opts:
00174 if o in ("-h", "--help", "-?"):
00175 print __doc__
00176 sys.exit(0)
00177 if o in ("-c", "--config"):
00178 cfg_file = a
00179 elif o in ("-d", "--debug"):
00180 rpki.log.use_syslog = False
00181 if argv:
00182 raise RuntimeError, "Unexpected arguments %s" % argv
00183
00184 rpki.log.init("irdbd")
00185
00186 cfg = rpki.config.parser(cfg_file, "irdbd")
00187
00188 startup_msg = cfg.get("startup-message", "")
00189 if startup_msg:
00190 rpki.log.info(startup_msg)
00191
00192 cfg.set_global_flags()
00193
00194 db = MySQLdb.connect(user = cfg.get("sql-username"),
00195 db = cfg.get("sql-database"),
00196 passwd = cfg.get("sql-password"))
00197
00198 cur = db.cursor()
00199 db.autocommit(True)
00200
00201 bpki_ta = rpki.x509.X509(Auto_file = cfg.get("bpki-ta"))
00202 rpkid_cert = rpki.x509.X509(Auto_file = cfg.get("rpkid-cert"))
00203 irdbd_cert = rpki.x509.X509(Auto_file = cfg.get("irdbd-cert"))
00204 irdbd_key = rpki.x509.RSA( Auto_file = cfg.get("irdbd-key"))
00205
00206 u = urlparse.urlparse(cfg.get("https-url"))
00207
00208 assert u.scheme in ("", "https") and \
00209 u.username is None and \
00210 u.password is None and \
00211 u.params == "" and \
00212 u.query == "" and \
00213 u.fragment == ""
00214
00215 rpki.https.server(server_key = irdbd_key,
00216 server_cert = irdbd_cert,
00217 client_ta = (bpki_ta, rpkid_cert),
00218 host = u.hostname or "localhost",
00219 port = u.port or 443,
00220 handlers = ((u.path, handler),))