diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..03cdf87 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,17 @@ +name: Build and test +on: [ push ] +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest, macos-latest, windows-latest ] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + with: + go-version: '^1.15' # The Go version to download (if necessary) and use. + - run: go test -race -coverprofile coverage.txt -coverpkg ./... -covermode atomic ./... + - uses: codecov/codecov-action@v1 + with: + file: coverage.txt diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..316ea63 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,22 @@ +on: + push: + tags: + - 'v*' + +name: Create Release + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Build + run: | + export PATH=${PATH}:`go env GOPATH`/bin + v=${{ github.ref }} ./release.sh + - name: Release + uses: softprops/action-gh-release@v1 + with: + files: release/* + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 6fbe39a..0000000 --- a/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: go - -go: - - "1.15" - -script: - - go test -race -coverprofile=coverage.txt -coverpkg=./... -covermode=atomic ./... - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/README.md b/README.md index cd85a0d..9b50dfc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/cbeuw/Cloak.svg?branch=master)](https://travis-ci.org/cbeuw/Cloak) +[![Build Status](https://github.com/cbeuw/Cloak/workflows/Build%20and%20test/badge.svg)](https://github.com/cbeuw/Cloak/actions) [![codecov](https://codecov.io/gh/cbeuw/Cloak/branch/master/graph/badge.svg)](https://codecov.io/gh/cbeuw/Cloak) [![Go Report Card](https://goreportcard.com/badge/github.com/cbeuw/Cloak)](https://goreportcard.com/report/github.com/cbeuw/Cloak) [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SAUYKGSREP8GL&source=url) @@ -165,9 +165,8 @@ is established. 0. Install at least one underlying proxy server (e.g. OpenVPN, Shadowsocks). 1. Download [the latest release](https://github.com/cbeuw/Cloak/releases) or clone and build this repo. -2. Run `ck-server -k`. The base64 string before the comma is the **public** key to be given to users, the one after the - comma is the **private** key to be kept secret. -3. Run `ck-server -u`. This will be used as the `AdminUID`. +2. Run `ck-server -key`. The **public** should be given to users, the **private** key should be kept secret. +3. (Skip if you only want to add unrestricted users) Run `ck-server -uid`. The new UID will be used as `AdminUID`. 4. Copy example_config/ckserver.json into a desired location. Change `PrivateKey` to the private key you just obtained; change `AdminUID` to the UID you just obtained. 5. Configure your underlying proxy server so that they all listen on localhost. Edit `ProxyBook` in the configuration @@ -181,7 +180,7 @@ is established. ##### Unrestricted users -Run `ck-server -u` and add the UID into the `BypassUID` field in `ckserver.json` +Run `ck-server -uid` and add the UID into the `BypassUID` field in `ckserver.json` ##### Users subject to bandwidth and credit controls diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 75509bd..0000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,64 +0,0 @@ -# Go -# Build your Go project. -# Add steps that test, save build artifacts, deploy, and more: -# https://docs.microsoft.com/azure/devops/pipelines/languages/go - -trigger: - tags: - include: - - refs/tags/v* - branches: - exclude: - - master - -pool: - vmImage: 'ubuntu-latest' - -variables: - GOBIN: '$(GOPATH)/bin' # Go binaries path - GOROOT: '$(Agent.BuildDirectory)/go' # Go installation path - GOPATH: '$(Agent.BuildDirectory)/gopath' # Go workspace path - modulePath: '$(GOPATH)/src/github.com/$(build.repository.name)' # Path to the module's code - -steps: -- script: | - mkdir -p '$(GOBIN)' - mkdir -p '$(GOPATH)/pkg' - mkdir -p '$(modulePath)' - shopt -s extglob - shopt -s dotglob - mv !(gopath) '$(modulePath)' - echo '##vso[task.prependpath]$(GOBIN)' - echo '##vso[task.prependpath]$(GOROOT)/bin' - wget "https://golang.org/dl/go1.15.2.linux-amd64.tar.gz" --output-document "$(Agent.BuildDirectory)/go1.15.2.tar.gz" - tar -C '$(Agent.BuildDirectory)' -xzf "$(Agent.BuildDirectory)/go1.15.2.tar.gz" - displayName: 'Set up the Go workspace' - -- script: | - v="$(git describe --tags)" ./release.sh - mv ./release/* $(Build.ArtifactStagingDirectory)/ - workingDirectory: '$(modulePath)' - displayName: 'Get dependencies, then build' - -# GitHub Release -# Create, edit, or delete a GitHub release -- task: GitHubRelease@0 - inputs: - gitHubConnection: github.com_cbeuw - repositoryName: '$(Build.Repository.Name)' - action: 'create' # Options: create, edit, delete - target: '$(Build.SourceVersion)' # Required when action == Create || Action == Edit - tagSource: 'auto' # Required when action == Create# Options: auto, manual - #tagPattern: # Optional - #tag: "$(git describe --tags)" # Required when action == Edit || Action == Delete || TagSource == Manual - #title: # Optional - #releaseNotesSource: 'file' # Optional. Options: file, input - #releaseNotesFile: # Optional - #releaseNotes: # Optional - #assets: '$(Build.ArtifactStagingDirectory)/*' # Optional - #assetUploadMode: 'delete' # Optional. Options: delete, replace - #isDraft: false # Optional - #isPreRelease: false # Optional - addChangeLog: false # Optional - #compareWith: 'lastFullRelease' # Required when addChangeLog == True. Options: lastFullRelease, lastRelease, lastReleaseByTag - #releaseTag: # Required when compareWith == LastReleaseByTag diff --git a/cmd/ck-client/ck-client.go b/cmd/ck-client/ck-client.go index 36b29bd..efe51c2 100644 --- a/cmd/ck-client/ck-client.go +++ b/cmd/ck-client/ck-client.go @@ -169,6 +169,7 @@ func main() { } log.Infof("Listening on %v %v for %v client", network, localConfig.LocalAddr, authInfo.ProxyMethod) seshMaker = func() *mux.Session { + authInfo := authInfo // copy the struct because we are overwriting SessionId // sessionID is usergenerated. There shouldn't be a security concern because the scope of // sessionID is limited to its UID. quad := make([]byte, 4) diff --git a/cmd/ck-server/ck-server.go b/cmd/ck-server/ck-server.go index e741149..b646232 100644 --- a/cmd/ck-server/ck-server.go +++ b/cmd/ck-server/ck-server.go @@ -80,8 +80,11 @@ func main() { askVersion := flag.Bool("v", false, "Print the version number") printUsage := flag.Bool("h", false, "Print this message") - genUID := flag.Bool("u", false, "Generate a UID") - genKeyPair := flag.Bool("k", false, "Generate a pair of public and private key, output in the format of pubkey,pvkey") + genUIDScript := flag.Bool("u", false, "Generate a UID to STDOUT") + genKeyPairScript := flag.Bool("k", false, "Generate a pair of public and private key and output to STDOUT in the format of ,") + + genUIDHuman := flag.Bool("uid", false, "Generate and print out a UID") + genKeyPairHuman := flag.Bool("key", false, "Generate and print out a public-private key pair") pprofAddr := flag.String("d", "", "debug use: ip:port to be listened by pprof profiler") verbosity := flag.String("verbosity", "info", "verbosity level") @@ -96,13 +99,23 @@ func main() { flag.Usage() return } - if *genUID { - fmt.Println(generateUID()) + if *genUIDScript || *genUIDHuman { + uid := generateUID() + if *genUIDScript { + fmt.Println(uid) + } else { + fmt.Printf("\x1B[35mYour UID is:\u001B[0m %s\n", uid) + } return } - if *genKeyPair { + if *genKeyPairScript || *genKeyPairHuman { pub, pv := generateKeyPair() - fmt.Printf("%v,%v", pub, pv) + if *genKeyPairScript { + fmt.Printf("%v,%v\n", pub, pv) + } else { + fmt.Printf("\x1B[36mYour PUBLIC key is:\x1B[0m %65s\n", pub) + fmt.Printf("\x1B[33mYour PRIVATE key is (keep it secret):\x1B[0m %47s\n", pv) + } return } diff --git a/example_config/ckclient.json b/example_config/ckclient.json index 1df5b86..a8b4243 100644 --- a/example_config/ckclient.json +++ b/example_config/ckclient.json @@ -2,8 +2,8 @@ "Transport": "direct", "ProxyMethod": "shadowsocks", "EncryptionMethod": "plain", - "UID": "5nneblJy6lniPJfr81LuYQ==", - "PublicKey": "IYoUzkle/T/kriE+Ufdm7AHQtIeGnBWbhhlTbmDpUUI=", + "UID": "---Your UID here---", + "PublicKey": "---Public key here---", "ServerName": "www.bing.com", "NumConn": 4, "BrowserSig": "chrome", diff --git a/example_config/ckserver.json b/example_config/ckserver.json index aa0566a..589868b 100644 --- a/example_config/ckserver.json +++ b/example_config/ckserver.json @@ -18,10 +18,10 @@ ":80" ], "BypassUID": [ - "1rmq6Ag1jZJCImLBIL5wzQ==" + "---Bypass UID here---" ], - "RedirAddr": "204.79.197.200:443", - "PrivateKey": "EN5aPEpNBO+vw+BtFQY2OnK9bQU7rvEj5qmnmgwEtUc=", - "AdminUID": "5nneblJy6lniPJfr81LuYQ==", + "RedirAddr": "cloudflare.com", + "PrivateKey": "---Private key here---", + "AdminUID": "---Admin UID here (optional)---", "DatabasePath": "userinfo.db" } diff --git a/go.mod b/go.mod index b3ebe02..e950ab7 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/refraction-networking/utls v0.0.0-20190909200633-43c36d3c1f57 github.com/sirupsen/logrus v1.5.0 github.com/stephens2424/writerset v1.0.2 // indirect - github.com/stretchr/testify v1.3.0 + github.com/stretchr/testify v1.6.1 go.etcd.io/bbolt v1.3.4 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect diff --git a/go.sum b/go.sum index d24d520..150adcb 100644 --- a/go.sum +++ b/go.sum @@ -43,6 +43,8 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= @@ -76,5 +78,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/client/piper.go b/internal/client/piper.go index 3b077ed..87bf385 100644 --- a/internal/client/piper.go +++ b/internal/client/piper.go @@ -11,7 +11,7 @@ import ( ) func RouteUDP(bindFunc func() (*net.UDPConn, error), streamTimeout time.Duration, singleplex bool, newSeshFunc func() *mux.Session) { - var multiplexSession *mux.Session + var sesh *mux.Session localConn, err := bindFunc() if err != nil { log.Fatal(err) @@ -27,25 +27,22 @@ func RouteUDP(bindFunc func() (*net.UDPConn, error), streamTimeout time.Duration continue } - if !singleplex && (multiplexSession == nil || multiplexSession.IsClosed()) { - multiplexSession = newSeshFunc() + if !singleplex && (sesh == nil || sesh.IsClosed()) { + sesh = newSeshFunc() } stream, ok := streams[addr.String()] if !ok { - var session *mux.Session - if multiplexSession != nil { - session = multiplexSession - } else { - session = newSeshFunc() + if singleplex { + sesh = newSeshFunc() } - stream, err = session.OpenStream() + stream, err = sesh.OpenStream() if err != nil { - log.Errorf("Failed to open stream: %v", err) - if session.Singleplex { - session.Close() + if singleplex { + sesh.Close() } + log.Errorf("Failed to open stream: %v", err) continue } @@ -82,22 +79,19 @@ func RouteUDP(bindFunc func() (*net.UDPConn, error), streamTimeout time.Duration } func RouteTCP(listener net.Listener, streamTimeout time.Duration, singleplex bool, newSeshFunc func() *mux.Session) { - var multiplexSession *mux.Session + var sesh *mux.Session for { localConn, err := listener.Accept() if err != nil { log.Fatal(err) continue } - if !singleplex && (multiplexSession == nil || multiplexSession.IsClosed()) { - multiplexSession = newSeshFunc() + if !singleplex && (sesh == nil || sesh.IsClosed()) { + sesh = newSeshFunc() } - go func(multiplexSession *mux.Session, newSingleplexSeshFunc func() *mux.Session, localConn net.Conn, timeout time.Duration) { - var session *mux.Session - if multiplexSession != nil { - session = multiplexSession - } else { - session = newSingleplexSeshFunc() + go func(sesh *mux.Session, localConn net.Conn, timeout time.Duration) { + if singleplex { + sesh = newSeshFunc() } data := make([]byte, 10240) @@ -115,8 +109,8 @@ func RouteTCP(listener net.Listener, streamTimeout time.Duration, singleplex boo if err != nil { log.Errorf("Failed to open stream: %v", err) localConn.Close() - if session.Singleplex { - session.Close() + if singleplex { + sesh.Close() } return } diff --git a/internal/multiplex/datagramBufferedPipe_test.go b/internal/multiplex/datagramBufferedPipe_test.go index f03cff0..4a5d4e2 100644 --- a/internal/multiplex/datagramBufferedPipe_test.go +++ b/internal/multiplex/datagramBufferedPipe_test.go @@ -76,7 +76,7 @@ func TestDatagramBuffer_BlockingRead(t *testing.T) { pipe := NewDatagramBufferedPipe() b := []byte{0x01, 0x02, 0x03} go func() { - time.Sleep(100 * time.Millisecond) + time.Sleep(readBlockTime) pipe.Write(Frame{Payload: b}) }() b2 := make([]byte, len(b)) diff --git a/internal/multiplex/mux_test.go b/internal/multiplex/mux_test.go index 436c407..76344ca 100644 --- a/internal/multiplex/mux_test.go +++ b/internal/multiplex/mux_test.go @@ -4,6 +4,7 @@ import ( "bytes" "github.com/cbeuw/Cloak/internal/common" "github.com/cbeuw/connutil" + "github.com/stretchr/testify/assert" "io" "math/rand" "net" @@ -111,12 +112,14 @@ func TestMultiplex(t *testing.T) { //test echo runEchoTest(t, streams, maxMsgLen) - if clientSession.streamCount() != numStreams { - t.Errorf("client stream count is wrong: %v", clientSession.streamCount()) - } - if serverSession.streamCount() != numStreams { - t.Errorf("server stream count is wrong: %v", serverSession.streamCount()) - } + + assert.Eventuallyf(t, func() bool { + return clientSession.streamCount() == numStreams + }, time.Second, 10*time.Millisecond, "client stream count is wrong: %v", clientSession.streamCount()) + + assert.Eventuallyf(t, func() bool { + return serverSession.streamCount() == numStreams + }, time.Second, 10*time.Millisecond, "server stream count is wrong: %v", serverSession.streamCount()) // close one stream closing, streams := streams[0], streams[1:] @@ -148,9 +151,12 @@ func TestMux_StreamClosing(t *testing.T) { t.Errorf("can't write to stream: %v", err) } - time.Sleep(500 * time.Millisecond) + _, err = io.ReadFull(toBeClosed, recvBuf[:1]) + if err != nil { + t.Errorf("can't read anything before stream closed: %v", err) + } _ = toBeClosed.Close() - _, err = io.ReadFull(toBeClosed, recvBuf) + _, err = io.ReadFull(toBeClosed, recvBuf[1:]) if err != nil { t.Errorf("can't read residual data on stream: %v", err) } diff --git a/internal/multiplex/session_test.go b/internal/multiplex/session_test.go index 52fe6a5..b280895 100644 --- a/internal/multiplex/session_test.go +++ b/internal/multiplex/session_test.go @@ -3,6 +3,7 @@ package multiplex import ( "bytes" "github.com/cbeuw/connutil" + "github.com/stretchr/testify/assert" "math/rand" "strconv" "sync" @@ -408,10 +409,10 @@ func TestSession_timeoutAfter(t *testing.T) { seshConfigOrdered.Obfuscator = obfuscator seshConfigOrdered.InactivityTimeout = 100 * time.Millisecond sesh := MakeSession(0, seshConfigOrdered) - time.Sleep(200 * time.Millisecond) - if !sesh.IsClosed() { - t.Error("session should have timed out") - } + + assert.Eventually(t, func() bool { + return sesh.IsClosed() + }, 5*seshConfigOrdered.InactivityTimeout, seshConfigOrdered.InactivityTimeout, "session should have timed out") } func BenchmarkRecvDataFromRemote_Ordered(b *testing.B) { diff --git a/internal/multiplex/streamBufferedPipe_test.go b/internal/multiplex/streamBufferedPipe_test.go index dcaad29..ff0ec24 100644 --- a/internal/multiplex/streamBufferedPipe_test.go +++ b/internal/multiplex/streamBufferedPipe_test.go @@ -7,6 +7,8 @@ import ( "time" ) +const readBlockTime = 500 * time.Millisecond + func TestPipeRW(t *testing.T) { pipe := NewStreamBufferedPipe() b := []byte{0x01, 0x02, 0x03} @@ -60,7 +62,7 @@ func TestReadBlock(t *testing.T) { pipe := NewStreamBufferedPipe() b := []byte{0x01, 0x02, 0x03} go func() { - time.Sleep(100 * time.Millisecond) + time.Sleep(readBlockTime) pipe.Write(b) }() b2 := make([]byte, len(b)) diff --git a/internal/multiplex/stream_test.go b/internal/multiplex/stream_test.go index 278082b..6ce16d9 100644 --- a/internal/multiplex/stream_test.go +++ b/internal/multiplex/stream_test.go @@ -3,6 +3,7 @@ package multiplex import ( "bytes" "github.com/cbeuw/Cloak/internal/common" + "github.com/stretchr/testify/assert" "io" "io/ioutil" "math/rand" @@ -230,11 +231,11 @@ func TestStream_Close(t *testing.T) { if err != nil { t.Errorf("can't read residual data %v", err) } - time.Sleep(100 * time.Millisecond) - if sI, _ := sesh.streams.Load(stream.(*Stream).id); sI != nil { - t.Error("stream still exists") - return - } + + assert.Eventually(t, func() bool { + sI, _ := sesh.streams.Load(stream.(*Stream).id) + return sI == nil + }, time.Second, 10*time.Millisecond, "streams still exists") }) } diff --git a/internal/multiplex/switchboard_test.go b/internal/multiplex/switchboard_test.go index e052b55..2c3f36f 100644 --- a/internal/multiplex/switchboard_test.go +++ b/internal/multiplex/switchboard_test.go @@ -2,6 +2,7 @@ package multiplex import ( "github.com/cbeuw/connutil" + "github.com/stretchr/testify/assert" "math/rand" "sync" "testing" @@ -145,11 +146,11 @@ func TestSwitchboard_CloseOnOneDisconn(t *testing.T) { sesh.AddConnection(conn1client) conn0server.Close() - time.Sleep(500 * time.Millisecond) - if !sesh.IsClosed() { - t.Error("session not closed after one conn is disconnected") - return - } + + assert.Eventually(t, func() bool { + return sesh.IsClosed() + }, time.Second, 10*time.Millisecond, "session not closed after one conn is disconnected") + if _, err := conn1client.Write([]byte{0x00}); err == nil { t.Error("the other conn is still connected") return @@ -178,9 +179,7 @@ func TestSwitchboard_ConnsCount(t *testing.T) { sesh.sb.closeAll() - time.Sleep(500 * time.Millisecond) - if sesh.sb.connsCount() != 0 { - t.Error("connsCount incorrect") - } - + assert.Eventuallyf(t, func() bool { + return sesh.sb.connsCount() == 0 + }, time.Second, 10*time.Millisecond, "connsCount incorrect: %v", sesh.sb.connsCount()) } diff --git a/internal/server/dispatcher.go b/internal/server/dispatcher.go index 4fa0698..80ee28c 100644 --- a/internal/server/dispatcher.go +++ b/internal/server/dispatcher.go @@ -190,7 +190,7 @@ func dispatchConnection(conn net.Conn, sta *State) { // adminUID can use the server as normal with unlimited QoS credits. The adminUID is not // added to the userinfo database. The distinction between going into the admin mode // and normal proxy mode is that sessionID needs == 0 for admin mode - if bytes.Equal(ci.UID, sta.AdminUID) && ci.SessionId == 0 { + if len(sta.AdminUID) != 0 && bytes.Equal(ci.UID, sta.AdminUID) && ci.SessionId == 0 { sesh := mux.MakeSession(0, seshConfig) preparedConn, err := finishHandshake(conn, sessionKey, sta.WorldState.Rand) if err != nil { diff --git a/internal/server/state.go b/internal/server/state.go index 66541f5..576e326 100644 --- a/internal/server/state.go +++ b/internal/server/state.go @@ -168,6 +168,10 @@ func InitState(preParse RawConfig, worldState common.WorldState) (sta *State, er return } + if len(preParse.PrivateKey) == 0 { + err = fmt.Errorf("must have a valid private key. Run `ck-server -key` to generate one") + return + } var pv [32]byte copy(pv[:], preParse.PrivateKey) sta.StaticPv = &pv @@ -179,8 +183,10 @@ func InitState(preParse RawConfig, worldState common.WorldState) (sta *State, er copy(arrUID[:], UID) sta.BypassUID[arrUID] = struct{}{} } - copy(arrUID[:], sta.AdminUID) - sta.BypassUID[arrUID] = struct{}{} + if len(sta.AdminUID) != 0 { + copy(arrUID[:], sta.AdminUID) + sta.BypassUID[arrUID] = struct{}{} + } go sta.UsedRandomCleaner() return sta, nil diff --git a/internal/test/integration_test.go b/internal/test/integration_test.go index 1e1fdd0..db58b39 100644 --- a/internal/test/integration_test.go +++ b/internal/test/integration_test.go @@ -10,6 +10,7 @@ import ( mux "github.com/cbeuw/Cloak/internal/multiplex" "github.com/cbeuw/Cloak/internal/server" "github.com/cbeuw/connutil" + "github.com/stretchr/testify/assert" "io" "io/ioutil" "math/rand" @@ -185,7 +186,9 @@ func establishSession(lcc client.LocalConnConfig, rcc client.RemoteConnConfig, a // whatever connection initiator (including a proper ck-client) netToCkServerD, ckServerListener := connutil.DialerListener(10 * 1024) + clientSeshMaker := func() *mux.Session { + ai := ai quad := make([]byte, 4) common.RandRead(ai.WorldState.Rand, quad) ai.SessionId = binary.BigEndian.Uint32(quad) @@ -354,17 +357,9 @@ func TestTCPSingleplex(t *testing.T) { proxyConn1.Close() - retries := 0 -retry: - time.Sleep(delayBeforeTestingConnClose) - if user.NumSession() != 1 { - retries++ - if retries > connCloseRetries { - t.Error("first session was not closed on connection close") - } else { - goto retry - } - } + assert.Eventually(t, func() bool { + return user.NumSession() == 1 + }, time.Second, 10*time.Millisecond, "first session was not closed on connection close") // conn2 should still work runEchoTest(t, []net.Conn{proxyConn2}, 65536) @@ -477,17 +472,10 @@ func TestClosingStreamsFromProxy(t *testing.T) { serverConn, _ := proxyFromCkServerL.Accept() serverConn.Close() - retries := 0 - retry: - time.Sleep(delayBeforeTestingConnClose) - if _, err := clientConn.Read(make([]byte, 16)); err == nil { - retries++ - if retries > connCloseRetries { - t.Errorf("closing stream on server side is not reflected to the client: %v", err) - } else { - goto retry - } - } + assert.Eventually(t, func() bool { + _, err := clientConn.Read(make([]byte, 16)) + return err != nil + }, time.Second, 10*time.Millisecond, "closing stream on server side is not reflected to the client") }) t.Run("closing from client", func(t *testing.T) { @@ -497,17 +485,10 @@ func TestClosingStreamsFromProxy(t *testing.T) { serverConn, _ := proxyFromCkServerL.Accept() clientConn.Close() - retries := 0 - retry: - time.Sleep(delayBeforeTestingConnClose) - if _, err := serverConn.Read(make([]byte, 16)); err == nil { - retries++ - if retries > 3 { - t.Errorf("closing stream on client side is not reflected to the server: %v", err) - } else { - goto retry - } - } + assert.Eventually(t, func() bool { + _, err := serverConn.Read(make([]byte, 16)) + return err != nil + }, time.Second, 10*time.Millisecond, "closing stream on client side is not reflected to the server") }) t.Run("send then close", func(t *testing.T) {