00001 """
00002 Command line IR back-end control program for rpkid and pubd.
00003
00004 $Id: irbe_cli.py 3107 2010-03-16 23:13:08Z sra $
00005
00006 Copyright (C) 2009-2010 Internet Systems Consortium ("ISC")
00007
00008 Permission to use, copy, modify, and distribute this software for any
00009 purpose with or without fee is hereby granted, provided that the above
00010 copyright notice and this permission notice appear in all copies.
00011
00012 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00013 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00014 AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00015 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00016 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00017 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00018 PERFORMANCE OF THIS SOFTWARE.
00019
00020 Portions copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN")
00021
00022 Permission to use, copy, modify, and distribute this software for any
00023 purpose with or without fee is hereby granted, provided that the above
00024 copyright notice and this permission notice appear in all copies.
00025
00026 THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH
00027 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00028 AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT,
00029 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00030 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00031 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00032 PERFORMANCE OF THIS SOFTWARE.
00033 """
00034
00035 import getopt, sys, textwrap
00036 import rpki.left_right, rpki.https, rpki.x509, rpki.config, rpki.log
00037 import rpki.publication, rpki.async
00038
00039 pem_out = None
00040
00041 class UsageWrapper(textwrap.TextWrapper):
00042 """
00043 Call interface around Python textwrap.Textwrapper class.
00044 """
00045
00046 def __call__(self, *args):
00047 """Format arguments, with TextWrapper indentation."""
00048 return self.fill(textwrap.dedent(" ".join(args)))
00049
00050 usage_fill = UsageWrapper(subsequent_indent = " " * 4)
00051
00052 class reply_elt_mixin(object):
00053 """
00054 Protocol mix-in for printout of reply PDUs.
00055 """
00056
00057 is_cmd = False
00058
00059 def client_reply_decode(self):
00060 pass
00061
00062 def client_reply_show(self):
00063 print self.element_name
00064 for i in self.attributes + self.elements:
00065 if getattr(self, i) is not None:
00066 print " %s: %s" % (i, getattr(self, i))
00067
00068 class cmd_elt_mixin(reply_elt_mixin):
00069 """
00070 Protocol mix-in for command line client element PDUs.
00071 """
00072
00073 is_cmd = True
00074
00075
00076
00077
00078 excludes = ()
00079
00080 @classmethod
00081 def usage(cls):
00082 """
00083 Generate usage message for this PDU.
00084 """
00085 args = " ".join("--" + x + "=" for x in cls.attributes + cls.elements if x not in cls.excludes)
00086 bools = " ".join("--" + x for x in cls.booleans)
00087 if args and bools:
00088 return args + " " + bools
00089 else:
00090 return args or bools
00091
00092 def client_getopt(self, argv):
00093 """
00094 Parse options for this class.
00095 """
00096 opts, argv = getopt.getopt(argv, "", [x + "=" for x in self.attributes + self.elements if x not in self.excludes] + list(self.booleans))
00097 for o, a in opts:
00098 o = o[2:]
00099 handler = getattr(self, "client_query_" + o, None)
00100 if handler is not None:
00101 handler(a)
00102 elif o in self.booleans:
00103 setattr(self, o, True)
00104 else:
00105 assert o in self.attributes
00106 setattr(self, o, a)
00107 return argv
00108
00109 def client_query_bpki_cert(self, arg):
00110 """Special handler for --bpki_cert option."""
00111 self.bpki_cert = rpki.x509.X509(Auto_file = arg)
00112
00113 def client_query_glue(self, arg):
00114 """Special handler for --bpki_glue option."""
00115 self.bpki_glue = rpki.x509.X509(Auto_file = arg)
00116
00117 def client_query_bpki_cms_cert(self, arg):
00118 """Special handler for --bpki_cms_cert option."""
00119 self.bpki_cms_cert = rpki.x509.X509(Auto_file = arg)
00120
00121 def client_query_cms_glue(self, arg):
00122 """Special handler for --bpki_cms_glue option."""
00123 self.bpki_cms_glue = rpki.x509.X509(Auto_file = arg)
00124
00125 def client_query_bpki_https_cert(self, arg):
00126 """Special handler for --bpki_https_cert option."""
00127 self.bpki_https_cert = rpki.x509.X509(Auto_file = arg)
00128
00129 def client_query_https_glue(self, arg):
00130 """Special handler for --bpki_https_glue option."""
00131 self.bpki_https_glue = rpki.x509.X509(Auto_file = arg)
00132
00133 class cmd_msg_mixin(object):
00134 """
00135 Protocol mix-in for command line client message PDUs.
00136 """
00137
00138 @classmethod
00139 def usage(cls):
00140 """
00141 Generate usage message for this PDU.
00142 """
00143 for k, v in cls.pdus.items():
00144 if v.is_cmd:
00145 print usage_fill(k, v.usage())
00146
00147
00148
00149 class self_elt(cmd_elt_mixin, rpki.left_right.self_elt):
00150 pass
00151
00152 class bsc_elt(cmd_elt_mixin, rpki.left_right.bsc_elt):
00153
00154 excludes = ("pkcs10_request",)
00155
00156 def client_query_signing_cert(self, arg):
00157 """--signing_cert option."""
00158 self.signing_cert = rpki.x509.X509(Auto_file = arg)
00159
00160 def client_query_signing_cert_crl(self, arg):
00161 """--signing_cert_crl option."""
00162 self.signing_cert_crl = rpki.x509.CRL(Auto_file = arg)
00163
00164 def client_reply_decode(self):
00165 global pem_out
00166 if pem_out is not None and self.pkcs10_request is not None:
00167 if isinstance(pem_out, str):
00168 pem_out = open(pem_out, "w")
00169 pem_out.write(self.pkcs10_request.get_PEM())
00170
00171 class parent_elt(cmd_elt_mixin, rpki.left_right.parent_elt):
00172 pass
00173
00174 class child_elt(cmd_elt_mixin, rpki.left_right.child_elt):
00175 pass
00176
00177 class repository_elt(cmd_elt_mixin, rpki.left_right.repository_elt):
00178 pass
00179
00180 class list_published_objects_elt(cmd_elt_mixin, rpki.left_right.list_published_objects_elt):
00181 excludes = ("uri",)
00182
00183 class list_received_resources_elt(cmd_elt_mixin, rpki.left_right.list_received_resources_elt):
00184 excludes = ("notBefore", "notAfter", "uri", "sia_uri", "aia_uri", "asn", "ipv4", "ipv6")
00185
00186 class report_error_elt(reply_elt_mixin, rpki.left_right.report_error_elt):
00187 pass
00188
00189 class left_right_msg(cmd_msg_mixin, rpki.left_right.msg):
00190 pdus = dict((x.element_name, x)
00191 for x in (self_elt, bsc_elt, parent_elt, child_elt, repository_elt,
00192 list_published_objects_elt, list_received_resources_elt, report_error_elt))
00193
00194 class left_right_sax_handler(rpki.left_right.sax_handler):
00195 pdu = left_right_msg
00196
00197 class left_right_cms_msg(rpki.left_right.cms_msg):
00198 saxify = left_right_sax_handler.saxify
00199
00200
00201
00202 class config_elt(cmd_elt_mixin, rpki.publication.config_elt):
00203
00204 def client_query_bpki_crl(self, arg):
00205 """Special handler for --bpki_crl option."""
00206 self.bpki_crl = rpki.x509.CRL(Auto_file = arg)
00207
00208 class client_elt(cmd_elt_mixin, rpki.publication.client_elt):
00209 pass
00210
00211 class certificate_elt(cmd_elt_mixin, rpki.publication.certificate_elt):
00212 pass
00213
00214 class crl_elt(cmd_elt_mixin, rpki.publication.crl_elt):
00215 pass
00216
00217 class manifest_elt(cmd_elt_mixin, rpki.publication.manifest_elt):
00218 pass
00219
00220 class roa_elt(cmd_elt_mixin, rpki.publication.roa_elt):
00221 pass
00222
00223 class report_error_elt(reply_elt_mixin, rpki.publication.report_error_elt):
00224 pass
00225
00226 class publication_msg(cmd_msg_mixin, rpki.publication.msg):
00227 pdus = dict((x.element_name, x)
00228 for x in (config_elt, client_elt, certificate_elt, crl_elt, manifest_elt, roa_elt, report_error_elt))
00229
00230 class publication_sax_handler(rpki.publication.sax_handler):
00231 pdu = publication_msg
00232
00233 class publication_cms_msg(rpki.publication.cms_msg):
00234 saxify = publication_sax_handler.saxify
00235
00236
00237
00238 top_opts = ["config=", "help", "pem_out=", "quiet", "verbose"]
00239
00240 def usage(code = 1):
00241 print __doc__.strip()
00242 print
00243 print "Usage:"
00244 print
00245 print "# Top-level options:"
00246 print usage_fill(*["--" + x for x in top_opts])
00247 print
00248 print "# left-right protocol:"
00249 left_right_msg.usage()
00250 print
00251 print "# publication protocol:"
00252 publication_msg.usage()
00253 sys.exit(code)
00254
00255
00256
00257 rpki.log.init("irbe_cli")
00258
00259 argv = sys.argv[1:]
00260
00261 if not argv:
00262 usage(0)
00263
00264 cfg_file = "irbe.conf"
00265 verbose = True
00266
00267 opts, argv = getopt.getopt(argv, "c:hpqv?", top_opts)
00268 for o, a in opts:
00269 if o in ("-?", "-h", "--help"):
00270 usage(0)
00271 elif o in ("-c", "--config"):
00272 cfg_file = a
00273 elif o in ("-p", "--pem_out"):
00274 pem_out = a
00275 elif o in ("-q", "--quiet"):
00276 verbose = False
00277 elif o in ("-v", "--verbose"):
00278 verbose = True
00279
00280 if not argv:
00281 usage(1)
00282
00283 cfg = rpki.config.parser(cfg_file, "irbe_cli")
00284
00285 q_msg_left_right = []
00286 q_msg_publication = []
00287
00288 while argv:
00289 if argv[0] in left_right_msg.pdus:
00290 q_pdu = left_right_msg.pdus[argv[0]]()
00291 q_msg = q_msg_left_right
00292 elif argv[0] in publication_msg.pdus:
00293 q_pdu = publication_msg.pdus[argv[0]]()
00294 q_msg = q_msg_publication
00295 else:
00296 usage(1)
00297 argv = q_pdu.client_getopt(argv[1:])
00298 q_msg.append(q_pdu)
00299
00300 if q_msg_left_right:
00301
00302 class left_right_proto(object):
00303 cms_msg = left_right_cms_msg
00304 msg = left_right_msg
00305
00306 call_rpkid = rpki.async.sync_wrapper(rpki.https.caller(
00307 proto = left_right_proto,
00308 client_key = rpki.x509.RSA( Auto_file = cfg.get("rpkid-irbe-key")),
00309 client_cert = rpki.x509.X509(Auto_file = cfg.get("rpkid-irbe-cert")),
00310 server_ta = rpki.x509.X509(Auto_file = cfg.get("rpkid-bpki-ta")),
00311 server_cert = rpki.x509.X509(Auto_file = cfg.get("rpkid-cert")),
00312 url = cfg.get("rpkid-url"),
00313 debug = verbose))
00314
00315 call_rpkid(*q_msg_left_right)
00316
00317 if q_msg_publication:
00318
00319 class publication_proto(object):
00320 msg = publication_msg
00321 cms_msg = publication_cms_msg
00322
00323 call_pubd = rpki.async.sync_wrapper(rpki.https.caller(
00324 proto = publication_proto,
00325 client_key = rpki.x509.RSA( Auto_file = cfg.get("pubd-irbe-key")),
00326 client_cert = rpki.x509.X509(Auto_file = cfg.get("pubd-irbe-cert")),
00327 server_ta = rpki.x509.X509(Auto_file = cfg.get("pubd-bpki-ta")),
00328 server_cert = rpki.x509.X509(Auto_file = cfg.get("pubd-cert")),
00329 url = cfg.get("pubd-url")),
00330 debug = verbose)
00331
00332 call_pubd(*q_msg_publication)