{"id":28070061,"url":"https://github.com/rpcpool/tpu-traffic-classifier","last_synced_at":"2025-05-12T19:36:05.821Z","repository":{"id":50681657,"uuid":"445687743","full_name":"rpcpool/tpu-traffic-classifier","owner":"rpcpool","description":null,"archived":false,"fork":false,"pushed_at":"2024-08-13T19:17:39.000Z","size":25087,"stargazers_count":36,"open_issues_count":0,"forks_count":13,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-09-15T08:59:22.057Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rpcpool.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2022-01-08T00:29:46.000Z","updated_at":"2024-09-04T07:09:44.000Z","dependencies_parsed_at":"2024-07-12T16:04:24.347Z","dependency_job_id":"dad85fce-d7e3-4dbd-8d4b-7e9439165156","html_url":"https://github.com/rpcpool/tpu-traffic-classifier","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rpcpool%2Ftpu-traffic-classifier","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rpcpool%2Ftpu-traffic-classifier/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rpcpool%2Ftpu-traffic-classifier/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rpcpool%2Ftpu-traffic-classifier/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rpcpool","download_url":"https://codeload.github.com/rpcpool/tpu-traffic-classifier/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253808714,"owners_count":21967586,"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":[],"created_at":"2025-05-12T19:36:05.007Z","updated_at":"2025-05-12T19:36:05.813Z","avatar_url":"https://github.com/rpcpool.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TPU traffic classifier\n\n**Use at your own risk: While this is tested to work well, it's early stage software used for testing and experiments.**\n\nThis small program classifies incoming Solana network traffic and creates ipsets and iptables firewall rules. It can be used by validators to restrict access to the TPU \u0026 TPU-Forward ports according to the class of traffic.\n\nBy default, it listens to Gossip and creates/maintains the following classes of ipsets:\n\n - `solana-gossip`: all ips visible in gossip\n - `solana-unstaked`: unstaked nodes visible in gossip\n - `solana-staked`: staked nodes visible in gossip\n - `solana-min-staked`: nodes visible in gossip with minimal stake\n - `solana-high-staked`: nodes visible in gossip with significant stake\n\nThese sets will be kept up to date for as long as the software runs. On exit it will clean up the sets.\n\nYou can modify these categories by editing `config.yml`, setting the minimum stake percentages for each category. The sender will be placed in the largest category that applies to it.\n\nIt also uses the PREROUTING tables to permanently mark traffic from these sets of IPs on the local nodes . This can be used in later traffic rules. By default the following fwmarks are set:\n\n - `1`: unstaked\n - `3`: staked\n - `5`: min staked \u003e 15K\n - `9`: high staked \u003e 150K\n\nIf you provide you validator pubkey it will assume that your validator runs on localhost and it will lookup the TPU port of the validator and enable the firewalling rules. If you do not provide your validator pubkey, all UDP traffic passing through this host will be passed through the chains created by this tool.\n\n##  Running\n\nRun: `go run .`\n\nBuild: `go build -o tpu-traffic-classifier .`\n\n```\nUsage of ./tpu-traffic-classifier:\n  -config-file string\n    \tconfiguration file (default \"config.yml\")\n  -fetch-identity\n    \tfetch identity from rpc\n  -fwd-policy string\n    \tthe default iptables policy for tpu forward, default is passthrough\n  -our-localhost\n    \tuse localhost:8899 for rpc and fetch identity from that rpc\n  -pubkey string\n    \tvalidator-pubkey\n  -rpc-uri string\n    \tthe rpc uri to use (default \"https://api.mainnet-beta.solana.com\")\n  -sleep duration\n    \thow long to sleep between updates (default 10s)\n  -tpu-policy string\n    \tthe default iptables policy for tpu, default is passthrough\n  -tpu-quic-fwd-policy string\n    \tthe default iptables policy for quic tpu fwd, default is passthrough\n  -tpu-quic-policy string\n    \tthe default iptables policy for quic tpu, default is passthrough\n  -update\n    \twhether or not to keep ipsets updated (default true)\n  -vote-policy string\n    \tthe default iptables policy for votes, default is passthrough\n```\n\n## Sample config.yml\n\n```\n# Special unstaked class for all nodes visible in gossip but without stake\nunstaked_class:\n  name: solana-unstaked\n  fwmark: 1\n\n# Different staked classes, the highest matching class will apply\nstaked_classes:\n  - name: solana-staked\n    stake_percentage: 0\n    fwmark: 3\n  - name: solana-min-staked\n    stake_percentage: 0.00003 # 15k stake and up - 0.003%\n    fwmark: 5\n  - name: solana-high-staked \n    stake_percentage: 0.0003 # 150k stake and up - 0.03%\n    fwmark: 9\n```\n\n## Firewalling\n\n**If you do not provide a validator pubkey, then all UDP traffic will pass through these firewall rules**.\n\nYou can add rules to `solana-tpu-custom` (or `solana-tpu-custom-quic`, `solana-tpu-custom-quic-fwd`). This chain will persist between invocations of this tool (it's not cleaned out). If you provide your validator pubkey, then the tool will look up your TPU port and send all incoming UDP TPU traffic to this port to the `solana-tpu-custom` chain. Same for the quic and quic-fwd ports.\n\nFor instance if you wanted to temporarily close TPU ports you can run:\n\n```\niptables -A solana-tpu-custom -j DROP\n```\nThis will drop all traffic to the tpu port.\n\nIf you would like to drop all traffic to UDP TPU port but allow UDP TPU and quic forwards from staked validators and allow all QUIC connections except from nodes in gossip:\n\n```\n# Old UDP TPU\niptables -N solana-tpu-custom || true\niptables -F solana-tpu-custom\niptables -A solana-tpu-custom -m set --match-set solana-high-staked src -j DROP\niptables -A solana-tpu-custom -m set --match-set solana-min-staked src -j DROP\niptables -A solana-tpu-custom -m set --match-set solana-staked src -j DROP\niptables -A solana-tpu-custom -m set --match-set solana-unstaked src -j DROP\niptables -A solana-tpu-custom -m set ! --match-set solana-gossip src -j DROP\niptables -A solana-tpu-custom -j DROP\n# Old UDP TPU Forwards\niptables -N solana-tpu-custom-fwd || true\niptables -F solana-tpu-custom-fwd\niptables -A solana-tpu-custom-fwd -m set --match-set solana-high-staked src -j ACCEPT\niptables -A solana-tpu-custom-fwd -m set --match-set solana-min-staked src -j ACCEPT\niptables -A solana-tpu-custom-fwd -m set --match-set solana-staked src -j ACCEPT\niptables -A solana-tpu-custom-fwd -m set --match-set solana-unstaked src -j DROP\niptables -A solana-tpu-custom-fwd -m set --match-set solana-gossip src -j DROP\niptables -A solana-tpu-custom-fwd -m set ! --match-set solana-gossip src -j DROP\niptables -A solana-tpu-custom-fwd -j DROP\n# New QUIC TPU\niptables -N solana-tpu-custom-quic || true\niptables -F solana-tpu-custom-quic\niptables -A solana-tpu-custom-quic -m set --match-set solana-high-staked src -j ACCEPT\niptables -A solana-tpu-custom-quic -m set --match-set solana-min-staked src -j ACCEPT\niptables -A solana-tpu-custom-quic -m set --match-set solana-staked src -j ACCEPT\niptables -A solana-tpu-custom-quic -m set --match-set solana-unstaked src -j ACCEPT\niptables -A solana-tpu-custom-quic -m set ! --match-set solana-gossip src -j DROP # this will drop all QUIC connections from nodes not in gossip\niptables -A solana-tpu-custom-quic -j DROP\n# New QUIC TPU Forwards\niptables -N solana-tpu-custom-quic-fwd || true\niptables -F solana-tpu-custom-quic-fwd\niptables -A solana-tpu-custom-quic-fwd -m set --match-set solana-high-staked src -j ACCEPT\niptables -A solana-tpu-custom-quic-fwd -m set --match-set solana-min-staked src -j ACCEPT\niptables -A solana-tpu-custom-quic-fwd -m set --match-set solana-staked src -j DROP\niptables -A solana-tpu-custom-quic-fwd -m set --match-set solana-unstaked src -j DROP\niptables -A solana-tpu-custom-quic-fwd -m set ! --match-set solana-gossip src -j DROP\niptables -A solana-tpu-custom-quic-fwd -j DROP\n```\n\nIf you would only allow nodes in gossip to send to your TPU:\n\n```\niptables -A solana-tpu-custom-quic -m set --match-set solana-gossip src -j ACCEPT\niptables -A solana-tpu-custom-quic -j DROP\n```\n\nLog all traffic from nodes not in gossip to you QUIC TPU fwd:\n\n```\niptables -A solana-tpu-custom-quic-fwd -m set ! --match-set solana-gossip src -j LOG --log-prefix 'TPUfwd:not in gossip:' --log-level info\n```\n\nThese rules will only work when this utility is running. When it is not running, the TPU port will be open as usual.\n\n## Rate limiting example\n\nYou can rate limit traffic to reduce the load on your TPU port:\n\n```\n#!/bin/bash\n\niptables -F solana-tpu-custom\n# accept any amount of traffic from nodes with more than 100k stake:\niptables -A solana-tpu-custom -m set --match-set solana-high-staked src -j ACCEPT  \n# accept 50/udp/second from low staked nodes\niptables -A solana-tpu-custom -m set --match-set solana-staked src -m limit --limit 50/sec -j ACCEPT                \n# accept 1000 packets/second from RPC nodes (and other unstaked)\niptables -A solana-tpu-custom -m set --match-set solana-unstaked src -m limit --limit 1000/sec  -j ACCEPT # rpc nodes   \n# accept 10 packets/second from nodes not visible in gossip\niptables -A solana-tpu-custom -m set ! --match-set solana-gossip src -m limit --limit 10/sec -j ACCEPT       \n# log all dropped traffic (warning: lots of logs)\niptables -A solana-tpu-custom -j LOG --log-prefix \"TPUport:\" --log-level info\n# drop everything that doesn't pass the limit\niptables -A solana-tpu-custom -j DROP\n\niptables -F solana-tpu-custom-fwd\n# accept only forwarding traffic from nodes in gossip:\niptables -A solana-tpu-custom-fwd -m set --match-set solana-gossip src -j ACCEPT                                                                             \niptables -A solana-tpu-custom-fwd -j LOG --log-prefix \"TPUfwd:\" --log-level info                                                                             \niptables -A solana-tpu-custom-fwd -j DROP\n```\n\n## Traffic shaping\n\n**Incomplete example, not usable as-is**\n\nYou can use the fwmarks set by this tool to create traffic classes for QoS/traffic shaping. You need to use IFB for incoming traffic filteringtraffic . \n\n\n```\ntc qdisc add dev eth0 handle 1: ingress\n\ntc filter add dev eth0 protocol ip parent 1: prio 1 handle 1 fw flowid 1:10 police rate 100mbit burst 100k # unstaked\ntc filter add dev eth0 protocol ip parent 1: prio 1 handle 3 fw flowid 1:20 # staked\ntc filter add dev eth0 protocol ip parent 1: prio 1 handle 9 fw flowid 1:30 # high staked\ntc filter add dev eth0 protocol ip parent 1: prio 1 handle 6 fw flowid 1:40 # others\n```\n\n\n## Example iptables generated\n\nThe examples below is generated by this tool when run with the `pubkey` param for a valid validator. When the tool exits it will clean these rules up with the exception of `-custom...`  if (and only if) it's not empty.\n\n```\n*filter\n:INPUT ACCEPT [0:0]\n:FORWARD DROP [0:0]\n:OUTPUT ACCEPT [0:0]\n:solana-tpu - [0:0]\n:solana-tpu-custom - [0:0]\n-A INPUT -p udp -m udp --dport 8004 -j solana-tpu\n-A INPUT -p udp -m udp --dport 8005 -j solana-tpu-fwd\n-A INPUT -p udp -m udp --dport 8006 -j solana-tpu-vote\n-A solana-tpu -j solana-tpu-custom\n-A solana-tpu-fwd -j solana-tpu-custom-fwd\n-A solana-tpu-vote -j solana-tpu-custom-vote\nCOMMIT\n```\n\n```\n*mangle\n:PREROUTING ACCEPT [0:0]\n:solana-nodes - [0:0]\n-A PREROUTING -p udp -m udp --dport 8004 -j solana-nodes\n-A PREROUTING -p udp -m udp --dport 8005 -j solana-nodes\n-A PREROUTING -p udp -m udp --dport 8006 -j solana-nodes\n-A solana-nodes -m set --match-set solana-high-staked src -j MARK --set-xmark 0x9/0xffffffff\n-A solana-nodes -m set --match-set solana-staked src -j MARK --set-xmark 0x3/0xffffffff\n-A solana-nodes -m set --match-set solana-unstaked src -j MARK --set-xmark 0x1/0xffffffff\nCOMMIT\n```\n\n## Example systemd service file \n\nThe example file creates a service that runs the tpu-traffic-classifier.service\n\n```\n[Unit]\nDescription=TPU traffic classifier\nAfter=network-online.target\nStartLimitInterval=0\nStartLimitIntervalSec=0\n\n[Service]\nType=simple\nUser=root\nGroup=root\nPermissionsStartOnly=true\nExecStart=/usr/local/sbin/tpu-traffic-classifier -config-file /etc/tpu-traffic-classifier/config.yml -pubkey \u003cpubkey\u003e\n\nSyslogIdentifier=tpu-traffic-classifier\nKillMode=process\nRestart=always\nRestartSec=5\n\nLimitNOFILE=700000\nLimitNPROC=700000\n\nProtectSystem=full\n\n[Install]\nWantedBy=multi-user.target\n```\n\n## Example iptables monitoring\n\nYou can create a script to watch the traffic go through all the various \"stake classes\" rules that you created and gives a nice overview of what kind of traffic is hitting your node\n\n```\n#!/bin/bash\n\nwatch -n 1 iptables -n -v -L \"${1}\"\n```\n\n## Recommended RPC node config\n\nRPC nodes shouldn't expose TPU and TPUfwd (as they don't process TPU traffic into blocks) and should only receive traffic via sendTransaction.\n\nYou can use this tool to enforce this kind of firewall:\n\n```\n./tpu-traffic-classifier -config-file config.yml -our-localhost -tpu-policy DROP -fwd-policy DROP -tpu-quic-policy DROP -update=false\n```\n\nThis mode will not keep the ipsets updated and will only create firewall rules for your RPC node to not accept traffic via TPU and TPUfwd.\n\n\nThis software repository is provided “as is\". Use the software at your own risk.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frpcpool%2Ftpu-traffic-classifier","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frpcpool%2Ftpu-traffic-classifier","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frpcpool%2Ftpu-traffic-classifier/lists"}