<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE rfc>

<?rfc sortrefs="yes"?>
<?rfc subcompact="no"?>
<?rfc symrefs="yes"?>
<?rfc toc="yes"?>
<?rfc tocdepth="3"?>
<?rfc compact="yes"?>
<?rfc subcompact="no"?>
<rfc
  xmlns:xi="http://www.w3.org/2001/XInclude"
  version="3"
  category="std"
  docName="draft-ietf-grow-nrtm-v4-09"
  submissionType="IETF"
  consensus="true"
  ipr="trust200902">

<front>

  <title abbrev="NRTM v4">Near Real Time Mirroring (NRTM) version 4</title>

  <author fullname="Sasha Romijn" initials="S." surname="Romijn">
    <organization>Reliably Coded</organization>
    <address>
      <postal>
        <street />
        <city>Amsterdam</city>
        <code />
        <country>Netherlands</country>
      </postal>
      <email>sasha@reliablycoded.nl</email>
      <uri>https://www.reliablycoded.nl/</uri>
    </address>
  </author>

  <author fullname="Job Snijders" initials="J." surname="Snijders">
    <organization abbrev="BSD">BSD Software Development</organization>
    <address>
      <postal>
        <street />
        <city>Amsterdam</city>
        <code />
        <country>Netherlands</country>
      </postal>
      <email>job@bsd.nl</email>
      <uri>https://www.bsd.nl/</uri>
    </address>
  </author>

  <author fullname="Edward Shryane" initials="E." surname="Shryane">
    <organization>RIPE NCC</organization>
    <address>
      <postal>
        <street />
        <city>Amsterdam</city>
        <code />
        <country>Netherlands</country>
      </postal>
      <email>eshryane@ripe.net</email>
    </address>
  </author>

  <author fullname="Stavros Konstantaras" initials="S." surname="Konstantaras">
    <organization>AMS-IX</organization>
    <address>
      <postal>
        <street />
        <city>Amsterdam</city>
        <code />
        <country>Netherlands</country>
      </postal>
      <email>stavros.konstantaras@ams-ix.net</email>
    </address>
  </author>
  <date />

  <area>OPS</area>
  <workgroup>GROW</workgroup>
  <keyword>NRTM</keyword>
  <keyword>RPSL</keyword>
  <keyword>IRR</keyword>

  <abstract>
    <t>
      This document specifies a one-way synchronization protocol for Internet Routing Registry (IRR) records, called Near Real Time Mirroring version 4 (NRTMv4), in which files are distributed over HTTPS.
      The protocol allows instances of IRR database servers to mirror IRR records, specified in the Routing Policy Specification Language (RPSL), between each other.
    </t>
  </abstract>

  <note title="Requirements Language">
    <t>
      The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as shown here.
    </t>
  </note>

</front>

<middle>

  <section title="Introduction">
    <t>
      The Internet Routing Registry (IRR) consists of several IRR Databases, each storing objects in the Routing Policy Specification Language (RPSL) <xref target="RFC2622"/>.
      About a dozen larger IRR Databases are well known and widely used, operated by different organizations such as Regional Internet Registries and some large network operators.
      IRR objects serve many purposes, ranging from manual research by operators to automated network configuration and filtering.
    </t>

    <t>
      Most of these well-known IRR Databases mirror IRR objects from some others, so that queries run against these instances provide a comprehensive view.
      Some parties also mirror IRR Databases to private IRR server instances, to reduce latency when replying to queries, analyze IRR objects, or other purposes.
    </t>

    <t>
      NRTM version 4 (NRTMv4) is a protocol for IRR mirroring, designed to address issues in existing IRR Database mirroring protocols.
      In NRTMv4, IRR Databases publish their records on an HTTPS <xref target="STD97"/> endpoint, with periodic Snapshot Files and regular Delta Files.
      Signing allows integrity checks.
      By only generating files once and publishing them over HTTPS, scalability is improved.
      NRTMv4 borrows some concepts in <xref target="RFC8182"/>, as there are overlaps between the two protocols.
    </t>

    <t>
      Reliable and secure distribution of IRR data is important for global routing operations, as network operators depend on IRR objects for route filtering and network configuration.
      Prior mirroring protocols lack integrity verification, have no formal specification, and scale poorly.
      NRTMv4 addresses these shortcomings by providing a formally specified, scalable, and integrity-protected mirroring protocol.
      Of earlier NRTM versions, particularly NRTMv3 <xref target="NRTMv3"/> was widely deployed.
      Some comparisons are made in <xref target="security_considerations" />.
    </t>

  </section>

  <section title="Overview">
    <t>
      In NRTMv4, a mirror server is an instance of IRR Database software that has a database of IRR objects and publishes them to allow mirroring by others.
      These objects can be retrieved by mirror clients, which then load them into their local storage.
      The IRR Database has a version, which the mirror server starts at 1, and increments every time it publishes a set of changes.
    </t>
    <figure>
      <name>NRTMv4 Protocol Overview</name>
      <artwork type="ascii-art"><![CDATA[
                        Mirror Server
                       +--------------+
                       | IRR Database |
                       +------+-------+
                              |
          +-------------------+-------------------+
          |                   |                   |
      periodic                |               on change
          |                   |                   |
          v                   v                   v
    +------------+      +-----------+      +------------+
    |  Snapshot  |      |  Update   |      |   Delta    |
    |    File    | refs |   Notif.  | refs |  File(s)   |
    |   (all     |<-----|   File    |----->| (changes   |
    |  objects)  |      |  (index)  |      |   only)    |
    +-----+------+      +-----------+      +-----+------+
          |                   |                  |
          |          +--------+--------+         |
          +--------->+  Mirror Client  +<--------+
            initial  | Local Database  |   update
                     +-----------------+
]]></artwork>
    </figure>
    <t>
      Publication consists of three different files:
    </t>
    <ul>
      <li>
        A single Update Notification File.
        This specifies the current IRR Database version and locations of the Snapshot File and Delta Files.
        It is signed to allow verification of the authenticity of the Update Notification File.
      </li>
      <li>
        A single active Snapshot File.
        This contains all published IRR objects at a particular version.
        The mirror server periodically generates a new snapshot.
      </li>
      <li>
        Zero or more Delta Files.
        These contain the changes between two database versions.
      </li>
     </ul>
     <t>
       The Update Notification File MUST be in the JSON Web Signature <xref target="RFC7515" /> format, where the payload is in the JavaScript Object Notation (JSON) format <xref target="RFC8259" />.
       The Snapshot File and Delta Files MUST be in the JSON Text Sequences <xref target="RFC7464" /> format, so that each object in large files can be parsed independently.
       Files MAY be compressed with GZIP <xref target="RFC1952" />.
     </t>
     <t>
       Mirror clients initially retrieve the small Update Notification File and a Snapshot File, from which they initialize their local copy of the Database.
       After that, mirror clients only retrieve the Update Notification File periodically, typically every minute, to determine whether there are any changes, and then retrieve only the relevant Delta Files, if any.
       This minimizes data transfer.
       Deltas have sequential versions.
     </t>
     <t>
       Mirror clients are configured with the URL of an Update Notification File, name of the IRR Database, and a public signing key. This public key is used to verify the Update Notification File, which in turn contains hashes of all the Snapshot and Delta Files.
     </t>
     <t>
       Upon initialization, the mirror server generates a session identifier (session_id) for the Database (<xref target="mirror_server_snapshot_initialization" />).
       This allows long term caching and is used by the client to determine that the Delta Files continue to form a full set of changes allowing an update to the latest version.
       If the mirror server loses partial history, or the mirror client starts mirroring from a different server, the session_id change will force a full reload from the latest Snapshot File, ensuring there are no accidental mirroring gaps.
     </t>
     <t>
       Mirror servers can use caching to reduce their load, particularly because snapshots and deltas are immutable for a given session_id and version number.
       These are also the largest files. Update Notification Files may not be cached for longer than one minute, but are fairly small.
     </t>
     <t>
       Note that in NRTMv4, contiguous version numbers are used for the Database version and Delta Files.
       This is different and unrelated to the serial in NRTMv3.
       NRTMv3 serials refer to a single change to a single object, whereas an NRTMv4 version refers to one delta, possibly containing multiple changes to multiple objects.
       NRTMv3 serials can also contain gaps, NRTMv4 versions may not.
      </t>
    </section>
  <section title="Terminology">
    <dl>
      <dt>IRR Database</dt>
      <dd>An Internet Routing Registry database that stores objects in the Routing Policy Specification Language (RPSL).</dd>
      <dt>Snapshot File</dt>
      <dd>A file that reflects the complete contents of the IRR objects in an IRR Database, at a particular point in time.</dd>
      <dt>Delta File</dt>
      <dd>A file that contains all changes for exactly one incremental update of the IRR Database.</dd>
      <dt>Update Notification File</dt>
      <dd>A file generated by the mirror server and used by mirror clients to discover which changes exist between the state of the IRR mirror server and of the mirror client.</dd>
      <dt>Mirror Server</dt>
      <dd>An instance of IRR Database software that has a database of IRR objects and publishes them to allow mirroring by others.</dd>
      <dt>Mirror Client</dt>
      <dd>An instance of IRR Database software that retrieves IRR objects from a mirror server and loads them into its local storage.</dd>
      <dt>Version</dt>
      <dd>An incremental number that identifies the IRR Database at a particular point in time.</dd>
    </dl>
  </section>
  <section title="Mirror Server Use">
    <section title="Key Configuration">
      <t>
        When enabling NRTMv4 publication for an IRR Database, the operator MUST generate a JSON Web Key <xref target="RFC7517"/> pair and configure the private key in the mirror server.
        The operator then provides the corresponding public key, the name of the IRR Database, and publication URL of the Update Notification File to any operators of mirror clients.
        The published public key MUST be encapsulated following Textual Encoding of Subject Public Key Info <xref target="RFC7468" section="13"/>, sometimes referred to as "PEM encoding".
        The process for providing this is not in the scope of this protocol, but a typical case is publication on the operator's known website.
        Key rotation is described in <xref target="public_key_rotation" />.
      </t>
      <t>
        It is RECOMMENDED that implementations provide easily accessible tools for operators to generate new signing keys to enter into their configuration and assist with key rotation.
        All configuration options SHOULD be clearly named to indicate that they are private keys.
      </t>
    </section>
    <section title="Snapshot Initialization" anchor="mirror_server_snapshot_initialization">
      <t>
        A mirror server MUST follow the initialization steps upon the first export for an IRR Database by that mirror server, or if the server lost history and can not reliably produce a continuous set of deltas from a previous state.
      </t>
      <t>
        In other words, either the mirror server guarantees that clients following the deltas have a correct and complete view, or must reinitialize, which will force clients to reinitialize as well.
      </t>
      <t>
        Initialization consists of these actions:
      </t>
      <ul>
        <li>
          The mirror server MUST generate a new session_id.
          This MUST be a Universally Unique Identifier version 4 (UUIDv4) (Section 5.4 of  <xref target="RFC9562"/>) and MUST be the same across all client sessions.
          The session_id is unique to the IRR Database, so an instance that serves multiple IRR Databases, will create a separate session_id for each.
        </li>
        <li>
          The server MUST generate a snapshot for version number one.
          This may contain an empty array of objects if the IRR Database is currently empty.
        </li>
        <li>
          The server MUST generate a new Update Notification File with the new session_id, a reference to the new snapshot, and no deltas.
        </li>
      </ul>
      <t>
        Note that a publication, and its associated session_ids and versions, always relates to a single specific IRR Database, even if multiple databases are published from one instance.
        For example, a mirror server publishing NRTMv4 for RIPE and RIPE-NONAUTH, will generate two Update Notification Files, referring to two Snapshot Files, and two sets of Delta Files each with contiguous version numbers - all completely independent of each other, with different session IDs, potentially at different times.
        This applies even if the same IRR server instance produces both.
      </t>
    </section>

    <section title="Publishing Updates">
      <t>
        After creating the initialization files, the mirror server processes updates by publishing Delta Files and, periodically, a new Snapshot File.
      </t>
      <section title="Delta Files">
        <t>
          Changes to IRR objects MUST be recorded in Delta Files. One Delta File can contain multiple changes.
        </t>
        <t>
          Updates are generated as follows:
        </t>
        <ul>
          <li>
            A mirror server MUST publish a Delta File approximately every minute, if there have been changes to IRR objects in that time frame.
          </li>
          <li>
            If a mirror server is lagging in production of Delta Files, such as after an initialization or server downtime, it MUST generate one larger "catch up" Delta File, rather than individual Delta Files for every one-minute window.
          </li>
          <li>
            A new Delta File MUST be generated with a new version, one greater than the last Delta File version, or one greater than the last Snapshot File version if there were no prior deltas at all.
          </li>
          <li>
            The Delta File MUST include all changes that happened during the time frame, in the order in which they occurred.
            If multiple changes have occurred within the time frame that would cancel each other out, like an addition and immediate deletion of the same object, the mirror server MUST still include all these changes.
          </li>
          <li>
            The URL where the Delta File is published MUST contain the session ID and version number to allow it to be indefinitely cached.
            It MUST also contain a random value that can not be predicted before publication, to counter negative caching issues.
          </li>
          <li>
            The Update Notification File MUST be updated to include the new Delta File.
          </li>
          <li>
            References to Delta Files older than 24 hours SHOULD be removed from the Update Notification File. Refer also to <xref target="storage" />.
          </li>
          <li>
            Note that, as Delta Files always contain changes compared to a previous state, there can never be a Delta File with version 1.
          </li>
        </ul>
        <t>
          Mirror servers with high object churn are RECOMMENDED to generate new Snapshot Files more frequently than the required minimum, to limit the length of the delta chain that clients must traverse on initialization or after a gap.
          Long delta chains increase initialization time and resource consumption for mirror clients.
        </t>
      </section>
      <section title="Snapshot Files">
        <t>
          Snapshot Files after initialization are generated as follows:
        </t>
        <ul>
          <li>
            If there have been no changes to the IRR objects since the last snapshot, the mirror server MUST NOT generate a new snapshot.
          </li>
          <li>
            The mirror server MUST generate a new Snapshot File between once per hour and once per day, if there have been changes to the IRR objects.
          </li>
          <li>
            The version number of the new snapshot MUST be equal to the last Delta File version.
          </li>
          <li>
            The URL where the Snapshot File is published MUST contain the session ID and version number to allow it to be indefinitely cached.
            It MUST also contain a random value that can not be predicted before publication, to counter negative caching issues.
          </li>
          <li>
            The Update Notification File MUST be updated to include the new snapshot, if one was generated.
          </li>
          <li>
            Snapshot generation may take some time, and in that time newer changes may occur that are not part of the snapshot in progress.
            The mirror server SHOULD continue to produce Delta Files during this window, which means that the server may publish a Snapshot File with a version number older than the most recent Delta File at the time of publication.
          </li>
        </ul>
      </section>
      <section title="Update Notification File">
        <t>
          The Update Notification File MUST be updated when a new Delta or Snapshot File is published and, even if there have been no changes, at least every 24 hours.
        </t>
      </section>
      <section title="Publication Policy Restrictions">
        <t>
          A mirror server MAY have a policy that restricts the publication of certain IRR objects or attributes, or modifies these before publication.
          Typical scenarios for this include preventing the distribution of certain personal data or password hashes, or excluding objects which do not meet validation rules like Resource Public Key Infrastructure (RPKI) consistency.
          It is RECOMMENDED to modify objects in such a way that this change is evident to humans reading the object text, for example, by adding remark lines or comments.
        </t>
        <t>
          Mirror servers are RECOMMENDED to remove password hashes from the auth lines in mntner objects, as they have little use beyond the authoritative server, and their publication may be a security risk.
        </t>
        <t>
          If a mirror server has a policy that restricts or modifies object publication, this MUST be applied consistently to Snapshot Files and Delta Files from the moment the policy is enacted or modified.
        </t>
      </section>
    </section>
  </section>

  <section title="Mirror Client Use">
    <section title="Client Configuration">
      <t>
        Mirror clients are configured with the name of the IRR Database, the URL of the Update Notification File, and the public key currently used for signing the Update Notification File.
        Key rotation is described in <xref target="public_key_rotation" />.
      </t>
    </section>

    <section title="Update Notification File Retrieval">
      <t>
        Mirror clients may retrieve the Update Notification File to check for changes every minute.
        Mirror clients MUST NOT check more than once per minute.
      </t>
    </section>

    <section title="Initialization from Snapshot">
      <t>
        Clients MUST initialize from a Snapshot File when initially configured or if they are not able to update their local data from the provided Delta Files:
      </t>
      <ul>
        <li>
          The client MUST retrieve the Update Notification File.
        </li>
        <li>
          The client MUST verify that the source attribute in the Update Notification File matches the configured IRR Database name.
        </li>
        <li>
          The client MUST retrieve the Snapshot File and load the objects into its local storage.
        </li>
        <li>
          The mirror client MUST verify that the hash of the Snapshot File matches the hash in the Update Notification File that referenced it.
          If the Snapshot File was compressed with GZIP, the hash MUST match the compressed data.
          In case of a mismatch of this hash, the file MUST be rejected.
        </li>
        <li>
          The client MUST record the session_id and version of the loaded Snapshot File.
        </li>
        <li>
          If an Update Notification File or a Snapshot File has an invalid syntax (e.g. missing mandatory parameters), the file MUST be rejected.
          For validating the IRR objects contained in the files, see <xref target="irr_object_validation" />.
        </li>
      </ul>
    </section>
    <section title="Processing Delta Files">
      <t>
        If a mirror client has previously initialized from a snapshot:
      </t>
      <ul>
        <li>
          The client MUST retrieve the Update Notification File.
        </li>
        <li>
          The client MUST verify that the source attribute in the Update Notification File matches the configured IRR Database name.
        </li>
        <li>
          The client MUST verify that the session_id matches the previously known session_id.
          If this does not match, the client MUST reinitialize from the snapshot.
        </li>
        <li>
          The client MUST verify that the Update Notification File version is the same or higher than the client's current most recent version.
          If not, the Update Notification File MUST be rejected.
          It is RECOMMENDED for the client to distinguish between an Update Notification File that is a single version older, and a much older version, in any status messages.
          The former can occur from time to time in synchronization issues, the latter is more likely a faulty implementation.
        </li>
        <li>
          The client MUST verify that the Update Notification File contains one contiguous set of Delta File versions after the client's current most recent version up to the latest version in the Update Notification File.
          If the Delta File versions are not contiguous, the Update Notification File MUST be rejected.
          If the available Delta File versions do not range from the client's most recent version plus one, the client MUST reinitialize from the snapshot.
        </li>
        <li>
          The mirror client MUST verify that the hashes of each Delta and Snapshot File have not changed compared to previous entries seen for the same file type and version.
          If a newer Update Notification File contains a different hash for a specific file, this indicates a misconfiguration in the server and the client MUST reject the Update Notification File.
          The client can do this by recording the files referenced by the previous valid Update Notification File and comparing the overlapping entries with the retrieved Update Notification File.
        </li>
        <li>
          The client MUST retrieve all Delta Files for versions since the client's last known version, if there are any.
        </li>
        <li>
          The mirror client MUST verify that the hash of each newly downloaded Delta File matches the hash in the Update Notification File that referenced it.
          If the Delta File was compressed with GZIP, the hash MUST match the compressed file.
          In case of a mismatch of this hash, the Delta File MUST be rejected.
        </li>
        <li>
          The client MUST process all changes in the Delta Files in order: lowest Delta File version number first, and in the order of the changes list in the Delta File.
        </li>
        <li>
          The client MUST update its records of the most recent version to the version of the Update Notification File.
        </li>
        <li>
          If an Update Notification File or a Delta File has an invalid syntax (including missing mandatory parameters), the file MUST be rejected.
          For validating the IRR objects contained in the files, see <xref target="irr_object_validation" />.
        </li>
      </ul>
      <t>
        If the Update Notification File or one of the Delta Files is rejected, the mirror client MUST NOT process any newer Deltas than those that are valid and have been successfully verified.
        If some Delta Files are rejected, it MAY process the valid Delta Files, but MUST NOT skip over any rejected Delta Files while doing so.
        Additionally, the changes in a specific Delta File MUST be processed either completely, or not at all, i.e., a Delta File must never be partially processed.
      </t>
    </section>
    <section title="Error Recovery">
      <t>
        When a mirror client fails to retrieve any file due to a transient error, such as a network failure or an HTTP 5xx response, the client SHOULD retry before concluding the retrieval has failed.
        It is RECOMMENDED that implementations use a bounded exponential backoff strategy, starting from a short initial interval (e.g., a few seconds) up to a capped maximum interval (e.g., several minutes), with a bounded total retry duration.
        Mirror clients SHOULD log retry and recovery events including the reason, to aid operator troubleshooting.
      </t>
      <t>
        If a file is rejected, the mirror client MUST NOT load any data from it.
        If the error may be transient, the mirror client SHOULD retry.
        After exhausting retries, if the required Delta Files remain unavailable or are still rejected, the mirror client SHOULD reinitialize from the Snapshot File.
        If the Snapshot File itself cannot be retrieved or is rejected after retries, as there is no further fallback, the client SHOULD alert the operator and stop until the issue is resolved.
      </t>
    </section>
    <section title="Signature and Staleness Verification">
      <t>
        Every time a mirror client retrieves a new version of the Update Notification File, it MUST verify the included signature.
        The signature MUST be valid for the configured public key for the contents of the Update Notification File.
        If the signature does not match, the mirror client MUST reject the Update Notification File, unless a key rotation is in progress as described in <xref target="public_key_rotation" />.
      </t>
      <t>
        A mirror client can use the generation timestamp in the Update Notification File to check whether the file is stale, as the mirror server must update this file at least every 24 hours.
        If the generation timestamp is more than 24 hours ago, the file is stale and the mirror client SHOULD warn the operator in log messages or other alerting, but MAY continue to process it otherwise.
      </t>
    </section>
    <section title="Policy Restrictions">
      <t>
        A mirror client MAY have a policy that restricts the processing of objects to certain object classes, or other limitations on which objects it processes.
      </t>
      <t>
        If a mirror client has a policy that restricts object processing, this MUST be applied consistently to Snapshot Files and Delta Files from the moment the policy is enacted or modified.
      </t>
    </section>
  </section>


  <section title="Update Notification File">
    <section title="Purpose">
      <t>
        The Update Notification File is generated by the mirror server and used by mirror clients to discover whether any changes exist between the state of the IRR mirror server and of the mirror client.
        It also describes the location of the Snapshot File and incremental Delta Files.
        Finally, the generation timestamp can be used to detect whether the file is stale.
      </t>
      <t>
        The mirror server MUST generate a new Update Notification File every time there are new deltas or snapshots and, even if there have been no changes, at least every 24 hours.
      </t>
    </section>

    <section title="Cache Concerns">
      <t>
        A mirror server may use caching infrastructure to cache the Update Notification File and reduce the load of HTTPS requests.
      </t>
      <t>
        However, since this file is used by mirror clients to determine whether any updates are available, the mirror server SHOULD ensure that this file is not cached for longer than one minute.
        An exception to this rule is that it is better to serve a stale Update Notification File rather than no Update Notification File.
      </t>
      <t>
        Mirror servers SHOULD set the HTTP <tt>Cache-Control</tt> response header on the Update Notification File to <tt>no-cache</tt> or <tt>max-age=60</tt>, consistent with the one-minute caching limit.
        Mirror servers SHOULD set <tt>Cache-Control: immutable</tt> on responses for Snapshot Files and Delta Files, as these are immutable for a given session_id and version.
        Mirror clients MAY use HTTP conditional requests (e.g., using <tt>If-None-Match</tt> with ETags or <tt>If-Modified-Since</tt>) when polling the Update Notification File, to reduce bandwidth consumption when no changes have occurred.
      </t>
    </section>

    <section title="Payload Format and Validation">
      <t>
        An example payload of an Update Notification File is provided below:
      </t>
<sourcecode><![CDATA[
{
  "nrtm_version": 4,
  "timestamp": "2025-12-01T15:00:00Z",
  "type": "notification",
  "next_signing_key": "bnJ0..bXY0",
  "source": "EXAMPLE",
  "session_id": "ca128382-78d9-41d1-8927-1ecef15275be",
  "version": 4,
  "snapshot": {
    "version": 3,
    "url":
"ca128382-78d9-41d1-8927-1ecef15275be/nrtm-snapshot.2.04759.json.gz",
    "hash": "9a..86"
  },
  "deltas": [
    {
      "version": 2,
      "url":
"ca128382-78d9-41d1-8927-1ecef15275be/nrtm-delta.1.784a2a6.json",
      "hash": "62..a2"
    },
    {
      "version": 3,
      "url":
"ca128382-78d9-41d1-8927-1ecef15275be/nrtm-delta.2.0f681f0.json",
      "hash": "25..9a"
    },
    {
      "version": 4,
      "url":
"ca128382-78d9-41d1-8927-1ecef15275be/nrtm-delta.3.d9c194a.json",
      "hash": "b4..13"
    }
  ],
  "metadata": {}
}
]]></sourcecode>
      <t>
        Note: hash and key values in this example are shortened because of formatting.
      </t>
      <t>
        In this example, the overall version is 4, the snapshot is at version 3, and deltas are listed for versions 2, 3, and 4.
        The deltas at versions 2 and 3 predate the snapshot but are still within the 24-hour retention window.
        A new client would initialize from the snapshot at version 3 and then apply only delta 4.
        An existing client already at version 1 can instead apply deltas 2, 3, and 4 without reinitializing from the snapshot.
      </t>
      <t>
        The following validation rules MUST be observed when creating or parsing Update Notification Files:
      </t>
      <ul>
        <li>
          The nrtm_version MUST be 4.
        </li>
        <li>
          The timestamp MUST be an <xref target="RFC3339"/> timestamp with the time-offset set to "Z".
        </li>
        <li>
          The type MUST be "notification".
        </li>
        <li>
          The optional field next_signing_key is used for in-band key rotation.
          If present, it MUST be a JWK <xref target="RFC7517"/> public key encoded in PEM, which matches the private key the mirror server will start using to sign the Update Notification File in the near future.
          Key rotation is described in <xref target="public_key_rotation" />.
          If there is no next signing key, this key MUST be omitted.
        </li>
        <li>
          The source MUST be a valid IRR object name <xref target="RFC2622"/>.
        </li>
        <li>
          The session_id attribute MUST be a UUIDv4 (Section 5.4 of <xref target="RFC9562"/>) unique to this session for this source.
        </li>
        <li>
          The version MUST be an unsigned positive integer and be equal to the highest version of the deltas and snapshot.
        </li>
        <li>
          The file MUST contain exactly one snapshot.
        </li>
        <li>
          The file MAY contain one or more deltas.
        </li>
        <li>
          The deltas MUST have a sequential contiguous set of version numbers.
        </li>
        <li>
          Each snapshot and delta element MUST have a version, URL and hash attribute.
          The URL must be relative to the path of the Update Notification File.
          For example, if the Update Notification File example above is published on https://example.com/nrtm/update-notification-file.json, the full URL for the referred snapshot is https://example.com/nrtm/ca128382-78d9-41d1-8927-1ecef15275be/nrtm-snapshot.2.047595d0fae972fbed0c51b4a41c7a349e0c47bb.json.gz.
          If the snapshot or delta file was compressed with GZIP, the filename MUST end in ".gz", and the hash MUST match the compressed data.
        </li>
        <li>
          The hash attribute in snapshot and delta elements MUST be the hexadecimal encoding of the SHA-256 hash <xref target="SHS"/> of the referenced file.
          The mirror client MUST verify this hash when the file is retrieved and reject the file if the hash does not match.
        </li>
        <li>
          The metadata key MAY be present, used for metadata produced by the server to aid in tracing and debugging.
          This can contain information like the name of the host on which the file was generated or the name and version of the software used.
          Each mirror server may choose which fields to include, or choose to not include any metadata.
          The mirror server SHOULD NOT cause excessive size increases by adding extensive metadata in the Update Notification File, as it is the most frequently retrieved file.
        </li>
      </ul>
    </section>
    <section title="Encoding and signature">
      <ul>
        <li>
          The actual Update Notification File content is a JSON Web Signature <xref target="RFC7515"/> using JWS Compact Serialization.
        </li>
        <li>
          The JWS Payload is the JSON <xref target="RFC8259"/> serialization of the structure described in the previous section.
        </li>
        <li>
          The filename of the serialized data MUST be "update-notification-file.jose".
        </li>
        <li>
          Implementations MUST support ES256 for interoperability.
          The algorithm MUST NOT be Deprecated, and it is RECOMMENDED to use Recommended or Recommended+ algorithms, as listed in the IANA JOSE Algorithms registry <xref target="IANA_jose"/>.
        </li>
      </ul>
    </section>
  </section>


  <section title="Snapshot File">

    <section title="Purpose">
      <t>
        The Snapshot File reflects the complete and current contents of all IRR objects in an IRR Database.
        Mirror clients MUST use this to initialize their local copy of the IRR Database.
      </t>
    </section>

    <section title="Cache Concerns">
      <t>
        A snapshot reflects the content of the IRR Database at a specific point in time; for that reason, it can be considered immutable data.
        Snapshot Files are published at a URL that is unique to the specific session and version.
        The URL also contains a random value that can not be predicted before publication, to counter negative caching issues.
      </t>
      <t>
        Because these files never change, they can be cached.
        However, as snapshots are large and old snapshots will no longer be referred by newer Update Notification Files, it is RECOMMENDED that a limited cache interval is used.
      </t>
    </section>

    <section title="File Format and Validation">
      <t>
        Example Snapshot File:
      </t>
<sourcecode><![CDATA[
␞{
  "nrtm_version": 4,
  "type": "snapshot",
  "source": "EXAMPLE",
  "session_id": "ca128382-78d9-41d1-8927-1ecef15275be",
  "version": 3
}
␞{"object": "route: 192.0.2.0/24\norigin: AS64500\nsource: EXAMPLE"}
␞{"object": "route: 2001:db8::/32\norigin: AS64500\nsource: EXAMPLE"}
]]></sourcecode>
      <t>
        Note: IRR object texts in this example are shortened because of formatting.
      </t>
      <t>
        The file is in JSON Text Sequences <xref target="RFC7464" /> format, and MUST contain one or more records (it must contain at least the header).
        The first record is the file header, and the following validation rules MUST be observed when creating or parsing a Snapshot File header:
      </t>
      <ul>
        <li>
          The nrtm_version MUST be 4.
        </li>
        <li>
          The type MUST be "snapshot".
        </li>
        <li>
          The source MUST match the source in the Update Notification File.
        </li>
        <li>
          The session_id attribute MUST match the session_id in the Update Notification File.
        </li>
        <li>
          The version MUST be an unsigned positive integer, matching the Update Notification File entry for this snapshot.
        </li>
      </ul>
      <t>
        The remaining records (zero or more) MUST each contain a string representation of an IRR object.
        The source attribute in the IRR object texts MUST match the source attribute of the Snapshot File.
      </t>
    </section>
  </section>

  <section title="Delta File">

    <section title="Purpose">
      <t>
        A Delta File contains all changes for exactly one incremental update of the IRR Database.
        It may include new, modified and deleted objects. Delta Files can contain multiple alterations to multiple objects.
      </t>
    </section>

    <section title="Cache Concerns">
      <t>
        Deltas reflect the difference in content of the IRR Database from one version to another; for that reason, it can be considered immutable data.
        Delta Files are published at a URL that is unique to the specific session and version.
        The URL also contains a random value that can not be predicted before publication, to counter negative caching issues.
      </t>
      <t>
        To avoid race conditions where a mirror client retrieves an Update Notification File moments before it's updated, mirror servers SHOULD retain old Delta Files for at least 5 minutes after a new Update Notification File is published that no longer contains these Delta Files.
      </t>
    </section>

    <section title="File Format and Validation">
      <t>
        Example Delta File:
      </t>
<sourcecode><![CDATA[
␞{
  "nrtm_version": 4,
  "type": "delta",
  "source": "EXAMPLE",
  "session_id": "ca128382-78d9-41d1-8927-1ecef15275be",
  "version": 3
}
␞{
  "action": "delete",
  "object_class": "person",
  "primary_key": "PRSN1-EXAMPLE"
}
␞{
  "action": "delete",
  "object_class": "route",
  "primary_key": "192.0.2.0/24AS64500"
}
␞{
  "action": "add_modify",
  "object": "route: 2001:db8::/32\norigin: AS64500\nsource: EXAMPLE"
}
]]></sourcecode>
      <t>
        Note: IRR object texts in this example are shortened because of formatting.
      </t>
      <t>
        The file is in JSON Text Sequences <xref target="RFC7464" /> format, and MUST contain two or more records (at least the header and one change).
        The first record is the file header, and the following validation rules MUST be observed when creating or parsing a Delta File header:
      </t>
      <ul>
        <li>
          The nrtm_version MUST be 4.
        </li>
        <li>
          The type MUST be "delta".
        </li>
        <li>
          The source MUST match the source in the Update Notification File.
        </li>
        <li>
          The session_id attribute MUST match the session_id in the Update Notification File.
        </li>
        <li>
          The version MUST be an unsigned positive integer, matching the Update Notification File entry for this delta.
        </li>
      </ul>
      <t>
        The remaining records (one or more) MUST each contain a JSON object representing a change, which MUST meet the following rules:
      </t>
      <ul>
        <li>
          An action attribute, which is either "delete" for object deletions, or "add_modify" for additions or modifications.
        </li>
        <li>
          If action is "delete": an object_class attribute with the RPSL object class name, and a primary_key attribute with the primary key, of the deleted object.
          For objects that are listed in <xref target="RFC2622"/> and <xref target="RFC4012"/> the primary key is the value of the RPSL field defined as "class key".
          For object classes that define a pair of attributes as class key, e.g. route, the values of the individual attributes are appended together without separators.
          For any other objects, the primary key is the value of the RPSL field with the same name as the object class name.
          The primary key and object class name are not case sensitive and therefore mirror clients MUST use case insensitive matching against their local database.
        </li>
        <li>
          If action is "add_modify": an object attribute with the RPSL text of the new version of the object.
        </li>
      </ul>

    </section>
  </section>

  <section title="Operational Considerations">

    <section title="Time">
      <t>
        IRR clients and servers are RECOMMENDED to use <xref target="RFC5905">NTP</xref> synchronisation to avoid timing discrepancies.
      </t>
    </section>

    <section title="IRR Object Validation" anchor="irr_object_validation">
      <t>
        Throughout the years, various implementations of IRR servers have taken liberties with the various RFCs regarding RPSL.
        Implementations have introduced different new object classes, attributes and validation rules.
        Current IRR Databases also contain legacy objects which were created under different validation rules.
        In practice, there is no uniformly implemented standard for RPSL, but merely rough outlines partially documented in different places.
      </t>
      <t>
        This has the potential to create interoperability issues.
        Some are addressed by NRTMv4, like having a consistent character set when mirroring data between implementations.
        However, some issues can not be addressed in this way, such as one implementation introducing a new object class that is entirely unknown to another implementation.
      </t>
      <t>
        A mirror client SHOULD be able to handle unknown object classes and objects that are invalid according to its own validation rules, which may mean simply discarding them, without rejecting remaining objects or preventing future updates.
      </t>
      <t>
        It is RECOMMENDED for mirror clients to log these cases, particularly those where an object was discarded due to violating validation rules.
        These cases create an inconsistency between the IRR objects of the server and client, and logs facilitate later analysis.
      </t>
      <t>
        It is RECOMMENDED for mirror clients to be flexible where possible and reasonable when applying their own validation rules to IRR objects retrieved from mirror servers.
        For example, a route object with an origin attribute that is not a valid AS number can't be usefully interpreted.
        There is no way for an IRR server to correctly parse and index such an object.
        However, a route-set object whose name does not start with "RS-" <xref target="RFC2622"/>, or an inetnum with an unknown extra "org" attribute, still allows the mirror client to interpret it unambiguously even if it does not meet the mirror client's own validation rules for authoritative records.
      </t>
    </section>

    <section title="Intermediate Mirror Instances">
      <t>
        An IRR Database generally has a single authoritative source.
        In some cases, an instance run by a third party will function as a kind of intermediate: both being a mirror client, mirroring IRR objects from the authoritative source, and simultaneously function as a mirror server to yet another mirror client.
      </t>
      <t>
        There are various operational reasons for such a setup, such as the intermediate filtering certain records.
        Regardless of the reason, the mirror client and server function of an IRR server must be treated as separate processes.
        In particular, this means they MUST have separate session IDs.
        The intermediate server MUST NOT republish the same files it retrieved from the authoritative source with the same session ID.
      </t>
    </section>

    <section title="Reading from Local Files">
      <t>
        In the typical use case for NRTMv4, a mirror client retrieves files from an HTTPS endpoint.
        However, implementations MAY also support reading from files on the local filesystem instead, for when operators want to use a different method to retrieve or distribute the files.
        When reading from local files, mirror clients SHOULD still follow all validation rules, including the validation of the signature and hashes.
      </t>
    </section>

    <section title="Storage Considerations" anchor="storage">
      <t>
        After publishing a new Update Notification File, and absent local policy, a mirror server SHOULD remove any Snapshot and Delta Files that are no longer referenced.
        To avoid race conditions where a mirror client retrieves an Update Notification File moments before it is updated, mirror servers SHOULD retain unreferenced files for at least 5 minutes after a new Update Notification File is published.
      </t>
    </section>

    <section title="Public Key Rotation" anchor="public_key_rotation">
      <t>
        It is RECOMMENDED that IRR Database operators rotate the signing key on their mirror server about once per year.
        The next_signing_key field in the Update Notification File supports in-band key rotation using the following process:
      </t>
        <ul>
          <li>
            The server operator generates a new key and configures this in the mirror server implementation as the upcoming new signing key.
          </li>
          <li>
            The mirror server MUST include this key in the next_signing_key field in any Update Notification File generated while the new signing key is configured.
            Hence, the new signing key will start being propagated to the mirror clients with the next publication of the Notification File, which will take at most 24 hours.
            Mirror server implementations MAY offer a method to cause the Update Notification File to be refreshed earlier, with the new_signing_key included, and thus start the propagation earlier.
          </li>
          <li>
            When mirror clients next retrieve the Update Notification File, they MUST detect the next_signing_key field, and store the key in their configuration.
          </li>
          <li>
            After allowing mirror clients time to have seen the new Update Notification File with the next_signing_key field, the mirror server operator configures the new key as currently active key, and removes the old key.
            Any Update Notification File generated after this point MUST be signed with this new key, and will not contain a next_signing_key field.
          </li>
          <li>
            The RECOMMENDED period between publication of the upcoming key in the next_signing_key field, and removal of the old key, is one week. This offers all active clients a reasonable chance to follow the rotation process.
          </li>
          <li>
            When mirror clients retrieve an Update Notification File and find that the signature does not match, they MUST attempt to verify against a next_signing_key encountered in a previous (valid) file.
            If the signature matches for this new key, the client MUST update its configuration to use the new key for validation.
            After this, the client MUST NOT use the old key for validation at any time: a mirror server can not switch back to an old key.
          </li>
        </ul>
      <t>
        If a mirror client never retrieves an Update Notification file at any point during the rotation process, it will no longer be able to verify the signature.
        In that scenario manual recovery is required, similar to a first time configuration of a new mirror client.
      </t>
    </section>

    <section title="Scalability">
      <t>
        As NRTMv4 uses HTTPS for all file retrieval, mirror servers can use standard HTTP caching infrastructure, horizontal scaling, and CDN integration to handle load.
        Caching considerations for each file type are discussed in the respective Cache Concerns sections.
      </t>
      <t>
        Delta Files are typically small, as they only contain changes since the previous version.
        Snapshot Files can be larger, but all files may be compressed with GZIP to reduce storage and bandwidth requirements.
      </t>
    </section>

    <section title="NRTMv3 Compatibility">
      <t>
        NRTMv4 is a new protocol that is not backwards compatible with NRTMv3.
        There is no migration path between the two protocols; operators wishing to support both can run them in parallel.
      </t>
    </section>
  </section>

  <section title="IANA Considerations" anchor="IANA">
    <t>
      This document has no IANA actions.
    </t>
  </section>

  <section title="Security Considerations" anchor="security_considerations">
    <t>
      IRR objects serve many purposes, including automated network configuration and filtering.
      Manipulation of IRR objects can therefore have a significant security impact.
      However, security in existing protocols is mostly absent.
    </t>
    <t>
      Before NRTMv4, the most common protocols for IRR Database mirroring are FTP for retrieving full snapshots, and NRTM version 3 for retrieving later changes.
      There are no provisions for integrity or authenticity, and there are various scenarios where mirroring may not be reliable.
    </t>
    <t>
      NRTMv4 requires integrity verification.
      The Delta and Snapshot Files are verified using the SHA-256 hash in the Update Notification File, and the Update Notification File is verified using its signature.
      Additionally, the channel security offered by HTTPS further limits security risks.
    </t>
    <t>
      By allowing publication on any HTTPS endpoint, NRTMv4 allows for extensive scaling, and there are many existing techniques and services to protect against denial-of-service attacks.
      In contrast, NRTMv3 required mirror clients to directly query the IRR server instance with special WHOIS queries.
      This scales poorly, and there are no standard protections against denial-of-service available.
    </t>
    <t>
      The HTTPS endpoint used for NRTMv4 MUST be configured according to the best practices in <xref target="BCP195"/>.
      Mirror clients MUST NOT use other protocols than HTTPS, such as HTTP or FTP.
    </t>
  </section>

  <section title="Acknowledgments">
    <t>
      The authors would like to thank
        George Michaelson, Shon Huang, Tim Bruijnzeels, Mahesh Aggarwal, Fedor Vompe, Paul Etchells,
        and Mohamed Boucadair
      for their helpful review of this document and/or work on implementations.
    </t>
    <t>
      The authors would also like to thank
        Daniele Ceccarelli, Claudio Allocchio, Menachem Dodge, Julian Reschke, Watson Ladd and Paul Kyzivat,
      for their reviews during IETF Last Call.
    </t>
  </section>

</middle>

<back>

  <references title="Normative References">
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml-rfcsubseries/reference.STD.97.xml"/>
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.1952.xml"/>
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2622.xml"/>
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3339.xml"/>
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9562.xml"/>
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4012.xml"/>
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7464.xml"/>
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7468.xml"/>    
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7515.xml"/>
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7517.xml"/>
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml-iana/reference.IANA.jose.xml"/>
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/>
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8259.xml"/>
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml-rfcsubseries/reference.BCP.195.xml"/>
    <reference anchor="SHS" target="https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf">
      <front>
        <title>Secure Hash Standard</title>
        <author>
        <organization>National Institute of Standards and Technology</organization>
        </author>
        <date month="March" year="2012" />
      </front>
    </reference>
  </references>

  <references title="Informative References">
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5905.xml"/>
    <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8182.xml"/>

    <reference anchor="NRTMv3" target="https://docs.db.ripe.net/RIPE-Database-Mirror/Access-to-NRTM/">
      <front>
        <title>Access to NRTM (v3)</title>
        <author>
        <organization>RIPE NCC</organization>
        </author>
        <date month="July" year="2024" />
      </front>
    </reference>

  </references>

</back>

</rfc>
