RPKI Engine 1.0
|
00001 """ 00002 RPKI "up-down" protocol. 00003 00004 $Id: up_down.py 3746 2011-03-27 01:24:39Z sra $ 00005 00006 Copyright (C) 2009--2011 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 base64, lxml.etree 00036 import rpki.resource_set, rpki.x509, rpki.exceptions, rpki.log 00037 import rpki.xml_utils, rpki.relaxng 00038 00039 xmlns = "http://www.apnic.net/specs/rescerts/up-down/" 00040 00041 nsmap = { None : xmlns } 00042 00043 class base_elt(object): 00044 """ 00045 Generic PDU object. 00046 00047 Virtual class, just provides some default methods. 00048 """ 00049 00050 def startElement(self, stack, name, attrs): 00051 """ 00052 Ignore startElement() if there's no specific handler. 00053 00054 Some elements have no attributes and we only care about their 00055 text content. 00056 """ 00057 pass 00058 00059 def endElement(self, stack, name, text): 00060 """ 00061 Ignore endElement() if there's no specific handler. 00062 00063 If we don't need to do anything else, just pop the stack. 00064 """ 00065 stack.pop() 00066 00067 def make_elt(self, name, *attrs): 00068 """ 00069 Construct a element, copying over a set of attributes. 00070 """ 00071 elt = lxml.etree.Element("{%s}%s" % (xmlns, name), nsmap=nsmap) 00072 for key in attrs: 00073 val = getattr(self, key, None) 00074 if val is not None: 00075 elt.set(key, str(val)) 00076 return elt 00077 00078 def make_b64elt(self, elt, name, value): 00079 """ 00080 Construct a sub-element with Base64 text content. 00081 """ 00082 if value is not None and not value.empty(): 00083 lxml.etree.SubElement(elt, "{%s}%s" % (xmlns, name), nsmap=nsmap).text = value.get_Base64() 00084 00085 def serve_pdu(self, q_msg, r_msg, child, callback, errback): 00086 """ 00087 Default PDU handler to catch unexpected types. 00088 """ 00089 raise rpki.exceptions.BadQuery, "Unexpected query type %s" % q_msg.type 00090 00091 def check_response(self): 00092 """ 00093 Placeholder for response checking. 00094 """ 00095 pass 00096 00097 class multi_uri(list): 00098 """ 00099 Container for a set of URIs. 00100 """ 00101 00102 def __init__(self, ini): 00103 """ 00104 Initialize a set of URIs, which includes basic some syntax checking. 00105 """ 00106 list.__init__(self) 00107 if isinstance(ini, (list, tuple)): 00108 self[:] = ini 00109 elif isinstance(ini, str): 00110 self[:] = ini.split(",") 00111 for s in self: 00112 if s.strip() != s or "://" not in s: 00113 raise rpki.exceptions.BadURISyntax, "Bad URI \"%s\"" % s 00114 else: 00115 raise TypeError 00116 00117 def __str__(self): 00118 """ 00119 Convert a multi_uri back to a string representation. 00120 """ 00121 return ",".join(self) 00122 00123 def rsync(self): 00124 """ 00125 Find first rsync://... URI in self. 00126 """ 00127 for s in self: 00128 if s.startswith("rsync://"): 00129 return s 00130 return None 00131 00132 class certificate_elt(base_elt): 00133 """ 00134 Up-Down protocol representation of an issued certificate. 00135 """ 00136 00137 def startElement(self, stack, name, attrs): 00138 """ 00139 Handle attributes of <certificate/> element. 00140 """ 00141 assert name == "certificate", "Unexpected name %s, stack %s" % (name, stack) 00142 self.cert_url = multi_uri(attrs["cert_url"]) 00143 self.req_resource_set_as = rpki.resource_set.resource_set_as(attrs.get("req_resource_set_as")) 00144 self.req_resource_set_ipv4 = rpki.resource_set.resource_set_ipv4(attrs.get("req_resource_set_ipv4")) 00145 self.req_resource_set_ipv6 = rpki.resource_set.resource_set_ipv6(attrs.get("req_resource_set_ipv6")) 00146 00147 def endElement(self, stack, name, text): 00148 """ 00149 Handle text content of a <certificate/> element. 00150 """ 00151 assert name == "certificate", "Unexpected name %s, stack %s" % (name, stack) 00152 self.cert = rpki.x509.X509(Base64 = text) 00153 stack.pop() 00154 00155 def toXML(self): 00156 """ 00157 Generate a <certificate/> element. 00158 """ 00159 elt = self.make_elt("certificate", "cert_url", 00160 "req_resource_set_as", "req_resource_set_ipv4", "req_resource_set_ipv6") 00161 elt.text = self.cert.get_Base64() 00162 return elt 00163 00164 class class_elt(base_elt): 00165 """ 00166 Up-Down protocol representation of a resource class. 00167 """ 00168 00169 issuer = None 00170 00171 def __init__(self): 00172 """ 00173 Initialize class_elt. 00174 """ 00175 base_elt.__init__(self) 00176 self.certs = [] 00177 00178 def startElement(self, stack, name, attrs): 00179 """ 00180 Handle <class/> elements and their children. 00181 """ 00182 if name == "certificate": 00183 cert = certificate_elt() 00184 self.certs.append(cert) 00185 stack.append(cert) 00186 cert.startElement(stack, name, attrs) 00187 elif name != "issuer": 00188 assert name == "class", "Unexpected name %s, stack %s" % (name, stack) 00189 self.class_name = attrs["class_name"] 00190 self.cert_url = multi_uri(attrs["cert_url"]) 00191 self.suggested_sia_head = attrs.get("suggested_sia_head") 00192 self.resource_set_as = rpki.resource_set.resource_set_as(attrs["resource_set_as"]) 00193 self.resource_set_ipv4 = rpki.resource_set.resource_set_ipv4(attrs["resource_set_ipv4"]) 00194 self.resource_set_ipv6 = rpki.resource_set.resource_set_ipv6(attrs["resource_set_ipv6"]) 00195 self.resource_set_notafter = rpki.sundial.datetime.fromXMLtime(attrs.get("resource_set_notafter")) 00196 00197 def endElement(self, stack, name, text): 00198 """ 00199 Handle <class/> elements and their children. 00200 """ 00201 if name == "issuer": 00202 self.issuer = rpki.x509.X509(Base64 = text) 00203 else: 00204 assert name == "class", "Unexpected name %s, stack %s" % (name, stack) 00205 stack.pop() 00206 00207 def toXML(self): 00208 """ 00209 Generate a <class/> element. 00210 """ 00211 elt = self.make_elt("class", "class_name", "cert_url", "resource_set_as", 00212 "resource_set_ipv4", "resource_set_ipv6", 00213 "resource_set_notafter", "suggested_sia_head") 00214 elt.extend([i.toXML() for i in self.certs]) 00215 self.make_b64elt(elt, "issuer", self.issuer) 00216 return elt 00217 00218 def to_resource_bag(self): 00219 """ 00220 Build a resource_bag from from this <class/> element. 00221 """ 00222 return rpki.resource_set.resource_bag(self.resource_set_as, 00223 self.resource_set_ipv4, 00224 self.resource_set_ipv6, 00225 self.resource_set_notafter) 00226 00227 def from_resource_bag(self, bag): 00228 """ 00229 Set resources of this class element from a resource_bag. 00230 """ 00231 self.resource_set_as = bag.asn 00232 self.resource_set_ipv4 = bag.v4 00233 self.resource_set_ipv6 = bag.v6 00234 self.resource_set_notafter = bag.valid_until 00235 00236 class list_pdu(base_elt): 00237 """ 00238 Up-Down protocol "list" PDU. 00239 """ 00240 00241 def toXML(self): 00242 """Generate (empty) payload of "list" PDU.""" 00243 return [] 00244 00245 def serve_pdu(self, q_msg, r_msg, child, callback, errback): 00246 """ 00247 Serve one "list" PDU. 00248 """ 00249 00250 def handle(irdb_resources): 00251 00252 r_msg.payload = list_response_pdu() 00253 00254 if irdb_resources.valid_until > rpki.sundial.now(): 00255 for parent in child.parents: 00256 for ca in parent.cas: 00257 ca_detail = ca.active_ca_detail 00258 if not ca_detail: 00259 continue 00260 resources = ca_detail.latest_ca_cert.get_3779resources().intersection(irdb_resources) 00261 if resources.empty(): 00262 continue 00263 rc = class_elt() 00264 rc.class_name = str(ca.ca_id) 00265 rc.cert_url = multi_uri(ca_detail.ca_cert_uri) 00266 rc.from_resource_bag(resources) 00267 for child_cert in child.fetch_child_certs(ca_detail = ca_detail): 00268 c = certificate_elt() 00269 c.cert_url = multi_uri(child_cert.uri) 00270 c.cert = child_cert.cert 00271 rc.certs.append(c) 00272 rc.issuer = ca_detail.latest_ca_cert 00273 r_msg.payload.classes.append(rc) 00274 00275 callback() 00276 00277 self.gctx.irdb_query_child_resources(child.self.self_handle, child.child_handle, handle, errback) 00278 00279 @classmethod 00280 def query(cls, parent, cb, eb): 00281 """ 00282 Send a "list" query to parent. 00283 """ 00284 try: 00285 rpki.log.info('Sending "list" request to parent %s' % parent.parent_handle) 00286 parent.query_up_down(cls(), cb, eb) 00287 except (rpki.async.ExitNow, SystemExit): 00288 raise 00289 except Exception, e: 00290 eb(e) 00291 00292 class class_response_syntax(base_elt): 00293 """ 00294 Syntax for Up-Down protocol "list_response" and "issue_response" PDUs. 00295 """ 00296 00297 def __init__(self): 00298 """ 00299 Initialize class_response_syntax. 00300 """ 00301 base_elt.__init__(self) 00302 self.classes = [] 00303 00304 def startElement(self, stack, name, attrs): 00305 """ 00306 Handle "list_response" and "issue_response" PDUs. 00307 """ 00308 assert name == "class", "Unexpected name %s, stack %s" % (name, stack) 00309 c = class_elt() 00310 self.classes.append(c) 00311 stack.append(c) 00312 c.startElement(stack, name, attrs) 00313 00314 def toXML(self): 00315 """Generate payload of "list_response" and "issue_response" PDUs.""" 00316 return [c.toXML() for c in self.classes] 00317 00318 class list_response_pdu(class_response_syntax): 00319 """ 00320 Up-Down protocol "list_response" PDU. 00321 """ 00322 pass 00323 00324 class issue_pdu(base_elt): 00325 """ 00326 Up-Down protocol "issue" PDU. 00327 """ 00328 00329 def startElement(self, stack, name, attrs): 00330 """ 00331 Handle "issue" PDU. 00332 """ 00333 assert name == "request", "Unexpected name %s, stack %s" % (name, stack) 00334 self.class_name = attrs["class_name"] 00335 self.req_resource_set_as = rpki.resource_set.resource_set_as(attrs.get("req_resource_set_as")) 00336 self.req_resource_set_ipv4 = rpki.resource_set.resource_set_ipv4(attrs.get("req_resource_set_ipv4")) 00337 self.req_resource_set_ipv6 = rpki.resource_set.resource_set_ipv6(attrs.get("req_resource_set_ipv6")) 00338 00339 def endElement(self, stack, name, text): 00340 """ 00341 Handle "issue" PDU. 00342 """ 00343 assert name == "request", "Unexpected name %s, stack %s" % (name, stack) 00344 self.pkcs10 = rpki.x509.PKCS10(Base64 = text) 00345 stack.pop() 00346 00347 def toXML(self): 00348 """ 00349 Generate payload of "issue" PDU. 00350 """ 00351 elt = self.make_elt("request", "class_name", "req_resource_set_as", 00352 "req_resource_set_ipv4", "req_resource_set_ipv6") 00353 elt.text = self.pkcs10.get_Base64() 00354 return [elt] 00355 00356 def serve_pdu(self, q_msg, r_msg, child, callback, errback): 00357 """ 00358 Serve one issue request PDU. 00359 """ 00360 00361 # Subsetting not yet implemented, this is the one place where we 00362 # have to handle it, by reporting that we're lame. 00363 00364 if self.req_resource_set_as or \ 00365 self.req_resource_set_ipv4 or \ 00366 self.req_resource_set_ipv6: 00367 raise rpki.exceptions.NotImplementedYet, "req_* attributes not implemented yet, sorry" 00368 00369 # Check the request 00370 self.pkcs10.check_valid_rpki() 00371 ca = child.ca_from_class_name(self.class_name) 00372 ca_detail = ca.active_ca_detail 00373 if ca_detail is None: 00374 raise rpki.exceptions.NoActiveCA, "No active CA for class %r" % self.class_name 00375 00376 # Check current cert, if any 00377 00378 def got_resources(irdb_resources): 00379 00380 if irdb_resources.valid_until < rpki.sundial.now(): 00381 raise rpki.exceptions.IRDBExpired, "IRDB entry for child %s expired %s" % (child.child_handle, irdb_resources.valid_until) 00382 00383 resources = irdb_resources.intersection(ca_detail.latest_ca_cert.get_3779resources()) 00384 req_key = self.pkcs10.getPublicKey() 00385 req_sia = self.pkcs10.get_SIA() 00386 child_cert = child.fetch_child_certs(ca_detail = ca_detail, ski = req_key.get_SKI(), unique = True) 00387 00388 # Generate new cert or regenerate old one if necessary 00389 00390 publisher = rpki.rpkid.publication_queue() 00391 00392 if child_cert is None: 00393 child_cert = ca_detail.issue( 00394 ca = ca, 00395 child = child, 00396 subject_key = req_key, 00397 sia = req_sia, 00398 resources = resources, 00399 publisher = publisher) 00400 else: 00401 child_cert = child_cert.reissue( 00402 ca_detail = ca_detail, 00403 sia = req_sia, 00404 resources = resources, 00405 publisher = publisher) 00406 00407 def done(): 00408 c = certificate_elt() 00409 c.cert_url = multi_uri(child_cert.uri) 00410 c.cert = child_cert.cert 00411 rc = class_elt() 00412 rc.class_name = self.class_name 00413 rc.cert_url = multi_uri(ca_detail.ca_cert_uri) 00414 rc.from_resource_bag(resources) 00415 rc.certs.append(c) 00416 rc.issuer = ca_detail.latest_ca_cert 00417 r_msg.payload = issue_response_pdu() 00418 r_msg.payload.classes.append(rc) 00419 callback() 00420 00421 self.gctx.sql.sweep() 00422 assert child_cert and child_cert.sql_in_db 00423 publisher.call_pubd(done, errback) 00424 00425 self.gctx.irdb_query_child_resources(child.self.self_handle, child.child_handle, got_resources, errback) 00426 00427 @classmethod 00428 def query(cls, parent, ca, ca_detail, callback, errback): 00429 """ 00430 Send an "issue" request to parent associated with ca. 00431 """ 00432 assert ca_detail is not None and ca_detail.state in ("pending", "active") 00433 sia = ((rpki.oids.name2oid["id-ad-caRepository"], ("uri", ca.sia_uri)), 00434 (rpki.oids.name2oid["id-ad-rpkiManifest"], ("uri", ca_detail.manifest_uri))) 00435 self = cls() 00436 self.class_name = ca.parent_resource_class 00437 self.pkcs10 = rpki.x509.PKCS10.create_ca(ca_detail.private_key_id, sia) 00438 rpki.log.info('Sending "issue" request to parent %s' % parent.parent_handle) 00439 parent.query_up_down(self, callback, errback) 00440 00441 class issue_response_pdu(class_response_syntax): 00442 """ 00443 Up-Down protocol "issue_response" PDU. 00444 """ 00445 00446 def check_response(self): 00447 """ 00448 Check whether this looks like a reasonable issue_response PDU. 00449 XML schema should be tighter for this response. 00450 """ 00451 if len(self.classes) != 1 or len(self.classes[0].certs) != 1: 00452 raise rpki.exceptions.BadIssueResponse 00453 00454 class revoke_syntax(base_elt): 00455 """ 00456 Syntax for Up-Down protocol "revoke" and "revoke_response" PDUs. 00457 """ 00458 00459 def startElement(self, stack, name, attrs): 00460 """Handle "revoke" PDU.""" 00461 self.class_name = attrs["class_name"] 00462 self.ski = attrs["ski"] 00463 00464 def toXML(self): 00465 """Generate payload of "revoke" PDU.""" 00466 return [self.make_elt("key", "class_name", "ski")] 00467 00468 class revoke_pdu(revoke_syntax): 00469 """ 00470 Up-Down protocol "revoke" PDU. 00471 """ 00472 00473 def get_SKI(self): 00474 """ 00475 Convert g(SKI) encoding from PDU back to raw SKI. 00476 """ 00477 return base64.urlsafe_b64decode(self.ski + "=") 00478 00479 def serve_pdu(self, q_msg, r_msg, child, cb, eb): 00480 """ 00481 Serve one revoke request PDU. 00482 """ 00483 00484 def done(): 00485 r_msg.payload = revoke_response_pdu() 00486 r_msg.payload.class_name = self.class_name 00487 r_msg.payload.ski = self.ski 00488 cb() 00489 00490 ca = child.ca_from_class_name(self.class_name) 00491 publisher = rpki.rpkid.publication_queue() 00492 for ca_detail in ca.ca_details: 00493 for child_cert in child.fetch_child_certs(ca_detail = ca_detail, ski = self.get_SKI()): 00494 child_cert.revoke(publisher = publisher) 00495 self.gctx.sql.sweep() 00496 publisher.call_pubd(done, eb) 00497 00498 @classmethod 00499 def query(cls, ca, gski, cb, eb): 00500 """ 00501 Send a "revoke" request for certificate(s) named by gski to parent associated with ca. 00502 """ 00503 parent = ca.parent 00504 self = cls() 00505 self.class_name = ca.parent_resource_class 00506 self.ski = gski 00507 rpki.log.info('Sending "revoke" request for SKI %s to parent %s' % (gski, parent.parent_handle)) 00508 parent.query_up_down(self, cb, eb) 00509 00510 class revoke_response_pdu(revoke_syntax): 00511 """ 00512 Up-Down protocol "revoke_response" PDU. 00513 """ 00514 00515 pass 00516 00517 class error_response_pdu(base_elt): 00518 """ 00519 Up-Down protocol "error_response" PDU. 00520 """ 00521 00522 codes = { 00523 1101 : "Already processing request", 00524 1102 : "Version number error", 00525 1103 : "Unrecognised request type", 00526 1201 : "Request - no such resource class", 00527 1202 : "Request - no resources allocated in resource class", 00528 1203 : "Request - badly formed certificate request", 00529 1301 : "Revoke - no such resource class", 00530 1302 : "Revoke - no such key", 00531 2001 : "Internal Server Error - Request not performed" } 00532 00533 exceptions = { 00534 rpki.exceptions.NoActiveCA : 1202 } 00535 00536 def __init__(self, exception = None): 00537 """ 00538 Initialize an error_response PDU from an exception object. 00539 """ 00540 base_elt.__init__(self) 00541 if exception is not None: 00542 self.status = self.exceptions.get(type(exception), 2001) 00543 self.description = str(exception) 00544 00545 def endElement(self, stack, name, text): 00546 """ 00547 Handle "error_response" PDU. 00548 """ 00549 if name == "status": 00550 code = int(text) 00551 if code not in self.codes: 00552 raise rpki.exceptions.BadStatusCode, "%s is not a known status code" % code 00553 self.status = code 00554 elif name == "description": 00555 self.description = text 00556 else: 00557 assert name == "message", "Unexpected name %s, stack %s" % (name, stack) 00558 stack.pop() 00559 stack[-1].endElement(stack, name, text) 00560 00561 def toXML(self): 00562 """ 00563 Generate payload of "error_response" PDU. 00564 """ 00565 assert self.status in self.codes 00566 elt = self.make_elt("status") 00567 elt.text = str(self.status) 00568 payload = [elt] 00569 if self.description: 00570 elt = self.make_elt("description") 00571 elt.text = str(self.description) 00572 elt.set("{http://www.w3.org/XML/1998/namespace}lang", "en-US") 00573 payload.append(elt) 00574 return payload 00575 00576 def check_response(self): 00577 """ 00578 Handle an error response. For now, just raise an exception, 00579 perhaps figure out something more clever to do later. 00580 """ 00581 raise rpki.exceptions.UpstreamError, self.codes[self.status] 00582 00583 class message_pdu(base_elt): 00584 """ 00585 Up-Down protocol message wrapper PDU. 00586 """ 00587 00588 version = 1 00589 00590 name2type = { 00591 "list" : list_pdu, 00592 "list_response" : list_response_pdu, 00593 "issue" : issue_pdu, 00594 "issue_response" : issue_response_pdu, 00595 "revoke" : revoke_pdu, 00596 "revoke_response" : revoke_response_pdu, 00597 "error_response" : error_response_pdu } 00598 00599 type2name = dict((v, k) for k, v in name2type.items()) 00600 00601 def toXML(self): 00602 """ 00603 Generate payload of message PDU. 00604 """ 00605 elt = self.make_elt("message", "version", "sender", "recipient", "type") 00606 elt.extend(self.payload.toXML()) 00607 return elt 00608 00609 def startElement(self, stack, name, attrs): 00610 """ 00611 Handle message PDU. 00612 00613 Payload of the <message/> element varies depending on the "type" 00614 attribute, so after some basic checks we have to instantiate the 00615 right class object to handle whatever kind of PDU this is. 00616 """ 00617 assert name == "message", "Unexpected name %s, stack %s" % (name, stack) 00618 assert self.version == int(attrs["version"]) 00619 self.sender = attrs["sender"] 00620 self.recipient = attrs["recipient"] 00621 self.type = attrs["type"] 00622 self.payload = self.name2type[attrs["type"]]() 00623 stack.append(self.payload) 00624 00625 def __str__(self): 00626 """ 00627 Convert a message PDU to a string. 00628 """ 00629 lxml.etree.tostring(self.toXML(), pretty_print = True, encoding = "UTF-8") 00630 00631 def serve_top_level(self, child, callback): 00632 """ 00633 Serve one message request PDU. 00634 """ 00635 00636 r_msg = message_pdu() 00637 r_msg.sender = self.recipient 00638 r_msg.recipient = self.sender 00639 00640 def done(): 00641 r_msg.type = self.type2name[type(r_msg.payload)] 00642 callback(r_msg) 00643 00644 def lose(e): 00645 rpki.log.traceback() 00646 callback(self.serve_error(e)) 00647 00648 try: 00649 self.log_query(child) 00650 self.payload.serve_pdu(self, r_msg, child, done, lose) 00651 except (rpki.async.ExitNow, SystemExit): 00652 raise 00653 except Exception, e: 00654 lose(e) 00655 00656 def log_query(self, child): 00657 """ 00658 Log query we're handling. Separate method so rootd can override. 00659 """ 00660 rpki.log.info("Serving %s query from child %s [sender %s, recipient %s]" % (self.type, child.child_handle, self.sender, self.recipient)) 00661 00662 def serve_error(self, exception): 00663 """ 00664 Generate an error_response message PDU. 00665 """ 00666 r_msg = message_pdu() 00667 r_msg.sender = self.recipient 00668 r_msg.recipient = self.sender 00669 r_msg.payload = error_response_pdu(exception) 00670 r_msg.type = self.type2name[type(r_msg.payload)] 00671 return r_msg 00672 00673 @classmethod 00674 def make_query(cls, payload, sender, recipient): 00675 """ 00676 Construct one message PDU. 00677 """ 00678 assert not cls.type2name[type(payload)].endswith("_response") 00679 if sender is None: 00680 sender = "tweedledee" 00681 if recipient is None: 00682 recipient = "tweedledum" 00683 self = cls() 00684 self.sender = sender 00685 self.recipient = recipient 00686 self.payload = payload 00687 self.type = self.type2name[type(payload)] 00688 return self 00689 00690 class sax_handler(rpki.xml_utils.sax_handler): 00691 """ 00692 SAX handler for Up-Down protocol. 00693 """ 00694 00695 pdu = message_pdu 00696 name = "message" 00697 version = "1" 00698 00699 class cms_msg(rpki.x509.XML_CMS_object): 00700 """ 00701 Class to hold a CMS-signed up-down PDU. 00702 """ 00703 00704 encoding = "UTF-8" 00705 schema = rpki.relaxng.up_down 00706 saxify = sax_handler.saxify