{"id":13721176,"url":"https://github.com/opencoff/go-tunnel","last_synced_at":"2025-04-07T12:11:19.405Z","repository":{"id":42613177,"uuid":"127704408","full_name":"opencoff/go-tunnel","owner":"opencoff","description":"TLS/SSL Tunnel - A modern STunnel replacement written in golang","archived":false,"fork":false,"pushed_at":"2024-04-23T22:26:44.000Z","size":294,"stargazers_count":278,"open_issues_count":10,"forks_count":41,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-04-23T23:50:12.855Z","etag":null,"topics":["golang","golang-application","golang-proxy","quic","quic-client","quic-server","ssl-termination","stunnel-replacement","tls-proxy","tls-sni","tls-tunnel"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/opencoff.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":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-02T04:57:06.000Z","updated_at":"2024-06-20T14:11:33.716Z","dependencies_parsed_at":"2024-01-13T11:12:50.959Z","dependency_job_id":"250cde3f-4c6b-4e85-a08c-923c5ebc2d3d","html_url":"https://github.com/opencoff/go-tunnel","commit_stats":null,"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opencoff%2Fgo-tunnel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opencoff%2Fgo-tunnel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opencoff%2Fgo-tunnel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opencoff%2Fgo-tunnel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/opencoff","download_url":"https://codeload.github.com/opencoff/go-tunnel/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247648977,"owners_count":20972945,"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":["golang","golang-application","golang-proxy","quic","quic-client","quic-server","ssl-termination","stunnel-replacement","tls-proxy","tls-sni","tls-tunnel"],"created_at":"2024-08-03T01:01:13.343Z","updated_at":"2025-04-07T12:11:19.387Z","avatar_url":"https://github.com/opencoff.png","language":"Go","funding_links":[],"categories":["\u003ca id=\"01e6651181d405ecdcd92a452989e7e0\"\u003e\u003c/a\u003e工具","Encryption"],"sub_categories":["\u003ca id=\"9d6789f22a280f5bb6491d1353b02384\"\u003e\u003c/a\u003e隧道\u0026\u0026穿透"],"readme":"# go-tunnel - Robust Quic/TLS Tunnel (Stunnel replacement)\n\n## What is it?\nA supercharged [Stunnel](https://www.stunnel.org) replacement written in golang.\nis in a sense a proxy enabling addition of network-encryption to existing\nclients without any source code changes.\n\n## Features\n\n- TLS 1.3 for client and server mode (TLS Connect or TLS Listen)\n- Quic client and server mode (Quic listen or Quic connect)\n- Optional SOCKS for connecting endpoint (SOCKS server)\n- Optional TLS client certificate (for Quic/TLS Connect)\n- SNI on the listening Quic/TLS server\n- Ratelimits - global and per-IP\n- [Proxy-Protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)\n  v1 support when connecting to downstream servers\n- YAML Configuration file\n- Access Control on per IP or subnet basis (allow/deny combination)\n- Strong ciphers and curves preferred on both client \u0026 server\n- Comes with end-to-end tests covering variety of scenarios\n\nNote that TLS private keys need to be *unencrypted*; we don't support password protected\nprivate keys yet. The main reason for this is that when `gotun` is daemonized, it may not be\npossible to obtain the password in an interactive manner. Additionally, for SNI support, it may be\nimpossible to ask for interactive password in the middle of a client connection setup.\n\n## Motivating Example\nLets assume you have a public server on `proxy.example.com`\nlistening on Quic/UDP supporting SOCKS protocol for connecting to\noutbound destinations. For security reasons, you want to limit\naccess to only clients that are TLS authenticated (TLS client\ncerts).\n\nLets also assume that you have a laptop that wants to connect to the\nSOCKS server efficiently.\n\nUsing two instances of `gotun`, you can accomplish this:\n\n1. Local gotun instance on your laptop configured to accept TCP and\n   connect using Quic to the external server `proxy.example.com`\n\n2. Server gotun instance on the external host configured to accept\n   authenticated Quic connections and proxy via SOCKS.\n\n3. Configure your laptop browser to use the \"local\" SOCKS server.\n\nUsing Quic to connect the two `gotun` instances reduces the TCP/TLS\noverhead of every socks connection. And, TLS client certs enables\nstrong authentication on the external server.\n\nThe picture below explains the connectivity:\n\n![example diagram](/docs/socks-example.png)\n\nIn the setup above, the laptop browser clients will treat\n`127.0.0.1:1080` as their \"real\" SOCKS server. Behind the scenes,\n`gotun` will tunnel the packets via Quic to a remote endpoint where\na second `gotun` instance will unbundle the SOCKS protocol and\nconnect to the final destination.\n\nThe config file shown above actually demonstrates a really secure tunnel\nwhere the server and client both use certificates to authenticate each other.\n\nAssuming the config on \"Gotunnel Laptop\" is in file `client.conf`, and the\nconfig on \"Gotunnel Server\" is in `server.conf`, to run the above example,\non host \"Gotunnel-A\":\n\n    gotun client.conf\n\nAnd, on the public server:\n\n    gotun server.conf\n\nThe `-d` flag for `gotun` runs it in debug mode - where the logs are sent\nto STDOUT. It's not recommended to run a production server in debug\nmode (too many log messages).\n\n## Building go-tunnel\nYou need a reasonably new Golang toolchain (1.14+). And the `go`\nexecutable needs to be in your path. Then run:\n\n    make\n\nMake essentially runs:\n\n    ./build\n\n`build` will build the binary `gotun` and places it in TARGET specific\ndirectory. e.g., for linux-amd64, the binaries will be in `./bin/linux-amd64`;\nand OS X, it will be in `./bin/darwin-amd64` and so on.\n\nYou can cross-compile 'go-tun' by passing appropriate architecture names to\nthe script. e.g., to build on host OS X for openbsd-amd64:\n\n    ./build --arch=openbsd-amd64\n\nYou can build a statically linked executable (with no other runtime dependency):\n\n    ./build -s\n\nThe script also has other options. To see them::\n\n    ./build --help\n\n\n### Running go-tunnel\n`gotun` takes a YAML config file as its sole command line argument. The server\ndoes *not* fork itself into the background. If you need that capability, explore your\nplatform's init toolchain (e.g., `start-stop-daemon`).\n\nThe server can run in debug mode; e.g., on Linux x86\\_64:\n\n    ./bin/linux-amd64/gotun -d etc/gotun.conf\n\n\nIn debug mode, the logs are sent to STDOUT and the debug level is set to DEBUG\n(i.e., verbose).\n\nIn the absence of the `-d` flag, the default log level is INFO or\nwhatever is set in the config file.\n\n## Config File\nThe config file is a YAML v2 document. A complete, self-explanatory example is below:\n\n```yaml\n\n# Log file; can be one of:\n#  - Absolute path\n#  - SYSLOG\n#  - STDOUT\n#  - STDERR\nlog: STDOUT\n#log: STDOUT\n\n# Logging level - \"DEBUG\", \"INFO\", \"WARN\", \"ERROR\"\nloglevel: DEBUG\n\n# config dir - where all non-absolute file references below will\n# apply.\nconfig-dir: /etc/gotun\n\n# Listeners\nlisten:\n    # Listen plain text\n    -   address: 127.0.0.1:9090\n        allow: [127.0.0.1/8, 11.0.1.0/24, 11.0.2.0/24]\n        deny: []\n\n        timeout:\n            connect: 5\n            read: 2\n            write: 2\n\n        # limit to N reqs/sec globally\n        ratelimit:\n            global: 2000\n            per-host: 30\n            cache-size: 10000\n\n        # Connect via TLS\n        connect:\n            address: host.name:443\n            bind: my.ip.address\n            tls:\n                cert: /path/to/crt\n                key: /path/to/key\n                # path to CA bundle that can verify the server certificate.\n                # This can be a file or a directory.\n                ca: /path/to/ca.crt\n\n            # if address is a name, then servername is populated from it.\n            # else, if it is an IP address, it must be set below.\n            # Not setting it =\u003e no verification (InsecureSkipVerify = true)\n            # servername: a.example.com\n\n    # Listen using TLS with SNI\n    -   address: 127.0.0.1:9443\n        allow: [127.0.0.1/8, 11.0.1.0/24, 11.0.2.0/24]\n        deny: []\n        timeout:\n            connect: 5\n            read: 2\n            write: 2\n\n        tls:\n            sni: /path/to/cert/dir\n\n            # clientcert can be \"required\" or \"optional\" or \"blank\" or absent.\n            # if it is required/optional, then clientca must be set to the list of\n            # CAs that can verify a presented client cert.\n            client-cert: required\n            client-ca: /path/to/clientca.crt\n\n        # plain connect but use proxy-protocol v1 when speaking\n        # downstream\n        connect:\n            address: 55.66.77.88:80\n            proxyprotocol: v1\n\n\n    # Listen on Quic + client auth and connect to SOCKS\n    -   address: 127.0.0.1:8443\n        tls:\n            quic: true\n            cert: /path/to/crt\n            key: /path/to/key\n            # path to CA bundle that can verify the server certificate.\n            # This can be a file or a directory.\n            ca: /path/to/ca.crt\n\n            client-cert: required\n            client-ca: /path/to/clientca.crt\n\n        connect:\n            address: SOCKS\n\n```\n\nThe `etc/` directory has example configurations for running\nQuic+SOCKS on a public server and a local laptop.\n\n## Using SNI\nSNI is exposed via domain specific certs \u0026 keys in the `tls.certdir` config block. SNI is\nenabled by setting `tls.sni` config element to `true`; and each hostname that is requested via\nSNI needs a cert and key file with the file prefix of hostname. e.g., if the client is looking\nfor hostname \"blog.mydomain.com\" via SNI, then `gotun` will look for `blog.mydomain.com.crt` and\n`blog.mydomain.com.key` in the directory identified by `tls.certdir`. The config file above has\nan example for SNI configured on listen address `127.0.0.1:9443`.\n\n## Generating Local Certificates\nIf you want client authentication and don't want the hassle of using\nopenssl or a commercial CA for obtaining the certs, you can use\n[certik](https://github.com/opencoff/certik) to create an easy,\nopinionated local CA infrastucture. Assuming you are on a\nlinux-amd64 platform:\n\n```sh\n\n$ git clone https://github.com/opencoff/certik\n$ cd certik\n$ ./build -s\n$ ./bin/linux-amd64/certik ca.db init \"client CA\" \n$ ./bin/linux-amd64/certik ca.db user username@example.com\n$ ./bin/linux-amd64/certik ca.db export -o ca --ca\n$ ./bin/linux-amd64/certik ca.db export -o username username@example.com\n\n```\n\nNow, you have `ca.crt` as the CA root of trust for the Quic server\nto validate client certs. And, the client cert/key for\n`username@example.com` is in `username.crt` and `username.key`\n\nYou can copy and use `ca.crt` and user's cert/key to `gotun` config directory\nand refer to it in the config file under \"client-ca\" and \"tls.cert\",\n\"tls.key\" respectively.\n\n## Security\n`gotun` tries to be safe by default:\n\n- Opinionated TLS 1.3 configuration\n- All config file references are checked for safety: e.g., any TLS\n  certs/keys are verified to have sane permissions (NOT group/world\n  writable)\n\n## Performance Test\nUsing iperf3 on two debian-linux (amd64) hosts connected via Gigabit Ethernet and `gotun` running on either end,\nthe performance looks like so:\n\n```shell\n$ iperf3 -V  -c 127.0.0.1 -p 9000\niperf 3.1.3\nLinux ungoliant 4.15.0-2-amd64 #1 SMP Debian 4.15.11-1 (2018-03-20) x86_64\nTime: Sat, 28 Apr 2018 21:18:46 GMT\nConnecting to host 127.0.0.1, port 9000\n      Cookie: ungoliant.1524950326.966562.77625193\n      TCP MSS: 21888 (default)\n[  4] local 127.0.0.1 port 35444 connected to 127.0.0.1 port 9000\nStarting Test: protocol: TCP, 1 streams, 131072 byte blocks, omitting 0 seconds, 10 second test\n[ ID] Interval           Transfer     Bandwidth       Retr  Cwnd\n[  4]   0.00-1.00   sec  54.5 MBytes   457 Mbits/sec    0   2.50 MBytes\n[  4]   1.00-2.00   sec  45.7 MBytes   383 Mbits/sec    0   2.50 MBytes\n[  4]   2.00-3.00   sec  46.2 MBytes   388 Mbits/sec    0   2.50 MBytes\n[  4]   3.00-4.00   sec  46.5 MBytes   390 Mbits/sec    0   2.50 MBytes\n[  4]   4.00-5.00   sec  46.6 MBytes   391 Mbits/sec    0   2.50 MBytes\n[  4]   5.00-6.00   sec  46.2 MBytes   388 Mbits/sec    0   2.50 MBytes\n[  4]   6.00-7.00   sec  47.0 MBytes   394 Mbits/sec    0   2.50 MBytes\n[  4]   7.00-8.00   sec  47.7 MBytes   400 Mbits/sec    0   2.50 MBytes\n[  4]   8.00-9.00   sec  47.5 MBytes   398 Mbits/sec    0   2.50 MBytes\n[  4]   9.00-10.00  sec  46.7 MBytes   392 Mbits/sec    0   2.50 MBytes\n- - - - - - - - - - - - - - - - - - - - - - - - -\nTest Complete. Summary Results:\n[ ID] Interval           Transfer     Bandwidth       Retr\n[  4]   0.00-10.00  sec   475 MBytes   398 Mbits/sec    0             sender\n[  4]   0.00-10.00  sec   464 MBytes   389 Mbits/sec                  receiver\nCPU Utilization: local/sender 1.8% (0.0%u/1.7%s), remote/receiver 9.0% (0.6%u/8.4%s)\n\n```\n\n## Access Control Rules\nGo-tunnel implements a flexible ACL by combination of\nallow/deny rules. The rules are evaluated in the following order:\n\n- If explicitly denied, then host is blocked\n- If allow list is empty, then host is allowed\n- If allow list is non-empty \u0026 host is in allow-list, then host is allowed\n- Explicit denial takes precedence over explicit allow\n- Default (fall through) policy is to deny\n\n### Example of allow/deny combinations\n\n1. Allow all:\n\n```yaml\n   allow: []\n   deny:  []\n```\n\n2. Only allow specific subnets and deny everyone else:\n\n```yaml\n    allow: [ 192.168.55.0/24, 172.16.10.0/24, 127.0.0.1/8 ]\n    deny: []\n```\n\n\n3. Allow all except selected subnets:\n\n```yaml\n    allow: []\n    deny: [ 192.168.80.0/24, 172.16.5.0/24 ]\n```\n\n\n4. Expliclty block certain hosts and explicitly allow certain\n   subnets and block everyone else:\n\n```yaml\n    allow: [ 192.168.55.0/24, 172.16.10.0/24, 127.0.0.1/8 ]\n    deny:  [ 192.168.1.1/32, 192.168.80.0/24, 172.16.5.0/24 ]\n```\n\n\n## Development Notes\nIf you are a developer, the notes here will be useful for you:\n\n- The code uses go modules; so, you'll need a reasonably new go toolchain (1.10+)\n\n- The go-tunnel code is in `./src`:\n\n    * main.go: `main()` for `gotun`\n    * server.go: Implements TCP/TLS and Quic servers; also\n      implements the SOCKS server protocol\n    * conf.go: YAML configuration file parser\n    * quicdial.go: Dial outbound connections via Quic + streams\n    * tcpdial.go: Dial outbound connections via TCP\n    * safety.go: Safely open files/dirs referenced in config file\n\n- Tests: running tests: `go test -v ./src`\n  Some of the tests/helpers:\n    * mocked_test.go: Mock servers and clients\n    * tcp_test.go: Tests for TCP/TLS to TCP/TLS\n    * quic_test.go: Tests for TCP/TLS to Quic and vice versa\n    * socks_test.go: Tests for socks (includes a test for the\n      example configuration above)\n    * utils_test.go: test helpers (e.g., `assert()`)\n\n- We build `build` - a a master shell script to build the daemons;\n  it does two very important things:\n\n    * Puts the binary in an OS/Arch specific directory\n    * Injects a git version-tag into the final binary (\"linker resolved symbol\")\n\n  This script can be reused for other go projects.\n\n- Example config files is in the `etc/gotun.conf` directory.\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopencoff%2Fgo-tunnel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopencoff%2Fgo-tunnel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopencoff%2Fgo-tunnel/lists"}