diff --git a/.gitignore b/.gitignore index a6bcb5f6..0182c89b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ # Git submodules /third_party/maxmind/ + +# Prometheus +/data/ diff --git a/.goreleaser.yml b/.goreleaser.yml index ade75a04..d5288b76 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -18,6 +18,7 @@ project_name: outline-ss-server # Skip 32 bit macOS builds. builds: - + main: ./cmd/outline-ss-server/main.go env: - CGO_ENABLED=0 goos: diff --git a/Makefile b/Makefile index e7d3321d..8e993b60 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,13 @@ BUILDDIR=$(CURDIR)/dist -GOBIN=$(CURDIR)/bin -GORELEASER=$(GOBIN)/goreleaser +GORELEASER=go run github.com/goreleaser/goreleaser .PHONY: release release-local test clean clean-all # This requires GITHUB_TOKEN to be set. -release: clean-all $(GORELEASER) +release: clean-all $(GORELEASER) -release-local: $(GORELEASER) +release-local: $(GORELEASER) --rm-dist --snapshot test: third_party/maxmind/test-data/GeoIP2-Country-Test.mmdb @@ -17,9 +16,6 @@ test: third_party/maxmind/test-data/GeoIP2-Country-Test.mmdb third_party/maxmind/test-data/GeoIP2-Country-Test.mmdb: git submodule update --init -$(GORELEASER): go.mod - env GOBIN=$(GOBIN) go install github.com/goreleaser/goreleaser - go.mod: tools.go go mod tidy touch go.mod @@ -30,4 +26,3 @@ clean: clean-all: clean rm -rf $(CURDIR)/third_party/maxmind/* - rm -rf $(GOBIN) diff --git a/README.md b/README.md index 8a19a17d..addb13bc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # Outline ss-server ![Build Status](https://github.com/Jigsaw-Code/outline-ss-server/actions/workflows/go.yml/badge.svg) +[![Go Report Card](https://goreportcard.com/badge/github.com/Jigsaw-Code/outline-ss-server)](https://goreportcard.com/report/github.com/Jigsaw-Code/outline-ss-server) +[![Go Reference](https://pkg.go.dev/badge/github.com/Jigsaw-Code/outline-ss-server.svg)](https://pkg.go.dev/github.com/Jigsaw-Code/outline-ss-server) + [![Mattermost](https://badgen.net/badge/Mattermost/Outline%20Community/blue)](https://community.internetfreedomfestival.org/community/channels/outline-community) [![Reddit](https://badgen.net/badge/Reddit/r%2Foutlinevpn/orange)](https://www.reddit.com/r/outlinevpn/) @@ -22,15 +25,15 @@ The Outline Shadowsocks service allows for: Fetch dependencies for this demo: ``` -GO111MODULE=off go get github.com/shadowsocks/go-shadowsocks2 github.com/prometheus/prometheus/cmd/... +GO111MODULE=off go get github.com/prometheus/prometheus/cmd/... ``` -If that doesn't work, download the [prometheus](https://prometheus.io/download/) or [go-shadowsocks2](https://github.com/shadowsocks/go-shadowsocks2/releases) binaries directly. +If that doesn't work, download the [prometheus](https://prometheus.io/download/) binary directly. ### Run the server On Terminal 1, from the repository directory, build and start the SS server: ``` -go run . -config config_example.yml -metrics localhost:9091 --replay_history=10000 +go run ./cmd/outline-ss-server -config cmd/outline-ss-server/config_example.yml -metrics localhost:9091 --replay_history=10000 ``` In production, you may want to specify `-ip_country_db` to get per-country metrics. See [how the Outline Server calls outline-ss-server](https://github.com/Jigsaw-Code/outline-server/blob/master/src/shadowbox/server/outline_shadowsocks_server.ts). @@ -38,13 +41,13 @@ In production, you may want to specify `-ip_country_db` to get per-country metri ### Run the Prometheus scraper for metrics collection On Terminal 2, start prometheus scraper for metrics collection: ``` -$(go env GOPATH)/bin/prometheus --config.file=prometheus_example.yml +$(go env GOPATH)/bin/prometheus --config.file=cmd/outline-ss-server/prometheus_example.yml ``` ### Run the SOCKS-to-Shadowsocks client On Terminal 3, start the SS client: ``` -$(go env GOPATH)/bin/go-shadowsocks2 -c ss://chacha20-ietf-poly1305:Secret0@:9000 -verbose -socks localhost:1080 +go run github.com/shadowsocks/go-shadowsocks2 -c ss://chacha20-ietf-poly1305:Secret0@:9000 -verbose -socks localhost:1080 ``` ### Fetch a page over Shadowsocks @@ -70,12 +73,12 @@ iperf3 -s Start the SS server (listening on port 9000): ``` -go run . -config config_example.yml +go run ./cmd/outline-ss-server -config cmd/outline-ss-server/config_example.yml ``` Start the SS tunnel to redirect port 8000 -> localhost:5201 via the proxy on 9000: ``` -$(go env GOPATH)/bin/go-shadowsocks2 -c ss://chacha20-ietf-poly1305:Secret0@:9000 -tcptun ":8000=localhost:5201" -udptun ":8000=localhost:5201" -verbose +go run github.com/shadowsocks/go-shadowsocks2 -c ss://chacha20-ietf-poly1305:Secret0@:9000 -tcptun ":8000=localhost:5201" -udptun ":8000=localhost:5201" -verbose ``` Test TCP upload (client -> server): @@ -102,7 +105,7 @@ iperf3 -c localhost -p 8000 --udp -b 0 --reverse Run the commands above, but start the SS server with ``` -$(go env GOPATH)/bin/go-shadowsocks2 -s ss://chacha20-ietf-poly1305:Secret0@:9000 -verbose +go run github.com/shadowsocks/go-shadowsocks2 -s ss://chacha20-ietf-poly1305:Secret0@:9000 -verbose ``` diff --git a/client/client.go b/client/client.go index f1fc3bf6..7b59ce19 100644 --- a/client/client.go +++ b/client/client.go @@ -6,9 +6,9 @@ import ( "net" "time" + "github.com/Jigsaw-Code/outline-ss-server/internal/slicepool" onet "github.com/Jigsaw-Code/outline-ss-server/net" ss "github.com/Jigsaw-Code/outline-ss-server/shadowsocks" - "github.com/Jigsaw-Code/outline-ss-server/slicepool" "github.com/shadowsocks/go-shadowsocks2/socks" ) @@ -156,7 +156,7 @@ func (c *packetConn) ReadFrom(b []byte) (int, net.Addr, error) { if socksSrcAddr == nil { return 0, nil, errors.New("Failed to read source address") } - srcAddr := NewAddr(socksSrcAddr.String(), "udp") + srcAddr := newAddr(socksSrcAddr.String(), "udp") n = copy(b, buf[len(socksSrcAddr):]) // Strip the SOCKS source address if len(b) < len(buf)-len(socksSrcAddr) { return n, srcAddr, io.ErrShortBuffer @@ -177,8 +177,8 @@ func (a *addr) Network() string { return a.network } -// NewAddr returns a net.Addr that holds an address of the form `host:port` with a domain name or IP as host. +// newAddr returns a net.Addr that holds an address of the form `host:port` with a domain name or IP as host. // Used for SOCKS addressing. -func NewAddr(address, network string) net.Addr { +func newAddr(address, network string) net.Addr { return &addr{address: address, network: network} } diff --git a/client/client_test.go b/client/client_test.go index 595932c0..67ef331a 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -176,7 +176,7 @@ func TestShadowsocksClient_ListenUDP(t *testing.T) { } defer conn.Close() conn.SetReadDeadline(time.Now().Add(time.Second * 5)) - pcrw := &packetConnReadWriter{PacketConn: conn, targetAddr: NewAddr(testTargetAddr, "udp")} + pcrw := &packetConnReadWriter{PacketConn: conn, targetAddr: newAddr(testTargetAddr, "udp")} expectEchoPayload(pcrw, ss.MakeTestPayload(1024), make([]byte, 1024), t) proxy.Close() @@ -236,7 +236,7 @@ func BenchmarkShadowsocksClient_ListenUDP(b *testing.B) { buf := make([]byte, clientUDPBufferSize) for n := 0; n < b.N; n++ { payload := ss.MakeTestPayload(1024) - pcrw := &packetConnReadWriter{PacketConn: conn, targetAddr: NewAddr(testTargetAddr, "udp")} + pcrw := &packetConnReadWriter{PacketConn: conn, targetAddr: newAddr(testTargetAddr, "udp")} b.StartTimer() expectEchoPayload(pcrw, payload, buf, b) b.StopTimer() diff --git a/config_example.yml b/cmd/outline-ss-server/config_example.yml similarity index 100% rename from config_example.yml rename to cmd/outline-ss-server/config_example.yml diff --git a/server.go b/cmd/outline-ss-server/main.go similarity index 100% rename from server.go rename to cmd/outline-ss-server/main.go diff --git a/prometheus_example.yml b/cmd/outline-ss-server/prometheus_example.yml similarity index 100% rename from prometheus_example.yml rename to cmd/outline-ss-server/prometheus_example.yml diff --git a/server_test.go b/cmd/outline-ss-server/server_test.go similarity index 100% rename from server_test.go rename to cmd/outline-ss-server/server_test.go diff --git a/integration_test/integration_test.go b/internal/integration_test/integration_test.go similarity index 100% rename from integration_test/integration_test.go rename to internal/integration_test/integration_test.go diff --git a/slicepool/slicepool.go b/internal/slicepool/slicepool.go similarity index 100% rename from slicepool/slicepool.go rename to internal/slicepool/slicepool.go diff --git a/slicepool/slicepool_test.go b/internal/slicepool/slicepool_test.go similarity index 100% rename from slicepool/slicepool_test.go rename to internal/slicepool/slicepool_test.go diff --git a/service/cipher_list.go b/service/cipher_list.go index 6b45da49..49394e03 100644 --- a/service/cipher_list.go +++ b/service/cipher_list.go @@ -37,7 +37,7 @@ type CipherEntry struct { // MakeCipherEntry constructs a CipherEntry. func MakeCipherEntry(id string, cipher *ss.Cipher, secret string) CipherEntry { var saltGenerator ServerSaltGenerator - if cipher.SaltSize()-ServerSaltMarkLen >= minSaltEntropy { + if cipher.SaltSize()-serverSaltMarkLen >= minSaltEntropy { // Mark salts with a tag for reverse replay protection. saltGenerator = NewServerSaltGenerator(secret) } else { diff --git a/service/server_salt.go b/service/server_salt.go index 72433d46..27230423 100644 --- a/service/server_salt.go +++ b/service/server_salt.go @@ -56,10 +56,10 @@ type serverSaltGenerator struct { key []byte } -// ServerSaltMarkLen is the number of bytes of salt to use as a marker. +// serverSaltMarkLen is the number of bytes of salt to use as a marker. // Increasing this value reduces the false positive rate, but increases // the likelihood of salt collisions. -const ServerSaltMarkLen = 4 // Must be less than or equal to SHA1.Size() +const serverSaltMarkLen = 4 // Must be less than or equal to SHA1.Size() // Constant to identify this marking scheme. var serverSaltLabel = []byte("outline-server-salt") @@ -79,9 +79,9 @@ func NewServerSaltGenerator(secret string) ServerSaltGenerator { } func (sg serverSaltGenerator) splitSalt(salt []byte) (prefix, mark []byte, err error) { - prefixLen := len(salt) - ServerSaltMarkLen + prefixLen := len(salt) - serverSaltMarkLen if prefixLen < 0 { - return nil, nil, fmt.Errorf("Salt is too short: %d < %d", len(salt), ServerSaltMarkLen) + return nil, nil, fmt.Errorf("Salt is too short: %d < %d", len(salt), serverSaltMarkLen) } return salt[:prefixLen], salt[prefixLen:], nil } @@ -116,5 +116,5 @@ func (sg serverSaltGenerator) IsServerSalt(salt []byte) bool { return false } tag := sg.getTag(prefix) - return bytes.Equal(tag[:ServerSaltMarkLen], mark) + return bytes.Equal(tag[:serverSaltMarkLen], mark) } diff --git a/shadowsocks/stream.go b/shadowsocks/stream.go index cdfb4c64..3d223d78 100644 --- a/shadowsocks/stream.go +++ b/shadowsocks/stream.go @@ -22,7 +22,7 @@ import ( "io" "sync" - "github.com/Jigsaw-Code/outline-ss-server/slicepool" + "github.com/Jigsaw-Code/outline-ss-server/internal/slicepool" ) // payloadSizeMask is the maximum size of payload in bytes.