Compare commits

...

24 Commits

Author SHA1 Message Date
Andy Wang c3d5470ef7
Merge pull request #312 from cbeuw/renovate/github.com-refraction-networking-utls-1.x 2025-07-22 10:03:39 +01:00
renovate[bot] 8f629c7b2e
fix(deps): update module github.com/refraction-networking/utls to v1.8.0 2025-07-22 08:50:24 +00:00
Andy Wang 49357fc20b
Merge pull request #310 from cbeuw/utls-1.7.0
Update utls and increase server first packet buffer size
2025-06-08 18:21:55 +01:00
Andy Wang 8af137637e
Add backwards compatibility fallback to firefox 2025-06-08 18:19:58 +01:00
Andy Wang 51ed286f35
Update utls to 1.7.3 2025-06-08 18:19:57 +01:00
Andy Wang 5146ea8503
Increase server first packet buffer size to 3000 2025-06-08 18:19:48 +01:00
Andy Wang 7f9c17439f
Merge pull request #308 from cbeuw/deps-20250430
Update deps
2025-04-30 21:03:48 +01:00
Andy Wang c15fd730de
Update Go in CI 2025-04-30 21:00:54 +01:00
Andy Wang d06c208ace
Fix IP resolution in test 2025-04-30 20:57:23 +01:00
Andy Wang 9800e3685d
Update deps 2025-04-30 20:48:17 +01:00
Andy Wang 07aa197061
Go mod tidy 2025-04-30 20:39:09 +01:00
Andy Wang cfdd5e6560
Merge pull request #294 from zaferatli/docFix
chore: doc link fix
2025-04-30 20:35:14 +01:00
zaferatli 64166bf580 chore: doc link fix 2025-01-02 00:01:32 +03:00
Andy Wang d229d8b3dc
Merge pull request #283 from cbeuw/padding
Pad the first 5 frames to mitigate encapsulated TLS handshakes detection
2024-10-03 23:17:27 +01:00
Andy Wang 8bbc7b08d3
Fix tests 2024-10-03 23:06:42 +01:00
Andy Wang 5cf975f596
Pad the first 5 frames 2024-10-03 23:06:41 +01:00
Andy Wang 19c8cd1f89
Merge pull request #285 from cbeuw/docker-tests
Run compatibility tests against previous Cloak version
2024-10-03 23:04:58 +01:00
Andy Wang 5867fa932b
Merge pull request #281 from zestysoft/faliure_typo
Fix spelling mistake
2024-10-03 23:04:42 +01:00
Andy Wang bfaf46d2e9
Update actions 2024-10-03 22:54:48 +01:00
Andy Wang e362e81d19
Add backwards compatibility CI job 2024-10-03 22:54:48 +01:00
Andy Wang deb0d26c08
Build and push docker image on release 2024-10-01 21:48:42 +01:00
Ian Brown 3687087c67
Fix spelling mistake
Signed-off-by: Ian Brown <ian@zestysoft.com>
2024-09-20 19:45:46 -07:00
Andy Wang 97a03139bc
Merge pull request #262 from cbeuw/renovate/github.com-refraction-networking-utls-1.x
Update module github.com/refraction-networking/utls to v1.6.6
2024-06-16 13:19:04 +01:00
renovate[bot] b3c6426ac5
Update module github.com/refraction-networking/utls to v1.6.6 2024-05-03 23:07:04 +00:00
15 changed files with 266 additions and 119 deletions

View File

@ -7,11 +7,85 @@ jobs:
matrix: matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ] os: [ ubuntu-latest, macos-latest, windows-latest ]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- uses: actions/setup-go@v2 - uses: actions/setup-go@v5
with: with:
go-version: '^1.22' # The Go version to download (if necessary) and use. go-version: '^1.24' # The Go version to download (if necessary) and use.
- run: go test -race -coverprofile coverage.txt -coverpkg ./... -covermode atomic ./... - run: go test -race -coverprofile coverage.txt -coverpkg ./... -covermode atomic ./...
- uses: codecov/codecov-action@v1 - uses: codecov/codecov-action@v4
with: with:
file: coverage.txt files: coverage.txt
token: ${{ secrets.CODECOV_TOKEN }}
compat-test:
runs-on: ubuntu-latest
strategy:
matrix:
encryption-method: [ plain, chacha20-poly1305 ]
num-conn: [ 0, 1, 4 ]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '^1.24'
- name: Build Cloak
run: make
- name: Create configs
run: |
mkdir config
cat << EOF > config/ckclient.json
{
"Transport": "direct",
"ProxyMethod": "iperf",
"EncryptionMethod": "${{ matrix.encryption-method }}",
"UID": "Q4GAXHVgnDLXsdTpw6bmoQ==",
"PublicKey": "4dae/bF43FKGq+QbCc5P/E/MPM5qQeGIArjmJEHiZxc=",
"ServerName": "cloudflare.com",
"BrowserSig": "firefox",
"NumConn": ${{ matrix.num-conn }}
}
EOF
cat << EOF > config/ckserver.json
{
"ProxyBook": {
"iperf": [
"tcp",
"127.0.0.1:5201"
]
},
"BindAddr": [
":8443"
],
"BypassUID": [
"Q4GAXHVgnDLXsdTpw6bmoQ=="
],
"RedirAddr": "cloudflare.com",
"PrivateKey": "AAaskZJRPIAbiuaRLHsvZPvE6gzOeSjg+ZRg1ENau0Y="
}
EOF
- name: Start iperf3 server
run: docker run -d --name iperf-server --network host ajoergensen/iperf3:latest --server
- name: Test new client against old server
run: |
docker run -d --name old-cloak-server --network host -v $PWD/config:/go/Cloak/config cbeuw/cloak:latest build/ck-server -c config/ckserver.json --verbosity debug
build/ck-client -c config/ckclient.json -s 127.0.0.1 -p 8443 --verbosity debug | tee new-cloak-client.log &
docker run --network host ajoergensen/iperf3:latest --client 127.0.0.1 -p 1984
docker stop old-cloak-server
- name: Test old client against new server
run: |
build/ck-server -c config/ckserver.json --verbosity debug | tee new-cloak-server.log &
docker run -d --name old-cloak-client --network host -v $PWD/config:/go/Cloak/config cbeuw/cloak:latest build/ck-client -c config/ckclient.json -s 127.0.0.1 -p 8443 --verbosity debug
docker run --network host ajoergensen/iperf3:latest --client 127.0.0.1 -p 1984
docker stop old-cloak-client
- name: Dump docker logs
if: always()
run: |
docker container logs iperf-server > iperf-server.log
docker container logs old-cloak-server > old-cloak-server.log
docker container logs old-cloak-client > old-cloak-client.log
- name: Upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.encryption-method }}-${{ matrix.num-conn }}-conn-logs
path: ./*.log

View File

@ -9,7 +9,7 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Build - name: Build
run: | run: |
export PATH=${PATH}:`go env GOPATH`/bin export PATH=${PATH}:`go env GOPATH`/bin
@ -20,3 +20,31 @@ jobs:
files: release/* files: release/*
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build-docker:
runs-on: ubuntu-latest
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
cbeuw/cloak
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

5
Dockerfile Normal file
View File

@ -0,0 +1,5 @@
FROM golang:latest
RUN git clone https://github.com/cbeuw/Cloak.git
WORKDIR Cloak
RUN make

View File

@ -12,7 +12,7 @@
<img src="https://user-images.githubusercontent.com/7034308/155629720-54dd8758-ec98-4fed-b603-623f0ad83b6c.svg" /> <img src="https://user-images.githubusercontent.com/7034308/155629720-54dd8758-ec98-4fed-b603-623f0ad83b6c.svg" />
</p> </p>
Cloak is a [pluggable transport](https://www.ietf.org/proceedings/103/slides/slides-103-pearg-pt-slides-01) that enhances Cloak is a [pluggable transport](https://datatracker.ietf.org/meeting/103/materials/slides-103-pearg-pt-slides-01) that enhances
traditional proxy tools like OpenVPN to evade [sophisticated censorship](https://en.wikipedia.org/wiki/Deep_packet_inspection) and [data discrimination](https://en.wikipedia.org/wiki/Net_bias). traditional proxy tools like OpenVPN to evade [sophisticated censorship](https://en.wikipedia.org/wiki/Deep_packet_inspection) and [data discrimination](https://en.wikipedia.org/wiki/Net_bias).
Cloak is not a standalone proxy program. Rather, it works by masquerading proxied traffic as normal web browsing Cloak is not a standalone proxy program. Rather, it works by masquerading proxied traffic as normal web browsing

26
go.mod
View File

@ -1,30 +1,30 @@
module github.com/cbeuw/Cloak module github.com/cbeuw/Cloak
go 1.21 go 1.24.0
toolchain go1.22.2 toolchain go1.24.2
require ( require (
github.com/cbeuw/connutil v0.0.0-20200411215123-966bfaa51ee3 github.com/cbeuw/connutil v0.0.0-20200411215123-966bfaa51ee3
github.com/gorilla/mux v1.8.1 github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.1 github.com/gorilla/websocket v1.5.3
github.com/juju/ratelimit v1.0.2 github.com/juju/ratelimit v1.0.2
github.com/refraction-networking/utls v1.6.4 github.com/refraction-networking/utls v1.8.0
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.10.0
go.etcd.io/bbolt v1.3.9 go.etcd.io/bbolt v1.4.0
golang.org/x/crypto v0.22.0 golang.org/x/crypto v0.37.0
) )
require ( require (
github.com/andybalholm/brotli v1.0.6 // indirect github.com/andybalholm/brotli v1.1.1 // indirect
github.com/cloudflare/circl v1.3.7 // indirect github.com/cloudflare/circl v1.6.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/klauspost/compress v1.17.4 // indirect github.com/klauspost/compress v1.18.0 // indirect
github.com/kr/pretty v0.3.1 // indirect github.com/kr/pretty v0.3.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/net v0.21.0 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect
golang.org/x/sys v0.19.0 // indirect golang.org/x/sys v0.32.0 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

59
go.sum
View File

@ -1,52 +1,61 @@
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/cbeuw/connutil v0.0.0-20200411215123-966bfaa51ee3 h1:LRxW8pdmWmyhoNh+TxUjxsAinGtCsVGjsl3xg6zoRSs= 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/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.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= 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.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI= 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/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.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/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.6 h1:igFsYBUJPYM8Rno9xUuDoM5GQrVEqY4llzEXOkL43Ig=
github.com/refraction-networking/utls v1.6.4/go.mod h1:2VL2xfiqgFAZtJKeUTlf+PSYFs3Eu7km0gCtXJ3m8zs= 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/refraction-networking/utls v1.7.0/go.mod h1:lV0Gwc1/Fi+HYH8hOtgFRdHfKo4FKSn6+FdyOz9hRms=
github.com/refraction-networking/utls v1.7.3 h1:L0WRhHY7Oq1T0zkdzVZMR6zWZv+sXbHB9zcuvsAEqCo=
github.com/refraction-networking/utls v1.7.3/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
github.com/refraction-networking/utls v1.8.0 h1:L38krhiTAyj9EeiQQa2sg+hYb4qwLCqdMcpZrRfbONE=
github.com/refraction-networking/utls v1.8.0/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= 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.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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.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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.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.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -21,8 +21,10 @@ func MakeSession(connConfig RemoteConnConfig, authInfo AuthInfo, dialer common.D
var wg sync.WaitGroup var wg sync.WaitGroup
for i := 0; i < connConfig.NumConn; i++ { for i := 0; i < connConfig.NumConn; i++ {
wg.Add(1) wg.Add(1)
transportConfig := connConfig.Transport
go func() { go func() {
makeconn: makeconn:
transportConn := transportConfig.CreateTransport()
remoteConn, err := dialer.Dial("tcp", connConfig.RemoteAddr) remoteConn, err := dialer.Dial("tcp", connConfig.RemoteAddr)
if err != nil { if err != nil {
log.Errorf("Failed to establish new connections to remote: %v", err) log.Errorf("Failed to establish new connections to remote: %v", err)
@ -31,12 +33,20 @@ func MakeSession(connConfig RemoteConnConfig, authInfo AuthInfo, dialer common.D
goto makeconn goto makeconn
} }
transportConn := connConfig.TransportMaker()
sk, err := transportConn.Handshake(remoteConn, authInfo) sk, err := transportConn.Handshake(remoteConn, authInfo)
if err != nil { if err != nil {
log.Errorf("Failed to prepare connection to remote: %v", err) log.Errorf("Failed to prepare connection to remote: %v", err)
transportConn.Close() transportConn.Close()
// In Cloak v2.11.0, we've updated uTLS version and subsequently increased the first packet size for chrome above 1500
// https://github.com/cbeuw/Cloak/pull/306#issuecomment-2862728738. As a backwards compatibility feature, if we fail
// to connect using chrome signature, retry with firefox which has a smaller packet size.
if transportConfig.mode == "direct" && transportConfig.browser == chrome {
transportConfig.browser = firefox
log.Warnf("failed to connect with chrome signature, falling back to retry with firefox")
}
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
goto makeconn goto makeconn
} }
// sessionKey given by each connection should be identical // sessionKey given by each connection should be identical

View File

@ -47,7 +47,7 @@ type RemoteConnConfig struct {
NumConn int NumConn int
KeepAlive time.Duration KeepAlive time.Duration
RemoteAddr string RemoteAddr string
TransportMaker func() Transport Transport TransportConfig
} }
type LocalConnConfig struct { type LocalConnConfig struct {
@ -230,11 +230,10 @@ func (raw *RawConfig) ProcessRawConfig(worldState common.WorldState) (local Loca
raw.CDNWsUrlPath = "/" raw.CDNWsUrlPath = "/"
} }
remote.TransportMaker = func() Transport { remote.Transport = TransportConfig{
return &WSOverTLS{ mode: "cdn",
wsUrl: "ws://" + cdnDomainPort + raw.CDNWsUrlPath, wsUrl: "ws://" + cdnDomainPort + raw.CDNWsUrlPath,
} }
}
case "direct": case "direct":
fallthrough fallthrough
default: default:
@ -249,12 +248,11 @@ func (raw *RawConfig) ProcessRawConfig(worldState common.WorldState) (local Loca
default: default:
browser = chrome browser = chrome
} }
remote.TransportMaker = func() Transport { remote.Transport = TransportConfig{
return &DirectTLS{ mode: "direct",
browser: browser, browser: browser,
} }
} }
}
// KeepAlive // KeepAlive
if raw.KeepAlive <= 0 { if raw.KeepAlive <= 0 {

View File

@ -8,3 +8,26 @@ type Transport interface {
Handshake(rawConn net.Conn, authInfo AuthInfo) (sessionKey [32]byte, err error) Handshake(rawConn net.Conn, authInfo AuthInfo) (sessionKey [32]byte, err error)
net.Conn net.Conn
} }
type TransportConfig struct {
mode string
wsUrl string
browser browser
}
func (t TransportConfig) CreateTransport() Transport {
switch t.mode {
case "cdn":
return &WSOverTLS{
wsUrl: t.wsUrl,
}
case "direct":
return &DirectTLS{
browser: t.browser,
}
default:
return nil
}
}

View File

@ -3,10 +3,10 @@ package multiplex
import ( import (
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"crypto/rand"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"github.com/cbeuw/Cloak/internal/common" "github.com/cbeuw/Cloak/internal/common"
"golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/salsa20" "golang.org/x/crypto/salsa20"
@ -15,6 +15,14 @@ import (
const frameHeaderLength = 14 const frameHeaderLength = 14
const salsa20NonceSize = 8 const salsa20NonceSize = 8
// maxExtraLen equals the max length of padding + AEAD tag.
// It is 255 bytes because the extra len field in frame header is only one byte.
const maxExtraLen = 1<<8 - 1
// padFirstNFrames specifies the number of initial frames to pad,
// to avoid TLS-in-TLS detection
const padFirstNFrames = 5
const ( const (
EncryptionMethodPlain = iota EncryptionMethodPlain = iota
EncryptionMethodAES256GCM EncryptionMethodAES256GCM
@ -27,8 +35,6 @@ type Obfuscator struct {
payloadCipher cipher.AEAD payloadCipher cipher.AEAD
sessionKey [32]byte sessionKey [32]byte
maxOverhead int
} }
// obfuscate adds multiplexing headers, encrypt and add TLS header // obfuscate adds multiplexing headers, encrypt and add TLS header
@ -49,45 +55,34 @@ func (o *Obfuscator) obfuscate(f *Frame, buf []byte, payloadOffsetInBuf int) (in
// to be large enough that they may never happen in reasonable time frames. Of course, different sessions // to be large enough that they may never happen in reasonable time frames. Of course, different sessions
// will produce the same combination of stream id and frame sequence, but they will have different session keys. // will produce the same combination of stream id and frame sequence, but they will have different session keys.
// //
// Salsa20 is assumed to be given a unique nonce each time because we assume the tags produced by payloadCipher
// AEAD is unique each time, as payloadCipher itself is given a unique iv/nonce each time due to points made above.
// This is relatively a weak guarantee as we are assuming AEADs to produce different tags given different iv/nonces.
// This is almost certainly true but I cannot find a source that outright states this.
// //
// Because the frame header, before it being encrypted, is fed into the AEAD, it is also authenticated. // Because the frame header, before it being encrypted, is fed into the AEAD, it is also authenticated.
// (rfc5116 s.2.1 "The nonce is authenticated internally to the algorithm"). // (rfc5116 s.2.1 "The nonce is authenticated internally to the algorithm").
// //
// In case the user chooses to not encrypt the frame payload, payloadCipher will be nil. In this scenario, // In case the user chooses to not encrypt the frame payload, payloadCipher will be nil. In this scenario,
// we pad the frame payload with random bytes until it reaches Salsa20's nonce size (8 bytes). Then we simply // we generate random bytes to be used as salsa20 nonce.
// encrypt the frame header with the last 8 bytes of frame payload as nonce.
// If the payload provided by the user is greater than 8 bytes, then we use entirely the user input as nonce.
// We can't ensure its uniqueness ourselves, which is why plaintext mode must only be used when the user input
// is already random-like. For Cloak it would normally mean that the user is using a proxy protocol that sends
// encrypted data.
payloadLen := len(f.Payload) payloadLen := len(f.Payload)
if payloadLen == 0 { if payloadLen == 0 {
return 0, errors.New("payload cannot be empty") return 0, errors.New("payload cannot be empty")
} }
var extraLen int tagLen := 0
if o.payloadCipher == nil { if o.payloadCipher != nil {
extraLen = salsa20NonceSize - payloadLen tagLen = o.payloadCipher.Overhead()
if extraLen < 0 {
// if our payload is already greater than 8 bytes
extraLen = 0
}
} else { } else {
extraLen = o.payloadCipher.Overhead() tagLen = salsa20NonceSize
if extraLen < salsa20NonceSize {
return 0, errors.New("AEAD's Overhead cannot be fewer than 8 bytes")
} }
// Pad to avoid size side channel leak
padLen := 0
if f.Seq < padFirstNFrames {
padLen = common.RandInt(maxExtraLen - tagLen + 1)
} }
usefulLen := frameHeaderLength + payloadLen + extraLen usefulLen := frameHeaderLength + payloadLen + padLen + tagLen
if len(buf) < usefulLen { if len(buf) < usefulLen {
return 0, errors.New("obfs buffer too small") return 0, errors.New("obfs buffer too small")
} }
// we do as much in-place as possible to save allocation // we do as much in-place as possible to save allocation
payload := buf[frameHeaderLength : frameHeaderLength+payloadLen] payload := buf[frameHeaderLength : frameHeaderLength+payloadLen+padLen]
if payloadOffsetInBuf != frameHeaderLength { if payloadOffsetInBuf != frameHeaderLength {
// if payload is not at the correct location in buffer // if payload is not at the correct location in buffer
copy(payload, f.Payload) copy(payload, f.Payload)
@ -97,14 +92,15 @@ func (o *Obfuscator) obfuscate(f *Frame, buf []byte, payloadOffsetInBuf int) (in
binary.BigEndian.PutUint32(header[0:4], f.StreamID) binary.BigEndian.PutUint32(header[0:4], f.StreamID)
binary.BigEndian.PutUint64(header[4:12], f.Seq) binary.BigEndian.PutUint64(header[4:12], f.Seq)
header[12] = f.Closing header[12] = f.Closing
header[13] = byte(extraLen) header[13] = byte(padLen + tagLen)
if o.payloadCipher == nil { // Random bytes for padding and nonce
if extraLen != 0 { // read nonce _, err := rand.Read(buf[frameHeaderLength+payloadLen : usefulLen])
extra := buf[usefulLen-extraLen : usefulLen] if err != nil {
common.CryptoRandRead(extra) return 0, fmt.Errorf("failed to pad random: %w", err)
} }
} else {
if o.payloadCipher != nil {
o.payloadCipher.Seal(payload[:0], header[:o.payloadCipher.NonceSize()], payload, nil) o.payloadCipher.Seal(payload[:0], header[:o.payloadCipher.NonceSize()], payload, nil)
} }
@ -166,7 +162,6 @@ func MakeObfuscator(encryptionMethod byte, sessionKey [32]byte) (o Obfuscator, e
switch encryptionMethod { switch encryptionMethod {
case EncryptionMethodPlain: case EncryptionMethodPlain:
o.payloadCipher = nil o.payloadCipher = nil
o.maxOverhead = salsa20NonceSize
case EncryptionMethodAES256GCM: case EncryptionMethodAES256GCM:
var c cipher.Block var c cipher.Block
c, err = aes.NewCipher(sessionKey[:]) c, err = aes.NewCipher(sessionKey[:])
@ -177,7 +172,6 @@ func MakeObfuscator(encryptionMethod byte, sessionKey [32]byte) (o Obfuscator, e
if err != nil { if err != nil {
return return
} }
o.maxOverhead = o.payloadCipher.Overhead()
case EncryptionMethodAES128GCM: case EncryptionMethodAES128GCM:
var c cipher.Block var c cipher.Block
c, err = aes.NewCipher(sessionKey[:16]) c, err = aes.NewCipher(sessionKey[:16])
@ -188,13 +182,11 @@ func MakeObfuscator(encryptionMethod byte, sessionKey [32]byte) (o Obfuscator, e
if err != nil { if err != nil {
return return
} }
o.maxOverhead = o.payloadCipher.Overhead()
case EncryptionMethodChaha20Poly1305: case EncryptionMethodChaha20Poly1305:
o.payloadCipher, err = chacha20poly1305.New(sessionKey[:]) o.payloadCipher, err = chacha20poly1305.New(sessionKey[:])
if err != nil { if err != nil {
return return
} }
o.maxOverhead = o.payloadCipher.Overhead()
default: default:
return o, fmt.Errorf("unknown encryption method valued %v", encryptionMethod) return o, fmt.Errorf("unknown encryption method valued %v", encryptionMethod)
} }

View File

@ -85,7 +85,6 @@ func TestObfuscate(t *testing.T) {
o := Obfuscator{ o := Obfuscator{
payloadCipher: nil, payloadCipher: nil,
sessionKey: sessionKey, sessionKey: sessionKey,
maxOverhead: salsa20NonceSize,
} }
runTest(t, o) runTest(t, o)
}) })
@ -98,7 +97,6 @@ func TestObfuscate(t *testing.T) {
o := Obfuscator{ o := Obfuscator{
payloadCipher: payloadCipher, payloadCipher: payloadCipher,
sessionKey: sessionKey, sessionKey: sessionKey,
maxOverhead: payloadCipher.Overhead(),
} }
runTest(t, o) runTest(t, o)
}) })
@ -111,7 +109,6 @@ func TestObfuscate(t *testing.T) {
o := Obfuscator{ o := Obfuscator{
payloadCipher: payloadCipher, payloadCipher: payloadCipher,
sessionKey: sessionKey, sessionKey: sessionKey,
maxOverhead: payloadCipher.Overhead(),
} }
runTest(t, o) runTest(t, o)
}) })
@ -122,7 +119,6 @@ func TestObfuscate(t *testing.T) {
o := Obfuscator{ o := Obfuscator{
payloadCipher: payloadCipher, payloadCipher: payloadCipher,
sessionKey: sessionKey, sessionKey: sessionKey,
maxOverhead: payloadCipher.Overhead(),
} }
runTest(t, o) runTest(t, o)
}) })
@ -150,7 +146,6 @@ func BenchmarkObfs(b *testing.B) {
obfuscator := Obfuscator{ obfuscator := Obfuscator{
payloadCipher: payloadCipher, payloadCipher: payloadCipher,
sessionKey: key, sessionKey: key,
maxOverhead: payloadCipher.Overhead(),
} }
b.SetBytes(int64(len(testFrame.Payload))) b.SetBytes(int64(len(testFrame.Payload)))
@ -166,7 +161,6 @@ func BenchmarkObfs(b *testing.B) {
obfuscator := Obfuscator{ obfuscator := Obfuscator{
payloadCipher: payloadCipher, payloadCipher: payloadCipher,
sessionKey: key, sessionKey: key,
maxOverhead: payloadCipher.Overhead(),
} }
b.SetBytes(int64(len(testFrame.Payload))) b.SetBytes(int64(len(testFrame.Payload)))
b.ResetTimer() b.ResetTimer()
@ -178,7 +172,6 @@ func BenchmarkObfs(b *testing.B) {
obfuscator := Obfuscator{ obfuscator := Obfuscator{
payloadCipher: nil, payloadCipher: nil,
sessionKey: key, sessionKey: key,
maxOverhead: salsa20NonceSize,
} }
b.SetBytes(int64(len(testFrame.Payload))) b.SetBytes(int64(len(testFrame.Payload)))
b.ResetTimer() b.ResetTimer()
@ -192,7 +185,6 @@ func BenchmarkObfs(b *testing.B) {
obfuscator := Obfuscator{ obfuscator := Obfuscator{
payloadCipher: payloadCipher, payloadCipher: payloadCipher,
sessionKey: key, sessionKey: key,
maxOverhead: payloadCipher.Overhead(),
} }
b.SetBytes(int64(len(testFrame.Payload))) b.SetBytes(int64(len(testFrame.Payload)))
b.ResetTimer() b.ResetTimer()
@ -222,7 +214,6 @@ func BenchmarkDeobfs(b *testing.B) {
obfuscator := Obfuscator{ obfuscator := Obfuscator{
payloadCipher: payloadCipher, payloadCipher: payloadCipher,
sessionKey: key, sessionKey: key,
maxOverhead: payloadCipher.Overhead(),
} }
n, _ := obfuscator.obfuscate(testFrame, obfsBuf, 0) n, _ := obfuscator.obfuscate(testFrame, obfsBuf, 0)
@ -241,7 +232,6 @@ func BenchmarkDeobfs(b *testing.B) {
obfuscator := Obfuscator{ obfuscator := Obfuscator{
payloadCipher: payloadCipher, payloadCipher: payloadCipher,
sessionKey: key, sessionKey: key,
maxOverhead: payloadCipher.Overhead(),
} }
n, _ := obfuscator.obfuscate(testFrame, obfsBuf, 0) n, _ := obfuscator.obfuscate(testFrame, obfsBuf, 0)
@ -256,7 +246,6 @@ func BenchmarkDeobfs(b *testing.B) {
obfuscator := Obfuscator{ obfuscator := Obfuscator{
payloadCipher: nil, payloadCipher: nil,
sessionKey: key, sessionKey: key,
maxOverhead: salsa20NonceSize,
} }
n, _ := obfuscator.obfuscate(testFrame, obfsBuf, 0) n, _ := obfuscator.obfuscate(testFrame, obfsBuf, 0)
@ -271,9 +260,8 @@ func BenchmarkDeobfs(b *testing.B) {
payloadCipher, _ := chacha20poly1305.New(key[:]) payloadCipher, _ := chacha20poly1305.New(key[:])
obfuscator := Obfuscator{ obfuscator := Obfuscator{
payloadCipher: nil, payloadCipher: payloadCipher,
sessionKey: key, sessionKey: key,
maxOverhead: payloadCipher.Overhead(),
} }
n, _ := obfuscator.obfuscate(testFrame, obfsBuf, 0) n, _ := obfuscator.obfuscate(testFrame, obfsBuf, 0)

View File

@ -108,7 +108,7 @@ func MakeSession(id uint32, config SessionConfig) *Session {
sesh.InactivityTimeout = defaultInactivityTimeout sesh.InactivityTimeout = defaultInactivityTimeout
} }
sesh.maxStreamUnitWrite = sesh.MsgOnWireSizeLimit - frameHeaderLength - sesh.maxOverhead sesh.maxStreamUnitWrite = sesh.MsgOnWireSizeLimit - frameHeaderLength - maxExtraLen
sesh.streamSendBufferSize = sesh.MsgOnWireSizeLimit sesh.streamSendBufferSize = sesh.MsgOnWireSizeLimit
sesh.connReceiveBufferSize = 20480 // for backwards compatibility sesh.connReceiveBufferSize = 20480 // for backwards compatibility

View File

@ -61,7 +61,7 @@ func decryptClientInfo(fragments authFragments, serverTime time.Time) (info Clie
var ErrReplay = errors.New("duplicate random") var ErrReplay = errors.New("duplicate random")
var ErrBadProxyMethod = errors.New("invalid proxy method") var ErrBadProxyMethod = errors.New("invalid proxy method")
var ErrBadDecryption = errors.New("decryption/authentication faliure") var ErrBadDecryption = errors.New("decryption/authentication failure")
// AuthFirstPacket checks if the first packet of data is ClientHello or HTTP GET, and checks if it was from a Cloak client // AuthFirstPacket checks if the first packet of data is ClientHello or HTTP GET, and checks if it was from a Cloak client
// if it is from a Cloak client, it returns the ClientInfo with the decrypted fields. It doesn't check if the user // if it is from a Cloak client, it returns the ClientInfo with the decrypted fields. It doesn't check if the user

View File

@ -20,6 +20,8 @@ import (
var b64 = base64.StdEncoding.EncodeToString var b64 = base64.StdEncoding.EncodeToString
const firstPacketSize = 3000
func Serve(l net.Listener, sta *State) { func Serve(l net.Listener, sta *State) {
waitDur := [10]time.Duration{ waitDur := [10]time.Duration{
50 * time.Millisecond, 100 * time.Millisecond, 300 * time.Millisecond, 500 * time.Millisecond, 1 * time.Second, 50 * time.Millisecond, 100 * time.Millisecond, 300 * time.Millisecond, 500 * time.Millisecond, 1 * time.Second,
@ -124,7 +126,7 @@ func readFirstPacket(conn net.Conn, buf []byte, timeout time.Duration) (int, Tra
func dispatchConnection(conn net.Conn, sta *State) { func dispatchConnection(conn net.Conn, sta *State) {
var err error var err error
buf := make([]byte, 1500) buf := make([]byte, firstPacketSize)
i, transport, redirOnErr, err := readFirstPacket(conn, buf, 15*time.Second) i, transport, redirOnErr, err := readFirstPacket(conn, buf, 15*time.Second)
data := buf[:i] data := buf[:i]

View File

@ -43,13 +43,22 @@ func TestParseRedirAddr(t *testing.T) {
t.Errorf("parsing %v error: %v", domainNoPort, err) t.Errorf("parsing %v error: %v", domainNoPort, err)
return return
} }
expHost, err := net.ResolveIPAddr("ip", "example.com")
expIPs, err := net.LookupIP("example.com")
if err != nil { if err != nil {
t.Errorf("tester error: cannot resolve example.com: %v", err) t.Errorf("tester error: cannot resolve example.com: %v", err)
return return
} }
if host.String() != expHost.String() {
t.Errorf("expected %v got %v", expHost.String(), host.String()) contain := false
for _, expIP := range expIPs {
if expIP.String() == host.String() {
contain = true
}
}
if !contain {
t.Errorf("expected one of %v got %v", expIPs, host.String())
} }
if port != "" { if port != "" {
t.Errorf("port not empty when there is no port") t.Errorf("port not empty when there is no port")
@ -63,13 +72,22 @@ func TestParseRedirAddr(t *testing.T) {
t.Errorf("parsing %v error: %v", domainWPort, err) t.Errorf("parsing %v error: %v", domainWPort, err)
return return
} }
expHost, err := net.ResolveIPAddr("ip", "example.com")
expIPs, err := net.LookupIP("example.com")
if err != nil { if err != nil {
t.Errorf("tester error: cannot resolve example.com: %v", err) t.Errorf("tester error: cannot resolve example.com: %v", err)
return return
} }
if host.String() != expHost.String() {
t.Errorf("expected %v got %v", expHost.String(), host.String()) contain := false
for _, expIP := range expIPs {
if expIP.String() == host.String() {
contain = true
}
}
if !contain {
t.Errorf("expected one of %v got %v", expIPs, host.String())
} }
if port != "80" { if port != "80" {
t.Errorf("wrong port: expected %v, got %v", "80", port) t.Errorf("wrong port: expected %v, got %v", "80", port)