mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-12-18 21:24:37 +03:00
Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
603264017a | ||
|
|
18e5b0963f | ||
|
|
90d915ea05 | ||
|
|
d9994538bc | ||
|
|
69aa3f48cc | ||
|
|
ca32496a38 | ||
|
|
d3060c28f8 | ||
|
|
ac8109eef8 | ||
|
|
197bc78ea1 | ||
|
|
039e5f2078 | ||
|
|
242f3b0e0b | ||
|
|
b4c1a56026 | ||
|
|
9f8e9e8e64 | ||
|
|
06c9e50c52 | ||
|
|
4f601530fa | ||
|
|
b33b0bc89d | ||
|
|
01b7e5e9be | ||
|
|
24a2be43ef | ||
|
|
29d7865d78 | ||
|
|
05d24d6827 | ||
|
|
76b27a37cb | ||
|
|
15cf31f30a | ||
|
|
54ad0e96a0 | ||
|
|
be23d5d3b7 | ||
|
|
67affe3753 | ||
|
|
2c0a89f7dc | ||
|
|
a4d1509c23 | ||
|
|
f4ab8d7e8b | ||
|
|
beb603af06 | ||
|
|
a0d06f3a97 | ||
|
|
526c6789ed | ||
|
|
6872be5cc3 | ||
|
|
c6b78318cb | ||
|
|
f89998fc77 | ||
|
|
0573760346 | ||
|
|
172f353bd7 | ||
|
|
55efac7236 | ||
|
|
f57ec13880 | ||
|
|
f1e35ad9d4 | ||
|
|
d6801ab031 | ||
|
|
c3322294be | ||
|
|
836e84b851 | ||
|
|
4a0b45d1ff | ||
|
|
c04c333afc | ||
|
|
9e5bc07bf2 | ||
|
|
4c8ee0af50 | ||
|
|
25ea69fc3a | ||
|
|
a4790133d2 | ||
|
|
ccba465590 | ||
|
|
6526e74d49 | ||
|
|
7b54255cc1 | ||
|
|
43bc929030 | ||
|
|
fbc7c1cf84 | ||
|
|
cc4be239cf | ||
|
|
2d898480be | ||
|
|
55dc26f228 | ||
|
|
9401d65ef1 | ||
|
|
c38179a67f | ||
|
|
a5b297f968 | ||
|
|
d208fd31c9 | ||
|
|
2e201c57cc | ||
|
|
336b2daeb9 | ||
|
|
c8b4580869 | ||
|
|
03b8c094de | ||
|
|
267d93f7bd | ||
|
|
7f16f4ccd9 | ||
|
|
9e07d8304d | ||
|
|
9d3de59d3f | ||
|
|
4d5c3195d2 | ||
|
|
c7358a32f5 | ||
|
|
e1cd1fd33e | ||
|
|
82003f28b2 | ||
|
|
4d2e2b24d3 | ||
|
|
15999e5c2a | ||
|
|
48ff0d92c9 | ||
|
|
229e2513b5 | ||
|
|
9046eda5ce | ||
|
|
f32921df30 | ||
|
|
c3faa8b7ac | ||
|
|
00c9576118 | ||
|
|
fa7300e910 | ||
|
|
b57d3fa869 | ||
|
|
53833c2323 |
21
.github/docker/Dockerfile
vendored
Normal file
21
.github/docker/Dockerfile
vendored
Normal 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
19
.github/docker/files/config.json
vendored
Normal 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
45
.github/workflows/docker.yml
vendored
Normal 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 }}
|
||||||
81
.github/workflows/release.yml
vendored
81
.github/workflows/release.yml
vendored
@@ -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
|
||||||
|
|||||||
23
.github/workflows/test.yml
vendored
23
.github/workflows/test.yml
vendored
@@ -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 ./...
|
||||||
|
|||||||
99
README.md
99
README.md
@@ -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
|
||||||
|
|
||||||
[](https://starchart.cc/XTLS/Xray-core)
|
[](https://starchart.cc/XTLS/Xray-core)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
347
app/tun/config.pb.go
Normal 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
32
app/tun/config.proto
Normal 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;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package xtls
|
package tun
|
||||||
|
|
||||||
import "github.com/xtls/xray-core/common/errors"
|
import "github.com/xtls/xray-core/common/errors"
|
||||||
|
|
||||||
50
app/tun/interface_finder.go
Normal file
50
app/tun/interface_finder.go
Normal 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
42
app/tun/packet_conn.go
Normal 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
296
app/tun/tun.go
Normal 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
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|||||||
@@ -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")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
46
common/singbridge/destination.go
Normal file
46
common/singbridge/destination.go
Normal 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
|
||||||
|
}
|
||||||
59
common/singbridge/dialer.go
Normal file
59
common/singbridge/dialer.go
Normal 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
|
||||||
|
}
|
||||||
10
common/singbridge/error.go
Normal file
10
common/singbridge/error.go
Normal 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
|
||||||
|
}
|
||||||
51
common/singbridge/handler.go
Normal file
51
common/singbridge/handler.go
Normal 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))
|
||||||
|
}
|
||||||
71
common/singbridge/logger.go
Normal file
71
common/singbridge/logger.go
Normal 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) {
|
||||||
|
}
|
||||||
82
common/singbridge/packet.go
Normal file
82
common/singbridge/packet.go
Normal 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
61
common/singbridge/pipe.go
Normal 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
|
||||||
|
}
|
||||||
66
common/singbridge/reader.go
Normal file
66
common/singbridge/reader.go
Normal 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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
36
common/xudp/xudp_test.go
Normal 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
10
core/core.go
10
core/core.go
@@ -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
11
features/tun/tun.go
Normal 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
65
go.mod
@@ -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
140
go.sum
@@ -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=
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
113
infra/conf/tun.go
Normal 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)
|
||||||
|
}
|
||||||
@@ -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`)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -15,5 +15,6 @@ func init() {
|
|||||||
// cmdConvert,
|
// cmdConvert,
|
||||||
tls.CmdTLS,
|
tls.CmdTLS,
|
||||||
cmdUUID,
|
cmdUUID,
|
||||||
|
cmdX25519,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
71
main/commands/all/x25519.go
Normal file
71
main/commands/all/x25519.go
Normal 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)
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"`
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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, ¤tCommand)
|
buffer = XtlsUnpadding(ctx, buffer, userUUID, &remainingContent, &remainingPadding, ¤tCommand)
|
||||||
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",
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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))
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
111
transport/internet/grpc/config_test.go
Normal file
111
transport/internet/grpc/config_test.go
Normal 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
Reference in New Issue
Block a user