Compare commits

..

No commits in common. 'master' and 'v2.6.0' have entirely different histories.

@ -10,7 +10,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '^1.22' # The Go version to download (if necessary) and use.
go-version: '^1.17' # 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:

@ -137,7 +137,7 @@ random-like. **You may only leave it as `plain` if you are certain that your und
encryption and authentication (via AEAD or similar techniques).**
`ServerName` is the domain you want to make your ISP or firewall _think_ you are visiting. Ideally it should
match `RedirAddr` in the server's configuration, a major site the censor allows, but it doesn't have to. Use `random` to randomize the server name for every connection made.
match `RedirAddr` in the server's configuration, a major site the censor allows, but it doesn't have to.
`AlternativeNames` is an array used alongside `ServerName` to shuffle between different ServerNames for every new
connection. **This may conflict with `CDN` Transport mode** if the CDN provider prohibits domain fronting and rejects
@ -155,13 +155,8 @@ Example:
`CDNOriginHost` is the domain name of the _origin_ server (i.e. the server running Cloak) under `CDN` mode. This only
has effect when `Transport` is set to `CDN`. If unset, it will default to the remote hostname supplied via the
commandline argument (in standalone mode), or by Shadowsocks (in plugin mode). After a TLS session is established with
the CDN server, this domain name will be used in the `Host` header of the HTTP request to ask the CDN server to
establish a WebSocket connection with this host.
`CDNWsUrlPath` is the url path used to build websocket request sent under `CDN` mode, and also only has effect
when `Transport` is set to `CDN`. If unset, it will default to "/". This option is used to build the first line of the
HTTP request after a TLS session is extablished. It's mainly for a Cloak server behind a reverse proxy, while only
requests under specific url path are forwarded.
the CDN server, this domain name will be used in the HTTP request to ask the CDN server to establish a WebSocket
connection with this host.
`NumConn` is the amount of underlying TCP connections you want to use. The default of 4 should be appropriate for most
people. Setting it too high will hinder the performance. Setting it to 0 will disable connection multiplexing and each
@ -169,7 +164,7 @@ TCP connection will spawn a separate short-lived session that will be closed aft
behave like GoQuiet. This maybe useful for people with unstable connections.
`BrowserSig` is the browser you want to **appear** to be using. It's not relevant to the browser you are actually using.
Currently, `chrome`, `firefox` and `safari` are supported.
Currently, `chrome` and `firefox` are supported.
`KeepAlive` is the number of seconds to tell the OS to wait after no activity before sending TCP KeepAlive probes to the
Cloak server. Zero or negative value disables it. Default is 0 (disabled). Warning: Enabling it might make your server

@ -1,4 +1,3 @@
//go:build go1.11
// +build go1.11
package main
@ -8,11 +7,10 @@ import (
"encoding/binary"
"flag"
"fmt"
"github.com/cbeuw/Cloak/internal/common"
"net"
"os"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/client"
mux "github.com/cbeuw/Cloak/internal/multiplex"
log "github.com/sirupsen/logrus"

@ -1,4 +1,3 @@
//go:build !android
// +build !android
package main

@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build android
// +build android
package main
@ -29,10 +28,9 @@ import "C"
import (
"bufio"
log "github.com/sirupsen/logrus"
"os"
"unsafe"
log "github.com/sirupsen/logrus"
)
var (

@ -1,4 +1,3 @@
//go:build !android
// +build !android
package main

@ -1,4 +1,3 @@
//go:build android
// +build android
package main
@ -66,9 +65,8 @@ void set_timeout(int sock) {
import "C"
import (
"syscall"
log "github.com/sirupsen/logrus"
"syscall"
)
// In Android, once an app starts the VpnService, all outgoing traffic are routed by the system

@ -3,16 +3,15 @@ package main
import (
"flag"
"fmt"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/server"
log "github.com/sirupsen/logrus"
"net"
"net/http"
_ "net/http/pprof"
"os"
"runtime"
"strings"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/server"
log "github.com/sirupsen/logrus"
)
var version string

@ -1,10 +1,9 @@
package main
import (
"github.com/stretchr/testify/assert"
"net"
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseBindAddr(t *testing.T) {

@ -3,7 +3,6 @@ package main
import (
"crypto/rand"
"encoding/base64"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/ecdh"
)

@ -1,4 +1,5 @@
coverage:
status:
project: off
patch: off
project:
default:
threshold: 1%

@ -1,30 +1,18 @@
module github.com/cbeuw/Cloak
go 1.21
toolchain go1.22.2
go 1.14
require (
github.com/cbeuw/connutil v0.0.0-20200411215123-966bfaa51ee3
github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.1
github.com/juju/ratelimit v1.0.2
github.com/refraction-networking/utls v1.6.6
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0
go.etcd.io/bbolt v1.3.9
golang.org/x/crypto v0.22.0
)
require (
github.com/andybalholm/brotli v1.0.6 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/klauspost/compress v1.17.4 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sys v0.19.0 // indirect
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.4.2
github.com/juju/ratelimit v1.0.1
github.com/kr/pretty v0.1.0 // indirect
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.6.1
gitlab.com/yawning/utls.git v0.0.12-1
go.etcd.io/bbolt v1.3.6
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

@ -1,56 +1,60 @@
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/cbeuw/connutil v0.0.0-20200411215123-966bfaa51ee3 h1:LRxW8pdmWmyhoNh+TxUjxsAinGtCsVGjsl3xg6zoRSs=
github.com/cbeuw/connutil v0.0.0-20200411215123-966bfaa51ee3/go.mod h1:6jR2SzckGv8hIIS9zWJ160mzGVVOYp4AXZMDtacL6LE=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI=
github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/juju/ratelimit v1.0.1 h1:+7AIFJVQ0EQgq/K9+0Krm7m530Du7tIz0METWzN0RgY=
github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/refraction-networking/utls v1.6.4 h1:aeynTroaYn7y+mFtqv8D0bQ4bw0y9nJHneGxJ7lvRDM=
github.com/refraction-networking/utls v1.6.4/go.mod h1:2VL2xfiqgFAZtJKeUTlf+PSYFs3Eu7km0gCtXJ3m8zs=
github.com/refraction-networking/utls v1.6.6 h1:igFsYBUJPYM8Rno9xUuDoM5GQrVEqY4llzEXOkL43Ig=
github.com/refraction-networking/utls v1.6.6/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
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/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo=
gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ=
gitlab.com/yawning/utls.git v0.0.12-1 h1:RL6O0MP2YI0KghuEU/uGN6+8b4183eqNWoYgx7CXD0U=
gitlab.com/yawning/utls.git v0.0.12-1/go.mod h1:3ONKiSFR9Im/c3t5RKmMJTVdmZN496FNyk3mjrY1dyo=
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

@ -1,11 +1,10 @@
package client
import (
"encoding/binary"
"github.com/cbeuw/Cloak/internal/common"
utls "github.com/refraction-networking/utls"
log "github.com/sirupsen/logrus"
"net"
"strings"
)
const appDataMaxLength = 16401
@ -17,122 +16,55 @@ type clientHelloFields struct {
serverName string
}
type browser int
const (
chrome = iota
firefox
safari
)
type DirectTLS struct {
*common.TLSConn
browser browser
type browser interface {
composeClientHello(clientHelloFields) []byte
}
var topLevelDomains = []string{"com", "net", "org", "it", "fr", "me", "ru", "cn", "es", "tr", "top", "xyz", "info"}
func randomServerName() string {
/*
Copyright: Proton AG
https://github.com/ProtonVPN/wireguard-go/commit/bcf344b39b213c1f32147851af0d2a8da9266883
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
charNum := int('z') - int('a') + 1
size := 3 + common.RandInt(10)
name := make([]byte, size)
for i := range name {
name[i] = byte(int('a') + common.RandInt(charNum))
}
return string(name) + "." + common.RandItem(topLevelDomains)
func generateSNI(serverName string) []byte {
serverNameListLength := make([]byte, 2)
binary.BigEndian.PutUint16(serverNameListLength, uint16(len(serverName)+3))
serverNameType := []byte{0x00} // host_name
serverNameLength := make([]byte, 2)
binary.BigEndian.PutUint16(serverNameLength, uint16(len(serverName)))
ret := make([]byte, 2+1+2+len(serverName))
copy(ret[0:2], serverNameListLength)
copy(ret[2:3], serverNameType)
copy(ret[3:5], serverNameLength)
copy(ret[5:], serverName)
return ret
}
func buildClientHello(browser browser, fields clientHelloFields) ([]byte, error) {
// We don't use utls to handle connections (as it'll attempt a real TLS negotiation)
// We only want it to build the ClientHello locally
fakeConn := net.TCPConn{}
var helloID utls.ClientHelloID
switch browser {
case chrome:
helloID = utls.HelloChrome_Auto
case firefox:
helloID = utls.HelloFirefox_Auto
case safari:
helloID = utls.HelloSafari_Auto
}
uclient := utls.UClient(&fakeConn, &utls.Config{ServerName: fields.serverName}, helloID)
if err := uclient.BuildHandshakeState(); err != nil {
return []byte{}, err
}
if err := uclient.SetClientRandom(fields.random); err != nil {
return []byte{}, err
}
uclient.HandshakeState.Hello.SessionId = make([]byte, 32)
copy(uclient.HandshakeState.Hello.SessionId, fields.sessionId)
// Find the X25519 key share and overwrite it
var extIndex int
var keyShareIndex int
for i, ext := range uclient.Extensions {
ext, ok := ext.(*utls.KeyShareExtension)
if ok {
extIndex = i
for j, keyShare := range ext.KeyShares {
if keyShare.Group == utls.X25519 {
keyShareIndex = j
}
}
}
}
copy(uclient.Extensions[extIndex].(*utls.KeyShareExtension).KeyShares[keyShareIndex].Data, fields.x25519KeyShare)
// addExtensionRecord, add type, length to extension data
func addExtRec(typ []byte, data []byte) []byte {
length := make([]byte, 2)
binary.BigEndian.PutUint16(length, uint16(len(data)))
ret := make([]byte, 2+2+len(data))
copy(ret[0:2], typ)
copy(ret[2:4], length)
copy(ret[4:], data)
return ret
}
if err := uclient.BuildHandshakeState(); err != nil {
return []byte{}, err
}
return uclient.HandshakeState.Hello.Raw, nil
type DirectTLS struct {
*common.TLSConn
browser browser
}
// Handshake handles the TLS handshake for a given conn and returns the sessionKey
// NewClientTransport handles the TLS handshake for a given conn and returns the sessionKey
// if the server proceed with Cloak authentication
func (tls *DirectTLS) Handshake(rawConn net.Conn, authInfo AuthInfo) (sessionKey [32]byte, err error) {
payload, sharedSecret := makeAuthenticationPayload(authInfo)
// random is marshalled ephemeral pub key 32 bytes
// The authentication ciphertext and its tag are then distributed among SessionId and X25519KeyShare
fields := clientHelloFields{
random: payload.randPubKey[:],
sessionId: payload.ciphertextWithTag[0:32],
x25519KeyShare: payload.ciphertextWithTag[32:64],
serverName: authInfo.MockDomain,
}
if strings.EqualFold(fields.serverName, "random") {
fields.serverName = randomServerName()
}
var ch []byte
ch, err = buildClientHello(tls.browser, fields)
if err != nil {
return
}
chWithRecordLayer := common.AddRecordLayer(ch, common.Handshake, common.VersionTLS11)
chOnly := tls.browser.composeClientHello(fields)
chWithRecordLayer := common.AddRecordLayer(chOnly, common.Handshake, common.VersionTLS11)
_, err = rawConn.Write(chWithRecordLayer)
if err != nil {
return

@ -0,0 +1,38 @@
package client
import (
"encoding/hex"
"github.com/stretchr/testify/assert"
"testing"
)
func htob(s string) []byte {
b, _ := hex.DecodeString(s)
return b
}
func TestMakeServerName(t *testing.T) {
type testingPair struct {
serverName string
target []byte
}
pairs := []testingPair{
{
"www.google.com",
htob("001100000e7777772e676f6f676c652e636f6d"),
},
{
"www.gstatic.com",
htob("001200000f7777772e677374617469632e636f6d"),
},
{
"googleads.g.doubleclick.net",
htob("001e00001b676f6f676c656164732e672e646f75626c65636c69636b2e6e6574"),
},
}
for _, p := range pairs {
assert.Equal(t, p.target, generateSNI(p.serverName))
}
}

@ -2,7 +2,6 @@ package client
import (
"encoding/binary"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/ecdh"
log "github.com/sirupsen/logrus"

@ -2,12 +2,11 @@ package client
import (
"bytes"
"testing"
"time"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/multiplex"
"github.com/stretchr/testify/assert"
"testing"
"time"
)
func TestMakeAuthenticationPayload(t *testing.T) {

@ -0,0 +1,105 @@
// Fingerprint of Chrome 99
package client
import (
"encoding/binary"
"encoding/hex"
"github.com/cbeuw/Cloak/internal/common"
)
type Chrome struct{}
func makeGREASE() []byte {
// see https://tools.ietf.org/html/draft-davidben-tls-grease-01
// This is exclusive to Chrome.
var one [1]byte
common.CryptoRandRead(one[:])
sixteenth := one[0] % 16
monoGREASE := sixteenth*16 + 0xA
doubleGREASE := []byte{monoGREASE, monoGREASE}
return doubleGREASE
}
func (c *Chrome) composeExtensions(serverName string, keyShare []byte) []byte {
makeSupportedGroups := func() []byte {
suppGroupListLen := []byte{0x00, 0x08}
ret := make([]byte, 2+8)
copy(ret[0:2], suppGroupListLen)
copy(ret[2:4], makeGREASE())
copy(ret[4:], []byte{0x00, 0x1d, 0x00, 0x17, 0x00, 0x18})
return ret
}
makeKeyShare := func(hidden []byte) []byte {
ret := make([]byte, 43)
ret[0], ret[1] = 0x00, 0x29 // length 41
copy(ret[2:4], makeGREASE())
ret[4], ret[5] = 0x00, 0x01 // length 1
ret[6] = 0x00
ret[7], ret[8] = 0x00, 0x1d // group x25519
ret[9], ret[10] = 0x00, 0x20 // length 32
copy(ret[11:43], hidden)
return ret
}
// extension length is always 403, and server name length is variable
var ext [18][]byte
ext[0] = addExtRec(makeGREASE(), nil) // First GREASE
ext[1] = addExtRec([]byte{0x00, 0x00}, generateSNI(serverName)) // server name indication
ext[2] = addExtRec([]byte{0x00, 0x17}, nil) // extended_master_secret
ext[3] = addExtRec([]byte{0xff, 0x01}, []byte{0x00}) // renegotiation_info
ext[4] = addExtRec([]byte{0x00, 0x0a}, makeSupportedGroups()) // supported groups
ext[5] = addExtRec([]byte{0x00, 0x0b}, []byte{0x01, 0x00}) // ec point formats
ext[6] = addExtRec([]byte{0x00, 0x23}, nil) // Session tickets
ALPN, _ := hex.DecodeString("000c02683208687474702f312e31")
ext[7] = addExtRec([]byte{0x00, 0x10}, ALPN) // app layer proto negotiation
ext[8] = addExtRec([]byte{0x00, 0x05}, []byte{0x01, 0x00, 0x00, 0x00, 0x00}) // status request
sigAlgo, _ := hex.DecodeString("001004030804040105030805050108060601")
ext[9] = addExtRec([]byte{0x00, 0x0d}, sigAlgo) // Signature Algorithms
ext[10] = addExtRec([]byte{0x00, 0x12}, nil) // signed cert timestamp
ext[11] = addExtRec([]byte{0x00, 0x33}, makeKeyShare(keyShare)) // key share
ext[12] = addExtRec([]byte{0x00, 0x2d}, []byte{0x01, 0x01}) // psk key exchange modes
suppVersions, _ := hex.DecodeString("069A9A03040303") // 9A9A needs to be a GREASE
copy(suppVersions[1:3], makeGREASE())
ext[13] = addExtRec([]byte{0x00, 0x2b}, suppVersions) // supported versions
ext[14] = addExtRec([]byte{0x00, 0x1b}, []byte{0x02, 0x00, 0x02}) // compress certificate
applicationSettings, _ := hex.DecodeString("0003026832")
ext[15] = addExtRec([]byte{0x44, 0x69}, applicationSettings) // application settings
ext[16] = addExtRec(makeGREASE(), []byte{0x00}) // Last GREASE
// len(ext[1]) + 175 + len(ext[16]) = 403
// len(ext[16]) = 228 - len(ext[1])
// 2+2+len(padding) = 228 - len(ext[1])
// len(padding) = 224 - len(ext[1])
ext[17] = addExtRec([]byte{0x00, 0x15}, make([]byte, 224-len(ext[1]))) // padding
var ret []byte
for _, e := range ext {
ret = append(ret, e...)
}
return ret
}
func (c *Chrome) composeClientHello(hd clientHelloFields) (ch []byte) {
var clientHello [12][]byte
clientHello[0] = []byte{0x01} // handshake type
clientHello[1] = []byte{0x00, 0x01, 0xfc} // length 508
clientHello[2] = []byte{0x03, 0x03} // client version
clientHello[3] = hd.random // random
clientHello[4] = []byte{0x20} // session id length 32
clientHello[5] = hd.sessionId // session id
clientHello[6] = []byte{0x00, 0x20} // cipher suites length 32
cipherSuites, _ := hex.DecodeString("130113021303c02bc02fc02cc030cca9cca8c013c014009c009d002f0035")
clientHello[7] = append(makeGREASE(), cipherSuites...) // cipher suites
clientHello[8] = []byte{0x01} // compression methods length 1
clientHello[9] = []byte{0x00} // compression methods
clientHello[11] = c.composeExtensions(hd.serverName, hd.x25519KeyShare)
clientHello[10] = []byte{0x00, 0x00} // extensions length 403
binary.BigEndian.PutUint16(clientHello[10], uint16(len(clientHello[11])))
var ret []byte
for _, c := range clientHello {
ret = append(ret, c...)
}
return ret
}

@ -0,0 +1,46 @@
package client
import (
"encoding/hex"
"testing"
)
func TestMakeGREASE(t *testing.T) {
a := hex.EncodeToString(makeGREASE())
if a[1] != 'a' || a[3] != 'a' {
t.Errorf("GREASE got %v", a)
}
var GREASEs []string
for i := 0; i < 50; i++ {
GREASEs = append(GREASEs, hex.EncodeToString(makeGREASE()))
}
var eqCount int
for _, g := range GREASEs {
if a == g {
eqCount++
}
}
if eqCount > 40 {
t.Error("GREASE is not random", GREASEs)
}
}
func TestComposeExtension(t *testing.T) {
serverName := "github.com"
keyShare, _ := hex.DecodeString("690f074f5c01756982269b66d58c90c47dc0f281d654c7b2c16f63c9033f5604")
result := (&Chrome{}).composeExtensions(serverName, keyShare)
target, _ := hex.DecodeString("3a3a00000000000f000d00000a6769746875622e636f6d00170000ff01000100000a000a00080a0a001d00170018000b00020100002300000010000e000c02683208687474702f312e31000500050100000000000d0012001004030804040105030805050108060601001200000033002b00296a6a000100001d0020690f074f5c01756982269b66d58c90c47dc0f281d654c7b2c16f63c9033f5604002d00020101002b000706dada03040303001b0003020002446900050003026832eaea000100001500cd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
for p := 0; p < len(result); p++ {
if result[p] != target[p] {
if result[p]&0x0F == 0xA && target[p]&0x0F == 0xA &&
((p > 0 && result[p-1] == result[p] && target[p-1] == target[p]) ||
(p < len(result)-1 && result[p+1] == result[p] && target[p+1] == target[p])) {
continue
}
t.Errorf("inequality at %v", p)
}
}
}

@ -1,13 +1,12 @@
package client
import (
"github.com/cbeuw/Cloak/internal/common"
"net"
"sync"
"sync/atomic"
"time"
"github.com/cbeuw/Cloak/internal/common"
mux "github.com/cbeuw/Cloak/internal/multiplex"
log "github.com/sirupsen/logrus"
)
@ -34,8 +33,8 @@ func MakeSession(connConfig RemoteConnConfig, authInfo AuthInfo, dialer common.D
transportConn := connConfig.TransportMaker()
sk, err := transportConn.Handshake(remoteConn, authInfo)
if err != nil {
log.Errorf("Failed to prepare connection to remote: %v", err)
transportConn.Close()
log.Errorf("Failed to prepare connection to remote: %v", err)
time.Sleep(time.Second * 3)
goto makeconn
}

@ -0,0 +1,79 @@
// Fingerprint of Firefox 99
package client
import (
"encoding/binary"
"encoding/hex"
"github.com/cbeuw/Cloak/internal/common"
)
type Firefox struct{}
func (f *Firefox) composeExtensions(serverName string, keyShare []byte) []byte {
composeKeyShare := func(hidden []byte) []byte {
ret := make([]byte, 107)
ret[0], ret[1] = 0x00, 0x69 // length 105
ret[2], ret[3] = 0x00, 0x1d // group x25519
ret[4], ret[5] = 0x00, 0x20 // length 32
copy(ret[6:38], hidden)
ret[38], ret[39] = 0x00, 0x17 // group secp256r1
ret[40], ret[41] = 0x00, 0x41 // length 65
common.CryptoRandRead(ret[42:107])
return ret
}
// extension length is always 401, and server name length is variable
var ext [15][]byte
ext[0] = addExtRec([]byte{0x00, 0x00}, generateSNI(serverName)) // server name indication
ext[1] = addExtRec([]byte{0x00, 0x17}, nil) // extended_master_secret
ext[2] = addExtRec([]byte{0xff, 0x01}, []byte{0x00}) // renegotiation_info
suppGroup, _ := hex.DecodeString("000c001d00170018001901000101")
ext[3] = addExtRec([]byte{0x00, 0x0a}, suppGroup) // supported groups
ext[4] = addExtRec([]byte{0x00, 0x0b}, []byte{0x01, 0x00}) // ec point formats
ext[5] = addExtRec([]byte{0x00, 0x23}, nil) // session ticket
ALPN, _ := hex.DecodeString("000c02683208687474702f312e31")
ext[6] = addExtRec([]byte{0x00, 0x10}, ALPN) // app layer proto negotiation
ext[7] = addExtRec([]byte{0x00, 0x05}, []byte{0x01, 0x00, 0x00, 0x00, 0x00}) // status request
delegatedCredentials, _ := hex.DecodeString("00080403050306030203")
ext[8] = addExtRec([]byte{0x00, 0x22}, delegatedCredentials) // delegated credentials
ext[9] = addExtRec([]byte{0x00, 0x33}, composeKeyShare(keyShare)) // key share
suppVersions, _ := hex.DecodeString("0403040303")
ext[10] = addExtRec([]byte{0x00, 0x2b}, suppVersions) // supported versions
sigAlgo, _ := hex.DecodeString("001604030503060308040805080604010501060102030201")
ext[11] = addExtRec([]byte{0x00, 0x0d}, sigAlgo) // Signature Algorithms
ext[12] = addExtRec([]byte{0x00, 0x2d}, []byte{0x01, 0x01}) // psk key exchange modes
ext[13] = addExtRec([]byte{0x00, 0x1c}, []byte{0x40, 0x01}) // record size limit
// len(ext[0]) + 238 + 4 + len(padding) = 401
// len(padding) = 177 - len(ext[0])
ext[14] = addExtRec([]byte{0x00, 0x15}, make([]byte, 159-len(ext[0]))) // padding
var ret []byte
for _, e := range ext {
ret = append(ret, e...)
}
return ret
}
func (f *Firefox) composeClientHello(hd clientHelloFields) (ch []byte) {
var clientHello [12][]byte
clientHello[0] = []byte{0x01} // handshake type
clientHello[1] = []byte{0x00, 0x01, 0xfc} // length 508
clientHello[2] = []byte{0x03, 0x03} // client version
clientHello[3] = hd.random // random
clientHello[4] = []byte{0x20} // session id length 32
clientHello[5] = hd.sessionId // session id
clientHello[6] = []byte{0x00, 0x22} // cipher suites length 34
cipherSuites, _ := hex.DecodeString("130113031302c02bc02fcca9cca8c02cc030c00ac009c013c014009c009d002f0035")
clientHello[7] = cipherSuites // cipher suites
clientHello[8] = []byte{0x01} // compression methods length 1
clientHello[9] = []byte{0x00} // compression methods
clientHello[11] = f.composeExtensions(hd.serverName, hd.x25519KeyShare)
clientHello[10] = []byte{0x00, 0x00} // extensions length
binary.BigEndian.PutUint16(clientHello[10], uint16(len(clientHello[11])))
var ret []byte
for _, c := range clientHello {
ret = append(ret, c...)
}
return ret
}

@ -0,0 +1,20 @@
package client
import (
"bytes"
"encoding/hex"
"testing"
)
func TestComposeExtensions(t *testing.T) {
target, _ := hex.DecodeString("000000170015000012636f6e73656e742e676f6f676c652e636f6d00170000ff01000100000a000e000c001d00170018001901000101000b00020100002300000010000e000c02683208687474702f312e310005000501000000000022000a000804030503060302030033006b0069001d00208d8ea1b80430b7710b65f0d89b0144a5eeb218709ce6613d4fc8bfb117657c1500170041947458330e3553dcde0a8741eb1dde26ebaee8262029c5edb3cbacc9ee1d7c866085b9cf483d943248997a65c5fa1d35725213895d0e5569d4e291863061b7d075002b00050403040303000d0018001604030503060308040805080604010501060102030201002d00020101001c0002400100150084000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
serverName := "consent.google.com"
keyShare, _ := hex.DecodeString("8d8ea1b80430b7710b65f0d89b0144a5eeb218709ce6613d4fc8bfb117657c15")
result := (&Firefox{}).composeExtensions(serverName, keyShare)
// skip random secp256r1
if !bytes.Equal(result[:151], target[:151]) || !bytes.Equal(result[216:], target[216:]) {
t.Errorf("got %x", result)
}
}

@ -1,13 +1,12 @@
package client
import (
"github.com/cbeuw/Cloak/internal/common"
"io"
"net"
"sync"
"time"
"github.com/cbeuw/Cloak/internal/common"
mux "github.com/cbeuw/Cloak/internal/multiplex"
log "github.com/sirupsen/logrus"
)

@ -4,14 +4,13 @@ import (
"crypto"
"encoding/json"
"fmt"
"github.com/cbeuw/Cloak/internal/common"
log "github.com/sirupsen/logrus"
"io/ioutil"
"net"
"strings"
"time"
"github.com/cbeuw/Cloak/internal/common"
log "github.com/sirupsen/logrus"
"github.com/cbeuw/Cloak/internal/ecdh"
mux "github.com/cbeuw/Cloak/internal/multiplex"
)
@ -37,7 +36,6 @@ type RawConfig struct {
BrowserSig string // nullable
Transport string // nullable
CDNOriginHost string // nullable
CDNWsUrlPath string // nullable
StreamTimeout int // nullable
KeepAlive int // nullable
}
@ -226,13 +224,10 @@ func (raw *RawConfig) ProcessRawConfig(worldState common.WorldState) (local Loca
} else {
cdnDomainPort = net.JoinHostPort(raw.CDNOriginHost, raw.RemotePort)
}
if raw.CDNWsUrlPath == "" {
raw.CDNWsUrlPath = "/"
}
remote.TransportMaker = func() Transport {
return &WSOverTLS{
wsUrl: "ws://" + cdnDomainPort + raw.CDNWsUrlPath,
cdnDomainPort: cdnDomainPort,
}
}
case "direct":
@ -241,13 +236,11 @@ func (raw *RawConfig) ProcessRawConfig(worldState common.WorldState) (local Loca
var browser browser
switch strings.ToLower(raw.BrowserSig) {
case "firefox":
browser = firefox
case "safari":
browser = safari
browser = &Firefox{}
case "chrome":
fallthrough
default:
browser = chrome
browser = &Chrome{}
}
remote.TransportMaker = func() Transport {
return &DirectTLS{

@ -1,10 +1,9 @@
package client
import (
"github.com/stretchr/testify/assert"
"io/ioutil"
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseConfig(t *testing.T) {

@ -4,18 +4,17 @@ import (
"encoding/base64"
"errors"
"fmt"
"github.com/cbeuw/Cloak/internal/common"
"github.com/gorilla/websocket"
utls "gitlab.com/yawning/utls.git"
"net"
"net/http"
"net/url"
"github.com/cbeuw/Cloak/internal/common"
"github.com/gorilla/websocket"
utls "github.com/refraction-networking/utls"
)
type WSOverTLS struct {
*common.WebSocketConn
wsUrl string
cdnDomainPort string
}
func (ws *WSOverTLS) Handshake(rawConn net.Conn, authInfo AuthInfo) (sessionKey [32]byte, err error) {
@ -41,7 +40,7 @@ func (ws *WSOverTLS) Handshake(rawConn net.Conn, authInfo AuthInfo) (sessionKey
return
}
u, err := url.Parse(ws.wsUrl)
u, err := url.Parse("ws://" + ws.cdnDomainPort)
if err != nil {
return sessionKey, fmt.Errorf("failed to parse ws url: %v", err)
}

@ -6,7 +6,6 @@ import (
"crypto/rand"
"errors"
"io"
"math/big"
"time"
log "github.com/sirupsen/logrus"
@ -53,8 +52,8 @@ func CryptoRandRead(buf []byte) {
RandRead(rand.Reader, buf)
}
func backoff(f func() error) {
err := f()
func RandRead(randSource io.Reader, buf []byte) {
_, err := randSource.Read(buf)
if err == nil {
return
}
@ -62,36 +61,12 @@ func backoff(f func() error) {
100 * time.Millisecond, 300 * time.Millisecond, 500 * time.Millisecond, 1 * time.Second,
3 * time.Second, 5 * time.Second}
for i := 0; i < 10; i++ {
log.Errorf("Failed to get random: %v. Retrying...", err)
err = f()
log.Errorf("Failed to get random bytes: %v. Retrying...", err)
_, err = randSource.Read(buf)
if err == nil {
return
}
time.Sleep(waitDur[i])
}
log.Fatal("Cannot get random after 10 retries")
}
func RandRead(randSource io.Reader, buf []byte) {
backoff(func() error {
_, err := randSource.Read(buf)
return err
})
}
func RandItem[T any](list []T) T {
return list[RandInt(len(list))]
}
func RandInt(n int) int {
s := new(int)
backoff(func() error {
size, err := rand.Int(rand.Reader, big.NewInt(int64(n)))
if err != nil {
return err
}
*s = int(size.Int64())
return nil
})
return *s
log.Fatal("Cannot get random bytes after 10 retries")
}

@ -4,11 +4,10 @@ import (
"bytes"
"encoding/hex"
"errors"
"github.com/stretchr/testify/assert"
"io"
"math/rand"
"testing"
"github.com/stretchr/testify/assert"
)
const gcmTagSize = 16

@ -2,11 +2,10 @@ package common
import (
"errors"
"github.com/gorilla/websocket"
"io"
"sync"
"time"
"github.com/gorilla/websocket"
)
// WebSocketConn implements io.ReadWriteCloser

@ -66,6 +66,46 @@ func (d *datagramBufferedPipe) Read(target []byte) (int, error) {
return dataLen, nil
}
func (d *datagramBufferedPipe) WriteTo(w io.Writer) (n int64, err error) {
d.rwCond.L.Lock()
defer d.rwCond.L.Unlock()
for {
if d.closed && len(d.pLens) == 0 {
return 0, io.EOF
}
hasRDeadline := !d.rDeadline.IsZero()
if hasRDeadline {
if time.Until(d.rDeadline) <= 0 {
return 0, ErrTimeout
}
}
if len(d.pLens) > 0 {
var dataLen int
dataLen, d.pLens = d.pLens[0], d.pLens[1:]
written, er := w.Write(d.buf.Next(dataLen))
n += int64(written)
if er != nil {
d.rwCond.Broadcast()
return n, er
}
d.rwCond.Broadcast()
} else {
if d.wtTimeout == 0 {
if hasRDeadline {
d.broadcastAfter(time.Until(d.rDeadline))
}
} else {
d.rDeadline = time.Now().Add(d.wtTimeout)
d.broadcastAfter(d.wtTimeout)
}
d.rwCond.Wait()
}
}
}
func (d *datagramBufferedPipe) Write(f *Frame) (toBeClosed bool, err error) {
d.rwCond.L.Lock()
defer d.rwCond.L.Unlock()
@ -111,6 +151,14 @@ func (d *datagramBufferedPipe) SetReadDeadline(t time.Time) {
d.rwCond.Broadcast()
}
func (d *datagramBufferedPipe) SetWriteToTimeout(t time.Duration) {
d.rwCond.L.Lock()
defer d.rwCond.L.Unlock()
d.wtTimeout = t
d.rwCond.Broadcast()
}
func (d *datagramBufferedPipe) broadcastAfter(t time.Duration) {
if d.timeoutTimer != nil {
d.timeoutTimer.Stop()

@ -1,10 +1,9 @@
package multiplex
import (
"github.com/stretchr/testify/assert"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestDatagramBuffer_RW(t *testing.T) {

@ -2,15 +2,14 @@ package multiplex
import (
"bytes"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/connutil"
"github.com/stretchr/testify/assert"
"io"
"math/rand"
"net"
"sync"
"testing"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/connutil"
"github.com/stretchr/testify/assert"
)
func serveEcho(l net.Listener) {

@ -6,7 +6,6 @@ import (
"encoding/binary"
"errors"
"fmt"
"github.com/cbeuw/Cloak/internal/common"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/salsa20"

@ -3,13 +3,12 @@ package multiplex
import (
"crypto/aes"
"crypto/cipher"
"github.com/stretchr/testify/assert"
"golang.org/x/crypto/chacha20poly1305"
"math/rand"
"reflect"
"testing"
"testing/quick"
"github.com/stretchr/testify/assert"
"golang.org/x/crypto/chacha20poly1305"
)
func TestGenerateObfs(t *testing.T) {

@ -14,8 +14,12 @@ type recvBuffer interface {
// Instead, it should behave as if it hasn't been closed. Closure is only relevant
// when the buffer is empty.
io.ReadCloser
io.WriterTo
Write(*Frame) (toBeClosed bool, err error)
SetReadDeadline(time time.Time)
// SetWriteToTimeout sets the duration a recvBuffer waits in a WriteTo call when nothing
// has been written for a while. After that duration it should return ErrTimeout
SetWriteToTimeout(d time.Duration)
}
// size we want the amount of unread data in buffer to grow before recvBuffer.Write blocks.

@ -3,13 +3,12 @@ package multiplex
import (
"errors"
"fmt"
"github.com/cbeuw/Cloak/internal/common"
"net"
"sync"
"sync/atomic"
"time"
"github.com/cbeuw/Cloak/internal/common"
log "github.com/sirupsen/logrus"
)
@ -265,7 +264,6 @@ func (sesh *Session) recvDataFromRemote(data []byte) error {
}
func (sesh *Session) SetTerminalMsg(msg string) {
log.Debug("terminal message set to " + msg)
sesh.terminalMsgSetter.Do(func() {
sesh.terminalMsg = msg
})

@ -1,4 +1,3 @@
//go:build gofuzz
// +build gofuzz
package multiplex

@ -2,6 +2,8 @@ package multiplex
import (
"bytes"
"github.com/cbeuw/connutil"
"github.com/stretchr/testify/assert"
"io"
"io/ioutil"
"math/rand"
@ -11,9 +13,6 @@ import (
"sync/atomic"
"testing"
"time"
"github.com/cbeuw/connutil"
"github.com/stretchr/testify/assert"
)
var seshConfigs = map[string]SessionConfig{
@ -557,7 +556,7 @@ func BenchmarkRecvDataFromRemote(b *testing.B) {
go func() {
stream, _ := sesh.Accept()
io.Copy(ioutil.Discard, stream)
stream.(*Stream).WriteTo(ioutil.Discard)
}()
binaryFrames := [maxIter][]byte{}

@ -6,10 +6,9 @@ import (
"net"
"time"
log "github.com/sirupsen/logrus"
"sync"
"sync/atomic"
log "github.com/sirupsen/logrus"
)
var ErrBrokenStream = errors.New("broken stream")
@ -96,6 +95,17 @@ func (s *Stream) Read(buf []byte) (n int, err error) {
return
}
// WriteTo continuously write data Stream has received into the writer w.
func (s *Stream) WriteTo(w io.Writer) (int64, error) {
// will keep writing until the underlying buffer is closed
n, err := s.recvBuf.WriteTo(w)
log.Tracef("%v read from stream %v with err %v", n, s.id, err)
if err == io.EOF {
return n, ErrBrokenStream
}
return n, nil
}
func (s *Stream) obfuscateAndSend(buf []byte, payloadOffsetInBuf int) error {
cipherTextLen, err := s.session.obfuscate(&s.writingFrame, buf, payloadOffsetInBuf)
s.writingFrame.Seq++
@ -199,6 +209,7 @@ func (s *Stream) Close() error {
func (s *Stream) LocalAddr() net.Addr { return s.session.addrs.Load().([]net.Addr)[0] }
func (s *Stream) RemoteAddr() net.Addr { return s.session.addrs.Load().([]net.Addr)[1] }
func (s *Stream) SetWriteToTimeout(d time.Duration) { s.recvBuf.SetWriteToTimeout(d) }
func (s *Stream) SetReadDeadline(t time.Time) error { s.recvBuf.SetReadDeadline(t); return nil }
func (s *Stream) SetReadFromTimeout(d time.Duration) { s.readFromTimeout = d }

@ -13,6 +13,7 @@ package multiplex
import (
"container/heap"
"fmt"
"io"
"sync"
"time"
)
@ -101,6 +102,10 @@ func (sb *streamBuffer) Read(buf []byte) (int, error) {
return sb.buf.Read(buf)
}
func (sb *streamBuffer) WriteTo(w io.Writer) (int64, error) {
return sb.buf.WriteTo(w)
}
func (sb *streamBuffer) Close() error {
sb.recvM.Lock()
defer sb.recvM.Unlock()
@ -108,4 +113,5 @@ func (sb *streamBuffer) Close() error {
return sb.buf.Close()
}
func (sb *streamBuffer) SetReadDeadline(t time.Time) { sb.buf.SetReadDeadline(t) }
func (sb *streamBuffer) SetReadDeadline(t time.Time) { sb.buf.SetReadDeadline(t) }
func (sb *streamBuffer) SetWriteToTimeout(d time.Duration) { sb.buf.SetWriteToTimeout(d) }

@ -3,7 +3,6 @@ package multiplex
import (
"encoding/binary"
"io"
//"log"
"sort"
"testing"

@ -58,6 +58,43 @@ func (p *streamBufferedPipe) Read(target []byte) (int, error) {
return n, err
}
func (p *streamBufferedPipe) WriteTo(w io.Writer) (n int64, err error) {
p.rwCond.L.Lock()
defer p.rwCond.L.Unlock()
for {
if p.closed && p.buf.Len() == 0 {
return 0, io.EOF
}
hasRDeadline := !p.rDeadline.IsZero()
if hasRDeadline {
if time.Until(p.rDeadline) <= 0 {
return 0, ErrTimeout
}
}
if p.buf.Len() > 0 {
written, er := p.buf.WriteTo(w)
n += written
if er != nil {
p.rwCond.Broadcast()
return n, er
}
p.rwCond.Broadcast()
} else {
if p.wtTimeout == 0 {
if hasRDeadline {
p.broadcastAfter(time.Until(p.rDeadline))
}
} else {
p.rDeadline = time.Now().Add(p.wtTimeout)
p.broadcastAfter(p.wtTimeout)
}
p.rwCond.Wait()
}
}
}
func (p *streamBufferedPipe) Write(input []byte) (int, error) {
p.rwCond.L.Lock()
defer p.rwCond.L.Unlock()
@ -94,6 +131,14 @@ func (p *streamBufferedPipe) SetReadDeadline(t time.Time) {
p.rwCond.Broadcast()
}
func (p *streamBufferedPipe) SetWriteToTimeout(d time.Duration) {
p.rwCond.L.Lock()
defer p.rwCond.L.Unlock()
p.wtTimeout = d
p.rwCond.Broadcast()
}
func (p *streamBufferedPipe) broadcastAfter(d time.Duration) {
if p.timeoutTimer != nil {
p.timeoutTimer.Stop()

@ -1,11 +1,10 @@
package multiplex
import (
"github.com/stretchr/testify/assert"
"math/rand"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
const readBlockTime = 500 * time.Millisecond

@ -2,14 +2,14 @@ package multiplex
import (
"bytes"
"github.com/cbeuw/Cloak/internal/common"
"github.com/stretchr/testify/assert"
"io"
"io/ioutil"
"math/rand"
"testing"
"time"
"github.com/cbeuw/Cloak/internal/common"
"github.com/stretchr/testify/assert"
"github.com/cbeuw/connutil"
)
@ -363,6 +363,31 @@ func TestStream_Read(t *testing.T) {
}
}
func TestStream_SetWriteToTimeout(t *testing.T) {
seshes := map[string]*Session{
"ordered": setupSesh(false, emptyKey, EncryptionMethodPlain),
"unordered": setupSesh(true, emptyKey, EncryptionMethodPlain),
}
for name, sesh := range seshes {
t.Run(name, func(t *testing.T) {
stream, _ := sesh.OpenStream()
stream.SetWriteToTimeout(100 * time.Millisecond)
done := make(chan struct{})
go func() {
stream.WriteTo(ioutil.Discard)
done <- struct{}{}
}()
select {
case <-done:
return
case <-time.After(500 * time.Millisecond):
t.Error("didn't timeout")
}
})
}
}
func TestStream_SetReadFromTimeout(t *testing.T) {
seshes := map[string]*Session{
"ordered": setupSesh(false, emptyKey, EncryptionMethodPlain),

@ -2,12 +2,12 @@ package multiplex
import (
"errors"
"github.com/cbeuw/Cloak/internal/common"
log "github.com/sirupsen/logrus"
"math/rand/v2"
"math/rand"
"net"
"sync"
"sync/atomic"
"time"
)
type switchboardStrategy int
@ -38,14 +38,19 @@ type switchboard struct {
}
func makeSwitchboard(sesh *Session) *switchboard {
var strategy switchboardStrategy
if sesh.Unordered {
log.Debug("Connection is unordered")
strategy = uniformSpread
} else {
strategy = fixedConnMapping
}
sb := &switchboard{
session: sesh,
strategy: uniformSpread,
strategy: strategy,
valve: sesh.Valve,
randPool: sync.Pool{New: func() interface{} {
var state [32]byte
common.CryptoRandRead(state[:])
return rand.New(rand.NewChaCha8(state))
return rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
}},
}
return sb
@ -54,8 +59,8 @@ func makeSwitchboard(sesh *Session) *switchboard {
var errBrokenSwitchboard = errors.New("the switchboard is broken")
func (sb *switchboard) addConn(conn net.Conn) {
connId := atomic.AddUint32(&sb.connsCount, 1) - 1
sb.conns.Store(connId, conn)
atomic.AddUint32(&sb.connsCount, 1)
sb.conns.Store(conn, conn)
go sb.deplex(conn)
}
@ -80,9 +85,6 @@ func (sb *switchboard) send(data []byte, assignedConn *net.Conn) (n int, err err
return n, err
}
case fixedConnMapping:
// FIXME: this strategy has a tendency to cause a TLS conn socket buffer to fill up,
// which is a problem when multiple streams are mapped to the same conn, resulting
// in all such streams being blocked.
conn = *assignedConn
if conn == nil {
conn, err = sb.pickRandConn()
@ -107,7 +109,7 @@ func (sb *switchboard) send(data []byte, assignedConn *net.Conn) (n int, err err
return n, nil
}
// returns a random conn. This function can be called concurrently.
// returns a random connId
func (sb *switchboard) pickRandConn() (net.Conn, error) {
if atomic.LoadUint32(&sb.broken) == 1 {
return nil, errBrokenSwitchboard
@ -119,15 +121,22 @@ func (sb *switchboard) pickRandConn() (net.Conn, error) {
}
randReader := sb.randPool.Get().(*rand.Rand)
connId := randReader.Uint32N(connsCount)
r := randReader.Intn(int(connsCount))
sb.randPool.Put(randReader)
ret, ok := sb.conns.Load(connId)
if !ok {
log.Errorf("failed to get conn %d", connId)
return nil, errBrokenSwitchboard
}
return ret.(net.Conn), nil
var c int
var ret net.Conn
sb.conns.Range(func(_, conn interface{}) bool {
if r == c {
ret = conn.(net.Conn)
return false
}
c++
return true
})
return ret, nil
}
// actively triggered by session.Close()
@ -135,10 +144,10 @@ func (sb *switchboard) closeAll() {
if !atomic.CompareAndSwapUint32(&sb.broken, 0, 1) {
return
}
atomic.StoreUint32(&sb.connsCount, 0)
sb.conns.Range(func(_, conn interface{}) bool {
conn.(net.Conn).Close()
sb.conns.Delete(conn)
atomic.AddUint32(&sb.connsCount, ^uint32(0))
return true
})
}

@ -1,14 +1,13 @@
package multiplex
import (
"github.com/cbeuw/connutil"
"github.com/stretchr/testify/assert"
"math/rand"
"sync"
"sync/atomic"
"testing"
"time"
"github.com/cbeuw/connutil"
"github.com/stretchr/testify/assert"
)
func TestSwitchboard_Send(t *testing.T) {

@ -4,11 +4,11 @@ import (
"crypto"
"errors"
"fmt"
"io"
"net"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/ecdh"
"io"
"math/rand"
"net"
log "github.com/sirupsen/logrus"
)
@ -45,7 +45,8 @@ func (TLS) makeResponder(clientHelloSessionId []byte, sharedSecret [32]byte) Res
// the cert length needs to be the same for all handshakes belonging to the same session
// we can use sessionKey as a seed here to ensure consistency
possibleCertLengths := []int{42, 27, 68, 59, 36, 44, 46}
cert := make([]byte, possibleCertLengths[common.RandInt(len(possibleCertLengths))])
rand.Seed(int64(sessionKey[0]))
cert := make([]byte, possibleCertLengths[rand.Intn(len(possibleCertLengths))])
common.RandRead(randSource, cert)
var nonce [12]byte

@ -5,7 +5,6 @@ import (
"encoding/binary"
"errors"
"fmt"
"github.com/cbeuw/Cloak/internal/common"
)
@ -164,12 +163,12 @@ func parseClientHello(data []byte) (ret *ClientHello, err error) {
func composeServerHello(sessionId []byte, nonce [12]byte, encryptedSessionKeyWithTag [48]byte) []byte {
var serverHello [11][]byte
serverHello[0] = []byte{0x02} // handshake type
serverHello[1] = []byte{0x00, 0x00, 0x76} // length 118
serverHello[1] = []byte{0x00, 0x00, 0x76} // length 77
serverHello[2] = []byte{0x03, 0x03} // server version
serverHello[3] = append(nonce[0:12], encryptedSessionKeyWithTag[0:20]...) // random 32 bytes
serverHello[4] = []byte{0x20} // session id length 32
serverHello[5] = sessionId // session id
serverHello[6] = []byte{0x13, 0x02} // cipher suite TLS_AES_256_GCM_SHA384
serverHello[6] = []byte{0xc0, 0x30} // cipher suite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
serverHello[7] = []byte{0x00} // compression method null
serverHello[8] = []byte{0x00, 0x2e} // extensions length 46

@ -1,9 +1,8 @@
package server
import (
"sync"
"github.com/cbeuw/Cloak/internal/server/usermanager"
"sync"
mux "github.com/cbeuw/Cloak/internal/multiplex"
)

@ -3,13 +3,12 @@ package server
import (
"crypto/rand"
"encoding/base64"
"io/ioutil"
"os"
"testing"
"github.com/cbeuw/Cloak/internal/common"
mux "github.com/cbeuw/Cloak/internal/multiplex"
"github.com/cbeuw/Cloak/internal/server/usermanager"
"io/ioutil"
"os"
"testing"
)
func getSeshConfig(unordered bool) mux.SessionConfig {

@ -5,9 +5,8 @@ import (
"encoding/binary"
"errors"
"fmt"
"time"
"github.com/cbeuw/Cloak/internal/common"
"time"
log "github.com/sirupsen/logrus"
)

@ -4,11 +4,10 @@ import (
"crypto"
"encoding/hex"
"fmt"
"testing"
"time"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/ecdh"
"testing"
"time"
)
func TestDecryptClientInfo(t *testing.T) {

@ -6,14 +6,13 @@ import (
"encoding/binary"
"errors"
"fmt"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/server/usermanager"
"io"
"net"
"net/http"
"time"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/server/usermanager"
mux "github.com/cbeuw/Cloak/internal/multiplex"
log "github.com/sirupsen/logrus"
)

@ -2,13 +2,12 @@ package server
import (
"encoding/hex"
"github.com/cbeuw/connutil"
"github.com/stretchr/testify/assert"
"io"
"net"
"testing"
"time"
"github.com/cbeuw/connutil"
"github.com/stretchr/testify/assert"
)
type rfpReturnValue struct {

@ -1,15 +1,13 @@
//go:build gofuzz
// +build gofuzz
package server
import (
"errors"
"net"
"time"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/connutil"
"net"
"time"
)
type rfpReturnValue_fuzz struct {

@ -5,14 +5,13 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/server/usermanager"
"io/ioutil"
"net"
"strings"
"sync"
"time"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/server/usermanager"
)
type RawConfig struct {

@ -4,13 +4,12 @@ import (
"bytes"
"encoding/base64"
"encoding/json"
"github.com/stretchr/testify/assert"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/stretchr/testify/assert"
)
var mockUIDb64 = base64.URLEncoding.EncodeToString(mockUID)

@ -2,7 +2,6 @@ package usermanager
import (
"encoding/binary"
"github.com/cbeuw/Cloak/internal/common"
log "github.com/sirupsen/logrus"
bolt "go.etcd.io/bbolt"

@ -2,6 +2,8 @@ package usermanager
import (
"encoding/binary"
"github.com/cbeuw/Cloak/internal/common"
"github.com/stretchr/testify/assert"
"io/ioutil"
"math/rand"
"os"
@ -10,9 +12,6 @@ import (
"sync"
"testing"
"time"
"github.com/cbeuw/Cloak/internal/common"
"github.com/stretchr/testify/assert"
)
var mockUID = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}

@ -1,9 +1,8 @@
package usermanager
import (
"testing"
"github.com/stretchr/testify/assert"
"testing"
)
var v = &Voidmanager{}

@ -2,12 +2,11 @@ package server
import (
"encoding/base64"
"github.com/cbeuw/Cloak/internal/server/usermanager"
"sync"
"sync/atomic"
"time"
"github.com/cbeuw/Cloak/internal/server/usermanager"
mux "github.com/cbeuw/Cloak/internal/multiplex"
log "github.com/sirupsen/logrus"
)

@ -2,13 +2,12 @@ package server
import (
"encoding/base64"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/server/usermanager"
"io/ioutil"
"os"
"testing"
"time"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/server/usermanager"
)
func TestUserPanel_BypassUser(t *testing.T) {

@ -7,12 +7,11 @@ import (
"encoding/base64"
"errors"
"fmt"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/ecdh"
"io"
"net"
"net/http"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/internal/ecdh"
)
type WebSocket struct{}

@ -2,11 +2,10 @@ package server
import (
"errors"
"net"
"net/http"
"github.com/cbeuw/Cloak/internal/common"
"github.com/gorilla/websocket"
"net"
"net/http"
log "github.com/sirupsen/logrus"
)

@ -2,9 +2,8 @@ package server
import (
"bytes"
"testing"
"github.com/cbeuw/connutil"
"testing"
)
func TestFirstBuffedConn_Read(t *testing.T) {

@ -5,19 +5,18 @@ import (
"encoding/base64"
"encoding/binary"
"fmt"
"io"
"math/rand"
"net"
"sync"
"testing"
"time"
"github.com/cbeuw/Cloak/internal/client"
"github.com/cbeuw/Cloak/internal/common"
mux "github.com/cbeuw/Cloak/internal/multiplex"
"github.com/cbeuw/Cloak/internal/server"
"github.com/cbeuw/connutil"
"github.com/stretchr/testify/assert"
"io"
"math/rand"
"net"
"sync"
"testing"
"time"
log "github.com/sirupsen/logrus"
)
@ -121,7 +120,7 @@ var singleplexTCPConfig = client.RawConfig{
RemotePort: "9999",
LocalHost: "127.0.0.1",
LocalPort: "9999",
BrowserSig: "safari",
BrowserSig: "chrome",
}
func generateClientConfigs(rawConfig client.RawConfig, state common.WorldState) (client.LocalConnConfig, client.RemoteConnConfig, client.AuthInfo) {

@ -1,8 +1,6 @@
#!/usr/bin/env bash
set -eu
go install github.com/mitchellh/gox@latest
go get github.com/mitchellh/gox
mkdir -p release
@ -20,7 +18,7 @@ echo "Compiling:"
os="windows linux darwin"
arch="amd64 386 arm arm64 mips mips64 mipsle mips64le"
pushd cmd/ck-client
pushd cmd/ck-client || exit 1
CGO_ENABLED=0 gox -ldflags "-X main.version=${v}" -os="$os" -arch="$arch" -osarch="$osarch" -output="$output"
CGO_ENABLED=0 GOOS="linux" GOARCH="mips" GOMIPS="softfloat" go build -ldflags "-X main.version=${v}" -o ck-client-linux-mips_softfloat-"${v}"
CGO_ENABLED=0 GOOS="linux" GOARCH="mipsle" GOMIPS="softfloat" go build -ldflags "-X main.version=${v}" -o ck-client-linux-mipsle_softfloat-"${v}"
@ -29,9 +27,7 @@ popd
os="linux"
arch="amd64 386 arm arm64"
pushd cmd/ck-server
pushd cmd/ck-server || exit 1
CGO_ENABLED=0 gox -ldflags "-X main.version=${v}" -os="$os" -arch="$arch" -osarch="$osarch" -output="$output"
mv ck-server-* ../../release
popd
sha256sum release/*
popd

@ -1,13 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
],
"packageRules": [
{
"packagePatterns": ["*"],
"excludePackagePatterns": ["utls"],
"enabled": false
}
]
}
Loading…
Cancel
Save