RFC 2769

Routing Policy System Replication

๐Ÿ“… published February 2000, from ietf

RFC 2769: Routing Policy System Replication โœจ

๐ŸŽ€ Title block tea ๐ŸŽ€

  • Number: RFC 2769
  • Title: Routing Policy System Replication
  • Authors: C. Villamizar (Avici Systems), C. Alaettinoglu and R. Govindan (ISI), and D. Meyer (Cisco)
  • Category: Standards Track, so this is an actual Internet standards track protocol ๐Ÿ˜ค
  • Date: February 2000 ๐Ÿ“
  • Obsoletes / Updates: Nothing listed. It doesn't replace or update any other RFC in its header.

Status of this Memo ๐Ÿ“œ

Okay so this part is the official paperwork ๐Ÿ’… This document is an Internet standards track protocol for the Internet community, and it's asking for discussion and suggestions for improvements. For the current standardization state and status of this protocol, check the "Internet Official Protocol Standards" (STD 1). Distribution of this memo is unlimited, so share it with everyone ๐ŸŒˆ

Copyright (C) The Internet Society (2000). All Rights Reserved. ๐Ÿซถ

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. ๐Ÿ‘‘ These are the BCP 14 requirement words, so they're doing a lot of work in the rest of the doc.

Abstract ๐ŸŒธ

Okay so the RIPE database specs and RPSL are the languages used as the basis for representing information in a routing policy system ๐Ÿงš A repository for that routing policy information is called a routing registry, and a routing registry is a way of swapping info needed for lots of important Internet operations ๐Ÿ’œ

Here's the vibe check: a routing policy system has to keep some integrity or it's literally useless ๐Ÿ’€ The Routing Policy System Security RFC [3] handles that by proposing an authentication and authorization model.

This document is about the next step. It covers spreading data across multiple repositories and delegating authority over subsets of the data to other repositories, all without messing up the authorization model from the Routing Policy System Security RFC. Iconic behavior ๐Ÿฆ‹

Table of Contents ๐Ÿ—‚๏ธ

1  Overview . . . . . . . . . . . . . . . . . . . . . . . . . . .   3
2  Data Representation  . . . . . . . . . . . . . . . . . . . . .   4
3  Authentication and Authorization . . . . . . . . . . . . . . .   5
4  Repository Hierarchy . . . . . . . . . . . . . . . . . . . . .   6
5  Additions to RPSL  . . . . . . . . . . . . . . . . . . . . . .   6
   5.1  repository object . . . . . . . . . . . . . . . . . . . .   7
   5.2  delegated attribute . . . . . . . . . . . . . . . . . . .   9
   5.3  integrity attribute . . . . . . . . . . . . . . . . . . .  10
6  Interactions with a Repository or Mirror . . . . . . . . . . .  11
   6.1  Initial Transaction Submission  . . . . . . . . . . . . .  12
   6.2  Redistribution of Transactions  . . . . . . . . . . . . .  12
   6.3  Transaction Commit and Confirmation . . . . . . . . . . .  12
7  Data Format Summaries, Transaction Encapsulation and Processing 13
   7.1  Transaction Submit and Confirm  . . . . . . . . . . . . .  13
   7.2  Redistribution of Transactions  . . . . . . . . . . . . .  16
   7.3  Redistribution Protocol Description . . . . . . . . . . .  16
        7.3.1 Explicitly Requesting Transactions  . . . . . . . .  21
        7.3.2 Heartbeat Processing  . . . . . . . . . . . . . . .  22
   7.4  Transaction Commit  . . . . . . . . . . . . . . . . . . .  23
   7.5  Database Snapshot . . . . . . . . . . . . . . . . . . . .  24
   7.6  Authenticating Operations . . . . . . . . . . . . . . . .  25
A  Examples . . . . . . . . . . . . . . . . . . . . . . . . . . .  27
   A.1  Initial Object Submission and Redistribution  . . . . . .  27
   A.2  Transaction Redistribution Encoding . . . . . . . . . . .  29
   A.3  Transaction Protocol Encoding . . . . . . . . . . . . . .  31
   A.4  Transaction Redistribution  . . . . . . . . . . . . . . .  32
B  Technical Discussion . . . . . . . . . . . . . . . . . . . . .  35
   B.1  Server Processing . . . . . . . . . . . . . . . . . . . .  35
        B.1.1 getting connected . . . . . . . . . . . . . . . . .  35
        B.1.2 rolling transaction logs forward and back . . . . .  35
        B.1.3 committing or disposing of transactions . . . . . .  36
        B.1.4 dealing with concurrency  . . . . . . . . . . . . .  36
   B.2  Repository Mirroring for Redundancy . . . . . . . . . . .  36
   B.3  Trust Relationships . . . . . . . . . . . . . . . . . . .  37
   B.4  A Router as a Minimal Mirror  . . . . . . . . . . . . . .  38
   B.5  Dealing with Errors . . . . . . . . . . . . . . . . . . .  38
C  Deployment Considerations  . . . . . . . . . . . . . . . . . .  39
D  Privacy of Contact Information . . . . . . . . . . . . . . . .  39
References  . . . . . . . . . . . . . . . . . . . . . . . . . . .  40
Security Considerations . . . . . . . . . . . . . . . . . . . . .  41
Authors' Addresses  . . . . . . . . . . . . . . . . . . . . . . .  41
Full Copyright Statement  . . . . . . . . . . . . . . . . . . . .  42

1. Overview ๐Ÿ”ฅ

Okay bestie, the core problem: a routing registry has to keep some integrity or it's useless ๐Ÿ˜ญ The IRR is being used more and more for stuff that needs stronger data integrity and security, and people also want to decentralize it further. This document proposes a way to decentralize the routing registry that still fits how the IRR is used, and that doesn't wreck data integrity and security even when the IRR is spread across less trusted repositories. Main character energy ๐Ÿ‘‘

There are two proposed ways to authenticate routing registry information. Let's go through them ๐Ÿงš

  • Authorization and authentication checks on transactions: The integrity of the routing registry data is insured by repeating authorization checks as transactions are processed. As transactions get flooded, each remote registry has the option to repeat the authorization and authentication checks. This scales with the total number of changes to the registry, no matter how many registries exist ๐Ÿ’– When you're querying, the repository has to be trustworthy. If an organization doesn't trust any of the available repositories or mirrors, they can run their own mirror and repeat the authorization checks there. Then they can send queries to a mirror under their own administration, which presumably can be trusted ๐Ÿซถ
  • Signing routing registry objects: The alternate that looks super attractive on the surface is signing the objects themselves. ๐Ÿ™ˆ Closer look: signing objects by itself is flawed. When it's used on top of signing transactions and rechecking authorizations as changes happen, it adds nothing. For critical objects like inetnums and routes to be valid, authorization checks have to allow the insertion. The objects those checks were made against can change later. To repeat the checks later, you'd need to know the state of other objects, possibly sitting in other repositories. If the repository isn't trusted, the change history of the object would have to be traced back to its insertion, and the change history of any object depended on for authorization would also need rechecking. That trace-back would have to go all the way to the epoch, or at least to a point where only trusted objects were relied on for authorizations. If the search depth is at all limited, authorization could be faked just by exceeding the search depth with a chain of authorization references back to falsified objects ๐Ÿ’€ That would be grossly inefficient. Basically, just verifying that an object is signed gives no assurance that its addition was properly authorized ๐Ÿ™…โ€โ™€๏ธ

There's a minor distinction between a repository and a mirror ๐Ÿ“ A repository is responsible for the initial authorization and authentication checks on transactions related to its local objects, and then those transactions get flooded out to adjacent repositories. A mirror gets flooded transactions from remote repositories but isn't the authoritative source for any objects. From a protocol standpoint, repositories and mirrors look identical in the flooding topology โœจ

Either a repository or a mirror may recheck all or a subset of the transactions flooded to it. A repository or mirror may also choose not to recheck authorization and authentication on transactions received from a trusted adjacency. The reasoning is that the adjacent repository is trusted and wouldn't have flooded the information unless it had already made those checks ๐ŸŒˆ

If all adjacencies are trusted for a given mirror, there's no need to implement the code that checks authorization and authentication. The mirror only needs to be able to check the signatures on the flooded transactions from the adjacent repository. This is an important special case, because it could let a router act as a mirror. Only changes to the registry database get received through flooding, which is a very low volume, and only the signature of the adjacent mirror or repository has to be checked. It's giving efficiency and I'm obsessed ๐Ÿ˜ญ๐Ÿ’…

Part 1 of 9 done, bestie! More parts are coming, so stay tuned ๐Ÿฆ‹๐Ÿ’–

2. Data Representation ๐ŸŽ€

okay so RPSL gives a complete description of what lives inside a routing repository [1] ๐ŸŒธ. Tons of RPSL data objects are literally unchanged from RIPE, and RPSL references the RIPE-181 spec as recorded in RFC-1786 [2] ๐Ÿ’…. It's all about external data representation, which means data can be stored differently inside a routing registry ๐Ÿงš. But the integrity of the distributed registry data needs the authorization and authentication additions to RPSL described in [3] ๐Ÿ”’.

Some extra stuff is needed so you can find all the repositories after locating just one of them, and so certain parameters can be selected per repository and are easy to grab ๐Ÿ—บ๏ธ. Those additions are described in Section 5.

Exchanging data needs some form of encapsulation ๐Ÿ“จ. The de-facto one is whatever the RIPE tools accept: a plain text file, or plain text in the body of an RFC-822 formatted mail message, with the info needed for authentication pulled from the mail headers. Merit slightly modified this by using the PGP signed portion of a plain text file, or the PGP signed portion of the body of a mail message ๐Ÿฆ‹.

Flooding is a different vibe from the initial submission ๐ŸŒŠ. To repeat the authorization checks, you need to know the state of every repository holding objects that the authorization checks reference. So each transaction in a repository gets a sequence number, and flooded transactions must carry the sequence number of each repository that the transaction's authorization depends on ๐Ÿ”ข.

To repeat authorization checks, it must be possible to retrieve older revisions of objects ๐Ÿ•ฐ๏ธ. How that happens is up to the implementation, and that's totally fine ๐Ÿ™Œ. One method that's pretty simple is to keep the traversal data structures for all current objects even if their state is deleted, keep the sequence number at which each version of an object became effective, and keep back links to prior versions. To find a prior version of an object, you look back through the references until you hit a version whose sequence number is less than or equal to the sequence number you're searching for ๐Ÿ”.

The existing very simple forms of encapsulation are good enough for the initial submission of a database transaction, and should be kept around as long as backward compatibility needs them ๐Ÿซถ. A more robust encapsulation and submission protocol, with optional confirmation, is defined in Section 6.1 ๐Ÿ’ช. An encapsulation for exchanging transactions between repositories is covered in Section 6. Query encapsulation and protocol are outside the scope of this document ๐Ÿ™…โ€โ™€๏ธ.


3. Authentication and Authorization ๐Ÿ”

Control has to be exercised over who can make changes and what changes they're allowed to make ๐Ÿ‘€. The who vs. what split is exactly what separates authentication from authorization, and that's the big distinction here ๐Ÿ’œ.

  • Authentication is the means to determine who is attempting to make a change ๐Ÿชช.
  • Authorization is the determination of whether a transaction that has passed a specific authentication check is allowed to perform a given operation โœ….

A submitted transaction carries a claimed identity ๐Ÿท๏ธ. Depending on the type of transaction, the authorization will depend on related objects ๐Ÿงฉ.

The "mnt-by", "mnt-routes", or "mnt-lower" attributes in those related objects reference "maintainer" objects ๐ŸŽ€. Those maintainer objects contain "auth" attributes ๐Ÿ—๏ธ. The auth attributes hold an authorization method and data, which generally includes the claimed identity and some form of public encryption key used to authenticate the claim ๐Ÿ”‘.

Authentication is done on transactions โœจ. Authentication should also be done between repositories, to keep the information exchange trustworthy ๐Ÿค. To comply with import, export, and use restrictions around the world, no encryption capability is specified ๐ŸŒ. Transactions must not be encrypted, because using decryption software may be illegal in some parts of the world โš ๏ธ.


4. Repository Hierarchy ๐ŸŒณ

With multiple repositories, "repository" objects are needed to spread the word about new repositories and to give an automated way to figure out the supported access methods and other characteristics of each repository ๐Ÿ“ฃ. The repository object is described in Section 5 ๐Ÿ’–.

Every repository should have a special repository object named ROOT ๐Ÿ‘‘. It should point to the root repository or to a higher level repository. This lets queries go to your local repository while still reaching the full set of registries for resolving hierarchically allocated objects ๐Ÿงญ.

Each repository may have an "expire" attribute โฐ. The expire attribute decides whether a repository has to be updated before a local transaction that depends on it can go ahead ๐Ÿšฆ.

The repository object also has attributes describing the access methods and the supported authentication methods of the repository ๐Ÿ“. The "query-address" attribute gives a host name and a port number used to direct queries ๐Ÿ“. The "response-auth-type" attribute gives the authentication types the repository may use when responding to queries ๐Ÿซง. The "submit-address" attribute gives a host name and a port number used to submit objects to the repository ๐Ÿ“ฎ. The "submit-auth-type" attribute gives the authentication types the repository may use when responding to submissions ๐Ÿ”.


5. Additions to RPSL ๐Ÿ’…

There are very few additions to RPSL defined here, honestly so minimal ๐Ÿฅฐ. These additions are called RPSL "objects". They live in the repository database and can be retrieved with ordinary queries ๐Ÿ“š. Objects are made of "attributes", which are name/value pairs ๐Ÿท๏ธ.

Attributes may be mandatory or optional ๐Ÿง. They may be single or multiple ๐Ÿ”ข. One or more attributes may be part of a key field ๐Ÿ”‘. Some attributes may need to be unique ๐Ÿ’Ž.

Most of the data formats in this document are encapsulations used in transaction exchanges ๐Ÿ“ฆ. These are called "meta-objects". Unlike RPSL "objects", "meta-objects" do not reside in the database, but some of them must be kept in a transaction log ๐Ÿ““. A similar format is used to represent "meta-objects" too, and they also consist of "attributes" that are name/value pairs ๐ŸŽ€.

This section has all of the additions to RPSL described in this document ๐Ÿ“‹. It describes only RPSL objects. Other sections describe only meta-objects ๐Ÿ™Œ.

5.1. repository object ๐ŸŒธ

A root repository must be agreed upon ๐Ÿค. Ideally, that repository would contain only top level delegations and pointers to the other repositories used in those delegations ๐ŸŒณ. It would be wise to allow only cryptographically strong transactions in the root repository [3] ๐Ÿ›ก๏ธ.

The root repository contains references to other repositories ๐Ÿ”—. An object of the following form identifies another repository ๐Ÿ‘‡.

  repository:         RIPE
  query-address:      whois://whois.ripe.net
  response-auth-type: PGPKEY-23F5CE35 # pointer to key-cert object
  response-auth-type: none
  remarks:            you can request rsa signature on queries
  remarks:            PGP required on submissions
  submit-address:     mailto://auto-dbm@ripe.net
  submit-address:     rps-query://whois.ripe.net:43
  submit-auth-type:   pgp-key, crypt-pw, mail-from
  remarks:            these are the authentication types supported
  mnt-by:             maint-ripe-db
  expire:             0000 04:00:00
  heartbeat-interval: 0000 01:00:00
  ...
  remarks:            admin and technical contact, etc
  source:             IANA

The attributes of the repository object are listed below ๐Ÿ“.

    repository      key  mandatory  single
    query-address        mandatory  multiple
    response-auth-type   mandatory  multiple
    submit-address       mandatory  multiple
    submit-auth-type     mandatory  multiple
    repository-cert      mandatory  multiple
    expire               mandatory  single
    heartbeat-interval   mandatory  single
    descr                optional   multiple
    remarks              optional   multiple
    admin-c              mandatory  multiple
    tech-c               mandatory  multiple
    notify               optional   multiple
    mnt-by               mandatory  multiple
    changed              mandatory  multiple
    source               mandatory  single

In the object type above, only a small number of the attribute types are new ๐ŸŒŸ. They are:

repository ๐Ÿ : This attribute provides the name of the repository. It's the key field for the object, it's single, and it must be globally unique. It's the same name used in the source attribute of all objects in that repository.

query-address ๐Ÿ”Ž: This attribute provides a url for directing queries. "rps-query" or "whois" can be used as the protocol identifier.

response-auth-type ๐Ÿชช: This attribute provides an authentication type that may be used by the repository when responding to user queries. Its syntax and semantics are the same as the auth attribute of the maintainer class.

submit-address ๐Ÿ“ฌ: This attribute provides a url for submitting objects to the repository.

submit-auth-type ๐Ÿ”: This attribute provides the authentication types that the repository allows users to use when submitting registrations.

repository-cert ๐Ÿ“œ: This attribute provides a reference to a public key certificate in the form of an RPSL key-cert object. It can be multiple, so the repository can use more than one method of signature ๐Ÿ–‹๏ธ.

heartbeat-interval ๐Ÿ’“: Heartbeat meta-objects are sent by this repository at the rate of one heartbeat meta-object per the interval indicated. The value of this attribute shall be expressed in the form "dddd hh:mm:ss", where "dddd" represents days, "hh" represents hours, "mm" minutes and "ss" seconds โฑ๏ธ.

expire โŒ›: If no heartbeat or new registrations are received from a repository for the expire period, objects from that repository should be considered non-authoritative, and cannot be used for authorization purposes ๐Ÿšซ. The value of this attribute shall be expressed in the form "dddd hh:mm:ss", where "dddd" represents days, "hh" represents hours, "mm" minutes and "ss" seconds. This value should be bigger than heartbeat-interval ๐Ÿ“.

Please note that the "heartbeat" meta-objects mentioned above, like the other meta-objects described in this document, are part of the protocol for exchanging information but are not placed in the database itself ๐Ÿ’Œ. See Section 7.3.2 for a description of the heartbeat meta-object ๐Ÿ”.

The remaining attributes in the repository object are defined in RPSL ๐Ÿ’–.

5.2. delegated attribute ๐Ÿฆ‹

okay so for a lot of RPSL object types, one entry should only live in ONE repository, bestie ๐Ÿ’… the ones with a natural hierarchy are "as-block", "aut-num", "inetnum", and "route". to make it possible to park an object in a different repository, we add a "delegated" attribute ๐ŸŽ€

  • delegated: the delegated attribute is allowed in any object type with a hierarchy. it tells you that any further searching for objects in that hierarchy has to happen in one or more alternate repositories ๐Ÿ” the current repository is allowed to be listed too. being able to list more than one repository only exists to cover grandfathered objects (the ones made before we had an authorization model) ๐Ÿ‘‘ the value of a delegated attribute is a list of repository names.

if an object has a "delegated" attribute, an exact key field match of that object can also show up in each repository listed in the "delegated" attribute. and when it comes to authorizing changes, only the mnt-by in the object inside the repository being modified counts ๐Ÿ™ˆ

here's an example of the delegated attribute in action ๐Ÿงš

inetnum:        193.0.0.0 - 193.0.0.255
delegated:      RIPE
...
source:         IANA

so this inetnum basically hands off storage of any more specific inetnum objects that overlap the stated range to the RIPE repository ๐ŸŒˆ an exact match of this inetnum can also exist in the RIPE repository, which gives you hooks for the attributes that reference maintainer objects. in that setup, when you add objects to the RIPE repository, the mnt-lower, mnt-routes, and mnt-by fields in the IANA inetnum object won't be considered. instead, the values in the RIPE copy get used โœจ

5.3. integrity attribute ๐Ÿ’–

the "integrity" attribute can show up in any RPSL object. it's meant purely as a way to get through a transition period, when some data has been moved out of repositories that came before a strong authorization model (so it's kinda questionable), or when some repositories aren't properly checking authorization ๐Ÿ˜ญ

the "integrity" attribute may have the values "legacy", "no-auth", "auth-failed", or "authorized". if it's absent, the integrity is considered to be "authorized". here's what each integrity value means ๐Ÿ“

  • legacy: this data existed before we had an adequate authorization model. it is highly suspect ๐Ÿ’€
  • no-auth: this data was added to a repository during an initial transition use of an authorization model. authorization depended on other objects whose integrity wasn't "authorized". this kind of addition is being allowed during the transition, but it would be disallowed later ๐Ÿซถ
  • auth-failed: the authoritative repository isn't checking authorization. if it had been, authorization would have failed. this attribute may be added by a repository that is mirroring, before it places the object in its local storage. it can also add this attribute to an encapsulating meta-object that's used to further propagate the transaction. if the failure to enforce authorization is intentional and part of a transition (for example, only issuing warnings), then the authoritative repository may add this attribute to the encapsulating meta-object used to further propagate the transaction ๐Ÿ”ฅ
  • authorized: authorization checks were passed. the maintainer contained a "referral-by" attribute, a form of authentication the repository considered adequate was used, and all objects needed for authorization were objects whose integrity was "authorized" ๐Ÿ‘‘

normally, once an object is added to a repository, another object can't overwrite it unless the maintainers referenced by the mnt-by attributes in the object itself say so ๐Ÿ”’ if the integrity attribute is anything but "authorized", an object can be overwritten or deleted by any transaction that would have been a properly authorized addition had the lesser-integrity object not existed. main character energy for sure ๐ŸŒธ

during such a transition, grandfathered data and data added without proper authorization becomes advisory until a properly authorized addition happens. after the transition, additions of this type would no longer be accepted. objects already added without proper authorization would stick around, but they'd be marked as candidates for replacement ๐Ÿฅ€


6. Interactions with a Repository or Mirror ๐ŸŒท

okay this section gives you the overview of the transaction distribution mechanisms ๐Ÿฆ‹ the detailed format of the meta-objects for encapsulating and distributing transactions, plus the rules for processing those meta-objects, are covered in Section 7. there are a few different types of interactions between routing repositories or mirrors โœจ

  • Initial submission of transactions: transactions can include additions, changes, and deletions. a transaction may operate on more than one object and must be treated as an atomic operation ๐Ÿงฉ by definition, initial submission of transactions doesn't apply to a mirror. initial submission is described in Section 6.1.
  • Redistribution of Transactions: the main purpose of the interactions between registries is redistributing transactions. there are a bunch of ways to do it, and that's discussed in Section 6.2 ๐Ÿ”
  • Queries: query interactions are outside the scope of this document ๐Ÿ™ˆ
  • Transaction Commit and Confirmation: repositories may optionally implement a commit protocol and a completion indication. this gives the submitter a response saying the transaction was successful and won't be lost if the local repository crashes ๐Ÿ’ช a submitter may optionally request this confirmation. it's discussed in Section 6.3 ๐Ÿ’œ

6.1. Initial Transaction Submission ๐ŸŽ€

the simplest way to submit a transaction is an object or set of objects sent with RFC-822 email encapsulation. this form is still supported for backwards compatibility ๐Ÿ•ฐ๏ธ a preferred form lets you include some meta-information in the submission, like a preferred form of confirmation โœจ with either encapsulation, the submitter connects to a host and port specified in the repository object, which allows immediate confirmation โšก if you want an email interface similar to the one the existing RIPE code provides, an external program can supply that email interface ๐Ÿ“ฌ

the encapsulation of a transaction submission and its response is described in detail in Section 7 ๐Ÿงš

6.2. Redistribution of Transactions ๐ŸŒˆ

redistribution of transactions can be done using one of the following:

  1. a repository snapshot is a request for the complete contents of a given repository. this is usually done when starting up a new repository or mirror, or when recovering from a disaster like a disk crash ๐Ÿ’€
  2. a transaction sequence exchange is a request for a specific set of transactions. often the request is for the most recent sequence number known to a mirror, up to the last transactions. this is used in polling ๐Ÿ“Š
  3. transaction flooding is accomplished through a unicast adjacency ๐ŸŒŠ

this section describes the operations somewhat qualitatively. data formats and state diagrams are provided in Section 7 ๐Ÿซถ

6.3. Transaction Commit and Confirmation ๐Ÿ”

if a submission needs a strong confirmation of completion, or if a higher degree of protection against false positive confirmation is wanted as a matter of repository policy, a commit may be performed ๐Ÿ™Œ

a commit request is a request from the repository processing an initial transaction submission, sent to another repository, to confirm that they've been able to advance the transaction sequence up to the sequence number immediately below the transaction in the request. it also asks whether they're willing to accept the transaction in the request as a further advance in the sequence ๐Ÿช„ this indicates that either the authorization was rechecked by the responding repository and passed, or that the responding repository trusts the requesting repository and has accepted the transaction ๐Ÿค

a commit request can be sent to more than one alternate repository. one commit completion response is enough to tell the submitter, positively, that the transaction has been completed. however, the repository or submitter may optionally require more than one ๐Ÿ‘‘


7. Data Format Summaries, Transaction Encapsulation and Processing ๐Ÿ“š

RIPE-181 [2] and RPSL [1] data is represented externally as ASCII text ๐Ÿ”ค objects consist of a set of attributes, and attributes are name/value pairs. a single attribute is represented as a single line: the name, then a colon, then whitespace characters (space, tab, or line continuation), then the value ๐Ÿ’… within a value, all consecutive whitespace characters count as a single space. line continuation is supported by putting a white space or '+' character at the beginning of the continuation lines โœจ an object is externally represented as a sequence of attributes, and objects are separated by blank lines ๐Ÿฉท

protocol interactions between registries are activated by passing "meta objects". meta objects aren't part of RPSL, but they do conform to RPSL object representation. they mostly serve as delimiters to the protocol messages, or to carry the request for an operation ๐ŸŽ

7.1. Transaction Submit and Confirm โœจ

okay so, the OG way people sent database changes was basically email ๐Ÿ“ง๐Ÿ’Œ and bestie, that method should still be supported by an external app. Merit added the pgp-from authentication method to the RADB (it got replaced by "pgpkey" in [4]). With pgp-from, the mail headers are basically ignored and the body has to be PGP signed. the vibe is very "trust the signature, not the envelope" ๐Ÿ”

This spec defines a different encapsulation for submitting transactions, and it's giving clean ๐Ÿงผ When you submit a group of objects to a repository, you MUST add exactly one timestamp meta-object and one or more signature meta-objects to the end of that group, in that order. โœจ

The timestamp meta-object has one attribute:

timestamp ๐Ÿ•ฐ๏ธ this one is mandatory and single-valued. It says when the user submits the transaction to the repository. The format is YYYYMMDD hh:mm:ss [+/-]xx:yy, where YYYY is the four-digit year, MM is the month, DD is the date, hh is the hour, mm is the minutes, and ss is the seconds. xx and yy are the hours and minutes that the timestamp is ahead of or behind UTC.

A repository may reject a transaction that doesn't include a timestamp meta-object. The timestamp is there to stop registrations from being replayed ๐Ÿ™…โ€โ™€๏ธ How that actually works is a local matter. For example, a repository can accept a transaction only if its timestamp is greater than the timestamp on the previous registration it got from this user (maintainer). Or it can only accept transactions whose timestamps fall inside its expire window. Choose your fighter ๐Ÿ’…

Each signature meta-object has one attribute:

signature ๐Ÿ–Š๏ธ this one is mandatory and single-valued. It's a block of free text that holds the signature for whatever authentication method was used on the transaction. When the method is a cryptographic hash (like PGP-based auth), the signature must cover all the text up to, but not including, the last blank line before the first signature meta-object. Very precise, very important ๐Ÿค“

A repository must reject a transaction that doesn't include any signature meta-object. No signature, no entry, periodt ๐Ÿšซ

The group of objects the user submitted, along with the timestamp and signature meta-objects, together make up the "submitted text" of the transaction. ๐ŸŽ€

This document doesn't specify the protocol used to submit a transaction or to get confirmation for locally committed transactions. That protocol is allowed to add more encapsulation around the submitted text, and the rest of this section shows one example of that. Implementations are totally free to pick a different encapsulation. ๐Ÿฆ‹

The meta-objects "transaction-submit-begin and "transaction-submit-end delimit a transaction. A transaction is treated as an atomic operation, so if any part of it fails, none of the changes take effect. Because of that, a transaction can only operate on a single database. All or nothing, iconic ๐Ÿ‘‘

A socket connection is used to request queries or submit transactions. An email interface can be provided by an external program that connects to that socket ๐Ÿ’Œ A socket connection must use the "transaction-submit-begin and "transaction-submit-end delimiters, but it can ask for a legacy-style confirmation. You can send multiple transactions before getting a response for any single one, and they might not finish in the order you sent them. Chaotic but efficient ๐ŸŒช๏ธโœจ

The "transaction-submit-begin meta-object may contain the following attributes:

transaction-submit-begin ๐ŸŽฌ this one is mandatory and single. Its value has the name of the database and an identifier that must be unique over the course of the socket connection.

response-auth-type ๐Ÿ” this one is optional and multiple. The rest of the line names an authentication type that would be acceptable in the response. This is how you ask for a response that the repository signs cryptographically.

transaction-confirm-type ๐Ÿงพ this one is optional and single. You must give a confirmation type keyword. The keywords are none, legacy, normal, and commit. You can follow the confirmation type with the option verbose.

The "transaction-submit-end meta-object has a single attribute with the same name. It must contain the same database name and identifier as the matching "transaction-submit-begin attribute. Matching is everything ๐Ÿซถ

Unless the confirmation type is none, a confirmation gets sent. If the confirmation type is legacy, an email message in the same form the RIPE database code currently sends is returned on the socket. It's suitable for submission to the sendmail program ๐Ÿ“ฌ

A normal confirmation does not require finishing the commit protocol. A commit confirmation does. A verbose confirmation may include extra detail. Pick your level of drama ๐ŸŽญ

A transaction confirmation comes back as a transaction-confirm meta-object. It may have the following attributes:

transaction-confirm ๐Ÿชช this one is mandatory and single. It contains the database name and identifier for the transaction.

confirmed-operation ๐Ÿ› ๏ธ this one is optional and multiple. It contains one of the keywords add, delete, or modify, followed by the object type and the key fields of the object that was operated on.

commit-status ๐Ÿšฆ this one is mandatory and single. It contains one of the keywords "succeeded, "error", or "held". The "error" keyword can be followed by an optional text string. The "held" keyword comes back when a repository holding a dependent object for authorization has expired. Oof, big "not meโ€ฆ" energy ๐Ÿ’€

7.2. Redistribution of Transactions ๐ŸŒ

So, to redistribute transactions, each repository keeps a TCP connection open with one or more other repositories ๐Ÿ”— After it locally commits a submitted transaction, a repository assigns a sequence number to that transaction, signs and encapsulates it, and then sends one copy to each neighboring (or "peer") repository. In turn, each repository authenticates the transaction (as described in Section 7.6), may re-sign it, and redistributes it to its neighbors. We use the term "originating repository" to tell apart the repository that redistributes a locally submitted transaction. Think of it as the OG friend who starts the group chat rumor ๐Ÿ—ฃ๏ธโœจ

This document also specifies two other ways to redistribute transactions to other repositories: a database snapshot format, used for initializing a new registry, and a polling technique that mirrors use ๐Ÿ“ธ๐Ÿชž

In this section, we first go over how a repository can encapsulate the submitted text of a transaction. Then we get into the protocol for flooding transactions or polling for them, plus the database snapshot contents and format. Stay tuned, it's about to get so good ๐Ÿฆ‹๐Ÿ’–

7.3. Redistribution Protocol Description โœจ

okay so first things first ๐Ÿ’… the originating repository must authenticate a submitted transaction using the methods described in [3]. no skipping this bestie ๐Ÿ”’

Once it's verified, the originating repository has to wrap the submitted text in a bunch of meta-objects before it gets redistributed ๐ŸŽ€ Here they are, one by one.

The originating repository must prepend the submitted text with exactly one transaction-label meta-object. This is the one that holds the following attributes:

  • transaction-label: mandatory and single. Its value conforms to the syntax of an RPSL word and is a globally unique identifier for the database this transaction is added to ๐Ÿท๏ธ
  • sequence: mandatory and single. Its value is an RPSL integer, the sequence number the originating repository assigned to the transaction. Successive transactions from the same originating repository get successive sequence numbers, and the first transaction a registry originates gets sequence number 1. Each repository must use sequence numbers drawn from a range at least as large as 64 bit unsigned integers ๐Ÿ”ข
  • timestamp: mandatory and single-valued. This is the time at which the originating repository encapsulates the submitted text โฐ The format is YYYYMMDD hh:mm:ss [+/-]xx:yy, where YYYY is the four digit year, MM the month, DD the date, hh the hour, mm the minutes, and ss the seconds of the timestamp. xx and yy are the hours and minutes that the timestamp is ahead of or behind UTC ๐ŸŒ
  • integrity: optional and single-valued. It may have the values legacy, no-auth, auth-failed, or authorized. If it's absent, the integrity is considered to be authorized ๐Ÿซถ

The originating repository may append one or more auth-dependency meta-objects to the submitted text. These show which other repositories' objects the originating registry used to authenticate the submitted text ๐Ÿ•ต๏ธโ€โ™€๏ธ They should be ordered from the most preferred repository to the least preferred one. A remote repository uses this order to tie break between multiple registrations of an object with the same level of integrity, so the order really matters ๐Ÿ‘‘ Each auth-dependency meta-object has these attributes:

  • auth-dependency: mandatory and single-valued. It equals a repository name from which an object is used to authorize or authenticate this transaction.
  • sequence: mandatory and single-valued. It equals the transaction sequence number of the dependent repository, as known at the originating repository at the time it processed this transaction.
  • timestamp: mandatory and single-valued. It equals the timestamp of the dependent repository, as known at the originating repository at the time it processed this transaction.

If the originating repository needs to modify submitted objects in a way that remote repositories can't re-create, it can append an override-objects meta-object followed by the modified versions of those objects ๐Ÿ› ๏ธ An example of this is auto assignment of NIC handles. The override-objects meta-object has one attribute:

  • override-objects: a free text remark.

Other repositories may or may not honor override requests, and they may limit the kinds of overrides they allow. So don't count on it being honored everywhere ๐Ÿ™ˆ

After all that, the originating repository must append exactly one repository-signature meta-object. It has these attributes:

  • repository-signature: mandatory and single-valued. It contains the name of the repository ๐Ÿ“
  • integrity: optional and single-valued. It may have the values legacy, no-auth, auth-failed, or authorized. If it's absent, the value is the same as the value in the transaction-label. If a different value is used, the value here takes precedence ๐ŸŽฏ
  • signature: optional and single-valued. This is a block of free text containing the repository's signature, made with the key in the repository-cert attribute of the repository object ๐Ÿ” When the authentication method is a cryptographic hash (like PGP-based authentication), the signature must include all text up to, but not including, this attribute. That means the repository-signature and integrity attributes of this object are included. This attribute is optional because cryptographic authentication isn't available everywhere, but using it wherever it is available is highly recommended ๐Ÿ’–

A repository must reject a redistributed transaction that doesn't include any repository-signature meta-object. No signature, no entry, bestie ๐Ÿšซ

The transaction-label, the submitted text, the dependency objects, the override-objects, the overridden objects, and the repository's signature all together make up what we call the "redistributed text" ๐Ÿงฉ

Next up is getting ready to send the transaction to other repositories. The originating repository must perform the following protocol encapsulation, which may involve transforming the redistributed text according to one of the "transfer-method"s described below ๐Ÿฆ‹

The transformed redistributed text gets prepended with exactly one transaction-begin meta-object, and one newline character separates this meta-object from the redistributed text. It has these attributes:

  • transaction-begin: mandatory and single. Its value is the length, in bytes, of the transformed redistributed text ๐Ÿ“
  • transfer-method: optional and single-valued. Its value is either gzip or plain. The value describes the kind of text encoding the repository has performed on the redistributed text ๐Ÿ—œ๏ธ If this attribute isn't specified, its value is assumed to be plain. An implementation must be capable of encoding and decoding both of these types ๐ŸŽ€

The transaction-begin meta-object and the transformed redistributed text together make up what we call the "transmitted text". The originating repository may distribute the transmitted text to one or more peer repositories ๐Ÿ“ฌ

When a repository receives the transmitted text of a transaction, it must perform the following steps. After doing these steps, a transaction may be marked successful or failed โœจ

  1. It must decapsulate the transaction-begin meta-object, then decode the original redistributed text according to the value of the transfer-method attribute specified in the transaction-begin meta-object.
  2. It should then extract the transaction-label meta-object from the transmitted text. If this transaction has already been processed, or is currently being held, the repository must silently discard this incarnation of the same transaction ๐Ÿ‘€
  3. It should verify that the signature of the originating repository matches the first repository-signature meta-object in the redistributed text that follows the auth-dependency meta-objects.
  4. If not all previous transactions from the same repository (meaning those with a lower sequence number) have been received or completely processed, the repository must "hold" this transaction โธ๏ธ
  5. It may check whether any subsequent repository-signature meta-objects were appended by a trusted repository. If so, that means the trusted repository verified the transaction's integrity and marked its conclusion in the integrity attribute of that object. The repository may verify the trusted repository's signature and also mark the transaction with the same integrity, and then skip the remaining steps ๐Ÿค
  6. It should verify the syntactic correctness of the transaction. An implementation may allow configurable levels of syntactic conformance with RPSL [1]. This lets RPSL extensions be incrementally deployed in the distributed registry scheme ๐ŸŒˆ
  7. The repository must authorize and authenticate this transaction. To do this, it may need to reference objects and transactions from other repositories. If those objects aren't available, the repository must "hold" this transaction as described in Section 7.6, until it can be authorized and authenticated later โณ To verify the authorization and authentication of this transaction, the repository must not use an object from a repository that isn't mentioned in an auth-dependency meta-object ๐Ÿšซ The repository should also only use the latest objects (rolling back to earlier versions if necessary) that fall within the transaction sequence numbers of the auth-dependency meta-objects ๐Ÿ”™

A non-originating repository must redistribute a failed transaction so it doesn't cause a gap in the sequence. (If the transaction were to fail at the originating registry, it would simply not be assigned a sequence number ๐Ÿซ )

A repository may append another repository-signature meta-object to the redistributed text of a transaction. This indicates that the repository has verified the transaction's integrity and marked it in the integrity attribute of this object. The signature covers the new redistributed text from (and including) the transaction-label object up to this object's signature attribute. That includes the repository-signature and integrity attributes of this object, but excludes the signature attribute itself. The original redistributed text, together with this new repository-signature meta-object, makes up the "modified redistributed text" ๐Ÿ’…

To redistribute a successful or failed transaction, the repository must encapsulate the (original or modified) redistributed text with a transaction-begin object. This step is basically the same as the one the originating repository performs, except the repository is free to use a different transfer-method from the one in the received transaction ๐Ÿฆ‹

7.3.1. Explicitly Requesting Transactions โœจ

okay so a repository can also just ask for transactions straight up ๐Ÿงš from one specific originating repository. this is literally the move for catching up after being offline for a bit ๐Ÿ˜ญ and for mirrors that poll a repo every so often to grab the newest transactions ๐Ÿฆ‹

to ask for a range, a repository has to send a transaction-request meta-object to its peer. a transaction-request can have these attributes:

  • transaction-request: mandatory and single. it holds the name of the database whose transactions are being requested. ๐Ÿ’–
  • sequence-begin: optional and single. it holds the sequence number of the first transaction being requested. ๐ŸŒธ
  • sequence-end: optional and single. it holds the sequence number of the last transaction being requested. ๐ŸŽ€

when a repository gets a transaction-request, here's what happens ๐Ÿ’… if sequence-begin isn't specified, the repository assumes the first sequence number is 1. the last sequence number is the lesser of the sequence-end value and the highest completed transaction in the matching database. then, in order, it sends the requested range of transactions. every single transaction gets prepared exactly according to the redistribution rules in Section 7.3. no shortcuts, bestie ๐Ÿ™ˆ

once all the transactions have been sent, the peer repository must send a transaction-response meta-object. this one has these attributes:

  • transaction-response: mandatory and single. it holds the name of the database whose transactions were requested. ๐Ÿ“
  • sequence-begin: optional and mandatory. it holds the value of the sequence-begin attribute from the original request. it's left out if that attribute wasn't in the original request. ๐Ÿงš
  • sequence-end: optional and mandatory. it holds the value of the sequence-end attribute from the original request. it's left out if that attribute wasn't in the original request. ๐Ÿฆ‹

after a repository receives a transaction-response, it may tear down the TCP connection to its peer. this is so useful for mirrors that resync transactions now and then ๐Ÿซถ if the TCP connection stays open, the repositories keep swapping transactions using the redistribution mechanism from Section 7.3. and while a repository is answering a transaction-request, it MAY forward heartbeats and other transactions from the requested repository on to the requestor. ๐Ÿ’œ


7.3.2. Heartbeat Processing โœจ

every repository that has originated at least one transaction must periodically send a heartbeat meta-object. the gap between two sends is configurable, but it must be less than 1 day โฐ this little guy basically says "hey, I'm still alive" ๐Ÿ’– and the repository's liveness decides how long transactions get held (see Section 7.6) ๐Ÿ‘‘

the heartbeat meta-object has these attributes:

  • heartbeat: mandatory and single. it holds the name of the repository that originated this meta-object. ๐ŸŒˆ
  • sequence: mandatory and single. it holds the highest transaction sequence number the repository has assigned. โญ
  • timestamp: mandatory and single. it holds the time this meta-object was generated, in this format:
YYYYMMDD hh:mm:ss [+/-]xx:yy

where YYYY is the four digit year, MM is the month, DD is the date, hh is the hour, mm is the minutes, and ss is the seconds. xx and yy are the hours and minutes that the timestamp is ahead of or behind UTC. ๐Ÿงš

when a repository gets a heartbeat, it has to check the timestamp of the latest heartbeat it received before. if that old timestamp is later than the one in the new heartbeat, the repository must silently discard the new one ๐Ÿ™ˆ otherwise, it must record the timestamp and sequence number from the heartbeat and redistribute the heartbeat, without modification, to each of its peer repositories. ๐Ÿซถ

if the heartbeat is from a repository the recipient has never heard of, the recipient may send a transaction-request to one or more of its peers to get every transaction for the matching database. same deal if the heartbeat's sequence number is higher than the highest sequence number the recipient has processed. ๐Ÿ’…


7.4. Transaction Commit โœจ

submitters can ask for stronger confirmation of commit on their transactions (see Section 6.3) ๐Ÿ’– this section describes a simple request-response protocol that lets a repository give that stronger confirmation by checking whether one or more other repositories have committed the transaction. implementing this protocol is optional ๐ŸŒธ

after it has redistributed a transaction, the originating repository may ask one or more peer repositories for a commit confirmation by sending them a commit-request meta-object. the commit-request has two attributes:

  • commit-request: mandatory and single. it holds the name of the database the commit confirmation is being requested for. ๐ŸŽ€
  • sequence: mandatory and single. it holds the transaction sequence number the commit confirmation is being requested for. ๐Ÿ“

a repository that gets a commit-request must not redistribute the request ๐Ÿšซ it must delay the response until the matching transaction has been processed. so the repository has to keep state about pending commit requests. it should throw that state away if the connection to the requester drops before the response goes out. in that case, the requester is responsible for sending the request again ๐Ÿ”

once a transaction has been processed (see Section 7.3), a repository must check whether any pending commit request exists for it. if there is one, it must send a commit-response meta-object to the requester. the commit-response has three attributes:

  • commit-response: mandatory and single. it holds the name of the database the commit response is being sent for. ๐ŸŒˆ
  • sequence: mandatory and single. it holds the transaction sequence number the commit response is being sent for. โญ
  • commit-status: mandatory and single. it holds one of the keywords held, error, or succeeded. the error keyword can be followed by an optional text string. the held keyword comes back when a repository holding a dependent object for authorization has expired. ๐Ÿ’€

7.5. Database Snapshot โœจ

a database snapshot is a complete copy of a database ๐Ÿ“ธ it's only meant for repository initialization or disaster recovery ๐Ÿš‘ it's an out of band mechanism, so a set of files gets made periodically at the source repository, then transferred to the requestor out of band (e.g. ftp transfer) ๐Ÿฆ‹ once they arrive, the objects in those files get registered locally.

a snapshot of repository X has this set of files:

  • X.db: holds the RPSL objects of repository X, separated by blank lines. on top of the RPSL objects and blank lines, comment lines can show up too. comment lines start with the character #, and they get ignored. the file X.db always ends with a special comment line, # eof ๐Ÿ’œ
  • X.<class>.db: an optional file that, if it's there, holds the RPSL objects from X.db that belong to class <class>. its format is the same as X.db. ๐ŸŒธ
  • X.transaction-label: holds a transaction-label object that records the timestamp and the latest sequence number of the repository at the time of the snapshot. ๐Ÿงš

each of these files can optionally be compressed using gzip, which is shown by adding the .gz suffix to the file name. each one can also optionally be PGP signed. in that case, the detached signature (ASCII armored, platform-independent text mode) gets stored in a file whose name is the file being signed plus .sig appended ๐Ÿ”

to build a repository's contents from a snapshot, the repository downloads these files. after uncompressing them and checking signatures, it records the objects in its database. no RPS authorization/authentication is done on these objects ๐Ÿ™ˆ the transaction-label object is the seed the replication protocol uses to get the follow-on transactions from this repository. so it isn't crucial to download a snapshot that's up to the minute ๐Ÿ’…

here's the tricky part ๐Ÿ˜ญ after a snapshot has been played, a repository might receive a transaction from a third repository that depends on an earlier version of one of the snapshot's objects. this can only happen within the expire period of the repository being downloaded, plus any possible network partition period. the dependency only matters if the repository wants to re-verify RPS authorization/authentication. there are three allowed alternatives here:

  1. the simplest one: accept the transaction and mark it with integrity "no-auth".
  2. only peer with trusted repositories during this time period, and accept the transaction with the same integrity as the trusted repository (possibly "authorized").
  3. the most preferred one: don't download an up to the minute snapshot. instead, download an older snapshot, at minimum twice the repository's expire time (in practice, a few days older). when an older snapshot is replayed, the replication protocol fetches the more current transactions from this repository. together they provide the versions of objects needed to re-verify RPS authorization/authentication. ๐Ÿ†

7.6. Authenticating Operations ๐Ÿ”

Okay so signatures are basically the bouncer at the door of the transaction club ๐Ÿ’… When there are multiple signature objects, each signature should be over the original contents, not over other signatures. That's what lets everyone check them in any order, and it's giving total flexibility ๐Ÿฆ‹

A maintainer can also sign a transaction using several authentication methods, and some of those methods may only be available in certain repositories ๐ŸŒธ

For PGP, implementations should let the "signature" and "repository-signature" meta-objects hold either detached PGP signatures or regular PGP signatures. Either way, ASCII armoring and platform-independent text mode should be used โœจ

Quick reminder: the RPSL objects themselves aren't signed. The entire transaction body is signed ๐Ÿ’œ When transactions get exchanged between registries, the meta-objects (like "auth-dependency") that come before the first "repository-signature" meta-object in the redistributed text are signed over too ๐Ÿ‘‘

Transactions must stay intact, signatures included, even if a repository handling the message doesn't use one of the submitter's authentication methods ๐Ÿซถ The originating repository is allowed to strip out clear-text password signatures and replace them with the keyword "clear-text-passwd" followed by the maintainer's id, like this:

signature: clear-text-passwd <maintainer-name>
๐Ÿšจ Here's the tea: swapping in clear-text-passwd does not make the system less secure. A clear-text password is a sign that the maintainer totally trusts the originating repository, so there's no extra risk being added ๐Ÿ˜ญ

A repository may sign a transaction it has verified ๐Ÿ”ฅ And if at any point a signature from a trusted repository shows up, no further authorization or authentication is needed. Iconic, honestly ๐ŸŒˆ


A. Examples โœจ

Okay bestie, time for the fun part ๐ŸŽ€ RPSL gives us an external representation of RPSL objects and their attributes. An attribute is a name/value pair. RPSL is line oriented, and line continuation is supported, but most attributes fit on a single line. You write the attribute name, then a colon, then any amount of whitespace, then the attribute value. Here's what one looks like in ASCII:

route:     140.222.0.0/16

An RPSL object is just a set of attributes. Objects are separated from each other by one or more blank lines. Here's a complete RPSL object:

route:         140.222.0.0/16
descr:         ANS Communications
origin:        AS1673
member-of:     RS-ANSOSPFAGGREGATE
mnt-by:        ANS
changed:       tck@ans.net 19980115
source:        ANS

A.1. Initial Object Submission and Redistribution ๐Ÿฆ‹

Figure 1 walks through submitting an object and the first redistribution from the authoritative registry out to its flooding peers. It's a whole journey ๐Ÿ’–

If the authorization check needs objects from other repositories, then the sequence numbers of the local copies of those databases are required so mirrors can recheck the authorization ๐Ÿงš

Say you want to resubmit the object from the previous example. The submitter, or a client app acting for the submitter, has to submit a transaction. The old-school way was to send PGP signed email ๐Ÿ“ง The preferred way now is for an interactive program to wrap a request between "transaction-submit-begin" and "transaction-submit-end" meta-objects, then encapsulate that as a signed block, like in this example:

    +--------------+
    |  Transaction |
    |  signed by   |
    |  submitter   |
    +--------------+
           |
           |  1
           v
    +---------------------+  2
    |  Primary repository |---->+----------+
    |  identified by      |     | database |
    |  RPSL source        |<----+----------+
    +---------------------+  3
           |
           |  4
           v
    +----------------+
    |  Redistributed |
    |  transaction   |
    +----------------+

    1.  submit object
    2.  authorization check
    3.  sequence needed for authorization
    4.  redistribute

Figure 1: Initial Object Submission and Redistribution

Here's the actual submission, with a signed block inside ๐Ÿ’…

transaction-submit-begin:  ANS 1
response-auth-type:        PGP
transaction-confirm-type:  normal

route:         140.222.0.0/16
descr:         ANS Communications
origin:        AS1673
member-of:     RS-ANSOSPFAGGREGATE
mnt-by:        ANS
changed:       curtis@ans.net 19990401
source:        ANS

timestamp: 19990401 10:30:00 +08:00
signature:
+ -----BEGIN PGP SIGNATURE-----
+ Version: PGP for Personal Privacy 5.0
+ MessageID: UZi4b7kjlzP7rb72pATPywPxYfQj4gXI
+
+ iQCVAwUANsrwkP/OhQ1cphB9AQFOvwP/Ts8qn3FRRLQQHKmQGzy2IxOTiF0QXB4U
+ Xzb3gEvfeg8NWhAI32zBw/D6FjkEw7P6wDFDeok52A1SA/xdP5wYE8heWQmMJQLX
+ Avf8W49d3CF3qzh59UC0ALtA5BjI3r37ubzTf3mgtw+ONqVJ5+lB5upWbqKN9zqv
+ PGBIEN3/NlM=
+ =c93c
+ -----END PGP SIGNATURE-----

transaction-submit-end:    ANS 1

The signature covers everything from the first blank line after the "transaction-submit-begin" object, down to the last blank line before the "signature" meta-object ๐Ÿ” If you need several signatures, you could just email this block to the other party, ask them to add a signature-block, and then have them return it or submit it ๐Ÿซถ But getting multiple signatures takes time, so the accuracy of the "timestamp" can't be strictly enforced ๐Ÿ˜ฌ Enforcing accuracy to within the "expire" time of the database might be a reasonable compromise. It's a real tradeoff: more convenience for gathering signatures means a longer window of exposure to replay attack ๐Ÿ’€

The ANS repository then checks its local database and makes authorization checks. If authorization passes, it gets the sequence number of any other database needed for the authorization ๐Ÿง 

If that all works out, a confirmation comes back. It looks like this:

transaction-confirm:  ANS 1
confirmed-operation:  change route 140.222.0.0/16 AS1673
commit-status:        commit
timestamp:            19990401 10:30:10 +05:00

A.2. Transaction Redistribution Encoding ๐ŸŒธ

Once the transaction passes the authorization check, it gets a sequence number, goes into the local transaction log, and then gets flooded ๐ŸŒŠ The meta-object flooded to another database is signed by the repository and looks like this:

transaction-label: ANS
sequence: 6666
timestamp: 19990401 13:30:10 +05:00
integrity: authorized

route:         140.222.0.0/16
descr:         ANS Communications
origin:        AS1673
member-of:     RS-ANSOSPFAGGREGATE
mnt-by:        ANS
changed:       curtis@ans.net 19990401
source:        ANS

timestamp: 19990401 10:30:00 +08:00

signature:
+ -----BEGIN PGP SIGNATURE-----
+ Version: PGP for Personal Privacy 5.0
+ MessageID: UZi4b7kjlzP7rb72pATPywPxYfQj4gXI
+
+ iQCVAwUANsrwkP/OhQ1cphB9AQFOvwP/Ts8qn3FRRLQQHKmQGzy2IxOTiF0QXB4U
+ Xzb3gEvfeg8NWhAI32zBw/D6FjkEw7P6wDFDeok52A1SA/xdP5wYE8heWQmMJQLX
+ Avf8W49d3CF3qzh59UC0ALtA5BjI3r37ubzTf3mgtw+ONqVJ5+lB5upWbqKN9zqv
+ PGBIEN3/NlM=
+ =c93c
+ -----END PGP SIGNATURE-----

auth-dependency: ARIN
sequence: 555
timestamp: 19990401 13:30:08 +05:00

auth-dependency: RADB
sequence: 4567
timestamp: 19990401 13:27:54 +05:00

repository-signature: ANS
signature:
+ -----BEGIN PGP SIGNATURE-----
+ Version: PGP for Personal Privacy 5.0
+ MessageID: UZi4b7kjlzP7rb72pATPywPxYfQj4gXI
+
+ iQCVAwUANsrwkP/OhQ1cphB9AQFOvwP/Ts8qn3FRRLQQHKmQGzy2IxOTiF0QXB4U
+ Xzb3gEvfeg8NWhAI32zBw/D6FjkEw7P6wDFDeok52A1SA/xdP5wYE8heWQmMJQLX
+ Avf8W49d3CF3qzh59UC0ALtA5BjI3r37ubzTf3mgtw+ONqVJ5+lB5upWbqKN9zqv
+ PGBIEN3/NlM=
+ =c93c
+ -----END PGP SIGNATURE-----

Heads up, the repository-signature above is a detached signature for another file and is illustrative only ๐Ÿ™ˆ The repository-signature covers everything from the "transaction-label" meta-object (including it) to the last blank line before the first "repository-signature" meta-object (excluding that last blank line and the "repository-signature" object itself).


A.3. Transaction Protocol Encoding ๐Ÿงš

Before the transaction goes out to a peer, the repository prepends a "transaction-begin" meta-object ๐ŸŽ€ The value of "transaction-begin" is the number of octets in the transaction, not counting the "transaction-begin" meta-object or the first blank line after it. Here's the full thing:

transaction-begin: 1276
transfer-method: plain

transaction-label: ANS
sequence: 6666
timestamp: 19990401 13:30:10 +05:00
integrity: authorized

route:         140.222.0.0/16
descr:         ANS Communications
origin:        AS1673
member-of:     RS-ANSOSPFAGGREGATE
mnt-by:        ANS
changed:       curtis@ans.net 19990401
source:        ANS

timestamp: 19990401 10:30:00 +08:00

signature:
+ -----BEGIN PGP SIGNATURE-----
+ Version: PGP for Personal Privacy 5.0
+ MessageID: UZi4b7kjlzP7rb72pATPywPxYfQj4gXI
+
+ iQCVAwUANsrwkP/OhQ1cphB9AQFOvwP/Ts8qn3FRRLQQHKmQGzy2IxOTiF0QXB4U
+ Xzb3gEvfeg8NWhAI32zBw/D6FjkEw7P6wDFDeok52A1SA/xdP5wYE8heWQmMJQLX
+ Avf8W49d3CF3qzh59UC0ALtA5BjI3r37ubzTf3mgtw+ONqVJ5+lB5upWbqKN9zqv
+ PGBIEN3/NlM=
+ =c93c
+ -----END PGP SIGNATURE-----

auth-dependency: ARIN
sequence: 555
timestamp: 19990401 13:30:08 +05:00

auth-dependency: RADB
sequence: 4567
timestamp: 19990401 13:27:54 +05:00
repository-signature: ANS
signature:
+ -----BEGIN PGP SIGNATURE-----
+ Version: PGP for Personal Privacy 5.0
+ MessageID: UZi4b7kjlzP7rb72pATPywPxYfQj4gXI
+
+ iQCVAwUANsrwkP/OhQ1cphB9AQFOvwP/Ts8qn3FRRLQQHKmQGzy2IxOTiF0QXB4U
+ Xzb3gEvfeg8NWhAI32zBw/D6FjkEw7P6wDFDeok52A1SA/xdP5wYE8heWQmMJQLX
+ Avf8W49d3CF3qzh59UC0ALtA5BjI3r37ubzTf3mgtw+ONqVJ5+lB5upWbqKN9zqv
+ PGBIEN3/NlM=
+ =c93c
+ -----END PGP SIGNATURE-----

Separating the transaction-begin and transaction-label objects lets different flooding peerings use different encodings ๐ŸŒˆ

A.4 Transaction Redistribution โœจ

okay so the last step in Figure 1 was the submitter's transaction getting redistributed through flooding (or later through polling) ๐Ÿ’Œ Figure 2 shows what happens next as it keeps getting passed along ๐Ÿฆ‹

If the authorization check was repeated, the mirror may optionally add a repository-signature before passing the transaction any further. A "signature" can go inside that block. The previous signatures should not be signed ๐Ÿซถ

Figure 3 is the special case called a "lightweight mirror" ๐Ÿงš It's specifically made for routers, so it's giving very purpose-built energy ๐Ÿ”ฅ

The lightweight mirror must trust the mirror it gets its feed from. This is a safe assumption when both are under the same administration, like when the mirror giving the feed is a host owned by the same ISP that owns the routers ๐Ÿ  The lightweight mirror just checks the signature of the adjacent repository to make sure the data hasn't been messed with ๐Ÿ”

    +----------------+
    |  Redistributed |
    |  transaction   |
    +----------------+
           |
           |  1
           v
    +--------------------+  2
    |                    |---->+----------+
    |  Mirror repository |     | database |
    |                    |<----+----------+
    +--------------------+  3
           |
           |  4
           v
    +------------------+
    |+----------------+|
    ||  Redistributed ||
    ||  transaction   ||
    |+----------------+|
    |  Optional        |
    |  signature       |
    +------------------+

    1.  redistribute transaction
    2.  recheck authorization against full DB at the
        time of the transaction using sequence numbers
    3.  authorization pass/fail
    4.  optionally sign then redistribute

   Figure 2:  Further Transaction Redistribution

    +----------------+
    |  Redistributed |
    |  transaction   |
    +----------------+
           |  1
           v
    +--------------------+  2
    |                    |---->+----------+
    |  Mirror repository |     | database |
    |                    |<----+----------+
    +--------------------+  3
           |  4
           v
    +----------------+
    |  Redistributed |
    |  transaction   |
    +----------------+
           |  5
           v
    +--------------------+
    |  Lightweight       |  6  +----------+
    |  Mirror repository |---->| database |
    |  (router?)         |     +----------+
    +--------------------+

    1.  redistribute transaction
    2.  recheck authorization against full DB at the
        time of the transaction using sequence numbers
    3.  authorization pass/fail
    4.  sign and redistribute
    5.  just check mirror signature
    6.  apply change with no authorization check

   Figure 3:  Redistribution to Lightweight Mirrors

B Technical Discussion ๐ŸŽ€

B.1 Server Processing ๐Ÿ’…

This document doesn't mandate any particular software design, programming language, underlying database, or underlying operating system. The examples are only there for illustration ๐ŸŒธ

B.1.1 getting connected ๐Ÿ“ฌ

There are two main ways to talk to a repository server. You can send an e-mail to the server. This method may be deprecated, but it at least needs to be supported during the transition ๐Ÿ•ฐ๏ธ The second method is the preferred one: connect directly to a TCP socket ๐Ÿ”Œ

Traditionally the whois service is supported for simple queries. It might be wise to keep the whois port connection just for simple queries, and use a second port outside the reserved number space for everything else, including queries except those using the whois unstructured single line query format ๐Ÿง 

There are two styles for handling connection initiation. One is a dedicated daemon, in the style of BSD sendmail. The other is launching through a general purpose daemon like BSD inetd. E-mail is normally handled sequentially, and it can be handled by a front end program that makes the connection to a socket in the process acting as a mail delivery agent ๐Ÿ“จ

B.1.2 rolling transaction logs forward and back โชโฉ

There's a need to be able to look back easily at previous states of any database, so authorization checks can be repeated as of the time of a transaction ๐Ÿ” This is hard to do with the RIPE database implementation, which uses a sequentially written ASCII file and a set of Berkeley DB maintained index files for traversal. At the very minimum, the way deletes or replacements are implemented would need to change ๐Ÿ˜ญ

To easily support looking at prior versions of objects, the sequence number of the transaction at which each object was entered would need to be kept with the object. A pointer back to the object's previous state would be needed too. A deletion would be implemented as a new object with a deleted attribute, which replaces the previous version but keeps a pointer back to it ๐Ÿชฆ

A separate transaction log needs to be maintained. Past some age, the older versions of objects and the older transaction log entries can be removed, although it's probably wise to archive them ๐Ÿ—„๏ธ

B.1.3 committing or disposing of transactions ๐Ÿ“

Committing large transactions, or rejecting them as a whole, causes problems for simplistic database designs ๐Ÿฅฒ This form of commit operation can be supported quite easily using memory mapped files. The changes can be made in virtual memory only, and then either committed or disposed of โœจ

B.1.4 dealing with concurrency ๐Ÿšฆ

Multiple connections may be active. A single connection may also have multiple outstanding operations at once. It makes sense to have one process or thread coordinate the responses for a given connection, and have multiple processes or threads each tending to a single operation. The operations may complete in random order ๐ŸŽฒ

Locking on reads isn't essential. Locking before write access is essential ๐Ÿ”’ The simplest approach to locking is to lock at the database granularity, or at the database and object type granularity. Finer locking granularity can also be implemented. Because there are multiple databases, deadlock avoidance must be considered ๐Ÿ’€ The usual deadlock avoidance mechanism is to acquire all the necessary locks in a single operation, or to acquire locks in a prescribed order ๐Ÿซง

B.2 Repository Mirroring for Redundancy ๐Ÿชž

There are lots of reasons why a repository operator might mirror their own repository. The most obvious are redundancy and how relatively easy disaster recovery becomes ๐Ÿ™Œ Another reason might be the widespread use of a small number of implementations (but more than one), and wanting to make sure the major repository software releases will accept a transaction before fully committing to it ๐Ÿง

Running a mirror just for redundancy is pretty straightforward. The primary repository host's transactions can be fed to the redundant host right away. For tighter assurance that false positive confirmations won't be sent, the primary repository host can, as a matter of policy, require commit confirmation before making a transaction sequence publicly available ๐Ÿ›ก๏ธ

There are lots of ways to keep local data intact even if there's a local crash in the middle of transaction disk writes ๐Ÿ’พ For example, transactions can be implemented as memory mapped file operations, with disk synchronization used as the local commit mechanism, and disposal of memory copies of pages used to handle commit failures. The old pages can be written to a separate file, and the new pages written into the database. The transaction can be logged, and then the old pages file can be removed. If there's a crash, the existence of an old pages file together with the lack of a record of the transaction completing triggers a rollback, which writes the old pages back to the database file ๐Ÿ”„

The primary repository host can still suffer severe damage, like a disk crash ๐Ÿ’ฅ If the primary repository host becomes corrupted, a mirror repository host gives you a backup, and rapid recovery from disaster is possible by simply reversing roles ๐Ÿ”

If a mirror is set up with a different software implementation and commit mirror confirmation is required, any transaction that fails due to a software bug will be deferred indefinitely. That way other transactions can keep going, instead of all remote processing halting until the bug is fixed everywhere ๐Ÿ™…โ€โ™€๏ธ

B.3 Trust Relationships ๐Ÿค

If all repositories trust each other, there's never a need to repeat authorization checks. This gives a convenient interim step for deployment before the software that supports that capability is finished ๐Ÿงƒ The opposite case is where no repository trusts any other repository. In that case, all repositories must roll forward transactions gradually, checking the authorization of each remote transaction ๐Ÿข

It's likely that repositories will trust a subset of other repositories. This trust can reduce how much processing a repository needs to keep mirror images of the full set of data ๐Ÿ“‰ For example, a subset of repositories might be trustworthy because they take reasonable security measures, the organizations themselves have the integrity not to alter data, and these repositories trust only a limited set of similar repositories ๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘ If any one of these repositories receives a transaction sequence and repeats the authorization checks, other major repositories that trust it don't need to repeat the checks. Also, trust doesn't need to be mutual to still get some benefit in reduced processing ๐ŸŒˆ

As a transaction sequence is passed from repository to repository, each repository signs it before forwarding it โœ๏ธ If a receiving repository finds that any trusted repository has signed the transaction sequence, it can be considered authorized, because the trusted repository either trusted a preceding repository or repeated the authorization checks ๐Ÿ’ซ

B.4 A Router as a Minimal Mirror ๐Ÿ›ฃ๏ธ

A router could serve as a minimal repository mirror ๐Ÿงšโ€โ™€๏ธ The following simplifications can be made:

  1. No support for repeating authorization checks or transaction authentication checks needs to be coded in the router.
  2. The router must be adjacent only to trusted mirrors, generally operated by the same organization.
  3. The router would only check the authentication of the adjacent repository mirrors.
  4. No support for transaction submission or query needs to be coded in the router. No commit support is needed.
  5. The router can dispose of any object types or attributes not needed for configuration of route filters.

Updating router configurations could be way less of a hassle if the router could act as a limited repository mirror ๐Ÿ™Œ

A significant amount of non-volatile storage would be needed. There are currently an estimated 100 transactions per day ๐Ÿ“Š If storage were flash memory with a limited number of writes, or if there were some other reason to avoid writing to flash, the router could only update the non-volatile copy every few days ๐Ÿ’พ A transaction sequence request can be made to get an update in the event of a crash, which returns only a few hundred updates after losing a few days of deferred writes. The routers can still take a frequent or continuous feed of transactions ๐ŸŒŠ

Alternatively, router filters can be reconfigured periodically, the way they are today ๐Ÿ—“๏ธ

B.5. Dealing with Errors ๐Ÿšจ

Okay bestie, so if verification of an authorization check fails, the whole transaction must be rejected, and the repository can't move forward at all until the originating repository fixes the problem ๐Ÿ™…โ€โ™€๏ธ. If the problem is a software bug, the bad transaction can be removed by hand once the bug is fixed. If the bug is in the receiving software, the transaction sequence stalls until that bug gets fixed too. Software should lean toward denying a transaction rather than accepting it, because if you accept something by mistake, you'll have to undo its effects later, and nobody wants that drama ๐Ÿ˜ญ.


C. Deployment Considerations ๐Ÿš€

Here's the tea: this section talks about deployment considerations, but it's raising issues, not handing you a deployment plan ๐Ÿง .

This document asks for a transaction exchange mechanism that's similar to, but not identical to, the existing "near real time mirroring" that the code base widely used by the routing registries already supports ๐Ÿ’…. As a first step, the transaction exchange can be built without the commit protocol or the ability to recheck transaction authorization. That's a pretty minimal step up from what's already there โœจ.

The transition can be staged like this:

  1. Modify the format of "near real time mirroring" transaction exchange to conform to the specifications of this document.
  2. Implement commit protocol and confirmation support.
  3. Implement remote recheck of authorization. Prior to this step all repositories must be trusted.
  4. Allow further decentralization of the repositories.

D. Privacy of Contact Information ๐Ÿ”’

The routing registries have contained contact information, and redistributing it has been a seriously delicate issue ๐Ÿฅบ. In some countries it has legal implications too, so be careful, bestie.

The person and role objects contain contact information. These objects are referenced by NIC-handles. Some attributes, like "changed" and "notify", require an email address. All of the fields that currently require an email address must also accept a NIC-handle ๐ŸŽ€.

The person and role objects should not be redistributed by default. If a submission has an email address in a field like "changed" instead of a NIC-handle, the submitter needs to know that they're letting that email address get redistributed and giving up their privacy ๐Ÿ‘€. Repositories that don't think prior warnings about this give enough legal protection should reject the submission and ask for a NIC-handle to be used instead.

Queries to role and person objects that arrive at a mirror must be referred to the authoritative repository. That way whatever authentication, restrictions, or limitations that repository thinks are appropriate can be enforced directly ๐Ÿซถ.

Software should make it possible to restrict the redistribution of other entire object types, as long as those object types aren't required for authorizing the additions of other object types ๐Ÿฆ‹. Redistributing objects with attributes removed or altered is not possible, since that would invalidate the submitter's signature and make later authentication checks impossible ๐Ÿ™…โ€โ™€๏ธ. Repositories should not redistribute a subset of the objects of a given type.

Software also shouldn't let a transaction contain both redistributable objects (e.g. policy objects) and non-redustributable objects (e.g. person). There's no way to verify the signature of those transactions without the non-redustributable objects, so it's a no-go ๐Ÿ’€.

When redistributing legacy data, contact information in attributes such as "changed" and "notify" should be stripped to keep things private ๐ŸŒธ. The "integrity" attribute on these objects should already be set to "legacy", which signals that their origin is questionable. So the fact that signatures can't be rechecked isn't as big a deal โœจ.


References ๐Ÿ“š

  • [1] Alaettinoglu, C., Villamizar, C., Gerich, E., Kessens, D., Meyer, D., Bates, T., Karrenberg, D. and M. Terpstra, "Routing Policy Specification Language", RFC 2622, June 1999.
  • [2] Bates, T., Gerich, E., Joncheray, L., Jouanigot, J-M., Karrenberg, D., Terpstra, M. and J. Yu, "Representation of IP Routing Policies in a Routing Registry (ripe-81++)", RFC 1786, March 1995.
  • [3] Villamizar, C., Alaettinoglu, C., Meyer, D. and S. Murphy, "Routing Policy System Security", RFC 2725, June 1999.
  • [4] Zsako, J., "PGP Authentication for RIPE Database Updates", RFC 2726, December 1999.

Security Considerations ๐Ÿ›ก๏ธ

An authentication and authorization model for routing policy object submission is provided by [3]. Cryptographic authentication is addressed by [4]. This document provides a protocol for the exchange of information among distributed routing registries, so the authorization model provided by [3] can be adhered to by all registries. Any deviation from those rules on the part of a registry, hopefully accidental, can be identified by other registries or mirrors ๐Ÿ‘‘.


Authors' Addresses ๐Ÿ’Œ

  • Curtis Villamizar Avici Systems EMail: curtis@avici.com
  • Cengiz Alaettinoglu ISI EMail: cengiz@ISI.EDU
  • Ramesh Govindan ISI EMail: govindan@ISI.EDU
  • David M. Meyer Cisco EMail: dmm@cisco.com

Copyright (C) The Internet Society (2000). All Rights Reserved.

This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English.

The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns.

This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.


Acknowledgement ๐ŸŒˆ

Funding for the RFC Editor function is currently provided by the Internet Society. ๐Ÿ’–

๐Ÿ“ฆ where this page comes from