00001 """
00002 Command line IR back-end control program for rpkid and pubd.
00003
00004 $Id: irbe-cli.py 1880 2008-06-12 21:54:53Z sra $
00005
00006 Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN")
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 ARIN DISCLAIMS ALL WARRANTIES WITH
00013 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00014 AND FITNESS. IN NO EVENT SHALL ARIN 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
00021 import getopt, sys, textwrap
00022 import rpki.left_right, rpki.https, rpki.x509, rpki.config, rpki.log, rpki.publication
00023
00024 pem_out = None
00025
00026 class UsageWrapper(textwrap.TextWrapper):
00027 """Call interface around Python textwrap.Textwrapper class."""
00028
00029 def __call__(self, *args):
00030 """Format arguments, with TextWrapper indentation."""
00031 return self.fill(textwrap.dedent(" ".join(args)))
00032
00033 usage_fill = UsageWrapper(subsequent_indent = " " * 4)
00034
00035 class cmd_elt_mixin(object):
00036 """Protocol mix-in for command line client element PDUs."""
00037
00038
00039
00040
00041
00042
00043 excludes = ()
00044
00045 @classmethod
00046 def usage(cls):
00047 """Generate usage message for this PDU."""
00048 args = " ".join("--" + x + "=" for x in cls.attributes + cls.elements if x not in cls.excludes)
00049 opts = " ".join("--" + x for x in cls.booleans)
00050 if args and opts:
00051 return args + " " + opts
00052 else:
00053 return args or opts
00054
00055 def client_getopt(self, argv):
00056 """Parse options for this class."""
00057 opts, argv = getopt.getopt(argv, "", [x + "=" for x in self.attributes + self.elements if x not in self.excludes] + list(self.booleans))
00058 for o, a in opts:
00059 o = o[2:]
00060 handler = getattr(self, "client_query_" + o, None)
00061 if handler is not None:
00062 handler(a)
00063 elif o in self.booleans:
00064 setattr(self, o, True)
00065 else:
00066 assert o in self.attributes
00067 setattr(self, o, a)
00068 return argv
00069
00070 def client_query_bpki_cert(self, arg):
00071 """Special handler for --bpki_cert option."""
00072 self.bpki_cert = rpki.x509.X509(Auto_file = arg)
00073
00074 def client_query_glue(self, arg):
00075 """Special handler for --bpki_glue option."""
00076 self.bpki_glue = rpki.x509.X509(Auto_file = arg)
00077
00078 def client_query_bpki_cms_cert(self, arg):
00079 """Special handler for --bpki_cms_cert option."""
00080 self.bpki_cms_cert = rpki.x509.X509(Auto_file = arg)
00081
00082 def client_query_cms_glue(self, arg):
00083 """Special handler for --bpki_cms_glue option."""
00084 self.bpki_cms_glue = rpki.x509.X509(Auto_file = arg)
00085
00086 def client_query_bpki_https_cert(self, arg):
00087 """Special handler for --bpki_https_cert option."""
00088 self.bpki_https_cert = rpki.x509.X509(Auto_file = arg)
00089
00090 def client_query_https_glue(self, arg):
00091 """Special handler for --bpki_https_glue option."""
00092 self.bpki_https_glue = rpki.x509.X509(Auto_file = arg)
00093
00094 def client_reply_decode(self):
00095 pass
00096
00097 def client_reply_show(self):
00098 print self.element_name
00099 for i in self.attributes + self.elements:
00100 if getattr(self, i) is not None:
00101 print " %s: %s" % (i, getattr(self, i))
00102
00103 class cmd_msg_mixin(object):
00104 """Protocol mix-in for command line client message PDUs."""
00105
00106 @classmethod
00107 def usage(cls):
00108 """Generate usage message for this PDU."""
00109 for k,v in cls.pdus.items():
00110 print usage_fill(k, v.usage())
00111
00112
00113
00114 class self_elt(cmd_elt_mixin, rpki.left_right.self_elt):
00115 pass
00116
00117 class bsc_elt(cmd_elt_mixin, rpki.left_right.bsc_elt):
00118
00119 excludes = ("pkcs10_request",)
00120
00121 def client_query_signing_cert(self, arg):
00122 """--signing_cert option."""
00123 self.signing_cert = rpki.x509.X509(Auto_file = arg)
00124
00125 def client_query_signing_cert_crl(self, arg):
00126 """--signing_cert_crl option."""
00127 self.signing_cert_crl = rpki.x509.CRL(Auto_file = arg)
00128
00129 def client_reply_decode(self):
00130 global pem_out
00131 if pem_out is not None and self.pkcs10_request is not None:
00132 if isinstance(pem_out, str):
00133 pem_out = open(pem_out, "w")
00134 pem_out.write(self.pkcs10_request.get_PEM())
00135
00136 class parent_elt(cmd_elt_mixin, rpki.left_right.parent_elt):
00137 pass
00138
00139 class child_elt(cmd_elt_mixin, rpki.left_right.child_elt):
00140 pass
00141
00142 class repository_elt(cmd_elt_mixin, rpki.left_right.repository_elt):
00143 pass
00144
00145 class route_origin_elt(cmd_elt_mixin, rpki.left_right.route_origin_elt):
00146
00147 def client_query_as_number(self, arg):
00148 """Handle autonomous sequence numbers."""
00149 self.as_number = long(arg)
00150
00151 def client_query_ipv4(self, arg):
00152 """Handle IPv4 addresses."""
00153 self.ipv4 = resource_set.roa_prefix_set_ipv4(arg)
00154
00155 def client_query_ipv6(self, arg):
00156 """Handle IPv6 addresses."""
00157 self.ipv6 = resource_set.roa_prefix_set_ipv6(arg)
00158
00159 class left_right_msg(cmd_msg_mixin, rpki.left_right.msg):
00160 pdus = dict((x.element_name, x)
00161 for x in (self_elt, bsc_elt, parent_elt, child_elt, repository_elt, route_origin_elt))
00162
00163 class left_right_sax_handler(rpki.left_right.sax_handler):
00164 pdu = left_right_msg
00165
00166 class left_right_cms_msg(rpki.left_right.cms_msg):
00167 saxify = left_right_sax_handler.saxify
00168
00169
00170
00171 class config_elt(cmd_elt_mixin, rpki.publication.config_elt):
00172
00173 def client_query_bpki_crl(self, arg):
00174 """Special handler for --bpki_crl option."""
00175 self.bpki_crl = rpki.x509.CRL(Auto_file = arg)
00176
00177 class client_elt(cmd_elt_mixin, rpki.publication.client_elt):
00178 pass
00179
00180 class certificate_elt(cmd_elt_mixin, rpki.publication.certificate_elt):
00181 pass
00182
00183 class crl_elt(cmd_elt_mixin, rpki.publication.crl_elt):
00184 pass
00185
00186 class manifest_elt(cmd_elt_mixin, rpki.publication.manifest_elt):
00187 pass
00188
00189 class roa_elt(cmd_elt_mixin, rpki.publication.roa_elt):
00190 pass
00191
00192 class publication_msg(cmd_msg_mixin, rpki.publication.msg):
00193 pdus = dict((x.element_name, x)
00194 for x in (config_elt, client_elt, certificate_elt, crl_elt, manifest_elt, roa_elt))
00195
00196 class publication_sax_handler(rpki.publication.sax_handler):
00197 pdu = publication_msg
00198
00199 class publication_cms_msg(rpki.publication.cms_msg):
00200 saxify = publication_sax_handler.saxify
00201
00202
00203
00204 top_opts = ["config=", "help", "pem_out=", "verbose"]
00205
00206 def usage(code = 1):
00207 print __doc__.strip()
00208 print
00209 print "Usage:"
00210 print
00211 print "# Top-level options:"
00212 print usage_fill(*["--" + x for x in top_opts])
00213 print
00214 print "# left-right protocol:"
00215 left_right_msg.usage()
00216 print
00217 print "# publication protocol:"
00218 publication_msg.usage()
00219 sys.exit(code)
00220
00221
00222
00223 def call_daemon(cms_class, client_key, client_cert, server_ta, url, q_msg):
00224 q_cms, q_xml = cms_class.wrap(q_msg, client_key, client_cert, pretty_print = True)
00225 if verbose:
00226 print q_xml
00227 der = rpki.https.client(client_key = client_key,
00228 client_cert = client_cert,
00229 server_ta = server_ta,
00230 url = url,
00231 msg = q_cms)
00232 r_msg, r_xml = cms_class.unwrap(der, server_ta, pretty_print = True)
00233 print r_xml
00234 for r_pdu in r_msg:
00235 r_pdu.client_reply_decode()
00236
00237
00238
00239 rpki.log.init("irbe-cli")
00240
00241 argv = sys.argv[1:]
00242
00243 if not argv:
00244 usage(0)
00245
00246 cfg_file = "irbe.conf"
00247 verbose = False
00248
00249 opts, argv = getopt.getopt(argv, "c:hpv?", top_opts)
00250 for o, a in opts:
00251 if o in ("-?", "-h", "--help"):
00252 usage(0)
00253 elif o in ("-c", "--config"):
00254 cfg_file = a
00255 elif o in ("-p", "--pem_out"):
00256 pem_out = a
00257 elif o in ("-v", "--verbose"):
00258 verbose = True
00259
00260 if not argv:
00261 usage(1)
00262
00263 cfg = rpki.config.parser(cfg_file, "irbe-cli")
00264
00265 q_msg_left_right = left_right_msg()
00266 q_msg_left_right.type = "query"
00267
00268 q_msg_publication = publication_msg()
00269 q_msg_publication.type = "query"
00270
00271 while argv:
00272 if argv[0] in left_right_msg.pdus:
00273 q_pdu = left_right_msg.pdus[argv[0]]()
00274 q_msg = q_msg_left_right
00275 elif argv[0] in publication_msg.pdus:
00276 q_pdu = publication_msg.pdus[argv[0]]()
00277 q_msg = q_msg_publication
00278 else:
00279 usage(1)
00280 argv = q_pdu.client_getopt(argv[1:])
00281 q_msg.append(q_pdu)
00282
00283 if q_msg_left_right:
00284 call_daemon(
00285 cms_class = left_right_cms_msg,
00286 client_key = rpki.x509.RSA( Auto_file = cfg.get("rpkid-irbe-key")),
00287 client_cert = rpki.x509.X509(Auto_file = cfg.get("rpkid-irbe-cert")),
00288 server_ta = (rpki.x509.X509(Auto_file = cfg.get("rpkid-bpki-ta")),
00289 rpki.x509.X509(Auto_file = cfg.get("rpkid-cert"))),
00290 url = cfg.get("rpkid-url"),
00291 q_msg = q_msg_left_right)
00292
00293 if q_msg_publication:
00294 call_daemon(
00295 cms_class = publication_cms_msg,
00296 client_key = rpki.x509.RSA( Auto_file = cfg.get("pubd-irbe-key")),
00297 client_cert = rpki.x509.X509(Auto_file = cfg.get("pubd-irbe-cert")),
00298 server_ta = (rpki.x509.X509(Auto_file = cfg.get("pubd-bpki-ta")),
00299 rpki.x509.X509(Auto_file = cfg.get("pubd-cert"))),
00300 url = cfg.get("pubd-url"),
00301 q_msg = q_msg_publication)