Merge branch 'master' into notsure2

This commit is contained in:
notsure2 2020-12-19 22:36:26 +02:00
commit 3155194ebe
21 changed files with 153 additions and 180 deletions

17
.github/workflows/build.yml vendored Normal file
View File

@ -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

22
.github/workflows/release.yml vendored Normal file
View File

@ -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 }}

View File

@ -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)

View File

@ -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) [![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) [![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) [![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). 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. 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 2. Run `ck-server -key`. The **public** should be given to users, the **private** key should be kept secret.
comma is the **private** key to 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`.
3. Run `ck-server -u`. This will be used as the `AdminUID`.
4. Copy example_config/ckserver.json into a desired location. Change `PrivateKey` to the private key you just obtained; 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. 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 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 ##### 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 ##### Users subject to bandwidth and credit controls

View File

@ -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

View File

@ -169,6 +169,7 @@ func main() {
} }
log.Infof("Listening on %v %v for %v client", network, localConfig.LocalAddr, authInfo.ProxyMethod) log.Infof("Listening on %v %v for %v client", network, localConfig.LocalAddr, authInfo.ProxyMethod)
seshMaker = func() *mux.Session { 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 usergenerated. There shouldn't be a security concern because the scope of
// sessionID is limited to its UID. // sessionID is limited to its UID.
quad := make([]byte, 4) quad := make([]byte, 4)

View File

@ -80,8 +80,11 @@ func main() {
askVersion := flag.Bool("v", false, "Print the version number") askVersion := flag.Bool("v", false, "Print the version number")
printUsage := flag.Bool("h", false, "Print this message") printUsage := flag.Bool("h", false, "Print this message")
genUID := flag.Bool("u", false, "Generate a UID") genUIDScript := flag.Bool("u", false, "Generate a UID to STDOUT")
genKeyPair := flag.Bool("k", false, "Generate a pair of public and private key, output in the format of pubkey,pvkey") genKeyPairScript := flag.Bool("k", false, "Generate a pair of public and private key and output to STDOUT in the format of <public key>,<private key>")
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") pprofAddr := flag.String("d", "", "debug use: ip:port to be listened by pprof profiler")
verbosity := flag.String("verbosity", "info", "verbosity level") verbosity := flag.String("verbosity", "info", "verbosity level")
@ -96,13 +99,23 @@ func main() {
flag.Usage() flag.Usage()
return return
} }
if *genUID { if *genUIDScript || *genUIDHuman {
fmt.Println(generateUID()) uid := generateUID()
if *genUIDScript {
fmt.Println(uid)
} else {
fmt.Printf("\x1B[35mYour UID is:\u001B[0m %s\n", uid)
}
return return
} }
if *genKeyPair { if *genKeyPairScript || *genKeyPairHuman {
pub, pv := generateKeyPair() 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 return
} }

View File

@ -2,8 +2,8 @@
"Transport": "direct", "Transport": "direct",
"ProxyMethod": "shadowsocks", "ProxyMethod": "shadowsocks",
"EncryptionMethod": "plain", "EncryptionMethod": "plain",
"UID": "5nneblJy6lniPJfr81LuYQ==", "UID": "---Your UID here---",
"PublicKey": "IYoUzkle/T/kriE+Ufdm7AHQtIeGnBWbhhlTbmDpUUI=", "PublicKey": "---Public key here---",
"ServerName": "www.bing.com", "ServerName": "www.bing.com",
"NumConn": 4, "NumConn": 4,
"BrowserSig": "chrome", "BrowserSig": "chrome",

View File

@ -18,10 +18,10 @@
":80" ":80"
], ],
"BypassUID": [ "BypassUID": [
"1rmq6Ag1jZJCImLBIL5wzQ==" "---Bypass UID here---"
], ],
"RedirAddr": "204.79.197.200:443", "RedirAddr": "cloudflare.com",
"PrivateKey": "EN5aPEpNBO+vw+BtFQY2OnK9bQU7rvEj5qmnmgwEtUc=", "PrivateKey": "---Private key here---",
"AdminUID": "5nneblJy6lniPJfr81LuYQ==", "AdminUID": "---Admin UID here (optional)---",
"DatabasePath": "userinfo.db" "DatabasePath": "userinfo.db"
} }

2
go.mod
View File

@ -15,7 +15,7 @@ require (
github.com/refraction-networking/utls v0.0.0-20190909200633-43c36d3c1f57 github.com/refraction-networking/utls v0.0.0-20190909200633-43c36d3c1f57
github.com/sirupsen/logrus v1.5.0 github.com/sirupsen/logrus v1.5.0
github.com/stephens2424/writerset v1.0.2 // indirect 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 go.etcd.io/bbolt v1.3.4
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect

5
go.sum
View File

@ -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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= 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.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= 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 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= 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-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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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=

View File

@ -11,7 +11,7 @@ import (
) )
func RouteUDP(bindFunc func() (*net.UDPConn, error), streamTimeout time.Duration, singleplex bool, newSeshFunc func() *mux.Session) { 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() localConn, err := bindFunc()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -27,25 +27,22 @@ func RouteUDP(bindFunc func() (*net.UDPConn, error), streamTimeout time.Duration
continue continue
} }
if !singleplex && (multiplexSession == nil || multiplexSession.IsClosed()) { if !singleplex && (sesh == nil || sesh.IsClosed()) {
multiplexSession = newSeshFunc() sesh = newSeshFunc()
} }
stream, ok := streams[addr.String()] stream, ok := streams[addr.String()]
if !ok { if !ok {
var session *mux.Session if singleplex {
if multiplexSession != nil { sesh = newSeshFunc()
session = multiplexSession
} else {
session = newSeshFunc()
} }
stream, err = session.OpenStream() stream, err = sesh.OpenStream()
if err != nil { if err != nil {
log.Errorf("Failed to open stream: %v", err) if singleplex {
if session.Singleplex { sesh.Close()
session.Close()
} }
log.Errorf("Failed to open stream: %v", err)
continue 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) { func RouteTCP(listener net.Listener, streamTimeout time.Duration, singleplex bool, newSeshFunc func() *mux.Session) {
var multiplexSession *mux.Session var sesh *mux.Session
for { for {
localConn, err := listener.Accept() localConn, err := listener.Accept()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
continue continue
} }
if !singleplex && (multiplexSession == nil || multiplexSession.IsClosed()) { if !singleplex && (sesh == nil || sesh.IsClosed()) {
multiplexSession = newSeshFunc() sesh = newSeshFunc()
} }
go func(multiplexSession *mux.Session, newSingleplexSeshFunc func() *mux.Session, localConn net.Conn, timeout time.Duration) { go func(sesh *mux.Session, localConn net.Conn, timeout time.Duration) {
var session *mux.Session if singleplex {
if multiplexSession != nil { sesh = newSeshFunc()
session = multiplexSession
} else {
session = newSingleplexSeshFunc()
} }
data := make([]byte, 10240) data := make([]byte, 10240)
@ -115,8 +109,8 @@ func RouteTCP(listener net.Listener, streamTimeout time.Duration, singleplex boo
if err != nil { if err != nil {
log.Errorf("Failed to open stream: %v", err) log.Errorf("Failed to open stream: %v", err)
localConn.Close() localConn.Close()
if session.Singleplex { if singleplex {
session.Close() sesh.Close()
} }
return return
} }

View File

@ -76,7 +76,7 @@ func TestDatagramBuffer_BlockingRead(t *testing.T) {
pipe := NewDatagramBufferedPipe() pipe := NewDatagramBufferedPipe()
b := []byte{0x01, 0x02, 0x03} b := []byte{0x01, 0x02, 0x03}
go func() { go func() {
time.Sleep(100 * time.Millisecond) time.Sleep(readBlockTime)
pipe.Write(Frame{Payload: b}) pipe.Write(Frame{Payload: b})
}() }()
b2 := make([]byte, len(b)) b2 := make([]byte, len(b))

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"github.com/cbeuw/Cloak/internal/common" "github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/connutil" "github.com/cbeuw/connutil"
"github.com/stretchr/testify/assert"
"io" "io"
"math/rand" "math/rand"
"net" "net"
@ -111,12 +112,14 @@ func TestMultiplex(t *testing.T) {
//test echo //test echo
runEchoTest(t, streams, maxMsgLen) runEchoTest(t, streams, maxMsgLen)
if clientSession.streamCount() != numStreams {
t.Errorf("client stream count is wrong: %v", clientSession.streamCount()) assert.Eventuallyf(t, func() bool {
} return clientSession.streamCount() == numStreams
if serverSession.streamCount() != numStreams { }, time.Second, 10*time.Millisecond, "client stream count is wrong: %v", clientSession.streamCount())
t.Errorf("server stream count is wrong: %v", serverSession.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 // close one stream
closing, streams := streams[0], streams[1:] 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) 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() _ = toBeClosed.Close()
_, err = io.ReadFull(toBeClosed, recvBuf) _, err = io.ReadFull(toBeClosed, recvBuf[1:])
if err != nil { if err != nil {
t.Errorf("can't read residual data on stream: %v", err) t.Errorf("can't read residual data on stream: %v", err)
} }

View File

@ -3,6 +3,7 @@ package multiplex
import ( import (
"bytes" "bytes"
"github.com/cbeuw/connutil" "github.com/cbeuw/connutil"
"github.com/stretchr/testify/assert"
"math/rand" "math/rand"
"strconv" "strconv"
"sync" "sync"
@ -408,10 +409,10 @@ func TestSession_timeoutAfter(t *testing.T) {
seshConfigOrdered.Obfuscator = obfuscator seshConfigOrdered.Obfuscator = obfuscator
seshConfigOrdered.InactivityTimeout = 100 * time.Millisecond seshConfigOrdered.InactivityTimeout = 100 * time.Millisecond
sesh := MakeSession(0, seshConfigOrdered) sesh := MakeSession(0, seshConfigOrdered)
time.Sleep(200 * time.Millisecond)
if !sesh.IsClosed() { assert.Eventually(t, func() bool {
t.Error("session should have timed out") return sesh.IsClosed()
} }, 5*seshConfigOrdered.InactivityTimeout, seshConfigOrdered.InactivityTimeout, "session should have timed out")
} }
func BenchmarkRecvDataFromRemote_Ordered(b *testing.B) { func BenchmarkRecvDataFromRemote_Ordered(b *testing.B) {

View File

@ -7,6 +7,8 @@ import (
"time" "time"
) )
const readBlockTime = 500 * time.Millisecond
func TestPipeRW(t *testing.T) { func TestPipeRW(t *testing.T) {
pipe := NewStreamBufferedPipe() pipe := NewStreamBufferedPipe()
b := []byte{0x01, 0x02, 0x03} b := []byte{0x01, 0x02, 0x03}
@ -60,7 +62,7 @@ func TestReadBlock(t *testing.T) {
pipe := NewStreamBufferedPipe() pipe := NewStreamBufferedPipe()
b := []byte{0x01, 0x02, 0x03} b := []byte{0x01, 0x02, 0x03}
go func() { go func() {
time.Sleep(100 * time.Millisecond) time.Sleep(readBlockTime)
pipe.Write(b) pipe.Write(b)
}() }()
b2 := make([]byte, len(b)) b2 := make([]byte, len(b))

View File

@ -3,6 +3,7 @@ package multiplex
import ( import (
"bytes" "bytes"
"github.com/cbeuw/Cloak/internal/common" "github.com/cbeuw/Cloak/internal/common"
"github.com/stretchr/testify/assert"
"io" "io"
"io/ioutil" "io/ioutil"
"math/rand" "math/rand"
@ -230,11 +231,11 @@ func TestStream_Close(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("can't read residual data %v", err) t.Errorf("can't read residual data %v", err)
} }
time.Sleep(100 * time.Millisecond)
if sI, _ := sesh.streams.Load(stream.(*Stream).id); sI != nil { assert.Eventually(t, func() bool {
t.Error("stream still exists") sI, _ := sesh.streams.Load(stream.(*Stream).id)
return return sI == nil
} }, time.Second, 10*time.Millisecond, "streams still exists")
}) })
} }

View File

@ -2,6 +2,7 @@ package multiplex
import ( import (
"github.com/cbeuw/connutil" "github.com/cbeuw/connutil"
"github.com/stretchr/testify/assert"
"math/rand" "math/rand"
"sync" "sync"
"testing" "testing"
@ -145,11 +146,11 @@ func TestSwitchboard_CloseOnOneDisconn(t *testing.T) {
sesh.AddConnection(conn1client) sesh.AddConnection(conn1client)
conn0server.Close() conn0server.Close()
time.Sleep(500 * time.Millisecond)
if !sesh.IsClosed() { assert.Eventually(t, func() bool {
t.Error("session not closed after one conn is disconnected") return sesh.IsClosed()
return }, time.Second, 10*time.Millisecond, "session not closed after one conn is disconnected")
}
if _, err := conn1client.Write([]byte{0x00}); err == nil { if _, err := conn1client.Write([]byte{0x00}); err == nil {
t.Error("the other conn is still connected") t.Error("the other conn is still connected")
return return
@ -178,9 +179,7 @@ func TestSwitchboard_ConnsCount(t *testing.T) {
sesh.sb.closeAll() sesh.sb.closeAll()
time.Sleep(500 * time.Millisecond) assert.Eventuallyf(t, func() bool {
if sesh.sb.connsCount() != 0 { return sesh.sb.connsCount() == 0
t.Error("connsCount incorrect") }, time.Second, 10*time.Millisecond, "connsCount incorrect: %v", sesh.sb.connsCount())
}
} }

View File

@ -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 // 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 // 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 // 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) sesh := mux.MakeSession(0, seshConfig)
preparedConn, err := finishHandshake(conn, sessionKey, sta.WorldState.Rand) preparedConn, err := finishHandshake(conn, sessionKey, sta.WorldState.Rand)
if err != nil { if err != nil {

View File

@ -168,6 +168,10 @@ func InitState(preParse RawConfig, worldState common.WorldState) (sta *State, er
return 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 var pv [32]byte
copy(pv[:], preParse.PrivateKey) copy(pv[:], preParse.PrivateKey)
sta.StaticPv = &pv sta.StaticPv = &pv
@ -179,8 +183,10 @@ func InitState(preParse RawConfig, worldState common.WorldState) (sta *State, er
copy(arrUID[:], UID) copy(arrUID[:], UID)
sta.BypassUID[arrUID] = struct{}{} sta.BypassUID[arrUID] = struct{}{}
} }
if len(sta.AdminUID) != 0 {
copy(arrUID[:], sta.AdminUID) copy(arrUID[:], sta.AdminUID)
sta.BypassUID[arrUID] = struct{}{} sta.BypassUID[arrUID] = struct{}{}
}
go sta.UsedRandomCleaner() go sta.UsedRandomCleaner()
return sta, nil return sta, nil

View File

@ -10,6 +10,7 @@ import (
mux "github.com/cbeuw/Cloak/internal/multiplex" mux "github.com/cbeuw/Cloak/internal/multiplex"
"github.com/cbeuw/Cloak/internal/server" "github.com/cbeuw/Cloak/internal/server"
"github.com/cbeuw/connutil" "github.com/cbeuw/connutil"
"github.com/stretchr/testify/assert"
"io" "io"
"io/ioutil" "io/ioutil"
"math/rand" "math/rand"
@ -185,7 +186,9 @@ func establishSession(lcc client.LocalConnConfig, rcc client.RemoteConnConfig, a
// whatever connection initiator (including a proper ck-client) // whatever connection initiator (including a proper ck-client)
netToCkServerD, ckServerListener := connutil.DialerListener(10 * 1024) netToCkServerD, ckServerListener := connutil.DialerListener(10 * 1024)
clientSeshMaker := func() *mux.Session { clientSeshMaker := func() *mux.Session {
ai := ai
quad := make([]byte, 4) quad := make([]byte, 4)
common.RandRead(ai.WorldState.Rand, quad) common.RandRead(ai.WorldState.Rand, quad)
ai.SessionId = binary.BigEndian.Uint32(quad) ai.SessionId = binary.BigEndian.Uint32(quad)
@ -354,17 +357,9 @@ func TestTCPSingleplex(t *testing.T) {
proxyConn1.Close() proxyConn1.Close()
retries := 0 assert.Eventually(t, func() bool {
retry: return user.NumSession() == 1
time.Sleep(delayBeforeTestingConnClose) }, time.Second, 10*time.Millisecond, "first session was not closed on connection close")
if user.NumSession() != 1 {
retries++
if retries > connCloseRetries {
t.Error("first session was not closed on connection close")
} else {
goto retry
}
}
// conn2 should still work // conn2 should still work
runEchoTest(t, []net.Conn{proxyConn2}, 65536) runEchoTest(t, []net.Conn{proxyConn2}, 65536)
@ -477,17 +472,10 @@ func TestClosingStreamsFromProxy(t *testing.T) {
serverConn, _ := proxyFromCkServerL.Accept() serverConn, _ := proxyFromCkServerL.Accept()
serverConn.Close() serverConn.Close()
retries := 0 assert.Eventually(t, func() bool {
retry: _, err := clientConn.Read(make([]byte, 16))
time.Sleep(delayBeforeTestingConnClose) return err != nil
if _, err := clientConn.Read(make([]byte, 16)); err == nil { }, time.Second, 10*time.Millisecond, "closing stream on server side is not reflected to the client")
retries++
if retries > connCloseRetries {
t.Errorf("closing stream on server side is not reflected to the client: %v", err)
} else {
goto retry
}
}
}) })
t.Run("closing from client", func(t *testing.T) { t.Run("closing from client", func(t *testing.T) {
@ -497,17 +485,10 @@ func TestClosingStreamsFromProxy(t *testing.T) {
serverConn, _ := proxyFromCkServerL.Accept() serverConn, _ := proxyFromCkServerL.Accept()
clientConn.Close() clientConn.Close()
retries := 0 assert.Eventually(t, func() bool {
retry: _, err := serverConn.Read(make([]byte, 16))
time.Sleep(delayBeforeTestingConnClose) return err != nil
if _, err := serverConn.Read(make([]byte, 16)); err == nil { }, time.Second, 10*time.Millisecond, "closing stream on client side is not reflected to the server")
retries++
if retries > 3 {
t.Errorf("closing stream on client side is not reflected to the server: %v", err)
} else {
goto retry
}
}
}) })
t.Run("send then close", func(t *testing.T) { t.Run("send then close", func(t *testing.T) {