RFC 2769
Routing Policy System Replication
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 Notice ยฉ๏ธ
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
delegatedattribute 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 adelegatedattribute 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:
- 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 ๐
- 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 ๐
- 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 isYYYYMMDD hh:mm:ss [+/-]xx:yy, whereYYYYis the four digit year,MMthe month,DDthe date,hhthe hour,mmthe minutes, andssthe seconds of the timestamp.xxandyyare the hours and minutes that the timestamp is ahead of or behind UTC ๐integrity: optional and single-valued. It may have the valueslegacy,no-auth,auth-failed, orauthorized. If it's absent, the integrity is considered to beauthorized๐ซถ
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 valueslegacy,no-auth,auth-failed, orauthorized. If it's absent, the value is the same as the value in thetransaction-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 therepository-certattribute 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 therepository-signatureandintegrityattributes 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 eithergziporplain. 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 beplain. 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 โจ
- It must decapsulate the
transaction-beginmeta-object, then decode the original redistributed text according to the value of thetransfer-methodattribute specified in thetransaction-beginmeta-object. - It should then extract the
transaction-labelmeta-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 ๐ - It should verify that the signature of the originating repository matches the first
repository-signaturemeta-object in the redistributed text that follows theauth-dependencymeta-objects. - 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 โธ๏ธ
- It may check whether any subsequent
repository-signaturemeta-objects were appended by a trusted repository. If so, that means the trusted repository verified the transaction's integrity and marked its conclusion in theintegrityattribute 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 ๐ค - 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 ๐
- 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-dependencymeta-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 theauth-dependencymeta-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 thesequence-beginattribute 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 thesequence-endattribute 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 keywordsheld,error, orsucceeded. theerrorkeyword can be followed by an optional text string. theheldkeyword 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 fileX.dbalways ends with a special comment line,# eof๐X.<class>.db: an optional file that, if it's there, holds the RPSL objects fromX.dbthat belong to class<class>. its format is the same asX.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:
- the simplest one: accept the transaction and mark it with integrity
"no-auth". - only peer with trusted repositories during this time period, and accept the transaction with the same integrity as the trusted repository (possibly
"authorized"). - 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:
- No support for repeating authorization checks or transaction authentication checks needs to be coded in the router.
- The router must be adjacent only to trusted mirrors, generally operated by the same organization.
- The router would only check the authentication of the adjacent repository mirrors.
- No support for transaction submission or query needs to be coded in the router. No commit support is needed.
- 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:
- Modify the format of "near real time mirroring" transaction exchange to conform to the specifications of this document.
- Implement commit protocol and confirmation support.
- Implement remote recheck of authorization. Prior to this step all repositories must be trusted.
- 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
Full Copyright Statement โ๏ธ
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
- ietf: rfc2769 2000-02
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms