{"id":13582313,"url":"https://github.com/cloudflare/gortr","last_synced_at":"2025-04-06T14:30:44.032Z","repository":{"id":50605642,"uuid":"143472418","full_name":"cloudflare/gortr","owner":"cloudflare","description":"The RPKI-to-Router server used at Cloudflare","archived":true,"fork":false,"pushed_at":"2024-02-29T15:14:39.000Z","size":9212,"stargazers_count":311,"open_issues_count":29,"forks_count":41,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-01-15T00:31:50.812Z","etag":null,"topics":["bgp","cisco","cloudflare","cryptography","juniper","prometheus","rpki","security"],"latest_commit_sha":null,"homepage":"https://rpki.cloudflare.com","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloudflare.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-08-03T20:53:04.000Z","updated_at":"2024-12-04T08:41:22.000Z","dependencies_parsed_at":"2024-01-19T08:12:51.935Z","dependency_job_id":"6086a618-c4f8-4ead-89b9-3c3ad59f4f48","html_url":"https://github.com/cloudflare/gortr","commit_stats":null,"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflare%2Fgortr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflare%2Fgortr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflare%2Fgortr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflare%2Fgortr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloudflare","download_url":"https://codeload.github.com/cloudflare/gortr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247495670,"owners_count":20948093,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bgp","cisco","cloudflare","cryptography","juniper","prometheus","rpki","security"],"created_at":"2024-08-01T15:02:35.458Z","updated_at":"2025-04-06T14:30:42.968Z","avatar_url":"https://github.com/cloudflare.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# GoRTR\n\n## DEPRECATION NOTICE\n**This software is no longer maintained. We advise replacing your production use of this software with the swap-in replacement [StayRTR](https://github.com/bgp/stayrtr)**\n\n[![Build Status](https://github.com/cloudflare/gortr/workflows/Go/badge.svg)](https://github.com/cloudflare/gortr/actions?query=workflow%3AGo)\n[![GoDoc](https://godoc.org/github.com/cloudflare/gortr?status.svg)](https://pkg.go.dev/github.com/cloudflare/gortr)\n![GitHub release (latest by date)](https://img.shields.io/github/v/release/cloudflare/gortr)\n\nGoRTR is an open-source implementation of RPKI to Router protocol (RFC 6810) using the [the Go Programming Language](http://golang.org/).\n\n* `/lib` contains a library to create your own server and client.\n* `/prefixfile` contains the structure of a JSON export file and signing capabilities.\n* `/cmd/gortr/gortr.go` is a simple implementation that fetches a list and offers it to a router.\n* `/cmd/rtrdump/rtrdump.go` allows copying the PDUs sent by a RTR server as a JSON file.\n* `/cmd/rtrmon/rtrmon.go` compare and monitor two RTR servers (using RTR and/or JSON), outputs diff and Prometheus metrics.\n\n## Disclaimer\n\n_This software comes with no warranty._\n\n## In the field\n\n\u003cimg align=\"left\" src=\"docs/images/cloudflare.png\" alt=\"Cloudflare\" width=\"200px\"\u003e\n\n_Cloudflare operates 200+ GoRTR globally. They provide redundancy in at the PoP level.\nThis provides increased reliability by computing a unique prefix list and providing\na secure distribution of the file over its CDN before being sent to the routers._\n\n_GoRTR also powers the public RTR server available on rtr.rpki.cloudflare.com on port 8282 and 8283 for SSH (rpki/rpki)_\n\n\u003cbr\u003e\n\n\u003cimg align=\"left\" src=\"docs/images/telia.png\" alt=\"Telia\" width=\"200px\"\u003e\n\n_Telia has deployed RPKI and uses GoRTR connected with OctoRPKI and rpki-client to distribute the ROAs to its routers.\nInstances of the RTR servers handle around 250 sessions each._\n\n\u003cbr\u003e\n\n\u003cimg align=\"left\" src=\"docs/images/ntt.png\" alt=\"NTT\" width=\"150px\"\u003e\n\n_NTT has deployed OpenBSD's rpki-client together with GoRTR to facilitate rejecting RPKI Invalid BGP route announcements\ntowards it's Global IP Network (AS 2914). More information is available [here](https://www.us.ntt.net/support/policy/rr.cfm#RPKI)._\n\n\u003cbr\u003e\n\n\u003cimg align=\"left\" src=\"docs/images/gtt.png\" alt=\"GTT\" width=\"100px\"\u003e\n\n_GTT deployed GoRTR along with OctoRPKI. The setup currently provides 400+ RTR sessions to their routers for filtering\nRPKI invalids._\n\n\u003cbr\u003e\n\n\u003cimg align=\"left\" src=\"docs/images/cogent.png\" alt=\"Cogent\" width=\"150px\"\u003e\n\n_Cogent deployed GoRTR and OctoRPKI at the end of May 2020. 8 validators feed approximately 2500 routers._\n\n\u003cbr\u003e\n\nRouter vendors also used this software to develop their implementations.\n\n_Do you use this tool at scale? Let us know!_\n\n## Features of the server\n\n* Refreshes a JSON list of prefixes (from either Cloudflare or a RIPE Validator)\n* Prometheus metrics\n* Lightweight\n* TLS\n* SSH\n* Signature verification and expiration control\n\n## Features of the extractor\n\n* Generate a list of prefixes sent via RTR (similar to Cloudflare JSON input, or RIPE RPKI Validator)\n* Lightweight\n* TLS\n* SSH\n\n## Features of the API\n\n* Protocol v0 of [RFC6810](https://tools.ietf.org/html/rfc6810)\n* Protocol v1 of [RFC8210](https://tools.ietf.org/html/rfc8210)\n* Event-driven API\n* TLS\n* SSH\n\n## To start developing\n\nYou need a working [Go environment](https://golang.org/doc/install) (1.10 or newer).\nThis project also uses [Go Modules](https://github.com/golang/go/wiki/Modules).\n\n```bash\n$ git clone git@github.com:cloudflare/gortr.git \u0026\u0026 cd gortr\n$ go build cmd/gortr/gortr.go\n```\n\n## With Docker\n\nIf you do not want to use Docker, please go to the next section.\n\nIf you have **Docker**, you can start GoRTR with `docker run -ti -p 8082:8082 cloudflare/gortr`.\nThe containers contain Cloudflare's public signing key and an testing ECDSA private\nkey for the SSH server.\n\nIt will automatically download Cloudflare's prefix list and use the public key\nto validate it.\n\nYou can now use any CLI attributes as long as they are after the image name:\n\n```bash\n$ docker run -ti -p 8083:8083 cloudflare/gortr -bind :8083\n```\n\nIf you want to build your own image of GoRTR:\n\n```bash\n$ docker build -t mygortr -f Dockerfile.gortr.prod .\n$ docker run -ti mygortr -h\n```\n\nIt will download the code from GitHub and compile it with Go and also generate an ECDSA key for SSH.\n\nPlease note: if you plan to use SSH with Cloudflare's default container (`cloudflare/gortr`),\nreplace the key `private.pem` since it is a testing key that has been published.\nAn example is given below:\n\n```bash\n$ docker run -ti -v $PWD/mynewkey.pem:/private.pem cloudflare/gortr -ssh.bind :8083\n```\n\n## Install it\n\nThere are a few solutions to install it.\n\nGo can directly fetch it from the source\n\n```bash\n$ go get github.com/cloudflare/gortr/cmd/gortr\n```\n\nCopy `cf.pub` to your local directory if you want to use Cloudflare's signed JSON file.\n\nYou can use the Makefile (by default it will be compiled for Linux, add `GOOS=darwin` for Mac)\n\n```bash\n$ make dist-key build-gortr\n```\n\nThe compiled file will be in `/dist`.\n\nOr you can use a package (or binary) file from the [Releases page](https://github.com/cloudflare/gortr/releases):\n\n```bash\n$ sudo dpkg -i gortr[...].deb\n$ sudo systemctl start gortr\n```\n\nIf you want to sign your list of prefixes, generate an ECDSA key.\nThen generate the public key to be used in GoRTR.\nYou will have to setup your validator to use this key or have another\ntool to sign the JSON file before passing it to GoRTR.\n\n```bash\n$ openssl ecparam -genkey -name prime256v1 -noout -outform pem \u003e private.pem\n$ openssl ec -in private.pem -pubout -outform pem \u003e public.pem\n```\n\n## Run it\n\nOnce you have a binary:\n\n```bash\n$ ./gortr -tls.bind 127.0.0.1:8282\n```\n\nMake sure cf.pub is in the current directory. Or pass `-verify.key=path/to/cf.pub`\n\n## Package it\n\nIf you want to package it (deb/rpm), you can use the pre-built docker-compose file.\n\n```bash\n$ docker-compose -f docker-compose-pkg.yml up\n```\n\nYou can find both files in the `dist/` directory.\n\n### Usage with a proxy\n\nThis was tested with a basic Squid proxy. The `User-Agent` header is passed\nin the CONNECT.\n\nYou have to export the following two variables in order for GoRTR to use the proxy.\n\n```\nexport HTTP_PROXY=schema://host:port\nexport HTTPS_PROXY=schema://host:port\n```\n\n### With SSL\n\nYou can run GoRTR and listen for TLS connections only (just pass `-bind \"\"`).\n\nFirst, you will have to create a SSL certificate.\n\n```bash\n$ openssl ecparam -genkey -name prime256v1 -noout -outform pem \u003e private.pem\n$ openssl req -new -x509 -key private.pem -out server.pem\n```\n\nThen, you have to run\n\n```bash\n$ ./gortr -ssh.bind :8282 -tls.key private.pem -tls.cert server.pem\n```\n\n### With SSH\n\nYou can run GoRTR and listen for SSH connections only (just pass `-bind \"\"`).\n\nYou will have to create an ECDSA key. You can use the following command:\n\n```bash\n$ openssl ecparam -genkey -name prime256v1 -noout -outform pem \u003e private.pem\n```\n\nThen you can start:\n\n```bash\n$ ./gortr -ssh.bind :8282 -ssh.key private.pem -bind \"\"\n```\n\nBy default, there is no authentication.\n\nYou can use password and key authentication:\n\nFor example, to configure user **rpki** and password **rpki**:\n\n```bash\n$ ./gortr -ssh.bind :8282 -ssh.key private.pem -ssh.method.password=true -ssh.auth.user rpki -ssh.auth.password rpki -bind \"\"\n```\n\nAnd to configure a bypass for every SSH key:\n\n```bash\n$ ./gortr -ssh.bind :8282 -ssh.key private.pem -ssh.method.key=true -ssh.auth.key.bypass=true -bind \"\"\n```\n\n## Configure filters and overrides (SLURM)\n\nGoRTR supports SLURM configuration files ([RFC8416](https://tools.ietf.org/html/rfc8416)).\n\nCreate a json file (`slurm.json`):\n\n```\n{\n    \"slurmVersion\": 1,\n    \"validationOutputFilters\": {\n     \"prefixFilters\": [\n       {\n        \"prefix\": \"10.0.0.0/8\",\n        \"comment\": \"Everything inside will be removed\"\n       },\n       {\n        \"asn\": 65001,\n       },\n       {\n        \"asn\": 65002,\n        \"prefix\": \"192.168.0.0/24\",\n       },\n     ],\n     \"bgpsecFilters\": []\n    },\n    \"locallyAddedAssertions\": {\n     \"prefixAssertions\": [\n       {\n        \"asn\": 65001,\n        \"prefix\": \"2001:db8::/32\",\n        \"maxPrefixLength\": 48,\n        \"comment\": \"Manual add\"\n       }\n     ],\n     \"bgpsecAssertions\": [\n     ]\n    }\n  }\n```\n\nWhen starting GoRTR, add the `-slurm ./slurm.json` argument.\n\nThe log should display something similar to the following:\n\n```\nINFO[0001] Slurm filtering: 112214 kept, 159 removed, 1 asserted\nINFO[0002] New update (112215 uniques, 112215 total prefixes).\n```\n\nFor instance, if the original JSON fetched contains the ROA: `10.0.0.0/24-24 AS65001`,\nit will be removed.\n\nThe JSON exported by GoRTR will contain the overrides and the file can be signed again.\nOthers GoRTR can be configured to fetch the ROAs from the filtering GoRTR:\nthe operator manages one SLURM file on a leader GoRTR.\n\n## Debug the content\n\nYou can check the content provided over RTR with rtrdump tool\n\n```bash\n$ ./rtrdump -connect 127.0.0.1:8282 -file debug.json\n```\n\nYou can also fetch the re-generated JSON from the `-export.path` endpoint (default: `http://localhost:8080/rpki.json`)\n\n### Data sources\n\nUse your own validator, as long as the JSON source follows the following schema:\n\n```\n{\n  \"roas\": [\n    {\n      \"prefix\": \"10.0.0.0/24\",\n      \"maxLength\": 24,\n      \"asn\": \"AS65001\"\n    },\n    ...\n  ]\n}\n```\n\n* [**Cloudflare**](https://rpki.cloudflare.com/rpki.json) *(list curated, signed, compressed and cached in +160 PoPs)*\n* **Third-party JSON formatted VRP exports:**\n  * [NTT](https://rpki.gin.ntt.net/api/export.json) (based on OpenBSD's `rpki-client`)\n  * [RIPE](https://rpki-validator.ripe.net/api/export.json) (based on RIPE NCC's RPKI Cache Validator)\n\nTo use a data source that do not contain signatures or validity information, pass:\n`-verify=false -checktime=false`\n\n**[Note: for boolean flags, it requires the equal sign](https://golang.org/pkg/flag/#hdr-Command_line_flag_syntax)**\n\nCloudflare's prefix list removes duplicates and entries that are not routed on the Internet (\u003e/24 IPv4 and \u003e/48 IPv6).\n\nBy default, the session ID will be randomly generated. The serial will start at zero.\n\nYou can define a serial to start with the following way:\n\n* the JSON must contain a `serial` field in `metadata`; and\n* the flag `-useserial` must be set to 1 or 2\n\nWhen flag is set to 1, every change of file will increment the serial regardless of the current `serial` field.\nMake sure the refresh rate of GoRTR is more frequent than the refresh rate of the JSON.\n\nWhen flag is set to 2, GoRTR will set the value of the serial in the JSON. If an ID is missed or not updated,\nit will cause discrepancies on the client.\n\n## Configurations\n\n### Compatibility matrix\n\nA simple comparison between software and devices.\nImplementations on versions may vary.\n\n| Device/software | Plaintext | TLS | SSH | Notes             |\n| --------------- | --------- | --- | --- | ----------------- |\n| RTRdump         | Yes       | Yes | Yes |                   |\n| RTRlib          | Yes       | No  | Yes | Only SSH key      |\n| Juniper         | Yes       | No  | No  |                   |\n| Cisco           | Yes       | No  | Yes | Only SSH password |\n| Nokia SR OS     | Yes       | No  | No  | Since 9.0.R1(2010)|\n| Arista          | Yes       | No  | No  |                   |\n| FRRouting       | Yes       | No  | Yes | Only SSH key      |\n| Bird2           | Yes       | No  | Yes | Only SSH key      |\n| Quagga          | Yes       | No  | No  |                   |\n\n### Configure on Juniper\n\nConfigure a session to the RTR server (assuming it runs on `192.168.1.100:8282`)\n\n```\nlouis@router\u003e show configuration routing-options validation\ngroup TEST-RPKI {\n    session 192.168.1.100 {\n        port 8282;\n    }\n}\n```\n\nAdd policies to validate or invalidate prefixes\n\n```\nlouis@router\u003e show configuration policy-options policy-statement STATEMENT-EXAMPLE\nterm RPKI-TEST-VAL {\n    from {\n        protocol bgp;\n        validation-database valid;\n    }\n    then {\n        validation-state valid;\n        next term;\n    }\n}\nterm RPKI-TEST-INV {\n    from {\n        protocol bgp;\n        validation-database invalid;\n    }\n    then {\n        validation-state invalid;\n        reject;\n    }\n}\n```\n\nDisplay status of the session to the RTR server.\n\n```\nlouis@router\u003e show validation session 192.168.1.100 detail\nSession 192.168.1.100, State: up, Session index: 1\n  Group: TEST-RPKI, Preference: 100\n  Port: 8282\n  Refresh time: 300s\n  Hold time: 600s\n  Record Life time: 3600s\n  Serial (Full Update): 1\n  Serial (Incremental Update): 1\n    Session flaps: 2\n    Session uptime: 00:25:07\n    Last PDU received: 00:04:50\n    IPv4 prefix count: 46478\n    IPv6 prefix count: 8216\n```\n\nShow content of the database (list the PDUs)\n\n```\nlouis@router\u003e show validation database brief\nRV database for instance master\n\nPrefix                 Origin-AS Session                                 State   Mismatch\n1.0.0.0/24-24              13335 192.168.1.100                           valid\n1.1.1.0/24-24              13335 192.168.1.100                           valid\n```\n\n### Configure on Cisco\n\nYou may want to use the option to do SSH-based connection.\n\nOn Cisco, you can have only one RTR server per IP.\n\nTo configure a session for `192.168.1.100:8282`:\nReplace `65001` by the configured ASN:\n\n```\nrouter bgp 65001\n rpki server 192.168.1.100\n  transport tcp port 8282\n !\n!\n```\n\nFor an SSH session, you will also have to configure\n`router bgp 65001 rpki server 192.168.1.100 password xxx`\nwhere `xxx` is the password.\nSome experimentations showed you have to configure\nthe username/password first, otherwise it will not accept the port.\n\n```\nrouter bgp 65001\n rpki server 192.168.1.100\n  username rpki\n  transport ssh port 8282\n !\n!\nssh client tcp-window-scale 14\nssh timeout 120\n```\n\nThe last two SSH statements solved an issue causing the\nconnection to break before receiving all the PDUs (TCP window full problem).\n\nTo visualize the state of the session:\n\n```\nRP/0/RP0/CPU0:ios#sh bgp rpki server 192.168.1.100\n\nRPKI Cache-Server 192.168.1.100\n  Transport: SSH port 8282\n  Connect state: ESTAB\n  Conn attempts: 1\n  Total byte RX: 1726892\n  Total byte TX: 452\n  Last reset\n    Timest: Apr 05 01:19:32 (04:26:58 ago)\n    Reason: protocol error\nSSH information\n  Username: rpki\n  Password: *****\n  SSH PID: 18576\nRPKI-RTR protocol information\n  Serial number: 15\n  Cache nonce: 0x0\n  Protocol state: DATA_END\n  Refresh  time: 600 seconds\n  Response time: 30 seconds\n  Purge time: 60 seconds\n  Protocol exchange\n    ROAs announced:  67358 IPv4   11754 IPv6\n    ROAs withdrawn:     80 IPv4      34 IPv6\n    Error Reports :      0 sent       0 rcvd\n  Last protocol error\n    Reason: response timeout\n    Detail: response timeout while in DATA_START state\n```\n\nTo visualize the accepted PDUs:\n\n```\nRP/0/RP0/CPU0:ios#sh bgp rpki table\n\n  Network               Maxlen          Origin-AS         Server\n  1.0.0.0/24            24              13335             192.168.1.100\n  1.1.1.0/24            24              13335             192.168.1.100\n```\n\n### Configure on Arista\n```\nrouter bgp \u003casn\u003e\n   rpki cache \u003cname\u003e\n      host \u003cipv4|ipv6|hostname\u003e [vrf \u003cvrfname\u003e] [port \u003c1-65535\u003e] # default port is 323\n      local-interface \u003cinterface\u003e\n      preference \u003c1-10\u003e                    # the lower the value, the more preferred\n                                           # default is 5\n      refresh-interval \u003c1-86400 seconds\u003e   # default is 3600\n      expire-interval \u003c600-172800 seconds\u003e # default is 7200\n      retry-interval \u003c1-7200 seconds\u003e      # default is 600\n```\nIf multiple caches are configured, the preference controls the priority.  \nCaches which are more preferred will be connected to first, if they are not reachable then connections will be attempted to less preferred caches.  \nIf caches have the same preference value, they will all be connected to and the ROAs that are synced from them will be merged together.\n\nTo visualize the state of the session:\n\n```\nshow bgp rpki cache [\u003cname\u003e]\nshow bgp rpki cache counters [errors]\nshow bgp rpki roa summary\n```\n\nTo visualize the accepted PDUs:\n\n```\nshow bgp rpki roa (ipv4|ipv6) [prefix]\n```\n\n### Configure on Nokia SR OS\n```\n/configure router \"management\" # or \"Base\" for in-band\n    origin-validation {\n        rpki-session 172.65.0.2 {\n            admin-state enable\n            description \"rtr.rpki.cloudflare.com\"\n            port 8282\n        }\n    }\n```\nSee [this NANOG 67 presentation](https://archive.nanog.org/sites/default/files/GrHankins.pdf) for context\n\nTo check the state:\n```\nA:admin@IXPRouter# show router \"management\" origin-validation rpki-session detail \n\n===============================================================================\nRPKI Session Information\n===============================================================================\nIP Address         : 172.65.0.2\nDescription        : rtr.rpki.cloudflare.com\n-------------------------------------------------------------------------------\nPort               : 8282               Oper State         : established\nUptime             : 0d 00:29:07        Flaps              : 0\nActive IPv4 Records: 327768             Active IPv6 Records: 67796\nAdmin State        : Up                 Local Address      : n/a\nHold Time          : 600                Refresh Time       : 300\nStale Route Time   : 3600               Connect Retry      : 120\nSerial ID          : 1                  Session ID         : 9944\n===============================================================================\nNo. of Sessions    : 1\n===============================================================================\n```\n\n## License\n\nLicensed under the BSD 3 License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudflare%2Fgortr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloudflare%2Fgortr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudflare%2Fgortr/lists"}