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 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),))