Caps the maximum RTR version the server will be willing to serve.
Defaults to 0 because the RTRv1 implementation still doesn't do
anything useful, and the RTRv2 implementation is transient.
(They're still tweaking the RTRv2 spec.)
Also fixes a couple of bugs:
- Was not closing the connection when returning internal error PDUs
- Some error reports before the version validation would erroneously
indicate v255 in the header
PDU parsing has been done by the poller up to this point.
I probably intended this to encapsulate all the stream operations in
the poller.
During 4e0f81dd5405f8c6c48d2e74c0468d16b44f9a50, the poller's block of
code that contained PDU parsing had to be moved to the mutex time.
This created a substantial incentive to migrate PDU parsing out of the
poller.
So now it's done by the RTR server threads instead.
If Fort decides to abandon a client because of misbehavior, it will
finish handling the current request (if there is one), cancel all
subsequent queued requests, and terminate the connection.
It's a temporal hack; not safe because of the multithreading.
It's meant to be enabled during the controlled environment of Rapport
tests, and nowhere else.
Compile with -DOVERRIDE_SIGTERM to enable.
> Relying Party implementations are RECOMMENDED to impose an upper
> bound on the number of Provider ASes for a given CAS.
> (...) an error SHOULD be logged in the
> local system, indicating the CAS for which the threshold was
> exceeded.
Remove RTR request session vs negotiated session check
I complained about this on sidrops:
https://mailarchive.ietf.org/arch/msg/sidrops/IqvFzvZcSkBN_9gQAwUKAJtIRko/
The hack was too horrid, so I decided to remove it, at least for this
release.
The request session is now only compared to the cache session.
Fort does not care whether the client sustains a constant session.
As long as it's a valid cached session, it's fine. It can ask for many
sessions if it wants.
In practice, all this means is the Corrupt Data is switched for a
Cache Reset.
Whatever. The client will be none the wiser, and the end result will be
the same (a new Cache Request).
It used to be caching incremental deltas between RTR serials.
Then, because the only thing that matters in the end is the net delta
between the router's serial and the latest, it was building up the net
delta from the incremental ones.
The complexity was O(n^2), where n is the total VRPs + RKs + ASPAs
across all involved incremental deltas. Under normal load, n seems to
tend to be small. But that's asking for trouble. Also, the algorithm
also had to allocate n objects, which is rather excessive for a Serial
Query handler.
There was also the issue that all the RTR data was cached in RAM,
which means the RTR session had to change every time Fort was
restarted. And this memory usage wasn't terribly insignificant.
And also, computing a net delta from incremental ASPAs is awkward.
Because ASPAs that share customerAS are supposed to override each other,
they cancel out differently from VRPs.
So I ended up rewriting the entire RTR session caching code.
The Serial Query handler now computes net deltas from RTR snapshots.
The snapshots are stored in the cache, not RAM.
Complexity is O(m), where m is the total VRPs + RKs + ASPAs of the two
relevant snapshots. So m tends to be large, but it degrades much
healthier. The handler also allocates very little memory.
Job Snijders [Sat, 16 May 2026 14:41:47 +0000 (14:41 +0000)]
Exclude hidden files and directories when synchronizing via Rsync
According to RFC 9286 section 4.2.2, filenames in the RPKI cannot start
with a dot. And RFC 6481 section 1.1 describes the concept of a publication
point as a "directory in a publicly accessible filesystem". From there it
follows there is no need to transfer hidden files and directories. This may
help in avoiding exposure to intermediate states (e.g., /a/.~tmp~/b.roa).
It's a temporal hack; not safe because of the multithreading.
It's meant to be enabled during the controlled environment of Rapport
tests, and nowhere else.
Compile with -DOVERRIDE_SIGTERM to enable.
Do not delete RPP files if snapshot is already exploded
There are situations in which the code might find itself attempting
to explode a snapshot a second time during a validation run.
The code was noticing this, and thus skipping the second download.
But by then, the cached files were already deleted. Which resulted
in the validation code receiving zero files as input.
In general, the openmetrics Content-Type is preferred. The code makes
an exception out of browsers, however.
The full logic is
- If the request has no Accept header, Content-Type will be openmetrics
1.0.0.
- If the Accept header expects neither openmetrics nor plaintext,
Content-Type will be plaintext 0.0.4.
This is because the client is usually a browser (which seem to typically
lack Openmetrics handlers) or a generic HTTP client like curl (which
don't really care about Content-Type).
- Otherwise Fort will decide between openmetrics 1.0.0 or plaintext
0.0.4, depending on q-values. (Requested version will be ignored,
because only one is supported for each.) If their q is the same,
openmetrics will be preferred.
fort_valid_vrps_total{ta="<TA>",proto="ipv<IP>"}
Total VRPs generated from TA <TA> (and the given
protocol) during the previous cycle.
"<TA>" is inferred from the TAL's file name.
fort_rtr_current_connections
Number of active RTR clients.
To activate the server, set --mode=server and --prometheus.port to an
allowed and available port number.
Stop rejecting RPPs if unrecognizable absent files are fileListed
RFC 9286:
> The RP MUST acquire all of the files enumerated in the manifest
> (fileList) from the publication point. If there are files listed in
> the manifest that cannot be retrieved from the publication point,
> the RP MUST treat this as a failed fetch.
This was clashing with Fort's default rsync filters because they were
preventing unknown extensions from being downloaded:
Which will be a problem whenever the IETF defines new legal repository
extensions, such as .asa.
Therefore, ignore unknown manifest fileList extensions. This technically
violates RFC 9286, but it's necessary evil given that we can't trust
repositories to always only serve proper RPKI content.