00001 """
00002 Command line IR back-end control program for rpkid and pubd.
00003
00004 $Id: irbe_cli.py 3449 2010-09-16 21:30:30Z 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.http, 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 class cmd_msg_mixin(object):
00126 """
00127 Protocol mix-in for command line client message PDUs.
00128 """
00129
00130 @classmethod
00131 def usage(cls):
00132 """
00133 Generate usage message for this PDU.
00134 """
00135 for k, v in cls.pdus.items():
00136 if v.is_cmd:
00137 print usage_fill(k, v.usage())
00138
00139
00140
00141 class self_elt(cmd_elt_mixin, rpki.left_right.self_elt):
00142 pass
00143
00144 class bsc_elt(cmd_elt_mixin, rpki.left_right.bsc_elt):
00145
00146 excludes = ("pkcs10_request",)
00147
00148 def client_query_signing_cert(self, arg):
00149 """--signing_cert option."""
00150 self.signing_cert = rpki.x509.X509(Auto_file = arg)
00151
00152 def client_query_signing_cert_crl(self, arg):
00153 """--signing_cert_crl option."""
00154 self.signing_cert_crl = rpki.x509.CRL(Auto_file = arg)
00155
00156 def client_reply_decode(self):
00157 global pem_out
00158 if pem_out is not None and self.pkcs10_request is not None:
00159 if isinstance(pem_out, str):
00160 pem_out = open(pem_out, "w")
00161 pem_out.write(self.pkcs10_request.get_PEM())
00162
00163 class parent_elt(cmd_elt_mixin, rpki.left_right.parent_elt):
00164 pass
00165
00166 class child_elt(cmd_elt_mixin, rpki.left_right.child_elt):
00167 pass
00168
00169 class repository_elt(cmd_elt_mixin, rpki.left_right.repository_elt):
00170 pass
00171
00172 class list_published_objects_elt(cmd_elt_mixin, rpki.left_right.list_published_objects_elt):
00173 excludes = ("uri",)
00174
00175 class list_received_resources_elt(cmd_elt_mixin, rpki.left_right.list_received_resources_elt):
00176 excludes = ("parent_handle", "notBefore", "notAfter", "uri", "sia_uri", "aia_uri", "asn", "ipv4", "ipv6")
00177
00178 class report_error_elt(reply_elt_mixin, rpki.left_right.report_error_elt):
00179 pass
00180
00181 class left_right_msg(cmd_msg_mixin, rpki.left_right.msg):
00182 pdus = dict((x.element_name, x)
00183 for x in (self_elt, bsc_elt, parent_elt, child_elt, repository_elt,
00184 list_published_objects_elt, list_received_resources_elt, report_error_elt))
00185
00186 class left_right_sax_handler(rpki.left_right.sax_handler):
00187 pdu = left_right_msg
00188
00189 class left_right_cms_msg(rpki.left_right.cms_msg):
00190 saxify = left_right_sax_handler.saxify
00191
00192
00193
00194 class config_elt(cmd_elt_mixin, rpki.publication.config_elt):
00195
00196 def client_query_bpki_crl(self, arg):
00197 """Special handler for --bpki_crl option."""
00198 self.bpki_crl = rpki.x509.CRL(Auto_file = arg)
00199
00200 class client_elt(cmd_elt_mixin, rpki.publication.client_elt):
00201 pass
00202
00203 class certificate_elt(cmd_elt_mixin, rpki.publication.certificate_elt):
00204 pass
00205
00206 class crl_elt(cmd_elt_mixin, rpki.publication.crl_elt):
00207 pass
00208
00209 class manifest_elt(cmd_elt_mixin, rpki.publication.manifest_elt):
00210 pass
00211
00212 class roa_elt(cmd_elt_mixin, rpki.publication.roa_elt):
00213 pass
00214
00215 class report_error_elt(reply_elt_mixin, rpki.publication.report_error_elt):
00216 pass
00217
00218 class publication_msg(cmd_msg_mixin, rpki.publication.msg):
00219 pdus = dict((x.element_name, x)
00220 for x in (config_elt, client_elt, certificate_elt, crl_elt, manifest_elt, roa_elt, report_error_elt))
00221
00222 class publication_sax_handler(rpki.publication.sax_handler):
00223 pdu = publication_msg
00224
00225 class publication_cms_msg(rpki.publication.cms_msg):
00226 saxify = publication_sax_handler.saxify
00227
00228
00229
00230 top_opts = ["config=", "help", "pem_out=", "quiet", "verbose"]
00231
00232 def usage(code = 1):
00233 print __doc__.strip()
00234 print
00235 print "Usage:"
00236 print
00237 print "# Top-level options:"
00238 print usage_fill(*["--" + x for x in top_opts])
00239 print
00240 print "# left-right protocol:"
00241 left_right_msg.usage()
00242 print
00243 print "# publication protocol:"
00244 publication_msg.usage()
00245 sys.exit(code)
00246
00247
00248
00249 rpki.log.init("irbe_cli")
00250
00251 argv = sys.argv[1:]
00252
00253 if not argv:
00254 usage(0)
00255
00256 cfg_file = "irbe.conf"
00257 verbose = True
00258
00259 opts, argv = getopt.getopt(argv, "c:hpqv?", top_opts)
00260 for o, a in opts:
00261 if o in ("-?", "-h", "--help"):
00262 usage(0)
00263 elif o in ("-c", "--config"):
00264 cfg_file = a
00265 elif o in ("-p", "--pem_out"):
00266 pem_out = a
00267 elif o in ("-q", "--quiet"):
00268 verbose = False
00269 elif o in ("-v", "--verbose"):
00270 verbose = True
00271
00272 if not argv:
00273 usage(1)
00274
00275 cfg = rpki.config.parser(cfg_file, "irbe_cli")
00276
00277 q_msg_left_right = []
00278 q_msg_publication = []
00279
00280 while argv:
00281 if argv[0] in left_right_msg.pdus:
00282 q_pdu = left_right_msg.pdus[argv[0]]()
00283 q_msg = q_msg_left_right
00284 elif argv[0] in publication_msg.pdus:
00285 q_pdu = publication_msg.pdus[argv[0]]()
00286 q_msg = q_msg_publication
00287 else:
00288 usage(1)
00289 argv = q_pdu.client_getopt(argv[1:])
00290 q_msg.append(q_pdu)
00291
00292 if q_msg_left_right:
00293
00294 class left_right_proto(object):
00295 cms_msg = left_right_cms_msg
00296 msg = left_right_msg
00297
00298 call_rpkid = rpki.async.sync_wrapper(rpki.http.caller(
00299 proto = left_right_proto,
00300 client_key = rpki.x509.RSA( Auto_file = cfg.get("rpkid-irbe-key")),
00301 client_cert = rpki.x509.X509(Auto_file = cfg.get("rpkid-irbe-cert")),
00302 server_ta = rpki.x509.X509(Auto_file = cfg.get("rpkid-bpki-ta")),
00303 server_cert = rpki.x509.X509(Auto_file = cfg.get("rpkid-cert")),
00304 url = cfg.get("rpkid-url"),
00305 debug = verbose))
00306
00307 call_rpkid(*q_msg_left_right)
00308
00309 if q_msg_publication:
00310
00311 class publication_proto(object):
00312 msg = publication_msg
00313 cms_msg = publication_cms_msg
00314
00315 call_pubd = rpki.async.sync_wrapper(rpki.http.caller(
00316 proto = publication_proto,
00317 client_key = rpki.x509.RSA( Auto_file = cfg.get("pubd-irbe-key")),
00318 client_cert = rpki.x509.X509(Auto_file = cfg.get("pubd-irbe-cert")),
00319 server_ta = rpki.x509.X509(Auto_file = cfg.get("pubd-bpki-ta")),
00320 server_cert = rpki.x509.X509(Auto_file = cfg.get("pubd-cert")),
00321 url = cfg.get("pubd-url")),
00322 debug = verbose)
00323
00324 call_pubd(*q_msg_publication)