Compare commits

...

83 Commits

Author SHA1 Message Date
世界
603264017a Add tun support 2023-04-23 19:51:48 +08:00
世界
18e5b0963f Update dependencies 2023-04-23 19:32:07 +08:00
yichya QC
90d915ea05 feat: add tcp_user_timeout
```json
{"streamSettings":{"sockopt": {"tcpUserTimeout": 10000}}}
```

run `gofmt -w -s .` as well
2023-04-22 20:41:43 -04:00
dependabot[bot]
d9994538bc Bump github.com/quic-go/quic-go from 0.33.0 to 0.34.0
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.33.0 to 0.34.0.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.33.0...v0.34.0)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-20 23:43:06 -04:00
冰天雪地
69aa3f48cc Fix : docker build when repo on organization. (#1973)
* feat : support docker build

* fix : ghcr build login when organization

---------

Co-authored-by: kunson <kunson@kunsondeMacBook-Pro-3.local>
2023-04-20 11:36:25 -04:00
kunson
ca32496a38 feat : support docker build 2023-04-20 11:07:35 -04:00
RPRX
d3060c28f8 v1.8.1 2023-04-17 23:22:12 +00:00
RPRX
ac8109eef8 Update README.md 2023-04-17 23:21:56 +00:00
yuhan6665
197bc78ea1 Turn off Quic qlog since it jam the regular test info 2023-04-17 11:56:55 -04:00
Vigilans
039e5f2078 Correctly implement quic sniffer's frame parsing 2023-04-17 11:55:35 -04:00
RPRX
242f3b0e0b XTLS protocol: Apply Vision's padding to XUDP Mux & Minor fixes
It's recommended to enable XUDP Mux when using XTLS Vision
Thank @yuhan6665 for testing
2023-04-16 21:15:36 +00:00
RPRX
b4c1a56026 XUDP practice: MUST check the flag first & Add more comments 2023-04-16 21:15:27 +00:00
yuhan6665
9f8e9e8e64 Add xudp buffer test 2023-04-15 20:22:10 -04:00
RPRX
06c9e50c52 Add "xudpProxyUDP443" to Mux config & XUDP rejects UDP/443 traffic by default (client side, excluding reverse proxy) 2023-04-14 22:51:18 +00:00
RPRX
4f601530fa Allow multiple XUDP in Mux when using XTLS Vision (client side) 2023-04-14 22:51:09 +00:00
RPRX
b33b0bc89d Allow multiple XUDP in Mux when using XTLS Vision (server side) 2023-04-12 23:20:38 +08:00
RPRX
01b7e5e9be XUDP Global ID should be empty if "cone" is disabled (client side) 2023-04-12 23:20:26 +08:00
RPRX
24a2be43ef Replace "only" with "xudpConcurrency" in Mux config 2023-04-10 10:36:07 +08:00
RPRX
29d7865d78 Refine "only" in Mux config 2023-04-10 10:15:16 +08:00
yuhan6665
05d24d6827 Amend XUDP related logs
- Useful for debug XUDP improvements
- Move XUDP log in core log
- Freedom connection log show local port
2023-04-09 13:29:39 -04:00
RPRX
76b27a37cb Update common/xudp/xudp.go and common/mux/server.go 2023-04-07 19:13:20 +08:00
MisakaNo の 小破站
15cf31f30a Add sbox-reality to README/Others/sing-box (#1909) 2023-04-07 10:20:56 +00:00
dependabot[bot]
54ad0e96a0 Bump golang.org/x/net from 0.8.0 to 0.9.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.8.0 to 0.9.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-06 21:33:41 -04:00
RPRX
be23d5d3b7 XUDP protocol: Add Global ID & UoT Migration
The first UoT protocol that supports UoT Migration
Thank @yuhan6665 for testing
2023-04-06 10:21:35 +00:00
dependabot[bot]
67affe3753 Bump golang.org/x/sys from 0.6.0 to 0.7.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/golang/sys/releases)
- [Commits](https://github.com/golang/sys/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-04 21:47:10 -04:00
RPRX
2c0a89f7dc REALITY protocol: Set the fourth byte as reserved 2023-03-31 22:39:57 +00:00
dependabot[bot]
a4d1509c23 Bump github.com/miekg/dns from 1.1.52 to 1.1.53
Bumps [github.com/miekg/dns](https://github.com/miekg/dns) from 1.1.52 to 1.1.53.
- [Release notes](https://github.com/miekg/dns/releases)
- [Changelog](https://github.com/miekg/dns/blob/master/Makefile.release)
- [Commits](https://github.com/miekg/dns/compare/v1.1.52...v1.1.53)

---
updated-dependencies:
- dependency-name: github.com/miekg/dns
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-29 00:59:47 +00:00
dependabot[bot]
f4ab8d7e8b Bump github.com/sagernet/sing from 0.2.0 to 0.2.1
Bumps [github.com/sagernet/sing](https://github.com/sagernet/sing) from 0.2.0 to 0.2.1.
- [Release notes](https://github.com/sagernet/sing/releases)
- [Commits](https://github.com/sagernet/sing/compare/v0.2.0...v0.2.1)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-29 03:38:12 +00:00
RPRX
beb603af06 Allow IP address ServerName when "serverName" is not configured
In this case, TLS Client Hello will not have SNI (RFC 6066, Section 3)
2023-03-26 10:57:20 +00:00
RPRX
a0d06f3a97 Add env support to "address", "listen", etc.
Usage: `"address": "env:ADDR"`, `"listen": "env:AUDS"`...
Just like existing `"port": "env:PORT"`
2023-03-26 10:10:27 +00:00
Hirbod Behnam
526c6789ed Add custom path to gRPC (#1815) 2023-03-26 09:28:19 +03:30
Hirbod Behnam
6872be5cc3 Add user agent to gRPC (#1790) 2023-03-26 09:23:42 +03:30
RPRX
c6b78318cb Update README.md
Co-authored-by: chika0801 <88967758+chika0801@users.noreply.github.com>
Co-authored-by: yuhan6665 <1588741+yuhan6665@users.noreply.github.com>
2023-03-24 22:57:56 +00:00
dependabot[bot]
f89998fc77 Update dependencies 2023-03-24 01:35:15 +00:00
RPRX
0573760346 Do not show ciphertext SessionID or full AuthKey 2023-03-20 23:39:56 +08:00
世界
172f353bd7 Update dependencies 2023-03-20 15:01:38 +08:00
世界
55efac7236 Reformat code 2023-03-17 13:17:08 +08:00
世界
f57ec13880 Update UoT protocol 2023-03-17 13:17:08 +08:00
dependabot[bot]
f1e35ad9d4 Bump github.com/sagernet/sing from 0.1.7 to 0.1.8
Bumps [github.com/sagernet/sing](https://github.com/sagernet/sing) from 0.1.7 to 0.1.8.
- [Release notes](https://github.com/sagernet/sing/releases)
- [Commits](https://github.com/sagernet/sing/compare/v0.1.7...v0.1.8)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-09 23:36:35 -05:00
RPRX
d6801ab031 v1.8.0 2023-03-09 13:55:09 +00:00
xqzr
c3322294be Add tcpWindowClamp to sockopt (#1757)
Co-authored-by: RPRX <63339210+RPRX@users.noreply.github.com>
2023-03-09 13:51:16 +00:00
RPRX
836e84b851 Add recover() to H2 server's flushWriter.Write()
Fixes https://github.com/XTLS/Xray-core/issues/1748
2023-03-08 14:06:20 +00:00
Hellojack
4a0b45d1ff Output real private key in x25519 command (#1747) 2023-03-08 13:43:42 +00:00
RPRX
c04c333afc They become a part of you 2023-03-04 15:39:27 +00:00
yuhan6665
9e5bc07bf2 Legends never die (#1725) 2023-03-04 10:39:26 +00:00
RPRX
4c8ee0af50 Set reserved to zero after Read()
Thank @IRN-Kawakaze for testing
2023-03-03 15:39:16 +00:00
yuhan6665
25ea69fc3a Fix Vision inserting multiple uuid headers
This happen for stream inbound like http
2023-03-03 09:45:10 -05:00
yuhan6665
a4790133d2 Fix padding extends out of bound again 2023-03-02 21:42:48 -05:00
RPRX
ccba465590 Add reserved to WireGuard config
Fixes https://github.com/XTLS/Xray-core/issues/1730
2023-03-02 16:55:42 +00:00
RPRX
6526e74d49 Add WaitReadCloser to make H2 real 0-RTT 2023-03-02 14:50:26 +00:00
yuhan6665
7b54255cc1 Fix padding extends out of bound 2023-03-01 08:43:00 -05:00
dependabot[bot]
43bc929030 Bump github.com/stretchr/testify from 1.8.1 to 1.8.2
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.1 to 1.8.2.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.8.1...v1.8.2)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-27 22:24:02 -05:00
dependabot[bot]
fbc7c1cf84 Bump github.com/miekg/dns from 1.1.50 to 1.1.51
Bumps [github.com/miekg/dns](https://github.com/miekg/dns) from 1.1.50 to 1.1.51.
- [Release notes](https://github.com/miekg/dns/releases)
- [Changelog](https://github.com/miekg/dns/blob/master/Makefile.release)
- [Commits](https://github.com/miekg/dns/compare/v1.1.50...v1.1.51)

---
updated-dependencies:
- dependency-name: github.com/miekg/dns
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-27 22:23:50 -05:00
HalfLife
cc4be239cf transfer geodat with actions/cache 2023-02-27 22:23:33 -05:00
yuhan6665
2d898480be Vision padding upgrade (#1646)
* Vision server allow multiple blocks of padding

* Fix Vision client to support multiple possible padding blocks

* Vision padding upgrade

- Now we have two types of padding: long (pad to 900-1400) and traditional (0-256)
- Long padding is applied to tls handshakes and first (empty) packet
- Traditional padding is applied to all beginning (7) packets of the connection (counted two-way)
- Since receiver changed its way to unpad buffer in fd6973b3c6, we can freely extend padding packet length easily in the future
- Simplify code

* Adjust receiver withinPaddingBuffers

Now default withinPaddingBuffers = true to give it a chance to do unpadding

* Fix magic numbers for Vision
Thanks @H1JK

Thanks @RPRX for guidance
2023-02-27 22:14:37 -05:00
RPRX
55dc26f228 Add REALITY support to gRPC client and server
Now you are able to configure REALITY gRPC client and server
Duplicate of REALITY H2, perhaps, just for fun
2023-02-27 19:52:01 +00:00
RPRX
9401d65ef1 Add REALITY support to H2 server
Now you are able to configure REALITY H2 server directly
Before: REALITY VLESS fallbacks -> H2C inbound
2023-02-27 16:20:19 +00:00
RPRX
c38179a67f Upgrade github.com/xtls/reality to f34b4d174342
Fixes https://github.com/XTLS/Xray-core/issues/1712
2023-02-26 19:26:57 +08:00
yuhan6665
a5b297f968 Update test.yml
Fix an issue when geoip fails download but geosite is ok
https://github.com/XTLS/Xray-core/actions/runs/4264609454/jobs/7422911731
2023-02-24 12:41:27 -05:00
dependabot[bot]
d208fd31c9 Bump github.com/sagernet/sing-shadowsocks
Bumps [github.com/sagernet/sing-shadowsocks](https://github.com/sagernet/sing-shadowsocks) from 0.1.1-0.20230202035033-e3123545f2f7 to 0.1.1.
- [Release notes](https://github.com/sagernet/sing-shadowsocks/releases)
- [Commits](https://github.com/sagernet/sing-shadowsocks/commits/v0.1.1)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing-shadowsocks
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-24 12:07:01 -05:00
dependabot[bot]
2e201c57cc Bump github.com/quic-go/quic-go from 0.32.0 to 0.33.0
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.32.0 to 0.33.0.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.32.0...v0.33.0)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-24 12:06:48 -05:00
sduoduo233
336b2daeb9 DNS Header for KCP (#1672)
* dns header

* fixed domain name encoding for dns header

---------

Co-authored-by: kerry <lvhaiyangkerry@gmail.com>
2023-02-24 12:06:24 -05:00
xqzr
c8b4580869 add V6Only (#1677)
* add `V6Only`

* add `V6Only`
2023-02-24 11:54:40 -05:00
Yue Yin
03b8c094de Support SPKI Fingerprint Pinning
Support SPKI Fingerprint Pinning for TLSObject
2023-02-24 11:47:00 -05:00
Hellojack
267d93f7bd Improve ReshapeMultiBuffer (#1636)
* Improve ReshapeMultiBuffer

* Improve again

* Always resize
2023-02-24 11:42:02 -05:00
dependabot[bot]
7f16f4ccd9 Bump github.com/sagernet/sing from 0.1.6 to 0.1.7
Bumps [github.com/sagernet/sing](https://github.com/sagernet/sing) from 0.1.6 to 0.1.7.
- [Release notes](https://github.com/sagernet/sing/releases)
- [Commits](https://github.com/sagernet/sing/compare/v0.1.6...v0.1.7)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-21 22:36:48 -05:00
yuhan6665
9e07d8304d Add retry for test steps to download geofiles 2023-02-21 22:36:36 -05:00
RPRX
9d3de59d3f Check "serverNames" and "shortIds" (client side)
Prevents https://github.com/XTLS/Xray-core/issues/1675
2023-02-21 13:43:13 +00:00
RPRX
4d5c3195d2 Refine random
Fixes https://github.com/XTLS/Xray-core/issues/1666
2023-02-18 05:55:19 +00:00
RPRX
c7358a32f5 Allow empty "spiderX" (client side) 2023-02-17 21:07:27 +08:00
RPRX
e1cd1fd33e Allow empty "shortId" (client side) 2023-02-17 12:39:18 +00:00
RPRX
82003f28b2 Upgrade github.com/xtls/reality to 085bdf2104d3
Fixes https://github.com/XTLS/Xray-core/issues/1659
2023-02-17 11:43:18 +00:00
RPRX
4d2e2b24d3 THE NEXT FUTURE becomes THE REALITY NOW
Thank @yuhan6665 for testing
2023-02-15 16:07:12 +00:00
RPRX
15999e5c2a v1.7.5 2023-02-08 17:20:24 +08:00
dependabot[bot]
48ff0d92c9 Bump google.golang.org/grpc from 1.52.3 to 1.53.0 (#1625) 2023-02-08 07:58:18 +00:00
dependabot[bot]
229e2513b5 Bump golang.org/x/sys from 0.4.0 to 0.5.0 (#1626) 2023-02-08 07:57:05 +00:00
RPRX
9046eda5ce Add callClose to UDP Dispatcher
Fixes https://github.com/XTLS/Xray-core/issues/1611
2023-02-08 14:59:14 +08:00
RPRX
f32921df30 Refine randomized
But we should avoid using it unless we have to, see
https://github.com/refraction-networking/utls/pull/157#issuecomment-1417156797
2023-02-08 14:51:15 +08:00
yuhan6665
c3faa8b7ac Insert padding with empty content to camouflage VLESS header (#1610)
This only affects the Vision client for protocols expecting server to send data first.
The change is compatible with existing version of Vision server.
2023-02-06 06:45:09 +00:00
RPRX
00c9576118 Use go:linkname in qtls_go118.go
Once and for all, whatever
2023-02-04 21:27:13 +08:00
RPRX
fa7300e910 Add warning on using old version of XTLS
And checks param `fingerprint` also
2023-02-03 23:29:46 +08:00
RPRX
b57d3fa869 1.20 -> '1.20' 2023-02-02 06:26:07 +00:00
RPRX
53833c2323 Update workflows to use Go 1.20 2023-02-02 05:59:58 +00:00
140 changed files with 4699 additions and 2672 deletions

21
.github/docker/Dockerfile vendored Normal file
View File

@@ -0,0 +1,21 @@
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM golang:alpine AS build
WORKDIR /src
COPY . .
ARG TARGETOS TARGETARCH
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
FROM --platform=${TARGETPLATFORM} alpine:latest
WORKDIR /root
COPY .github/docker/files/config.json /etc/xray/config.json
COPY --from=build /src/xray /usr/bin/xray
RUN set -ex \
&& apk add --no-cache tzdata ca-certificates \
&& mkdir -p /var/log/xray /usr/share/xray \
&& chmod +x /usr/bin/xray \
&& wget -O /usr/share/xray/geosite.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat \
&& wget -O /usr/share/xray/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
VOLUME /etc/xray
ENV TZ=Asia/Shanghai
CMD [ "/usr/bin/xray", "-config", "/etc/xray/config.json" ]

19
.github/docker/files/config.json vendored Normal file
View File

@@ -0,0 +1,19 @@
{
"inbounds": [{
"port": 9000,
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "1eb6e917-774b-4a84-aff6-b058577c60a5",
"level": 1,
"alterId": 64
}
]
}
}],
"outbounds": [{
"protocol": "freedom",
"settings": {}
}]
}

45
.github/workflows/docker.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: Build docker image
on:
push:
branches:
- '*'
jobs:
build-image:
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- uses: actions/checkout@v3
- name: Docker metadata
id: meta
uses: docker/metadata-action@v4
with:
images: ghcr.io/${{ github.repository_owner }}/xray-core
flavor: latest=true
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- # Add support for more platforms with QEMU (optional)
# https://github.com/docker/setup-qemu-action
name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm64
file: .github/docker/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@@ -20,7 +20,51 @@ on:
- "go.sum" - "go.sum"
- ".github/workflows/*.yml" - ".github/workflows/*.yml"
jobs: jobs:
prepare:
runs-on: ubuntu-latest
steps:
- name: Restore Cache
uses: actions/cache/restore@v3
with:
path: resources
key: xray-geodat-
- name: Update Geodat
id: update
uses: nick-fields/retry@v2
with:
timeout_minutes: 60
retry_wait_seconds: 60
max_attempts: 60
command: |
[ -d 'resources' ] || mkdir resources
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite')
for i in "${LIST[@]}"
do
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3}'))
FILE_NAME="${INFO[2]}.dat"
echo -e "Verifying HASH key..."
HASH="$(curl -sL "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
if [ -s "./resources/${FILE_NAME}" ] && [ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ]; then
continue
else
echo -e "Downloading https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat..."
curl -L "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat" -o ./resources/${FILE_NAME}
echo -e "Verifying HASH key..."
[ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ] || { echo -e "The HASH key of ${FILE_NAME} does not match cloud one."; exit 1; }
echo "unhit=true" >> $GITHUB_OUTPUT
fi
done
- name: Save Cache
uses: actions/cache/save@v3
if: ${{ steps.update.outputs.unhit }}
with:
path: resources
key: xray-geodat-${{ github.sha }}-${{ github.run_number }}
build: build:
needs: prepare
permissions: permissions:
contents: write contents: write
strategy: strategy:
@@ -121,9 +165,9 @@ jobs:
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v3 uses: actions/setup-go@v4
with: with:
go-version: 1.19 go-version: '1.20'
check-latest: true check-latest: true
- name: Get project dependencies - name: Get project dependencies
@@ -142,12 +186,12 @@ jobs:
- name: Build Xray - name: Build Xray
run: | run: |
mkdir -p build_assets mkdir -p build_assets
go build -v -o build_assets/xray -trimpath -ldflags "-s -w -buildid=" ./main go build -v -o build_assets/xray -trimpath -ldflags "-s -w -buildid=" -tags with_gvisor ./main
- name: Build background Xray on Windows - name: Build background Xray on Windows
if: matrix.goos == 'windows' if: matrix.goos == 'windows'
run: | run: |
go build -v -o build_assets/wxray.exe -trimpath -ldflags "-s -w -H windowsgui -buildid=" ./main go build -v -o build_assets/wxray.exe -trimpath -ldflags "-s -w -H windowsgui -buildid=" -tags with_gvisor ./main
- name: Build Mips softfloat Xray - name: Build Mips softfloat Xray
if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle' if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle'
@@ -160,26 +204,17 @@ jobs:
cd ./build_assets || exit 1 cd ./build_assets || exit 1
mv xray xray.exe mv xray xray.exe
- name: Prepare to release - name: Restore Cache
uses: nick-fields/retry@v2 uses: actions/cache/restore@v3
with: with:
timeout_minutes: 60 path: resources
retry_wait_seconds: 60 key: xray-geodat-
max_attempts: 60
command: | - name: Copy README.md & LICENSE
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md run: |
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE mv -f resources/* build_assets
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite') cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
for i in "${LIST[@]}" cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
do
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3}'))
FILE_NAME="${INFO[2]}.dat"
echo -e "Downloading https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat..."
curl -L "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat" -o ./build_assets/${FILE_NAME}
echo -e "Verifying HASH key..."
HASH="$(curl -sL "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
[ "$(sha256sum "./build_assets/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ] || { echo -e "The HASH key of ${FILE_NAME} does not match cloud one."; exit 1; }
done
- name: Create ZIP archive - name: Create ZIP archive
shell: bash shell: bash

View File

@@ -28,24 +28,17 @@ jobs:
os: [windows-latest, ubuntu-latest, macos-latest] os: [windows-latest, ubuntu-latest, macos-latest]
steps: steps:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v3 uses: actions/setup-go@v4
with: with:
go-version: 1.19 go-version: '1.20'
check-latest: true check-latest: true
- name: Checkout codebase - name: Checkout codebase
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Restore Cache
- name: Prepare geo*dat uses: actions/cache/restore@v3
if: ${{ matrix.os != 'windows-latest' }} with:
run: | path: resources
mkdir resources key: xray-geodat-
wget -O ./resources/geoip.dat https://github.com/v2fly/geoip/releases/latest/download/geoip.dat enableCrossOsArchive: true
wget -O ./resources/geosite.dat https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat
- name: Prepare geo*dat for Windows
if: ${{ matrix.os == 'windows-latest' }}
run: |
mkdir resources
Invoke-WebRequest -Uri "https://github.com/v2fly/geoip/releases/latest/download/geoip.dat" -OutFile "./resources/geoip.dat"
Invoke-WebRequest -Uri "https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat" -OutFile "./resources/geosite.dat"
- name: Test - name: Test
run: go test -timeout 1h -v ./... run: go test -timeout 1h -v ./...

View File

@@ -1,58 +1,105 @@
# Project X # Project X
[Project X](https://github.com/XTLS) originates from XTLS protocol, provides a set of network tools such as [Xray-core](https://github.com/XTLS/Xray-core). [Project X](https://github.com/XTLS) originates from XTLS protocol, providing a set of network tools such as [Xray-core](https://github.com/XTLS/Xray-core) and [REALITY](https://github.com/XTLS/REALITY).
[README](https://github.com/XTLS/Xray-core#readme) is open, so feel free to submit your project [here](https://github.com/XTLS/Xray-core/pulls).
## License ## License
[Mozilla Public License Version 2.0](https://github.com/XTLS/Xray-core/blob/main/LICENSE) [Mozilla Public License Version 2.0](https://github.com/XTLS/Xray-core/blob/main/LICENSE)
## Documentation
[Project X Official Website](https://xtls.github.io)
## Telegram
[Project X](https://t.me/projectXray)
[Project X Channel](https://t.me/projectXtls)
## Installation ## Installation
- Linux Script - Linux Script
- [Xray-install](https://github.com/XTLS/Xray-install) - [XTLS/Xray-install](https://github.com/XTLS/Xray-install)
- [Xray-script](https://github.com/kirin10000/Xray-script)
- Docker - Docker
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray) - [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
- Web Panel
- [X-UI](https://github.com/FranzKafkaYu/x-ui), [X-UI-English](https://github.com/NidukaAkalanka/x-ui-english), [3X-UI](https://github.com/MHSanaei/3x-ui), [X-UI](https://github.com/alireza0/x-ui), [X-UI](https://github.com/diditra/x-ui)
- [Xray-UI](https://github.com/qist/xray-ui), [X-UI](https://github.com/sing-web/x-ui)
- [Hiddify](https://github.com/hiddify/hiddify-config)
- [Marzban](https://github.com/Gozargah/Marzban)
- [Libertea](https://github.com/VZiChoushaDui/Libertea)
- One Click - One Click
- [ProxySU](https://github.com/proxysu/ProxySU) - [Xray-script](https://github.com/kirin10000/Xray-script), [Xray-REALITY](https://github.com/zxcvos/Xray-script), [LetsXray](https://github.com/tdjnodj/LetsXray)
- [v2ray-agent](https://github.com/mack-a/v2ray-agent) - [XTool](https://github.com/LordPenguin666/XTool), [Xray_bash_onekey](https://github.com/hello-yunshu/Xray_bash_onekey), [xray-reality](https://github.com/sajjaddg/xray-reality)
- [Xray-yes](https://github.com/jiuqi9997/Xray-yes) - [v2ray-agent](https://github.com/mack-a/v2ray-agent), [Xray_onekey](https://github.com/wulabing/Xray_onekey), [ProxySU](https://github.com/proxysu/ProxySU)
- [Xray_onekey](https://github.com/wulabing/Xray_onekey)
- Magisk - Magisk
- [Xray4Magisk](https://github.com/CerteKim/Xray4Magisk) - [Xray4Magisk](https://github.com/Asterisk4Magisk/Xray4Magisk)
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk) - [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
- Homebrew - Homebrew
- `brew install xray` - `brew install xray`
- [(Tap) Repository 0](https://github.com/N4FA/homebrew-xray)
- [(Tap) Repository 1](https://github.com/xiruizhao/homebrew-xray)
## Contributing
[Code Of Conduct](https://github.com/XTLS/Xray-core/blob/main/CODE_OF_CONDUCT.md)
## Usage ## Usage
[Xray-examples](https://github.com/XTLS/Xray-examples) / [VLESS-TCP-XTLS-WHATEVER](https://github.com/XTLS/Xray-examples/tree/main/VLESS-TCP-XTLS-WHATEVER) - Example
- [VLESS-XTLS-uTLS-REALITY](https://github.com/XTLS/REALITY#readme)
- [VLESS-TCP-XTLS-Vision](https://github.com/XTLS/Xray-examples/tree/main/VLESS-TCP-XTLS-Vision)
- [All-in-One-fallbacks-Nginx](https://github.com/XTLS/Xray-examples/tree/main/All-in-One-fallbacks-Nginx)
- Xray-examples
- [XTLS/Xray-examples](https://github.com/XTLS/Xray-examples)
- [chika0801/Xray-examples](https://github.com/chika0801/Xray-examples)
- [lxhao61/integrated-examples](https://github.com/lxhao61/integrated-examples)
- Tutorial
- [XTLS Vision](https://github.com/chika0801/Xray-install)
- [REALITY (English)](https://cscot.pages.dev/2023/03/02/Xray-REALITY-tutorial/)
- [XTLS-Iran-Reality (English)](https://github.com/SasukeFreestyle/XTLS-Iran-Reality)
## GUI Clients ## GUI Clients
- OpenWrt - OpenWrt
- [PassWall](https://github.com/xiaorouji/openwrt-passwall) - [PassWall](https://github.com/xiaorouji/openwrt-passwall), [PassWall 2](https://github.com/xiaorouji/openwrt-passwall2)
- [Hello World](https://github.com/jerrykuku/luci-app-vssr)
- [ShadowSocksR Plus+](https://github.com/fw876/helloworld) - [ShadowSocksR Plus+](https://github.com/fw876/helloworld)
- [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray)) - [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray))
- Windows - Windows
- [v2rayN](https://github.com/2dust/v2rayN) - [v2rayN](https://github.com/2dust/v2rayN)
- [Qv2ray](https://github.com/Qv2ray/Qv2ray) (This project had been archived and currently inactive) - [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
- [Netch (NetFilter & TUN/TAP)](https://github.com/NetchX/Netch) (This project had been archived and currently inactive)
- Android - Android
- [v2rayNG](https://github.com/2dust/v2rayNG) - [v2rayNG](https://github.com/2dust/v2rayNG)
- [Kitsunebi](https://github.com/rurirei/Kitsunebi/tree/release_xtls) - [X-flutter](https://github.com/XTLS/X-flutter)
- iOS & macOS (with M1 chip) - iOS & macOS arm64
- [Mango](https://github.com/arror/Mango)
- [Wings X](https://apps.apple.com/app/wings-x/id6446119727)
- macOS arm64 & x64
- [V2RayXS](https://github.com/tzmax/V2RayXS)
- [Wings X](https://apps.apple.com/app/wings-x/id6446119727)
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
- iOS & macOS arm64
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118) - [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
- [Stash](https://apps.apple.com/app/stash/id1596063349) - [Stash](https://apps.apple.com/app/stash/id1596063349)
- macOS (Intel chip & M1 chip) - Xray Wrapper
- [Qv2ray](https://github.com/Qv2ray/Qv2ray) (This project had been archived and currently inactive) - [xtlsapi](https://github.com/hiddify/xtlsapi)
- [V2RayXS](https://github.com/tzmax/V2RayXS) - [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite)
- [XrayKit](https://github.com/arror/XrayKit)
- [libxray](https://github.com/KouYiGuo/libxray)
- [XrayR](https://github.com/XrayR-project/XrayR)
- [XrayR-release](https://github.com/XrayR-project/XrayR-release)
- [XrayR-V2Board](https://github.com/missuo/XrayR-V2Board)
- [Clash.Meta](https://github.com/MetaCubeX/Clash.Meta)
- [Clash Verge](https://github.com/zzzgydi/clash-verge)
- [clashN](https://github.com/2dust/clashN)
- [Clash Meta for Android](https://github.com/MetaCubeX/ClashMetaForAndroid)
- [meta_for_ios](https://t.me/meta_for_ios)
- [sing-box](https://github.com/SagerNet/sing-box)
- [installReality](https://github.com/BoxXt/installReality)
- [sbox-reality](https://github.com/Misaka-blog/sbox-reality)
- [sing-box-for-ios](https://github.com/SagerNet/sing-box-for-ios)
## Contributing
[Code of Conduct](https://github.com/XTLS/Xray-core/blob/main/CODE_OF_CONDUCT.md)
## Credits ## Credits
@@ -88,12 +135,6 @@ go build -o xray.exe -trimpath -ldflags "-s -w -buildid=" ./main
go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
``` ```
## Telegram
[Project X](https://t.me/projectXray)
[Project X Channel](https://t.me/projectXtls)
## Stargazers over time ## Stargazers over time
[![Stargazers over time](https://starchart.cc/XTLS/Xray-core.svg)](https://starchart.cc/XTLS/Xray-core) [![Stargazers over time](https://starchart.cc/XTLS/Xray-core.svg)](https://starchart.cc/XTLS/Xray-core)

View File

@@ -342,29 +342,27 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
} }
sniffingRequest := content.SniffingRequest sniffingRequest := content.SniffingRequest
if !sniffingRequest.Enabled { if !sniffingRequest.Enabled {
go d.routedDispatch(ctx, outbound, destination) d.routedDispatch(ctx, outbound, destination)
} else { } else {
go func() { cReader := &cachedReader{
cReader := &cachedReader{ reader: outbound.Reader.(*pipe.Reader),
reader: outbound.Reader.(*pipe.Reader), }
outbound.Reader = cReader
result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly, destination.Network)
if err == nil {
content.Protocol = result.Protocol()
}
if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) {
domain := result.Domain()
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
destination.Address = net.ParseAddress(domain)
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
ob.RouteTarget = destination
} else {
ob.Target = destination
} }
outbound.Reader = cReader }
result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly, destination.Network) d.routedDispatch(ctx, outbound, destination)
if err == nil {
content.Protocol = result.Protocol()
}
if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) {
domain := result.Domain()
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
destination.Address = net.ParseAddress(domain)
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
ob.RouteTarget = destination
} else {
ob.Target = destination
}
}
d.routedDispatch(ctx, outbound, destination)
}()
} }
return nil return nil

View File

@@ -594,7 +594,11 @@ type MultiplexingConfig struct {
// Whether or not Mux is enabled. // Whether or not Mux is enabled.
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
// Max number of concurrent connections that one Mux connection can handle. // Max number of concurrent connections that one Mux connection can handle.
Concurrency uint32 `protobuf:"varint,2,opt,name=concurrency,proto3" json:"concurrency,omitempty"` Concurrency int32 `protobuf:"varint,2,opt,name=concurrency,proto3" json:"concurrency,omitempty"`
// Transport XUDP in another Mux.
XudpConcurrency int32 `protobuf:"varint,3,opt,name=xudpConcurrency,proto3" json:"xudpConcurrency,omitempty"`
// "reject" (default), "allow" or "skip".
XudpProxyUDP443 string `protobuf:"bytes,4,opt,name=xudpProxyUDP443,proto3" json:"xudpProxyUDP443,omitempty"`
} }
func (x *MultiplexingConfig) Reset() { func (x *MultiplexingConfig) Reset() {
@@ -636,13 +640,27 @@ func (x *MultiplexingConfig) GetEnabled() bool {
return false return false
} }
func (x *MultiplexingConfig) GetConcurrency() uint32 { func (x *MultiplexingConfig) GetConcurrency() int32 {
if x != nil { if x != nil {
return x.Concurrency return x.Concurrency
} }
return 0 return 0
} }
func (x *MultiplexingConfig) GetXudpConcurrency() int32 {
if x != nil {
return x.XudpConcurrency
}
return 0
}
func (x *MultiplexingConfig) GetXudpProxyUDP443() string {
if x != nil {
return x.XudpProxyUDP443
}
return ""
}
type AllocationStrategy_AllocationStrategyConcurrency struct { type AllocationStrategy_AllocationStrategyConcurrency struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -856,21 +874,26 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78,
0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69,
0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x50, 0x0a, 0x12, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0xa4, 0x01, 0x0a,
0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01,
0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a,
0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01,
0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2a, 0x23, 0x28, 0x05, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12,
0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x4c, 0x63, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f,
0x53, 0x10, 0x01, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64,
0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x18, 0x04, 0x20, 0x01,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x28, 0x09, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50,
0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x34, 0x34, 0x33, 0x2a, 0x23, 0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74,
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12,
0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x07, 0x0a, 0x03, 0x54, 0x4c, 0x53, 0x10, 0x01, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e,
0x6f, 0x33, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61,
0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72,
0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -97,5 +97,9 @@ message MultiplexingConfig {
// Whether or not Mux is enabled. // Whether or not Mux is enabled.
bool enabled = 1; bool enabled = 1;
// Max number of concurrent connections that one Mux connection can handle. // Max number of concurrent connections that one Mux connection can handle.
uint32 concurrency = 2; int32 concurrency = 2;
// Transport XUDP in another Mux.
int32 xudpConcurrency = 3;
// "reject" (default), "allow" or "skip".
string xudpProxyUDP443 = 4;
} }

View File

@@ -57,6 +57,8 @@ type Handler struct {
proxy proxy.Outbound proxy proxy.Outbound
outboundManager outbound.Manager outboundManager outbound.Manager
mux *mux.ClientManager mux *mux.ClientManager
xudp *mux.ClientManager
udp443 string
uplinkCounter stats.Counter uplinkCounter stats.Counter
downlinkCounter stats.Counter downlinkCounter stats.Counter
} }
@@ -106,22 +108,50 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
} }
if h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil { if h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil {
config := h.senderSettings.MultiplexSettings if config := h.senderSettings.MultiplexSettings; config.Enabled {
if config.Concurrency < 1 || config.Concurrency > 1024 { if config.Concurrency < 0 {
return nil, newError("invalid mux concurrency: ", config.Concurrency).AtWarning() h.mux = &mux.ClientManager{Enabled: false}
} }
h.mux = &mux.ClientManager{ if config.Concurrency == 0 {
Enabled: h.senderSettings.MultiplexSettings.Enabled, config.Concurrency = 8 // same as before
Picker: &mux.IncrementalWorkerPicker{ }
Factory: &mux.DialingWorkerFactory{ if config.Concurrency > 0 {
Proxy: proxyHandler, h.mux = &mux.ClientManager{
Dialer: h, Enabled: true,
Strategy: mux.ClientStrategy{ Picker: &mux.IncrementalWorkerPicker{
MaxConcurrency: config.Concurrency, Factory: &mux.DialingWorkerFactory{
MaxConnection: 128, Proxy: proxyHandler,
Dialer: h,
Strategy: mux.ClientStrategy{
MaxConcurrency: uint32(config.Concurrency),
MaxConnection: 128,
},
},
}, },
}, }
}, }
if config.XudpConcurrency < 0 {
h.xudp = &mux.ClientManager{Enabled: false}
}
if config.XudpConcurrency == 0 {
h.xudp = nil // same as before
}
if config.XudpConcurrency > 0 {
h.xudp = &mux.ClientManager{
Enabled: true,
Picker: &mux.IncrementalWorkerPicker{
Factory: &mux.DialingWorkerFactory{
Proxy: proxyHandler,
Dialer: h,
Strategy: mux.ClientStrategy{
MaxConcurrency: uint32(config.XudpConcurrency),
MaxConnection: 128,
},
},
},
}
}
h.udp443 = config.XudpProxyUDP443
} }
} }
@@ -136,31 +166,54 @@ func (h *Handler) Tag() string {
// Dispatch implements proxy.Outbound.Dispatch. // Dispatch implements proxy.Outbound.Dispatch.
func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) { func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
if h.mux != nil && (h.mux.Enabled || session.MuxPreferedFromContext(ctx)) { if h.mux != nil {
if err := h.mux.Dispatch(ctx, link); err != nil { test := func(err error) {
err := newError("failed to process mux outbound traffic").Base(err) if err != nil {
session.SubmitOutboundErrorToOriginator(ctx, err) err := newError("failed to process mux outbound traffic").Base(err)
err.WriteToLog(session.ExportIDToError(ctx)) session.SubmitOutboundErrorToOriginator(ctx, err)
common.Interrupt(link.Writer) err.WriteToLog(session.ExportIDToError(ctx))
} common.Interrupt(link.Writer)
} else {
err := h.proxy.Process(ctx, link, h)
if err != nil {
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, context.Canceled) {
err = nil
} }
} }
if err != nil { outbound := session.OutboundFromContext(ctx)
// Ensure outbound ray is properly closed. if outbound.Target.Network == net.Network_UDP && outbound.Target.Port == 443 {
err := newError("failed to process outbound traffic").Base(err) switch h.udp443 {
session.SubmitOutboundErrorToOriginator(ctx, err) case "reject":
err.WriteToLog(session.ExportIDToError(ctx)) test(newError("XUDP rejected UDP/443 traffic").AtInfo())
common.Interrupt(link.Writer) return
} else { case "skip":
common.Must(common.Close(link.Writer)) goto out
}
}
if h.xudp != nil && outbound.Target.Network == net.Network_UDP {
if !h.xudp.Enabled {
goto out
}
test(h.xudp.Dispatch(ctx, link))
return
}
if h.mux.Enabled {
test(h.mux.Dispatch(ctx, link))
return
} }
common.Interrupt(link.Reader)
} }
out:
err := h.proxy.Process(ctx, link, h)
if err != nil {
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, context.Canceled) {
err = nil
}
}
if err != nil {
// Ensure outbound ray is properly closed.
err := newError("failed to process outbound traffic").Base(err)
session.SubmitOutboundErrorToOriginator(ctx, err)
err.WriteToLog(session.ExportIDToError(ctx))
common.Interrupt(link.Writer)
} else {
common.Close(link.Writer)
}
common.Interrupt(link.Reader)
} }
// Address implements internet.Dialer. // Address implements internet.Dialer.

View File

@@ -11,13 +11,21 @@ import (
) )
func (h *Handler) getUoTConnection(ctx context.Context, dest net.Destination) (stat.Connection, error) { func (h *Handler) getUoTConnection(ctx context.Context, dest net.Destination) (stat.Connection, error) {
if !dest.Address.Family().IsDomain() || dest.Address.Domain() != uot.UOTMagicAddress { if !dest.Address.Family().IsDomain() {
return nil, os.ErrInvalid
}
var uotVersion int
if dest.Address.Domain() == uot.MagicAddress {
uotVersion = uot.Version
} else if dest.Address.Domain() == uot.LegacyMagicAddress {
uotVersion = uot.LegacyVersion
} else {
return nil, os.ErrInvalid return nil, os.ErrInvalid
} }
packetConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{IP: net.AnyIP.IP(), Port: 0}, h.streamSettings.SocketSettings) packetConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{IP: net.AnyIP.IP(), Port: 0}, h.streamSettings.SocketSettings)
if err != nil { if err != nil {
return nil, newError("unable to listen socket").Base(err) return nil, newError("unable to listen socket").Base(err)
} }
conn := uot.NewServerConn(packetConn) conn := uot.NewServerConn(packetConn, uotVersion)
return h.getStatCouterConnection(conn), nil return h.getStatCouterConnection(conn), nil
} }

347
app/tun/config.pb.go Normal file
View File

@@ -0,0 +1,347 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.21.12
// source: app/tun/config.proto
package tun
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
InterfaceName string `protobuf:"bytes,1,opt,name=interface_name,json=interfaceName,proto3" json:"interface_name,omitempty"`
Inet4Address []string `protobuf:"bytes,2,rep,name=inet4_address,json=inet4Address,proto3" json:"inet4_address,omitempty"`
Inet6Address []string `protobuf:"bytes,3,rep,name=inet6_address,json=inet6Address,proto3" json:"inet6_address,omitempty"`
Mtu uint32 `protobuf:"varint,4,opt,name=mtu,proto3" json:"mtu,omitempty"`
AutoRoute bool `protobuf:"varint,5,opt,name=auto_route,json=autoRoute,proto3" json:"auto_route,omitempty"`
StrictRoute bool `protobuf:"varint,6,opt,name=strict_route,json=strictRoute,proto3" json:"strict_route,omitempty"`
Inet4RouteAddress []string `protobuf:"bytes,7,rep,name=inet4_route_address,json=inet4RouteAddress,proto3" json:"inet4_route_address,omitempty"`
Inet6RouteAddress []string `protobuf:"bytes,8,rep,name=inet6_route_address,json=inet6RouteAddress,proto3" json:"inet6_route_address,omitempty"`
EndpointIndependentNat bool `protobuf:"varint,9,opt,name=endpoint_independent_nat,json=endpointIndependentNat,proto3" json:"endpoint_independent_nat,omitempty"`
UdpTimeout int64 `protobuf:"varint,10,opt,name=udp_timeout,json=udpTimeout,proto3" json:"udp_timeout,omitempty"`
Stack string `protobuf:"bytes,11,opt,name=stack,proto3" json:"stack,omitempty"`
IncludeUid []uint32 `protobuf:"varint,12,rep,packed,name=include_uid,json=includeUid,proto3" json:"include_uid,omitempty"`
IncludeUidRange []string `protobuf:"bytes,13,rep,name=include_uid_range,json=includeUidRange,proto3" json:"include_uid_range,omitempty"`
ExcludeUid []uint32 `protobuf:"varint,14,rep,packed,name=exclude_uid,json=excludeUid,proto3" json:"exclude_uid,omitempty"`
ExcludeUidRange []string `protobuf:"bytes,15,rep,name=exclude_uid_range,json=excludeUidRange,proto3" json:"exclude_uid_range,omitempty"`
IncludeAndroidUser []int32 `protobuf:"varint,16,rep,packed,name=include_android_user,json=includeAndroidUser,proto3" json:"include_android_user,omitempty"`
IncludePackage []string `protobuf:"bytes,17,rep,name=include_package,json=includePackage,proto3" json:"include_package,omitempty"`
ExcludePackage []string `protobuf:"bytes,18,rep,name=exclude_package,json=excludePackage,proto3" json:"exclude_package,omitempty"`
// for xray
AutoDetectInterface bool `protobuf:"varint,100,opt,name=auto_detect_interface,json=autoDetectInterface,proto3" json:"auto_detect_interface,omitempty"`
OverrideAndroidVpn bool `protobuf:"varint,101,opt,name=override_android_vpn,json=overrideAndroidVpn,proto3" json:"override_android_vpn,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_tun_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_tun_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_tun_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetInterfaceName() string {
if x != nil {
return x.InterfaceName
}
return ""
}
func (x *Config) GetInet4Address() []string {
if x != nil {
return x.Inet4Address
}
return nil
}
func (x *Config) GetInet6Address() []string {
if x != nil {
return x.Inet6Address
}
return nil
}
func (x *Config) GetMtu() uint32 {
if x != nil {
return x.Mtu
}
return 0
}
func (x *Config) GetAutoRoute() bool {
if x != nil {
return x.AutoRoute
}
return false
}
func (x *Config) GetStrictRoute() bool {
if x != nil {
return x.StrictRoute
}
return false
}
func (x *Config) GetInet4RouteAddress() []string {
if x != nil {
return x.Inet4RouteAddress
}
return nil
}
func (x *Config) GetInet6RouteAddress() []string {
if x != nil {
return x.Inet6RouteAddress
}
return nil
}
func (x *Config) GetEndpointIndependentNat() bool {
if x != nil {
return x.EndpointIndependentNat
}
return false
}
func (x *Config) GetUdpTimeout() int64 {
if x != nil {
return x.UdpTimeout
}
return 0
}
func (x *Config) GetStack() string {
if x != nil {
return x.Stack
}
return ""
}
func (x *Config) GetIncludeUid() []uint32 {
if x != nil {
return x.IncludeUid
}
return nil
}
func (x *Config) GetIncludeUidRange() []string {
if x != nil {
return x.IncludeUidRange
}
return nil
}
func (x *Config) GetExcludeUid() []uint32 {
if x != nil {
return x.ExcludeUid
}
return nil
}
func (x *Config) GetExcludeUidRange() []string {
if x != nil {
return x.ExcludeUidRange
}
return nil
}
func (x *Config) GetIncludeAndroidUser() []int32 {
if x != nil {
return x.IncludeAndroidUser
}
return nil
}
func (x *Config) GetIncludePackage() []string {
if x != nil {
return x.IncludePackage
}
return nil
}
func (x *Config) GetExcludePackage() []string {
if x != nil {
return x.ExcludePackage
}
return nil
}
func (x *Config) GetAutoDetectInterface() bool {
if x != nil {
return x.AutoDetectInterface
}
return false
}
func (x *Config) GetOverrideAndroidVpn() bool {
if x != nil {
return x.OverrideAndroidVpn
}
return false
}
var File_app_tun_config_proto protoreflect.FileDescriptor
var file_app_tun_config_proto_rawDesc = []byte{
0x0a, 0x14, 0x61, 0x70, 0x70, 0x2f, 0x74, 0x75, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x74, 0x75, 0x6e, 0x22, 0xa2, 0x06, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61,
0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x65, 0x74, 0x34, 0x5f,
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x69,
0x6e, 0x65, 0x74, 0x34, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69,
0x6e, 0x65, 0x74, 0x36, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x03,
0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x65, 0x74, 0x36, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x12, 0x10, 0x0a, 0x03, 0x6d, 0x74, 0x75, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6d,
0x74, 0x75, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65,
0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x61, 0x75, 0x74, 0x6f, 0x52, 0x6f, 0x75, 0x74,
0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5f, 0x72, 0x6f, 0x75, 0x74,
0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x52,
0x6f, 0x75, 0x74, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x69, 0x6e, 0x65, 0x74, 0x34, 0x5f, 0x72, 0x6f,
0x75, 0x74, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28,
0x09, 0x52, 0x11, 0x69, 0x6e, 0x65, 0x74, 0x34, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x41, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x69, 0x6e, 0x65, 0x74, 0x36, 0x5f, 0x72, 0x6f,
0x75, 0x74, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28,
0x09, 0x52, 0x11, 0x69, 0x6e, 0x65, 0x74, 0x36, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x41, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x12, 0x38, 0x0a, 0x18, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
0x5f, 0x69, 0x6e, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x74,
0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
0x49, 0x6e, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x74, 0x12, 0x1f,
0x0a, 0x0b, 0x75, 0x64, 0x70, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x0a, 0x20,
0x01, 0x28, 0x03, 0x52, 0x0a, 0x75, 0x64, 0x70, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12,
0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
0x73, 0x74, 0x61, 0x63, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65,
0x5f, 0x75, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0a, 0x69, 0x6e, 0x63, 0x6c,
0x75, 0x64, 0x65, 0x55, 0x69, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,
0x65, 0x5f, 0x75, 0x69, 0x64, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x0d, 0x20, 0x03, 0x28,
0x09, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x55, 0x69, 0x64, 0x52, 0x61, 0x6e,
0x67, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x75, 0x69,
0x64, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0a, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65,
0x55, 0x69, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x75,
0x69, 0x64, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f,
0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x55, 0x69, 0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12,
0x30, 0x0a, 0x14, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x61, 0x6e, 0x64, 0x72, 0x6f,
0x69, 0x64, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, 0x10, 0x20, 0x03, 0x28, 0x05, 0x52, 0x12, 0x69,
0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x55, 0x73, 0x65,
0x72, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x70, 0x61, 0x63,
0x6b, 0x61, 0x67, 0x65, 0x18, 0x11, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c,
0x75, 0x64, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x78,
0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x18, 0x12, 0x20,
0x03, 0x28, 0x09, 0x52, 0x0e, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x61, 0x63, 0x6b,
0x61, 0x67, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x74, 0x65,
0x63, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x64, 0x20, 0x01,
0x28, 0x08, 0x52, 0x13, 0x61, 0x75, 0x74, 0x6f, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x49, 0x6e,
0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x6f, 0x76, 0x65, 0x72, 0x72,
0x69, 0x64, 0x65, 0x5f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x76, 0x70, 0x6e, 0x18,
0x65, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x41,
0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x56, 0x70, 0x6e, 0x42, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6d,
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x74, 0x75, 0x6e, 0x50, 0x01, 0x5a,
0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73,
0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x74,
0x75, 0x6e, 0xaa, 0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x54, 0x75,
0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_tun_config_proto_rawDescOnce sync.Once
file_app_tun_config_proto_rawDescData = file_app_tun_config_proto_rawDesc
)
func file_app_tun_config_proto_rawDescGZIP() []byte {
file_app_tun_config_proto_rawDescOnce.Do(func() {
file_app_tun_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_tun_config_proto_rawDescData)
})
return file_app_tun_config_proto_rawDescData
}
var file_app_tun_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_app_tun_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: xray.app.tun.Config
}
var file_app_tun_config_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_app_tun_config_proto_init() }
func file_app_tun_config_proto_init() {
if File_app_tun_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_tun_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_tun_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_app_tun_config_proto_goTypes,
DependencyIndexes: file_app_tun_config_proto_depIdxs,
MessageInfos: file_app_tun_config_proto_msgTypes,
}.Build()
File_app_tun_config_proto = out.File
file_app_tun_config_proto_rawDesc = nil
file_app_tun_config_proto_goTypes = nil
file_app_tun_config_proto_depIdxs = nil
}

32
app/tun/config.proto Normal file
View File

@@ -0,0 +1,32 @@
syntax = "proto3";
package xray.app.tun;
option csharp_namespace = "Xray.App.Tun";
option go_package = "github.com/xtls/xray-core/app/tun";
option java_package = "com.xray.app.tun";
option java_multiple_files = true;
message Config {
string interface_name = 1;
repeated string inet4_address = 2;
repeated string inet6_address = 3;
uint32 mtu = 4;
bool auto_route = 5;
bool strict_route = 6;
repeated string inet4_route_address = 7;
repeated string inet6_route_address = 8;
bool endpoint_independent_nat = 9;
int64 udp_timeout = 10;
string stack = 11;
repeated uint32 include_uid = 12;
repeated string include_uid_range = 13;
repeated uint32 exclude_uid = 14;
repeated string exclude_uid_range = 15;
repeated int32 include_android_user = 16;
repeated string include_package = 17;
repeated string exclude_package = 18;
// for xray
bool auto_detect_interface = 100;
bool override_android_vpn = 101;
}

View File

@@ -1,4 +1,4 @@
package xtls package tun
import "github.com/xtls/xray-core/common/errors" import "github.com/xtls/xray-core/common/errors"

View File

@@ -0,0 +1,50 @@
package tun
import (
"net"
"github.com/sagernet/sing/common/control"
)
var _ control.InterfaceFinder = (*myInterfaceFinder)(nil)
type myInterfaceFinder struct {
ifs []net.Interface
}
func (f *myInterfaceFinder) update() error {
ifs, err := net.Interfaces()
if err != nil {
return err
}
f.ifs = ifs
return nil
}
func (f *myInterfaceFinder) InterfaceIndexByName(name string) (interfaceIndex int, err error) {
for _, netInterface := range f.ifs {
if netInterface.Name == name {
return netInterface.Index, nil
}
}
netInterface, err := net.InterfaceByName(name)
if err != nil {
return
}
f.update()
return netInterface.Index, nil
}
func (f *myInterfaceFinder) InterfaceNameByIndex(index int) (interfaceName string, err error) {
for _, netInterface := range f.ifs {
if netInterface.Index == index {
return netInterface.Name, nil
}
}
netInterface, err := net.InterfaceByIndex(index)
if err != nil {
return
}
f.update()
return netInterface.Name, nil
}

42
app/tun/packet_conn.go Normal file
View File

@@ -0,0 +1,42 @@
package tun
import (
sing_common "github.com/sagernet/sing/common"
sing_buf "github.com/sagernet/sing/common/buf"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/singbridge"
)
type PacketConn struct {
N.PacketConn
}
func (p *PacketConn) ReadMultiBuffer() (buf.MultiBuffer, error) {
packet := buf.New()
packet.Extend(buf.Size)
sPacket := sing_buf.With(packet.Bytes())
destination, err := p.ReadPacket(sPacket)
if err != nil {
packet.Release()
return nil, err
}
packet.Clear()
packet.Resize(int32(sPacket.Start()), int32(sPacket.Start()+sPacket.Len()))
destinationX := singbridge.ToDestination(destination, net.Network_UDP)
packet.UDP = &destinationX
return buf.MultiBuffer{packet}, nil
}
func (p *PacketConn) WriteMultiBuffer(mb buf.MultiBuffer) error {
defer buf.ReleaseMulti(mb)
for _, buffer := range mb {
destination := sing_common.PtrValueOrDefault(buffer.UDP)
err := p.PacketConn.WritePacket(sing_buf.As(buffer.Bytes()), singbridge.ToSocksaddr(destination))
if err != nil {
return err
}
}
return nil
}

296
app/tun/tun.go Normal file
View File

@@ -0,0 +1,296 @@
package tun
import (
"context"
"net/netip"
"runtime"
"strconv"
"strings"
"time"
"github.com/sagernet/sing-tun"
sing_common "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/ranges"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/routing"
features_tun "github.com/xtls/xray-core/features/tun"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet"
)
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
return New(ctx, cfg.(*Config))
}))
}
var TunInitializer features_tun.Interface = (*Tun)(nil)
type Tun struct {
ctx context.Context
dispatcher routing.Dispatcher
logger logger.ContextLogger
tunOptions tun.Options
stack string
endpointIndependentNat bool
udpTimeout int64
tunIf tun.Tun
tunStack tun.Stack
networkMonitor tun.NetworkUpdateMonitor
interfaceMonitor tun.DefaultInterfaceMonitor
packageManager tun.PackageManager
interfaceFinder *myInterfaceFinder
}
func New(ctx context.Context, config *Config) (*Tun, error) {
instance := core.MustFromContext(ctx)
tunInterface := &Tun{
ctx: ctx,
dispatcher: instance.GetFeature(routing.DispatcherType()).(routing.Dispatcher),
logger: singbridge.NewLogger(newError),
stack: config.Stack,
endpointIndependentNat: config.EndpointIndependentNat,
udpTimeout: int64(5 * time.Minute.Seconds()),
interfaceFinder: new(myInterfaceFinder),
}
networkUpdateMonitor, err := tun.NewNetworkUpdateMonitor(tunInterface)
if err != nil {
return nil, err
}
defaultInterfaceMonitor, err := tun.NewDefaultInterfaceMonitor(networkUpdateMonitor, tun.DefaultInterfaceMonitorOptions{
OverrideAndroidVPN: config.OverrideAndroidVpn,
})
if err != nil {
return nil, err
}
defaultInterfaceMonitor.RegisterCallback(tunInterface.notifyNetworkUpdate)
if config.AutoDetectInterface {
networkUpdateMonitor.RegisterCallback(tunInterface.interfaceFinder.update)
const useInterfaceName = runtime.GOOS == "linux" || runtime.GOOS == "android"
bindFunc := control.BindToInterfaceFunc(tunInterface.interfaceFinder, func(network string, address string) (interfaceName string, interfaceIndex int) {
remoteAddr := M.ParseSocksaddr(address).Addr
if useInterfaceName {
return defaultInterfaceMonitor.DefaultInterfaceName(remoteAddr), -1
} else {
return "", defaultInterfaceMonitor.DefaultInterfaceIndex(remoteAddr)
}
})
internet.UseAlternativeSystemDialer(nil)
internet.RegisterDialerController(bindFunc)
internet.RegisterListenerController(bindFunc)
}
if runtime.GOOS == "android" {
packageManage, err := tun.NewPackageManager(tunInterface)
if err != nil {
return nil, err
}
tunInterface.packageManager = packageManage
}
tunInterface.networkMonitor = networkUpdateMonitor
tunInterface.interfaceMonitor = defaultInterfaceMonitor
tunName := config.InterfaceName
if tunName == "" {
tunName = tun.CalculateInterfaceName("")
}
tunMTU := config.Mtu
if tunMTU == 0 {
tunMTU = 9000
}
includeUID := uidToRange(config.IncludeUid)
if len(config.IncludeUidRange) > 0 {
var err error
includeUID, err = parseRange(includeUID, config.IncludeUidRange)
if err != nil {
return nil, E.Cause(err, "parse include_uid_range")
}
}
excludeUID := uidToRange(config.ExcludeUid)
if len(config.ExcludeUidRange) > 0 {
var err error
excludeUID, err = parseRange(excludeUID, config.ExcludeUidRange)
if err != nil {
return nil, E.Cause(err, "parse exclude_uid_range")
}
}
if config.UdpTimeout != 0 {
tunInterface.udpTimeout = config.UdpTimeout
}
tunInterface.tunOptions = tun.Options{
Name: tunName,
Inet4Address: sing_common.Map(config.Inet4Address, netip.MustParsePrefix),
Inet6Address: sing_common.Map(config.Inet6Address, netip.MustParsePrefix),
MTU: tunMTU,
AutoRoute: config.AutoRoute,
StrictRoute: config.StrictRoute,
Inet4RouteAddress: sing_common.Map(config.Inet4RouteAddress, netip.MustParsePrefix),
Inet6RouteAddress: sing_common.Map(config.Inet6RouteAddress, netip.MustParsePrefix),
IncludeUID: includeUID,
ExcludeUID: excludeUID,
IncludeAndroidUser: sing_common.Map(config.IncludeAndroidUser, func(it int32) int {
return int(it)
}),
IncludePackage: config.IncludePackage,
ExcludePackage: config.ExcludePackage,
InterfaceMonitor: defaultInterfaceMonitor,
TableIndex: 2022,
}
return tunInterface, nil
}
func (t *Tun) Type() interface{} {
return features_tun.InterfaceType()
}
func (t *Tun) Start() error {
err := t.interfaceMonitor.Start()
if err != nil {
return err
}
err = t.networkMonitor.Start()
if err != nil {
return err
}
if runtime.GOOS == "android" {
err = t.packageManager.Start()
if err != nil {
return err
}
t.tunOptions.BuildAndroidRules(t.packageManager, t)
}
tunIf, err := tun.New(t.tunOptions)
if err != nil {
return E.Cause(err, "configure tun interface")
}
t.tunIf = tunIf
t.tunStack, err = tun.NewStack(t.stack, tun.StackOptions{
Context: t.ctx,
Tun: tunIf,
MTU: t.tunOptions.MTU,
Name: t.tunOptions.Name,
Inet4Address: t.tunOptions.Inet4Address,
Inet6Address: t.tunOptions.Inet6Address,
EndpointIndependentNat: t.endpointIndependentNat,
UDPTimeout: t.udpTimeout,
Handler: t,
Logger: t.logger,
})
if err != nil {
return err
}
err = t.tunStack.Start()
if err != nil {
return err
}
t.logger.Info("tun started at ", t.tunOptions.Name)
return nil
}
func (t *Tun) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
sid := session.NewID()
ctx = session.ContextWithID(ctx, sid)
t.logger.InfoContext(ctx, "inbound connection from ", metadata.Source)
t.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
ctx = session.ContextWithInbound(ctx, &session.Inbound{
Source: net.DestinationFromAddr(metadata.Source.TCPAddr()),
Conn: conn,
})
wConn := singbridge.NewConn(conn)
_ = t.dispatcher.DispatchLink(ctx, singbridge.ToDestination(metadata.Destination, net.Network_TCP), &transport.Link{
Reader: wConn,
Writer: wConn,
})
conn.Close()
return nil
}
func (t *Tun) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
sid := session.NewID()
ctx = session.ContextWithID(ctx, sid)
t.logger.InfoContext(ctx, "inbound packet connection from ", metadata.Source)
t.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination)
ctx = session.ContextWithInbound(ctx, &session.Inbound{
Source: net.DestinationFromAddr(metadata.Source.UDPAddr()),
})
pc := &PacketConn{conn}
_ = t.dispatcher.DispatchLink(ctx, singbridge.ToDestination(metadata.Destination, net.Network_UDP), &transport.Link{
Reader: pc,
Writer: pc,
})
conn.Close()
return nil
}
func (t *Tun) Close() error {
return sing_common.Close(
t.packageManager,
t.interfaceMonitor,
t.networkMonitor,
t.tunStack,
t.tunIf,
)
}
func (t *Tun) OnPackagesUpdated(packages int, sharedUsers int) {
t.logger.Info("updated packages list: ", packages, " packages, ", sharedUsers, " shared users")
}
func (t *Tun) NewError(ctx context.Context, err error) {
}
func (t *Tun) notifyNetworkUpdate(int) error {
if runtime.GOOS == "android" {
var vpnStatus string
if t.interfaceMonitor.AndroidVPNEnabled() {
vpnStatus = "enabled"
} else {
vpnStatus = "disabled"
}
t.logger.Info("updated default interface ", t.interfaceMonitor.DefaultInterfaceName(netip.IPv4Unspecified()), ", index ", t.interfaceMonitor.DefaultInterfaceIndex(netip.IPv4Unspecified()), ", vpn ", vpnStatus)
} else {
t.logger.Info("updated default interface ", t.interfaceMonitor.DefaultInterfaceName(netip.IPv4Unspecified()), ", index ", t.interfaceMonitor.DefaultInterfaceIndex(netip.IPv4Unspecified()))
}
return nil
}
func uidToRange(uidList []uint32) []ranges.Range[uint32] {
return sing_common.Map(uidList, func(uid uint32) ranges.Range[uint32] {
return ranges.NewSingle(uint32(uid))
})
}
func parseRange(uidRanges []ranges.Range[uint32], rangeList []string) ([]ranges.Range[uint32], error) {
for _, uidRange := range rangeList {
if !strings.Contains(uidRange, ":") {
return nil, E.New("missing ':' in range: ", uidRange)
}
subIndex := strings.Index(uidRange, ":")
if subIndex == 0 {
return nil, E.New("missing range start: ", uidRange)
} else if subIndex == len(uidRange)-1 {
return nil, E.New("missing range end: ", uidRange)
}
var start, end uint64
var err error
start, err = strconv.ParseUint(uidRange[:subIndex], 10, 32)
if err != nil {
return nil, E.Cause(err, "parse range start")
}
end, err = strconv.ParseUint(uidRange[subIndex+1:], 10, 32)
if err != nil {
return nil, E.Cause(err, "parse range end")
}
uidRanges = append(uidRanges, ranges.New(uint32(start), uint32(end)))
}
return uidRanges, nil
}

View File

@@ -14,6 +14,7 @@ import (
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/done"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/common/xudp"
"github.com/xtls/xray-core/proxy" "github.com/xtls/xray-core/proxy"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
@@ -247,22 +248,20 @@ func fetchInput(ctx context.Context, s *Session, output buf.Writer) {
transferType = protocol.TransferTypePacket transferType = protocol.TransferTypePacket
} }
s.transferType = transferType s.transferType = transferType
writer := NewWriter(s.ID, dest, output, transferType) writer := NewWriter(s.ID, dest, output, transferType, xudp.GetGlobalID(ctx))
defer s.Close() defer s.Close(false)
defer writer.Close() defer writer.Close()
newError("dispatching request to ", dest).WriteToLog(session.ExportIDToError(ctx)) newError("dispatching request to ", dest).WriteToLog(session.ExportIDToError(ctx))
if err := writeFirstPayload(s.input, writer); err != nil { if err := writeFirstPayload(s.input, writer); err != nil {
newError("failed to write first payload").Base(err).WriteToLog(session.ExportIDToError(ctx)) newError("failed to write first payload").Base(err).WriteToLog(session.ExportIDToError(ctx))
writer.hasError = true writer.hasError = true
common.Interrupt(s.input)
return return
} }
if err := buf.Copy(s.input, writer); err != nil { if err := buf.Copy(s.input, writer); err != nil {
newError("failed to fetch all input").Base(err).WriteToLog(session.ExportIDToError(ctx)) newError("failed to fetch all input").Base(err).WriteToLog(session.ExportIDToError(ctx))
writer.hasError = true writer.hasError = true
common.Interrupt(s.input)
return return
} }
} }
@@ -335,15 +334,8 @@ func (m *ClientWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.Buffere
err := buf.Copy(rr, s.output) err := buf.Copy(rr, s.output)
if err != nil && buf.IsWriteError(err) { if err != nil && buf.IsWriteError(err) {
newError("failed to write to downstream. closing session ", s.ID).Base(err).WriteToLog() newError("failed to write to downstream. closing session ", s.ID).Base(err).WriteToLog()
s.Close(false)
// Notify remote peer to close this session. return buf.Copy(rr, buf.Discard)
closingWriter := NewResponseWriter(meta.SessionID, m.link.Writer, protocol.TransferTypeStream)
closingWriter.Close()
drainErr := buf.Copy(rr, buf.Discard)
common.Interrupt(s.input)
s.Close()
return drainErr
} }
return err return err
@@ -351,12 +343,7 @@ func (m *ClientWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.Buffere
func (m *ClientWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.BufferedReader) error { func (m *ClientWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.BufferedReader) error {
if s, found := m.sessionManager.Get(meta.SessionID); found { if s, found := m.sessionManager.Get(meta.SessionID); found {
if meta.Option.Has(OptionError) { s.Close(false)
common.Interrupt(s.input)
common.Interrupt(s.output)
}
common.Interrupt(s.input)
s.Close()
} }
if meta.Option.Has(OptionData) { if meta.Option.Has(OptionData) {
return buf.Copy(NewStreamReader(reader), buf.Discard) return buf.Copy(NewStreamReader(reader), buf.Discard)

View File

@@ -58,6 +58,7 @@ type FrameMetadata struct {
SessionID uint16 SessionID uint16
Option bitmask.Byte Option bitmask.Byte
SessionStatus SessionStatus SessionStatus SessionStatus
GlobalID [8]byte
} }
func (f FrameMetadata) WriteTo(b *buf.Buffer) error { func (f FrameMetadata) WriteTo(b *buf.Buffer) error {
@@ -81,6 +82,9 @@ func (f FrameMetadata) WriteTo(b *buf.Buffer) error {
if err := addrParser.WriteAddressPort(b, f.Target.Address, f.Target.Port); err != nil { if err := addrParser.WriteAddressPort(b, f.Target.Address, f.Target.Port); err != nil {
return err return err
} }
if b.UDP != nil { // make sure it's user's proxy request
b.Write(f.GlobalID[:]) // no need to check whether it's empty
}
} else if b.UDP != nil { } else if b.UDP != nil {
b.WriteByte(byte(TargetNetworkUDP)) b.WriteByte(byte(TargetNetworkUDP))
addrParser.WriteAddressPort(b, b.UDP.Address, b.UDP.Port) addrParser.WriteAddressPort(b, b.UDP.Address, b.UDP.Port)
@@ -122,7 +126,8 @@ func (f *FrameMetadata) UnmarshalFromBuffer(b *buf.Buffer) error {
f.Option = bitmask.Byte(b.Byte(3)) f.Option = bitmask.Byte(b.Byte(3))
f.Target.Network = net.Network_Unknown f.Target.Network = net.Network_Unknown
if f.SessionStatus == SessionStatusNew || (f.SessionStatus == SessionStatusKeep && b.Len() != 4) { if f.SessionStatus == SessionStatusNew || (f.SessionStatus == SessionStatusKeep && b.Len() > 4 &&
TargetNetwork(b.Byte(4)) == TargetNetworkUDP) { // MUST check the flag first
if b.Len() < 8 { if b.Len() < 8 {
return newError("insufficient buffer: ", b.Len()) return newError("insufficient buffer: ", b.Len())
} }
@@ -144,5 +149,11 @@ func (f *FrameMetadata) UnmarshalFromBuffer(b *buf.Buffer) error {
} }
} }
// Application data is essential, to test whether the pipe is closed.
if f.SessionStatus == SessionStatusNew && f.Option.Has(OptionData) &&
f.Target.Network == net.Network_UDP && b.Len() >= 8 {
copy(f.GlobalID[:], b.Bytes())
}
return nil return nil
} }

View File

@@ -32,13 +32,13 @@ func TestReaderWriter(t *testing.T) {
pReader, pWriter := pipe.New(pipe.WithSizeLimit(1024)) pReader, pWriter := pipe.New(pipe.WithSizeLimit(1024))
dest := net.TCPDestination(net.DomainAddress("example.com"), 80) dest := net.TCPDestination(net.DomainAddress("example.com"), 80)
writer := NewWriter(1, dest, pWriter, protocol.TransferTypeStream) writer := NewWriter(1, dest, pWriter, protocol.TransferTypeStream, [8]byte{})
dest2 := net.TCPDestination(net.LocalHostIP, 443) dest2 := net.TCPDestination(net.LocalHostIP, 443)
writer2 := NewWriter(2, dest2, pWriter, protocol.TransferTypeStream) writer2 := NewWriter(2, dest2, pWriter, protocol.TransferTypeStream, [8]byte{})
dest3 := net.TCPDestination(net.LocalHostIPv6, 18374) dest3 := net.TCPDestination(net.LocalHostIPv6, 18374)
writer3 := NewWriter(3, dest3, pWriter, protocol.TransferTypeStream) writer3 := NewWriter(3, dest3, pWriter, protocol.TransferTypeStream, [8]byte{})
writePayload := func(writer *Writer, payload ...byte) error { writePayload := func(writer *Writer, payload ...byte) error {
b := buf.New() b := buf.New()

View File

@@ -99,7 +99,7 @@ func handle(ctx context.Context, s *Session, output buf.Writer) {
} }
writer.Close() writer.Close()
s.Close() s.Close(false)
} }
func (w *ServerWorker) ActiveConnections() uint32 { func (w *ServerWorker) ActiveConnections() uint32 {
@@ -131,6 +131,81 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
} }
ctx = log.ContextWithAccessMessage(ctx, msg) ctx = log.ContextWithAccessMessage(ctx, msg)
} }
if network := session.AllowedNetworkFromContext(ctx); network != net.Network_Unknown {
if meta.Target.Network != network {
return newError("unexpected network ", meta.Target.Network) // it will break the whole Mux connection
}
}
if meta.GlobalID != [8]byte{} { // MUST ignore empty Global ID
mb, err := NewPacketReader(reader, &meta.Target).ReadMultiBuffer()
if err != nil {
return err
}
XUDPManager.Lock()
x := XUDPManager.Map[meta.GlobalID]
if x == nil {
x = &XUDP{GlobalID: meta.GlobalID}
XUDPManager.Map[meta.GlobalID] = x
XUDPManager.Unlock()
} else {
if x.Status == Initializing { // nearly impossible
XUDPManager.Unlock()
newError("XUDP hit ", meta.GlobalID).Base(errors.New("conflict")).AtWarning().WriteToLog(session.ExportIDToError(ctx))
// It's not a good idea to return an err here, so just let client wait.
// Client will receive an End frame after sending a Keep frame.
return nil
}
x.Status = Initializing
XUDPManager.Unlock()
x.Mux.Close(false) // detach from previous Mux
b := buf.New()
b.Write(mb[0].Bytes())
b.UDP = mb[0].UDP
if err = x.Mux.output.WriteMultiBuffer(mb); err != nil {
x.Interrupt()
mb = buf.MultiBuffer{b}
} else {
b.Release()
mb = nil
}
newError("XUDP hit ", meta.GlobalID).Base(err).WriteToLog(session.ExportIDToError(ctx))
}
if mb != nil {
ctx = session.ContextWithTimeoutOnly(ctx, true)
// Actually, it won't return an error in Xray-core's implementations.
link, err := w.dispatcher.Dispatch(ctx, meta.Target)
if err != nil {
XUDPManager.Lock()
delete(XUDPManager.Map, x.GlobalID)
XUDPManager.Unlock()
err = newError("XUDP new ", meta.GlobalID).Base(errors.New("failed to dispatch request to ", meta.Target).Base(err))
return err // it will break the whole Mux connection
}
link.Writer.WriteMultiBuffer(mb) // it's meaningless to test a new pipe
x.Mux = &Session{
input: link.Reader,
output: link.Writer,
}
newError("XUDP new ", meta.GlobalID).Base(err).WriteToLog(session.ExportIDToError(ctx))
}
x.Mux = &Session{
input: x.Mux.input,
output: x.Mux.output,
parent: w.sessionManager,
ID: meta.SessionID,
transferType: protocol.TransferTypePacket,
XUDP: x,
}
go handle(ctx, x.Mux, w.link.Writer)
x.Status = Active
if !w.sessionManager.Add(x.Mux) {
x.Mux.Close(false)
}
return nil
}
link, err := w.dispatcher.Dispatch(ctx, meta.Target) link, err := w.dispatcher.Dispatch(ctx, meta.Target)
if err != nil { if err != nil {
if meta.Option.Has(OptionData) { if meta.Option.Has(OptionData) {
@@ -157,8 +232,7 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
rr := s.NewReader(reader, &meta.Target) rr := s.NewReader(reader, &meta.Target)
if err := buf.Copy(rr, s.output); err != nil { if err := buf.Copy(rr, s.output); err != nil {
buf.Copy(rr, buf.Discard) buf.Copy(rr, buf.Discard)
common.Interrupt(s.input) return s.Close(false)
return s.Close()
} }
return nil return nil
} }
@@ -182,15 +256,8 @@ func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.Buffere
if err != nil && buf.IsWriteError(err) { if err != nil && buf.IsWriteError(err) {
newError("failed to write to downstream writer. closing session ", s.ID).Base(err).WriteToLog() newError("failed to write to downstream writer. closing session ", s.ID).Base(err).WriteToLog()
s.Close(false)
// Notify remote peer to close this session. return buf.Copy(rr, buf.Discard)
closingWriter := NewResponseWriter(meta.SessionID, w.link.Writer, protocol.TransferTypeStream)
closingWriter.Close()
drainErr := buf.Copy(rr, buf.Discard)
common.Interrupt(s.input)
s.Close()
return drainErr
} }
return err return err
@@ -198,12 +265,7 @@ func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.Buffere
func (w *ServerWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.BufferedReader) error { func (w *ServerWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.BufferedReader) error {
if s, found := w.sessionManager.Get(meta.SessionID); found { if s, found := w.sessionManager.Get(meta.SessionID); found {
if meta.Option.Has(OptionError) { s.Close(false)
common.Interrupt(s.input)
common.Interrupt(s.output)
}
common.Interrupt(s.input)
s.Close()
} }
if meta.Option.Has(OptionData) { if meta.Option.Has(OptionData) {
return buf.Copy(NewStreamReader(reader), buf.Discard) return buf.Copy(NewStreamReader(reader), buf.Discard)

View File

@@ -1,12 +1,16 @@
package mux package mux
import ( import (
"io"
"runtime"
"sync" "sync"
"time"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/transport/pipe"
) )
type SessionManager struct { type SessionManager struct {
@@ -61,21 +65,25 @@ func (m *SessionManager) Allocate() *Session {
return s return s
} }
func (m *SessionManager) Add(s *Session) { func (m *SessionManager) Add(s *Session) bool {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
if m.closed { if m.closed {
return return false
} }
m.count++ m.count++
m.sessions[s.ID] = s m.sessions[s.ID] = s
return true
} }
func (m *SessionManager) Remove(id uint16) { func (m *SessionManager) Remove(locked bool, id uint16) {
m.Lock() if !locked {
defer m.Unlock() m.Lock()
defer m.Unlock()
}
locked = true
if m.closed { if m.closed {
return return
@@ -83,9 +91,11 @@ func (m *SessionManager) Remove(id uint16) {
delete(m.sessions, id) delete(m.sessions, id)
if len(m.sessions) == 0 { /*
m.sessions = make(map[uint16]*Session, 16) if len(m.sessions) == 0 {
} m.sessions = make(map[uint16]*Session, 16)
}
*/
} }
func (m *SessionManager) Get(id uint16) (*Session, bool) { func (m *SessionManager) Get(id uint16) (*Session, bool) {
@@ -127,8 +137,7 @@ func (m *SessionManager) Close() error {
m.closed = true m.closed = true
for _, s := range m.sessions { for _, s := range m.sessions {
common.Close(s.input) s.Close(true)
common.Close(s.output)
} }
m.sessions = nil m.sessions = nil
@@ -142,13 +151,40 @@ type Session struct {
parent *SessionManager parent *SessionManager
ID uint16 ID uint16
transferType protocol.TransferType transferType protocol.TransferType
closed bool
XUDP *XUDP
} }
// Close closes all resources associated with this session. // Close closes all resources associated with this session.
func (s *Session) Close() error { func (s *Session) Close(locked bool) error {
common.Close(s.output) if !locked {
common.Close(s.input) s.parent.Lock()
s.parent.Remove(s.ID) defer s.parent.Unlock()
}
locked = true
if s.closed {
return nil
}
s.closed = true
if s.XUDP == nil {
common.Interrupt(s.input)
common.Close(s.output)
} else {
// Stop existing handle(), then trigger writer.Close().
// Note that s.output may be dispatcher.SizeStatWriter.
s.input.(*pipe.Reader).ReturnAnError(io.EOF)
runtime.Gosched()
// If the error set by ReturnAnError still exists, clear it.
s.input.(*pipe.Reader).Recover()
XUDPManager.Lock()
if s.XUDP.Status == Active {
s.XUDP.Expire = time.Now().Add(time.Minute)
s.XUDP.Status = Expiring
newError("XUDP put ", s.XUDP.GlobalID).AtDebug().WriteToLog()
}
XUDPManager.Unlock()
}
s.parent.Remove(locked, s.ID)
return nil return nil
} }
@@ -159,3 +195,45 @@ func (s *Session) NewReader(reader *buf.BufferedReader, dest *net.Destination) b
} }
return NewPacketReader(reader, dest) return NewPacketReader(reader, dest)
} }
const (
Initializing = 0
Active = 1
Expiring = 2
)
type XUDP struct {
GlobalID [8]byte
Status uint64
Expire time.Time
Mux *Session
}
func (x *XUDP) Interrupt() {
common.Interrupt(x.Mux.input)
common.Close(x.Mux.output)
}
var XUDPManager struct {
sync.Mutex
Map map[[8]byte]*XUDP
}
func init() {
XUDPManager.Map = make(map[[8]byte]*XUDP)
go func() {
for {
time.Sleep(time.Minute)
now := time.Now()
XUDPManager.Lock()
for id, x := range XUDPManager.Map {
if x.Status == Expiring && now.After(x.Expire) {
x.Interrupt()
delete(XUDPManager.Map, id)
newError("XUDP del ", id).AtDebug().WriteToLog()
}
}
XUDPManager.Unlock()
}
}()
}

View File

@@ -44,7 +44,7 @@ func TestSessionManagerClose(t *testing.T) {
if m.CloseIfNoSession() { if m.CloseIfNoSession() {
t.Error("able to close") t.Error("able to close")
} }
m.Remove(s.ID) m.Remove(false, s.ID)
if !m.CloseIfNoSession() { if !m.CloseIfNoSession() {
t.Error("not able to close") t.Error("not able to close")
} }

View File

@@ -15,15 +15,17 @@ type Writer struct {
followup bool followup bool
hasError bool hasError bool
transferType protocol.TransferType transferType protocol.TransferType
globalID [8]byte
} }
func NewWriter(id uint16, dest net.Destination, writer buf.Writer, transferType protocol.TransferType) *Writer { func NewWriter(id uint16, dest net.Destination, writer buf.Writer, transferType protocol.TransferType, globalID [8]byte) *Writer {
return &Writer{ return &Writer{
id: id, id: id,
dest: dest, dest: dest,
writer: writer, writer: writer,
followup: false, followup: false,
transferType: transferType, transferType: transferType,
globalID: globalID,
} }
} }
@@ -40,6 +42,7 @@ func (w *Writer) getNextFrameMeta() FrameMetadata {
meta := FrameMetadata{ meta := FrameMetadata{
SessionID: w.id, SessionID: w.id,
Target: w.dest, Target: w.dest,
GlobalID: w.globalID,
} }
if w.followup { if w.followup {

View File

@@ -3,11 +3,10 @@ package protocol
import ( import (
"runtime" "runtime"
"golang.org/x/sys/cpu"
"github.com/xtls/xray-core/common/bitmask" "github.com/xtls/xray-core/common/bitmask"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/uuid" "github.com/xtls/xray-core/common/uuid"
"golang.org/x/sys/cpu"
) )
// RequestCommand is a custom command in a proxy request. // RequestCommand is a custom command in a proxy request.

View File

@@ -1,16 +1,18 @@
package quic package quic
import ( import (
"crypto"
"crypto/cipher" "crypto/cipher"
_ "crypto/tls"
"github.com/quic-go/qtls-go1-20" _ "unsafe"
) )
type ( type CipherSuiteTLS13 struct {
// A CipherSuiteTLS13 is a cipher suite for TLS 1.3 ID uint16
CipherSuiteTLS13 = qtls.CipherSuiteTLS13 KeyLen int
) AEAD func(key, fixedNonce []byte) cipher.AEAD
Hash crypto.Hash
func AEADAESGCMTLS13(key, fixedNonce []byte) cipher.AEAD {
return qtls.AEADAESGCMTLS13(key, fixedNonce)
} }
//go:linkname AEADAESGCMTLS13 crypto/tls.aeadAESGCMTLS13
func AEADAESGCMTLS13(key, nonceMask []byte) cipher.AEAD

View File

@@ -10,6 +10,7 @@ import (
"github.com/quic-go/quic-go/quicvarint" "github.com/quic-go/quic-go/quicvarint"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/bytespool"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
ptls "github.com/xtls/xray-core/common/protocol/tls" ptls "github.com/xtls/xray-core/common/protocol/tls"
"golang.org/x/crypto/hkdf" "golang.org/x/crypto/hkdf"
@@ -141,7 +142,7 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
packetNumber = uint32(n) packetNumber = uint32(n)
} }
if packetNumber != 0 { if packetNumber != 0 && packetNumber != 1 {
return nil, errNotQuicInitial return nil, errNotQuicInitial
} }
@@ -159,32 +160,92 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
return nil, err return nil, err
} }
buffer = buf.FromBytes(decrypted) buffer = buf.FromBytes(decrypted)
frameType, err := buffer.ReadByte()
if err != nil { cryptoLen := uint(0)
return nil, io.ErrUnexpectedEOF cryptoData := bytespool.Alloc(buffer.Len())
defer bytespool.Free(cryptoData)
for i := 0; !buffer.IsEmpty(); i++ {
frameType := byte(0x0) // Default to PADDING frame
for frameType == 0x0 && !buffer.IsEmpty() {
frameType, _ = buffer.ReadByte()
}
switch frameType {
case 0x00: // PADDING frame
case 0x01: // PING frame
case 0x02, 0x03: // ACK frame
if _, err = quicvarint.Read(buffer); err != nil { // Field: Largest Acknowledged
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Delay
return nil, io.ErrUnexpectedEOF
}
ackRangeCount, err := quicvarint.Read(buffer) // Field: ACK Range Count
if err != nil {
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: First ACK Range
return nil, io.ErrUnexpectedEOF
}
for i := 0; i < int(ackRangeCount); i++ { // Field: ACK Range
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Range -> Gap
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Range -> ACK Range Length
return nil, io.ErrUnexpectedEOF
}
}
if frameType == 0x03 {
if _, err = quicvarint.Read(buffer); err != nil { // Field: ECN Counts -> ECT0 Count
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: ECN Counts -> ECT1 Count
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { //nolint:misspell // Field: ECN Counts -> ECT-CE Count
return nil, io.ErrUnexpectedEOF
}
}
case 0x06: // CRYPTO frame, we will use this frame
offset, err := quicvarint.Read(buffer) // Field: Offset
if err != nil {
return nil, io.ErrUnexpectedEOF
}
length, err := quicvarint.Read(buffer) // Field: Length
if err != nil || length > uint64(buffer.Len()) {
return nil, io.ErrUnexpectedEOF
}
if cryptoLen < uint(offset+length) {
cryptoLen = uint(offset + length)
}
if _, err := buffer.Read(cryptoData[offset : offset+length]); err != nil { // Field: Crypto Data
return nil, io.ErrUnexpectedEOF
}
case 0x1c: // CONNECTION_CLOSE frame, only 0x1c is permitted in initial packet
if _, err = quicvarint.Read(buffer); err != nil { // Field: Error Code
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: Frame Type
return nil, io.ErrUnexpectedEOF
}
length, err := quicvarint.Read(buffer) // Field: Reason Phrase Length
if err != nil {
return nil, io.ErrUnexpectedEOF
}
if _, err := buffer.ReadBytes(int32(length)); err != nil { // Field: Reason Phrase
return nil, io.ErrUnexpectedEOF
}
default:
// Only above frame types are permitted in initial packet.
// See https://www.rfc-editor.org/rfc/rfc9000.html#section-17.2.2-8
return nil, errNotQuicInitial
}
} }
if frameType != 0x6 {
// not crypto frame
return &SniffHeader{domain: ""}, nil
}
if common.Error2(quicvarint.Read(buffer)) != nil {
return nil, io.ErrUnexpectedEOF
}
dataLen, err := quicvarint.Read(buffer)
if err != nil {
return nil, io.ErrUnexpectedEOF
}
if dataLen > uint64(buffer.Len()) {
return nil, io.ErrUnexpectedEOF
}
frameData, err := buffer.ReadBytes(int32(dataLen))
common.Must(err)
tlsHdr := &ptls.SniffHeader{} tlsHdr := &ptls.SniffHeader{}
err = ptls.ReadClientHello(frameData, tlsHdr) err = ptls.ReadClientHello(cryptoData[:cryptoLen], tlsHdr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &SniffHeader{domain: tlsHdr.Domain()}, nil return &SniffHeader{domain: tlsHdr.Domain()}, nil
} }

View File

@@ -2,10 +2,15 @@ package session
import ( import (
"context" "context"
_ "unsafe"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
) )
//go:linkname IndependentCancelCtx context.newCancelCtx
func IndependentCancelCtx(parent context.Context) context.Context
type sessionKey int type sessionKey int
const ( const (
@@ -17,6 +22,8 @@ const (
sockoptSessionKey sockoptSessionKey
trackedConnectionErrorKey trackedConnectionErrorKey
dispatcherKey dispatcherKey
timeoutOnlyKey
allowedNetworkKey
) )
// ContextWithID returns a new context with the given ID. // ContextWithID returns a new context with the given ID.
@@ -131,3 +138,25 @@ func DispatcherFromContext(ctx context.Context) routing.Dispatcher {
} }
return nil return nil
} }
func ContextWithTimeoutOnly(ctx context.Context, only bool) context.Context {
return context.WithValue(ctx, timeoutOnlyKey, only)
}
func TimeoutOnlyFromContext(ctx context.Context) bool {
if val, ok := ctx.Value(timeoutOnlyKey).(bool); ok {
return val
}
return false
}
func ContextWithAllowedNetwork(ctx context.Context, network net.Network) context.Context {
return context.WithValue(ctx, allowedNetworkKey, network)
}
func AllowedNetworkFromContext(ctx context.Context) net.Network {
if val, ok := ctx.Value(allowedNetworkKey).(net.Network); ok {
return val
}
return net.Network_Unknown
}

View File

@@ -42,6 +42,8 @@ type Inbound struct {
Gateway net.Destination Gateway net.Destination
// Tag of the inbound proxy that handles the connection. // Tag of the inbound proxy that handles the connection.
Tag string Tag string
// Name of the inbound proxy that handles the connection.
Name string
// User is the user that authencates for the inbound. May be nil if the protocol allows anounymous traffic. // User is the user that authencates for the inbound. May be nil if the protocol allows anounymous traffic.
User *protocol.MemoryUser User *protocol.MemoryUser
// Conn is actually internet.Connection. May be nil. // Conn is actually internet.Connection. May be nil.

View File

@@ -0,0 +1,46 @@
package singbridge
import (
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common/net"
)
func ToNetwork(network string) net.Network {
switch N.NetworkName(network) {
case N.NetworkTCP:
return net.Network_TCP
case N.NetworkUDP:
return net.Network_UDP
default:
return net.Network_Unknown
}
}
func ToDestination(socksaddr M.Socksaddr, network net.Network) net.Destination {
if socksaddr.IsFqdn() {
return net.Destination{
Network: network,
Address: net.DomainAddress(socksaddr.Fqdn),
Port: net.Port(socksaddr.Port),
}
} else {
return net.Destination{
Network: network,
Address: net.IPAddress(socksaddr.Addr.AsSlice()),
Port: net.Port(socksaddr.Port),
}
}
}
func ToSocksaddr(destination net.Destination) M.Socksaddr {
var addr M.Socksaddr
switch destination.Address.Family() {
case net.AddressFamilyDomain:
addr.Fqdn = destination.Address.Domain()
default:
addr.Addr = M.AddrFromIP(destination.Address.IP())
}
addr.Port = uint16(destination.Port)
return addr
}

View File

@@ -0,0 +1,59 @@
package singbridge
import (
"context"
"os"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/proxy"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/pipe"
)
var _ N.Dialer = (*XrayDialer)(nil)
type XrayDialer struct {
internet.Dialer
}
func NewDialer(dialer internet.Dialer) *XrayDialer {
return &XrayDialer{dialer}
}
func (d *XrayDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
return d.Dialer.Dial(ctx, ToDestination(destination, ToNetwork(network)))
}
func (d *XrayDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
return nil, os.ErrInvalid
}
type XrayOutboundDialer struct {
outbound proxy.Outbound
dialer internet.Dialer
}
func NewOutboundDialer(outbound proxy.Outbound, dialer internet.Dialer) *XrayOutboundDialer {
return &XrayOutboundDialer{outbound, dialer}
}
func (d *XrayOutboundDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
ctx = session.ContextWithOutbound(context.Background(), &session.Outbound{
Target: ToDestination(destination, ToNetwork(network)),
})
opts := []pipe.Option{pipe.WithSizeLimit(64 * 1024)}
uplinkReader, uplinkWriter := pipe.New(opts...)
downlinkReader, downlinkWriter := pipe.New(opts...)
conn := cnc.NewConnection(cnc.ConnectionInputMulti(downlinkWriter), cnc.ConnectionOutputMulti(uplinkReader))
go d.outbound.Process(ctx, &transport.Link{Reader: downlinkReader, Writer: uplinkWriter}, d.dialer)
return conn, nil
}
func (d *XrayOutboundDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
return nil, os.ErrInvalid
}

View File

@@ -0,0 +1,10 @@
package singbridge
import E "github.com/sagernet/sing/common/exceptions"
func ReturnError(err error) error {
if E.IsClosedOrCanceled(err) {
return nil
}
return err
}

View File

@@ -0,0 +1,51 @@
package singbridge
import (
"context"
"io"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport"
)
var (
_ N.TCPConnectionHandler = (*Dispatcher)(nil)
_ N.UDPConnectionHandler = (*Dispatcher)(nil)
)
type Dispatcher struct {
upstream routing.Dispatcher
newErrorFunc func(values ...any) *errors.Error
}
func NewDispatcher(dispatcher routing.Dispatcher, newErrorFunc func(values ...any) *errors.Error) *Dispatcher {
return &Dispatcher{
upstream: dispatcher,
newErrorFunc: newErrorFunc,
}
}
func (d *Dispatcher) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
xConn := NewConn(conn)
return d.upstream.DispatchLink(ctx, ToDestination(metadata.Destination, net.Network_TCP), &transport.Link{
Reader: xConn,
Writer: xConn,
})
}
func (d *Dispatcher) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
return d.upstream.DispatchLink(ctx, ToDestination(metadata.Destination, net.Network_UDP), &transport.Link{
Reader: buf.NewPacketReader(conn.(io.Reader)),
Writer: buf.NewWriter(conn.(io.Writer)),
})
}
func (d *Dispatcher) NewError(ctx context.Context, err error) {
d.newErrorFunc(err).WriteToLog(session.ExportIDToError(ctx))
}

View File

@@ -0,0 +1,71 @@
package singbridge
import (
"context"
"github.com/sagernet/sing/common/logger"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/session"
)
var _ logger.ContextLogger = (*XrayLogger)(nil)
type XrayLogger struct {
newError func(values ...any) *errors.Error
}
func NewLogger(newErrorFunc func(values ...any) *errors.Error) *XrayLogger {
return &XrayLogger{
newErrorFunc,
}
}
func (l *XrayLogger) Trace(args ...any) {
}
func (l *XrayLogger) Debug(args ...any) {
l.newError(args...).AtDebug().WriteToLog()
}
func (l *XrayLogger) Info(args ...any) {
l.newError(args...).AtInfo().WriteToLog()
}
func (l *XrayLogger) Warn(args ...any) {
l.newError(args...).AtWarning().WriteToLog()
}
func (l *XrayLogger) Error(args ...any) {
l.newError(args...).AtError().WriteToLog()
}
func (l *XrayLogger) Fatal(args ...any) {
}
func (l *XrayLogger) Panic(args ...any) {
}
func (l *XrayLogger) TraceContext(ctx context.Context, args ...any) {
}
func (l *XrayLogger) DebugContext(ctx context.Context, args ...any) {
l.newError(args...).AtDebug().WriteToLog(session.ExportIDToError(ctx))
}
func (l *XrayLogger) InfoContext(ctx context.Context, args ...any) {
l.newError(args...).AtInfo().WriteToLog(session.ExportIDToError(ctx))
}
func (l *XrayLogger) WarnContext(ctx context.Context, args ...any) {
l.newError(args...).AtWarning().WriteToLog(session.ExportIDToError(ctx))
}
func (l *XrayLogger) ErrorContext(ctx context.Context, args ...any) {
l.newError(args...).AtError().WriteToLog(session.ExportIDToError(ctx))
}
func (l *XrayLogger) FatalContext(ctx context.Context, args ...any) {
}
func (l *XrayLogger) PanicContext(ctx context.Context, args ...any) {
}

View File

@@ -0,0 +1,82 @@
package singbridge
import (
"context"
B "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport"
)
func CopyPacketConn(ctx context.Context, inboundConn net.Conn, link *transport.Link, destination net.Destination, serverConn net.PacketConn) error {
conn := &PacketConnWrapper{
Reader: link.Reader,
Writer: link.Writer,
Dest: destination,
Conn: inboundConn,
}
return ReturnError(bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(serverConn)))
}
type PacketConnWrapper struct {
buf.Reader
buf.Writer
net.Conn
Dest net.Destination
cached buf.MultiBuffer
}
func (w *PacketConnWrapper) ReadPacket(buffer *B.Buffer) (M.Socksaddr, error) {
if w.cached != nil {
mb, bb := buf.SplitFirst(w.cached)
if bb == nil {
w.cached = nil
} else {
buffer.Write(bb.Bytes())
w.cached = mb
var destination net.Destination
if bb.UDP != nil {
destination = *bb.UDP
} else {
destination = w.Dest
}
bb.Release()
return ToSocksaddr(destination), nil
}
}
mb, err := w.ReadMultiBuffer()
if err != nil {
return M.Socksaddr{}, err
}
nb, bb := buf.SplitFirst(mb)
if bb == nil {
return M.Socksaddr{}, nil
} else {
buffer.Write(bb.Bytes())
w.cached = nb
var destination net.Destination
if bb.UDP != nil {
destination = *bb.UDP
} else {
destination = w.Dest
}
bb.Release()
return ToSocksaddr(destination), nil
}
}
func (w *PacketConnWrapper) WritePacket(buffer *B.Buffer, destination M.Socksaddr) error {
vBuf := buf.New()
vBuf.Write(buffer.Bytes())
endpoint := ToDestination(destination, net.Network_UDP)
vBuf.UDP = &endpoint
return w.Writer.WriteMultiBuffer(buf.MultiBuffer{vBuf})
}
func (w *PacketConnWrapper) Close() error {
buf.ReleaseMulti(w.cached)
return nil
}

61
common/singbridge/pipe.go Normal file
View File

@@ -0,0 +1,61 @@
package singbridge
import (
"context"
"io"
"net"
"github.com/sagernet/sing/common/bufio"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/transport"
)
func CopyConn(ctx context.Context, inboundConn net.Conn, link *transport.Link, serverConn net.Conn) error {
conn := &PipeConnWrapper{
W: link.Writer,
Conn: inboundConn,
}
if ir, ok := link.Reader.(io.Reader); ok {
conn.R = ir
} else {
conn.R = &buf.BufferedReader{Reader: link.Reader}
}
return ReturnError(bufio.CopyConn(ctx, conn, serverConn))
}
type PipeConnWrapper struct {
R io.Reader
W buf.Writer
net.Conn
}
func (w *PipeConnWrapper) Close() error {
return nil
}
func (w *PipeConnWrapper) Read(b []byte) (n int, err error) {
return w.R.Read(b)
}
func (w *PipeConnWrapper) Write(p []byte) (n int, err error) {
n = len(p)
var mb buf.MultiBuffer
pLen := len(p)
for pLen > 0 {
buffer := buf.New()
if pLen > buf.Size {
_, err = buffer.Write(p[:buf.Size])
p = p[buf.Size:]
} else {
buffer.Write(p)
}
pLen -= int(buffer.Len())
mb = append(mb, buffer)
}
err = w.W.WriteMultiBuffer(mb)
if err != nil {
n = 0
buf.ReleaseMulti(mb)
}
return
}

View File

@@ -0,0 +1,66 @@
package singbridge
import (
"time"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/bufio"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
)
var (
_ buf.Reader = (*Conn)(nil)
_ buf.TimeoutReader = (*Conn)(nil)
_ buf.Writer = (*Conn)(nil)
)
type Conn struct {
net.Conn
writer N.VectorisedWriter
}
func NewConn(conn net.Conn) *Conn {
writer, _ := bufio.CreateVectorisedWriter(conn)
return &Conn{
Conn: conn,
writer: writer,
}
}
func (c *Conn) ReadMultiBuffer() (buf.MultiBuffer, error) {
buffer, err := buf.ReadBuffer(c.Conn)
if err != nil {
return nil, err
}
return buf.MultiBuffer{buffer}, nil
}
func (c *Conn) ReadMultiBufferTimeout(duration time.Duration) (buf.MultiBuffer, error) {
err := c.SetReadDeadline(time.Now().Add(duration))
if err != nil {
return nil, err
}
defer c.SetReadDeadline(time.Time{})
return c.ReadMultiBuffer()
}
func (c *Conn) WriteMultiBuffer(bufferList buf.MultiBuffer) error {
defer buf.ReleaseMulti(bufferList)
if c.writer != nil {
bytesList := make([][]byte, len(bufferList))
for i, buffer := range bufferList {
bytesList[i] = buffer.Bytes()
}
return common.Error(bufio.WriteVectorised(c.writer, bytesList))
}
// Since this conn is only used by tun, we don't force buffer writes to merge.
for _, buffer := range bufferList {
_, err := c.Conn.Write(buffer.Bytes())
if err != nil {
return err
}
}
return nil
}

View File

@@ -38,6 +38,12 @@ func Run(ctx context.Context, tasks ...func() error) error {
}(task) }(task)
} }
/*
if altctx := ctx.Value("altctx"); altctx != nil {
ctx = altctx.(context.Context)
}
*/
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
select { select {
case err := <-done: case err := <-done:
@@ -48,5 +54,11 @@ func Run(ctx context.Context, tasks ...func() error) error {
} }
} }
/*
if cancel := ctx.Value("cancel"); cancel != nil {
cancel.(context.CancelFunc)()
}
*/
return nil return nil
} }

View File

@@ -1,30 +1,79 @@
package xudp package xudp
import ( import (
"context"
"crypto/rand"
"encoding/base64"
"fmt"
"io" "io"
"os"
"strings"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session"
"lukechampine.com/blake3"
) )
var addrParser = protocol.NewAddressParser( var AddrParser = protocol.NewAddressParser(
protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4), protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4),
protocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain), protocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain),
protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv6), net.AddressFamilyIPv6), protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv6), net.AddressFamilyIPv6),
protocol.PortThenAddress(), protocol.PortThenAddress(),
) )
func NewPacketWriter(writer buf.Writer, dest net.Destination) *PacketWriter { var (
Show bool
BaseKey []byte
)
const (
EnvShow = "XRAY_XUDP_SHOW"
EnvBaseKey = "XRAY_XUDP_BASEKEY"
)
func init() {
if strings.ToLower(os.Getenv(EnvShow)) == "true" {
Show = true
}
if raw, found := os.LookupEnv(EnvBaseKey); found {
if BaseKey, _ = base64.RawURLEncoding.DecodeString(raw); len(BaseKey) == 32 {
return
}
panic(EnvBaseKey + ": invalid value: " + raw)
}
rand.Read(BaseKey)
}
func GetGlobalID(ctx context.Context) (globalID [8]byte) {
if cone := ctx.Value("cone"); cone == nil || !cone.(bool) { // cone is nil only in some unit tests
return
}
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.Network == net.Network_UDP &&
(inbound.Name == "dokodemo-door" || inbound.Name == "socks" || inbound.Name == "shadowsocks") {
h := blake3.New(8, BaseKey)
h.Write([]byte(inbound.Source.String()))
copy(globalID[:], h.Sum(nil))
if Show {
fmt.Printf("XUDP inbound.Source.String(): %v\tglobalID: %v\n", inbound.Source.String(), globalID)
}
}
return
}
func NewPacketWriter(writer buf.Writer, dest net.Destination, globalID [8]byte) *PacketWriter {
return &PacketWriter{ return &PacketWriter{
Writer: writer, Writer: writer,
Dest: dest, Dest: dest,
GlobalID: globalID,
} }
} }
type PacketWriter struct { type PacketWriter struct {
Writer buf.Writer Writer buf.Writer
Dest net.Destination Dest net.Destination
GlobalID [8]byte
} }
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
@@ -37,19 +86,22 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
} }
eb := buf.New() eb := buf.New()
eb.Write([]byte{0, 0, 0, 0}) eb.Write([]byte{0, 0, 0, 0}) // Meta data length; Mux Session ID
if w.Dest.Network == net.Network_UDP { if w.Dest.Network == net.Network_UDP {
eb.WriteByte(1) // New eb.WriteByte(1) // New
eb.WriteByte(1) // Opt eb.WriteByte(1) // Opt
eb.WriteByte(2) // UDP eb.WriteByte(2) // UDP
addrParser.WriteAddressPort(eb, w.Dest.Address, w.Dest.Port) AddrParser.WriteAddressPort(eb, w.Dest.Address, w.Dest.Port)
if b.UDP != nil { // make sure it's user's proxy request
eb.Write(w.GlobalID[:]) // no need to check whether it's empty
}
w.Dest.Network = net.Network_Unknown w.Dest.Network = net.Network_Unknown
} else { } else {
eb.WriteByte(2) // Keep eb.WriteByte(2) // Keep
eb.WriteByte(1) eb.WriteByte(1) // Opt
if b.UDP != nil { if b.UDP != nil {
eb.WriteByte(2) eb.WriteByte(2) // UDP
addrParser.WriteAddressPort(eb, b.UDP.Address, b.UDP.Port) AddrParser.WriteAddressPort(eb, b.UDP.Address, b.UDP.Port)
} }
} }
l := eb.Len() - 2 l := eb.Len() - 2
@@ -96,9 +148,10 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
discard := false discard := false
switch b.Byte(2) { switch b.Byte(2) {
case 2: case 2:
if l != 4 { if l > 4 && b.Byte(4) == 2 { // MUST check the flag first
b.Advance(5) b.Advance(5)
addr, port, err := addrParser.ReadAddressPort(nil, b) // b.Clear() will be called automatically if all data had been read.
addr, port, err := AddrParser.ReadAddressPort(nil, b)
if err != nil { if err != nil {
b.Release() b.Release()
return nil, err return nil, err
@@ -115,6 +168,7 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
b.Release() b.Release()
return nil, io.EOF return nil, io.EOF
} }
b.Clear() // in case there is padding (empty bytes) attached
if b.Byte(3) == 1 { if b.Byte(3) == 1 {
if _, err := io.ReadFull(r.Reader, r.cache); err != nil { if _, err := io.ReadFull(r.Reader, r.cache); err != nil {
b.Release() b.Release()
@@ -122,7 +176,6 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
} }
length := int32(r.cache[0])<<8 | int32(r.cache[1]) length := int32(r.cache[0])<<8 | int32(r.cache[1])
if length > 0 { if length > 0 {
b.Clear()
if _, err := b.ReadFullFrom(r.Reader, length); err != nil { if _, err := b.ReadFullFrom(r.Reader, length); err != nil {
b.Release() b.Release()
return nil, err return nil, err

36
common/xudp/xudp_test.go Normal file
View File

@@ -0,0 +1,36 @@
package xudp
import (
"testing"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
)
func TestXudpReadWrite(t *testing.T) {
addr, _ := net.ParseDestination("tcp:127.0.0.1:1345")
mb := make(buf.MultiBuffer, 0, 16)
m := buf.MultiBufferContainer{
MultiBuffer: mb,
}
var arr [8]byte
writer := NewPacketWriter(&m, addr, arr)
source := make(buf.MultiBuffer, 0, 16)
b := buf.New()
b.WriteByte('a')
b.UDP = &addr
source = append(source, b)
writer.WriteMultiBuffer(source)
reader := NewPacketReader(&m)
dest, err := reader.ReadMultiBuffer()
common.Must(err)
if dest[0].Byte(0) != 'a' {
t.Error("failed to parse xudp buffer")
}
if dest[0].UDP.Port != 1345 {
t.Error("failed to parse xudp buffer")
}
}

View File

@@ -12,13 +12,19 @@ package core
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
import ( import (
"fmt"
"runtime" "runtime"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
) )
var ( var (
version = "1.7.3" Version_x byte = 1
Version_y byte = 8
Version_z byte = 1
)
var (
build = "Custom" build = "Custom"
codename = "Xray, Penetrates Everything." codename = "Xray, Penetrates Everything."
intro = "A unified platform for anti-censorship." intro = "A unified platform for anti-censorship."
@@ -27,7 +33,7 @@ var (
// Version returns Xray's version as a string, in the form of "x.y.z" where x, y and z are numbers. // Version returns Xray's version as a string, in the form of "x.y.z" where x, y and z are numbers.
// ".z" part may be omitted in regular releases. // ".z" part may be omitted in regular releases.
func Version() string { func Version() string {
return version return fmt.Sprintf("%v.%v.%v", Version_x, Version_y, Version_z)
} }
// VersionStatement returns a list of strings representing the full version info. // VersionStatement returns a list of strings representing the full version info.

11
features/tun/tun.go Normal file
View File

@@ -0,0 +1,11 @@
package tun
import "github.com/xtls/xray-core/features"
type Interface interface {
features.Feature
}
func InterfaceType() interface{} {
return (*Interface)(nil)
}

65
go.mod
View File

@@ -5,56 +5,61 @@ go 1.20
require ( require (
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.2 github.com/golang/protobuf v1.5.3
github.com/google/go-cmp v0.5.9 github.com/google/go-cmp v0.5.9
github.com/gorilla/websocket v1.5.0 github.com/gorilla/websocket v1.5.0
github.com/miekg/dns v1.1.50 github.com/miekg/dns v1.1.53
github.com/pelletier/go-toml v1.9.5 github.com/pelletier/go-toml v1.9.5
github.com/pires/go-proxyproto v0.6.2 github.com/pires/go-proxyproto v0.7.0
github.com/quic-go/qtls-go1-20 v0.1.0 github.com/quic-go/quic-go v0.34.0
github.com/quic-go/quic-go v0.32.0 github.com/refraction-networking/utls v1.3.2
github.com/refraction-networking/utls v1.2.0 github.com/sagernet/sing v0.2.4
github.com/sagernet/sing v0.1.6 github.com/sagernet/sing-shadowsocks v0.2.1
github.com/sagernet/sing-shadowsocks v0.1.1-0.20230202035033-e3123545f2f7
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.2
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 github.com/xtls/reality v0.0.0-20230331223127-176a94313eda
go.starlark.net v0.0.0-20230128213706-3f75dec8e403 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254
golang.org/x/crypto v0.5.0 golang.org/x/crypto v0.8.0
golang.org/x/net v0.5.0 golang.org/x/net v0.9.0
golang.org/x/sync v0.1.0 golang.org/x/sync v0.1.0
golang.org/x/sys v0.4.0 golang.org/x/sys v0.7.0
google.golang.org/grpc v1.52.3 google.golang.org/grpc v1.54.0
google.golang.org/protobuf v1.28.1 google.golang.org/protobuf v1.30.0
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c
h12.io/socks v1.0.3 h12.io/socks v1.0.3
lukechampine.com/blake3 v1.1.7
) )
require ( require (
github.com/andybalholm/brotli v1.0.4 // indirect github.com/andybalholm/brotli v1.0.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect github.com/francoispqt/gojay v1.2.13 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gaukas/godicttls v0.0.3 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/google/btree v1.1.2 // indirect github.com/google/btree v1.1.2 // indirect
github.com/google/pprof v0.0.0-20230131232505-5a9e8f65f08f // indirect github.com/google/pprof v0.0.0-20230406165453-00490a63f317 // indirect
github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/compress v1.16.5 // indirect
github.com/klauspost/cpuid/v2 v2.2.3 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/onsi/ginkgo/v2 v2.8.0 // indirect github.com/onsi/ginkgo/v2 v2.9.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qtls-go1-18 v0.2.0 // indirect github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
github.com/quic-go/qtls-go1-19 v0.2.0 // indirect github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
github.com/sagernet/sing-tun v0.1.4 // indirect
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
go.uber.org/atomic v1.10.0 // indirect go.uber.org/atomic v1.10.0 // indirect
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 // indirect golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
golang.org/x/mod v0.7.0 // indirect golang.org/x/mod v0.10.0 // indirect
golang.org/x/text v0.6.0 // indirect golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.5.0 // indirect golang.org/x/tools v0.8.0 // indirect
google.golang.org/genproto v0.0.0-20230131230820-1c016267d619 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.1.7 // indirect
) )

140
go.sum
View File

@@ -8,8 +8,8 @@ dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
@@ -33,14 +33,18 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gaukas/godicttls v0.0.3 h1:YNDIf0d9adcxOijiLrEzpfZGAkNwLRzPaG6OjU7EITk=
github.com/gaukas/godicttls v0.0.3/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4= github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
@@ -58,8 +62,8 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
@@ -76,8 +80,8 @@ github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+u
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20230131232505-5a9e8f65f08f h1:gl1DCiSk+mrXXBGPm6CEeS2MkJuMVzAOrXg34oVj1QI= github.com/google/pprof v0.0.0-20230406165453-00490a63f317 h1:hFhpt7CTmR3DX+b4R19ydQFtofxT0Sv3QsKNMVQYTMQ=
github.com/google/pprof v0.0.0-20230131232505-5a9e8f65f08f/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/pprof v0.0.0-20230406165453-00490a63f317/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -91,11 +95,11 @@ github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -106,22 +110,22 @@ github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/onsi/ginkgo/v2 v2.8.0 h1:pAM+oBNPrpXRs+E/8spkeGx9QgekbRVyr74EUvRVOUI= github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
github.com/onsi/ginkgo/v2 v2.8.0/go.mod h1:6JsQiECmxCa3V5st74AL/AmsV482EDdVrGaVW6z3oYU= github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y= github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8= github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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=
@@ -130,23 +134,30 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U= github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U=
github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc= github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4nttk= github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI= github.com/quic-go/quic-go v0.34.0 h1:OvOJ9LFjTySgwOTYUZmNoq0FzVicP8YujpV0kB7m2lU=
github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= github.com/quic-go/quic-go v0.34.0/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
github.com/quic-go/quic-go v0.32.0 h1:lY02md31s1JgPiiyfqJijpu/UX/Iun304FI3yUqX7tA= github.com/refraction-networking/utls v1.3.2 h1:o+AkWB57mkcoW36ET7uJ002CpBWHu0KPxi6vzxvPnv8=
github.com/quic-go/quic-go v0.32.0/go.mod h1:/fCsKANhQIeD5l76c2JFU+07gVE3KaA0FP+0zMWwfwo= github.com/refraction-networking/utls v1.3.2/go.mod h1:fmoaOww2bxzzEpIKOebIsnBvjQpqP7L2vcm/9KUfm/E=
github.com/refraction-networking/utls v1.2.0 h1:U5f8wkij2NVinfLuJdFP3gCMwIHs+EzvhxmYdXgiapo=
github.com/refraction-networking/utls v1.2.0/go.mod h1:NPq+cVqzH7D1BeOkmOcb5O/8iVewAsiVt2x1/eO0hgQ=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sagernet/sing v0.1.6 h1:Qy63OUfKpcqKjfd5rPmUlj0RGjHZSK/PJn0duyCCsRg= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
github.com/sagernet/sing v0.1.6/go.mod h1:JLSXsPTGRJFo/3X7EcAOCUgJH2/gAoxSJgBsnCZRp/w= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
github.com/sagernet/sing-shadowsocks v0.1.1-0.20230202035033-e3123545f2f7 h1:Plup6oEiyLzY3HDqQ+QsUBzgBGdVmcsgf3t8h940z9U= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
github.com/sagernet/sing-shadowsocks v0.1.1-0.20230202035033-e3123545f2f7/go.mod h1:O5LtOs8Ivw686FqLpO0Zu+A0ROVE15VeqEK3yDRRAms= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.2.3 h1:V50MvZ4c3Iij2lYFWPlzL1PyipwSzjGeN9x+Ox89vpk=
github.com/sagernet/sing v0.2.3/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
github.com/sagernet/sing v0.2.4 h1:gC8BR5sglbJZX23RtMyFa8EETP9YEUADhfbEzU1yVbo=
github.com/sagernet/sing v0.2.4/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
github.com/sagernet/sing-shadowsocks v0.2.1 h1:FvdLQOqpvxHBJUcUe4fvgiYP2XLLwH5i1DtXQviVEPw=
github.com/sagernet/sing-shadowsocks v0.2.1/go.mod h1:T/OgurSjsAe+Ug3+6PprXjmgHFmJidjOvQcjXGTKb3I=
github.com/sagernet/sing-tun v0.1.4 h1:Fa6kgvuM2fPbPu3R97S8L8NgaD5lJq3wQorNuTb5oqo=
github.com/sagernet/sing-tun v0.1.4/go.mod h1:7BrtP7NMp9FK5oVsZWg92b7yFrD+sM2+udapFurReyw=
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo=
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI=
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U= github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
@@ -180,23 +191,24 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI= github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU= github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 h1:a3Y4WVjCxwoyO4E2xdNvq577tW8lkSBgyrA8E9+2NtM= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3/go.mod h1:YJTRELIWrGxR1s8xcEBgxcxBfwQfMGjdvNLTjN9XFgY= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/xtls/reality v0.0.0-20230331223127-176a94313eda h1:psRJD2RrZbnI0OWyHvXfgYCPqlRM5q5SPDcjDoDBWhE=
github.com/xtls/reality v0.0.0-20230331223127-176a94313eda/go.mod h1:rkuAY1S9F8eI8gDiPDYvACE8e2uwkyg8qoOTuwWov7Y=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.starlark.net v0.0.0-20230128213706-3f75dec8e403 h1:jPeC7Exc+m8OBJUlWbBLh0O5UZPM7yU5W4adnhhbG4U= go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 h1:Ss6D3hLXTM0KobyBYEAygXzFfGcjnmfEJOBgSbemCtg=
go.starlark.net v0.0.0-20230128213706-3f75dec8e403/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.starlark.net v0.0.0-20230302034142-4b1e35fe2254/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
@@ -205,18 +217,18 @@ golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 h1:BEABXpNXLEz0WxtA+6CQIz2xkg80e+1zrhWyMcq8VzE= golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -229,9 +241,8 @@ golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -251,24 +262,24 @@ golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
@@ -282,9 +293,8 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y=
golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -303,16 +313,16 @@ google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20230131230820-1c016267d619 h1:p0kMzw6AG0JEzd7Z+kXqOiLhC6gjUQTbtS2zR0Q3DbI= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
google.golang.org/genproto v0.0.0-20230131230820-1c016267d619/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.52.3 h1:pf7sOysg4LdgBqduXveGKrcEwbStiK2rtfghdzlUYDQ= google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -323,8 +333,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
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-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=

View File

@@ -45,6 +45,9 @@ func (v *Address) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &rawStr); err != nil { if err := json.Unmarshal(data, &rawStr); err != nil {
return newError("invalid address: ", string(data)).Base(err) return newError("invalid address: ", string(data)).Base(err)
} }
if strings.HasPrefix(rawStr, "env:") {
rawStr = os.Getenv(rawStr[4:])
}
v.Address = net.ParseAddress(rawStr) v.Address = net.ParseAddress(rawStr)
return nil return nil
@@ -115,8 +118,7 @@ func parseIntPort(data []byte) (net.Port, error) {
func parseStringPort(s string) (net.Port, net.Port, error) { func parseStringPort(s string) (net.Port, net.Port, error) {
if strings.HasPrefix(s, "env:") { if strings.HasPrefix(s, "env:") {
s = s[4:] s = os.Getenv(s[4:])
s = os.Getenv(s)
} }
pair := strings.SplitN(s, "-", 2) pair := strings.SplitN(s, "-", 2)

View File

@@ -12,6 +12,7 @@ type GRPCConfig struct {
HealthCheckTimeout int32 `json:"health_check_timeout"` HealthCheckTimeout int32 `json:"health_check_timeout"`
PermitWithoutStream bool `json:"permit_without_stream"` PermitWithoutStream bool `json:"permit_without_stream"`
InitialWindowsSize int32 `json:"initial_windows_size"` InitialWindowsSize int32 `json:"initial_windows_size"`
UserAgent string `json:"user_agent"`
} }
func (g *GRPCConfig) Build() (proto.Message, error) { func (g *GRPCConfig) Build() (proto.Message, error) {
@@ -33,5 +34,6 @@ func (g *GRPCConfig) Build() (proto.Message, error) {
HealthCheckTimeout: g.HealthCheckTimeout, HealthCheckTimeout: g.HealthCheckTimeout,
PermitWithoutStream: g.PermitWithoutStream, PermitWithoutStream: g.PermitWithoutStream,
InitialWindowsSize: g.InitialWindowsSize, InitialWindowsSize: g.InitialWindowsSize,
UserAgent: g.UserAgent,
}, nil }, nil
} }

View File

@@ -155,14 +155,15 @@ func buildShadowsocks2022(v *ShadowsocksServerConfig) (proto.Message, error) {
} }
type ShadowsocksServerTarget struct { type ShadowsocksServerTarget struct {
Address *Address `json:"address"` Address *Address `json:"address"`
Port uint16 `json:"port"` Port uint16 `json:"port"`
Cipher string `json:"method"` Cipher string `json:"method"`
Password string `json:"password"` Password string `json:"password"`
Email string `json:"email"` Email string `json:"email"`
Level byte `json:"level"` Level byte `json:"level"`
IVCheck bool `json:"ivCheck"` IVCheck bool `json:"ivCheck"`
UoT bool `json:"uot"` UoT bool `json:"uot"`
UoTVersion int `json:"uotVersion"`
} }
type ShadowsocksClientConfig struct { type ShadowsocksClientConfig struct {
@@ -193,6 +194,7 @@ func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
config.Method = server.Cipher config.Method = server.Cipher
config.Key = server.Password config.Key = server.Password
config.UdpOverTcp = server.UoT config.UdpOverTcp = server.UoT
config.UdpOverTcpVersion = uint32(server.UoTVersion)
return config, nil return config, nil
} }
} }

View File

@@ -4,6 +4,7 @@ import (
"sort" "sort"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/transport/internet/headers/dns"
"github.com/xtls/xray-core/transport/internet/headers/http" "github.com/xtls/xray-core/transport/internet/headers/http"
"github.com/xtls/xray-core/transport/internet/headers/noop" "github.com/xtls/xray-core/transport/internet/headers/noop"
"github.com/xtls/xray-core/transport/internet/headers/srtp" "github.com/xtls/xray-core/transport/internet/headers/srtp"
@@ -49,6 +50,19 @@ func (WireguardAuthenticator) Build() (proto.Message, error) {
return new(wireguard.WireguardConfig), nil return new(wireguard.WireguardConfig), nil
} }
type DNSAuthenticator struct {
Domain string `json:"domain"`
}
func (v *DNSAuthenticator) Build() (proto.Message, error) {
config := new(dns.Config)
config.Domain = "www.baidu.com"
if len(v.Domain) > 0 {
config.Domain = v.Domain
}
return config, nil
}
type DTLSAuthenticator struct{} type DTLSAuthenticator struct{}
func (DTLSAuthenticator) Build() (proto.Message, error) { func (DTLSAuthenticator) Build() (proto.Message, error) {

View File

@@ -2,13 +2,17 @@ package conf
import ( import (
"encoding/base64" "encoding/base64"
"encoding/hex"
"encoding/json" "encoding/json"
"math" "math"
"net/url" "net/url"
"runtime"
"strconv" "strconv"
"strings" "strings"
"syscall"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/platform/filesystem" "github.com/xtls/xray-core/common/platform/filesystem"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
@@ -18,10 +22,10 @@ import (
"github.com/xtls/xray-core/transport/internet/http" "github.com/xtls/xray-core/transport/internet/http"
"github.com/xtls/xray-core/transport/internet/kcp" "github.com/xtls/xray-core/transport/internet/kcp"
"github.com/xtls/xray-core/transport/internet/quic" "github.com/xtls/xray-core/transport/internet/quic"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/tcp" "github.com/xtls/xray-core/transport/internet/tcp"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/websocket" "github.com/xtls/xray-core/transport/internet/websocket"
"github.com/xtls/xray-core/transport/internet/xtls"
) )
var ( var (
@@ -32,6 +36,7 @@ var (
"wechat-video": func() interface{} { return new(WechatVideoAuthenticator) }, "wechat-video": func() interface{} { return new(WechatVideoAuthenticator) },
"dtls": func() interface{} { return new(DTLSAuthenticator) }, "dtls": func() interface{} { return new(DTLSAuthenticator) },
"wireguard": func() interface{} { return new(WireguardAuthenticator) }, "wireguard": func() interface{} { return new(WireguardAuthenticator) },
"dns": func() interface{} { return new(DNSAuthenticator) },
}, "type", "") }, "type", "")
tcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{ tcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
@@ -338,19 +343,20 @@ func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
} }
type TLSConfig struct { type TLSConfig struct {
Insecure bool `json:"allowInsecure"` Insecure bool `json:"allowInsecure"`
Certs []*TLSCertConfig `json:"certificates"` Certs []*TLSCertConfig `json:"certificates"`
ServerName string `json:"serverName"` ServerName string `json:"serverName"`
ALPN *StringList `json:"alpn"` ALPN *StringList `json:"alpn"`
EnableSessionResumption bool `json:"enableSessionResumption"` EnableSessionResumption bool `json:"enableSessionResumption"`
DisableSystemRoot bool `json:"disableSystemRoot"` DisableSystemRoot bool `json:"disableSystemRoot"`
MinVersion string `json:"minVersion"` MinVersion string `json:"minVersion"`
MaxVersion string `json:"maxVersion"` MaxVersion string `json:"maxVersion"`
CipherSuites string `json:"cipherSuites"` CipherSuites string `json:"cipherSuites"`
PreferServerCipherSuites bool `json:"preferServerCipherSuites"` PreferServerCipherSuites bool `json:"preferServerCipherSuites"`
Fingerprint string `json:"fingerprint"` Fingerprint string `json:"fingerprint"`
RejectUnknownSNI bool `json:"rejectUnknownSni"` RejectUnknownSNI bool `json:"rejectUnknownSni"`
PinnedPeerCertificateChainSha256 *[]string `json:"pinnedPeerCertificateChainSha256"` PinnedPeerCertificateChainSha256 *[]string `json:"pinnedPeerCertificateChainSha256"`
PinnedPeerCertificatePublicKeySha256 *[]string `json:"pinnedPeerCertificatePublicKeySha256"`
} }
// Build implements Buildable. // Build implements Buildable.
@@ -395,114 +401,187 @@ func (c *TLSConfig) Build() (proto.Message, error) {
} }
} }
return config, nil if c.PinnedPeerCertificatePublicKeySha256 != nil {
} config.PinnedPeerCertificatePublicKeySha256 = [][]byte{}
for _, v := range *c.PinnedPeerCertificatePublicKeySha256 {
type XTLSCertConfig struct {
CertFile string `json:"certificateFile"`
CertStr []string `json:"certificate"`
KeyFile string `json:"keyFile"`
KeyStr []string `json:"key"`
Usage string `json:"usage"`
OcspStapling uint64 `json:"ocspStapling"`
OneTimeLoading bool `json:"oneTimeLoading"`
}
// Build implements Buildable.
func (c *XTLSCertConfig) Build() (*xtls.Certificate, error) {
certificate := new(xtls.Certificate)
cert, err := readFileOrString(c.CertFile, c.CertStr)
if err != nil {
return nil, newError("failed to parse certificate").Base(err)
}
certificate.Certificate = cert
certificate.CertificatePath = c.CertFile
if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {
key, err := readFileOrString(c.KeyFile, c.KeyStr)
if err != nil {
return nil, newError("failed to parse key").Base(err)
}
certificate.Key = key
certificate.KeyPath = c.KeyFile
}
switch strings.ToLower(c.Usage) {
case "encipherment":
certificate.Usage = xtls.Certificate_ENCIPHERMENT
case "verify":
certificate.Usage = xtls.Certificate_AUTHORITY_VERIFY
case "issue":
certificate.Usage = xtls.Certificate_AUTHORITY_ISSUE
default:
certificate.Usage = xtls.Certificate_ENCIPHERMENT
}
if certificate.KeyPath == "" && certificate.CertificatePath == "" {
certificate.OneTimeLoading = true
} else {
certificate.OneTimeLoading = c.OneTimeLoading
}
certificate.OcspStapling = c.OcspStapling
return certificate, nil
}
type XTLSConfig struct {
Insecure bool `json:"allowInsecure"`
Certs []*XTLSCertConfig `json:"certificates"`
ServerName string `json:"serverName"`
ALPN *StringList `json:"alpn"`
EnableSessionResumption bool `json:"enableSessionResumption"`
DisableSystemRoot bool `json:"disableSystemRoot"`
MinVersion string `json:"minVersion"`
MaxVersion string `json:"maxVersion"`
CipherSuites string `json:"cipherSuites"`
PreferServerCipherSuites bool `json:"preferServerCipherSuites"`
RejectUnknownSNI bool `json:"rejectUnknownSni"`
PinnedPeerCertificateChainSha256 *[]string `json:"pinnedPeerCertificateChainSha256"`
}
// Build implements Buildable.
func (c *XTLSConfig) Build() (proto.Message, error) {
config := new(xtls.Config)
config.Certificate = make([]*xtls.Certificate, len(c.Certs))
for idx, certConf := range c.Certs {
cert, err := certConf.Build()
if err != nil {
return nil, err
}
config.Certificate[idx] = cert
}
serverName := c.ServerName
config.AllowInsecure = c.Insecure
if len(c.ServerName) > 0 {
config.ServerName = serverName
}
if c.ALPN != nil && len(*c.ALPN) > 0 {
config.NextProtocol = []string(*c.ALPN)
}
config.EnableSessionResumption = c.EnableSessionResumption
config.DisableSystemRoot = c.DisableSystemRoot
config.MinVersion = c.MinVersion
config.MaxVersion = c.MaxVersion
config.CipherSuites = c.CipherSuites
config.PreferServerCipherSuites = c.PreferServerCipherSuites
config.RejectUnknownSni = c.RejectUnknownSNI
if c.PinnedPeerCertificateChainSha256 != nil {
config.PinnedPeerCertificateChainSha256 = [][]byte{}
for _, v := range *c.PinnedPeerCertificateChainSha256 {
hashValue, err := base64.StdEncoding.DecodeString(v) hashValue, err := base64.StdEncoding.DecodeString(v)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.PinnedPeerCertificateChainSha256 = append(config.PinnedPeerCertificateChainSha256, hashValue) config.PinnedPeerCertificatePublicKeySha256 = append(config.PinnedPeerCertificatePublicKeySha256, hashValue)
} }
} }
return config, nil return config, nil
} }
type REALITYConfig struct {
Show bool `json:"show"`
Dest json.RawMessage `json:"dest"`
Type string `json:"type"`
Xver uint64 `json:"xver"`
ServerNames []string `json:"serverNames"`
PrivateKey string `json:"privateKey"`
MinClientVer string `json:"minClientVer"`
MaxClientVer string `json:"maxClientVer"`
MaxTimeDiff uint64 `json:"maxTimeDiff"`
ShortIds []string `json:"shortIds"`
Fingerprint string `json:"fingerprint"`
ServerName string `json:"serverName"`
PublicKey string `json:"publicKey"`
ShortId string `json:"shortId"`
SpiderX string `json:"spiderX"`
}
func (c *REALITYConfig) Build() (proto.Message, error) {
config := new(reality.Config)
config.Show = c.Show
var err error
if c.Dest != nil {
var i uint16
var s string
if err = json.Unmarshal(c.Dest, &i); err == nil {
s = strconv.Itoa(int(i))
} else {
_ = json.Unmarshal(c.Dest, &s)
}
if c.Type == "" && s != "" {
switch s[0] {
case '@', '/':
c.Type = "unix"
if s[0] == '@' && len(s) > 1 && s[1] == '@' && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy
copy(fullAddr, s[1:])
s = string(fullAddr)
}
default:
if _, err = strconv.Atoi(s); err == nil {
s = "127.0.0.1:" + s
}
if _, _, err = net.SplitHostPort(s); err == nil {
c.Type = "tcp"
}
}
}
if c.Type == "" {
return nil, newError(`please fill in a valid value for "dest"`)
}
if c.Xver > 2 {
return nil, newError(`invalid PROXY protocol version, "xver" only accepts 0, 1, 2`)
}
if len(c.ServerNames) == 0 {
return nil, newError(`empty "serverNames"`)
}
if c.PrivateKey == "" {
return nil, newError(`empty "privateKey"`)
}
if config.PrivateKey, err = base64.RawURLEncoding.DecodeString(c.PrivateKey); err != nil || len(config.PrivateKey) != 32 {
return nil, newError(`invalid "privateKey": `, c.PrivateKey)
}
if c.MinClientVer != "" {
config.MinClientVer = make([]byte, 3)
var u uint64
for i, s := range strings.Split(c.MinClientVer, ".") {
if i == 3 {
return nil, newError(`invalid "minClientVer": `, c.MinClientVer)
}
if u, err = strconv.ParseUint(s, 10, 8); err != nil {
return nil, newError(`"minClientVer[`, i, `]" should be lesser than 256`)
} else {
config.MinClientVer[i] = byte(u)
}
}
}
if c.MaxClientVer != "" {
config.MaxClientVer = make([]byte, 3)
var u uint64
for i, s := range strings.Split(c.MaxClientVer, ".") {
if i == 3 {
return nil, newError(`invalid "maxClientVer": `, c.MaxClientVer)
}
if u, err = strconv.ParseUint(s, 10, 8); err != nil {
return nil, newError(`"maxClientVer[`, i, `]" should be lesser than 256`)
} else {
config.MaxClientVer[i] = byte(u)
}
}
}
if len(c.ShortIds) == 0 {
return nil, newError(`empty "shortIds"`)
}
config.ShortIds = make([][]byte, len(c.ShortIds))
for i, s := range c.ShortIds {
config.ShortIds[i] = make([]byte, 8)
if _, err = hex.Decode(config.ShortIds[i], []byte(s)); err != nil {
return nil, newError(`invalid "shortIds[`, i, `]": `, s)
}
}
config.Dest = s
config.Type = c.Type
config.Xver = c.Xver
config.ServerNames = c.ServerNames
config.MaxTimeDiff = c.MaxTimeDiff
} else {
if c.Fingerprint == "" {
return nil, newError(`empty "fingerprint"`)
}
if config.Fingerprint = strings.ToLower(c.Fingerprint); tls.GetFingerprint(config.Fingerprint) == nil {
return nil, newError(`unknown "fingerprint": `, config.Fingerprint)
}
if config.Fingerprint == "hellogolang" {
return nil, newError(`invalid "fingerprint": `, config.Fingerprint)
}
if len(c.ServerNames) != 0 {
return nil, newError(`non-empty "serverNames", please use "serverName" instead`)
}
if c.PublicKey == "" {
return nil, newError(`empty "publicKey"`)
}
if config.PublicKey, err = base64.RawURLEncoding.DecodeString(c.PublicKey); err != nil || len(config.PublicKey) != 32 {
return nil, newError(`invalid "publicKey": `, c.PublicKey)
}
if len(c.ShortIds) != 0 {
return nil, newError(`non-empty "shortIds", please use "shortId" instead`)
}
config.ShortId = make([]byte, 8)
if _, err = hex.Decode(config.ShortId, []byte(c.ShortId)); err != nil {
return nil, newError(`invalid "shortId": `, c.ShortId)
}
if c.SpiderX == "" {
c.SpiderX = "/"
}
if c.SpiderX[0] != '/' {
return nil, newError(`invalid "spiderX": `, c.SpiderX)
}
config.SpiderY = make([]int64, 10)
u, _ := url.Parse(c.SpiderX)
q := u.Query()
parse := func(param string, index int) {
if q.Get(param) != "" {
s := strings.Split(q.Get(param), "-")
if len(s) == 1 {
config.SpiderY[index], _ = strconv.ParseInt(s[0], 10, 64)
config.SpiderY[index+1], _ = strconv.ParseInt(s[0], 10, 64)
} else {
config.SpiderY[index], _ = strconv.ParseInt(s[0], 10, 64)
config.SpiderY[index+1], _ = strconv.ParseInt(s[1], 10, 64)
}
}
q.Del(param)
}
parse("p", 0) // padding
parse("c", 2) // concurrency
parse("t", 4) // times
parse("i", 6) // interval
parse("r", 8) // return
u.RawQuery = q.Encode()
config.SpiderX = u.String()
config.ServerName = c.ServerName
}
return config, nil
}
type TransportProtocol string type TransportProtocol string
// Build implements Buildable. // Build implements Buildable.
@@ -537,6 +616,9 @@ type SocketConfig struct {
TCPKeepAliveInterval int32 `json:"tcpKeepAliveInterval"` TCPKeepAliveInterval int32 `json:"tcpKeepAliveInterval"`
TCPKeepAliveIdle int32 `json:"tcpKeepAliveIdle"` TCPKeepAliveIdle int32 `json:"tcpKeepAliveIdle"`
TCPCongestion string `json:"tcpCongestion"` TCPCongestion string `json:"tcpCongestion"`
TCPWindowClamp int32 `json:"tcpWindowClamp"`
TCPUserTimeout int32 `json:"tcpUserTimeout"`
V6only bool `json:"v6only"`
Interface string `json:"interface"` Interface string `json:"interface"`
} }
@@ -587,24 +669,27 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
TcpKeepAliveInterval: c.TCPKeepAliveInterval, TcpKeepAliveInterval: c.TCPKeepAliveInterval,
TcpKeepAliveIdle: c.TCPKeepAliveIdle, TcpKeepAliveIdle: c.TCPKeepAliveIdle,
TcpCongestion: c.TCPCongestion, TcpCongestion: c.TCPCongestion,
TcpWindowClamp: c.TCPWindowClamp,
TcpUserTimeout: c.TCPUserTimeout,
V6Only: c.V6only,
Interface: c.Interface, Interface: c.Interface,
}, nil }, nil
} }
type StreamConfig struct { type StreamConfig struct {
Network *TransportProtocol `json:"network"` Network *TransportProtocol `json:"network"`
Security string `json:"security"` Security string `json:"security"`
TLSSettings *TLSConfig `json:"tlsSettings"` TLSSettings *TLSConfig `json:"tlsSettings"`
XTLSSettings *XTLSConfig `json:"xtlsSettings"` REALITYSettings *REALITYConfig `json:"realitySettings"`
TCPSettings *TCPConfig `json:"tcpSettings"` TCPSettings *TCPConfig `json:"tcpSettings"`
KCPSettings *KCPConfig `json:"kcpSettings"` KCPSettings *KCPConfig `json:"kcpSettings"`
WSSettings *WebSocketConfig `json:"wsSettings"` WSSettings *WebSocketConfig `json:"wsSettings"`
HTTPSettings *HTTPConfig `json:"httpSettings"` HTTPSettings *HTTPConfig `json:"httpSettings"`
DSSettings *DomainSocketConfig `json:"dsSettings"` DSSettings *DomainSocketConfig `json:"dsSettings"`
QUICSettings *QUICConfig `json:"quicSettings"` QUICSettings *QUICConfig `json:"quicSettings"`
SocketSettings *SocketConfig `json:"sockopt"` SocketSettings *SocketConfig `json:"sockopt"`
GRPCConfig *GRPCConfig `json:"grpcSettings"` GRPCConfig *GRPCConfig `json:"grpcSettings"`
GUNConfig *GRPCConfig `json:"gunSettings"` GUNConfig *GRPCConfig `json:"gunSettings"`
} }
// Build implements Buildable. // Build implements Buildable.
@@ -619,12 +704,11 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
} }
config.ProtocolName = protocol config.ProtocolName = protocol
} }
if strings.EqualFold(c.Security, "tls") { switch strings.ToLower(c.Security) {
case "", "none":
case "tls":
tlsSettings := c.TLSSettings tlsSettings := c.TLSSettings
if tlsSettings == nil { if tlsSettings == nil {
if c.XTLSSettings != nil {
return nil, newError(`TLS: Please use "tlsSettings" instead of "xtlsSettings".`)
}
tlsSettings = &TLSConfig{} tlsSettings = &TLSConfig{}
} }
ts, err := tlsSettings.Build() ts, err := tlsSettings.Build()
@@ -634,25 +718,24 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
tm := serial.ToTypedMessage(ts) tm := serial.ToTypedMessage(ts)
config.SecuritySettings = append(config.SecuritySettings, tm) config.SecuritySettings = append(config.SecuritySettings, tm)
config.SecurityType = tm.Type config.SecurityType = tm.Type
} case "reality":
if strings.EqualFold(c.Security, "xtls") { if config.ProtocolName != "tcp" && config.ProtocolName != "http" && config.ProtocolName != "grpc" && config.ProtocolName != "domainsocket" {
if config.ProtocolName != "tcp" && config.ProtocolName != "mkcp" && config.ProtocolName != "domainsocket" { return nil, newError("REALITY only supports TCP, H2, gRPC and DomainSocket for now.")
return nil, newError("XTLS only supports TCP, mKCP and DomainSocket for now.")
} }
xtlsSettings := c.XTLSSettings if c.REALITYSettings == nil {
if xtlsSettings == nil { return nil, newError(`REALITY: Empty "realitySettings".`)
if c.TLSSettings != nil {
return nil, newError(`XTLS: Please use "xtlsSettings" instead of "tlsSettings".`)
}
xtlsSettings = &XTLSConfig{}
} }
ts, err := xtlsSettings.Build() ts, err := c.REALITYSettings.Build()
if err != nil { if err != nil {
return nil, newError("Failed to build XTLS config.").Base(err) return nil, newError("Failed to build REALITY config.").Base(err)
} }
tm := serial.ToTypedMessage(ts) tm := serial.ToTypedMessage(ts)
config.SecuritySettings = append(config.SecuritySettings, tm) config.SecuritySettings = append(config.SecuritySettings, tm)
config.SecurityType = tm.Type config.SecurityType = tm.Type
case "xtls":
return nil, newError(`Please use VLESS flow "xtls-rprx-vision" with TLS or REALITY.`)
default:
return nil, newError(`Unknown security "` + c.Security + `".`)
} }
if c.TCPSettings != nil { if c.TCPSettings != nil {
ts, err := c.TCPSettings.Build() ts, err := c.TCPSettings.Build()

View File

@@ -53,11 +53,7 @@ func (c *TrojanClientConfig) Build() (proto.Message, error) {
} }
switch account.Flow { switch account.Flow {
case "", "xtls-rprx-origin", "xtls-rprx-origin-udp443", "xtls-rprx-direct", "xtls-rprx-direct-udp443": case "":
case "xtls-rprx-splice", "xtls-rprx-splice-udp443":
if runtime.GOOS != "linux" && runtime.GOOS != "android" {
return nil, newError(`Trojan servers: "` + account.Flow + `" only support linux in this version`)
}
default: default:
return nil, newError(`Trojan servers: "flow" doesn't support "` + account.Flow + `" in this version`) return nil, newError(`Trojan servers: "flow" doesn't support "` + account.Flow + `" in this version`)
} }
@@ -119,9 +115,7 @@ func (c *TrojanServerConfig) Build() (proto.Message, error) {
} }
switch account.Flow { switch account.Flow {
case "", "xtls-rprx-origin", "xtls-rprx-direct": case "":
case "xtls-rprx-splice":
return nil, newError(`Trojan clients: inbound doesn't support "xtls-rprx-splice" in this version, please use "xtls-rprx-direct" instead`)
default: default:
return nil, newError(`Trojan clients: "flow" doesn't support "` + account.Flow + `" in this version`) return nil, newError(`Trojan clients: "flow" doesn't support "` + account.Flow + `" in this version`)
} }

113
infra/conf/tun.go Normal file
View File

@@ -0,0 +1,113 @@
package conf
import (
"encoding/json"
"net/netip"
"github.com/sagernet/sing/common"
"github.com/xtls/xray-core/app/tun"
)
type TunConfig struct {
InterfaceName string `json:"interface_name,omitempty"`
MTU uint32 `json:"mtu,omitempty"`
Inet4Address Listable[ListenPrefix] `json:"inet4_address,omitempty"`
Inet6Address Listable[ListenPrefix] `json:"inet6_address,omitempty"`
AutoRoute bool `json:"auto_route,omitempty"`
StrictRoute bool `json:"strict_route,omitempty"`
Inet4RouteAddress Listable[ListenPrefix] `json:"inet4_route_address,omitempty"`
Inet6RouteAddress Listable[ListenPrefix] `json:"inet6_route_address,omitempty"`
IncludeUID Listable[uint32] `json:"include_uid,omitempty"`
IncludeUIDRange Listable[string] `json:"include_uid_range,omitempty"`
ExcludeUID Listable[uint32] `json:"exclude_uid,omitempty"`
ExcludeUIDRange Listable[string] `json:"exclude_uid_range,omitempty"`
IncludeAndroidUser Listable[int] `json:"include_android_user,omitempty"`
IncludePackage Listable[string] `json:"include_package,omitempty"`
ExcludePackage Listable[string] `json:"exclude_package,omitempty"`
EndpointIndependentNat bool `json:"endpoint_independent_nat,omitempty"`
UDPTimeout int64 `json:"udp_timeout,omitempty"`
Stack string `json:"stack,omitempty"`
AutoDetectInterface bool `json:"auto_detect_interface,omitempty"`
OverrideAndroidVPN bool `json:"override_android_vpn,omitempty"`
}
func (f *TunConfig) Build() (*tun.Config, error) {
var config tun.Config
config.InterfaceName = f.InterfaceName
config.Mtu = f.MTU
config.Inet4Address = common.Map(common.Map(f.Inet4Address, ListenPrefix.Build), netip.Prefix.String)
config.Inet6Address = common.Map(common.Map(f.Inet6Address, ListenPrefix.Build), netip.Prefix.String)
config.AutoRoute = f.AutoRoute
config.StrictRoute = f.StrictRoute
config.Inet4RouteAddress = common.Map(common.Map(f.Inet4RouteAddress, ListenPrefix.Build), netip.Prefix.String)
config.Inet6RouteAddress = common.Map(common.Map(f.Inet6RouteAddress, ListenPrefix.Build), netip.Prefix.String)
config.IncludeUid = f.IncludeUID
config.IncludeUidRange = f.IncludeUIDRange
config.ExcludeUid = f.ExcludeUID
config.ExcludeUidRange = f.ExcludeUIDRange
config.IncludeAndroidUser = common.Map(f.IncludeAndroidUser, func(it int) int32 {
return int32(it)
})
config.IncludePackage = f.IncludePackage
config.ExcludePackage = f.ExcludePackage
config.EndpointIndependentNat = f.EndpointIndependentNat
config.UdpTimeout = f.UDPTimeout
config.Stack = f.Stack
// for xray
config.AutoDetectInterface = f.AutoDetectInterface
config.OverrideAndroidVpn = f.OverrideAndroidVPN
return &config, nil
}
type Listable[T comparable] []T
func (l Listable[T]) MarshalJSON() ([]byte, error) {
arrayList := []T(l)
if len(arrayList) == 1 {
return json.Marshal(arrayList[0])
}
return json.Marshal(arrayList)
}
func (l *Listable[T]) UnmarshalJSON(content []byte) error {
err := json.Unmarshal(content, (*[]T)(l))
if err == nil {
return nil
}
var singleItem T
err = json.Unmarshal(content, &singleItem)
if err != nil {
return err
}
*l = []T{singleItem}
return nil
}
type ListenPrefix netip.Prefix
func (p ListenPrefix) MarshalJSON() ([]byte, error) {
prefix := netip.Prefix(p)
if !prefix.IsValid() {
return json.Marshal(nil)
}
return json.Marshal(prefix.String())
}
func (p *ListenPrefix) UnmarshalJSON(bytes []byte) error {
var value string
err := json.Unmarshal(bytes, &value)
if err != nil {
return err
}
prefix, err := netip.ParsePrefix(value)
if err != nil {
return err
}
*p = ListenPrefix(prefix)
return nil
}
func (p ListenPrefix) Build() netip.Prefix {
return netip.Prefix(p)
}

View File

@@ -4,7 +4,6 @@ import (
"encoding/json" "encoding/json"
"runtime" "runtime"
"strconv" "strconv"
"strings"
"syscall" "syscall"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
@@ -53,18 +52,8 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
} }
account.Id = u.String() account.Id = u.String()
accountFlow := account.Flow switch account.Flow {
flows := strings.Split(account.Flow, ",") case "", vless.XRV:
for _, f := range flows {
t := strings.TrimSpace(f)
if t != "none" {
accountFlow = t
}
}
switch accountFlow {
case "", vless.XRO, vless.XRD, vless.XRV:
case vless.XRS:
return nil, newError(`VLESS clients: inbound doesn't support "xtls-rprx-splice" in this version, please use "xtls-rprx-direct" instead`)
default: default:
return nil, newError(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`) return nil, newError(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`)
} }
@@ -191,11 +180,7 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
account.Id = u.String() account.Id = u.String()
switch account.Flow { switch account.Flow {
case "", vless.XRO, vless.XRO + "-udp443", vless.XRD, vless.XRD + "-udp443", vless.XRV, vless.XRV + "-udp443": case "", vless.XRV, vless.XRV + "-udp443":
case vless.XRS, vless.XRS + "-udp443":
if runtime.GOOS != "linux" && runtime.GOOS != "android" {
return nil, newError(`VLESS users: "` + account.Flow + `" only support linux in this version`)
}
default: default:
return nil, newError(`VLESS users: "flow" doesn't support "` + account.Flow + `" in this version`) return nil, newError(`VLESS users: "flow" doesn't support "` + account.Flow + `" in this version`)
} }

View File

@@ -26,7 +26,7 @@ func TestVLessOutbound(t *testing.T) {
"users": [ "users": [
{ {
"id": "27848739-7e62-4138-9fd3-098a63964b6b", "id": "27848739-7e62-4138-9fd3-098a63964b6b",
"flow": "xtls-rprx-direct-udp443", "flow": "xtls-rprx-vision-udp443",
"encryption": "none", "encryption": "none",
"level": 0 "level": 0
} }
@@ -47,7 +47,7 @@ func TestVLessOutbound(t *testing.T) {
{ {
Account: serial.ToTypedMessage(&vless.Account{ Account: serial.ToTypedMessage(&vless.Account{
Id: "27848739-7e62-4138-9fd3-098a63964b6b", Id: "27848739-7e62-4138-9fd3-098a63964b6b",
Flow: "xtls-rprx-direct-udp443", Flow: "xtls-rprx-vision-udp443",
Encryption: "none", Encryption: "none",
}), }),
Level: 0, Level: 0,
@@ -71,7 +71,7 @@ func TestVLessInbound(t *testing.T) {
"clients": [ "clients": [
{ {
"id": "27848739-7e62-4138-9fd3-098a63964b6b", "id": "27848739-7e62-4138-9fd3-098a63964b6b",
"flow": "xtls-rprx-direct", "flow": "xtls-rprx-vision",
"level": 0, "level": 0,
"email": "love@example.com" "email": "love@example.com"
} }
@@ -98,7 +98,7 @@ func TestVLessInbound(t *testing.T) {
{ {
Account: serial.ToTypedMessage(&vless.Account{ Account: serial.ToTypedMessage(&vless.Account{
Id: "27848739-7e62-4138-9fd3-098a63964b6b", Id: "27848739-7e62-4138-9fd3-098a63964b6b",
Flow: "xtls-rprx-direct", Flow: "xtls-rprx-vision",
}), }),
Level: 0, Level: 0,
Email: "love@example.com", Email: "love@example.com",

View File

@@ -52,6 +52,7 @@ type WireGuardConfig struct {
Peers []*WireGuardPeerConfig `json:"peers"` Peers []*WireGuardPeerConfig `json:"peers"`
MTU int `json:"mtu"` MTU int `json:"mtu"`
NumWorkers int `json:"workers"` NumWorkers int `json:"workers"`
Reserved []byte `json:"reserved"`
} }
func (c *WireGuardConfig) Build() (proto.Message, error) { func (c *WireGuardConfig) Build() (proto.Message, error) {
@@ -90,6 +91,11 @@ func (c *WireGuardConfig) Build() (proto.Message, error) {
// we don't need to process fallback manually // we don't need to process fallback manually
config.NumWorkers = int32(c.NumWorkers) config.NumWorkers = int32(c.NumWorkers)
if len(c.Reserved) != 0 && len(c.Reserved) != 3 {
return nil, newError(`"reserved" should be empty or 3 bytes`)
}
config.Reserved = c.Reserved
return config, nil return config, nil
} }

View File

@@ -13,7 +13,6 @@ import (
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
core "github.com/xtls/xray-core/core" core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/xtls"
) )
var ( var (
@@ -108,25 +107,27 @@ func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {
} }
type MuxConfig struct { type MuxConfig struct {
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
Concurrency int16 `json:"concurrency"` Concurrency int16 `json:"concurrency"`
XudpConcurrency int16 `json:"xudpConcurrency"`
XudpProxyUDP443 string `json:"xudpProxyUDP443"`
} }
// Build creates MultiplexingConfig, Concurrency < 0 completely disables mux. // Build creates MultiplexingConfig, Concurrency < 0 completely disables mux.
func (m *MuxConfig) Build() *proxyman.MultiplexingConfig { func (m *MuxConfig) Build() (*proxyman.MultiplexingConfig, error) {
if m.Concurrency < 0 { switch m.XudpProxyUDP443 {
return nil case "":
m.XudpProxyUDP443 = "reject"
case "reject", "allow", "skip":
default:
return nil, newError(`unknown "xudpProxyUDP443": `, m.XudpProxyUDP443)
} }
var con uint32 = 8
if m.Concurrency > 0 {
con = uint32(m.Concurrency)
}
return &proxyman.MultiplexingConfig{ return &proxyman.MultiplexingConfig{
Enabled: m.Enabled, Enabled: m.Enabled,
Concurrency: con, Concurrency: int32(m.Concurrency),
} XudpConcurrency: int32(m.XudpConcurrency),
XudpProxyUDP443: m.XudpProxyUDP443,
}, nil
} }
type InboundDetourAllocationConfig struct { type InboundDetourAllocationConfig struct {
@@ -236,9 +237,6 @@ func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if ss.SecurityType == serial.GetMessageType(&xtls.Config{}) && !strings.EqualFold(c.Protocol, "vless") && !strings.EqualFold(c.Protocol, "trojan") {
return nil, newError("XTLS doesn't supports " + c.Protocol + " for now.")
}
receiverSettings.StreamSettings = ss receiverSettings.StreamSettings = ss
} }
if c.SniffingConfig != nil { if c.SniffingConfig != nil {
@@ -319,9 +317,6 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if ss.SecurityType == serial.GetMessageType(&xtls.Config{}) && !strings.EqualFold(c.Protocol, "vless") && !strings.EqualFold(c.Protocol, "trojan") {
return nil, newError("XTLS doesn't supports " + c.Protocol + " for now.")
}
senderSettings.StreamSettings = ss senderSettings.StreamSettings = ss
} }
@@ -346,13 +341,9 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
} }
if c.MuxSettings != nil { if c.MuxSettings != nil {
ms := c.MuxSettings.Build() ms, err := c.MuxSettings.Build()
if ms != nil && ms.Enabled { if err != nil {
if ss := senderSettings.StreamSettings; ss != nil { return nil, newError("failed to build Mux config.").Base(err)
if ss.SecurityType == serial.GetMessageType(&xtls.Config{}) {
return nil, newError("XTLS doesn't support Mux for now.")
}
}
} }
senderSettings.MultiplexSettings = ms senderSettings.MultiplexSettings = ms
} }
@@ -419,6 +410,7 @@ type Config struct {
Reverse *ReverseConfig `json:"reverse"` Reverse *ReverseConfig `json:"reverse"`
FakeDNS *FakeDNSConfig `json:"fakeDns"` FakeDNS *FakeDNSConfig `json:"fakeDns"`
Observatory *ObservatoryConfig `json:"observatory"` Observatory *ObservatoryConfig `json:"observatory"`
Tun *TunConfig `json:"tun"`
} }
func (c *Config) findInboundTag(tag string) int { func (c *Config) findInboundTag(tag string) int {
@@ -483,6 +475,10 @@ func (c *Config) Override(o *Config, fn string) {
c.Observatory = o.Observatory c.Observatory = o.Observatory
} }
if o.Tun != nil {
c.Tun = o.Tun
}
// deprecated attrs... keep them for now // deprecated attrs... keep them for now
if o.InboundConfig != nil { if o.InboundConfig != nil {
c.InboundConfig = o.InboundConfig c.InboundConfig = o.InboundConfig
@@ -646,6 +642,14 @@ func (c *Config) Build() (*core.Config, error) {
config.App = append(config.App, serial.ToTypedMessage(r)) config.App = append(config.App, serial.ToTypedMessage(r))
} }
if c.Tun != nil {
r, err := c.Tun.Build()
if err != nil {
return nil, err
}
config.App = append(config.App, serial.ToTypedMessage(r))
}
var inbounds []InboundDetourConfig var inbounds []InboundDetourConfig
if c.InboundConfig != nil { if c.InboundConfig != nil {

View File

@@ -340,24 +340,35 @@ func TestMuxConfig_Build(t *testing.T) {
want *proxyman.MultiplexingConfig want *proxyman.MultiplexingConfig
}{ }{
{"default", `{"enabled": true, "concurrency": 16}`, &proxyman.MultiplexingConfig{ {"default", `{"enabled": true, "concurrency": 16}`, &proxyman.MultiplexingConfig{
Enabled: true, Enabled: true,
Concurrency: 16, Concurrency: 16,
XudpConcurrency: 0,
XudpProxyUDP443: "reject",
}}, }},
{"empty def", `{}`, &proxyman.MultiplexingConfig{ {"empty def", `{}`, &proxyman.MultiplexingConfig{
Enabled: false, Enabled: false,
Concurrency: 8, Concurrency: 0,
XudpConcurrency: 0,
XudpProxyUDP443: "reject",
}}, }},
{"not enable", `{"enabled": false, "concurrency": 4}`, &proxyman.MultiplexingConfig{ {"not enable", `{"enabled": false, "concurrency": 4}`, &proxyman.MultiplexingConfig{
Enabled: false, Enabled: false,
Concurrency: 4, Concurrency: 4,
XudpConcurrency: 0,
XudpProxyUDP443: "reject",
}},
{"forbidden", `{"enabled": false, "concurrency": -1}`, &proxyman.MultiplexingConfig{
Enabled: false,
Concurrency: -1,
XudpConcurrency: 0,
XudpProxyUDP443: "reject",
}}, }},
{"forbidden", `{"enabled": false, "concurrency": -1}`, nil},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
m := &MuxConfig{} m := &MuxConfig{}
common.Must(json.Unmarshal([]byte(tt.fields), m)) common.Must(json.Unmarshal([]byte(tt.fields), m))
if got := m.Build(); !reflect.DeepEqual(got, tt.want) { if got, _ := m.Build(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("MuxConfig.Build() = %v, want %v", got, tt.want) t.Errorf("MuxConfig.Build() = %v, want %v", got, tt.want)
} }
}) })

View File

@@ -15,5 +15,6 @@ func init() {
// cmdConvert, // cmdConvert,
tls.CmdTLS, tls.CmdTLS,
cmdUUID, cmdUUID,
cmdX25519,
) )
} }

View File

@@ -0,0 +1,71 @@
package all
import (
"crypto/rand"
"encoding/base64"
"fmt"
"github.com/xtls/xray-core/main/commands/base"
"golang.org/x/crypto/curve25519"
)
var cmdX25519 = &base.Command{
UsageLine: `{{.Exec}} x25519 [-i "private key (base64.RawURLEncoding)"]`,
Short: `Generate key pair for x25519 key exchange`,
Long: `
Generate key pair for x25519 key exchange.
Random: {{.Exec}} x25519
From private key: {{.Exec}} x25519 -i "private key (base64.RawURLEncoding)"
`,
}
func init() {
cmdX25519.Run = executeX25519 // break init loop
}
var input_base64 = cmdX25519.Flag.String("i", "", "")
func executeX25519(cmd *base.Command, args []string) {
var output string
var err error
var privateKey []byte
var publicKey []byte
if len(*input_base64) > 0 {
privateKey, err = base64.RawURLEncoding.DecodeString(*input_base64)
if err != nil {
output = err.Error()
goto out
}
if len(privateKey) != curve25519.ScalarSize {
output = "Invalid length of private key."
goto out
}
}
if privateKey == nil {
privateKey = make([]byte, curve25519.ScalarSize)
if _, err = rand.Read(privateKey); err != nil {
output = err.Error()
goto out
}
}
// Modify random bytes using algorithm described at:
// https://cr.yp.to/ecdh.html.
privateKey[0] &= 248
privateKey[31] &= 127
privateKey[31] |= 64
if publicKey, err = curve25519.X25519(privateKey, curve25519.Basepoint); err != nil {
output = err.Error()
goto out
}
output = fmt.Sprintf("Private key: %v\nPublic key: %v",
base64.RawURLEncoding.EncodeToString(privateKey),
base64.RawURLEncoding.EncodeToString(publicKey))
out:
fmt.Println(output)
}

View File

@@ -16,6 +16,7 @@ import (
// Developer preview services // Developer preview services
_ "github.com/xtls/xray-core/app/observatory/command" _ "github.com/xtls/xray-core/app/observatory/command"
_ "github.com/xtls/xray-core/app/tun"
// Other optional features. // Other optional features.
_ "github.com/xtls/xray-core/app/dns" _ "github.com/xtls/xray-core/app/dns"
@@ -56,11 +57,11 @@ import (
_ "github.com/xtls/xray-core/transport/internet/http" _ "github.com/xtls/xray-core/transport/internet/http"
_ "github.com/xtls/xray-core/transport/internet/kcp" _ "github.com/xtls/xray-core/transport/internet/kcp"
_ "github.com/xtls/xray-core/transport/internet/quic" _ "github.com/xtls/xray-core/transport/internet/quic"
_ "github.com/xtls/xray-core/transport/internet/reality"
_ "github.com/xtls/xray-core/transport/internet/tcp" _ "github.com/xtls/xray-core/transport/internet/tcp"
_ "github.com/xtls/xray-core/transport/internet/tls" _ "github.com/xtls/xray-core/transport/internet/tls"
_ "github.com/xtls/xray-core/transport/internet/udp" _ "github.com/xtls/xray-core/transport/internet/udp"
_ "github.com/xtls/xray-core/transport/internet/websocket" _ "github.com/xtls/xray-core/transport/internet/websocket"
_ "github.com/xtls/xray-core/transport/internet/xtls"
// Transport headers // Transport headers
_ "github.com/xtls/xray-core/transport/internet/headers/http" _ "github.com/xtls/xray-core/transport/internet/headers/http"

View File

@@ -148,6 +148,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.
} }
} }
if session.TimeoutOnlyFromContext(ctx) {
ctx, _ = context.WithCancel(context.Background())
}
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, h.timeout) timer := signal.CancelAfterInactivity(ctx, cancel, h.timeout)

View File

@@ -103,6 +103,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
inbound := session.InboundFromContext(ctx) inbound := session.InboundFromContext(ctx)
if inbound != nil { if inbound != nil {
inbound.Name = "dokodemo-door"
inbound.User = &protocol.MemoryUser{ inbound.User = &protocol.MemoryUser{
Level: d.config.UserLevel, Level: d.config.UserLevel,
} }

View File

@@ -117,7 +117,6 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
UDPOverride.Port = destination.Port UDPOverride.Port = destination.Port
} }
} }
newError("opening connection to ", destination).WriteToLog(session.ExportIDToError(ctx))
input := link.Reader input := link.Reader
output := link.Writer output := link.Writer
@@ -148,10 +147,22 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return newError("failed to open connection to ", destination).Base(err) return newError("failed to open connection to ", destination).Base(err)
} }
defer conn.Close() defer conn.Close()
newError("connection opened to ", destination, ", local endpoint ", conn.LocalAddr(), ", remote endpoint ", conn.RemoteAddr()).WriteToLog(session.ExportIDToError(ctx))
var newCtx context.Context
var newCancel context.CancelFunc
if session.TimeoutOnlyFromContext(ctx) {
newCtx, newCancel = context.WithCancel(context.Background())
}
plcy := h.policy() plcy := h.policy()
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle) timer := signal.CancelAfterInactivity(ctx, func() {
cancel()
if newCancel != nil {
newCancel()
}
}, plcy.Timeouts.ConnectionIdle)
requestDone := func() error { requestDone := func() error {
defer timer.SetTimeout(plcy.Timeouts.DownlinkOnly) defer timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
@@ -186,6 +197,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return nil return nil
} }
if newCtx != nil {
ctx = newCtx
}
if err := task.Run(ctx, requestDone, task.OnSuccess(responseDone, task.Close(output))); err != nil { if err := task.Run(ctx, requestDone, task.OnSuccess(responseDone, task.Close(output))); err != nil {
return newError("connection ends").Base(err) return newError("connection ends").Base(err)
} }

View File

@@ -128,8 +128,19 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
p = c.policyManager.ForLevel(user.Level) p = c.policyManager.ForLevel(user.Level)
} }
var newCtx context.Context
var newCancel context.CancelFunc
if session.TimeoutOnlyFromContext(ctx) {
newCtx, newCancel = context.WithCancel(context.Background())
}
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, p.Timeouts.ConnectionIdle) timer := signal.CancelAfterInactivity(ctx, func() {
cancel()
if newCancel != nil {
newCancel()
}
}, p.Timeouts.ConnectionIdle)
requestFunc := func() error { requestFunc := func() error {
defer timer.SetTimeout(p.Timeouts.DownlinkOnly) defer timer.SetTimeout(p.Timeouts.DownlinkOnly)
@@ -140,6 +151,10 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
return buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer)) return buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer))
} }
if newCtx != nil {
ctx = newCtx
}
responseDonePost := task.OnSuccess(responseFunc, task.Close(link.Writer)) responseDonePost := task.OnSuccess(responseFunc, task.Close(link.Writer))
if err := task.Run(ctx, requestFunc, responseDonePost); err != nil { if err := task.Run(ctx, requestFunc, responseDonePost); err != nil {
return newError("connection ends").Base(err) return newError("connection ends").Base(err)

View File

@@ -85,6 +85,7 @@ type readerOnly struct {
func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error { func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error {
inbound := session.InboundFromContext(ctx) inbound := session.InboundFromContext(ctx)
if inbound != nil { if inbound != nil {
inbound.Name = "http"
inbound.User = &protocol.MemoryUser{ inbound.User = &protocol.MemoryUser{
Level: s.config.UserLevel, Level: s.config.UserLevel,
} }

View File

@@ -96,9 +96,24 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
} }
request.User = user request.User = user
var newCtx context.Context
var newCancel context.CancelFunc
if session.TimeoutOnlyFromContext(ctx) {
newCtx, newCancel = context.WithCancel(context.Background())
}
sessionPolicy := c.policyManager.ForLevel(user.Level) sessionPolicy := c.policyManager.ForLevel(user.Level)
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle) timer := signal.CancelAfterInactivity(ctx, func() {
cancel()
if newCancel != nil {
newCancel()
}
}, sessionPolicy.Timeouts.ConnectionIdle)
if newCtx != nil {
ctx = newCtx
}
if request.Command == protocol.RequestCommandTCP { if request.Command == protocol.RequestCommandTCP {
requestDone := func() error { requestDone := func() error {

View File

@@ -113,6 +113,7 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dis
if inbound == nil { if inbound == nil {
panic("no inbound metadata") panic("no inbound metadata")
} }
inbound.Name = "shadowsocks"
var dest *net.Destination var dest *net.Destination

View File

@@ -389,11 +389,12 @@ type ClientConfig struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
Method string `protobuf:"bytes,3,opt,name=method,proto3" json:"method,omitempty"` Method string `protobuf:"bytes,3,opt,name=method,proto3" json:"method,omitempty"`
Key string `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"` Key string `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"`
UdpOverTcp bool `protobuf:"varint,5,opt,name=udp_over_tcp,json=udpOverTcp,proto3" json:"udp_over_tcp,omitempty"` UdpOverTcp bool `protobuf:"varint,5,opt,name=udp_over_tcp,json=udpOverTcp,proto3" json:"udp_over_tcp,omitempty"`
UdpOverTcpVersion uint32 `protobuf:"varint,6,opt,name=udp_over_tcp_version,json=udpOverTcpVersion,proto3" json:"udp_over_tcp_version,omitempty"`
} }
func (x *ClientConfig) Reset() { func (x *ClientConfig) Reset() {
@@ -463,6 +464,13 @@ func (x *ClientConfig) GetUdpOverTcp() bool {
return false return false
} }
func (x *ClientConfig) GetUdpOverTcpVersion() uint32 {
if x != nil {
return x.UdpOverTcpVersion
}
return 0
}
var File_proxy_shadowsocks_2022_config_proto protoreflect.FileDescriptor var File_proxy_shadowsocks_2022_config_proto protoreflect.FileDescriptor
var file_proxy_shadowsocks_2022_config_proto_rawDesc = []byte{ var file_proxy_shadowsocks_2022_config_proto_rawDesc = []byte{
@@ -520,7 +528,7 @@ var file_proxy_shadowsocks_2022_config_proto_rawDesc = []byte{
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c,
0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0xa5, 0x01, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0xd6, 0x01,
0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35,
0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
@@ -531,15 +539,18 @@ var file_proxy_shadowsocks_2022_config_proto_rawDesc = []byte{
0x64, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x6b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0c, 0x75, 0x64, 0x70, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0c, 0x75, 0x64, 0x70, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x5f,
0x74, 0x63, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x64, 0x70, 0x4f, 0x76, 0x74, 0x63, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x64, 0x70, 0x4f, 0x76,
0x65, 0x72, 0x54, 0x63, 0x70, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x65, 0x72, 0x54, 0x63, 0x70, 0x12, 0x2f, 0x0a, 0x14, 0x75, 0x64, 0x70, 0x5f, 0x6f, 0x76, 0x65,
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x72, 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20,
0x63, 0x6b, 0x73, 0x5f, 0x32, 0x30, 0x32, 0x32, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x75, 0x64, 0x70, 0x4f, 0x76, 0x65, 0x72, 0x54, 0x63, 0x70, 0x56,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x68, 0x61, 0x64, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73,
0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x32, 0x30, 0x32, 0x32, 0xaa, 0x02, 0x1a, 0x58, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x32, 0x30, 0x32, 0x32, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74,
0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
0x73, 0x6f, 0x63, 0x6b, 0x73, 0x32, 0x30, 0x32, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x68, 0x61,
0x33, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x32, 0x30, 0x32, 0x32, 0xaa, 0x02, 0x1a,
0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x68, 0x61, 0x64, 0x6f,
0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x32, 0x30, 0x32, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
} }
var ( var (

View File

@@ -51,4 +51,5 @@ message ClientConfig {
string method = 3; string method = 3;
string key = 4; string key = 4;
bool udp_over_tcp = 5; bool udp_over_tcp = 5;
uint32 udp_over_tcp_version = 6;
} }

View File

@@ -3,7 +3,7 @@ package shadowsocks_2022
import ( import (
"context" "context"
"github.com/sagernet/sing-shadowsocks" shadowsocks "github.com/sagernet/sing-shadowsocks"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022" "github.com/sagernet/sing-shadowsocks/shadowaead_2022"
C "github.com/sagernet/sing/common" C "github.com/sagernet/sing/common"
B "github.com/sagernet/sing/common/buf" B "github.com/sagernet/sing/common/buf"
@@ -17,6 +17,7 @@ import (
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
) )
@@ -50,7 +51,7 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Inbound, error) {
if !C.Contains(shadowaead_2022.List, config.Method) { if !C.Contains(shadowaead_2022.List, config.Method) {
return nil, newError("unsupported method ", config.Method) return nil, newError("unsupported method ", config.Method)
} }
service, err := shadowaead_2022.NewServiceWithPassword(config.Method, config.Key, 500, inbound) service, err := shadowaead_2022.NewServiceWithPassword(config.Method, config.Key, 500, inbound, nil)
if err != nil { if err != nil {
return nil, newError("create service").Base(err) return nil, newError("create service").Base(err)
} }
@@ -64,6 +65,7 @@ func (i *Inbound) Network() []net.Network {
func (i *Inbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error { func (i *Inbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
inbound := session.InboundFromContext(ctx) inbound := session.InboundFromContext(ctx)
inbound.Name = "shadowsocks-2022"
var metadata M.Metadata var metadata M.Metadata
if inbound.Source.IsValid() { if inbound.Source.IsValid() {
@@ -73,7 +75,7 @@ func (i *Inbound) Process(ctx context.Context, network net.Network, connection s
ctx = session.ContextWithDispatcher(ctx, dispatcher) ctx = session.ContextWithDispatcher(ctx, dispatcher)
if network == net.Network_TCP { if network == net.Network_TCP {
return returnError(i.service.NewConnection(ctx, connection, metadata)) return singbridge.ReturnError(i.service.NewConnection(ctx, connection, metadata))
} else { } else {
reader := buf.NewReader(connection) reader := buf.NewReader(connection)
pc := &natPacketConn{connection} pc := &natPacketConn{connection}
@@ -81,7 +83,7 @@ func (i *Inbound) Process(ctx context.Context, network net.Network, connection s
mb, err := reader.ReadMultiBuffer() mb, err := reader.ReadMultiBuffer()
if err != nil { if err != nil {
buf.ReleaseMulti(mb) buf.ReleaseMulti(mb)
return returnError(err) return singbridge.ReturnError(err)
} }
for _, buffer := range mb { for _, buffer := range mb {
packet := B.As(buffer.Bytes()).ToOwned() packet := B.As(buffer.Bytes()).ToOwned()
@@ -111,16 +113,11 @@ func (i *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata M.M
}) })
newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx)) newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
dispatcher := session.DispatcherFromContext(ctx) dispatcher := session.DispatcherFromContext(ctx)
link, err := dispatcher.Dispatch(ctx, toDestination(metadata.Destination, net.Network_TCP)) link, err := dispatcher.Dispatch(ctx, singbridge.ToDestination(metadata.Destination, net.Network_TCP))
if err != nil { if err != nil {
return err return err
} }
outConn := &pipeConnWrapper{ return singbridge.CopyConn(ctx, nil, link, conn)
&buf.BufferedReader{Reader: link.Reader},
link.Writer,
conn,
}
return bufio.CopyConn(ctx, conn, outConn)
} }
func (i *Inbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error { func (i *Inbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
@@ -137,12 +134,12 @@ func (i *Inbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, me
}) })
newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx)) newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
dispatcher := session.DispatcherFromContext(ctx) dispatcher := session.DispatcherFromContext(ctx)
destination := toDestination(metadata.Destination, net.Network_UDP) destination := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
link, err := dispatcher.Dispatch(ctx, destination) link, err := dispatcher.Dispatch(ctx, destination)
if err != nil { if err != nil {
return err return err
} }
outConn := &packetConnWrapper{ outConn := &singbridge.PacketConnWrapper{
Reader: link.Reader, Reader: link.Reader,
Writer: link.Writer, Writer: link.Writer,
Dest: destination, Dest: destination,

View File

@@ -21,6 +21,7 @@ import (
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/common/uuid" "github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
@@ -58,7 +59,7 @@ func NewMultiServer(ctx context.Context, config *MultiUserServerConfig) (*MultiU
if err != nil { if err != nil {
return nil, newError("parse config").Base(err) return nil, newError("parse config").Base(err)
} }
service, err := shadowaead_2022.NewMultiService[int](config.Method, psk, 500, inbound) service, err := shadowaead_2022.NewMultiService[int](config.Method, psk, 500, inbound, nil)
if err != nil { if err != nil {
return nil, newError("create service").Base(err) return nil, newError("create service").Base(err)
} }
@@ -153,6 +154,7 @@ func (i *MultiUserInbound) Network() []net.Network {
func (i *MultiUserInbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error { func (i *MultiUserInbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
inbound := session.InboundFromContext(ctx) inbound := session.InboundFromContext(ctx)
inbound.Name = "shadowsocks-2022-multi"
var metadata M.Metadata var metadata M.Metadata
if inbound.Source.IsValid() { if inbound.Source.IsValid() {
@@ -162,7 +164,7 @@ func (i *MultiUserInbound) Process(ctx context.Context, network net.Network, con
ctx = session.ContextWithDispatcher(ctx, dispatcher) ctx = session.ContextWithDispatcher(ctx, dispatcher)
if network == net.Network_TCP { if network == net.Network_TCP {
return returnError(i.service.NewConnection(ctx, connection, metadata)) return singbridge.ReturnError(i.service.NewConnection(ctx, connection, metadata))
} else { } else {
reader := buf.NewReader(connection) reader := buf.NewReader(connection)
pc := &natPacketConn{connection} pc := &natPacketConn{connection}
@@ -170,7 +172,7 @@ func (i *MultiUserInbound) Process(ctx context.Context, network net.Network, con
mb, err := reader.ReadMultiBuffer() mb, err := reader.ReadMultiBuffer()
if err != nil { if err != nil {
buf.ReleaseMulti(mb) buf.ReleaseMulti(mb)
return returnError(err) return singbridge.ReturnError(err)
} }
for _, buffer := range mb { for _, buffer := range mb {
packet := B.As(buffer.Bytes()).ToOwned() packet := B.As(buffer.Bytes()).ToOwned()
@@ -202,16 +204,11 @@ func (i *MultiUserInbound) NewConnection(ctx context.Context, conn net.Conn, met
}) })
newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx)) newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
dispatcher := session.DispatcherFromContext(ctx) dispatcher := session.DispatcherFromContext(ctx)
link, err := dispatcher.Dispatch(ctx, toDestination(metadata.Destination, net.Network_TCP)) link, err := dispatcher.Dispatch(ctx, singbridge.ToDestination(metadata.Destination, net.Network_TCP))
if err != nil { if err != nil {
return err return err
} }
outConn := &pipeConnWrapper{ return singbridge.CopyConn(ctx, conn, link, conn)
&buf.BufferedReader{Reader: link.Reader},
link.Writer,
conn,
}
return bufio.CopyConn(ctx, conn, outConn)
} }
func (i *MultiUserInbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error { func (i *MultiUserInbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
@@ -230,12 +227,12 @@ func (i *MultiUserInbound) NewPacketConnection(ctx context.Context, conn N.Packe
}) })
newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx)) newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
dispatcher := session.DispatcherFromContext(ctx) dispatcher := session.DispatcherFromContext(ctx)
destination := toDestination(metadata.Destination, net.Network_UDP) destination := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
link, err := dispatcher.Dispatch(ctx, destination) link, err := dispatcher.Dispatch(ctx, destination)
if err != nil { if err != nil {
return err return err
} }
outConn := &packetConnWrapper{ outConn := &singbridge.PacketConnWrapper{
Reader: link.Reader, Reader: link.Reader,
Writer: link.Writer, Writer: link.Writer,
Dest: destination, Dest: destination,

View File

@@ -19,6 +19,7 @@ import (
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/common/uuid" "github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
@@ -66,7 +67,7 @@ func NewRelayServer(ctx context.Context, config *RelayServerConfig) (*RelayInbou
C.MapIndexed(config.Destinations, func(index int, it *RelayDestination) int { return index }), C.MapIndexed(config.Destinations, func(index int, it *RelayDestination) int { return index }),
C.Map(config.Destinations, func(it *RelayDestination) string { return it.Key }), C.Map(config.Destinations, func(it *RelayDestination) string { return it.Key }),
C.Map(config.Destinations, func(it *RelayDestination) M.Socksaddr { C.Map(config.Destinations, func(it *RelayDestination) M.Socksaddr {
return toSocksaddr(net.Destination{ return singbridge.ToSocksaddr(net.Destination{
Address: it.Address.AsAddress(), Address: it.Address.AsAddress(),
Port: net.Port(it.Port), Port: net.Port(it.Port),
}) })
@@ -85,6 +86,7 @@ func (i *RelayInbound) Network() []net.Network {
func (i *RelayInbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error { func (i *RelayInbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
inbound := session.InboundFromContext(ctx) inbound := session.InboundFromContext(ctx)
inbound.Name = "shadowsocks-2022-relay"
var metadata M.Metadata var metadata M.Metadata
if inbound.Source.IsValid() { if inbound.Source.IsValid() {
@@ -94,7 +96,7 @@ func (i *RelayInbound) Process(ctx context.Context, network net.Network, connect
ctx = session.ContextWithDispatcher(ctx, dispatcher) ctx = session.ContextWithDispatcher(ctx, dispatcher)
if network == net.Network_TCP { if network == net.Network_TCP {
return returnError(i.service.NewConnection(ctx, connection, metadata)) return singbridge.ReturnError(i.service.NewConnection(ctx, connection, metadata))
} else { } else {
reader := buf.NewReader(connection) reader := buf.NewReader(connection)
pc := &natPacketConn{connection} pc := &natPacketConn{connection}
@@ -102,7 +104,7 @@ func (i *RelayInbound) Process(ctx context.Context, network net.Network, connect
mb, err := reader.ReadMultiBuffer() mb, err := reader.ReadMultiBuffer()
if err != nil { if err != nil {
buf.ReleaseMulti(mb) buf.ReleaseMulti(mb)
return returnError(err) return singbridge.ReturnError(err)
} }
for _, buffer := range mb { for _, buffer := range mb {
packet := B.As(buffer.Bytes()).ToOwned() packet := B.As(buffer.Bytes()).ToOwned()
@@ -134,16 +136,11 @@ func (i *RelayInbound) NewConnection(ctx context.Context, conn net.Conn, metadat
}) })
newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx)) newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
dispatcher := session.DispatcherFromContext(ctx) dispatcher := session.DispatcherFromContext(ctx)
link, err := dispatcher.Dispatch(ctx, toDestination(metadata.Destination, net.Network_TCP)) link, err := dispatcher.Dispatch(ctx, singbridge.ToDestination(metadata.Destination, net.Network_TCP))
if err != nil { if err != nil {
return err return err
} }
outConn := &pipeConnWrapper{ return singbridge.CopyConn(ctx, nil, link, conn)
&buf.BufferedReader{Reader: link.Reader},
link.Writer,
conn,
}
return bufio.CopyConn(ctx, conn, outConn)
} }
func (i *RelayInbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error { func (i *RelayInbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
@@ -162,12 +159,12 @@ func (i *RelayInbound) NewPacketConnection(ctx context.Context, conn N.PacketCon
}) })
newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx)) newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
dispatcher := session.DispatcherFromContext(ctx) dispatcher := session.DispatcherFromContext(ctx)
destination := toDestination(metadata.Destination, net.Network_UDP) destination := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
link, err := dispatcher.Dispatch(ctx, destination) link, err := dispatcher.Dispatch(ctx, destination)
if err != nil { if err != nil {
return err return err
} }
outConn := &packetConnWrapper{ outConn := &singbridge.PacketConnWrapper{
Reader: link.Reader, Reader: link.Reader,
Writer: link.Writer, Writer: link.Writer,
Dest: destination, Dest: destination,

View File

@@ -2,22 +2,21 @@ package shadowsocks_2022
import ( import (
"context" "context"
"io"
"runtime" "runtime"
"time" "time"
"github.com/sagernet/sing-shadowsocks" shadowsocks "github.com/sagernet/sing-shadowsocks"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022" "github.com/sagernet/sing-shadowsocks/shadowaead_2022"
C "github.com/sagernet/sing/common" C "github.com/sagernet/sing/common"
B "github.com/sagernet/sing/common/buf" B "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/uot" "github.com/sagernet/sing/common/uot"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
) )
@@ -29,10 +28,10 @@ func init() {
} }
type Outbound struct { type Outbound struct {
ctx context.Context ctx context.Context
server net.Destination server net.Destination
method shadowsocks.Method method shadowsocks.Method
uot bool uotClient *uot.Client
} }
func NewClient(ctx context.Context, config *ClientConfig) (*Outbound, error) { func NewClient(ctx context.Context, config *ClientConfig) (*Outbound, error) {
@@ -43,13 +42,12 @@ func NewClient(ctx context.Context, config *ClientConfig) (*Outbound, error) {
Port: net.Port(config.Port), Port: net.Port(config.Port),
Network: net.Network_TCP, Network: net.Network_TCP,
}, },
uot: config.UdpOverTcp,
} }
if C.Contains(shadowaead_2022.List, config.Method) { if C.Contains(shadowaead_2022.List, config.Method) {
if config.Key == "" { if config.Key == "" {
return nil, newError("missing psk") return nil, newError("missing psk")
} }
method, err := shadowaead_2022.NewWithPassword(config.Method, config.Key) method, err := shadowaead_2022.NewWithPassword(config.Method, config.Key, nil)
if err != nil { if err != nil {
return nil, newError("create method").Base(err) return nil, newError("create method").Base(err)
} }
@@ -57,6 +55,9 @@ func NewClient(ctx context.Context, config *ClientConfig) (*Outbound, error) {
} else { } else {
return nil, newError("unknown method ", config.Method) return nil, newError("unknown method ", config.Method)
} }
if config.UdpOverTcp {
o.uotClient = &uot.Client{Version: uint8(config.UdpOverTcpVersion)}
}
return o, nil return o, nil
} }
@@ -77,7 +78,7 @@ func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer int
newError("tunneling request to ", destination, " via ", o.server.NetAddr()).WriteToLog(session.ExportIDToError(ctx)) newError("tunneling request to ", destination, " via ", o.server.NetAddr()).WriteToLog(session.ExportIDToError(ctx))
serverDestination := o.server serverDestination := o.server
if o.uot { if o.uotClient != nil {
serverDestination.Network = net.Network_TCP serverDestination.Network = net.Network_TCP
} else { } else {
serverDestination.Network = network serverDestination.Network = network
@@ -87,8 +88,12 @@ func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer int
return newError("failed to connect to server").Base(err) return newError("failed to connect to server").Base(err)
} }
if session.TimeoutOnlyFromContext(ctx) {
ctx, _ = context.WithCancel(context.Background())
}
if network == net.Network_TCP { if network == net.Network_TCP {
serverConn := o.method.DialEarlyConn(connection, toSocksaddr(destination)) serverConn := o.method.DialEarlyConn(connection, singbridge.ToSocksaddr(destination))
var handshake bool var handshake bool
if timeoutReader, isTimeoutReader := link.Reader.(buf.TimeoutReader); isTimeoutReader { if timeoutReader, isTimeoutReader := link.Reader.(buf.TimeoutReader); isTimeoutReader {
mb, err := timeoutReader.ReadMultiBufferTimeout(time.Millisecond * 100) mb, err := timeoutReader.ReadMultiBufferTimeout(time.Millisecond * 100)
@@ -123,17 +128,7 @@ func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer int
return newError("client handshake").Base(err) return newError("client handshake").Base(err)
} }
} }
conn := &pipeConnWrapper{ return singbridge.CopyConn(ctx, inboundConn, link, serverConn)
W: link.Writer,
Conn: inboundConn,
}
if ir, ok := link.Reader.(io.Reader); ok {
conn.R = ir
} else {
conn.R = &buf.BufferedReader{Reader: link.Reader}
}
return returnError(bufio.CopyConn(ctx, conn, serverConn))
} else { } else {
var packetConn N.PacketConn var packetConn N.PacketConn
if pc, isPacketConn := inboundConn.(N.PacketConn); isPacketConn { if pc, isPacketConn := inboundConn.(N.PacketConn); isPacketConn {
@@ -141,7 +136,7 @@ func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer int
} else if nc, isNetPacket := inboundConn.(net.PacketConn); isNetPacket { } else if nc, isNetPacket := inboundConn.(net.PacketConn); isNetPacket {
packetConn = bufio.NewPacketConn(nc) packetConn = bufio.NewPacketConn(nc)
} else { } else {
packetConn = &packetConnWrapper{ packetConn = &singbridge.PacketConnWrapper{
Reader: link.Reader, Reader: link.Reader,
Writer: link.Writer, Writer: link.Writer,
Conn: inboundConn, Conn: inboundConn,
@@ -149,12 +144,15 @@ func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer int
} }
} }
if o.uot { if o.uotClient != nil {
serverConn := o.method.DialEarlyConn(connection, M.Socksaddr{Fqdn: uot.UOTMagicAddress}) uConn, err := o.uotClient.DialEarlyConn(o.method.DialEarlyConn(connection, uot.RequestDestination(o.uotClient.Version)), false, singbridge.ToSocksaddr(destination))
return returnError(bufio.CopyPacketConn(ctx, packetConn, uot.NewClientConn(serverConn))) if err != nil {
return err
}
return singbridge.ReturnError(bufio.CopyPacketConn(ctx, packetConn, uConn))
} else { } else {
serverConn := o.method.DialPacketConn(connection) serverConn := o.method.DialPacketConn(connection)
return returnError(bufio.CopyPacketConn(ctx, packetConn, serverConn)) return singbridge.ReturnError(bufio.CopyPacketConn(ctx, packetConn, serverConn))
} }
} }
} }

View File

@@ -1,145 +1,3 @@
package shadowsocks_2022 package shadowsocks_2022
import (
"io"
B "github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
)
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
func toDestination(socksaddr M.Socksaddr, network net.Network) net.Destination {
if socksaddr.IsFqdn() {
return net.Destination{
Network: network,
Address: net.DomainAddress(socksaddr.Fqdn),
Port: net.Port(socksaddr.Port),
}
} else {
return net.Destination{
Network: network,
Address: net.IPAddress(socksaddr.Addr.AsSlice()),
Port: net.Port(socksaddr.Port),
}
}
}
func toSocksaddr(destination net.Destination) M.Socksaddr {
var addr M.Socksaddr
switch destination.Address.Family() {
case net.AddressFamilyDomain:
addr.Fqdn = destination.Address.Domain()
default:
addr.Addr = M.AddrFromIP(destination.Address.IP())
}
addr.Port = uint16(destination.Port)
return addr
}
type pipeConnWrapper struct {
R io.Reader
W buf.Writer
net.Conn
}
func (w *pipeConnWrapper) Close() error {
return nil
}
func (w *pipeConnWrapper) Read(b []byte) (n int, err error) {
return w.R.Read(b)
}
func (w *pipeConnWrapper) Write(p []byte) (n int, err error) {
n = len(p)
var mb buf.MultiBuffer
pLen := len(p)
for pLen > 0 {
buffer := buf.New()
if pLen > buf.Size {
_, err = buffer.Write(p[:buf.Size])
p = p[buf.Size:]
} else {
buffer.Write(p)
}
pLen -= int(buffer.Len())
mb = append(mb, buffer)
}
err = w.W.WriteMultiBuffer(mb)
if err != nil {
n = 0
buf.ReleaseMulti(mb)
}
return
}
type packetConnWrapper struct {
buf.Reader
buf.Writer
net.Conn
Dest net.Destination
cached buf.MultiBuffer
}
func (w *packetConnWrapper) ReadPacket(buffer *B.Buffer) (M.Socksaddr, error) {
if w.cached != nil {
mb, bb := buf.SplitFirst(w.cached)
if bb == nil {
w.cached = nil
} else {
buffer.Write(bb.Bytes())
w.cached = mb
var destination net.Destination
if bb.UDP != nil {
destination = *bb.UDP
} else {
destination = w.Dest
}
bb.Release()
return toSocksaddr(destination), nil
}
}
mb, err := w.ReadMultiBuffer()
if err != nil {
return M.Socksaddr{}, err
}
nb, bb := buf.SplitFirst(mb)
if bb == nil {
return M.Socksaddr{}, nil
} else {
buffer.Write(bb.Bytes())
w.cached = nb
var destination net.Destination
if bb.UDP != nil {
destination = *bb.UDP
} else {
destination = w.Dest
}
bb.Release()
return toSocksaddr(destination), nil
}
}
func (w *packetConnWrapper) WritePacket(buffer *B.Buffer, destination M.Socksaddr) error {
vBuf := buf.New()
vBuf.Write(buffer.Bytes())
endpoint := toDestination(destination, net.Network_UDP)
vBuf.UDP = &endpoint
return w.Writer.WriteMultiBuffer(buf.MultiBuffer{vBuf})
}
func (w *packetConnWrapper) Close() error {
buf.ReleaseMulti(w.cached)
return nil
}
func returnError(err error) error {
if E.IsClosed(err) {
return nil
}
return err
}

View File

@@ -151,8 +151,19 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
newError("failed to clear deadline after handshake").Base(err).WriteToLog(session.ExportIDToError(ctx)) newError("failed to clear deadline after handshake").Base(err).WriteToLog(session.ExportIDToError(ctx))
} }
var newCtx context.Context
var newCancel context.CancelFunc
if session.TimeoutOnlyFromContext(ctx) {
newCtx, newCancel = context.WithCancel(context.Background())
}
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, p.Timeouts.ConnectionIdle) timer := signal.CancelAfterInactivity(ctx, func() {
cancel()
if newCancel != nil {
newCancel()
}
}, p.Timeouts.ConnectionIdle)
var requestFunc func() error var requestFunc func() error
var responseFunc func() error var responseFunc func() error
@@ -183,6 +194,10 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
} }
} }
if newCtx != nil {
ctx = newCtx
}
responseDonePost := task.OnSuccess(responseFunc, task.Close(link.Writer)) responseDonePost := task.OnSuccess(responseFunc, task.Close(link.Writer))
if err := task.Run(ctx, requestFunc, responseDonePost); err != nil { if err := task.Run(ctx, requestFunc, responseDonePost); err != nil {
return newError("connection ends").Base(err) return newError("connection ends").Base(err)

View File

@@ -64,6 +64,7 @@ func (s *Server) Network() []net.Network {
// Process implements proxy.Inbound. // Process implements proxy.Inbound.
func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error { func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error {
if inbound := session.InboundFromContext(ctx); inbound != nil { if inbound := session.InboundFromContext(ctx); inbound != nil {
inbound.Name = "socks"
inbound.User = &protocol.MemoryUser{ inbound.User = &protocol.MemoryUser{
Level: s.config.UserLevel, Level: s.config.UserLevel,
} }

View File

@@ -2,14 +2,12 @@ package trojan
import ( import (
"context" "context"
"syscall"
"time" "time"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/retry" "github.com/xtls/xray-core/common/retry"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
@@ -17,11 +15,9 @@ import (
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
core "github.com/xtls/xray-core/core" core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/xtls"
) )
// Client is a inbound handler for trojan protocol // Client is a inbound handler for trojan protocol
@@ -97,52 +93,20 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
Flow: account.Flow, Flow: account.Flow,
} }
var rawConn syscall.RawConn var newCtx context.Context
var sctx context.Context var newCancel context.CancelFunc
if session.TimeoutOnlyFromContext(ctx) {
allowUDP443 := false newCtx, newCancel = context.WithCancel(context.Background())
switch connWriter.Flow {
case XRO + "-udp443", XRD + "-udp443", XRS + "-udp443":
allowUDP443 = true
connWriter.Flow = connWriter.Flow[:16]
fallthrough
case XRO, XRD, XRS:
if destination.Address.Family().IsDomain() && destination.Address.Domain() == muxCoolAddress {
return newError(connWriter.Flow + " doesn't support Mux").AtWarning()
}
if destination.Network == net.Network_UDP {
if !allowUDP443 && destination.Port == 443 {
return newError(connWriter.Flow + " stopped UDP/443").AtInfo()
}
connWriter.Flow = ""
} else { // enable XTLS only if making TCP request
if xtlsConn, ok := iConn.(*xtls.Conn); ok {
xtlsConn.RPRX = true
xtlsConn.SHOW = xtls_show
xtlsConn.MARK = "XTLS"
if connWriter.Flow == XRS {
sctx = ctx
connWriter.Flow = XRD
}
if connWriter.Flow == XRD {
xtlsConn.DirectMode = true
if sc, ok := xtlsConn.NetConn().(syscall.Conn); ok {
rawConn, _ = sc.SyscallConn()
}
}
} else {
return newError(`failed to use ` + connWriter.Flow + `, maybe "security" is not "xtls"`).AtWarning()
}
}
default:
if _, ok := iConn.(*xtls.Conn); ok {
panic(`To avoid misunderstanding, you must fill in Trojan "flow" when using XTLS.`)
}
} }
sessionPolicy := c.policyManager.ForLevel(user.Level) sessionPolicy := c.policyManager.ForLevel(user.Level)
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle) timer := signal.CancelAfterInactivity(ctx, func() {
cancel()
if newCancel != nil {
newCancel()
}
}, sessionPolicy.Timeouts.ConnectionIdle)
postRequest := func() error { postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly) defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
@@ -193,16 +157,13 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
} else { } else {
reader = buf.NewReader(conn) reader = buf.NewReader(conn)
} }
if rawConn != nil {
var counter stats.Counter
if statConn != nil {
counter = statConn.ReadCounter
}
return ReadV(reader, link.Writer, timer, iConn.(*xtls.Conn), rawConn, counter, sctx)
}
return buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)) return buf.Copy(reader, link.Writer, buf.UpdateActivity(timer))
} }
if newCtx != nil {
ctx = newCtx
}
responseDoneAndCloseWriter := task.OnSuccess(getResponse, task.Close(link.Writer)) responseDoneAndCloseWriter := task.OnSuccess(getResponse, task.Close(link.Writer))
if err := task.Run(ctx, postRequest, responseDoneAndCloseWriter); err != nil { if err := task.Run(ctx, postRequest, responseDoneAndCloseWriter); err != nil {
return newError("connection ends").Base(err) return newError("connection ends").Base(err)
@@ -215,11 +176,4 @@ func init() {
common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewClient(ctx, config.(*ClientConfig)) return NewClient(ctx, config.(*ClientConfig))
})) }))
const defaultFlagValue = "NOT_DEFINED_AT_ALL"
xtlsShow := platform.NewEnvFlag("xray.trojan.xtls.show").GetValue(func() string { return defaultFlagValue })
if xtlsShow == "true" {
xtls_show = true
}
} }

View File

@@ -1,22 +1,12 @@
package trojan package trojan
import ( import (
"context"
"encoding/binary" "encoding/binary"
fmt "fmt"
"io" "io"
"runtime"
"syscall"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/xtls"
) )
var ( var (
@@ -27,25 +17,13 @@ var (
protocol.AddressFamilyByte(0x04, net.AddressFamilyIPv6), protocol.AddressFamilyByte(0x04, net.AddressFamilyIPv6),
protocol.AddressFamilyByte(0x03, net.AddressFamilyDomain), protocol.AddressFamilyByte(0x03, net.AddressFamilyDomain),
) )
xtls_show = false
) )
const ( const (
maxLength = 8192 maxLength = 8192
// XRS is constant for XTLS splice mode
XRS = "xtls-rprx-splice"
// XRD is constant for XTLS direct mode
XRD = "xtls-rprx-direct"
// XRO is constant for XTLS origin mode
XRO = "xtls-rprx-origin"
commandTCP byte = 1 commandTCP byte = 1
commandUDP byte = 3 commandUDP byte = 3
// for XTLS
commandXRD byte = 0xf0 // XTLS direct mode
commandXRO byte = 0xf1 // XTLS origin mode
) )
// ConnWriter is TCP Connection Writer Wrapper for trojan protocol // ConnWriter is TCP Connection Writer Wrapper for trojan protocol
@@ -90,10 +68,6 @@ func (c *ConnWriter) writeHeader() error {
command := commandTCP command := commandTCP
if c.Target.Network == net.Network_UDP { if c.Target.Network == net.Network_UDP {
command = commandUDP command = commandUDP
} else if c.Flow == XRD {
command = commandXRD
} else if c.Flow == XRO {
command = commandXRO
} }
if _, err := buffer.Write(c.Account.Key); err != nil { if _, err := buffer.Write(c.Account.Key); err != nil {
@@ -201,10 +175,6 @@ func (c *ConnReader) ParseHeader() error {
network := net.Network_TCP network := net.Network_TCP
if command[0] == commandUDP { if command[0] == commandUDP {
network = net.Network_UDP network = net.Network_UDP
} else if command[0] == commandXRD {
c.Flow = XRD
} else if command[0] == commandXRO {
c.Flow = XRO
} }
addr, port, err := addrParser.ReadAddressPort(nil, c.Reader) addr, port, err := addrParser.ReadAddressPort(nil, c.Reader)
@@ -288,66 +258,3 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
return mb, nil return mb, nil
} }
func ReadV(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn *xtls.Conn, rawConn syscall.RawConn, counter stats.Counter, sctx context.Context) error {
err := func() error {
var ct stats.Counter
for {
if conn.DirectIn {
conn.DirectIn = false
if sctx != nil {
if inbound := session.InboundFromContext(sctx); inbound != nil && inbound.Conn != nil {
iConn := inbound.Conn
statConn, ok := iConn.(*stat.CounterConnection)
if ok {
iConn = statConn.Connection
}
if xc, ok := iConn.(*xtls.Conn); ok {
iConn = xc.NetConn()
}
if tc, ok := iConn.(*net.TCPConn); ok {
if conn.SHOW {
fmt.Println(conn.MARK, "Splice")
}
runtime.Gosched() // necessary
w, err := tc.ReadFrom(conn.NetConn())
if counter != nil {
counter.Add(w)
}
if statConn != nil && statConn.WriteCounter != nil {
statConn.WriteCounter.Add(w)
}
return err
} else {
panic("XTLS Splice: not TCP inbound")
}
} else {
// panic("XTLS Splice: nil inbound or nil inbound.Conn")
}
}
reader = buf.NewReadVReader(conn.NetConn(), rawConn, nil)
ct = counter
if conn.SHOW {
fmt.Println(conn.MARK, "ReadV")
}
}
buffer, err := reader.ReadMultiBuffer()
if !buffer.IsEmpty() {
if ct != nil {
ct.Add(int64(buffer.Len()))
}
timer.Update()
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
return werr
}
}
if err != nil {
return err
}
}
}()
if err != nil && errors.Cause(err) != io.EOF {
return err
}
return nil
}

View File

@@ -5,7 +5,6 @@ import (
"io" "io"
"strconv" "strconv"
"strings" "strings"
"syscall"
"time" "time"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
@@ -13,7 +12,6 @@ import (
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
udp_proto "github.com/xtls/xray-core/common/protocol/udp" udp_proto "github.com/xtls/xray-core/common/protocol/udp"
"github.com/xtls/xray-core/common/retry" "github.com/xtls/xray-core/common/retry"
@@ -23,24 +21,16 @@ import (
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/udp" "github.com/xtls/xray-core/transport/internet/udp"
"github.com/xtls/xray-core/transport/internet/xtls"
) )
func init() { func init() {
common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewServer(ctx, config.(*ServerConfig)) return NewServer(ctx, config.(*ServerConfig))
})) }))
const defaultFlagValue = "NOT_DEFINED_AT_ALL"
xtlsShow := platform.NewEnvFlag("xray.trojan.xtls.show").GetValue(func() string { return defaultFlagValue })
if xtlsShow == "true" {
xtls_show = true
}
} }
// Server is an inbound connection handler that handles messages in trojan protocol. // Server is an inbound connection handler that handles messages in trojan protocol.
@@ -227,6 +217,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
if inbound == nil { if inbound == nil {
panic("no inbound metadata") panic("no inbound metadata")
} }
inbound.Name = "trojan"
inbound.User = user inbound.User = user
sessionPolicy = s.policyManager.ForLevel(user.Level) sessionPolicy = s.policyManager.ForLevel(user.Level)
@@ -234,39 +225,6 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
return s.handleUDPPayload(ctx, &PacketReader{Reader: clientReader}, &PacketWriter{Writer: conn}, dispatcher) return s.handleUDPPayload(ctx, &PacketReader{Reader: clientReader}, &PacketWriter{Writer: conn}, dispatcher)
} }
// handle tcp request
account, ok := user.Account.(*MemoryAccount)
if !ok {
return newError("user account is not valid")
}
var rawConn syscall.RawConn
switch clientReader.Flow {
case XRO, XRD:
if account.Flow == clientReader.Flow {
if destination.Address.Family().IsDomain() && destination.Address.Domain() == muxCoolAddress {
return newError(clientReader.Flow + " doesn't support Mux").AtWarning()
}
if xtlsConn, ok := iConn.(*xtls.Conn); ok {
xtlsConn.RPRX = true
xtlsConn.SHOW = xtls_show
xtlsConn.MARK = "XTLS"
if clientReader.Flow == XRD {
xtlsConn.DirectMode = true
if sc, ok := xtlsConn.NetConn().(syscall.Conn); ok {
rawConn, _ = sc.SyscallConn()
}
}
} else {
return newError(`failed to use ` + clientReader.Flow + `, maybe "security" is not "xtls"`).AtWarning()
}
} else {
return newError(account.Password + " is not able to use " + clientReader.Flow).AtWarning()
}
case "":
}
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{ ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: conn.RemoteAddr(), From: conn.RemoteAddr(),
To: destination, To: destination,
@@ -276,7 +234,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
}) })
newError("received request for ", destination).WriteToLog(sid) newError("received request for ", destination).WriteToLog(sid)
return s.handleConnection(ctx, sessionPolicy, destination, clientReader, buf.NewWriter(conn), dispatcher, iConn, rawConn, statConn) return s.handleConnection(ctx, sessionPolicy, destination, clientReader, buf.NewWriter(conn), dispatcher, iConn, statConn)
} }
func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReader, clientWriter *PacketWriter, dispatcher routing.Dispatcher) error { func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReader, clientWriter *PacketWriter, dispatcher routing.Dispatcher) error {
@@ -342,7 +300,7 @@ func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReade
func (s *Server) handleConnection(ctx context.Context, sessionPolicy policy.Session, func (s *Server) handleConnection(ctx context.Context, sessionPolicy policy.Session,
destination net.Destination, destination net.Destination,
clientReader buf.Reader, clientReader buf.Reader,
clientWriter buf.Writer, dispatcher routing.Dispatcher, iConn stat.Connection, rawConn syscall.RawConn, statConn *stat.CounterConnection, clientWriter buf.Writer, dispatcher routing.Dispatcher, iConn stat.Connection, statConn *stat.CounterConnection,
) error { ) error {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle) timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
@@ -355,18 +313,7 @@ func (s *Server) handleConnection(ctx context.Context, sessionPolicy policy.Sess
requestDone := func() error { requestDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly) defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
if buf.Copy(clientReader, link.Writer, buf.UpdateActivity(timer)) != nil {
var err error
if rawConn != nil {
var counter stats.Counter
if statConn != nil {
counter = statConn.ReadCounter
}
err = ReadV(clientReader, link.Writer, timer, iConn.(*xtls.Conn), rawConn, counter, nil)
} else {
err = buf.Copy(clientReader, link.Writer, buf.UpdateActivity(timer))
}
if err != nil {
return newError("failed to transfer request").Base(err) return newError("failed to transfer request").Base(err)
} }
return nil return nil
@@ -405,8 +352,8 @@ func (s *Server) fallback(ctx context.Context, sid errors.ExportOption, err erro
alpn = cs.NegotiatedProtocol alpn = cs.NegotiatedProtocol
newError("realName = " + name).AtInfo().WriteToLog(sid) newError("realName = " + name).AtInfo().WriteToLog(sid)
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid) newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
} else if xtlsConn, ok := iConn.(*xtls.Conn); ok { } else if realityConn, ok := iConn.(*reality.Conn); ok {
cs := xtlsConn.ConnectionState() cs := realityConn.ConnectionState()
name = cs.ServerName name = cs.ServerName
alpn = cs.NegotiatedProtocol alpn = cs.NegotiatedProtocol
newError("realName = " + name).AtInfo().WriteToLog(sid) newError("realName = " + name).AtInfo().WriteToLog(sid)

View File

@@ -22,7 +22,7 @@ func (a *Account) AsAccount() (protocol.Account, error) {
type MemoryAccount struct { type MemoryAccount struct {
// ID of the account. // ID of the account.
ID *protocol.ID ID *protocol.ID
// Flow of the account. May be "xtls-rprx-direct". // Flow of the account. May be "xtls-rprx-vision".
Flow string Flow string
// Encryption of the account. Used for client connections, and only accepts "none" for now. // Encryption of the account. Used for client connections, and only accepts "none" for now.
Encryption string Encryption string

View File

@@ -27,7 +27,7 @@ type Account struct {
// ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57". // ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
// Flow settings. May be "xtls-rprx-direct". // Flow settings. May be "xtls-rprx-vision".
Flow string `protobuf:"bytes,2,opt,name=flow,proto3" json:"flow,omitempty"` Flow string `protobuf:"bytes,2,opt,name=flow,proto3" json:"flow,omitempty"`
// Encryption settings. Only applies to client side, and only accepts "none" for now. // Encryption settings. Only applies to client side, and only accepts "none" for now.
Encryption string `protobuf:"bytes,3,opt,name=encryption,proto3" json:"encryption,omitempty"` Encryption string `protobuf:"bytes,3,opt,name=encryption,proto3" json:"encryption,omitempty"`

View File

@@ -9,7 +9,7 @@ option java_multiple_files = true;
message Account { message Account {
// ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57". // ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
string id = 1; string id = 1;
// Flow settings. May be "xtls-rprx-direct". // Flow settings. May be "xtls-rprx-vision".
string flow = 2; string flow = 2;
// Encryption settings. Only applies to client side, and only accepts "none" for now. // Encryption settings. Only applies to client side, and only accepts "none" for now.
string encryption = 3; string encryption = 3;

View File

@@ -11,7 +11,7 @@ import (
func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error { func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {
switch addons.Flow { switch addons.Flow {
case vless.XRO, vless.XRD, vless.XRV: case vless.XRV:
bytes, err := proto.Marshal(addons) bytes, err := proto.Marshal(addons)
if err != nil { if err != nil {
return newError("failed to marshal addons protobuf value").Base(err) return newError("failed to marshal addons protobuf value").Base(err)

View File

@@ -6,7 +6,6 @@ import (
"bytes" "bytes"
"context" "context"
"crypto/rand" "crypto/rand"
"fmt"
"io" "io"
"math/big" "math/big"
"runtime" "runtime"
@@ -22,9 +21,9 @@ import (
"github.com/xtls/xray-core/common/signal" "github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/proxy/vless" "github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/xtls"
) )
const ( const (
@@ -36,6 +35,23 @@ var (
tlsClientHandShakeStart = []byte{0x16, 0x03} tlsClientHandShakeStart = []byte{0x16, 0x03}
tlsServerHandShakeStart = []byte{0x16, 0x03, 0x03} tlsServerHandShakeStart = []byte{0x16, 0x03, 0x03}
tlsApplicationDataStart = []byte{0x17, 0x03, 0x03} tlsApplicationDataStart = []byte{0x17, 0x03, 0x03}
Tls13CipherSuiteDic = map[uint16]string{
0x1301: "TLS_AES_128_GCM_SHA256",
0x1302: "TLS_AES_256_GCM_SHA384",
0x1303: "TLS_CHACHA20_POLY1305_SHA256",
0x1304: "TLS_AES_128_CCM_SHA256",
0x1305: "TLS_AES_128_CCM_8_SHA256",
}
)
const (
tlsHandshakeTypeClientHello byte = 0x01
tlsHandshakeTypeServerHello byte = 0x02
CommandPaddingContinue byte = 0x00
CommandPaddingEnd byte = 0x01
CommandPaddingDirect byte = 0x02
) )
var addrParser = protocol.NewAddressParser( var addrParser = protocol.NewAddressParser(
@@ -189,65 +205,6 @@ func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*A
return responseAddons, nil return responseAddons, nil
} }
func ReadV(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn *xtls.Conn, rawConn syscall.RawConn, counter stats.Counter, ctx context.Context) error {
err := func() error {
var ct stats.Counter
for {
if conn.DirectIn {
conn.DirectIn = false
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil {
iConn := inbound.Conn
statConn, ok := iConn.(*stat.CounterConnection)
if ok {
iConn = statConn.Connection
}
if xc, ok := iConn.(*xtls.Conn); ok {
iConn = xc.NetConn()
}
if tc, ok := iConn.(*net.TCPConn); ok {
if conn.SHOW {
fmt.Println(conn.MARK, "Splice")
}
runtime.Gosched() // necessary
w, err := tc.ReadFrom(conn.NetConn())
if counter != nil {
counter.Add(w)
}
if statConn != nil && statConn.WriteCounter != nil {
statConn.WriteCounter.Add(w)
}
return err
} else {
panic("XTLS Splice: not TCP inbound")
}
}
reader = buf.NewReadVReader(conn.NetConn(), rawConn, nil)
ct = counter
if conn.SHOW {
fmt.Println(conn.MARK, "ReadV")
}
}
buffer, err := reader.ReadMultiBuffer()
if !buffer.IsEmpty() {
if ct != nil {
ct.Add(int64(buffer.Len()))
}
timer.Update()
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
return werr
}
}
if err != nil {
return err
}
}
}()
if err != nil && errors.Cause(err) != io.EOF {
return err
}
return nil
}
// XtlsRead filter and read xtls protocol // XtlsRead filter and read xtls protocol
func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, rawConn syscall.RawConn, func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, rawConn syscall.RawConn,
input *bytes.Reader, rawInput *bytes.Buffer, input *bytes.Reader, rawInput *bytes.Buffer,
@@ -256,7 +213,7 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater
) error { ) error {
err := func() error { err := func() error {
var ct stats.Counter var ct stats.Counter
filterUUID := true withinPaddingBuffers := true
shouldSwitchToDirectCopy := false shouldSwitchToDirectCopy := false
var remainingContent int32 = -1 var remainingContent int32 = -1
var remainingPadding int32 = -1 var remainingPadding int32 = -1
@@ -271,8 +228,10 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater
if ok { if ok {
iConn = statConn.Connection iConn = statConn.Connection
} }
if xc, ok := iConn.(*tls.Conn); ok { if tlsConn, ok := iConn.(*tls.Conn); ok {
iConn = xc.NetConn() iConn = tlsConn.NetConn()
} else if realityConn, ok := iConn.(*reality.Conn); ok {
iConn = realityConn.NetConn()
} }
if tc, ok := iConn.(*net.TCPConn); ok { if tc, ok := iConn.(*net.TCPConn); ok {
newError("XtlsRead splice").WriteToLog(session.ExportIDToError(ctx)) newError("XtlsRead splice").WriteToLog(session.ExportIDToError(ctx))
@@ -294,13 +253,15 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater
} }
buffer, err := reader.ReadMultiBuffer() buffer, err := reader.ReadMultiBuffer()
if !buffer.IsEmpty() { if !buffer.IsEmpty() {
if filterUUID && (*isTLS || *numberOfPacketToFilter > 0) { if withinPaddingBuffers || *numberOfPacketToFilter > 0 {
buffer = XtlsUnpadding(ctx, buffer, userUUID, &remainingContent, &remainingPadding, &currentCommand) buffer = XtlsUnpadding(ctx, buffer, userUUID, &remainingContent, &remainingPadding, &currentCommand)
if remainingContent == 0 && remainingPadding == 0 { if remainingContent == 0 && remainingPadding == 0 {
if currentCommand == 1 { if currentCommand == 1 {
filterUUID = false withinPaddingBuffers = false
remainingContent = -1
remainingPadding = -1 // set to initial state to parse the next padding
} else if currentCommand == 2 { } else if currentCommand == 2 {
filterUUID = false withinPaddingBuffers = false
shouldSwitchToDirectCopy = true shouldSwitchToDirectCopy = true
// XTLS Vision processes struct TLS Conn's input and rawInput // XTLS Vision processes struct TLS Conn's input and rawInput
if inputBuffer, err := buf.ReadFrom(input); err == nil { if inputBuffer, err := buf.ReadFrom(input); err == nil {
@@ -313,9 +274,15 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater
buffer, _ = buf.MergeMulti(buffer, rawInputBuffer) buffer, _ = buf.MergeMulti(buffer, rawInputBuffer)
} }
} }
} else if currentCommand != 0 { } else if currentCommand == 0 {
withinPaddingBuffers = true
} else {
newError("XtlsRead unknown command ", currentCommand, buffer.Len()).WriteToLog(session.ExportIDToError(ctx)) newError("XtlsRead unknown command ", currentCommand, buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
} }
} else if remainingContent > 0 || remainingPadding > 0 {
withinPaddingBuffers = true
} else {
withinPaddingBuffers = false
} }
} }
if *numberOfPacketToFilter > 0 { if *numberOfPacketToFilter > 0 {
@@ -342,12 +309,12 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater
// XtlsWrite filter and write xtls protocol // XtlsWrite filter and write xtls protocol
func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, counter stats.Counter, func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, counter stats.Counter,
ctx context.Context, userUUID *[]byte, numberOfPacketToFilter *int, enableXtls *bool, isTLS12orAbove *bool, isTLS *bool, ctx context.Context, numberOfPacketToFilter *int, enableXtls *bool, isTLS12orAbove *bool, isTLS *bool,
cipher *uint16, remainingServerHello *int32, cipher *uint16, remainingServerHello *int32,
) error { ) error {
err := func() error { err := func() error {
var ct stats.Counter var ct stats.Counter
filterTlsApplicationData := true isPadding := true
shouldSwitchToDirectCopy := false shouldSwitchToDirectCopy := false
for { for {
buffer, err := reader.ReadMultiBuffer() buffer, err := reader.ReadMultiBuffer()
@@ -355,27 +322,26 @@ func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdate
if *numberOfPacketToFilter > 0 { if *numberOfPacketToFilter > 0 {
XtlsFilterTls(buffer, numberOfPacketToFilter, enableXtls, isTLS12orAbove, isTLS, cipher, remainingServerHello, ctx) XtlsFilterTls(buffer, numberOfPacketToFilter, enableXtls, isTLS12orAbove, isTLS, cipher, remainingServerHello, ctx)
} }
if filterTlsApplicationData && *isTLS { if isPadding {
buffer = ReshapeMultiBuffer(ctx, buffer) buffer = ReshapeMultiBuffer(ctx, buffer)
var xtlsSpecIndex int var xtlsSpecIndex int
for i, b := range buffer { for i, b := range buffer {
if b.Len() >= 6 && bytes.Equal(tlsApplicationDataStart, b.BytesTo(3)) { if *isTLS && b.Len() >= 6 && bytes.Equal(tlsApplicationDataStart, b.BytesTo(3)) {
var command byte = 0x01 var command byte = CommandPaddingEnd
if *enableXtls { if *enableXtls {
shouldSwitchToDirectCopy = true shouldSwitchToDirectCopy = true
xtlsSpecIndex = i xtlsSpecIndex = i
command = 0x02 command = CommandPaddingDirect
} }
filterTlsApplicationData = false isPadding = false
buffer[i] = XtlsPadding(b, command, userUUID, ctx) buffer[i] = XtlsPadding(b, command, nil, *isTLS, ctx)
break break
} else if !*isTLS12orAbove && *numberOfPacketToFilter <= 0 { } else if !*isTLS12orAbove && *numberOfPacketToFilter <= 1 { // For compatibility with earlier vision receiver, we finish padding 1 packet early
// maybe tls 1.1 or 1.0 isPadding = false
filterTlsApplicationData = false buffer[i] = XtlsPadding(b, CommandPaddingEnd, nil, *isTLS, ctx)
buffer[i] = XtlsPadding(b, 0x01, userUUID, ctx)
break break
} }
buffer[i] = XtlsPadding(b, 0x00, userUUID, ctx) buffer[i] = XtlsPadding(b, CommandPaddingContinue, nil, *isTLS, ctx)
} }
if shouldSwitchToDirectCopy { if shouldSwitchToDirectCopy {
encryptBuffer, directBuffer := buf.SplitMulti(buffer, xtlsSpecIndex+1) encryptBuffer, directBuffer := buf.SplitMulti(buffer, xtlsSpecIndex+1)
@@ -422,7 +388,7 @@ func XtlsFilterTls(buffer buf.MultiBuffer, numberOfPacketToFilter *int, enableXt
*numberOfPacketToFilter-- *numberOfPacketToFilter--
if b.Len() >= 6 { if b.Len() >= 6 {
startsBytes := b.BytesTo(6) startsBytes := b.BytesTo(6)
if bytes.Equal(tlsServerHandShakeStart, startsBytes[:3]) && startsBytes[5] == 0x02 { if bytes.Equal(tlsServerHandShakeStart, startsBytes[:3]) && startsBytes[5] == tlsHandshakeTypeServerHello {
*remainingServerHello = (int32(startsBytes[3])<<8 | int32(startsBytes[4])) + 5 *remainingServerHello = (int32(startsBytes[3])<<8 | int32(startsBytes[4])) + 5
*isTLS12orAbove = true *isTLS12orAbove = true
*isTLS = true *isTLS = true
@@ -433,7 +399,7 @@ func XtlsFilterTls(buffer buf.MultiBuffer, numberOfPacketToFilter *int, enableXt
} else { } else {
newError("XtlsFilterTls short server hello, tls 1.2 or older? ", b.Len(), " ", *remainingServerHello).WriteToLog(session.ExportIDToError(ctx)) newError("XtlsFilterTls short server hello, tls 1.2 or older? ", b.Len(), " ", *remainingServerHello).WriteToLog(session.ExportIDToError(ctx))
} }
} else if bytes.Equal(tlsClientHandShakeStart, startsBytes[:2]) && startsBytes[5] == 0x01 { } else if bytes.Equal(tlsClientHandShakeStart, startsBytes[:2]) && startsBytes[5] == tlsHandshakeTypeClientHello {
*isTLS = true *isTLS = true
newError("XtlsFilterTls found tls client hello! ", buffer.Len()).WriteToLog(session.ExportIDToError(ctx)) newError("XtlsFilterTls found tls client hello! ", buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
} }
@@ -469,62 +435,75 @@ func XtlsFilterTls(buffer buf.MultiBuffer, numberOfPacketToFilter *int, enableXt
// ReshapeMultiBuffer prepare multi buffer for padding stucture (max 21 bytes) // ReshapeMultiBuffer prepare multi buffer for padding stucture (max 21 bytes)
func ReshapeMultiBuffer(ctx context.Context, buffer buf.MultiBuffer) buf.MultiBuffer { func ReshapeMultiBuffer(ctx context.Context, buffer buf.MultiBuffer) buf.MultiBuffer {
needReshape := false needReshape := 0
for _, b := range buffer { for _, b := range buffer {
if b.Len() >= buf.Size-21 { if b.Len() >= buf.Size-21 {
needReshape = true needReshape += 1
} }
} }
if !needReshape { if needReshape == 0 {
return buffer return buffer
} }
mb2 := make(buf.MultiBuffer, 0, len(buffer)) mb2 := make(buf.MultiBuffer, 0, len(buffer)+needReshape)
print := "" toPrint := ""
for _, b := range buffer { for i, buffer1 := range buffer {
if b.Len() >= buf.Size-21 { if buffer1.Len() >= buf.Size-21 {
index := int32(bytes.LastIndex(b.Bytes(), tlsApplicationDataStart)) index := int32(bytes.LastIndex(buffer1.Bytes(), tlsApplicationDataStart))
if index <= 0 { if index <= 0 || index > buf.Size-21 {
index = buf.Size / 2 index = buf.Size / 2
} }
buffer1 := buf.New()
buffer2 := buf.New() buffer2 := buf.New()
buffer1.Write(b.BytesTo(index)) buffer2.Write(buffer1.BytesFrom(index))
buffer2.Write(b.BytesFrom(index)) buffer1.Resize(0, index)
mb2 = append(mb2, buffer1, buffer2) mb2 = append(mb2, buffer1, buffer2)
print += " " + strconv.Itoa(int(buffer1.Len())) + " " + strconv.Itoa(int(buffer2.Len())) toPrint += " " + strconv.Itoa(int(buffer1.Len())) + " " + strconv.Itoa(int(buffer2.Len()))
} else { } else {
newbuffer := buf.New() mb2 = append(mb2, buffer1)
newbuffer.Write(b.Bytes()) toPrint += " " + strconv.Itoa(int(buffer1.Len()))
mb2 = append(mb2, newbuffer)
print += " " + strconv.Itoa(int(b.Len()))
} }
buffer[i] = nil
} }
buf.ReleaseMulti(buffer) buffer = buffer[:0]
newError("ReshapeMultiBuffer ", print).WriteToLog(session.ExportIDToError(ctx)) newError("ReshapeMultiBuffer ", toPrint).WriteToLog(session.ExportIDToError(ctx))
return mb2 return mb2
} }
// XtlsPadding add padding to eliminate length siganature during tls handshake // XtlsPadding add padding to eliminate length siganature during tls handshake
func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, ctx context.Context) *buf.Buffer { func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, longPadding bool, ctx context.Context) *buf.Buffer {
var length int32 = 0 var contentLen int32 = 0
if b.Len() < 900 { var paddingLen int32 = 0
if b != nil {
contentLen = b.Len()
}
if contentLen < 900 && longPadding {
l, err := rand.Int(rand.Reader, big.NewInt(500)) l, err := rand.Int(rand.Reader, big.NewInt(500))
if err != nil { if err != nil {
newError("failed to generate padding").Base(err).WriteToLog(session.ExportIDToError(ctx)) newError("failed to generate padding").Base(err).WriteToLog(session.ExportIDToError(ctx))
} }
length = int32(l.Int64()) + 900 - b.Len() paddingLen = int32(l.Int64()) + 900 - contentLen
} else {
l, err := rand.Int(rand.Reader, big.NewInt(256))
if err != nil {
newError("failed to generate padding").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
paddingLen = int32(l.Int64())
}
if paddingLen > buf.Size-21-contentLen {
paddingLen = buf.Size - 21 - contentLen
} }
newbuffer := buf.New() newbuffer := buf.New()
if userUUID != nil { if userUUID != nil {
newbuffer.Write(*userUUID) newbuffer.Write(*userUUID)
*userUUID = nil *userUUID = nil
} }
newbuffer.Write([]byte{command, byte(b.Len() >> 8), byte(b.Len()), byte(length >> 8), byte(length)}) newbuffer.Write([]byte{command, byte(contentLen >> 8), byte(contentLen), byte(paddingLen >> 8), byte(paddingLen)})
newbuffer.Write(b.Bytes()) if b != nil {
newbuffer.Extend(length) newbuffer.Write(b.Bytes())
newError("XtlsPadding ", b.Len(), " ", length, " ", command).WriteToLog(session.ExportIDToError(ctx)) b.Release()
b.Release() b = nil
b = nil }
newbuffer.Extend(paddingLen)
newError("XtlsPadding ", contentLen, " ", paddingLen, " ", command).WriteToLog(session.ExportIDToError(ctx))
return newbuffer return newbuffer
} }
@@ -539,6 +518,7 @@ func XtlsUnpadding(ctx context.Context, buffer buf.MultiBuffer, userUUID []byte,
posByte = 16 posByte = 16
*remainingContent = 0 *remainingContent = 0
*remainingPadding = 0 *remainingPadding = 0
*currentCommand = 0
break break
} }
} }
@@ -597,11 +577,3 @@ func XtlsUnpadding(ctx context.Context, buffer buf.MultiBuffer, userUUID []byte,
buf.ReleaseMulti(buffer) buf.ReleaseMulti(buffer)
return mb2 return mb2
} }
var Tls13CipherSuiteDic = map[uint16]string{
0x1301: "TLS_AES_128_GCM_SHA256",
0x1302: "TLS_AES_256_GCM_SHA384",
0x1303: "TLS_CHACHA20_POLY1305_SHA256",
0x1304: "TLS_AES_128_CCM_SHA256",
0x1305: "TLS_AES_128_CCM_8_SHA256",
}

View File

@@ -20,13 +20,12 @@ import (
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/retry" "github.com/xtls/xray-core/common/retry"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal" "github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
core "github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
feature_inbound "github.com/xtls/xray-core/features/inbound" feature_inbound "github.com/xtls/xray-core/features/inbound"
"github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/policy"
@@ -34,13 +33,11 @@ import (
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/proxy/vless" "github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/proxy/vless/encoding" "github.com/xtls/xray-core/proxy/vless/encoding"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/xtls"
) )
var xtls_show = false
func init() { func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
var dc dns.Client var dc dns.Client
@@ -52,13 +49,6 @@ func init() {
} }
return New(ctx, config.(*Config), dc) return New(ctx, config.(*Config), dc)
})) }))
const defaultFlagValue = "NOT_DEFINED_AT_ALL"
xtlsShow := platform.NewEnvFlag("xray.vless.xtls.show").GetValue(func() string { return defaultFlagValue })
if xtlsShow == "true" {
xtls_show = true
}
} }
// Handler is an inbound connection handler that handles messages in VLess protocol. // Handler is an inbound connection handler that handles messages in VLess protocol.
@@ -240,8 +230,8 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
alpn = cs.NegotiatedProtocol alpn = cs.NegotiatedProtocol
newError("realName = " + name).AtInfo().WriteToLog(sid) newError("realName = " + name).AtInfo().WriteToLog(sid)
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid) newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
} else if xtlsConn, ok := iConn.(*xtls.Conn); ok { } else if realityConn, ok := iConn.(*reality.Conn); ok {
cs := xtlsConn.ConnectionState() cs := realityConn.ConnectionState()
name = cs.ServerName name = cs.ServerName
alpn = cs.NegotiatedProtocol alpn = cs.NegotiatedProtocol
newError("realName = " + name).AtInfo().WriteToLog(sid) newError("realName = " + name).AtInfo().WriteToLog(sid)
@@ -448,6 +438,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
if inbound == nil { if inbound == nil {
panic("no inbound metadata") panic("no inbound metadata")
} }
inbound.Name = "vless"
inbound.User = request.User inbound.User = request.User
account := request.User.Account.(*vless.MemoryAccount) account := request.User.Account.(*vless.MemoryAccount)
@@ -460,75 +451,50 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
var rawConn syscall.RawConn var rawConn syscall.RawConn
var input *bytes.Reader var input *bytes.Reader
var rawInput *bytes.Buffer var rawInput *bytes.Buffer
allowNoneFlow := false
accountFlow := account.Flow
flows := strings.Split(account.Flow, ",")
for _, f := range flows {
t := strings.TrimSpace(f)
if t == "none" {
allowNoneFlow = true
} else {
accountFlow = t
}
}
switch requestAddons.Flow { switch requestAddons.Flow {
case vless.XRO, vless.XRD, vless.XRV: case vless.XRV:
if accountFlow == requestAddons.Flow { if account.Flow == requestAddons.Flow {
switch request.Command { switch request.Command {
case protocol.RequestCommandMux:
return newError(requestAddons.Flow + " doesn't support Mux").AtWarning()
case protocol.RequestCommandUDP: case protocol.RequestCommandUDP:
return newError(requestAddons.Flow + " doesn't support UDP").AtWarning() return newError(requestAddons.Flow + " doesn't support UDP").AtWarning()
case protocol.RequestCommandMux:
fallthrough // we will break Mux connections that contain TCP requests
case protocol.RequestCommandTCP: case protocol.RequestCommandTCP:
if requestAddons.Flow == vless.XRV { var t reflect.Type
var t reflect.Type var p uintptr
var p uintptr if tlsConn, ok := iConn.(*tls.Conn); ok {
if tlsConn, ok := iConn.(*tls.Conn); ok { if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 { return newError(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version).AtWarning()
return newError(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version).AtWarning()
}
netConn = tlsConn.NetConn()
if pc, ok := netConn.(*proxyproto.Conn); ok {
netConn = pc.Raw()
// 8192 > 4096, there is no need to process pc's bufReader
}
t = reflect.TypeOf(tlsConn.Conn).Elem()
p = uintptr(unsafe.Pointer(tlsConn.Conn))
} else if _, ok := iConn.(*tls.UConn); ok {
return newError("XTLS only supports UTLS fingerprint for the outbound.").AtWarning()
} else if _, ok := iConn.(*xtls.Conn); ok {
return newError(`failed to use ` + requestAddons.Flow + `, vision "security" must be "tls"`).AtWarning()
} else {
return newError("XTLS only supports TCP, mKCP and DomainSocket for now.").AtWarning()
}
if sc, ok := netConn.(syscall.Conn); ok {
rawConn, _ = sc.SyscallConn()
}
i, _ := t.FieldByName("input")
r, _ := t.FieldByName("rawInput")
input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset))
rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
} else if xtlsConn, ok := iConn.(*xtls.Conn); ok {
xtlsConn.RPRX = true
xtlsConn.SHOW = xtls_show
xtlsConn.MARK = "XTLS"
if requestAddons.Flow == vless.XRD {
xtlsConn.DirectMode = true
if sc, ok := xtlsConn.NetConn().(syscall.Conn); ok {
rawConn, _ = sc.SyscallConn()
}
} }
netConn = tlsConn.NetConn()
t = reflect.TypeOf(tlsConn.Conn).Elem()
p = uintptr(unsafe.Pointer(tlsConn.Conn))
} else if realityConn, ok := iConn.(*reality.Conn); ok {
netConn = realityConn.NetConn()
t = reflect.TypeOf(realityConn.Conn).Elem()
p = uintptr(unsafe.Pointer(realityConn.Conn))
} else { } else {
return newError(`failed to use ` + requestAddons.Flow + `, maybe "security" is not "xtls"`).AtWarning() return newError("XTLS only supports TLS and REALITY directly for now.").AtWarning()
} }
if pc, ok := netConn.(*proxyproto.Conn); ok {
netConn = pc.Raw()
// 8192 > 4096, there is no need to process pc's bufReader
}
if sc, ok := netConn.(syscall.Conn); ok {
rawConn, _ = sc.SyscallConn()
}
i, _ := t.FieldByName("input")
r, _ := t.FieldByName("rawInput")
input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset))
rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
} }
} else { } else {
return newError(account.ID.String() + " is not able to use " + requestAddons.Flow).AtWarning() return newError(account.ID.String() + " is not able to use " + requestAddons.Flow).AtWarning()
} }
case "", "none": case "":
if accountFlow == vless.XRV && !allowNoneFlow && (request.Command == protocol.RequestCommandTCP || isMuxAndNotXUDP(request, first)) { if account.Flow == vless.XRV && (request.Command == protocol.RequestCommandTCP || isMuxAndNotXUDP(request, first)) {
return newError(account.ID.String() + " is not able to use " + vless.XRV + return newError(account.ID.String() + " is not able to use \"\". Note that the pure TLS proxy has certain TLS in TLS characters.").AtWarning()
". Note the pure tls proxy has certain tls in tls characters. Append \",none\" in flow to suppress").AtWarning()
} }
default: default:
return newError("unknown request flow " + requestAddons.Flow).AtWarning() return newError("unknown request flow " + requestAddons.Flow).AtWarning()
@@ -542,6 +508,8 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
Reason: "", Reason: "",
Email: request.User.Email, Email: request.User.Email,
}) })
} else if account.Flow == vless.XRV {
ctx = session.ContextWithAllowedNetwork(ctx, net.Network_UDP)
} }
sessionPolicy = h.policyManager.ForLevel(request.User.Level) sessionPolicy = h.policyManager.ForLevel(request.User.Level)
@@ -578,12 +546,8 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
} }
// TODO enable splice // TODO enable splice
ctx = session.ContextWithInbound(ctx, nil) ctx = session.ContextWithInbound(ctx, nil)
if requestAddons.Flow == vless.XRV { err = encoding.XtlsRead(clientReader, serverWriter, timer, netConn, rawConn, input, rawInput, counter, ctx, account.ID.Bytes(),
err = encoding.XtlsRead(clientReader, serverWriter, timer, netConn, rawConn, input, rawInput, counter, ctx, account.ID.Bytes(), &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello)
&numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello)
} else {
err = encoding.ReadV(clientReader, serverWriter, timer, iConn.(*xtls.Conn), rawConn, counter, ctx)
}
} else { } else {
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer // from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer)) err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
@@ -613,11 +577,9 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
} }
if requestAddons.Flow == vless.XRV { if requestAddons.Flow == vless.XRV {
encoding.XtlsFilterTls(multiBuffer, &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello, ctx) encoding.XtlsFilterTls(multiBuffer, &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello, ctx)
if isTLS { multiBuffer = encoding.ReshapeMultiBuffer(ctx, multiBuffer)
multiBuffer = encoding.ReshapeMultiBuffer(ctx, multiBuffer) for i, b := range multiBuffer {
for i, b := range multiBuffer { multiBuffer[i] = encoding.XtlsPadding(b, encoding.CommandPaddingContinue, &userUUID, isTLS, ctx)
multiBuffer[i] = encoding.XtlsPadding(b, 0x00, &userUUID, ctx)
}
} }
} }
if err := clientWriter.WriteMultiBuffer(multiBuffer); err != nil { if err := clientWriter.WriteMultiBuffer(multiBuffer); err != nil {
@@ -634,7 +596,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
if statConn != nil { if statConn != nil {
counter = statConn.WriteCounter counter = statConn.WriteCounter
} }
err = encoding.XtlsWrite(serverReader, clientWriter, timer, netConn, counter, ctx, &userUUID, &numberOfPacketToFilter, err = encoding.XtlsWrite(serverReader, clientWriter, timer, netConn, counter, ctx, &numberOfPacketToFilter,
&enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello) &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello)
} else { } else {
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer // from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer

View File

@@ -15,38 +15,28 @@ import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/retry" "github.com/xtls/xray-core/common/retry"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal" "github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/common/xudp" "github.com/xtls/xray-core/common/xudp"
core "github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/proxy/vless" "github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/proxy/vless/encoding" "github.com/xtls/xray-core/proxy/vless/encoding"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/xtls"
) )
var xtls_show = false
func init() { func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config)) return New(ctx, config.(*Config))
})) }))
const defaultFlagValue = "NOT_DEFINED_AT_ALL"
xtlsShow := platform.NewEnvFlag("xray.vless.xtls.show").GetValue(func() string { return defaultFlagValue })
if xtlsShow == "true" {
xtls_show = true
}
} }
// Handler is an outbound connection handler for VLess protocol. // Handler is an outbound connection handler for VLess protocol.
@@ -139,69 +129,61 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
var rawInput *bytes.Buffer var rawInput *bytes.Buffer
allowUDP443 := false allowUDP443 := false
switch requestAddons.Flow { switch requestAddons.Flow {
case vless.XRO + "-udp443", vless.XRD + "-udp443", vless.XRS + "-udp443", vless.XRV + "-udp443": case vless.XRV + "-udp443":
allowUDP443 = true allowUDP443 = true
requestAddons.Flow = requestAddons.Flow[:16] requestAddons.Flow = requestAddons.Flow[:16]
fallthrough fallthrough
case vless.XRO, vless.XRD, vless.XRS, vless.XRV: case vless.XRV:
switch request.Command { switch request.Command {
case protocol.RequestCommandMux:
return newError(requestAddons.Flow + " doesn't support Mux").AtWarning()
case protocol.RequestCommandUDP: case protocol.RequestCommandUDP:
if !allowUDP443 && request.Port == 443 { if !allowUDP443 && request.Port == 443 {
return newError(requestAddons.Flow + " stopped UDP/443").AtInfo() return newError("XTLS rejected UDP/443 traffic").AtInfo()
} }
requestAddons.Flow = "" requestAddons.Flow = ""
case protocol.RequestCommandMux:
fallthrough // let server break Mux connections that contain TCP requests
case protocol.RequestCommandTCP: case protocol.RequestCommandTCP:
if requestAddons.Flow == vless.XRV { var t reflect.Type
var t reflect.Type var p uintptr
var p uintptr if tlsConn, ok := iConn.(*tls.Conn); ok {
if tlsConn, ok := iConn.(*tls.Conn); ok { netConn = tlsConn.NetConn()
netConn = tlsConn.NetConn() t = reflect.TypeOf(tlsConn.Conn).Elem()
t = reflect.TypeOf(tlsConn.Conn).Elem() p = uintptr(unsafe.Pointer(tlsConn.Conn))
p = uintptr(unsafe.Pointer(tlsConn.Conn)) } else if utlsConn, ok := iConn.(*tls.UConn); ok {
} else if utlsConn, ok := iConn.(*tls.UConn); ok { netConn = utlsConn.NetConn()
netConn = utlsConn.NetConn() t = reflect.TypeOf(utlsConn.Conn).Elem()
t = reflect.TypeOf(utlsConn.Conn).Elem() p = uintptr(unsafe.Pointer(utlsConn.Conn))
p = uintptr(unsafe.Pointer(utlsConn.Conn)) } else if realityConn, ok := iConn.(*reality.UConn); ok {
} else if _, ok := iConn.(*xtls.Conn); ok { netConn = realityConn.NetConn()
return newError(`failed to use ` + requestAddons.Flow + `, vision "security" must be "tls"`).AtWarning() t = reflect.TypeOf(realityConn.Conn).Elem()
} else { p = uintptr(unsafe.Pointer(realityConn.Conn))
return newError("XTLS only supports TCP, mKCP and DomainSocket for now.").AtWarning()
}
if sc, ok := netConn.(syscall.Conn); ok {
rawConn, _ = sc.SyscallConn()
}
i, _ := t.FieldByName("input")
r, _ := t.FieldByName("rawInput")
input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset))
rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
} else if xtlsConn, ok := iConn.(*xtls.Conn); ok {
xtlsConn.RPRX = true
xtlsConn.SHOW = xtls_show
xtlsConn.MARK = "XTLS"
if requestAddons.Flow == vless.XRS {
requestAddons.Flow = vless.XRD
}
if requestAddons.Flow == vless.XRD {
xtlsConn.DirectMode = true
if sc, ok := xtlsConn.NetConn().(syscall.Conn); ok {
rawConn, _ = sc.SyscallConn()
}
}
} else { } else {
return newError(`failed to use ` + requestAddons.Flow + `, maybe "security" is not "xtls"`).AtWarning() return newError("XTLS only supports TLS and REALITY directly for now.").AtWarning()
} }
if sc, ok := netConn.(syscall.Conn); ok {
rawConn, _ = sc.SyscallConn()
}
i, _ := t.FieldByName("input")
r, _ := t.FieldByName("rawInput")
input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset))
rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
} }
default: }
if _, ok := iConn.(*xtls.Conn); ok {
panic(`To avoid misunderstanding, you must fill in VLESS "flow" when using XTLS.`) var newCtx context.Context
} var newCancel context.CancelFunc
if session.TimeoutOnlyFromContext(ctx) {
newCtx, newCancel = context.WithCancel(context.Background())
} }
sessionPolicy := h.policyManager.ForLevel(request.User.Level) sessionPolicy := h.policyManager.ForLevel(request.User.Level)
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle) timer := signal.CancelAfterInactivity(ctx, func() {
cancel()
if newCancel != nil {
newCancel()
}
}, sessionPolicy.Timeouts.ConnectionIdle)
clientReader := link.Reader // .(*pipe.Reader) clientReader := link.Reader // .(*pipe.Reader)
clientWriter := link.Writer // .(*pipe.Writer) clientWriter := link.Writer // .(*pipe.Writer)
@@ -229,7 +211,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
// default: serverWriter := bufferWriter // default: serverWriter := bufferWriter
serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons) serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons)
if request.Command == protocol.RequestCommandMux && request.Port == 666 { if request.Command == protocol.RequestCommandMux && request.Port == 666 {
serverWriter = xudp.NewPacketWriter(serverWriter, target) serverWriter = xudp.NewPacketWriter(serverWriter, target, xudp.GetGlobalID(ctx))
} }
userUUID := account.ID.Bytes() userUUID := account.ID.Bytes()
timeoutReader, ok := clientReader.(buf.TimeoutReader) timeoutReader, ok := clientReader.(buf.TimeoutReader)
@@ -238,10 +220,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
if err1 == nil { if err1 == nil {
if requestAddons.Flow == vless.XRV { if requestAddons.Flow == vless.XRV {
encoding.XtlsFilterTls(multiBuffer, &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello, ctx) encoding.XtlsFilterTls(multiBuffer, &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello, ctx)
if isTLS { multiBuffer = encoding.ReshapeMultiBuffer(ctx, multiBuffer)
for i, b := range multiBuffer { for i, b := range multiBuffer {
multiBuffer[i] = encoding.XtlsPadding(b, 0x00, &userUUID, ctx) multiBuffer[i] = encoding.XtlsPadding(b, encoding.CommandPaddingContinue, &userUUID, isTLS, ctx)
}
} }
} }
if err := serverWriter.WriteMultiBuffer(multiBuffer); err != nil { if err := serverWriter.WriteMultiBuffer(multiBuffer); err != nil {
@@ -249,6 +230,13 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
} }
} else if err1 != buf.ErrReadTimeout { } else if err1 != buf.ErrReadTimeout {
return err1 return err1
} else if requestAddons.Flow == vless.XRV {
mb := make(buf.MultiBuffer, 1)
mb[0] = encoding.XtlsPadding(nil, encoding.CommandPaddingContinue, &userUUID, true, ctx) // we do a long padding to hide vless header
newError("Insert padding with empty content to camouflage VLESS header ", mb.Len()).WriteToLog(session.ExportIDToError(ctx))
if err := serverWriter.WriteMultiBuffer(mb); err != nil {
return err
}
} }
} else { } else {
newError("Reader is not timeout reader, will send out vless header separately from first payload").AtDebug().WriteToLog(session.ExportIDToError(ctx)) newError("Reader is not timeout reader, will send out vless header separately from first payload").AtDebug().WriteToLog(session.ExportIDToError(ctx))
@@ -273,7 +261,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
if statConn != nil { if statConn != nil {
counter = statConn.WriteCounter counter = statConn.WriteCounter
} }
err = encoding.XtlsWrite(clientReader, serverWriter, timer, netConn, counter, ctx, &userUUID, &numberOfPacketToFilter, err = encoding.XtlsWrite(clientReader, serverWriter, timer, netConn, counter, ctx, &numberOfPacketToFilter,
&enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello) &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello)
} else { } else {
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer // from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
@@ -309,15 +297,8 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
if statConn != nil { if statConn != nil {
counter = statConn.ReadCounter counter = statConn.ReadCounter
} }
if requestAddons.Flow == vless.XRV { err = encoding.XtlsRead(serverReader, clientWriter, timer, netConn, rawConn, input, rawInput, counter, ctx, account.ID.Bytes(),
err = encoding.XtlsRead(serverReader, clientWriter, timer, netConn, rawConn, input, rawInput, counter, ctx, account.ID.Bytes(), &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello)
&numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello)
} else {
if requestAddons.Flow != vless.XRS {
ctx = session.ContextWithInbound(ctx, nil)
}
err = encoding.ReadV(serverReader, clientWriter, timer, iConn.(*xtls.Conn), rawConn, counter, ctx)
}
} else { } else {
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer // from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer)) err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
@@ -330,6 +311,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return nil return nil
} }
if newCtx != nil {
ctx = newCtx
}
if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil { if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil {
return newError("connection ends").Base(err).AtInfo() return newError("connection ends").Base(err).AtInfo()
} }

View File

@@ -8,8 +8,5 @@ package vless
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
const ( const (
XRO = "xtls-rprx-origin"
XRD = "xtls-rprx-direct"
XRS = "xtls-rprx-splice"
XRV = "xtls-rprx-vision" XRV = "xtls-rprx-vision"
) )

View File

@@ -287,6 +287,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
if inbound == nil { if inbound == nil {
panic("no inbound metadata") panic("no inbound metadata")
} }
inbound.Name = "vmess"
inbound.User = request.User inbound.User = request.User
sessionPolicy = h.policyManager.ForLevel(request.User.Level) sessionPolicy = h.policyManager.ForLevel(request.User.Level)

View File

@@ -138,11 +138,22 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
behaviorSeed := crc64.Checksum(hashkdf.Sum(nil), crc64.MakeTable(crc64.ISO)) behaviorSeed := crc64.Checksum(hashkdf.Sum(nil), crc64.MakeTable(crc64.ISO))
var newCtx context.Context
var newCancel context.CancelFunc
if session.TimeoutOnlyFromContext(ctx) {
newCtx, newCancel = context.WithCancel(context.Background())
}
session := encoding.NewClientSession(ctx, isAEAD, protocol.DefaultIDHash, int64(behaviorSeed)) session := encoding.NewClientSession(ctx, isAEAD, protocol.DefaultIDHash, int64(behaviorSeed))
sessionPolicy := h.policyManager.ForLevel(request.User.Level) sessionPolicy := h.policyManager.ForLevel(request.User.Level)
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle) timer := signal.CancelAfterInactivity(ctx, func() {
cancel()
if newCancel != nil {
newCancel()
}
}, sessionPolicy.Timeouts.ConnectionIdle)
if request.Command == protocol.RequestCommandUDP && h.cone && request.Port != 53 && request.Port != 443 { if request.Command == protocol.RequestCommandUDP && h.cone && request.Port != 53 && request.Port != 443 {
request.Command = protocol.RequestCommandMux request.Command = protocol.RequestCommandMux
@@ -164,7 +175,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
} }
bodyWriter2 := bodyWriter bodyWriter2 := bodyWriter
if request.Command == protocol.RequestCommandMux && request.Port == 666 { if request.Command == protocol.RequestCommandMux && request.Port == 666 {
bodyWriter = xudp.NewPacketWriter(bodyWriter, target) bodyWriter = xudp.NewPacketWriter(bodyWriter, target, xudp.GetGlobalID(ctx))
} }
if err := buf.CopyOnceTimeout(input, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout { if err := buf.CopyOnceTimeout(input, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
return newError("failed to write first payload").Base(err) return newError("failed to write first payload").Base(err)
@@ -208,6 +219,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return buf.Copy(bodyReader, output, buf.UpdateActivity(timer)) return buf.Copy(bodyReader, output, buf.UpdateActivity(timer))
} }
if newCtx != nil {
ctx = newCtx
}
responseDonePost := task.OnSuccess(responseDone, task.Close(output)) responseDonePost := task.OnSuccess(responseDone, task.Close(output))
if err := task.Run(ctx, requestDone, responseDonePost); err != nil { if err := task.Run(ctx, requestDone, responseDonePost); err != nil {
return newError("connection ends").Base(err) return newError("connection ends").Base(err)

View File

@@ -31,6 +31,7 @@ type netBindClient struct {
dialer internet.Dialer dialer internet.Dialer
dns dns.Client dns dns.Client
dnsOption dns.IPOption dnsOption dns.IPOption
reserved []byte
readQueue chan *netReadInfo readQueue chan *netReadInfo
} }
@@ -128,6 +129,13 @@ func (bind *netBindClient) connectTo(endpoint *netEndpoint) error {
return return
} }
i, err := c.Read(v.buff) i, err := c.Read(v.buff)
if i > 3 {
v.buff[1] = 0
v.buff[2] = 0
v.buff[3] = 0
}
v.bytes = i v.bytes = i
v.endpoint = endpoint v.endpoint = endpoint
v.err = err v.err = err
@@ -157,6 +165,10 @@ func (bind *netBindClient) Send(buff []byte, endpoint conn.Endpoint) error {
} }
} }
if len(buff) > 3 && len(bind.reserved) == 3 {
copy(buff[1:], bind.reserved)
}
_, err = nend.conn.Write(buff) _, err = nend.conn.Write(buff)
return err return err

View File

@@ -109,6 +109,7 @@ type DeviceConfig struct {
Peers []*PeerConfig `protobuf:"bytes,3,rep,name=peers,proto3" json:"peers,omitempty"` Peers []*PeerConfig `protobuf:"bytes,3,rep,name=peers,proto3" json:"peers,omitempty"`
Mtu int32 `protobuf:"varint,4,opt,name=mtu,proto3" json:"mtu,omitempty"` Mtu int32 `protobuf:"varint,4,opt,name=mtu,proto3" json:"mtu,omitempty"`
NumWorkers int32 `protobuf:"varint,5,opt,name=num_workers,json=numWorkers,proto3" json:"num_workers,omitempty"` NumWorkers int32 `protobuf:"varint,5,opt,name=num_workers,json=numWorkers,proto3" json:"num_workers,omitempty"`
Reserved []byte `protobuf:"bytes,6,opt,name=reserved,proto3" json:"reserved,omitempty"`
} }
func (x *DeviceConfig) Reset() { func (x *DeviceConfig) Reset() {
@@ -178,6 +179,13 @@ func (x *DeviceConfig) GetNumWorkers() int32 {
return 0 return 0
} }
func (x *DeviceConfig) GetReserved() []byte {
if x != nil {
return x.Reserved
}
return nil
}
var File_proxy_wireguard_config_proto protoreflect.FileDescriptor var File_proxy_wireguard_config_proto protoreflect.FileDescriptor
var file_proxy_wireguard_config_proto_rawDesc = []byte{ var file_proxy_wireguard_config_proto_rawDesc = []byte{
@@ -195,7 +203,7 @@ var file_proxy_wireguard_config_proto_rawDesc = []byte{
0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x41, 0x6c, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x41, 0x6c,
0x69, 0x76, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x69, 0x69, 0x76, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x69,
0x70, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x70, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65,
0x64, 0x49, 0x70, 0x73, 0x22, 0xb4, 0x01, 0x0a, 0x0c, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x64, 0x49, 0x70, 0x73, 0x22, 0xd0, 0x01, 0x0a, 0x0c, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x63, 0x72, 0x65, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x63, 0x72, 0x65,
0x74, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
@@ -206,14 +214,15 @@ var file_proxy_wireguard_config_proto_rawDesc = []byte{
0x67, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x74, 0x75, 0x18, 0x67, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x74, 0x75, 0x18,
0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6d, 0x74, 0x75, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x75, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6d, 0x74, 0x75, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x75,
0x6d, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x6d, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52,
0x0a, 0x6e, 0x75, 0x6d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x42, 0x5e, 0x0a, 0x18, 0x63, 0x0a, 0x6e, 0x75, 0x6d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72,
0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x77, 0x69, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72,
0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x42, 0x5e, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x77, 0x69, 0x72, 0x65, 0x67, 0x75,
0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x77, 0x69, 0x72, 0x65, 0x67, 0x61, 0x72, 0x64, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
0x75, 0x61, 0x72, 0x64, 0xaa, 0x02, 0x14, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65,
0x79, 0x2e, 0x57, 0x69, 0x72, 0x65, 0x47, 0x75, 0x61, 0x72, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x77, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64,
0x74, 0x6f, 0x33, 0xaa, 0x02, 0x14, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x57, 0x69,
0x72, 0x65, 0x47, 0x75, 0x61, 0x72, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -20,4 +20,5 @@ message DeviceConfig {
repeated PeerConfig peers = 3; repeated PeerConfig peers = 3;
int32 mtu = 4; int32 mtu = 4;
int32 num_workers = 5; int32 num_workers = 5;
bytes reserved = 6;
} }

View File

@@ -82,9 +82,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
}) })
// bind := conn.NewStdNetBind() // TODO: conn.Bind wrapper for dialer // bind := conn.NewStdNetBind() // TODO: conn.Bind wrapper for dialer
bind := &netBindClient{ bind := &netBindClient{
dialer: dialer, dialer: dialer,
workers: int(h.conf.NumWorkers), workers: int(h.conf.NumWorkers),
dns: h.dns, dns: h.dns,
reserved: h.conf.Reserved,
} }
net, err := h.makeVirtualTun(bind) net, err := h.makeVirtualTun(bind)
@@ -126,10 +127,21 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
addr = net.IPAddress(ips[0]) addr = net.IPAddress(ips[0])
} }
var newCtx context.Context
var newCancel context.CancelFunc
if session.TimeoutOnlyFromContext(ctx) {
newCtx, newCancel = context.WithCancel(context.Background())
}
p := h.policyManager.ForLevel(0) p := h.policyManager.ForLevel(0)
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, p.Timeouts.ConnectionIdle) timer := signal.CancelAfterInactivity(ctx, func() {
cancel()
if newCancel != nil {
newCancel()
}
}, p.Timeouts.ConnectionIdle)
addrPort := netip.AddrPortFrom(toNetIpAddr(addr), destination.Port.Value()) addrPort := netip.AddrPortFrom(toNetIpAddr(addr), destination.Port.Value())
var requestFunc func() error var requestFunc func() error
@@ -165,6 +177,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
} }
} }
if newCtx != nil {
ctx = newCtx
}
responseDonePost := task.OnSuccess(responseFunc, task.Close(link.Writer)) responseDonePost := task.OnSuccess(responseFunc, task.Close(link.Writer))
if err := task.Run(ctx, requestFunc, responseDonePost); err != nil { if err := task.Run(ctx, requestFunc, responseDonePost); err != nil {
return newError("connection ends").Base(err) return newError("connection ends").Base(err)

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.28.1 // protoc-gen-go v1.28.1
// protoc v3.21.12 // protoc v4.22.0
// source: transport/internet/config.proto // source: transport/internet/config.proto
package internet package internet
@@ -426,6 +426,9 @@ type SocketConfig struct {
TcpKeepAliveIdle int32 `protobuf:"varint,11,opt,name=tcp_keep_alive_idle,json=tcpKeepAliveIdle,proto3" json:"tcp_keep_alive_idle,omitempty"` TcpKeepAliveIdle int32 `protobuf:"varint,11,opt,name=tcp_keep_alive_idle,json=tcpKeepAliveIdle,proto3" json:"tcp_keep_alive_idle,omitempty"`
TcpCongestion string `protobuf:"bytes,12,opt,name=tcp_congestion,json=tcpCongestion,proto3" json:"tcp_congestion,omitempty"` TcpCongestion string `protobuf:"bytes,12,opt,name=tcp_congestion,json=tcpCongestion,proto3" json:"tcp_congestion,omitempty"`
Interface string `protobuf:"bytes,13,opt,name=interface,proto3" json:"interface,omitempty"` Interface string `protobuf:"bytes,13,opt,name=interface,proto3" json:"interface,omitempty"`
V6Only bool `protobuf:"varint,14,opt,name=v6only,proto3" json:"v6only,omitempty"`
TcpWindowClamp int32 `protobuf:"varint,15,opt,name=tcp_window_clamp,json=tcpWindowClamp,proto3" json:"tcp_window_clamp,omitempty"`
TcpUserTimeout int32 `protobuf:"varint,16,opt,name=tcp_user_timeout,json=tcpUserTimeout,proto3" json:"tcp_user_timeout,omitempty"`
} }
func (x *SocketConfig) Reset() { func (x *SocketConfig) Reset() {
@@ -551,6 +554,27 @@ func (x *SocketConfig) GetInterface() string {
return "" return ""
} }
func (x *SocketConfig) GetV6Only() bool {
if x != nil {
return x.V6Only
}
return false
}
func (x *SocketConfig) GetTcpWindowClamp() int32 {
if x != nil {
return x.TcpWindowClamp
}
return 0
}
func (x *SocketConfig) GetTcpUserTimeout() int32 {
if x != nil {
return x.TcpUserTimeout
}
return 0
}
var File_transport_internet_config_proto protoreflect.FileDescriptor var File_transport_internet_config_proto protoreflect.FileDescriptor
var file_transport_internet_config_proto_rawDesc = []byte{ var file_transport_internet_config_proto_rawDesc = []byte{
@@ -603,7 +627,7 @@ var file_transport_internet_config_proto_rawDesc = []byte{
0x12, 0x30, 0x0a, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x61, 0x79, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x61, 0x79,
0x65, 0x72, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x74,
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x50, 0x72, 0x6f,
0x78, 0x79, 0x22, 0x86, 0x05, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x78, 0x79, 0x22, 0xf2, 0x05, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,
0x05, 0x52, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x66, 0x6f, 0x18, 0x02, 0x05, 0x52, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x66, 0x6f, 0x18, 0x02,
0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x74, 0x66, 0x6f, 0x12, 0x48, 0x0a, 0x06, 0x74, 0x70, 0x72, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x74, 0x66, 0x6f, 0x12, 0x48, 0x0a, 0x06, 0x74, 0x70, 0x72,
@@ -640,27 +664,34 @@ var file_transport_internet_config_proto_rawDesc = []byte{
0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74,
0x63, 0x70, 0x43, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x70, 0x43, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52,
0x09, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x22, 0x2f, 0x0a, 0x0a, 0x54, 0x50, 0x09, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x36,
0x72, 0x6f, 0x78, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x66, 0x66, 0x10, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x76, 0x36, 0x6f, 0x6e,
0x00, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x6c, 0x79, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x63, 0x70, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77,
0x08, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10, 0x02, 0x2a, 0x5a, 0x0a, 0x11, 0x54, 0x5f, 0x63, 0x6c, 0x61, 0x6d, 0x70, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x74, 0x63,
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x70, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x43, 0x6c, 0x61, 0x6d, 0x70, 0x12, 0x28, 0x0a, 0x10,
0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x74, 0x63, 0x70, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x4b, 0x43, 0x50, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x74, 0x63, 0x70, 0x55, 0x73, 0x65, 0x72, 0x54,
0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x2f, 0x0a, 0x0a, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79,
0x54, 0x54, 0x50, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x66, 0x66, 0x10, 0x00, 0x12, 0x0a, 0x0a,
0x6f, 0x63, 0x6b, 0x65, 0x74, 0x10, 0x05, 0x2a, 0x41, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x06, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x64,
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10, 0x02, 0x2a, 0x5a, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73,
0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x07, 0x0a, 0x03,
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x54, 0x43, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x01, 0x12, 0x08,
0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f, 0x0a, 0x04, 0x4d, 0x4b, 0x43, 0x50, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x57, 0x65, 0x62, 0x53,
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10,
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x6f, 0x63, 0x6b, 0x65,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x74, 0x10, 0x05, 0x2a, 0x41, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72,
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x49, 0x53, 0x10, 0x00,
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07,
0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45,
0x6e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,
0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f,
0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74,
0x65, 0x72, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -100,4 +100,10 @@ message SocketConfig {
string tcp_congestion = 12; string tcp_congestion = 12;
string interface = 13; string interface = 13;
bool v6only = 14;
int32 tcp_window_clamp = 15;
int32 tcp_user_timeout = 16;
} }

View File

@@ -9,9 +9,9 @@ import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/xtls"
) )
func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (stat.Connection, error) { func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (stat.Connection, error) {
@@ -28,8 +28,8 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil { if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
return tls.Client(conn, config.GetTLSConfig(tls.WithDestination(dest))), nil return tls.Client(conn, config.GetTLSConfig(tls.WithDestination(dest))), nil
} else if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil { } else if config := reality.ConfigFromStreamSettings(streamSettings); config != nil {
return xtls.Client(conn, config.GetXTLSConfig(xtls.WithDestination(dest))), nil return reality.UClient(conn, config, ctx, dest)
} }
return conn, nil return conn, nil

View File

@@ -9,24 +9,24 @@ import (
"os" "os"
"strings" "strings"
goxtls "github.com/xtls/go" goreality "github.com/xtls/reality"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/xtls"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
type Listener struct { type Listener struct {
addr *net.UnixAddr addr *net.UnixAddr
ln net.Listener ln net.Listener
tlsConfig *gotls.Config tlsConfig *gotls.Config
xtlsConfig *goxtls.Config realityConfig *goreality.Config
config *Config config *Config
addConn internet.ConnHandler addConn internet.ConnHandler
locker *fileLocker locker *fileLocker
} }
func Listen(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) { func Listen(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) {
@@ -61,8 +61,8 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil { if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
ln.tlsConfig = config.GetTLSConfig() ln.tlsConfig = config.GetTLSConfig()
} }
if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil { if config := reality.ConfigFromStreamSettings(streamSettings); config != nil {
ln.xtlsConfig = config.GetXTLSConfig() ln.realityConfig = config.GetREALITYConfig()
} }
go ln.run() go ln.run()
@@ -91,14 +91,17 @@ func (ln *Listener) run() {
newError("failed to accepted raw connections").Base(err).AtWarning().WriteToLog() newError("failed to accepted raw connections").Base(err).AtWarning().WriteToLog()
continue continue
} }
go func() {
if ln.tlsConfig != nil { if ln.tlsConfig != nil {
conn = tls.Server(conn, ln.tlsConfig) conn = tls.Server(conn, ln.tlsConfig)
} else if ln.xtlsConfig != nil { } else if ln.realityConfig != nil {
conn = xtls.Server(conn, ln.xtlsConfig) if conn, err = reality.Server(conn, ln.realityConfig); err != nil {
} newError(err).AtInfo().WriteToLog()
return
ln.addConn(stat.Connection(conn)) }
}
ln.addConn(stat.Connection(conn))
}()
} }
} }

View File

@@ -2,6 +2,7 @@ package grpc
import ( import (
"net/url" "net/url"
"strings"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
@@ -15,6 +16,41 @@ func init() {
})) }))
} }
func (c *Config) getNormalizedName() string { func (c *Config) getServiceName() string {
return url.PathEscape(c.ServiceName) // Normal old school config
if !strings.HasPrefix(c.ServiceName, "/") {
return url.PathEscape(c.ServiceName)
}
// Otherwise new custom paths
rawServiceName := c.ServiceName[1:strings.LastIndex(c.ServiceName, "/")] // trim from first to last '/'
serviceNameParts := strings.Split(rawServiceName, "/")
for i := range serviceNameParts {
serviceNameParts[i] = url.PathEscape(serviceNameParts[i])
}
return strings.Join(serviceNameParts, "/")
}
func (c *Config) getTunStreamName() string {
// Normal old school config
if !strings.HasPrefix(c.ServiceName, "/") {
return "Tun"
}
// Otherwise new custom paths
endingPath := c.ServiceName[strings.LastIndex(c.ServiceName, "/")+1:] // from the last '/' to end of string
return url.PathEscape(strings.Split(endingPath, "|")[0])
}
func (c *Config) getTunMultiStreamName() string {
// Normal old school config
if !strings.HasPrefix(c.ServiceName, "/") {
return "TunMulti"
}
// Otherwise new custom paths
endingPath := c.ServiceName[strings.LastIndex(c.ServiceName, "/")+1:] // from the last '/' to end of string
streamNames := strings.Split(endingPath, "|")
if len(streamNames) == 1 { // client side. Service name is the full path to multi tun
return url.PathEscape(streamNames[0])
} else { // server side. The second part is the path to multi tun
return url.PathEscape(streamNames[1])
}
} }

View File

@@ -32,6 +32,7 @@ type Config struct {
HealthCheckTimeout int32 `protobuf:"varint,5,opt,name=health_check_timeout,json=healthCheckTimeout,proto3" json:"health_check_timeout,omitempty"` HealthCheckTimeout int32 `protobuf:"varint,5,opt,name=health_check_timeout,json=healthCheckTimeout,proto3" json:"health_check_timeout,omitempty"`
PermitWithoutStream bool `protobuf:"varint,6,opt,name=permit_without_stream,json=permitWithoutStream,proto3" json:"permit_without_stream,omitempty"` PermitWithoutStream bool `protobuf:"varint,6,opt,name=permit_without_stream,json=permitWithoutStream,proto3" json:"permit_without_stream,omitempty"`
InitialWindowsSize int32 `protobuf:"varint,7,opt,name=initial_windows_size,json=initialWindowsSize,proto3" json:"initial_windows_size,omitempty"` InitialWindowsSize int32 `protobuf:"varint,7,opt,name=initial_windows_size,json=initialWindowsSize,proto3" json:"initial_windows_size,omitempty"`
UserAgent string `protobuf:"bytes,8,opt,name=user_agent,json=userAgent,proto3" json:"user_agent,omitempty"`
} }
func (x *Config) Reset() { func (x *Config) Reset() {
@@ -115,6 +116,13 @@ func (x *Config) GetInitialWindowsSize() int32 {
return 0 return 0
} }
func (x *Config) GetUserAgent() string {
if x != nil {
return x.UserAgent
}
return ""
}
var File_transport_internet_grpc_config_proto protoreflect.FileDescriptor var File_transport_internet_grpc_config_proto protoreflect.FileDescriptor
var file_transport_internet_grpc_config_proto_rawDesc = []byte{ var file_transport_internet_grpc_config_proto_rawDesc = []byte{
@@ -122,7 +130,7 @@ var file_transport_internet_grpc_config_proto_rawDesc = []byte{
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x25, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x25, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
0x67, 0x72, 0x70, 0x63, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x99, 0x02, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0xb8, 0x02,
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
@@ -140,11 +148,13 @@ var file_transport_internet_grpc_config_proto_rawDesc = []byte{
0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x30, 0x0a, 0x14, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x30, 0x0a, 0x14, 0x69, 0x6e, 0x69, 0x74, 0x69,
0x61, 0x6c, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x61, 0x6c, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18,
0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x57, 0x69, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x57, 0x69,
0x6e, 0x64, 0x6f, 0x77, 0x73, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x72, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75,
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68,
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -11,4 +11,5 @@ message Config {
int32 health_check_timeout = 5; int32 health_check_timeout = 5;
bool permit_without_stream = 6; bool permit_without_stream = 6;
int32 initial_windows_size = 7; int32 initial_windows_size = 7;
string user_agent = 8;
} }

View File

@@ -0,0 +1,111 @@
package grpc
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestConfig_GetServiceName(t *testing.T) {
tests := []struct {
TestName string
ServiceName string
Expected string
}{
{
TestName: "simple no absolute path",
ServiceName: "hello",
Expected: "hello",
},
{
TestName: "escape no absolute path",
ServiceName: "hello/world!",
Expected: "hello%2Fworld%21",
},
{
TestName: "absolute path",
ServiceName: "/my/sample/path/a|b",
Expected: "my/sample/path",
},
{
TestName: "escape absolute path",
ServiceName: "/hello /world!/a|b",
Expected: "hello%20/world%21",
},
}
for _, test := range tests {
t.Run(test.TestName, func(t *testing.T) {
config := Config{ServiceName: test.ServiceName}
assert.Equal(t, test.Expected, config.getServiceName())
})
}
}
func TestConfig_GetTunStreamName(t *testing.T) {
tests := []struct {
TestName string
ServiceName string
Expected string
}{
{
TestName: "no absolute path",
ServiceName: "hello",
Expected: "Tun",
},
{
TestName: "absolute path server",
ServiceName: "/my/sample/path/tun_service|multi_service",
Expected: "tun_service",
},
{
TestName: "absolute path client",
ServiceName: "/my/sample/path/tun_service",
Expected: "tun_service",
},
{
TestName: "escape absolute path client",
ServiceName: "/m y/sa !mple/pa\\th/tun\\_serv!ice",
Expected: "tun%5C_serv%21ice",
},
}
for _, test := range tests {
t.Run(test.TestName, func(t *testing.T) {
config := Config{ServiceName: test.ServiceName}
assert.Equal(t, test.Expected, config.getTunStreamName())
})
}
}
func TestConfig_GetTunMultiStreamName(t *testing.T) {
tests := []struct {
TestName string
ServiceName string
Expected string
}{
{
TestName: "no absolute path",
ServiceName: "hello",
Expected: "TunMulti",
},
{
TestName: "absolute path server",
ServiceName: "/my/sample/path/tun_service|multi_service",
Expected: "multi_service",
},
{
TestName: "absolute path client",
ServiceName: "/my/sample/path/multi_service",
Expected: "multi_service",
},
{
TestName: "escape absolute path client",
ServiceName: "/m y/sa !mple/pa\\th/mu%lti\\_serv!ice",
Expected: "mu%25lti%5C_serv%21ice",
},
}
for _, test := range tests {
t.Run(test.TestName, func(t *testing.T) {
config := Config{ServiceName: test.ServiceName}
assert.Equal(t, test.Expected, config.getTunMultiStreamName())
})
}
}

Some files were not shown because too many files have changed in this diff Show More