diff options
-rwxr-xr-x | scripts/irdb.py | 6 | ||||
-rw-r--r-- | scripts/rpki/exceptions.py | 4 | ||||
-rw-r--r-- | scripts/rpki/left_right.py | 53 | ||||
-rw-r--r-- | scripts/rpki/sql.py | 49 | ||||
-rw-r--r-- | scripts/rpki/up_down.py | 7 | ||||
-rwxr-xr-x | scripts/rpkid.py | 6 |
6 files changed, 88 insertions, 37 deletions
diff --git a/scripts/irdb.py b/scripts/irdb.py index 5894ccc6..5423c506 100755 --- a/scripts/irdb.py +++ b/scripts/irdb.py @@ -92,4 +92,8 @@ privateKey = rpki.x509.RSA_Keypair(PEM_file = cfg.get(section, "https-key")) certChain = rpki.x509.X509_chain() certChain.load_from_PEM(cfg.multiget(section, "https-cert")) -rpki.https.server(privateKey=privateKey, certChain=certChain, handlers=handler) +rpki.https.server(privateKey = privateKey, + certChain = certChain, + host = cfg.get(section, "https-host"), + port = int(cfg.get(section, "https-port")), + handlers = { cfg.get(section, "https-url") : handler }) diff --git a/scripts/rpki/exceptions.py b/scripts/rpki/exceptions.py index f1be383e..6302d1b9 100644 --- a/scripts/rpki/exceptions.py +++ b/scripts/rpki/exceptions.py @@ -14,8 +14,8 @@ class BadStatusCode(Exception): class BadQuery(Exception): """Unexpected protocol query.""" -class MultipleROAsFound(Exception): - """Found multiple ROAs in a relationship that should be one-to-one.""" +class DBConsistancyError(Exception): + """Found multiple matches for a database query that shouldn't ever return that.""" class CMSVerificationFailed(Exception): """Verification of a CMS message failed.""" diff --git a/scripts/rpki/left_right.py b/scripts/rpki/left_right.py index 4715700e..643ab5e0 100644 --- a/scripts/rpki/left_right.py +++ b/scripts/rpki/left_right.py @@ -3,7 +3,7 @@ """RPKI "left-right" protocol.""" import base64, lxml.etree -import rpki.sax_utils, rpki.resource_set, rpki.x509, rpki.sql, rpki.exceptions, rpki.pkcs10 +import rpki.sax_utils, rpki.resource_set, rpki.x509, rpki.sql, rpki.exceptions, rpki.pkcs10, rpki.https xmlns = "http://www.hactrn.net/uris/rpki/left-right-spec/" @@ -444,7 +444,7 @@ class route_origin_elt(data_elt): roa = roas[0][0] ca_detail_id = roas[0][1] elif len(roas) > 0: - raise rpki.exceptions.MultipleROAsFound, "Multiple ROAs found for route_origin %s, mapping should be one-to-one" % self.route_origin_id + raise rpki.exceptions.DBConsistancyError, "Multiple ROAs found for route_origin %s, mapping should be one-to-one" % self.route_origin_id def sql_insert_hook(self, db, cur): if self.ipv4 + self.ipv6: @@ -486,7 +486,7 @@ class resource_class_elt(base_elt): """<resource_class/> element.""" element_name = "resource_class" - attributes = ("as", "req_as", "ipv4", "req_ipv4", "ipv6", "req_ipv6", "subject_name") + attributes = ("as", "ipv4", "ipv6", "subject_name") def startElement(self, stack, name, attrs): """Handle <resource_class/> element.""" @@ -494,16 +494,10 @@ class resource_class_elt(base_elt): self.read_attrs(attrs) if self.as is not None: self.as = rpki.resource_set.resource_set_as(self.as) - if self.req_as is not None: - self.req_as = rpki.resource_set.resource_set_as(self.req_as) if self.ipv4 is not None: self.ipv4 = rpki.resource_set.resource_set_ipv4(self.ipv4) - if self.req_ipv4 is not None: - self.req_ipv4 = rpki.resource_set.resource_set_ipv4(self.req_ipv4) if self.ipv6 is not None: self.ipv6 = rpki.resource_set.resource_set_ipv6(self.ipv6) - if self.req_ipv6 is not None: - self.req_ipv6 = rpki.resource_set.resource_set_ipv6(self.req_ipv6) def endElement(self, stack, name, text): """Handle <resource_class/> element.""" @@ -610,3 +604,44 @@ class sax_handler(rpki.sax_utils.handler): """Top-level PDU for this protocol is <msg/>.""" assert name == "msg" and attrs["version"] == "1" return self.pdu() + +def irdb_query(gctx, self_id, child_id=None): + """Perform an IRDB callback query. + + In the long run this should not be a blocking routine, it should + instead issue a query and set up a handler to receive the response. + For the moment, though, we're doing simple lock step and damn the + torpedos. + """ + + q_msg = msg_elt() + q_msg.append(list_resources_elt()) + q_msg[0].type = "query" + q_msg[0].self_id = self_id + q_msg[0].child_id = child_id + q_elt = q_msg.toXML() + rpki.relaxng.left_right.assertValid(q_elt) + q_cms = rpki.cms.xml_encode(q_elt, gctx.cms_key, gctx.cms_certs) + r_cms = rpki.https.client(privateKey = gctx.https_key, + certChain = gctx.https_certs, + x509TrustList = gctx.https_tas, + host = gctx.irdb_host, + port = gctx.irdb_port, + url = gctx.irdb_url, + msg = q_cms) + r_elt = rpki.cms.xml_decode(r_cms, gctx.cms_ta_irbe) + rpki.relaxng.left_right.assertValid(r_elt) + r_msg = rpki.left_right.sax_handler.saxify(r_elt) + if len(r_msg) != 0 or not isinstance(r_msg[0], list_resources_elt) or r_msg[0].type != "reply": + raise rpki.exceptions.BadIRDBReply, "Unexpected response to IRDB query: %s" % r_msg.toXML() + as = rpki.resource_set.resource_set_as() + ipv4 = rpki.resource_set.resource_set_ipv4() + ipv6 = rpki.resource_set.resource_set_ipv6() + for r in r_msg[0].resources: + if r.as is not None: + as.union(r.as) + if r.ipv4 is not None: + ipv4.union(r.ipv4) + if r.ipv6 is not None: + ipv6.union(r.ipv6) + return as, ipv4, ipv6 diff --git a/scripts/rpki/sql.py b/scripts/rpki/sql.py index bab07e5e..2831a447 100644 --- a/scripts/rpki/sql.py +++ b/scripts/rpki/sql.py @@ -14,16 +14,15 @@ def connect(cfg, section="sql"): class template(object): """SQL template generator.""" def __init__(self, table_name, *columns): - index_column = columns[0] - data_columns = columns[1:] - self.table = table_name - self.index = index_column - self.columns = columns - self.insert = "INSERT %s (%s) VALUES (%s)" % (table_name, ", ".join(data_columns), ", ".join("%(" + s + ")s" for s in data_columns)) - self.update = "UPDATE %s SET %s WHERE %s = %%(%s)s" % (table_name, ", ".join(s + " = %(" + s + ")s" for s in data_columns), index_column, index_column) - self.delete = "DELETE FROM %s WHERE %s = %%s" % (table_name, index_column) - self.select_all = "SELECT %s FROM %s" % (", ".join(columns), table_name) - self.select_one = self.select_all + " WHERE " + index_column + " = %s" + index_column = columns[0] + data_columns = columns[1:] + self.table = table_name + self.index = index_column + self.columns = columns + self.select = "SELECT %s FROM %s" % (", ".join(columns), table_name) + self.insert = "INSERT %s (%s) VALUES (%s)" % (table_name, ", ".join(data_columns), ", ".join("%(" + s + ")s" for s in data_columns)) + self.update = "UPDATE %s SET %s WHERE %s = %%(%s)s" % (table_name, ", ".join(s + " = %(" + s + ")s" for s in data_columns), index_column, index_column) + self.delete = "DELETE FROM %s WHERE %s = %%s" % (table_name, index_column) ## @var sql_cache # Cache of objects pulled from SQL. @@ -58,27 +57,33 @@ class sql_persistant(object): @classmethod def sql_fetch(cls, db, cur, id): - key = (cls, id) - if key in sql_cache: - return sql_cache[key] - cur.execute(cls.sql_template.select_one, id) - row = cur.fetchone() - if row is None: + results = cls.sql_fetch_where(db, cur, "WHERE %s = %s" % (cls.sql_template.index, id)) + assert len(results) <= 1 + if len(results) == 0: return None + elif len(results) == 1: + return results[0] else: - return cls.sql_init(db, cur, row, key) + raise rpki.exceptions.DBConsistancyError, "Database contained multiple matches for %s.%s" % (cls.__name__, id) @classmethod def sql_fetch_all(cls, db, cur): - cur.execute(cls.sql_template.select_all) - all = [] + return cls.sql_fetch_where(db, cur, None) + + @classmethod + def sql_fetch_where(cls, db, cur, where): + if where is None: + cur.execute(cls.sql_template.select) + else: + cur.execute(cls.sql_template.select + where) + results = [] for row in cur.fetchall(): key = (cls, row[0]) if key in sql_cache: - all.append(sql_cache[key]) + results.append(sql_cache[key]) else: - all.append(cls.sql_init(db, cur, row, key)) - return all + results.append(cls.sql_init(db, cur, row, key)) + return results @classmethod def sql_init(cls, db, cur, row, key): diff --git a/scripts/rpki/up_down.py b/scripts/rpki/up_down.py index 507e42e6..dbaba3fd 100644 --- a/scripts/rpki/up_down.py +++ b/scripts/rpki/up_down.py @@ -144,18 +144,19 @@ class list_pdu(base_elt): raise NotImplementedError # Tasks: - # + # 1) extract child's resource set from irdb # + irdb_as, irdb_ipv4, irdb_ipv6 = rpki.left_right.irdb_query(gctx, child.self_id, child.child_id) + # 2) for every ca, compute intersection of child's resource set # with ca's resource set; if result is non-null, this ca is one # of the resource classes for this child # # 3) establish ca_child_link bindings based on (2)? # - # 4) generate result pdu + # 4) generate result pdu, unless we do that as part of (2) - child_data = irdb_query(child) r_msg.payload = list_response_pdu() for ca in rpki.sql.fetch_column(gctx.cur, "SELECT ca_id FROM child_ca_link WHERE child_id = %s" % child.child_id): klass = class_elt() diff --git a/scripts/rpkid.py b/scripts/rpkid.py index cdac0c60..5ef0809d 100755 --- a/scripts/rpkid.py +++ b/scripts/rpkid.py @@ -66,8 +66,14 @@ gctx.cms_certs = gctx.cfg.multiget(gctx.cfg_section, "cms-cert") gctx.https_key = rpki.x509.RSA_Keypair(PEM_file = gctx.cfg.get(gctx.cfg_section, "https-key")) gctx.https_certs = certChain = rpki.x509.X509_chain() +gctx.https_tas = rpki.x509.X509_chain() gctx.https_certs.load_from_PEM(gctx.cfg.multiget(gctx.cfg_section, "https-cert")) +gctx.https_tas.load_from_PEM(gctx.cfg.multiget(gctx.cfg_section, "https-ta")) + +gctx.irdb_host = gctx.cfg.get(gctx.cfg_section, "irdb-host") +gctx.irdb_port = gctx.cfg.get(gctx.cfg_section, "irdb-port") +gctx.irdb_url = gctx.cfg.get(gctx.cfg_section, "irdb-url") rpki.https.server(privateKey=gctx.https_key, certChain=gctx.https_certs, handlers=(("/left-right", left_right_handler), |