{"id":27185055,"url":"https://github.com/threefoldtech/tcprouter","last_synced_at":"2025-04-09T17:10:17.181Z","repository":{"id":46898425,"uuid":"189485379","full_name":"threefoldtech/tcprouter","owner":"threefoldtech","description":"down to earth tcprouter with TLS support based on SNI","archived":false,"fork":false,"pushed_at":"2023-10-12T02:57:23.000Z","size":6717,"stargazers_count":7,"open_issues_count":9,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-06-19T10:14:05.757Z","etag":null,"topics":["proxy","router","tcpproxy","tls"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/threefoldtech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-05-30T21:33:27.000Z","updated_at":"2023-09-05T17:53:08.000Z","dependencies_parsed_at":"2023-10-12T12:50:28.069Z","dependency_job_id":null,"html_url":"https://github.com/threefoldtech/tcprouter","commit_stats":null,"previous_names":["xmonader/tcprouter"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/threefoldtech%2Ftcprouter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/threefoldtech%2Ftcprouter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/threefoldtech%2Ftcprouter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/threefoldtech%2Ftcprouter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/threefoldtech","download_url":"https://codeload.github.com/threefoldtech/tcprouter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248074976,"owners_count":21043490,"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":["proxy","router","tcpproxy","tls"],"created_at":"2025-04-09T17:10:16.588Z","updated_at":"2025-04-09T17:10:17.174Z","avatar_url":"https://github.com/threefoldtech.png","language":"Go","readme":"# tcprouter\n\nA down to earth tcp router based on traefik tcp streaming and supports multiple backends using [valkyrie](https://github.com/abronan/valkeyrie)\n\n## Build\n\n```\ngit clone https://github.com/threefoldtech/tcprouter\nmake\n```\n\nThis will generate two binaries in bin dir\n\n- `trs`: tcp router server\n- `trc`: tcp router client\n\n## Running\n\nExample configuration file\n\n```toml\n[server]\naddr = \"0.0.0.0\" # listening address for all entrypoints (http, https, tcp router client)\nport = 443 # TLS listening port\nhttpport = 80 # HTTP listening port\n\n[server.dbbackend] # configuration for the redis backend\ntype \t = \"redis\"\naddr     = \"127.0.0.1\"\nport     = 6379\nrefresh  = 10 # make the tcp router poll for new configuration every 10 seconds\n\n\n[server.services]\n    [server.services.\"mydomain.com\"]\n        addr = \"172.217.19.46\"\n        tlsport = 443\n        httpport = 80\n```\n\nthen `trs -config router.toml`\n\nPlease notice if you are using low numbered port like 80 or 443 you can use sudo or setcap before running the binary.\n- `sudo setcap CAP_NET_BIND_SERVICE=+eip trs`\n\n### router.toml\n\nWe have two 3 sections so far\n\n#### [server]\n\n```toml\n[server]\naddr = \"0.0.0.0\"\nport = 443\nhttpport = 80\n```\n\nin `[server]` section we define the listening interface/port the tcprouter intercepting: typically that's 443 for TLS connections.\n\n#### [server.dbbackend]\n\n```toml\n[server.dbbackend]\ntype    = \"redis\"\naddr    = \"127.0.0.1\"\nport    = 6379\nrefresh = 10\n```\n\nin `server.dbbackend` we define the backend kv store and its connection information `addr,port` and how often we want to reload the data from the kv store using `refresh` key in seconds.\n\n#### [server.services]\n\n```toml\n[server.services]\n    [server.services.\"mydomain.com\"]\n        addr = \"172.217.19.46\"\n        tlsport = 443\n        httpport = 80\n```\n\nServices are static configuration that are hardcoded in the configuration file instead of coming from the database backend.  \nIn this example the request for domain `mydomain.com` will be forwarded to the backend server at `172.217.19.46:443` for TLS traffic and `172.217.19.46:80` for non TLS traffic.\n\n## Data representation in KV\n\n```shell\n127.0.0.1:6379\u003e KEYS *\n1) \"/tcprouter/services/www.bing.com\"\n2) \"/tcprouter/services/www.google.com\"\n3) \"/tcprouter/services/www.facebook.com\"\n\n127.0.0.1:6379\u003e get /tcprouter/services/www.google.com\n\"{\\\"Key\\\":\\\"tcprouter/services/www.google.com\\\",\\\"Value\\\":\\\"eyJhZGRyIjogIjE3Mi4yMTcuMTkuNDYiLCAiaHR0cHBvcnQiIDgwLCAidGxzcG9ydCI6IDQ0M30=\\\",\\\"LastIndex\\\":75292246}\"\n```\n\n### Decoding data from python\n\n```ipython\n\nIn [64]: res = r.get(\"/tcprouter/service/www.google.com\")\n\nIn [65]: decoded = json.loads(res)\n\nIn [66]: decoded\nOut[66]:\n{'Key': '/tcprouter/service/www.google.com',\n 'Value': 'eyJhZGRyIjogIjE3Mi4yMTcuMTkuNDYiLCAiaHR0cHBvcnQiIDgwLCAidGxzcG9ydCI6IDQ0M30='}\n```\n\n`Value` payload is base64 encoded because of how golang is marshaling.\n\n```ipython\nIn [67]: base64.b64decode(decoded['Value'])\nOut[67]: b'{\"addr\": \"172.217.19.46\", \"httpport\" 80, \"tlsport\": 443}'\n```\n\n## Examples\n\n### Go\n\nThis example can be found at [examples/main.go](./examples/main.go)\n\n```go\npackage main\n\nimport (\n    \"encoding/json\"\n    \"log\"\n    \"time\"\n\n    \"github.com/abronan/valkeyrie\"\n    \"github.com/abronan/valkeyrie/store\"\n\n    \"github.com/abronan/valkeyrie/store/redis\"\n)\n\nfunc init() {\n\tredis.Register()\n}\n\ntype Service struct {\n\tAddr string `json:\"addr\"`\n\tSNI  string `json:\"sni\"`\n\tName string `json:\"bing\"`\n}\n\nfunc main() {\n\n\t// Initialize a new store with redis\n\tkv, err := valkeyrie.NewStore(\n\t\tstore.REDIS,\n\t\t[]string{\"127.0.0.1:6379\" },\n\t\t\u0026store.Config{\n\t\t\tConnectionTimeout: 10 * time.Second,\n\t\t},\n\t)\n\tif err != nil {\n\t\tlog.Fatal(\"Cannot create store redis\")\n\t}\n\tgoogle := \u0026Service{Addr:\"172.217.19.46:443\", SNI:\"www.google.com\", Name:\"google\"}\n\tencGoogle, _ := json.Marshal(google)\n\tbing := \u0026Service{Addr:\"13.107.21.200:443\", SNI:\"www.bing.com\", Name:\"bing\"}\n\tencBing, _ := json.Marshal(bing)\n\n\tkv.Put(\"/tcprouter/services/google\", encGoogle, nil)\n\tkv.Put(\"/tcprouter/services/bing\", encBing, nil)\n}\n```\n\n### Python\n\n```python\nimport base64\nimport json\nimport redis\n\nr = redis.Redis()\n\ndef create_service(name, sni, addr):\n    service = {}\n    service['Key'] = '/tcprouter/service/{}'.format(name)\n    record = {\"addr\":addr, \"sni\":sni, \"name\":name}\n    json_dumped_record_bytes = json.dumps(record).encode()\n    b64_record = base64.b64encode(json_dumped_record_bytes).decode()\n    service['Value'] = b64_record\n    r.set(service['Key'], json.dumps(service))\n\ncreate_service('facebook', \"www.facebook.com\", \"102.132.97.35:443\")\ncreate_service('google', 'www.google.com', '172.217.19.46:443')\ncreate_service('bing', 'www.bing.com', '13.107.21.200:443')\n```\n\nIf you want to test that locally you can modify `/etc/hosts`\n\n```shell\n127.0.0.1 www.google.com\n127.0.0.1 www.bing.com\n127.0.0.1 www.facebook.com\n```\n\nSo your browser go to your `127.0.0.1:443` on requesting google or bing.\n\n## CATCH_ALL\n\nto add a global `catch all` service\n\n`python3 create_service.py CATCH_ALL 'CATCH_ALL' '127.0.0.1:9092'`\n\n## Reverse tunneling\n\nTCP router also support to forward connection to a server that is hidden behind NAT. The way it works is on the hidden client side, \na small client runs and opens a connection to the tcp router server. The client sends a secret during an handshake with the server to authenticate the connection.\n\nThe server then keeps the connection opens and is able to forward incoming public traffic to the open connection.  This is specially useful if there is no way for the tcp router server to open a connection to the backend. Usually because of NAT.\n\n![reverse_tunnel](reverse_tunnel.png)\n\n### example\n\nFist create the configuration on the server side. The only required field in the configuration is the secret for the client connection:\n\n```toml\n[server.services]\n    [server.services.\"mydomain.com\"]\n        clientsecret = \"TB2pbZ5FR8GQZp9W2z97jBjxSgWgQKaQTxEgrZNBa4pEFzv3PJcRVEtG2a5BU9qd\"\n```\n\nSecond starts the tcp router client and make it opens a connection to the tcp router server:\nThe following command will connect the the server located at `tcprouter-1.com`, forward traffic for `mydomain.com` to the local application running at `localhost:8080` and send the response back.\n\n\n`trc -local localhost:8080 -remote tcprouter-1.com -secret TB2pbZ5FR8GQZp9W2z97jBjxSgWgQKaQTxEgrZNBa4pEFzv3PJcRVEtG2a5BU9qd`\n\n\nTo forward tls traffic to a difference port than none-tls traffic add the `--local-tls` flag\n\n`trc -local localhost:8080 -local-tls localhost:443 -remote tcprouter-1.com -secret TB2pbZ5FR8GQZp9W2z97jBjxSgWgQKaQTxEgrZNBa4pEFzv3PJcRVEtG2a5BU9qd`\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthreefoldtech%2Ftcprouter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthreefoldtech%2Ftcprouter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthreefoldtech%2Ftcprouter/lists"}