RPKI Engine 1.0
|
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),))