- bookworm 1.5.4-1
- bookworm-backports 1.6.4+20240930-1~bpo12+1
- testing 1.6.4+20240930-1
- unstable 1.6.5-1
fort(8) | FORT validator | fort(8) |
NAME¶
fort - RPKI validator and RTR server
SYNOPSIS¶
fort [--mode=server] [OPTIONS]
fort --mode=standalone [OPTIONS]
fort --init-tals --tal=PATH
fort [-h|--help|--V|--version|--usage]
DESCRIPTION¶
Fort is an RPKI "Relying Party" (RP), an artifact that validates Route Origin Attestations (ROAs) by way of a Public Key Infrastructure (PKI). ROAs are employed by routers, to verify BGP routing attestations.
Its main input is one or more Trust Anchor Locator (TAL) files (--tal), which point to the RPKI Trust Anchors (ie. root certificates). Fort downloads all the resources governed by the trust anchors into a local cache (--local-repository), and proceeds to validate their entirety. The output of the validation is a set of VRPs (Validated ROA Payloads), which are served to routers (--mode=server, --server.address, --server.port) through the RTR protocol (RFC 6810).
OPTIONS¶
--usage
-V, --version
--init-tals
The "currently known core TALs" are
https://rpki.afrinic.net/tal/afrinic.tal
https://tal.apnic.net/apnic.tal
https://www.arin.net/resources/manage/rpki/arin.tal
https://www.lacnic.net/innovaportal/file/4983/1/lacnic.tal
https://tal.rpki.ripe.net/ripe-ncc.tal
--init-as0-tals
The "currently known AS0 TALs" are
https://tal.apnic.net/apnic-as0.tal
https://www.lacnic.net/innovaportal/file/4983/1/lacnic-as0.tal
-f, --configuration-file=FILE
The configuration options are mostly the same as the ones presented in this manual. Each property is mapped as a member of the main JSON object, the members that contain a dot '.' must be set as objects (eg. "--server.port=8323" will be set as "{ "server": { "port": "8323" } }".
An example configuration file can be seen in this manual at the EXAMPLES section.
Some configuration options can't be set at the JSON configuration file: --version, --help, --version, and --configuration-file.
Other configuration options can be configured exclusively at the JSON configuration file:
rsync.program
rsync.arguments-recursive
FORT will replace "$REMOTE" with the remote URL it needs to download, and "$LOCAL" with the target local directory where the file is supposed to be dropped.
See rsync(1) for a description of each argument.
incidences
The incidences are configured inside the member "incidences" as a JSON array of objects, each with two members "name" and "action", eg:
"incidences": [
"action": "warn"
"action": "error"
An incidence contains a name and an action. The name is merely an identifier defined by FORT that states a particular error condition, and the action is an enumeration that states the outcome of a violation of the corresponding incidence.
The action can have one of three values:
warn: Print error message in warning log level, continue validation as if nothing happened.
ignore: Do not print error message, continue validation as if nothing happened.
Currently these are the registered incidences, each with a distinct action configured by default.
incid-hashalg-has-params (Signed Object's hash algorithm has NULL object as parameters). [Default action: ignore]
incid-obj-not-der-encoded (Object isn't DER encoded). [Default action: ignore]
incid-file-at-mft-not-found (File listed at manifest doesn't exist). [Default action: error]
incid-file-at-mft-hash-not-match (File hash listed at manifest doesn't match the actual file hash). [Default action: error]
incid-mft-stale (Manifest is stale). [Default action: error]
incid-crl-stale (CRL is stale). [Default action: error]
More information about incidences can be consulted at FORT's web docs.
-t, --tal=(FILE|DIRECTORY)
The TAL ("Trust Anchor Locator") is a text file that lists a few URLs which can be used to access the "Trust Anchor" (the root of a particular RPKI tree) and its public key. (See RFC 8630.)
-r, --local-repository=DIRECTORY
FORT accesses RPKI repositories either with rsync or RRDP (see RFC 8182). During each validation cycle, and depending on the preferred access methods defined by the CAs, Fort can do two things:
- Literally invoke an rsync command (see rsync.program and rsync.arguments-recursive), which will download the files into --local-repository.
- Fetch the RRDP Update Notification file (which implies an HTTP request) and fetch the files from there on (can be obtained from a Snapshot file or Delta files). The files will be downloaed into --local-repository.
Fort's entire validation process operates on the resulting copy of the files (doesn't matter if the files where fetched by rsync of https).
Because rsync uses delta encoding, you’re advised to keep this cache around. It significantly speeds up subsequent validation cycles.
By default, the path is /var/lib/fort.
--daemon
All the enabled logs will be sent to syslog, so the configured values of --log.output and --validation-log.output will be ignored.
--work-offline
Otherwise, Fort will perform outgoing requests whenever this is needed. If a specific protocol needs to be deactivated, use --rsync.enabled or --http.enabled.
--maximum-certificate-depth=UNSIGNED_INTEGER
By default, it has a value of 32. The minimum allowed value is 5.
(Required to prevent loops and "other degenerate forms of the logical RPKI hierarchy." (RFC 6481))
--slurm=(FILE|DIRECTORY)
The SLURM definition is from RFC 8416. SLURM stands for "Simplified Local Internet Number Resource Management with the RPKI", basically is a document that can override (either as a filter or adding assertions) the global RPKI repository data fetched by FORT; potentially useful for network operators.
In case a DIRECTORY is set, the files with extension '.slurm' will be the ones considered as SLURM files and FORT will use them.
The configured SLURM path (either FILE or DIRECTORY) will be read each time a new validation cycle begins. If there's a syntax or content error, the last valid version of the SLURM will be applied (if there's one) and a message will be logged to indicate this action. Note that all this will happen only if --mode=server and --slurm is configured.
A basic example of a SLURM file can be seen in this manual at the EXAMPLES section (it's almost the same as the one in RFC 8416).
See more about SLURM configuration at FORT's web docs.
--mode=(server|standalone|print)
server (Default)
standalone
--server.address=NODE(S)
The address list must be comma-separated, and each address must have the following format: <address>[#<port>]. The port defaults to --server.port.
Here are some examples:
- --server.address="localhost": Bind to localhost, port
--server.port.
- --server.address="localhost, ::1#8324": Same as above, and
also bind to [::1]:8324.
- --server.address="localhost#8323, ::1#8324": Bind to
localhost on port 8323, and to [::1]:8324.
(--server.port is ignored.)
Use wildcards to bind to all available addresses. Note that, for historical reasons, Linux is a bit strange:
BSDs:
- 0.0.0.0 : Bind to all available IPv4 addresses
- :: : Bind to all available IPv6 addresses
- 0.0.0.0, :: : Bind to all available IPv4 and IPv6 addresses
Linux:
- 0.0.0.0 : Bind to all available IPv4 addresses
- :: : Bind to all available IPv4 and IPv6 addresses
- 0.0.0.0, :: : Error
--server.port=SERVICE
This is a string because a service alias can be used as a valid value. The alias are commonly located at /etc/services. See also getaddrinfo(3) and services(5).
The default port (323) is privileged. To improve security, either change or jail it.
The default fort-validator.service configuration sets the CAP_NET_BIND_SERVICE capability to allow the unprivileged daemon to bind port 323 anyway.
--server.backlog=UNSIGNED_INTEGER
By default, it has a value of SOMAXCONN.
--server.interval.validation=UNSIGNED_INTEGER
By default, it has a value of 3600.
--server.interval.refresh=UNSIGNED_INTEGER
This value is utilized only on RTR version 1 sessions (more information at RFC 8210 section 6).
By default, it has a value of 3600. Minimum allowed value: 1, maximum allowed value 86400.
--server.interval.retry=UNSIGNED_INTEGER
This value is utilized only on RTR version 1 sessions (more information at RFC 8210 section 6).
By default, it has a value of 600. Minimum allowed value: 1, maximum allowed value 7200.
--server.interval.expire=UNSIGNED_INTEGER
This value is utilized only on RTR version 1 sessions (more information at RFC 8210 section 6).
By default, it has a value of 7200. Minimum allowed value: 600, maximum allowed value 172800. It must be larger than server.interval.refresh and server.interval.retry.
--server.deltas.lifetime=UNSIGNED_INTEGER
During each validation cycle, Fort generates a new snapshot, as well as the deltas needed to build the new snapshot from the previous one. These are all stored in RAM. --server.deltas.lifetime is the number of iterations a set of deltas will be kept before being deallocated. (Recall that every iteration lasts --server.interval.validation seconds, plus however long the validation takes.)
If a router lags behind, to the point Fort has already deleted the deltas it needs to update the router’s snapshot, Fort will have to fall back to fetch the entire latest snapshot instead.
--log.enabled=true|false
By default, it has a value of true (these logs are enabled).
Read more about logs at FORT validator's web docs, module 'Logging'.
--log.level=(error|warning|info|debug)
The priority levels, from higher to lowest, are:
- error
- warning
- info
- debug
By default, it has a value of warning.
Read more about logs at FORT validator's web docs, module 'Logging'.
--log.output=(syslog|console)
The value console will log messages at standard output and standard error; syslog will log to syslog.
Depending on the OS, distinct implementations of syslog could be installed (syslog, rsyslog, or syslog-ng are the most common ones). Syslog usage and configuration is out of this man scope.
By default, it has a value of console.
Read more about logs at FORT validator's web docs, module 'Logging'.
-c, --log.color-output=true|false
Meaningful only if --log.output value is console.
By default, it has a value of false (it's disabled).
Read more about logs at FORT validator's web docs, module 'Logging'.
--log.file-name-format=(global-url | local-path | file-name)
Suppose a certificate was downloaded from `rsync://rpki.example.com/foo/bar/baz.cer` into the local cache `repository/`:
global-url
local-path
file-name
By default, it has a value of global-url.
Read more about logs at FORT validator's web docs, module 'Logging'.
--log.facility=(auth | authpriv | cron | daemon | ftp | lpr | mail | news | user | uucp | from local0 to local7)
By default, it has a value of daemon.
Read more about logs at FORT validator's web docs, module 'Logging'.
--log.tag=STRING
By default, it has a NULL value.
Read more about logs at FORT validator's web docs, module 'Logging'.
--validation-log.enabled=true|false
By default, it has a value of false (these logs are disabled).
Read more about logs at FORT validator's web docs, module 'Logging'.
--validation-log.level=(error|warning|info|debug)
The priority levels, from higher to lowest, are:
- error
- warning
- info
- debug
By default, it has a value of warning.
Read more about logs at FORT validator's web docs, module 'Logging'.
--validation-log.output=(syslog|console)
The value console will log messages at standard output and standard error; syslog will log to syslog.
Depending on the OS, distinct implementations of syslog could be installed (syslog, rsyslog, or syslog-ng are the most common ones). Syslog usage and configuration is out of this man scope.
By default, it has a value of console.
Read more about logs at FORT validator's web docs, module 'Logging'.
-c, --validation-log.color-output=true|false
Meaningful only if --validation-log.output value is console.
By default, it has a value of false (it's disabled).
Read more about logs at FORT validator's web docs, module 'Logging'.
--validation-log.file-name-format=(global-url | local-path | file-name)
Suppose a certificate was downloaded from `rsync://rpki.example.com/foo/bar/baz.cer` into the local cache `repository/`:
global-url
local-path
file-name
By default, it has a value of global-url.
Read more about logs at FORT validator's web docs, module 'Logging'.
--validation-log.facility=(auth | authpriv | cron | daemon | ftp | lpr | mail | news | user | uucp | from local0 to local7)
By default, it has a value of daemon.
Read more about logs at FORT validator's web docs, module 'Logging'.
--validation-log.tag=STRING
By default, it has the value Validation.
Read more about logs at FORT validator's web docs, module 'Logging'.
--http.enabled=true|false
If disabled (eg. --http.enabled=false), FORT validator won't request HTTP URIs, and will expect to find all the corresponding repository files at --local-repository.
--http.priority=UNSIGNED_INTEGER
This argument works along with --rsync.priority, since the higher value of the two arguments will result in the first protocol to utilize when fetching repositories files. Of course, this depends also on certificates information or the TAL URIs, since currently HTTP URIs are optional and not every RIR repository makes use of them.
Whenever a certificate or a TAL has both RSYNC and HTTP URIs, the following criteria is followed to prioritize which one to use first:
- --rsync.priority equals --http.priority: use the order specified at the certificate or the TAL to fetch the corresponding URI.
- --rsync.priority greater than --http.priority: use RSYNC repository/TAL URI first; if there's an error fetching data, fallback to fetch HTTP repository/TAL URI.
- --rsync.priority less than --http.priority: use HTTP repository/TAL URI first; if there's an error fetching data, fallback to use RSYNC repository/TAL URI.
By default, the value is 60, so HTTP requests are preferred over rsync requests.
--http.retry.count=UNSIGNED_INTEGER
A value of 0 means no retries.
Whenever is necessary to request an HTTP URI, the validator will try the request at least once. If there was an error requesting the URI, the validator will retry at most --http.retry.count times to fetch the file, waiting --http.retry.interval seconds between each retry.
By default, the value is 4.
--http.retry.interval=UNSIGNED_INTEGER
By default, the value is 5.
--http.user-agent=STRING
The value specified (either by the argument or the default value) is utilized in libcurl’s option CURLOPT_USERAGENT.
By default, the value is fort/<current-version>.
--http.connect-timeout=UNSIGNED_INTEGER
Whenever an HTTP connection will try to be established, the validator will wait a maximum of http.connect-timeout seconds for the peer to respond to the connection request; if the timeout is reached, the connection attempt will be ceased.
The value specified (either by the argument or the default value) is utilized in libcurl’s option CURLOPT_CONNECTTIMEOUT.
By default, it has a value of 30. The minimum allowed value is 1.
--http.transfer-timeout=UNSIGNED_INTEGER
Once the connection is established with the server, the request will last a maximum of http.transfer-timeout seconds. A value of 0 means unlimited time (default value).
The value specified (either by the argument or the default value) is utilized in libcurl’s option CURLOPT_TIMEOUT.
By default, it has a value of 900.
--low-speed-limit=UNSIGNED_INTEGER
"Abort connection if slower than LIMIT bytes/sec during TIME seconds."
(See --low-speed-time.)
Default: 100000 (100 KB/s)
--low-speed-time=UNSIGNED_INTEGER
"Abort connection if slower than LIMIT bytes/sec during TIME seconds."
(See --low-speed-limit.)
Default: 10
--http.max-file-size=UNSIGNED_INTEGER
Default: 1000000000 (1 GB)
--http.ca-path=DIRECTORY
Useful when the CA from the peer isn’t located at the default OS certificate bundle. If specified, the peer certificate will be verified using the CAs at the path. The directory MUST be prepared using the rehash utility from the SSL library:
- OpenSSL command (with help): $ openssl rehash -h
- LibreSSL command (with help): $ openssl certhash -h
The value specified is utilized in libcurl’s option CURLOPT_CAPATH.
By default, the path has a NULL value.
--rsync.enabled=true|false
If disabled (eg. --rsync.enabled=false), FORT validator won't download files nor directories via RSYNC, and will expect to find all repository files at --local-repository.
--rsync.priority=UNSIGNED_INTEGER
This argument works along with --http.priority, since the higher value of the two arguments will result in the first protocol to utilize when fetching repositories files. Of course, this depends also on certificates information or the TAL URIs, since currently HTTP URIs are optional and not every RIR repository makes use of them.
Whenever a certificate has both RSYNC and HTTP URIs, the following criteria is followed to prioritize which one to use first:
- --rsync.priority equals --http.priority: use the order specified at the certificate or the TAL to fetch the corresponding URI.
- --rsync.priority greater than --http.priority: use RSYNC repository/TAL URI first; if there's an error fetching data, fallback to use fetch HTTP repository/TAL URI.
- --rsync.priority less than --http.priority: use HTTP repository/TAL URI first; if there's an error fetching data, fallback to use RSYNC repository/TAL URI.
By default, the value is 50, so HTTP requests are preferred over rsync requests.
--rsync.retry.count=UNSIGNED_INTEGER
A value of 0 means no retries.
Whenever is necessary to execute an RSYNC, the validator will try the execution at least once. If there was an error executing the RSYNC, the validator will retry it at most --rsync.retry.count times, waiting --rsync.retry.interval seconds between each retry.
By default, the value is 4.
--rsync.retry.interval=UNSIGNED_INTEGER
By default, the value is 5.
--rsync.transfer-timeout=UNSIGNED_INTEGER
Once the connection is established with the server, the request will last a maximum of rsync.transfer-timeout seconds. A value of 0 means unlimited time (default value).
By default, it has a value of 900.
--output.roa=FILE
When the FILE is specified, its content will be overwritten by the resulting ROAs of the validation (if FILE doesn't exists, it'll be created).
When --output.format=csv (which is the default value), then each line of the result is printed in the following order: AS, Prefix, Max prefix length; the first line contains those column descriptors.
When --output.format=json, then each element is printed inside an object array of "roas"; ie:
{
"roas": [
{
"asn": "AS64496",
"prefix": "198.51.100.0/24",
"maxLength": 24
},
{
"asn": "AS64496",
"prefix": "2001:DB8::/32",
"maxLength": 48
}
] }
In order to print the ROAs at console, use a hyphen as the FILE value, eg. --output.roa=-
By default, it has no value set.
--output.bgpsec=FILE
Since most of the data is binary (Subject Key Identifier and Subject Public Key Info), such data is base64url encoded without trailing pads.
When the FILE is specified, its content will be overwritten by the resulting Router Keys of the validation (if FILE doesn't exists, it'll be created).
When --output.format=csv (which is the default value), then each line of the result is printed in the following order: AS, Subject Key Identifier, Subject Public Key Info; the first line contains those column descriptors.
When --output.format=json, then each element is printed inside an object array of "router-keys"; ie:
{
"router-keys": [
{
"asn": "AS64496",
"ski": "<Base64 Encoded SKI>",
"spki": "<Base64 Encoded SPKI>"
},
{
"asn": "AS64496",
"ski": "<Base64 Encoded SKI>",
"spki": "<Base64 Encoded SPKI>"
}
] }
In order to print the Router Keys at console, use a hyphen as the FILE value, eg. --output.bgpsec=-
By default, it has no value set.
--output.format=csv|json
By default, it has a value of csv.
--thread-pool.server.max=UNSIGNED_INTEGER
Minimum: 1
Maximum: UINT_MAX
Default: 20
--asn1-decode-max-stack=UNSIGNED_INTEGER
By default, it has a value of 4096 (4 kB).
EXAMPLES¶
fort --init-tals --tal=/tmp/tal
fort -t /etc/tals -r /var/lib/fort --server.port=9323
fort -t /etc/tals -r /var/lib/fort --mode=standalone --output.roa=-
fort -t /etc/tals -r /var/lib/fort \
--mode=standalone \
--slurm=/etc/fort/slurm/
fort --configuration-file=conf.json
fort -t /etc/tals -r /var/lib/fort \
--server.address=::1 --server.port=9323 \
--server.interval.validation=1800 \
--output.roa=/var/lib/fort/roas.csv
Complete configuration file
{
"tal": "/etc/tals/",
"local-repository": "/var/lib/fort/",
"maximum-certificate-depth": 32,
"slurm": "/etc/fort/slurm/",
"mode": "server",
"work-offline": false,
"daemon": false,
"server": {
"address": [
"192.0.2.1",
"2001:db8::1"
],
"port": "8323",
"backlog": 4096,
"interval": {
"validation": 3600,
"refresh": 3600,
"retry": 600,
"expire": 7200
},
"deltas": {
"lifetime": 2
}
},
"rsync": {
"enabled": true,
"priority": 50,
"retry": {
"count": 1,
"interval": 4
},
"transfer-timeout": 900,
"program": "rsync",
"arguments-recursive": [
"-rtz",
"--delete",
"--omit-dir-times",
"--contimeout=20",
"--max-size=20MB",
"--timeout=15",
"--include=*/",
"--include=*.cer",
"--include=*.crl",
"--include=*.gbr",
"--include=*.mft",
"--include=*.roa",
"--exclude=*",
"$REMOTE",
"$LOCAL"
]
},
"http": {
"enabled": true,
"priority": 60,
"retry": {
"count": 1,
"interval": 4
},
"user-agent": "fort/1.6.4",
"max-redirs": 10,
"connect-timeout": 30,
"transfer-timeout": 900,
"low-speed-limit": 100000,
"low-speed-time": 10,
"max-file-size": 1000000000,
"ca-path": "/etc/ssl/certs"
},
"log": {
"enabled": true,
"output": "console",
"level": "warning",
"tag": "Op",
"facility": "daemon",
"file-name-format": "global-url",
"color-output": false
},
"validation-log": {
"enabled": false,
"output": "console",
"level": "warning",
"tag": "Validation",
"facility": "daemon",
"file-name-format": "global-url",
"color-output": false
},
"incidences": [
{
"name": "incid-hashalg-has-params",
"action": "ignore"
}, {
"name": "incid-obj-not-der-encoded",
"action": "ignore"
}, {
"name": "incid-file-at-mft-not-found",
"action": "error"
}, {
"name": "incid-file-at-mft-hash-not-match",
"action": "error"
}, {
"name": "incid-mft-stale",
"action": "error"
}, {
"name": "incid-crl-stale",
"action": "error"
}
],
"output": {
"roa": "/var/lib/fort/roas.csv",
"bgpsec": "/var/lib/fort/bgpsec.csv",
"format": "csv"
},
"asn1-decode-max-stack": 4096,
"thread-pool": {
"server": {
"max": 20
}
} }
Dummy SLURM file
{
"slurmVersion": 1,
"validationOutputFilters": {
"prefixFilters": [
{
"prefix": "192.0.2.0/24",
"comment": "All VRPs encompassed by prefix"
},
{
"asn": 64496,
"comment": "All VRPs matching ASN"
},
{
"prefix": "198.51.100.0/24",
"asn": 64497,
"comment": "All VRPs encompassed by prefix, matching ASN"
}
],
"bgpsecFilters": [
{
"asn": 64496,
"comment": "All keys for ASN"
},
{
"SKI": "Q8KMeBsCto1PJ6EuhowleIGNL7A",
"comment": "Key matching Router SKI"
},
{
"asn": 64497,
"SKI": "g5RQYCnkMpDqEbt9WazTeB19nZs",
"comment": "Key for ASN 64497 matching Router SKI"
}
]
},
"locallyAddedAssertions": {
"prefixAssertions": [
{
"asn": 64496,
"prefix": "198.51.100.0/24",
"comment": "My other important route"
},
{
"asn": 64496,
"prefix": "2001:DB8::/32",
"maxPrefixLength": 48,
"comment": "My other important de-aggregated routes"
}
],
"bgpsecAssertions": [
{
"asn": 64496,
"SKI": "Dulqji-sUM5sX5M-3mqngKaFDjE",
"routerPublicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE-rkSLXlPpL_m-L7CfCfKrv1FHrM55FsIc8fMlnjHE6Y5nTuCn3UgWfCV6sYuGUZzPZ0Ey6AvezmfcELUB87eBA"
}
]
} }
SEE ALSO¶
2024-12-18 | v1.6.5 |