aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buildtools/make-sql-schemas.py2
-rw-r--r--rpkid/Makefile.in2
-rw-r--r--rpkid/examples/rpki.conf2
-rw-r--r--rpkid/rpki/irdb/models.py16
-rw-r--r--rpkid/rpki/irdbd.py202
-rw-r--r--rpkid/rpki/old_irdbd.py249
-rw-r--r--rpkid/rpki/resource_set.py25
-rw-r--r--rpkid/rpki/rpkic.py195
-rw-r--r--rpkid/rpki/sql_schemas.py109
-rw-r--r--rpkid/tests/old_irdbd.py21
-rw-r--r--rpkid/tests/old_irdbd.sql (renamed from rpkid/irdbd.sql)0
-rw-r--r--rpkid/tests/smoketest.py6
-rw-r--r--rpkid/tests/sql-cleaner.py4
-rw-r--r--rpkid/tests/yamltest.py265
-rw-r--r--scripts/convert-from-entitydb-to-sql.py6
15 files changed, 680 insertions, 424 deletions
diff --git a/buildtools/make-sql-schemas.py b/buildtools/make-sql-schemas.py
index 700d2b9c..3ecde014 100644
--- a/buildtools/make-sql-schemas.py
+++ b/buildtools/make-sql-schemas.py
@@ -32,7 +32,7 @@ OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
"""
-schemas = ("rpkid", "irdbd", "pubd")
+schemas = ("rpkid", "pubd")
format_1 = """\
# Automatically generated, do not edit.
diff --git a/rpkid/Makefile.in b/rpkid/Makefile.in
index aba6872b..db47b0da 100644
--- a/rpkid/Makefile.in
+++ b/rpkid/Makefile.in
@@ -82,7 +82,7 @@ publication-schema.rng: publication-schema.rnc
myrpki.rng: myrpki.rnc
trang myrpki.rnc myrpki.rng
-rpki/sql_schemas.py: ${abs_top_srcdir}/buildtools/make-sql-schemas.py rpkid.sql irdbd.sql pubd.sql
+rpki/sql_schemas.py: ${abs_top_srcdir}/buildtools/make-sql-schemas.py rpkid.sql pubd.sql
${PYTHON} ${abs_top_srcdir}/buildtools/make-sql-schemas.py >$@.tmp
mv $@.tmp $@
diff --git a/rpkid/examples/rpki.conf b/rpkid/examples/rpki.conf
index 06b853a9..17e37b7b 100644
--- a/rpkid/examples/rpki.conf
+++ b/rpkid/examples/rpki.conf
@@ -308,7 +308,7 @@ rpki-root-cert-uri = rsync://${myrpki::publication_rsync_server}/${myrpki:
# Private key corresponding to rootd's root RPKI certificate
-rpki-root-key = ${myrpki::bpki_servers_directory}/ca.key
+rpki-root-key = ${myrpki::bpki_servers_directory}/root.key
# Filename (as opposed to rsync URI) of rootd's root RPKI certificate
diff --git a/rpkid/rpki/irdb/models.py b/rpkid/rpki/irdb/models.py
index 071e0918..1add3593 100644
--- a/rpkid/rpki/irdb/models.py
+++ b/rpkid/rpki/irdb/models.py
@@ -209,6 +209,7 @@ class CertificateManager(django.db.models.Manager):
return obj, changed
def _get_or_certify_keys(self, kwargs):
+ assert len(self.model._meta.unique_together) == 1
return dict((k, kwargs[k]) for k in self.model._meta.unique_together[0])
class ResourceHolderCAManager(CertificateManager):
@@ -452,6 +453,10 @@ class Child(CrossCertification):
name = django.db.models.TextField(null = True, blank = True)
valid_until = SundialField()
+ # This shouldn't be necessary
+ class Meta:
+ unique_together = ("issuer", "handle")
+
class ChildASN(django.db.models.Model):
child = django.db.models.ForeignKey(Child, related_name = "asns")
start_as = django.db.models.BigIntegerField()
@@ -477,6 +482,10 @@ class Parent(CrossCertification, Turtle):
referrer = HandleField(null = True, blank = True)
referral_authorization = SignedReferralField(null = True, blank = True)
+ # This shouldn't be necessary
+ class Meta:
+ unique_together = ("issuer", "handle")
+
class ROARequest(django.db.models.Model):
issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "roa_requests")
asn = django.db.models.BigIntegerField()
@@ -503,7 +512,14 @@ class Repository(CrossCertification):
sia_base = django.db.models.TextField()
turtle = django.db.models.OneToOneField(Turtle, related_name = "repository")
+ # This shouldn't be necessary
+ class Meta:
+ unique_together = ("issuer", "handle")
+
class Client(CrossCertification):
issuer = django.db.models.ForeignKey(ServerCA, related_name = "clients")
sia_base = django.db.models.TextField()
+ # This shouldn't be necessary
+ class Meta:
+ unique_together = ("issuer", "handle")
diff --git a/rpkid/rpki/irdbd.py b/rpkid/rpki/irdbd.py
index c2e01287..adda4be2 100644
--- a/rpkid/rpki/irdbd.py
+++ b/rpkid/rpki/irdbd.py
@@ -5,7 +5,7 @@ Usage: python irdbd.py [ { -c | --config } configfile ] [ { -h | --help } ]
$Id$
-Copyright (C) 2009--2011 Internet Systems Consortium ("ISC")
+Copyright (C) 2009--2012 Internet Systems Consortium ("ISC")
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -38,116 +38,106 @@ import sys, os, time, getopt, urlparse, warnings
import rpki.http, rpki.config, rpki.resource_set, rpki.relaxng
import rpki.exceptions, rpki.left_right, rpki.log, rpki.x509
-from rpki.mysql_import import MySQLdb
+from django.conf import settings
-class main(object):
+os.environ["TZ"] = "UTC"
+time.tzset()
+cfg_file = None
- def handle_list_resources(self, q_pdu, r_msg):
+opts, argv = getopt.getopt(sys.argv[1:], "c:dh?", ["config=", "debug", "help"])
+for o, a in opts:
+ if o in ("-h", "--help", "-?"):
+ print __doc__
+ sys.exit(0)
+ if o in ("-c", "--config"):
+ cfg_file = a
+ elif o in ("-d", "--debug"):
+ rpki.log.use_syslog = False
+if argv:
+ raise rpki.exceptions.CommandParseFailure, "Unexpected arguments %s" % argv
- r_pdu = rpki.left_right.list_resources_elt()
- r_pdu.tag = q_pdu.tag
- r_pdu.self_handle = q_pdu.self_handle
- r_pdu.child_handle = q_pdu.child_handle
+rpki.log.init("irdbd")
+
+cfg = rpki.config.parser(cfg_file, "irdbd")
- self.cur.execute(
- "SELECT registrant_id, valid_until FROM registrant WHERE registry_handle = %s AND registrant_handle = %s",
- (q_pdu.self_handle, q_pdu.child_handle))
+startup_msg = cfg.get("startup-message", "")
+if startup_msg:
+ rpki.log.info(startup_msg)
- if self.cur.rowcount != 1:
- raise rpki.exceptions.NotInDatabase, \
- "This query should have produced a single exact match, something's messed up (rowcount = %d, self_handle = %s, child_handle = %s)" \
- % (self.cur.rowcount, q_pdu.self_handle, q_pdu.child_handle)
+cfg.set_global_flags()
- registrant_id, valid_until = self.cur.fetchone()
+settings.configure(
+ DEBUG = True,
+ DATABASES = { "default" : {
+ "ENGINE" : "django.db.backends.mysql",
+ "NAME" : cfg.get("sql-database"),
+ "USER" : cfg.get("sql-username"),
+ "PASSWORD" : cfg.get("sql-password"),
+ "HOST" : "",
+ "PORT" : ""}},
+ INSTALLED_APPS = ("rpki.irdb",),)
- r_pdu.valid_until = valid_until.strftime("%Y-%m-%dT%H:%M:%SZ")
+import rpki.irdb
- r_pdu.asn = rpki.resource_set.resource_set_as.from_sql(
- self.cur,
- "SELECT start_as, end_as FROM registrant_asn WHERE registrant_id = %s",
- (registrant_id,))
- r_pdu.ipv4 = rpki.resource_set.resource_set_ipv4.from_sql(
- self.cur,
- "SELECT start_ip, end_ip FROM registrant_net WHERE registrant_id = %s AND version = 4",
- (registrant_id,))
+class Main(object):
- r_pdu.ipv6 = rpki.resource_set.resource_set_ipv6.from_sql(
- self.cur,
- "SELECT start_ip, end_ip FROM registrant_net WHERE registrant_id = %s AND version = 6",
- (registrant_id,))
+ def handle_list_resources(self, q_pdu, r_msg):
+ child = rpki.irdb.Child.objects.get(issuer__handle__exact = q_pdu.self_handle, handle = q_pdu.child_handle)
+ r_pdu = rpki.left_right.list_resources_elt()
+ r_pdu.tag = q_pdu.tag
+ r_pdu.self_handle = q_pdu.self_handle
+ r_pdu.child_handle = q_pdu.child_handle
+ r_pdu.valid_until = child.valid_until.strftime("%Y-%m-%dT%H:%M:%SZ")
+ r_pdu.asn = rpki.resource_set.resource_set_as.from_django(
+ (a.start_as, a.end_s) for a in child.asns.all())
+ r_pdu.ipv4 = rpki.resource_set.resource_set_ipv4.from_django(
+ (a.start_ip, a.end_ip) for a in child.address_ranges.filter(version = 4))
+ r_pdu.ipv6 = rpki.resource_set.resource_set_ipv6.from_django(
+ (a.start_ip, a.end_ip) for a in child.address_ranges.filter(version = 6))
r_msg.append(r_pdu)
def handle_list_roa_requests(self, q_pdu, r_msg):
-
- self.cur.execute(
- "SELECT roa_request_id, asn FROM roa_request WHERE roa_request_handle = %s",
- (q_pdu.self_handle,))
-
- for roa_request_id, asn in self.cur.fetchall():
-
+ for request in rpki.irdb.ROARequest.objects.filter(issuer__handle__exact = q_pdu.self_handle):
r_pdu = rpki.left_right.list_roa_requests_elt()
r_pdu.tag = q_pdu.tag
r_pdu.self_handle = q_pdu.self_handle
- r_pdu.asn = asn
-
- r_pdu.ipv4 = rpki.resource_set.roa_prefix_set_ipv4.from_sql(
- self.cur,
- "SELECT prefix, prefixlen, max_prefixlen FROM roa_request_prefix WHERE roa_request_id = %s AND version = 4",
- (roa_request_id,))
-
- r_pdu.ipv6 = rpki.resource_set.roa_prefix_set_ipv6.from_sql(
- self.cur,
- "SELECT prefix, prefixlen, max_prefixlen FROM roa_request_prefix WHERE roa_request_id = %s AND version = 6",
- (roa_request_id,))
-
+ r_pdu.asn = request.asn
+ r_pdu.ipv4 = rpki.resource_set.roa_prefix_set_ipv4.from_django(
+ (p.prefix, p.prefixlen, p.max_prefixlen) for p in request.prefixes.filter(version = 4))
+ r_pdu.ipv6 = rpki.resource_set.roa_prefix_set_ipv6.from_django(
+ (p.prefix, p.prefixlen, p.max_prefixlen) for p in request.prefixes.filter(version = 6))
r_msg.append(r_pdu)
def handle_list_ghostbuster_requests(self, q_pdu, r_msg):
-
- self.cur.execute(
- "SELECT vcard FROM ghostbuster_request WHERE self_handle = %s AND parent_handle = %s",
- (q_pdu.self_handle, q_pdu.parent_handle))
-
- vcards = [result[0] for result in self.cur.fetchall()]
-
- if not vcards:
-
- self.cur.execute(
- "SELECT vcard FROM ghostbuster_request WHERE self_handle = %s AND parent_handle IS NULL",
- (q_pdu.self_handle,))
-
- vcards = [result[0] for result in self.cur.fetchall()]
-
- for vcard in vcards:
+ ghostbusters = rpki.irdb.GhostbusterRequest.objects.filter(issuer__handle__exact = q_pdu.self_handle,
+ parent__handle__exact = q_pdu.parent_handle)
+ if ghostbusters.count() == 0:
+ ghostbusters = rpki.irdb.GhostbusterRequest.objects.filter(issuer__handle__exact = q_pdu.self_handle,
+ parent = None)
+ for ghostbuster in ghostbusters:
r_pdu = rpki.left_right.list_ghostbuster_requests_elt()
r_pdu.tag = q_pdu.tag
r_pdu.self_handle = q_pdu.self_handle
r_pdu.parent_handle = q_pdu.parent_handle
- r_pdu.vcard = vcard
+ r_pdu.vcard = ghostbuster.vcard
r_msg.append(r_pdu)
- handle_dispatch = {
- rpki.left_right.list_resources_elt : handle_list_resources,
- rpki.left_right.list_roa_requests_elt : handle_list_roa_requests,
- rpki.left_right.list_ghostbuster_requests_elt : handle_list_ghostbuster_requests}
-
-
def handler(self, query, path, cb):
- try:
-
- self.db.ping(True)
+ try:
r_msg = rpki.left_right.msg.reply()
- try:
+ serverCA = rpki.irdb.ServerCA.objects.get()
+ rpkid = serverCA.ee_certificates.get(purpose = "rpkid")
- q_msg = rpki.left_right.cms_msg(DER = query).unwrap((self.bpki_ta, self.rpkid_cert))
+ try:
+ q_msg = rpki.left_right.cms_msg(DER = query).unwrap((serverCA.certificate, rpkid.certificate))
if not isinstance(q_msg, rpki.left_right.msg) or not q_msg.is_query():
raise rpki.exceptions.BadQuery, "Unexpected %r PDU" % q_msg
@@ -177,7 +167,9 @@ class main(object):
rpki.log.traceback()
r_msg.append(rpki.left_right.report_error_elt.from_exception(e))
- cb(200, body = rpki.left_right.cms_msg().wrap(r_msg, self.irdbd_key, self.irdbd_cert))
+ irdbd = serverCA.ee_certificates.get(purpose = "irdbd")
+
+ cb(200, body = rpki.left_right.cms_msg().wrap(r_msg, irdbd.private_key, irdbd.certificate))
except (rpki.async.ExitNow, SystemExit):
raise
@@ -191,56 +183,28 @@ class main(object):
cb(500, reason = "Unhandled exception %s: %s" % (e.__class__.__name__, e))
- def __init__(self):
-
- os.environ["TZ"] = "UTC"
- time.tzset()
-
- cfg_file = None
-
- opts, argv = getopt.getopt(sys.argv[1:], "c:dh?", ["config=", "debug", "help"])
- for o, a in opts:
- if o in ("-h", "--help", "-?"):
- print __doc__
- sys.exit(0)
- if o in ("-c", "--config"):
- cfg_file = a
- elif o in ("-d", "--debug"):
- rpki.log.use_syslog = False
- if argv:
- raise rpki.exceptions.CommandParseFailure, "Unexpected arguments %s" % argv
-
- rpki.log.init("irdbd")
-
- self.cfg = rpki.config.parser(cfg_file, "irdbd")
-
- startup_msg = self.cfg.get("startup-message", "")
- if startup_msg:
- rpki.log.info(startup_msg)
-
- self.cfg.set_global_flags()
-
- self.db = MySQLdb.connect(user = self.cfg.get("sql-username"),
- db = self.cfg.get("sql-database"),
- passwd = self.cfg.get("sql-password"))
+ handle_dispatch = {
+ rpki.left_right.list_resources_elt : handle_list_resources,
+ rpki.left_right.list_roa_requests_elt : handle_list_roa_requests,
+ rpki.left_right.list_ghostbuster_requests_elt : handle_list_ghostbuster_requests}
- self.cur = self.db.cursor()
- self.db.autocommit(True)
- self.bpki_ta = rpki.x509.X509(Auto_update = self.cfg.get("bpki-ta"))
- self.rpkid_cert = rpki.x509.X509(Auto_update = self.cfg.get("rpkid-cert"))
- self.irdbd_cert = rpki.x509.X509(Auto_update = self.cfg.get("irdbd-cert"))
- self.irdbd_key = rpki.x509.RSA( Auto_update = self.cfg.get("irdbd-key"))
+ def __init__(self, **kwargs):
+ for k in kwargs:
+ setattr(self, k, kwargs[k])
- u = urlparse.urlparse(self.cfg.get("http-url"))
+ def __call__(self):
+ u = urlparse.urlparse(self.http_url)
assert u.scheme in ("", "http") and \
u.username is None and \
u.password is None and \
u.params == "" and \
u.query == "" and \
u.fragment == ""
+ rpki.http.server(host = u.hostname or "localhost",
+ port = u.port or 443,
+ handlers = ((u.path, self.handler),))
+
- rpki.http.server(host = u.hostname or "localhost",
- port = u.port or 443,
- handlers = ((u.path, self.handler),))
+main = Main(http_url = cfg.get("http-url"))
diff --git a/rpkid/rpki/old_irdbd.py b/rpkid/rpki/old_irdbd.py
new file mode 100644
index 00000000..c63ce9e2
--- /dev/null
+++ b/rpkid/rpki/old_irdbd.py
@@ -0,0 +1,249 @@
+"""
+IR database daemon.
+
+Usage: python irdbd.py [ { -c | --config } configfile ] [ { -h | --help } ]
+
+This is the old (pre-Django) version of irdbd, still used by smoketest
+and perhaps still useful as a minimal example.
+
+$Id$
+
+Copyright (C) 2009--2012 Internet Systems Consortium ("ISC")
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+Portions copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN")
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+"""
+
+import sys, os, time, getopt, urlparse, warnings
+import rpki.http, rpki.config, rpki.resource_set, rpki.relaxng
+import rpki.exceptions, rpki.left_right, rpki.log, rpki.x509
+
+from rpki.mysql_import import MySQLdb
+
+class main(object):
+
+
+ def handle_list_resources(self, q_pdu, r_msg):
+
+ r_pdu = rpki.left_right.list_resources_elt()
+ r_pdu.tag = q_pdu.tag
+ r_pdu.self_handle = q_pdu.self_handle
+ r_pdu.child_handle = q_pdu.child_handle
+
+ self.cur.execute(
+ "SELECT registrant_id, valid_until FROM registrant WHERE registry_handle = %s AND registrant_handle = %s",
+ (q_pdu.self_handle, q_pdu.child_handle))
+
+ if self.cur.rowcount != 1:
+ raise rpki.exceptions.NotInDatabase, \
+ "This query should have produced a single exact match, something's messed up (rowcount = %d, self_handle = %s, child_handle = %s)" \
+ % (self.cur.rowcount, q_pdu.self_handle, q_pdu.child_handle)
+
+ registrant_id, valid_until = self.cur.fetchone()
+
+ r_pdu.valid_until = valid_until.strftime("%Y-%m-%dT%H:%M:%SZ")
+
+ r_pdu.asn = rpki.resource_set.resource_set_as.from_sql(
+ self.cur,
+ "SELECT start_as, end_as FROM registrant_asn WHERE registrant_id = %s",
+ (registrant_id,))
+
+ r_pdu.ipv4 = rpki.resource_set.resource_set_ipv4.from_sql(
+ self.cur,
+ "SELECT start_ip, end_ip FROM registrant_net WHERE registrant_id = %s AND version = 4",
+ (registrant_id,))
+
+ r_pdu.ipv6 = rpki.resource_set.resource_set_ipv6.from_sql(
+ self.cur,
+ "SELECT start_ip, end_ip FROM registrant_net WHERE registrant_id = %s AND version = 6",
+ (registrant_id,))
+
+ r_msg.append(r_pdu)
+
+
+ def handle_list_roa_requests(self, q_pdu, r_msg):
+
+ self.cur.execute(
+ "SELECT roa_request_id, asn FROM roa_request WHERE roa_request_handle = %s",
+ (q_pdu.self_handle,))
+
+ for roa_request_id, asn in self.cur.fetchall():
+
+ r_pdu = rpki.left_right.list_roa_requests_elt()
+ r_pdu.tag = q_pdu.tag
+ r_pdu.self_handle = q_pdu.self_handle
+ r_pdu.asn = asn
+
+ r_pdu.ipv4 = rpki.resource_set.roa_prefix_set_ipv4.from_sql(
+ self.cur,
+ "SELECT prefix, prefixlen, max_prefixlen FROM roa_request_prefix WHERE roa_request_id = %s AND version = 4",
+ (roa_request_id,))
+
+ r_pdu.ipv6 = rpki.resource_set.roa_prefix_set_ipv6.from_sql(
+ self.cur,
+ "SELECT prefix, prefixlen, max_prefixlen FROM roa_request_prefix WHERE roa_request_id = %s AND version = 6",
+ (roa_request_id,))
+
+ r_msg.append(r_pdu)
+
+
+ def handle_list_ghostbuster_requests(self, q_pdu, r_msg):
+
+ self.cur.execute(
+ "SELECT vcard FROM ghostbuster_request WHERE self_handle = %s AND parent_handle = %s",
+ (q_pdu.self_handle, q_pdu.parent_handle))
+
+ vcards = [result[0] for result in self.cur.fetchall()]
+
+ if not vcards:
+
+ self.cur.execute(
+ "SELECT vcard FROM ghostbuster_request WHERE self_handle = %s AND parent_handle IS NULL",
+ (q_pdu.self_handle,))
+
+ vcards = [result[0] for result in self.cur.fetchall()]
+
+ for vcard in vcards:
+ r_pdu = rpki.left_right.list_ghostbuster_requests_elt()
+ r_pdu.tag = q_pdu.tag
+ r_pdu.self_handle = q_pdu.self_handle
+ r_pdu.parent_handle = q_pdu.parent_handle
+ r_pdu.vcard = vcard
+ r_msg.append(r_pdu)
+
+
+ handle_dispatch = {
+ rpki.left_right.list_resources_elt : handle_list_resources,
+ rpki.left_right.list_roa_requests_elt : handle_list_roa_requests,
+ rpki.left_right.list_ghostbuster_requests_elt : handle_list_ghostbuster_requests}
+
+
+ def handler(self, query, path, cb):
+ try:
+
+ self.db.ping(True)
+
+ r_msg = rpki.left_right.msg.reply()
+
+ try:
+
+ q_msg = rpki.left_right.cms_msg(DER = query).unwrap((self.bpki_ta, self.rpkid_cert))
+
+ if not isinstance(q_msg, rpki.left_right.msg) or not q_msg.is_query():
+ raise rpki.exceptions.BadQuery, "Unexpected %r PDU" % q_msg
+
+ for q_pdu in q_msg:
+
+ try:
+
+ try:
+ h = self.handle_dispatch[type(q_pdu)]
+ except KeyError:
+ raise rpki.exceptions.BadQuery, "Unexpected %r PDU" % q_pdu
+ else:
+ h(self, q_pdu, r_msg)
+
+ except (rpki.async.ExitNow, SystemExit):
+ raise
+
+ except Exception, e:
+ rpki.log.traceback()
+ r_msg.append(rpki.left_right.report_error_elt.from_exception(e, q_pdu.self_handle, q_pdu.tag))
+
+ except (rpki.async.ExitNow, SystemExit):
+ raise
+
+ except Exception, e:
+ rpki.log.traceback()
+ r_msg.append(rpki.left_right.report_error_elt.from_exception(e))
+
+ cb(200, body = rpki.left_right.cms_msg().wrap(r_msg, self.irdbd_key, self.irdbd_cert))
+
+ except (rpki.async.ExitNow, SystemExit):
+ raise
+
+ except Exception, e:
+ rpki.log.traceback()
+
+ # We only get here in cases where we couldn't or wouldn't generate
+ # <report_error/>, so just return HTTP failure.
+
+ cb(500, reason = "Unhandled exception %s: %s" % (e.__class__.__name__, e))
+
+
+ def __init__(self):
+
+ os.environ["TZ"] = "UTC"
+ time.tzset()
+
+ cfg_file = None
+
+ opts, argv = getopt.getopt(sys.argv[1:], "c:dh?", ["config=", "debug", "help"])
+ for o, a in opts:
+ if o in ("-h", "--help", "-?"):
+ print __doc__
+ sys.exit(0)
+ if o in ("-c", "--config"):
+ cfg_file = a
+ elif o in ("-d", "--debug"):
+ rpki.log.use_syslog = False
+ if argv:
+ raise rpki.exceptions.CommandParseFailure, "Unexpected arguments %s" % argv
+
+ rpki.log.init("irdbd")
+
+ self.cfg = rpki.config.parser(cfg_file, "irdbd")
+
+ startup_msg = self.cfg.get("startup-message", "")
+ if startup_msg:
+ rpki.log.info(startup_msg)
+
+ self.cfg.set_global_flags()
+
+ self.db = MySQLdb.connect(user = self.cfg.get("sql-username"),
+ db = self.cfg.get("sql-database"),
+ passwd = self.cfg.get("sql-password"))
+
+ self.cur = self.db.cursor()
+ self.db.autocommit(True)
+
+ self.bpki_ta = rpki.x509.X509(Auto_update = self.cfg.get("bpki-ta"))
+ self.rpkid_cert = rpki.x509.X509(Auto_update = self.cfg.get("rpkid-cert"))
+ self.irdbd_cert = rpki.x509.X509(Auto_update = self.cfg.get("irdbd-cert"))
+ self.irdbd_key = rpki.x509.RSA( Auto_update = self.cfg.get("irdbd-key"))
+
+ u = urlparse.urlparse(self.cfg.get("http-url"))
+
+ assert u.scheme in ("", "http") and \
+ u.username is None and \
+ u.password is None and \
+ u.params == "" and \
+ u.query == "" and \
+ u.fragment == ""
+
+ rpki.http.server(host = u.hostname or "localhost",
+ port = u.port or 443,
+ handlers = ((u.path, self.handler),))
diff --git a/rpkid/rpki/resource_set.py b/rpkid/rpki/resource_set.py
index 2fd10756..2be8a614 100644
--- a/rpkid/rpki/resource_set.py
+++ b/rpkid/rpki/resource_set.py
@@ -500,6 +500,18 @@ class resource_set(list):
for (b, e) in sql.fetchall()])
@classmethod
+ def from_django(cls, iterable):
+ """
+ Create resource set from a Django query.
+
+ iterable is something which returns (min, max) pairs.
+ """
+
+ return cls(ini = [cls.range_type(cls.range_type.datum_type(b),
+ cls.range_type.datum_type(e))
+ for (b, e) in iterable])
+
+ @classmethod
def parse_str(cls, s):
"""
Parse resource set from text string (eg, XML attributes). This is
@@ -983,6 +995,19 @@ class roa_prefix_set(list):
return cls([cls.prefix_type(cls.prefix_type.range_type.datum_type(x), int(y), int(z))
for (x, y, z) in sql.fetchall()])
+ @classmethod
+ def from_sql(cls, iterable):
+ """
+ Create ROA prefix set from a Django query.
+
+ iterable is something which returns (prefix, prefixlen,
+ max_prefixlen) triples.
+ """
+
+ return cls([cls.prefix_type(cls.prefix_type.range_type.datum_type(x), int(y), int(z))
+ for (x, y, z) in iterable])
+
+
def to_roa_tuple(self):
"""
Convert ROA prefix set into tuple format used by ROA ASN.1
diff --git a/rpkid/rpki/rpkic.py b/rpkid/rpki/rpkic.py
index a946ec65..c098eea5 100644
--- a/rpkid/rpki/rpkic.py
+++ b/rpkid/rpki/rpkic.py
@@ -82,13 +82,43 @@ def B64Element(e, tag, obj, **kwargs):
DER object.
"""
- if e.text is None:
+ if e is None:
+ se = Element(tag, **kwargs)
+ else:
+ se = SubElement(e, tag, **kwargs)
+ if e is not None and e.text is None:
e.text = "\n"
- se = SubElement(e, tag, **kwargs)
se.text = "\n" + obj.get_Base64()
se.tail = "\n"
return se
+class PEM_writer(object):
+ """
+ Write PEM files to disk, keeping track of which ones we've already
+ written and setting the file mode appropriately.
+ """
+
+ def __init__(self, verbose = False):
+ self.wrote = set()
+ self.verbose = verbose
+
+ def __call__(self, filename, obj):
+ filename = os.path.realpath(filename)
+ if filename in self.wrote:
+ return
+ tempname = filename
+ if not filename.startswith("/dev/"):
+ tempname += ".%s.tmp" % os.getpid()
+ mode = 0400 if filename.endswith(".key") else 0444
+ if self.verbose:
+ print "Writing", filename
+ f = os.fdopen(os.open(tempname, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, mode), "w")
+ f.write(obj.get_PEM())
+ f.close()
+ if tempname != filename:
+ os.rename(tempname, filename)
+ self.wrote.add(filename)
+
def etree_write(e, filename, verbose = False, msg = None):
@@ -199,12 +229,16 @@ class main(rpki.cli.Cmd):
"USER" : self.cfg.get("sql-username", section = irdbd_section),
"PASSWORD" : self.cfg.get("sql-password", section = irdbd_section),
"HOST" : "",
- "PORT" : "" }},
+ "PORT" : "",
+ "OPTIONS" : { "init_command": "SET storage_engine=INNODB" }}},
INSTALLED_APPS = ("rpki.irdb",),
)
import rpki.irdb
+ import django.core.management
+ django.core.management.call_command("syncdb", verbosity = 0, load_initial_data = False)
+
if self.run_rootd and (not self.run_pubd or not self.run_rpkid):
raise CantRunRootd, "Can't run rootd unless also running rpkid and pubd"
@@ -286,12 +320,14 @@ class main(rpki.cli.Cmd):
# Build the identity.xml file. Need to check for existing file so we don't
# overwrite? Worry about that later.
+ run_rootd = self.run_rootd and self.handle == self.cfg.get("handle")
+
e = Element("identity", handle = self.handle)
B64Element(e, "bpki_ta", self.resource_ca.certificate)
- etree_write(e, "identity.xml",
- msg = None if self.run_rootd else 'This is the "identity" file you will need to send to your parent')
+ etree_write(e, "%s.identity.xml" % self.handle,
+ msg = None if run_rootd else 'This is the "identity" file you will need to send to your parent')
- if self.run_rootd:
+ if run_rootd:
assert self.run_rpkid and self.run_pubd
rpki.irdb.Rootd.objects.get_or_certify(
@@ -308,9 +344,47 @@ class main(rpki.cli.Cmd):
except rpki.irdb.Repository.DoesNotExist:
e = Element("repository", type = "offer", handle = self.handle, parent_handle = self.handle)
B64Element(e, "bpki_client_ta", self.resource_ca.certificate)
- etree_write(e, "rootd_repository_offer.xml",
+ etree_write(e, "%s.%s.repository-request.xml" % (self.handle, self.handle),
msg = 'This is the "repository offer" file for you to use if you want to publish in your own repository')
+ # Not (yet) sure whether we should be calling this here, try it for now
+ self.write_bpki_files()
+
+
+ def write_bpki_files(self):
+ """
+ Write out BPKI certificate, key, and CRL files for daemons that
+ need them.
+ """
+
+ writer = PEM_writer()
+
+ if self.run_rpkid:
+ rpkid = self.server_ca.ee_certificates.get(purpose = "rpkid")
+ writer(self.cfg.get("bpki-ta", section = "rpkid"), self.server_ca.certificate)
+ writer(self.cfg.get("rpkid-key", section = "rpkid"), rpkid.private_key)
+ writer(self.cfg.get("rpkid-cert", section = "rpkid"), rpkid.certificate)
+ writer(self.cfg.get("irdb-cert", section = "rpkid"),
+ self.server_ca.ee_certificates.get(purpose = "irdbd").certificate)
+ writer(self.cfg.get("irbe-cert", section = "rpkid"),
+ self.server_ca.ee_certificates.get(purpose = "irbe").certificate)
+
+ if self.run_pubd:
+ pubd = self.server_ca.ee_certificates.get(purpose = "pubd")
+ writer(self.cfg.get("bpki-ta", section = "pubd"), self.server_ca.certificate)
+ writer(self.cfg.get("pubd-key", section = "pubd"), pubd.private_key)
+ writer(self.cfg.get("pubd-cert", section = "pubd"), pubd.certificate)
+ writer(self.cfg.get("irbe-cert", section = "pubd"),
+ self.server_ca.ee_certificates.get(purpose = "irbe").certificate)
+
+ if self.run_rootd:
+ rootd = rpki.irdb.ResourceHolderCA.objects.get(handle = self.cfg.get("handle", section = "myrpki")).rootd
+ writer(self.cfg.get("bpki-ta", section = "rootd"), self.server_ca.certificate)
+ writer(self.cfg.get("rootd-bpki-crl", section = "rootd"), self.server_ca.latest_crl)
+ writer(self.cfg.get("rootd-bpki-key", section = "rootd"), rootd.private_key)
+ writer(self.cfg.get("rootd-bpki-cert", section = "rootd"), rootd.certificate)
+ writer(self.cfg.get("child-bpki-cert", section = "rootd"), rootd.issuer.certificate)
+
def do_update_bpki(self, arg):
"""
@@ -347,6 +421,9 @@ class main(rpki.cli.Cmd):
print "Regenerating CRL for", ca.handle
ca.generate_crl()
+ self.write_bpki_files()
+
+
def do_configure_child(self, arg):
"""
Configure a new child of this RPKI entity, given the child's XML
@@ -380,42 +457,46 @@ class main(rpki.cli.Cmd):
print "Child calls itself %r, we call it %r" % (c.get("handle"), child_handle)
- rpki.irdb.Child.objects.get_or_certify(
+ child, created = rpki.irdb.Child.objects.get_or_certify(
issuer = self.resource_ca,
handle = child_handle,
ta = rpki.x509.X509(Base64 = c.findtext("bpki_ta")),
- valid_until = valid_until.toXMLtime())
+ valid_until = valid_until)
e = Element("parent", parent_handle = self.handle, child_handle = child_handle,
- service_uri = service_uri, valid_until = valid_until)
+ service_uri = service_uri, valid_until = str(valid_until))
B64Element(e, "bpki_resource_ta", self.resource_ca.certificate)
- SubElement(e, "bpki_child_ta").text = c.findtext("bpki_ta")
+ B64Element(e, "bpki_child_ta", child.ta)
try:
- repo = self.resource_ca.repositories.get(handle = self.default_repository)
+ if self.default_repository:
+ repo = self.resource_ca.repositories.get(handle = self.default_repository)
+ else:
+ repo = self.resource_ca.repositories.get()
except rpki.irdb.Repository.DoesNotExist:
- try:
- repo = self.resource_ca.repositories[0]
- except rpki.irdb.Repository.DoesNotExist:
- repo = None
+ repo = None
if repo is None:
print "Couldn't find any usable repositories, not giving referral"
- elif repo_handle == self.handle:
+ elif repo.handle == self.handle:
SubElement(e, "repository", type = "offer")
else:
- proposed_sia_base = repo.get("sia_base") + child_handle + "/"
- r = Element("referral", authorized_sia_base = proposed_sia_base)
- r.text = c.findtext("bpki_ta")
- auth = self.bpki_resources.cms_xml_sign(r)
+ proposed_sia_base = repo.sia_base + child_handle + "/"
+ referral_cert, created = rpki.irdb.Referral.objects.get_or_certify(issuer = self.resource_ca)
+ auth = rpki.x509.SignedReferral()
+ auth.set_content(B64Element(None, namespaceQName + "referral", child.ta,
+ version = version,
+ authorized_sia_base = proposed_sia_base))
+ auth.schema_check()
+ auth.sign(referral_cert.private_key, referral_cert.certificate, self.resource_ca.latest_crl)
r = SubElement(e, "repository", type = "referral")
- SubElement(r, "authorization", referrer = repo.get("client_handle")).text = auth
- SubElement(r, "contact_info").text = repo.findtext("contact_info")
+ B64Element(r, "authorization", auth, referrer = repo.client_handle)
+ SubElement(r, "contact_info")
- etree_write(e, "parent-response-to-%s.xml" % child_handle,
+ etree_write(e, "%s.%s.parent-response.xml" % (self.handle, child_handle),
msg = "Send this file back to the child you just configured")
@@ -477,7 +558,7 @@ class main(rpki.cli.Cmd):
print "Parent calls itself %r, we call it %r" % (p.get("parent_handle"), parent_handle)
print "Parent calls us %r" % p.get("child_handle")
- rpki.irdb.Parent.get_or_certify(
+ rpki.irdb.Parent.objects.get_or_certify(
issuer = self.resource_ca,
handle = parent_handle,
child_handle = p.get("child_handle"),
@@ -493,7 +574,7 @@ class main(rpki.cli.Cmd):
r.set("handle", self.handle)
r.set("parent_handle", parent_handle)
B64Element(r, "bpki_client_ta", self.resource_ca.certificate)
- etree_write(r, "repository-request-for-%s.xml" % parent_handle,
+ etree_write(r, "%s.%s.repository-request.xml" % (self.handle, parent_handle),
msg = "This is the file to send to the repository operator")
@@ -542,12 +623,12 @@ class main(rpki.cli.Cmd):
print "This looks like a referral, checking"
try:
auth = client.find("authorization")
- referrer = self.resource_ca.clients.get(handle = auth.get("referrer"))
+ referrer = self.server_ca.clients.get(handle = auth.get("referrer"))
referral_cms = rpki.x509.SignedReferral(Base64 = auth.text)
referral_xml = referral_cms.unwrap(ta = (referrer.certificate, self.server_ca.certificate))
if rpki.x509.X509(Base64 = referral_xml.text) != client_ta:
raise BadXMLMessage, "Referral trust anchor does not match"
- sia_base = referral.get("authorized_sia_base")
+ sia_base = referral_xml.get("authorized_sia_base")
except rpki.irdb.Client.DoesNotExist:
print "We have no record of the client (%s) alleged to have made this referral" % auth.get("referrer")
@@ -578,7 +659,7 @@ class main(rpki.cli.Cmd):
print "Client calls itself %r, we call it %r" % (client.get("handle"), client_handle)
print "Client says its parent handle is %r" % parent_handle
- rpki.irdb.Client.get_or_certify(
+ rpki.irdb.Client.objects.get_or_certify(
issuer = self.server_ca,
handle = client_handle,
ta = client_ta,
@@ -595,7 +676,7 @@ class main(rpki.cli.Cmd):
B64Element(e, "bpki_server_ta", self.server_ca.certificate)
B64Element(e, "bpki_client_ta", client_ta)
SubElement(e, "contact_info").text = self.pubd_contact_info
- etree_write(e, "repository-response-to-%s.xml" % client_handle.replace("/", "."),
+ etree_write(e, "%s.repository-response.xml" % client_handle.replace("/", "."),
msg = "Send this file back to the publication client you just configured")
@@ -651,7 +732,7 @@ class main(rpki.cli.Cmd):
print "Could not find parent %r in our database" % parent_handle
else:
- rpki.irdb.Repository.get_or_certify(
+ rpki.irdb.Repository.objects.get_or_certify(
issuer = self.resource_ca,
handle = parent_handle,
client_handle = r.get("client_handle"),
@@ -809,6 +890,58 @@ class main(rpki.cli.Cmd):
q.delete()
+ def do_synchronize_roa_requests(self, arg):
+ """
+ Synchronize IRDB against roa.csv.
+ """
+
+ argv = arg.split()
+
+ if len(argv) != 1:
+ raise BadCommandSyntax("Need to specify roa.csv filename")
+
+ grouped = {}
+
+ # format: p/n-m asn group
+ for pnm, asn, group in csv_reader(argv[0], columns = 3):
+ key = (asn, group)
+ if key not in grouped:
+ grouped[key] = []
+ grouped[key].append(pnm)
+
+ import django.db.transaction
+
+ with django.db.transaction.commit_on_success():
+
+ # Deleting and recreating all the ROA requests is inefficient,
+ # but rpkid's current representation of ROA requests is wrong
+ # (see #32), so it's not worth a lot of effort here as we're
+ # just going to have to rewrite this soon anyway.
+
+ self.resource_ca.roa_requests.all().delete()
+
+ for key, pnms in grouped.iteritems():
+ asn, group = key
+
+ roa_request = rpki.irdb.ROARequest.objects.create(
+ issuer = self.resource_ca,
+ asn = asn)
+
+ for pnm in pnms:
+ if ":" in pnm:
+ p = rpki.resource_set.roa_prefix_ipv6.parse_str(pnm)
+ v = 6
+ else:
+ p = rpki.resource_set.roa_prefix_ipv4.parse_str(pnm)
+ v = 4
+ rpki.irdb.ROARequestPrefix.objects.create(
+ roa_request = roa_request,
+ version = v,
+ prefix = str(p.prefix),
+ prefixlen = int(p.prefixlen),
+ max_prefixlen = int(p.max_prefixlen))
+
+
def do_synchronize(self, arg):
"""
Temporary testing hack (probably) to let me run .synchronize()
diff --git a/rpkid/rpki/sql_schemas.py b/rpkid/rpki/sql_schemas.py
index 154ab5c1..e7c65299 100644
--- a/rpkid/rpki/sql_schemas.py
+++ b/rpkid/rpki/sql_schemas.py
@@ -239,115 +239,6 @@ CREATE TABLE ghostbuster (
-- End:
'''
-## @var irdbd
-## SQL schema irdbd
-irdbd = '''-- $Id: irdbd.sql 3730 2011-03-21 12:42:43Z sra $
-
--- Copyright (C) 2009--2011 Internet Systems Consortium ("ISC")
---
--- Permission to use, copy, modify, and distribute this software for any
--- purpose with or without fee is hereby granted, provided that the above
--- copyright notice and this permission notice appear in all copies.
---
--- THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
--- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
--- AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
--- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
--- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
--- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
--- PERFORMANCE OF THIS SOFTWARE.
-
--- Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN")
---
--- Permission to use, copy, modify, and distribute this software for any
--- purpose with or without fee is hereby granted, provided that the above
--- copyright notice and this permission notice appear in all copies.
---
--- THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH
--- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
--- AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT,
--- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
--- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
--- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
--- PERFORMANCE OF THIS SOFTWARE.
-
--- SQL objects needed by irdbd.py. You only need this if you're using
--- irdbd.py as your IRDB; if you have a "real" backend you can do
--- anything you like so long as you implement the relevant portion of
--- the left-right protocol.
-
--- DROP TABLE commands must be in correct (reverse dependency) order
--- to satisfy FOREIGN KEY constraints.
-
-DROP TABLE IF EXISTS roa_request_prefix;
-DROP TABLE IF EXISTS roa_request;
-DROP TABLE IF EXISTS registrant_net;
-DROP TABLE IF EXISTS registrant_asn;
-DROP TABLE IF EXISTS registrant;
-DROP TABLE IF EXISTS ghostbuster_request;
-
-CREATE TABLE registrant (
- registrant_id SERIAL NOT NULL,
- registrant_handle VARCHAR(255) NOT NULL,
- registrant_name TEXT,
- registry_handle VARCHAR(255),
- valid_until DATETIME NOT NULL,
- PRIMARY KEY (registrant_id),
- UNIQUE (registry_handle, registrant_handle)
-) ENGINE=InnoDB;
-
-CREATE TABLE registrant_asn (
- registrant_asn_id SERIAL NOT NULL,
- start_as BIGINT UNSIGNED NOT NULL,
- end_as BIGINT UNSIGNED NOT NULL,
- registrant_id BIGINT UNSIGNED NOT NULL,
- PRIMARY KEY (registrant_asn_id),
- CONSTRAINT registrant_asn_registrant_id
- FOREIGN KEY (registrant_id) REFERENCES registrant (registrant_id) ON DELETE CASCADE
-) ENGINE=InnoDB;
-
-CREATE TABLE registrant_net (
- registrant_net_id SERIAL NOT NULL,
- start_ip VARCHAR(40) NOT NULL,
- end_ip VARCHAR(40) NOT NULL,
- version TINYINT UNSIGNED NOT NULL,
- registrant_id BIGINT UNSIGNED NOT NULL,
- PRIMARY KEY (registrant_net_id),
- CONSTRAINT registrant_net_registrant_id
- FOREIGN KEY (registrant_id) REFERENCES registrant (registrant_id) ON DELETE CASCADE
-) ENGINE=InnoDB;
-
-CREATE TABLE roa_request (
- roa_request_id SERIAL NOT NULL,
- roa_request_handle VARCHAR(255) NOT NULL,
- asn BIGINT UNSIGNED NOT NULL,
- PRIMARY KEY (roa_request_id)
-) ENGINE=InnoDB;
-
-CREATE TABLE roa_request_prefix (
- prefix VARCHAR(40) NOT NULL,
- prefixlen TINYINT UNSIGNED NOT NULL,
- max_prefixlen TINYINT UNSIGNED NOT NULL,
- version TINYINT UNSIGNED NOT NULL,
- roa_request_id BIGINT UNSIGNED NOT NULL,
- PRIMARY KEY (roa_request_id, prefix, prefixlen, max_prefixlen),
- CONSTRAINT roa_request_prefix_roa_request_id
- FOREIGN KEY (roa_request_id) REFERENCES roa_request (roa_request_id) ON DELETE CASCADE
-) ENGINE=InnoDB;
-
-CREATE TABLE ghostbuster_request (
- ghostbuster_request_id SERIAL NOT NULL,
- self_handle VARCHAR(40) NOT NULL,
- parent_handle VARCHAR(40),
- vcard LONGBLOB NOT NULL,
- PRIMARY KEY (ghostbuster_request_id)
-) ENGINE=InnoDB;
-
--- Local Variables:
--- indent-tabs-mode: nil
--- End:
-'''
-
## @var pubd
## SQL schema pubd
pubd = '''-- $Id: pubd.sql 3465 2010-10-07 00:59:39Z sra $
diff --git a/rpkid/tests/old_irdbd.py b/rpkid/tests/old_irdbd.py
new file mode 100644
index 00000000..3fa84b80
--- /dev/null
+++ b/rpkid/tests/old_irdbd.py
@@ -0,0 +1,21 @@
+"""
+$Id$
+
+Copyright (C) 2010-2012 Internet Systems Consortium ("ISC")
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+"""
+
+if __name__ == "__main__":
+ import rpki.old_irdbd
+ rpki.old_irdbd.main()
diff --git a/rpkid/irdbd.sql b/rpkid/tests/old_irdbd.sql
index bf324cd8..bf324cd8 100644
--- a/rpkid/irdbd.sql
+++ b/rpkid/tests/old_irdbd.sql
diff --git a/rpkid/tests/smoketest.py b/rpkid/tests/smoketest.py
index 4c888f67..7dfc584c 100644
--- a/rpkid/tests/smoketest.py
+++ b/rpkid/tests/smoketest.py
@@ -124,8 +124,8 @@ pubd_name = cfg.get("pubd_name", "pubd")
prog_python = cfg.get("prog_python", sys.executable)
prog_rpkid = cfg.get("prog_rpkid", "../../rpkid.py")
-prog_irdbd = cfg.get("prog_irdbd", "../../irdbd.py")
-prog_poke = cfg.get("prog_poke", "../../testpoke.py")
+prog_irdbd = cfg.get("prog_irdbd", "../old_irdbd.py")
+prog_poke = cfg.get("prog_poke", "../testpoke.py")
prog_rootd = cfg.get("prog_rootd", "../../rootd.py")
prog_pubd = cfg.get("prog_pubd", "../../pubd.py")
prog_rsyncd = cfg.get("prog_rsyncd", "rsync")
@@ -135,7 +135,7 @@ prog_openssl = cfg.get("prog_openssl", "../../../openssl/openssl/apps/openss
rcynic_stats = cfg.get("rcynic_stats", "echo ; ../../../rcynic/show.sh %s.xml ; echo" % rcynic_name)
rpki_sql_file = cfg.get("rpki_sql_file", "../rpkid.sql")
-irdb_sql_file = cfg.get("irdb_sql_file", "../irdbd.sql")
+irdb_sql_file = cfg.get("irdb_sql_file", "old_irdbd.sql")
pub_sql_file = cfg.get("pub_sql_file", "../pubd.sql")
startup_delay = int(cfg.get("startup_delay", "10"))
diff --git a/rpkid/tests/sql-cleaner.py b/rpkid/tests/sql-cleaner.py
index 5d11781f..5db122e1 100644
--- a/rpkid/tests/sql-cleaner.py
+++ b/rpkid/tests/sql-cleaner.py
@@ -29,10 +29,10 @@ for name in ("rpkid", "irdbd", "pubd"):
password = cfg.get("%s_sql_password" % name, "fnord")
schema = []
- for line in getattr(rpki.sql_schemas, name).splitlines():
+ for line in getattr(rpki.sql_schemas, name, "").splitlines():
schema.extend(line.partition("--")[0].split())
schema = " ".join(schema).strip(";").split(";")
- schema = [statement.strip() for statement in schema if "DROP TABLE" not in statement]
+ schema = [statement.strip() for statement in schema if statement and "DROP TABLE" not in statement]
for i in xrange(12):
diff --git a/rpkid/tests/yamltest.py b/rpkid/tests/yamltest.py
index 403076f1..600a0e62 100644
--- a/rpkid/tests/yamltest.py
+++ b/rpkid/tests/yamltest.py
@@ -46,7 +46,7 @@ PERFORMANCE OF THIS SOFTWARE.
"""
import subprocess, re, os, getopt, sys, yaml, signal, time
-import rpki.resource_set, rpki.sundial, rpki.config, rpki.log, rpki.rpkic
+import rpki.resource_set, rpki.sundial, rpki.config, rpki.log, rpki.csv_utils
# Nasty regular expressions for parsing config files. Sadly, while
# the Python ConfigParser supports writing config files, it does so in
@@ -67,11 +67,11 @@ this_dir = os.getcwd()
test_dir = cleanpath(this_dir, "yamltest.dir")
rpkid_dir = cleanpath(this_dir, "..")
-prog_rpkic = cleanpath(rpkid_dir, "rpkic.py")
-prog_rpkid = cleanpath(rpkid_dir, "rpkid.py")
-prog_irdbd = cleanpath(rpkid_dir, "irdbd.py")
-prog_pubd = cleanpath(rpkid_dir, "pubd.py")
-prog_rootd = cleanpath(rpkid_dir, "rootd.py")
+prog_rpkic = cleanpath(rpkid_dir, "rpkic")
+prog_rpkid = cleanpath(rpkid_dir, "rpkid")
+prog_irdbd = cleanpath(rpkid_dir, "irdbd")
+prog_pubd = cleanpath(rpkid_dir, "pubd")
+prog_rootd = cleanpath(rpkid_dir, "rootd")
prog_openssl = cleanpath(this_dir, "../../openssl/openssl/apps/openssl")
if not os.path.exists(prog_openssl):
@@ -116,14 +116,14 @@ class allocation_db(list):
def __init__(self, yaml):
list.__init__(self)
self.root = allocation(yaml, self)
- assert self.root.is_root()
+ assert self.root.is_root
if self.root.crl_interval is None:
self.root.crl_interval = 24 * 60 * 60
if self.root.regen_margin is None:
self.root.regen_margin = 24 * 60 * 60
for a in self:
if a.sia_base is None:
- if a.runs_pubd():
+ if a.runs_pubd:
base = "rsync://localhost:%d/rpki/" % a.rsync_port
else:
base = a.parent.sia_base
@@ -134,14 +134,13 @@ class allocation_db(list):
a.crl_interval = a.parent.crl_interval
if a.regen_margin is None:
a.regen_margin = a.parent.regen_margin
- a.client_handle = "/".join(a.sia_base.rstrip("/").split("/")[3:])
self.root.closure()
self.map = dict((a.name, a) for a in self)
for a in self:
- if a.is_hosted():
+ if a.is_hosted:
a.hosted_by = self.map[a.hosted_by]
a.hosted_by.hosts.append(a)
- assert not a.is_root() and not a.hosted_by.is_hosted()
+ assert not a.is_root and not a.hosted_by.is_hosted
def dump(self):
"""
@@ -218,14 +217,14 @@ class allocation(object):
self.base.v6 = self.base.v6.union(r.v6.to_resource_set())
self.hosted_by = yaml.get("hosted_by")
self.hosts = []
- if not self.is_hosted():
+ if not self.is_hosted:
self.engine = self.allocate_engine()
self.rpkid_port = self.allocate_port()
self.irdbd_port = self.allocate_port()
- if self.runs_pubd():
+ if self.runs_pubd:
self.pubd_port = self.allocate_port()
self.rsync_port = self.allocate_port()
- if self.is_root():
+ if self.is_root:
self.rootd_port = self.allocate_port()
def closure(self):
@@ -253,55 +252,56 @@ class allocation(object):
if self.kids: s += " Kids: %s\n" % ", ".join(k.name for k in self.kids)
if self.parent: s += " Up: %s\n" % self.parent.name
if self.sia_base: s += " SIA: %s\n" % self.sia_base
- if self.is_hosted(): s += " Host: %s\n" % self.hosted_by.name
+ if self.is_hosted: s += " Host: %s\n" % self.hosted_by.name
if self.hosts: s += " Hosts: %s\n" % ", ".join(h.name for h in self.hosts)
for r in self.roa_requests: s += " ROA: %s\n" % r
- if not self.is_hosted(): s += " IPort: %s\n" % self.irdbd_port
- if self.runs_pubd(): s += " PPort: %s\n" % self.pubd_port
- if not self.is_hosted(): s += " RPort: %s\n" % self.rpkid_port
- if self.runs_pubd(): s += " SPort: %s\n" % self.rsync_port
- if self.is_root(): s += " TPort: %s\n" % self.rootd_port
+ if not self.is_hosted: s += " IPort: %s\n" % self.irdbd_port
+ if self.runs_pubd: s += " PPort: %s\n" % self.pubd_port
+ if not self.is_hosted: s += " RPort: %s\n" % self.rpkid_port
+ if self.runs_pubd: s += " SPort: %s\n" % self.rsync_port
+ if self.is_root: s += " TPort: %s\n" % self.rootd_port
return s + " Until: %s\n" % self.resources.valid_until
+ @property
def is_root(self):
"""
Is this the root node?
"""
return self.parent is None
+ @property
def is_hosted(self):
"""
Is this entity hosted?
"""
return self.hosted_by is not None
+ @property
def runs_pubd(self):
"""
Does this entity run a pubd?
"""
- return self.is_root() or not (self.is_hosted() or only_one_pubd)
+ return self.is_root or not (self.is_hosted or only_one_pubd)
def path(self, *names):
"""
Construct pathnames in this entity's test directory.
"""
- return cleanpath(test_dir, self.name, *names)
+ return cleanpath(test_dir, self.host.name, *names)
def csvout(self, fn):
"""
- Open and log a CSV output file. We use delimiter and dialect
- settings imported from the rpkic module, so that we automatically
- write CSV files in the right format.
+ Open and log a CSV output file.
"""
path = self.path(fn)
print "Writing", path
- return rpki.rpkic.csv_writer(path)
+ return rpki.csv_utils.csv_writer(path)
def up_down_url(self):
"""
Construct service URL for this node's parent.
"""
- parent_port = self.parent.hosted_by.rpkid_port if self.parent.is_hosted() else self.parent.rpkid_port
+ parent_port = self.parent.hosted_by.rpkid_port if self.parent.is_hosted else self.parent.rpkid_port
return "http://localhost:%d/up-down/%s/%s" % (parent_port, self.parent.name, self.name)
def dump_asns(self, fn):
@@ -312,37 +312,7 @@ class allocation(object):
for k in self.kids:
f.writerows((k.name, a) for a in k.resources.asn)
f.close()
-
- def dump_children(self, fn):
- """
- Write children CSV file.
- """
- f = self.csvout(fn)
- f.writerows((k.name, k.resources.valid_until, k.path("bpki/resources/ca.cer"))
- for k in self.kids)
- f.close()
-
- def dump_parents(self, fn):
- """
- Write parents CSV file.
- """
- f = self.csvout(fn)
- if self.is_root():
- f.writerow(("rootd",
- "http://localhost:%d/" % self.rootd_port,
- self.path("bpki/servers/ca.cer"),
- self.path("bpki/servers/ca.cer"),
- self.name,
- self.sia_base))
- else:
- parent_host = self.parent.hosted_by if self.parent.is_hosted() else self.parent
- f.writerow((self.parent.name,
- self.up_down_url(),
- self.parent.path("bpki/resources/ca.cer"),
- parent_host.path("bpki/servers/ca.cer"),
- self.name,
- self.sia_base))
- f.close()
+ self.run_rpkic("synchronize_asns", fn)
def dump_prefixes(self, fn):
"""
@@ -352,43 +322,45 @@ class allocation(object):
for k in self.kids:
f.writerows((k.name, p) for p in (k.resources.v4 + k.resources.v6))
f.close()
+ self.run_rpkic("synchronize_prefixes", fn)
def dump_roas(self, fn):
"""
Write ROA CSV file.
"""
- group = self.name if self.is_root() else self.parent.name
+ group = self.name if self.is_root else self.parent.name
f = self.csvout(fn)
for r in self.roa_requests:
f.writerows((p, r.asn, group)
for p in (r.v4 + r.v6 if r.v4 and r.v6 else r.v4 or r.v6 or ()))
f.close()
+ self.run_rpkic("synchronize_roa_requests", fn)
- def dump_clients(self, fn, db):
- """
- Write pubclients CSV file.
- """
- if self.runs_pubd():
- f = self.csvout(fn)
- f.writerows((s.client_handle, s.path("bpki/resources/ca.cer"), s.sia_base)
- for s in (db if only_one_pubd else [self] + self.kids))
- f.close()
-
- def find_pubd(self):
+ @property
+ def pubd(self):
"""
Walk up tree until we find somebody who runs pubd.
"""
s = self
- path = [s]
- while not s.runs_pubd():
+ while not s.runs_pubd:
s = s.parent
- path.append(s)
- return s, ".".join(i.name for i in reversed(path))
+ return s
- def find_host(self):
+ @property
+ def client_handle(self):
"""
- Figure out who hosts this entity.
+ Work out what pubd configure_publication_client will call us.
"""
+ path = []
+ s = self
+ while not s.runs_pubd:
+ path.append(s)
+ s = s.parent
+ path.append(s)
+ return ".".join(i.name for i in reversed(path))
+
+ @property
+ def host(self):
return self.hosted_by or self
def dump_conf(self, fn):
@@ -396,12 +368,10 @@ class allocation(object):
Write configuration file for OpenSSL and RPKI tools.
"""
- s, ignored = self.find_pubd()
-
r = { "handle" : self.name,
- "run_rpkid" : str(not self.is_hosted()),
- "run_pubd" : str(self.runs_pubd()),
- "run_rootd" : str(self.is_root()),
+ "run_rpkid" : str(not self.is_hosted),
+ "run_pubd" : str(self.runs_pubd),
+ "run_rootd" : str(self.is_root),
"openssl" : prog_openssl,
"irdbd_sql_database" : "irdb%d" % self.engine,
"irdbd_sql_username" : "irdb",
@@ -415,8 +385,8 @@ class allocation(object):
"pubd_sql_database" : "pubd%d" % self.engine,
"pubd_sql_username" : "pubd",
"pubd_server_host" : "localhost",
- "pubd_server_port" : str(s.pubd_port),
- "publication_rsync_server" : "localhost:%s" % s.rsync_port }
+ "pubd_server_port" : str(self.pubd.pubd_port),
+ "publication_rsync_server" : "localhost:%s" % self.pubd.rsync_port }
r.update(config_overrides)
@@ -442,7 +412,7 @@ class allocation(object):
Write rsyncd configuration file.
"""
- if self.runs_pubd():
+ if self.runs_pubd:
f = open(self.path(fn), "w")
print "Writing", f.name
f.writelines(s + "\n" for s in
@@ -457,40 +427,26 @@ class allocation(object):
"comment = RPKI test"))
f.close()
- def run_configure_daemons(self):
- """
- Run configure_daemons if this entity is not hosted by another engine.
- """
- if self.is_hosted():
- print "%s is hosted, skipping configure_daemons" % self.name
- else:
- files = [h.path("myrpki.xml") for h in self.hosts]
- self.run_rpkic("configure_daemons", *[f for f in files if os.path.exists(f)])
-
- def run_configure_resources(self):
- """
- Run configure_resources for this entity.
- """
- self.run_rpkic("configure_resources")
-
def run_rpkic(self, *args):
"""
- Run rpkic.py for this entity.
+ Run rpkic for this entity.
"""
- print 'Running "%s" for %s' % (" ".join(("rpkic",) + args), self.name)
- subprocess.check_call((sys.executable, prog_rpkic) + args, cwd = self.path())
+ cmd = (prog_rpkic, "-i", self.name, "-c", self.path("rpki.conf")) + args
+ print 'Running "%s"' % " ".join(cmd)
+ subprocess.check_call(cmd, cwd = self.host.path())
def run_python_daemon(self, prog):
"""
Start a Python daemon and return a subprocess.Popen object
representing the running daemon.
"""
- basename = os.path.basename(prog)
- p = subprocess.Popen((sys.executable, prog, "-d", "-c", self.path("rpki.conf")),
+ cmd = (prog, "-d", "-c", self.path("rpki.conf"))
+ log = os.path.splitext(os.path.basename(prog))[0] + ".log"
+ p = subprocess.Popen(cmd,
cwd = self.path(),
- stdout = open(self.path(os.path.splitext(basename)[0] + ".log"), "w"),
+ stdout = open(self.path(log), "w"),
stderr = subprocess.STDOUT)
- print "Running %s for %s: pid %d process %r" % (basename, self.name, p.pid, p)
+ print 'Running %s for %s: pid %d process %r' % (" ".join(cmd), self.name, p.pid, p)
return p
def run_rpkid(self):
@@ -604,21 +560,18 @@ try:
# Show what we loaded
- db.dump()
+ #db.dump()
# Set up each entity in our test
for d in db:
- os.makedirs(d.path())
- d.dump_asns("asns.csv")
- d.dump_prefixes("prefixes.csv")
- d.dump_roas("roas.csv")
- d.dump_conf("rpki.conf")
- d.dump_rsyncd("rsyncd.conf")
- if False:
- d.dump_children("children.csv")
- d.dump_parents("parents.csv")
- d.dump_clients("pubclients.csv", db)
+ if not d.is_hosted:
+ os.makedirs(d.path())
+ os.makedirs(d.path("bpki/resources"))
+ os.makedirs(d.path("bpki/servers"))
+ d.dump_conf("rpki.conf")
+ if d.runs_pubd:
+ d.dump_rsyncd("rsyncd.conf")
# Initialize BPKI and generate self-descriptor for each entity.
@@ -628,7 +581,7 @@ try:
# Create publication directories.
for d in db:
- if d.is_root() or d.runs_pubd():
+ if d.is_root or d.runs_pubd:
os.makedirs(d.path("publication"))
# Create RPKI root certificate.
@@ -636,11 +589,11 @@ try:
print "Creating rootd RPKI root certificate"
# Should use req -subj here to set subject name. Later.
- db.root.run_openssl("x509", "-req", "-sha256", "-outform", "DER",
- "-signkey", "bpki/servers/ca.key",
- "-in", "bpki/servers/ca.req",
- "-out", "publication/root.cer",
- "-extfile", "rpki.conf",
+ db.root.run_openssl("req", "-x509", "-sha256", "-outform", "DER",
+ "-newkey", "rsa:2048",
+ "-keyout", "bpki/servers/root.key",
+ "-out", "publication/root.cer",
+ "-config", "rpki.conf",
"-extensions", "rootd_x509_extensions")
@@ -659,62 +612,62 @@ try:
print
print "Configuring", d.name
print
- if d.is_root():
- d.run_rpkic("configure_publication_client", d.path("entitydb", "repositories", "%s.xml" % d.name))
+ if d.is_root:
+ assert not d.is_hosted
+ d.run_rpkic("configure_publication_client",
+ d.path("%s.%s.repository-request.xml" % (d.name, d.name)))
print
- d.run_rpkic("configure_repository", d.path("entitydb", "pubclients", "%s.xml" % d.name))
+ d.run_rpkic("configure_repository",
+ d.path("%s.repository-response.xml" % d.client_handle))
print
else:
- d.parent.run_rpkic("configure_child", d.path("entitydb", "identity.xml"))
+ d.parent.run_rpkic("configure_child", d.path("%s.identity.xml" % d.name))
print
- d.run_rpkic("configure_parent", d.parent.path("entitydb", "children", "%s.xml" % d.name))
+ d.run_rpkic("configure_parent",
+ d.parent.path("%s.%s.parent-response.xml" % (d.parent.name, d.name)))
print
- publisher, path = d.find_pubd()
- publisher.run_rpkic("configure_publication_client", d.path("entitydb", "repositories", "%s.xml" % d.parent.name))
+ d.pubd.run_rpkic("configure_publication_client",
+ d.path("%s.%s.repository-request.xml" % (d.name, d.parent.name)))
print
- d.run_rpkic("configure_repository", publisher.path("entitydb", "pubclients", "%s.xml" % path))
+ d.run_rpkic("configure_repository",
+ d.pubd.path("%s.repository-response.xml" % d.client_handle))
print
- parent_host = d.parent.find_host()
- if d.parent is not parent_host:
- d.parent.run_configure_resources()
- print
- parent_host.run_configure_daemons()
+ d.parent.run_rpkic("synchronize")
print
- if publisher is not parent_host:
- publisher.run_configure_daemons()
+ if d.pubd is not d.parent.host:
+ d.pubd.run_rpkic("synchronize")
print
print "Running daemons for", d.name
- if d.is_root():
+ if d.is_root:
progs.append(d.run_rootd())
- if not d.is_hosted():
+ if not d.is_hosted:
progs.append(d.run_irdbd())
progs.append(d.run_rpkid())
- if d.runs_pubd():
+ if d.runs_pubd:
progs.append(d.run_pubd())
progs.append(d.run_rsyncd())
- if d.is_root() or not d.is_hosted() or d.runs_pubd():
+ if d.is_root or not d.is_hosted or d.runs_pubd:
print "Giving", d.name, "daemons time to start up"
time.sleep(20)
print
assert all(p.poll() is None for p in progs)
- # Run configure_daemons to set up IRDB and RPKI objects. Need to
- # run a second time to push BSC certs out to rpkid. Nothing
- # should happen on the third pass. Oops, when hosting we need to
- # run configure_resources between passes, since only the hosted
- # entity can issue the BSC, etc.
+ # In theory we now only need to synchronize the new entity once.
+ d.run_rpkic("synchronize")
+ # Run through list again, to be sure we catch hosted cases.
+ # In theory this is no longer necessary.
+ if False:
for i in xrange(3):
- d.run_configure_resources()
- d.find_host().run_configure_daemons()
+ for d in db:
+ d.run_rpkic("synchronize")
- # Run through list again, to be sure we catch hosted cases
-
- for i in xrange(3):
- for d in db:
- d.run_configure_resources()
- d.run_configure_daemons()
+ # Load all the CSV files
+ for d in db:
+ d.dump_asns("%s.asns.csv" % d.name)
+ d.dump_prefixes("%s.prefixes.csv" % d.name)
+ d.dump_roas("%s.roas.csv" % d.name)
print "Done initializing daemons"
diff --git a/scripts/convert-from-entitydb-to-sql.py b/scripts/convert-from-entitydb-to-sql.py
index d96dd62d..1b469261 100644
--- a/scripts/convert-from-entitydb-to-sql.py
+++ b/scripts/convert-from-entitydb-to-sql.py
@@ -247,7 +247,11 @@ for filename in glob.iglob(os.path.join(entitydb, "children", "*.xml")):
registrant_id, valid_until = cur.fetchone()
valid_until = rpki.sundial.datetime.fromdatetime(valid_until)
- assert valid_until == rpki.sundial.datetime.fromXMLtime(e.get("valid_until"))
+ if valid_until != rpki.sundial.datetime.fromXMLtime(e.get("valid_until")):
+ print "WARNING: valid_until dates in XML and SQL do not match for child", child_handle
+ print " SQL:", str(valid_until)
+ print " XML:", str(rpki.sundial.datetime.fromXMLtime(e.get("valid_until")))
+ print "Blundering onwards"
child = rpki.irdb.Child.objects.get_or_create(
handle = child_handle,