Compare commits

...

62 Commits

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* Fix Vision client to support multiple possible padding blocks

* Vision padding upgrade

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

* Adjust receiver withinPaddingBuffers

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

* Fix magic numbers for Vision
Thanks @H1JK

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

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

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

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

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

* fixed domain name encoding for dns header

---------

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

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

* Improve again

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

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-21 22:36:48 -05:00
yuhan6665
9e07d8304d Add retry for test steps to download geofiles 2023-02-21 22:36:36 -05:00
RPRX
9d3de59d3f Check "serverNames" and "shortIds" (client side)
Prevents https://github.com/XTLS/Xray-core/issues/1675
2023-02-21 13:43:13 +00:00
110 changed files with 2076 additions and 2385 deletions

View File

@@ -20,7 +20,51 @@ on:
- "go.sum" - "go.sum"
- ".github/workflows/*.yml" - ".github/workflows/*.yml"
jobs: jobs:
prepare:
runs-on: ubuntu-latest
steps:
- name: Restore Cache
uses: actions/cache/restore@v3
with:
path: resources
key: xray-geodat-
- name: Update Geodat
id: update
uses: nick-fields/retry@v2
with:
timeout_minutes: 60
retry_wait_seconds: 60
max_attempts: 60
command: |
[ -d 'resources' ] || mkdir resources
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite')
for i in "${LIST[@]}"
do
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3}'))
FILE_NAME="${INFO[2]}.dat"
echo -e "Verifying HASH key..."
HASH="$(curl -sL "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
if [ -s "./resources/${FILE_NAME}" ] && [ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ]; then
continue
else
echo -e "Downloading https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat..."
curl -L "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat" -o ./resources/${FILE_NAME}
echo -e "Verifying HASH key..."
[ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ] || { echo -e "The HASH key of ${FILE_NAME} does not match cloud one."; exit 1; }
echo "unhit=true" >> $GITHUB_OUTPUT
fi
done
- name: Save Cache
uses: actions/cache/save@v3
if: ${{ steps.update.outputs.unhit }}
with:
path: resources
key: xray-geodat-${{ github.sha }}-${{ github.run_number }}
build: build:
needs: prepare
permissions: permissions:
contents: write contents: write
strategy: strategy:
@@ -121,7 +165,7 @@ 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.20' go-version: '1.20'
check-latest: true check-latest: true
@@ -160,26 +204,17 @@ jobs:
cd ./build_assets || exit 1 cd ./build_assets || exit 1
mv xray xray.exe mv xray xray.exe
- name: Prepare to release - name: Restore Cache
uses: nick-fields/retry@v2 uses: actions/cache/restore@v3
with: with:
timeout_minutes: 60 path: resources
retry_wait_seconds: 60 key: xray-geodat-
max_attempts: 60
command: | - name: Copy README.md & LICENSE
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md run: |
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE mv -f resources/* build_assets
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite') cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
for i in "${LIST[@]}" cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
do
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3}'))
FILE_NAME="${INFO[2]}.dat"
echo -e "Downloading https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat..."
curl -L "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat" -o ./build_assets/${FILE_NAME}
echo -e "Verifying HASH key..."
HASH="$(curl -sL "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
[ "$(sha256sum "./build_assets/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ] || { echo -e "The HASH key of ${FILE_NAME} does not match cloud one."; exit 1; }
done
- name: Create ZIP archive - name: Create ZIP archive
shell: bash shell: bash

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

@@ -20,8 +20,8 @@ import (
var ( var (
Version_x byte = 1 Version_x byte = 1
Version_y byte = 7 Version_y byte = 8
Version_z byte = 5 Version_z byte = 1
) )
var ( var (

61
go.mod
View File

@@ -5,57 +5,56 @@ 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/quic-go v0.32.0 github.com/quic-go/quic-go v0.33.0
github.com/refraction-networking/utls v1.2.2 github.com/refraction-networking/utls v1.3.2
github.com/sagernet/sing v0.1.6 github.com/sagernet/sing v0.2.3
github.com/sagernet/sing-shadowsocks v0.1.1-0.20230202035033-e3123545f2f7 github.com/sagernet/sing-shadowsocks v0.2.1
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
github.com/xtls/reality v0.0.0-20230217102704-085bdf2104d3 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254
go.starlark.net v0.0.0-20230128213706-3f75dec8e403 golang.org/x/crypto v0.8.0
golang.org/x/crypto v0.6.0 golang.org/x/net v0.9.0
golang.org/x/net v0.7.0
golang.org/x/sync v0.1.0 golang.org/x/sync v0.1.0
golang.org/x/sys v0.5.0 golang.org/x/sys v0.7.0
google.golang.org/grpc v1.53.0 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/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-20230207041349-798e818bf904 // 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.1 // 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/quic-go/qtls-go1-20 v0.1.0 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
go.uber.org/atomic v1.10.0 // indirect go.uber.org/atomic v1.10.0 // indirect
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb // indirect golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
golang.org/x/mod v0.8.0 // indirect golang.org/x/mod v0.10.0 // indirect
golang.org/x/text v0.7.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.6.0 // indirect golang.org/x/tools v0.8.0 // indirect
google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc // 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
) )

126
go.sum
View File

@@ -8,8 +8,8 @@ dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
@@ -33,14 +33,16 @@ 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/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 +60,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 +78,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-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= github.com/google/pprof v0.0.0-20230406165453-00490a63f317 h1:hFhpt7CTmR3DX+b4R19ydQFtofxT0Sv3QsKNMVQYTMQ=
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= 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 +93,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 +108,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.1 h1:xFTEVwOFa1D/Ty24Ws1npBWkDYEV9BqZrsDxVrVkrrU= github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc= github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q= 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 +132,21 @@ 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.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA=
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.2 h1:uBE6V173CwG8MQrSBpNZHAix1fxOvuLKYyjFAu3uqo0=
github.com/refraction-networking/utls v1.2.2/go.mod h1:L1goe44KvhnTfctUffM2isnJpSjPlYShrhXDeZaoYKw=
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/sing v0.2.3 h1:V50MvZ4c3Iij2lYFWPlzL1PyipwSzjGeN9x+Ox89vpk=
github.com/sagernet/sing v0.1.6/go.mod h1:JLSXsPTGRJFo/3X7EcAOCUgJH2/gAoxSJgBsnCZRp/w= github.com/sagernet/sing v0.2.3/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
github.com/sagernet/sing-shadowsocks v0.1.1-0.20230202035033-e3123545f2f7 h1:Plup6oEiyLzY3HDqQ+QsUBzgBGdVmcsgf3t8h940z9U= github.com/sagernet/sing-shadowsocks v0.2.1 h1:FvdLQOqpvxHBJUcUe4fvgiYP2XLLwH5i1DtXQviVEPw=
github.com/sagernet/sing-shadowsocks v0.1.1-0.20230202035033-e3123545f2f7/go.mod h1:O5LtOs8Ivw686FqLpO0Zu+A0ROVE15VeqEK3yDRRAms= github.com/sagernet/sing-shadowsocks v0.2.1/go.mod h1:T/OgurSjsAe+Ug3+6PprXjmgHFmJidjOvQcjXGTKb3I=
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,25 +180,22 @@ 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/xtls/reality v0.0.0-20230331223127-176a94313eda h1:psRJD2RrZbnI0OWyHvXfgYCPqlRM5q5SPDcjDoDBWhE=
github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3/go.mod h1:YJTRELIWrGxR1s8xcEBgxcxBfwQfMGjdvNLTjN9XFgY= github.com/xtls/reality v0.0.0-20230331223127-176a94313eda/go.mod h1:rkuAY1S9F8eI8gDiPDYvACE8e2uwkyg8qoOTuwWov7Y=
github.com/xtls/reality v0.0.0-20230217102704-085bdf2104d3 h1:Rp9BfXZ+Li5j5L40zAdFZLcr0nXrYBPgaNpQ9lQnpWg=
github.com/xtls/reality v0.0.0-20230217102704-085bdf2104d3/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=
@@ -207,18 +204,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.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= 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-20230213192124-5e25df0256eb h1:PaBZQdo+iSDyHT053FjUCgZQ/9uqVwPOcl7KSWhKn6w= golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb/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.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.8.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=
@@ -231,9 +228,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.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
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=
@@ -255,22 +251,19 @@ golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7w
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-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.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.7.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=
@@ -284,9 +277,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.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
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=
@@ -305,16 +297,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-20230209215440-0dfe4f8abfcc h1:ijGwO+0vL2hJt5gaygqP2j6PfflOBrRot0IczKbmtio= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/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.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= 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=
@@ -325,8 +317,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=

View File

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

View File

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

View File

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

View File

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

View File

@@ -26,7 +26,6 @@ import (
"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 (
@@ -37,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{
@@ -343,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.
@@ -400,117 +401,17 @@ 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"`
Fingerprint string `json:"fingerprint"`
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
if c.Fingerprint != "" {
return nil, newError(`Old version of XTLS does not support fingerprint. Please use flow "xtls-rprx-vision" with "tls & tlsSettings" instead.`)
}
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)
} }
} }
newError(`You are using an old version of XTLS, which is deprecated now and will be removed soon. Please use flow "xtls-rprx-vision" with "tls & tlsSettings" instead.`).AtWarning().WriteToLog()
return config, nil return config, nil
} }
@@ -631,12 +532,18 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
if config.Fingerprint == "hellogolang" { if config.Fingerprint == "hellogolang" {
return nil, newError(`invalid "fingerprint": `, config.Fingerprint) 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 == "" { if c.PublicKey == "" {
return nil, newError(`empty "publicKey"`) return nil, newError(`empty "publicKey"`)
} }
if config.PublicKey, err = base64.RawURLEncoding.DecodeString(c.PublicKey); err != nil || len(config.PublicKey) != 32 { if config.PublicKey, err = base64.RawURLEncoding.DecodeString(c.PublicKey); err != nil || len(config.PublicKey) != 32 {
return nil, newError(`invalid "publicKey": `, c.PublicKey) 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) config.ShortId = make([]byte, 8)
if _, err = hex.Decode(config.ShortId, []byte(c.ShortId)); err != nil { if _, err = hex.Decode(config.ShortId, []byte(c.ShortId)); err != nil {
return nil, newError(`invalid "shortId": `, c.ShortId) return nil, newError(`invalid "shortId": `, c.ShortId)
@@ -709,6 +616,8 @@ 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"`
V6only bool `json:"v6only"`
Interface string `json:"interface"` Interface string `json:"interface"`
} }
@@ -759,6 +668,8 @@ 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,
V6Only: c.V6only,
Interface: c.Interface, Interface: c.Interface,
}, nil }, nil
} }
@@ -767,7 +678,6 @@ 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"` REALITYSettings *REALITYConfig `json:"realitySettings"`
TCPSettings *TCPConfig `json:"tcpSettings"` TCPSettings *TCPConfig `json:"tcpSettings"`
KCPSettings *KCPConfig `json:"kcpSettings"` KCPSettings *KCPConfig `json:"kcpSettings"`
@@ -792,12 +702,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()
@@ -807,29 +716,9 @@ 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 xtlsSettings == nil {
if c.TLSSettings != nil {
return nil, newError(`XTLS: Please use "xtlsSettings" instead of "tlsSettings".`)
}
xtlsSettings = &XTLSConfig{}
}
ts, err := xtlsSettings.Build()
if err != nil {
return nil, newError("Failed to build XTLS config.").Base(err)
}
tm := serial.ToTypedMessage(ts)
config.SecuritySettings = append(config.SecuritySettings, tm)
config.SecurityType = tm.Type
}
if strings.EqualFold(c.Security, "reality") {
if config.ProtocolName != "tcp" && config.ProtocolName != "http" && config.ProtocolName != "domainsocket" {
return nil, newError("REALITY only supports TCP, H2 and DomainSocket for now.")
} }
if c.REALITYSettings == nil { if c.REALITYSettings == nil {
return nil, newError(`REALITY: Empty "realitySettings".`) return nil, newError(`REALITY: Empty "realitySettings".`)
@@ -841,6 +730,10 @@ 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 "xtls":
return nil, newError(`Please use VLESS flow "xtls-rprx-vision" with TLS or REALITY.`)
default:
return nil, newError(`Unknown security "` + c.Security + `".`)
} }
if c.TCPSettings != nil { if c.TCPSettings != nil {
ts, err := c.TCPSettings.Build() ts, err := c.TCPSettings.Build()

View File

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

View File

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

View File

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

View File

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

View File

@@ -13,7 +13,6 @@ import (
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
core "github.com/xtls/xray-core/core" core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/xtls"
) )
var ( var (
@@ -108,25 +107,27 @@ func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {
} }
type MuxConfig struct { type MuxConfig struct {
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
Concurrency int16 `json:"concurrency"` Concurrency int16 `json:"concurrency"`
XudpConcurrency int16 `json:"xudpConcurrency"`
XudpProxyUDP443 string `json:"xudpProxyUDP443"`
} }
// Build creates MultiplexingConfig, Concurrency < 0 completely disables mux. // Build creates MultiplexingConfig, Concurrency < 0 completely disables mux.
func (m *MuxConfig) Build() *proxyman.MultiplexingConfig { func (m *MuxConfig) Build() (*proxyman.MultiplexingConfig, error) {
if m.Concurrency < 0 { switch m.XudpProxyUDP443 {
return nil case "":
m.XudpProxyUDP443 = "reject"
case "reject", "allow", "skip":
default:
return nil, newError(`unknown "xudpProxyUDP443": `, m.XudpProxyUDP443)
} }
var con uint32 = 8
if m.Concurrency > 0 {
con = uint32(m.Concurrency)
}
return &proxyman.MultiplexingConfig{ return &proxyman.MultiplexingConfig{
Enabled: m.Enabled, Enabled: m.Enabled,
Concurrency: con, Concurrency: int32(m.Concurrency),
} XudpConcurrency: int32(m.XudpConcurrency),
XudpProxyUDP443: m.XudpProxyUDP443,
}, nil
} }
type InboundDetourAllocationConfig struct { type InboundDetourAllocationConfig struct {
@@ -236,9 +237,6 @@ func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if ss.SecurityType == serial.GetMessageType(&xtls.Config{}) && !strings.EqualFold(c.Protocol, "vless") && !strings.EqualFold(c.Protocol, "trojan") {
return nil, newError("XTLS doesn't supports " + c.Protocol + " for now.")
}
receiverSettings.StreamSettings = ss receiverSettings.StreamSettings = ss
} }
if c.SniffingConfig != nil { if c.SniffingConfig != nil {
@@ -319,9 +317,6 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if ss.SecurityType == serial.GetMessageType(&xtls.Config{}) && !strings.EqualFold(c.Protocol, "vless") && !strings.EqualFold(c.Protocol, "trojan") {
return nil, newError("XTLS doesn't supports " + c.Protocol + " for now.")
}
senderSettings.StreamSettings = ss senderSettings.StreamSettings = ss
} }
@@ -346,13 +341,9 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
} }
if c.MuxSettings != nil { if c.MuxSettings != nil {
ms := c.MuxSettings.Build() ms, err := c.MuxSettings.Build()
if ms != nil && ms.Enabled { if err != nil {
if ss := senderSettings.StreamSettings; ss != nil { return nil, newError("failed to build Mux config.").Base(err)
if ss.SecurityType == serial.GetMessageType(&xtls.Config{}) {
return nil, newError("XTLS doesn't support Mux for now.")
}
}
} }
senderSettings.MultiplexSettings = ms senderSettings.MultiplexSettings = ms
} }

View File

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

View File

@@ -4,7 +4,6 @@ import (
"crypto/rand" "crypto/rand"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"io"
"github.com/xtls/xray-core/main/commands/base" "github.com/xtls/xray-core/main/commands/base"
"golang.org/x/crypto/curve25519" "golang.org/x/crypto/curve25519"
@@ -44,17 +43,26 @@ func executeX25519(cmd *base.Command, args []string) {
goto out goto out
} }
} }
if privateKey == nil { if privateKey == nil {
privateKey = make([]byte, curve25519.ScalarSize) privateKey = make([]byte, curve25519.ScalarSize)
if _, err = io.ReadFull(rand.Reader, privateKey); err != nil { if _, err = rand.Read(privateKey); err != nil {
output = err.Error() output = err.Error()
goto out 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 { if publicKey, err = curve25519.X25519(privateKey, curve25519.Basepoint); err != nil {
output = err.Error() output = err.Error()
goto out goto out
} }
output = fmt.Sprintf("Private key: %v\nPublic key: %v", output = fmt.Sprintf("Private key: %v\nPublic key: %v",
base64.RawURLEncoding.EncodeToString(privateKey), base64.RawURLEncoding.EncodeToString(privateKey),
base64.RawURLEncoding.EncodeToString(publicKey)) base64.RawURLEncoding.EncodeToString(publicKey))

View File

@@ -61,7 +61,6 @@ import (
_ "github.com/xtls/xray-core/transport/internet/tls" _ "github.com/xtls/xray-core/transport/internet/tls"
_ "github.com/xtls/xray-core/transport/internet/udp" _ "github.com/xtls/xray-core/transport/internet/udp"
_ "github.com/xtls/xray-core/transport/internet/websocket" _ "github.com/xtls/xray-core/transport/internet/websocket"
_ "github.com/xtls/xray-core/transport/internet/xtls"
// Transport headers // Transport headers
_ "github.com/xtls/xray-core/transport/internet/headers/http" _ "github.com/xtls/xray-core/transport/internet/headers/http"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,7 +3,7 @@ package shadowsocks_2022
import ( import (
"context" "context"
"github.com/sagernet/sing-shadowsocks" shadowsocks "github.com/sagernet/sing-shadowsocks"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022" "github.com/sagernet/sing-shadowsocks/shadowaead_2022"
C "github.com/sagernet/sing/common" C "github.com/sagernet/sing/common"
B "github.com/sagernet/sing/common/buf" B "github.com/sagernet/sing/common/buf"
@@ -50,7 +50,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 +64,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() {

View File

@@ -58,7 +58,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 +153,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() {

View File

@@ -85,6 +85,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() {

View File

@@ -6,12 +6,11 @@ import (
"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"
@@ -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,6 +88,10 @@ 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, toSocksaddr(destination))
var handshake bool var handshake bool
@@ -149,9 +154,12 @@ 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, toSocksaddr(destination))
return returnError(bufio.CopyPacketConn(ctx, packetConn, uot.NewClientConn(serverConn))) if err != nil {
return err
}
return 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 returnError(bufio.CopyPacketConn(ctx, packetConn, serverConn))

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,7 +5,6 @@ import (
"io" "io"
"strconv" "strconv"
"strings" "strings"
"syscall"
"time" "time"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
@@ -13,7 +12,6 @@ import (
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
udp_proto "github.com/xtls/xray-core/common/protocol/udp" udp_proto "github.com/xtls/xray-core/common/protocol/udp"
"github.com/xtls/xray-core/common/retry" "github.com/xtls/xray-core/common/retry"
@@ -23,25 +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/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.
@@ -228,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)
@@ -235,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,
@@ -277,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 {
@@ -343,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)
@@ -356,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
@@ -406,12 +352,6 @@ 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 {
cs := xtlsConn.ConnectionState()
name = cs.ServerName
alpn = cs.NegotiatedProtocol
newError("realName = " + name).AtInfo().WriteToLog(sid)
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
} else if realityConn, ok := iConn.(*reality.Conn); ok { } else if realityConn, ok := iConn.(*reality.Conn); ok {
cs := realityConn.ConnectionState() cs := realityConn.ConnectionState()
name = cs.ServerName name = cs.ServerName

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,7 +20,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"
"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"
@@ -37,11 +36,8 @@ import (
"github.com/xtls/xray-core/transport/internet/reality" "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
@@ -53,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.
@@ -241,12 +230,6 @@ 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 {
cs := xtlsConn.ConnectionState()
name = cs.ServerName
alpn = cs.NegotiatedProtocol
newError("realName = " + name).AtInfo().WriteToLog(sid)
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
} else if realityConn, ok := iConn.(*reality.Conn); ok { } else if realityConn, ok := iConn.(*reality.Conn); ok {
cs := realityConn.ConnectionState() cs := realityConn.ConnectionState()
name = cs.ServerName name = cs.ServerName
@@ -455,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)
@@ -467,79 +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 realityConn, ok := iConn.(*reality.Conn); ok {
netConn = realityConn.NetConn()
t = reflect.TypeOf(realityConn.Conn).Elem()
p = uintptr(unsafe.Pointer(realityConn.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" or "reality"`).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()
@@ -553,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)
@@ -589,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))
@@ -624,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 {
@@ -645,7 +596,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
if statConn != nil { if statConn != nil {
counter = statConn.WriteCounter counter = statConn.WriteCounter
} }
err = encoding.XtlsWrite(serverReader, clientWriter, timer, netConn, counter, ctx, &userUUID, &numberOfPacketToFilter, err = encoding.XtlsWrite(serverReader, clientWriter, timer, netConn, counter, ctx, &numberOfPacketToFilter,
&enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello) &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello)
} else { } else {
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer // from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer

View File

@@ -15,7 +15,6 @@ 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"
@@ -32,22 +31,12 @@ import (
"github.com/xtls/xray-core/transport/internet/reality" "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.
@@ -140,73 +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 realityConn, ok := iConn.(*reality.UConn); ok { netConn = realityConn.NetConn()
netConn = realityConn.NetConn() t = reflect.TypeOf(realityConn.Conn).Elem()
t = reflect.TypeOf(realityConn.Conn).Elem() p = uintptr(unsafe.Pointer(realityConn.Conn))
p = uintptr(unsafe.Pointer(realityConn.Conn))
} else if _, ok := iConn.(*xtls.Conn); ok {
return newError(`failed to use ` + requestAddons.Flow + `, vision "security" must be "tls" or "reality"`).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.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)
@@ -234,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)
@@ -243,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 {
@@ -256,7 +232,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return err1 return err1
} else if requestAddons.Flow == vless.XRV { } else if requestAddons.Flow == vless.XRV {
mb := make(buf.MultiBuffer, 1) mb := make(buf.MultiBuffer, 1)
mb[0] = encoding.XtlsPadding(nil, 0x01, &userUUID, ctx) // it must not be tls so padding finish with it (command 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)) newError("Insert padding with empty content to camouflage VLESS header ", mb.Len()).WriteToLog(session.ExportIDToError(ctx))
if err := serverWriter.WriteMultiBuffer(mb); err != nil { if err := serverWriter.WriteMultiBuffer(mb); err != nil {
return err return err
@@ -285,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
@@ -321,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))
@@ -342,6 +311,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return nil return nil
} }
if newCtx != nil {
ctx = newCtx
}
if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil { if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil {
return newError("connection ends").Base(err).AtInfo() return newError("connection ends").Base(err).AtInfo()
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.28.1 // protoc-gen-go v1.28.1
// protoc v3.21.12 // protoc v4.22.0
// source: transport/internet/config.proto // source: transport/internet/config.proto
package internet package internet
@@ -426,6 +426,8 @@ 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"`
} }
func (x *SocketConfig) Reset() { func (x *SocketConfig) Reset() {
@@ -551,6 +553,20 @@ 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
}
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 +619,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, 0xc8, 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 +656,31 @@ 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, 0x22, 0x2f, 0x0a, 0x0a,
0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x66,
0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x4b, 0x43, 0x50, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x66, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x10, 0x01, 0x12,
0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10, 0x02, 0x2a, 0x5a, 0x0a,
0x54, 0x54, 0x50, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,
0x6f, 0x63, 0x6b, 0x65, 0x74, 0x10, 0x05, 0x2a, 0x41, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6f, 0x6c, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x55,
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x44, 0x50, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x4b, 0x43, 0x50, 0x10, 0x02, 0x12, 0x0d,
0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x0a, 0x09, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x10, 0x03, 0x12, 0x08, 0x0a,
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x6f, 0x6d, 0x61, 0x69,
0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f, 0x6e, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x10, 0x05, 0x2a, 0x41, 0x0a, 0x0e, 0x44, 0x6f, 0x6d,
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41,
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x53, 0x5f, 0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12,
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x42, 0x67, 0x0a, 0x1b,
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2c, 0x67,
0x6e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78,
0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x17, 0x58, 0x72,
0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74,
0x65, 0x72, 0x6e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

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

View File

@@ -12,7 +12,6 @@ import (
"github.com/xtls/xray-core/transport/internet/reality" "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) {
@@ -29,8 +28,6 @@ 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 {
return xtls.Client(conn, config.GetXTLSConfig(xtls.WithDestination(dest))), nil
} else if config := reality.ConfigFromStreamSettings(streamSettings); config != nil { } else if config := reality.ConfigFromStreamSettings(streamSettings); config != nil {
return reality.UClient(conn, config, ctx, dest) return reality.UClient(conn, config, ctx, dest)
} }

View File

@@ -9,7 +9,6 @@ import (
"os" "os"
"strings" "strings"
goxtls "github.com/xtls/go"
goreality "github.com/xtls/reality" 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"
@@ -17,7 +16,6 @@ import (
"github.com/xtls/xray-core/transport/internet/reality" "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"
) )
@@ -25,7 +23,6 @@ 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 realityConfig *goreality.Config
config *Config config *Config
addConn internet.ConnHandler addConn internet.ConnHandler
@@ -64,9 +61,6 @@ 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 {
ln.xtlsConfig = config.GetXTLSConfig()
}
if config := reality.ConfigFromStreamSettings(streamSettings); config != nil { if config := reality.ConfigFromStreamSettings(streamSettings); config != nil {
ln.realityConfig = config.GetREALITYConfig() ln.realityConfig = config.GetREALITYConfig()
} }
@@ -100,8 +94,6 @@ func (ln *Listener) run() {
go func() { 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 {
conn = xtls.Server(conn, ln.xtlsConfig)
} else if ln.realityConfig != nil { } else if ln.realityConfig != nil {
if conn, err = reality.Server(conn, ln.realityConfig); err != nil { if conn, err = reality.Server(conn, ln.realityConfig); err != nil {
newError(err).AtInfo().WriteToLog() newError(err).AtInfo().WriteToLog()

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,6 +11,7 @@ import (
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/grpc/encoding" "github.com/xtls/xray-core/transport/internet/grpc/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"
"google.golang.org/grpc" "google.golang.org/grpc"
@@ -53,15 +54,16 @@ func dialgRPC(ctx context.Context, dest net.Destination, streamSettings *interne
} }
client := encoding.NewGRPCServiceClient(conn) client := encoding.NewGRPCServiceClient(conn)
if grpcSettings.MultiMode { if grpcSettings.MultiMode {
newError("using gRPC multi mode").AtDebug().WriteToLog() newError("using gRPC multi mode service name: `" + grpcSettings.getServiceName() + "` stream name: `" + grpcSettings.getTunMultiStreamName() + "`").AtDebug().WriteToLog()
grpcService, err := client.(encoding.GRPCServiceClientX).TunMultiCustomName(ctx, grpcSettings.getNormalizedName()) grpcService, err := client.(encoding.GRPCServiceClientX).TunMultiCustomName(ctx, grpcSettings.getServiceName(), grpcSettings.getTunMultiStreamName())
if err != nil { if err != nil {
return nil, newError("Cannot dial gRPC").Base(err) return nil, newError("Cannot dial gRPC").Base(err)
} }
return encoding.NewMultiHunkConn(grpcService, nil), nil return encoding.NewMultiHunkConn(grpcService, nil), nil
} }
grpcService, err := client.(encoding.GRPCServiceClientX).TunCustomName(ctx, grpcSettings.getNormalizedName()) newError("using gRPC tun mode service name: `" + grpcSettings.getServiceName() + "` stream name: `" + grpcSettings.getTunStreamName() + "`").AtDebug().WriteToLog()
grpcService, err := client.(encoding.GRPCServiceClientX).TunCustomName(ctx, grpcSettings.getServiceName(), grpcSettings.getTunStreamName())
if err != nil { if err != nil {
return nil, newError("Cannot dial gRPC").Base(err) return nil, newError("Cannot dial gRPC").Base(err)
} }
@@ -77,6 +79,7 @@ func getGrpcClient(ctx context.Context, dest net.Destination, streamSettings *in
globalDialerMap = make(map[dialerConf]*grpc.ClientConn) globalDialerMap = make(map[dialerConf]*grpc.ClientConn)
} }
tlsConfig := tls.ConfigFromStreamSettings(streamSettings) tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
realityConfig := reality.ConfigFromStreamSettings(streamSettings)
sockopt := streamSettings.SocketSettings sockopt := streamSettings.SocketSettings
grpcSettings := streamSettings.ProtocolSettings.(*Config) grpcSettings := streamSettings.ProtocolSettings.(*Config)
@@ -116,7 +119,11 @@ func getGrpcClient(ctx context.Context, dest net.Destination, streamSettings *in
return nil, err return nil, err
} }
address := net.ParseAddress(rawHost) address := net.ParseAddress(rawHost)
return internet.DialSystem(gctx, net.TCPDestination(address, port), sockopt) c, err := internet.DialSystem(gctx, net.TCPDestination(address, port), sockopt)
if err == nil && realityConfig != nil {
return reality.UClient(c, realityConfig, ctx, dest)
}
return c, err
}), }),
} }
@@ -144,6 +151,10 @@ func getGrpcClient(ctx context.Context, dest net.Destination, streamSettings *in
dialOptions = append(dialOptions, grpc.WithInitialWindowSize(grpcSettings.InitialWindowsSize)) dialOptions = append(dialOptions, grpc.WithInitialWindowSize(grpcSettings.InitialWindowsSize))
} }
if grpcSettings.UserAgent != "" {
dialOptions = append(dialOptions, grpc.WithUserAgent(grpcSettings.UserAgent))
}
var grpcDestHost string var grpcDestHost string
if dest.Address.Family().IsDomain() { if dest.Address.Family().IsDomain() {
grpcDestHost = dest.Address.Domain() grpcDestHost = dest.Address.Domain()

View File

@@ -6,20 +6,20 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
) )
func ServerDesc(name string) grpc.ServiceDesc { func ServerDesc(name, tun, tunMulti string) grpc.ServiceDesc {
return grpc.ServiceDesc{ return grpc.ServiceDesc{
ServiceName: name, ServiceName: name,
HandlerType: (*GRPCServiceServer)(nil), HandlerType: (*GRPCServiceServer)(nil),
Methods: []grpc.MethodDesc{}, Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{ Streams: []grpc.StreamDesc{
{ {
StreamName: "Tun", StreamName: tun,
Handler: _GRPCService_Tun_Handler, Handler: _GRPCService_Tun_Handler,
ServerStreams: true, ServerStreams: true,
ClientStreams: true, ClientStreams: true,
}, },
{ {
StreamName: "TunMulti", StreamName: tunMulti,
Handler: _GRPCService_TunMulti_Handler, Handler: _GRPCService_TunMulti_Handler,
ServerStreams: true, ServerStreams: true,
ClientStreams: true, ClientStreams: true,
@@ -29,8 +29,8 @@ func ServerDesc(name string) grpc.ServiceDesc {
} }
} }
func (c *gRPCServiceClient) TunCustomName(ctx context.Context, name string, opts ...grpc.CallOption) (GRPCService_TunClient, error) { func (c *gRPCServiceClient) TunCustomName(ctx context.Context, name, tun string, opts ...grpc.CallOption) (GRPCService_TunClient, error) {
stream, err := c.cc.NewStream(ctx, &ServerDesc(name).Streams[0], "/"+name+"/Tun", opts...) stream, err := c.cc.NewStream(ctx, &ServerDesc(name, tun, "").Streams[0], "/"+name+"/"+tun, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -38,8 +38,8 @@ func (c *gRPCServiceClient) TunCustomName(ctx context.Context, name string, opts
return x, nil return x, nil
} }
func (c *gRPCServiceClient) TunMultiCustomName(ctx context.Context, name string, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error) { func (c *gRPCServiceClient) TunMultiCustomName(ctx context.Context, name, tunMulti string, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error) {
stream, err := c.cc.NewStream(ctx, &ServerDesc(name).Streams[1], "/"+name+"/TunMulti", opts...) stream, err := c.cc.NewStream(ctx, &ServerDesc(name, "", tunMulti).Streams[1], "/"+name+"/"+tunMulti, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -48,13 +48,13 @@ func (c *gRPCServiceClient) TunMultiCustomName(ctx context.Context, name string,
} }
type GRPCServiceClientX interface { type GRPCServiceClientX interface {
TunCustomName(ctx context.Context, name string, opts ...grpc.CallOption) (GRPCService_TunClient, error) TunCustomName(ctx context.Context, name, tun string, opts ...grpc.CallOption) (GRPCService_TunClient, error)
TunMultiCustomName(ctx context.Context, name string, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error) TunMultiCustomName(ctx context.Context, name, tunMulti string, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error)
Tun(ctx context.Context, opts ...grpc.CallOption) (GRPCService_TunClient, error) Tun(ctx context.Context, opts ...grpc.CallOption) (GRPCService_TunClient, error)
TunMulti(ctx context.Context, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error) TunMulti(ctx context.Context, opts ...grpc.CallOption) (GRPCService_TunMultiClient, error)
} }
func RegisterGRPCServiceServerX(s *grpc.Server, srv GRPCServiceServer, name string) { func RegisterGRPCServiceServerX(s *grpc.Server, srv GRPCServiceServer, name, tun, tunMulti string) {
desc := ServerDesc(name) desc := ServerDesc(name, tun, tunMulti)
s.RegisterService(&desc, srv) s.RegisterService(&desc, srv)
} }

View File

@@ -4,11 +4,13 @@ import (
"context" "context"
"time" "time"
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/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/grpc/encoding" "github.com/xtls/xray-core/transport/internet/grpc/encoding"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials"
@@ -123,8 +125,12 @@ func Listen(ctx context.Context, address net.Address, port net.Port, settings *i
} }
} }
encoding.RegisterGRPCServiceServerX(s, listener, grpcSettings.getNormalizedName()) newError("gRPC listen for service name `" + grpcSettings.getServiceName() + "` tun `" + grpcSettings.getTunStreamName() + "` multi tun `" + grpcSettings.getTunMultiStreamName() + "`").AtDebug().WriteToLog()
encoding.RegisterGRPCServiceServerX(s, listener, grpcSettings.getServiceName(), grpcSettings.getTunStreamName(), grpcSettings.getTunMultiStreamName())
if config := reality.ConfigFromStreamSettings(settings); config != nil {
streamListener = goreality.NewListener(streamListener, config.GetREALITYConfig())
}
if err = s.Serve(streamListener); err != nil { if err = s.Serve(streamListener); err != nil {
newError("Listener for gRPC ended").Base(err).WriteToLog() newError("Listener for gRPC ended").Base(err).WriteToLog()
} }

View File

@@ -0,0 +1,153 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.21.12
// source: transport/internet/headers/dns/config.proto
package dns
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
Domain string `protobuf:"bytes,1,opt,name=domain,proto3" json:"domain,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_transport_internet_headers_dns_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_transport_internet_headers_dns_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_transport_internet_headers_dns_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
var File_transport_internet_headers_dns_config_proto protoreflect.FileDescriptor
var file_transport_internet_headers_dns_config_proto_rawDesc = []byte{
0x0a, 0x2b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x64, 0x6e, 0x73,
0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x23, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x64,
0x6e, 0x73, 0x22, 0x20, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x0a, 0x06,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0x42, 0x8b, 0x01, 0x0a, 0x27, 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, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x64, 0x6e, 0x73,
0x50, 0x01, 0x5a, 0x38, 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,
0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x23, 0x58,
0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x44,
0x4e, 0x53, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_transport_internet_headers_dns_config_proto_rawDescOnce sync.Once
file_transport_internet_headers_dns_config_proto_rawDescData = file_transport_internet_headers_dns_config_proto_rawDesc
)
func file_transport_internet_headers_dns_config_proto_rawDescGZIP() []byte {
file_transport_internet_headers_dns_config_proto_rawDescOnce.Do(func() {
file_transport_internet_headers_dns_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_dns_config_proto_rawDescData)
})
return file_transport_internet_headers_dns_config_proto_rawDescData
}
var file_transport_internet_headers_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_headers_dns_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: xray.transport.internet.headers.dns.Config
}
var file_transport_internet_headers_dns_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_transport_internet_headers_dns_config_proto_init() }
func file_transport_internet_headers_dns_config_proto_init() {
if File_transport_internet_headers_dns_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_transport_internet_headers_dns_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_transport_internet_headers_dns_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_headers_dns_config_proto_goTypes,
DependencyIndexes: file_transport_internet_headers_dns_config_proto_depIdxs,
MessageInfos: file_transport_internet_headers_dns_config_proto_msgTypes,
}.Build()
File_transport_internet_headers_dns_config_proto = out.File
file_transport_internet_headers_dns_config_proto_rawDesc = nil
file_transport_internet_headers_dns_config_proto_goTypes = nil
file_transport_internet_headers_dns_config_proto_depIdxs = nil
}

View File

@@ -0,0 +1,12 @@
syntax = "proto3";
package xray.transport.internet.headers.dns;
option csharp_namespace = "Xray.Transport.Internet.Headers.DNS";
option go_package = "github.com/xtls/xray-core/transport/internet/headers/dns";
option java_package = "com.xray.transport.internet.headers.dns";
option java_multiple_files = true;
message Config {
string domain = 1;
}

View File

@@ -0,0 +1,56 @@
package dns
import (
"context"
"encoding/binary"
"github.com/miekg/dns"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice"
)
type DNS struct {
header []byte
}
func (d DNS) Size() int32 {
return int32(len(d.header))
}
// Serialize implements PacketHeader.
func (d DNS) Serialize(b []byte) {
copy(b, d.header)
binary.BigEndian.PutUint16(b[0:], dice.RollUint16()) // random transaction ID
}
// NewDNS returns a new DNS instance based on given config.
func NewDNS(ctx context.Context, config interface{}) (interface{}, error) {
var header []byte
header = binary.BigEndian.AppendUint16(header, 0x0000) // Transaction ID
header = binary.BigEndian.AppendUint16(header, 0x0100) // Flags: Standard query
header = binary.BigEndian.AppendUint16(header, 0x0001) // Questions
header = binary.BigEndian.AppendUint16(header, 0x0000) // Answer RRs
header = binary.BigEndian.AppendUint16(header, 0x0000) // Authority RRs
header = binary.BigEndian.AppendUint16(header, 0x0000) // Additional RRs
buf := make([]byte, 0x100)
off1, err := dns.PackDomainName(dns.Fqdn(config.(*Config).Domain), buf, 0, nil, false)
if err != nil {
return nil, err
}
header = append(header, buf[:off1]...)
header = binary.BigEndian.AppendUint16(header, 0x0001) // Type: A
header = binary.BigEndian.AppendUint16(header, 0x0001) // Class: IN
return DNS{
header: header,
}, nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), NewDNS))
}

View File

@@ -3,6 +3,7 @@ package http
import ( import (
"context" "context"
gotls "crypto/tls" gotls "crypto/tls"
"io"
"net/http" "net/http"
"net/url" "net/url"
"sync" "sync"
@@ -166,23 +167,68 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
// Disable any compression method from server. // Disable any compression method from server.
request.Header.Set("Accept-Encoding", "identity") request.Header.Set("Accept-Encoding", "identity")
response, err := client.Do(request) wrc := &WaitReadCloser{Wait: make(chan struct{})}
if err != nil { go func() {
return nil, newError("failed to dial to ", dest).Base(err).AtWarning() response, err := client.Do(request)
} if err != nil {
if response.StatusCode != 200 { newError("failed to dial to ", dest).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))
return nil, newError("unexpected status", response.StatusCode).AtWarning() wrc.Close()
} return
}
if response.StatusCode != 200 {
newError("unexpected status", response.StatusCode).AtWarning().WriteToLog(session.ExportIDToError(ctx))
wrc.Close()
return
}
wrc.Set(response.Body)
}()
bwriter := buf.NewBufferedWriter(pwriter) bwriter := buf.NewBufferedWriter(pwriter)
common.Must(bwriter.SetBuffered(false)) common.Must(bwriter.SetBuffered(false))
return cnc.NewConnection( return cnc.NewConnection(
cnc.ConnectionOutput(response.Body), cnc.ConnectionOutput(wrc),
cnc.ConnectionInput(bwriter), cnc.ConnectionInput(bwriter),
cnc.ConnectionOnClose(common.ChainedClosable{breader, bwriter, response.Body}), cnc.ConnectionOnClose(common.ChainedClosable{breader, bwriter, wrc}),
), nil ), nil
} }
func init() { func init() {
common.Must(internet.RegisterTransportDialer(protocolName, Dial)) common.Must(internet.RegisterTransportDialer(protocolName, Dial))
} }
type WaitReadCloser struct {
Wait chan struct{}
io.ReadCloser
}
func (w *WaitReadCloser) Set(rc io.ReadCloser) {
w.ReadCloser = rc
defer func() {
if recover() != nil {
rc.Close()
}
}()
close(w.Wait)
}
func (w *WaitReadCloser) Read(b []byte) (int, error) {
if w.ReadCloser == nil {
if <-w.Wait; w.ReadCloser == nil {
return 0, io.ErrClosedPipe
}
}
return w.ReadCloser.Read(b)
}
func (w *WaitReadCloser) Close() error {
if w.ReadCloser != nil {
return w.ReadCloser.Close()
}
defer func() {
if recover() != nil && w.ReadCloser != nil {
w.ReadCloser.Close()
}
}()
close(w.Wait)
return nil
}

View File

@@ -7,6 +7,7 @@ import (
"strings" "strings"
"time" "time"
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/common/net/cnc" "github.com/xtls/xray-core/common/net/cnc"
@@ -15,6 +16,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/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
"golang.org/x/net/http2" "golang.org/x/net/http2"
"golang.org/x/net/http2/h2c" "golang.org/x/net/http2/h2c"
@@ -49,6 +51,13 @@ func (fw flushWriter) Write(p []byte) (n int, err error) {
return 0, io.ErrClosedPipe return 0, io.ErrClosedPipe
} }
defer func() {
if recover() != nil {
fw.d.Close()
err = io.ErrClosedPipe
}
}()
n, err = fw.w.Write(p) n, err = fw.w.Write(p)
if f, ok := fw.w.(http.Flusher); ok && err == nil { if f, ok := fw.w.(http.Flusher); ok && err == nil {
f.Flush() f.Flush()
@@ -187,14 +196,17 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
} }
if config == nil { if config == nil {
if config := reality.ConfigFromStreamSettings(streamSettings); config != nil {
streamListener = goreality.NewListener(streamListener, config.GetREALITYConfig())
}
err = server.Serve(streamListener) err = server.Serve(streamListener)
if err != nil { if err != nil {
newError("stopping serving H2C").Base(err).WriteToLog(session.ExportIDToError(ctx)) newError("stopping serving H2C or REALITY H2").Base(err).WriteToLog(session.ExportIDToError(ctx))
} }
} else { } else {
err = server.ServeTLS(streamListener, "", "") err = server.ServeTLS(streamListener, "", "")
if err != nil { if err != nil {
newError("stopping serving TLS").Base(err).WriteToLog(session.ExportIDToError(ctx)) newError("stopping serving TLS H2").Base(err).WriteToLog(session.ExportIDToError(ctx))
} }
} }
}() }()

View File

@@ -12,7 +12,6 @@ import (
"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/tls" "github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/xtls"
) )
var globalConv = uint32(dice.RollUint16()) var globalConv = uint32(dice.RollUint16())
@@ -87,8 +86,6 @@ func DialKCP(ctx context.Context, dest net.Destination, streamSettings *internet
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil { if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
iConn = tls.Client(iConn, config.GetTLSConfig(tls.WithDestination(dest))) iConn = tls.Client(iConn, config.GetTLSConfig(tls.WithDestination(dest)))
} else if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {
iConn = xtls.Client(iConn, config.GetXTLSConfig(xtls.WithDestination(dest)))
} }
return iConn, nil return iConn, nil

View File

@@ -6,7 +6,6 @@ import (
gotls "crypto/tls" gotls "crypto/tls"
"sync" "sync"
goxtls "github.com/xtls/go"
"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"
@@ -14,7 +13,6 @@ import (
"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"
) )
type ConnectionID struct { type ConnectionID struct {
@@ -26,15 +24,14 @@ type ConnectionID struct {
// Listener defines a server listening for connections // Listener defines a server listening for connections
type Listener struct { type Listener struct {
sync.Mutex sync.Mutex
sessions map[ConnectionID]*Connection sessions map[ConnectionID]*Connection
hub *udp.Hub hub *udp.Hub
tlsConfig *gotls.Config tlsConfig *gotls.Config
xtlsConfig *goxtls.Config config *Config
config *Config reader PacketReader
reader PacketReader header internet.PacketHeader
header internet.PacketHeader security cipher.AEAD
security cipher.AEAD addConn internet.ConnHandler
addConn internet.ConnHandler
} }
func NewListener(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (*Listener, error) { func NewListener(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (*Listener, error) {
@@ -62,9 +59,6 @@ func NewListener(ctx context.Context, address net.Address, port net.Port, stream
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil { if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
l.tlsConfig = config.GetTLSConfig() l.tlsConfig = config.GetTLSConfig()
} }
if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {
l.xtlsConfig = config.GetXTLSConfig()
}
hub, err := udp.ListenUDP(ctx, address, port, streamSettings, udp.HubCapacity(1024)) hub, err := udp.ListenUDP(ctx, address, port, streamSettings, udp.HubCapacity(1024))
if err != nil { if err != nil {
@@ -137,8 +131,6 @@ func (l *Listener) OnReceive(payload *buf.Buffer, src net.Destination) {
var netConn stat.Connection = conn var netConn stat.Connection = conn
if l.tlsConfig != nil { if l.tlsConfig != nil {
netConn = tls.Server(conn, l.tlsConfig) netConn = tls.Server(conn, l.tlsConfig)
} else if l.xtlsConfig != nil {
netConn = xtls.Server(conn, l.xtlsConfig)
} }
l.addConn(netConn) l.addConn(netConn)

View File

@@ -1,22 +1,18 @@
package quic package quic
import (
"fmt"
"github.com/xtls/xray-core/common/log"
)
type QlogWriter struct { type QlogWriter struct {
connID []byte connID []byte
} }
func (w *QlogWriter) Write(b []byte) (int, error) { func (w *QlogWriter) Write(b []byte) (int, error) {
if len(b) > 1 { // skip line separator "0a" in qlog // to much log, only turn on when debug Quic
log.Record(&log.GeneralMessage{
Severity: log.Severity_Debug, // if len(b) > 1 { // skip line separator "0a" in qlog
Content: fmt.Sprintf("[%x] %s", w.connID, b), // log.Record(&log.GeneralMessage{
}) // Severity: log.Severity_Debug,
} // Content: fmt.Sprintf("[%x] %s", w.connID, b),
// })
// }
return len(b), nil return len(b), nil
} }

View File

@@ -1,6 +1,7 @@
package reality package reality
import ( import (
"net"
"time" "time"
"github.com/xtls/reality" "github.com/xtls/reality"
@@ -8,7 +9,10 @@ import (
) )
func (c *Config) GetREALITYConfig() *reality.Config { func (c *Config) GetREALITYConfig() *reality.Config {
var dialer net.Dialer
config := &reality.Config{ config := &reality.Config{
DialContext: dialer.DialContext,
Show: c.Show, Show: c.Show,
Type: c.Type, Type: c.Type,
Dest: c.Dest, Dest: c.Dest,

View File

@@ -52,7 +52,7 @@ func (c *Conn) HandshakeAddress() net.Address {
} }
func Server(c net.Conn, config *reality.Config) (net.Conn, error) { func Server(c net.Conn, config *reality.Config) (net.Conn, error) {
realityConn, err := reality.Server(c, config) realityConn, err := reality.Server(context.Background(), c, config)
return &Conn{Conn: realityConn}, err return &Conn{Conn: realityConn}, err
} }
@@ -107,8 +107,8 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
InsecureSkipVerify: true, InsecureSkipVerify: true,
SessionTicketsDisabled: true, SessionTicketsDisabled: true,
} }
if utlsConfig.ServerName == "" && dest.Address.Family().IsDomain() { if utlsConfig.ServerName == "" {
utlsConfig.ServerName = dest.Address.Domain() utlsConfig.ServerName = dest.Address.String()
} }
uConn.ServerName = utlsConfig.ServerName uConn.ServerName = utlsConfig.ServerName
fingerprint := tls.GetFingerprint(config.Fingerprint) fingerprint := tls.GetFingerprint(config.Fingerprint)
@@ -121,13 +121,13 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
hello := uConn.HandshakeState.Hello hello := uConn.HandshakeState.Hello
hello.SessionId = make([]byte, 32) hello.SessionId = make([]byte, 32)
copy(hello.Raw[39:], hello.SessionId) // the location of session ID copy(hello.Raw[39:], hello.SessionId) // the location of session ID
binary.BigEndian.PutUint64(hello.SessionId, uint64(time.Now().Unix()))
hello.SessionId[0] = core.Version_x hello.SessionId[0] = core.Version_x
hello.SessionId[1] = core.Version_y hello.SessionId[1] = core.Version_y
hello.SessionId[2] = core.Version_z hello.SessionId[2] = core.Version_z
binary.BigEndian.PutUint32(hello.SessionId[4:], uint32(time.Now().Unix()))
copy(hello.SessionId[8:], config.ShortId) copy(hello.SessionId[8:], config.ShortId)
if config.Show { if config.Show {
fmt.Printf("REALITY localAddr: %v\thello.sessionId[:16]: %v\n", localAddr, hello.SessionId[:16]) fmt.Printf("REALITY localAddr: %v\thello.SessionId[:16]: %v\n", localAddr, hello.SessionId[:16])
} }
uConn.AuthKey = uConn.HandshakeState.State13.EcdheParams.SharedKey(config.PublicKey) uConn.AuthKey = uConn.HandshakeState.State13.EcdheParams.SharedKey(config.PublicKey)
if uConn.AuthKey == nil { if uConn.AuthKey == nil {
@@ -136,14 +136,13 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
if _, err := hkdf.New(sha256.New, uConn.AuthKey, hello.Random[:20], []byte("REALITY")).Read(uConn.AuthKey); err != nil { if _, err := hkdf.New(sha256.New, uConn.AuthKey, hello.Random[:20], []byte("REALITY")).Read(uConn.AuthKey); err != nil {
return nil, err return nil, err
} }
if config.Show {
fmt.Printf("REALITY localAddr: %v\tuConn.AuthKey[:16]: %v\n", localAddr, uConn.AuthKey[:16])
}
block, _ := aes.NewCipher(uConn.AuthKey) block, _ := aes.NewCipher(uConn.AuthKey)
aead, _ := cipher.NewGCM(block) aead, _ := cipher.NewGCM(block)
aead.Seal(hello.SessionId[:0], hello.Random[20:], hello.SessionId[:16], hello.Raw) aead.Seal(hello.SessionId[:0], hello.Random[20:], hello.SessionId[:16], hello.Raw)
copy(hello.Raw[39:], hello.SessionId) copy(hello.Raw[39:], hello.SessionId)
if config.Show {
fmt.Printf("REALITY localAddr: %v\thello.sessionId: %v\n", localAddr, hello.SessionId)
fmt.Printf("REALITY localAddr: %v\tuConn.AuthKey: %v\n", localAddr, uConn.AuthKey)
}
} }
if err := uConn.Handshake(); err != nil { if err := uConn.Handshake(); err != nil {
return nil, err return nil, err
@@ -240,8 +239,10 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
return uConn, nil return uConn, nil
} }
var href = regexp.MustCompile(`href="([/h].*?)"`) var (
var dot = []byte(".") href = regexp.MustCompile(`href="([/h].*?)"`)
dot = []byte(".")
)
var maps struct { var maps struct {
sync.Mutex sync.Mutex

View File

@@ -47,11 +47,11 @@ func applyOutboundSocketOptions(network string, address string, fd uintptr, conf
} }
} }
if config.Interface != "" { if config.Interface != "" {
if err := syscall.BindToDevice(int(fd), config.Interface); err != nil { if err := syscall.BindToDevice(int(fd), config.Interface); err != nil {
return newError("failed to set Interface").Base(err) return newError("failed to set Interface").Base(err)
} }
} }
if isTCPSocket(network) { if isTCPSocket(network) {
tfo := config.ParseTFOValue() tfo := config.ParseTFOValue()
@@ -89,6 +89,12 @@ func applyOutboundSocketOptions(network string, address string, fd uintptr, conf
return newError("failed to set TCP_CONGESTION", err) return newError("failed to set TCP_CONGESTION", err)
} }
} }
if config.TcpWindowClamp > 0 {
if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_WINDOW_CLAMP, int(config.TcpWindowClamp)); err != nil {
return newError("failed to set TCP_WINDOW_CLAMP", err)
}
}
} }
if config.Tproxy.IsEnabled() { if config.Tproxy.IsEnabled() {
@@ -139,6 +145,12 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
return newError("failed to set TCP_CONGESTION", err) return newError("failed to set TCP_CONGESTION", err)
} }
} }
if config.TcpWindowClamp > 0 {
if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_WINDOW_CLAMP, int(config.TcpWindowClamp)); err != nil {
return newError("failed to set TCP_WINDOW_CLAMP", err)
}
}
} }
if config.Tproxy.IsEnabled() { if config.Tproxy.IsEnabled() {
@@ -155,6 +167,12 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
} }
} }
if config.V6Only {
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, syscall.IPV6_V6ONLY, 1); err != nil {
return newError("failed to set IPV6_V6ONLY", err)
}
}
return nil return nil
} }

View File

@@ -10,7 +10,6 @@ import (
"github.com/xtls/xray-core/transport/internet/reality" "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"
) )
// Dial dials a new TCP connection to the given destination. // Dial dials a new TCP connection to the given destination.
@@ -31,9 +30,6 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
} else { } else {
conn = tls.Client(conn, tlsConfig) conn = tls.Client(conn, tlsConfig)
} }
} else if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {
xtlsConfig := config.GetXTLSConfig(xtls.WithDestination(dest))
conn = xtls.Client(conn, xtlsConfig)
} else if config := reality.ConfigFromStreamSettings(streamSettings); config != nil { } else if config := reality.ConfigFromStreamSettings(streamSettings); config != nil {
if conn, err = reality.UClient(conn, config, ctx, dest); err != nil { if conn, err = reality.UClient(conn, config, ctx, dest); err != nil {
return nil, err return nil, err

View File

@@ -6,7 +6,6 @@ import (
"strings" "strings"
"time" "time"
goxtls "github.com/xtls/go"
goreality "github.com/xtls/reality" 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"
@@ -15,14 +14,12 @@ import (
"github.com/xtls/xray-core/transport/internet/reality" "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"
) )
// Listener is an internet.Listener that listens for TCP connections. // Listener is an internet.Listener that listens for TCP connections.
type Listener struct { type Listener struct {
listener net.Listener listener net.Listener
tlsConfig *gotls.Config tlsConfig *gotls.Config
xtlsConfig *goxtls.Config
realityConfig *goreality.Config realityConfig *goreality.Config
authConfig internet.ConnectionAuthenticator authConfig internet.ConnectionAuthenticator
config *Config config *Config
@@ -78,9 +75,6 @@ func ListenTCP(ctx context.Context, address net.Address, port net.Port, streamSe
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil { if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
l.tlsConfig = config.GetTLSConfig() l.tlsConfig = config.GetTLSConfig()
} }
if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {
l.xtlsConfig = config.GetXTLSConfig()
}
if config := reality.ConfigFromStreamSettings(streamSettings); config != nil { if config := reality.ConfigFromStreamSettings(streamSettings); config != nil {
l.realityConfig = config.GetREALITYConfig() l.realityConfig = config.GetREALITYConfig()
} }
@@ -118,8 +112,6 @@ func (v *Listener) keepAccepting() {
go func() { go func() {
if v.tlsConfig != nil { if v.tlsConfig != nil {
conn = tls.Server(conn, v.tlsConfig) conn = tls.Server(conn, v.tlsConfig)
} else if v.xtlsConfig != nil {
conn = xtls.Server(conn, v.xtlsConfig)
} else if v.realityConfig != nil { } else if v.realityConfig != nil {
if conn, err = reality.Server(conn, v.realityConfig); err != nil { if conn, err = reality.Server(conn, v.realityConfig); err != nil {
newError(err).AtInfo().WriteToLog() newError(err).AtInfo().WriteToLog()

View File

@@ -266,6 +266,20 @@ func (c *Config) verifyPeerCert(rawCerts [][]byte, verifiedChains [][]*x509.Cert
} }
return newError("peer cert is unrecognized: ", base64.StdEncoding.EncodeToString(hashValue)) return newError("peer cert is unrecognized: ", base64.StdEncoding.EncodeToString(hashValue))
} }
if c.PinnedPeerCertificatePublicKeySha256 != nil {
for _, v := range verifiedChains {
for _, cert := range v {
publicHash := GenerateCertPublicKeyHash(cert)
for _, c := range c.PinnedPeerCertificatePublicKeySha256 {
if hmac.Equal(publicHash, c) {
return nil
}
}
}
}
return newError("peer public key is unrecognized.")
}
return nil return nil
} }
@@ -359,8 +373,8 @@ type Option func(*tls.Config)
// WithDestination sets the server name in TLS config. // WithDestination sets the server name in TLS config.
func WithDestination(dest net.Destination) Option { func WithDestination(dest net.Destination) Option {
return func(config *tls.Config) { return func(config *tls.Config) {
if dest.Address.Family().IsDomain() && config.ServerName == "" { if config.ServerName == "" {
config.ServerName = dest.Address.Domain() config.ServerName = dest.Address.String()
} }
} }
} }

View File

@@ -203,6 +203,11 @@ type Config struct {
// @Document This value replace allow_insecure. // @Document This value replace allow_insecure.
// @Critical // @Critical
PinnedPeerCertificateChainSha256 [][]byte `protobuf:"bytes,13,rep,name=pinned_peer_certificate_chain_sha256,json=pinnedPeerCertificateChainSha256,proto3" json:"pinned_peer_certificate_chain_sha256,omitempty"` PinnedPeerCertificateChainSha256 [][]byte `protobuf:"bytes,13,rep,name=pinned_peer_certificate_chain_sha256,json=pinnedPeerCertificateChainSha256,proto3" json:"pinned_peer_certificate_chain_sha256,omitempty"`
// @Document A pinned certificate public key sha256 hash.
// @Document If the server's public key hash does not match this value, the connection will be aborted.
// @Document This value replace allow_insecure.
// @Critical
PinnedPeerCertificatePublicKeySha256 [][]byte `protobuf:"bytes,14,rep,name=pinned_peer_certificate_public_key_sha256,json=pinnedPeerCertificatePublicKeySha256,proto3" json:"pinned_peer_certificate_public_key_sha256,omitempty"`
} }
func (x *Config) Reset() { func (x *Config) Reset() {
@@ -328,6 +333,13 @@ func (x *Config) GetPinnedPeerCertificateChainSha256() [][]byte {
return nil return nil
} }
func (x *Config) GetPinnedPeerCertificatePublicKeySha256() [][]byte {
if x != nil {
return x.PinnedPeerCertificatePublicKeySha256
}
return nil
}
var File_transport_internet_tls_config_proto protoreflect.FileDescriptor var File_transport_internet_tls_config_proto protoreflect.FileDescriptor
var file_transport_internet_tls_config_proto_rawDesc = []byte{ var file_transport_internet_tls_config_proto_rawDesc = []byte{
@@ -357,7 +369,7 @@ var file_transport_internet_tls_config_proto_rawDesc = []byte{
0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10,
0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52, 0x49, 0x46, 0x59, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52, 0x49, 0x46, 0x59,
0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f,
0x49, 0x53, 0x53, 0x55, 0x45, 0x10, 0x02, 0x22, 0xf3, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x49, 0x53, 0x53, 0x55, 0x45, 0x10, 0x02, 0x22, 0xcc, 0x05, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x65,
0x63, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f,
0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x4a, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x4a, 0x0a, 0x0b, 0x63, 0x65, 0x72,
@@ -396,15 +408,21 @@ var file_transport_internet_tls_config_proto_rawDesc = []byte{
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x73,
0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x20, 0x70, 0x69, 0x6e, 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x20, 0x70, 0x69, 0x6e,
0x6e, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x6e, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x42, 0x73, 0x0a, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x12, 0x57, 0x0a,
0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x29, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x63, 0x65, 0x72,
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c, 0x73, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f,
0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0c,
0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x52, 0x24, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74,
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79,
0x2f, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x1b, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x42, 0x73, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x54, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,
0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c, 0x73, 0x50, 0x01, 0x5a, 0x30, 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, 0x2f, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x1b,
0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49,
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x54, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -76,4 +76,11 @@ message Config {
@Critical @Critical
*/ */
repeated bytes pinned_peer_certificate_chain_sha256 = 13; repeated bytes pinned_peer_certificate_chain_sha256 = 13;
/* @Document A pinned certificate public key sha256 hash.
@Document If the server's public key hash does not match this value, the connection will be aborted.
@Document This value replace allow_insecure.
@Critical
*/
repeated bytes pinned_peer_certificate_public_key_sha256 = 14;
} }

View File

@@ -2,6 +2,7 @@ package tls
import ( import (
"crypto/sha256" "crypto/sha256"
"crypto/x509"
"encoding/base64" "encoding/base64"
"encoding/pem" "encoding/pem"
) )
@@ -34,3 +35,8 @@ func GenerateCertChainHash(rawCerts [][]byte) []byte {
} }
return hashValue return hashValue
} }
func GenerateCertPublicKeyHash(cert *x509.Certificate) []byte {
out := sha256.Sum256(cert.RawSubjectPublicKeyInfo)
return out[:]
}

View File

@@ -1,6 +1,9 @@
package tls package tls
import ( import (
"crypto/x509"
"encoding/base64"
"encoding/pem"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -108,3 +111,89 @@ tzY45d4mjPs0fKCFKSsVM6YT0tX4NwIKsOaeQg30WLtRyDwYm6ma/a/UUUS0FloZ
assert.Equal(t, "FW3SVMCL6um2wVltOdgJ3DpI82aredw83YoCblkMkVM=", hash) assert.Equal(t, "FW3SVMCL6um2wVltOdgJ3DpI82aredw83YoCblkMkVM=", hash)
}) })
} }
func TestCalculateCertPublicKeyHash(t *testing.T) {
const Single = `-----BEGIN CERTIFICATE-----
MIINWTCCC0GgAwIBAgITLQAxbA/A+lw/1sLDAAAAADFsDzANBgkqhkiG9w0BAQsF
ADBPMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
MSAwHgYDVQQDExdNaWNyb3NvZnQgUlNBIFRMUyBDQSAwMjAeFw0yMjExMjUwMDU2
NTZaFw0yMzA1MjUwMDU2NTZaMBcxFTATBgNVBAMTDHd3dy5iaW5nLmNvbTCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOH89lKmtkDnClFiQwfZofZO4h8C
Ye/+ChI67pEw5Q6/MxJzHiMKe8f1WaNuc+wkdHdct+BmQ+AftozIJt+eSN6IF7eY
dsutBvR87GNLFe40MBvfyvTQVM9Ulv04JxOpKTYnsf2wmktEI3y7FCgfm9RT71n+
Zef8Z8fa4By7aGfbbCQ0DsHl5P9o3ug/eLQODzK9NuQlwcVBHD2Zvgo+K7WOsjgE
k8JnOr+2zc0WWT4OrWSDJE/3l+jvhxmZkrwgmks4m9zUZvAnYAz/xxVCJRqbI3Ou
S5fkJJ3f6IxPbS2i8OWz6tma1aIkgQaFNJQuYOJa1esfQcEzs6kb/Xx5DXUCAwEA
AaOCCWQwgglgMIIBfQYKKwYBBAHWeQIEAgSCAW0EggFpAWcAdgCt9776fP8QyIud
PZwePhhqtGcpXc+xDCTKhYY069yCigAAAYSsUtxtAAAEAwBHMEUCIQCP/Jpp337p
cKITqS/kNlA4bNY6TK1Ad0VlsdkzQU+oZgIgFZb2AcsyT1UKCmM3ziGsLdvS9MAT
D1g/kztyDXhkA70AdgBVgdTCFpA2AUrqC5tXPFPwwOQ4eHAlCBcvo6odBxPTDAAA
AYSsUtsZAAAEAwBHMEUCIQDvlqXrdA440PW6b+JLj4F0ZVQNKHcv1lub0FhQqHgR
wAIgAtC7eXvXXhVBuO+Bd3fkDI0aGQM+pcvIesBoygzStjQAdQB6MoxU2LcttiDq
OOBSHumEFnAyE4VNO9IrwTpXo1LrUgAAAYSsUtmfAAAEAwBGMEQCIDgjSYt6e/h8
dv2KGEL3AJZUBH2gp1AA5saH8o3OyMJhAiBOCzo3oWlVFeF/8c0fxIIs9Fj4w8BY
INo0jNP/k7apgTAnBgkrBgEEAYI3FQoEGjAYMAoGCCsGAQUFBwMBMAoGCCsGAQUF
BwMCMD4GCSsGAQQBgjcVBwQxMC8GJysGAQQBgjcVCIfahnWD7tkBgsmFG4G1nmGF
9OtggV2Fho5Bh8KYUAIBZAIBJzCBhwYIKwYBBQUHAQEEezB5MFMGCCsGAQUFBzAC
hkdodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL21zY29ycC9NaWNyb3NvZnQl
MjBSU0ElMjBUTFMlMjBDQSUyMDAyLmNydDAiBggrBgEFBQcwAYYWaHR0cDovL29j
c3AubXNvY3NwLmNvbTAdBgNVHQ4EFgQUpuSPPchFlPGu8FTbzPhJTFxQ7RowDgYD
VR0PAQH/BAQDAgSwMIIFbQYDVR0RBIIFZDCCBWCCDHd3dy5iaW5nLmNvbYIQZGlj
dC5iaW5nLmNvbS5jboITKi5wbGF0Zm9ybS5iaW5nLmNvbYIKKi5iaW5nLmNvbYII
YmluZy5jb22CFmllb25saW5lLm1pY3Jvc29mdC5jb22CEyoud2luZG93c3NlYXJj
aC5jb22CGWNuLmllb25saW5lLm1pY3Jvc29mdC5jb22CESoub3JpZ2luLmJpbmcu
Y29tgg0qLm1tLmJpbmcubmV0gg4qLmFwaS5iaW5nLmNvbYIYZWNuLmRldi52aXJ0
dWFsZWFydGgubmV0gg0qLmNuLmJpbmcubmV0gg0qLmNuLmJpbmcuY29tghBzc2wt
YXBpLmJpbmcuY29tghBzc2wtYXBpLmJpbmcubmV0gg4qLmFwaS5iaW5nLm5ldIIO
Ki5iaW5nYXBpcy5jb22CD2JpbmdzYW5kYm94LmNvbYIWZmVlZGJhY2subWljcm9z
b2Z0LmNvbYIbaW5zZXJ0bWVkaWEuYmluZy5vZmZpY2UubmV0gg5yLmJhdC5iaW5n
LmNvbYIQKi5yLmJhdC5iaW5nLmNvbYISKi5kaWN0LmJpbmcuY29tLmNugg8qLmRp
Y3QuYmluZy5jb22CDiouc3NsLmJpbmcuY29tghAqLmFwcGV4LmJpbmcuY29tghYq
LnBsYXRmb3JtLmNuLmJpbmcuY29tgg13cC5tLmJpbmcuY29tggwqLm0uYmluZy5j
b22CD2dsb2JhbC5iaW5nLmNvbYIRd2luZG93c3NlYXJjaC5jb22CDnNlYXJjaC5t
c24uY29tghEqLmJpbmdzYW5kYm94LmNvbYIZKi5hcGkudGlsZXMuZGl0dS5saXZl
LmNvbYIPKi5kaXR1LmxpdmUuY29tghgqLnQwLnRpbGVzLmRpdHUubGl2ZS5jb22C
GCoudDEudGlsZXMuZGl0dS5saXZlLmNvbYIYKi50Mi50aWxlcy5kaXR1LmxpdmUu
Y29tghgqLnQzLnRpbGVzLmRpdHUubGl2ZS5jb22CFSoudGlsZXMuZGl0dS5saXZl
LmNvbYILM2QubGl2ZS5jb22CE2FwaS5zZWFyY2gubGl2ZS5jb22CFGJldGEuc2Vh
cmNoLmxpdmUuY29tghVjbndlYi5zZWFyY2gubGl2ZS5jb22CDGRldi5saXZlLmNv
bYINZGl0dS5saXZlLmNvbYIRZmFyZWNhc3QubGl2ZS5jb22CDmltYWdlLmxpdmUu
Y29tgg9pbWFnZXMubGl2ZS5jb22CEWxvY2FsLmxpdmUuY29tLmF1ghRsb2NhbHNl
YXJjaC5saXZlLmNvbYIUbHM0ZC5zZWFyY2gubGl2ZS5jb22CDW1haWwubGl2ZS5j
b22CEW1hcGluZGlhLmxpdmUuY29tgg5sb2NhbC5saXZlLmNvbYINbWFwcy5saXZl
LmNvbYIQbWFwcy5saXZlLmNvbS5hdYIPbWluZGlhLmxpdmUuY29tgg1uZXdzLmxp
dmUuY29tghxvcmlnaW4uY253ZWIuc2VhcmNoLmxpdmUuY29tghZwcmV2aWV3Lmxv
Y2FsLmxpdmUuY29tgg9zZWFyY2gubGl2ZS5jb22CEnRlc3QubWFwcy5saXZlLmNv
bYIOdmlkZW8ubGl2ZS5jb22CD3ZpZGVvcy5saXZlLmNvbYIVdmlydHVhbGVhcnRo
LmxpdmUuY29tggx3YXAubGl2ZS5jb22CEndlYm1hc3Rlci5saXZlLmNvbYITd2Vi
bWFzdGVycy5saXZlLmNvbYIVd3d3LmxvY2FsLmxpdmUuY29tLmF1ghR3d3cubWFw
cy5saXZlLmNvbS5hdTCBsAYDVR0fBIGoMIGlMIGioIGfoIGchk1odHRwOi8vbXNj
cmwubWljcm9zb2Z0LmNvbS9wa2kvbXNjb3JwL2NybC9NaWNyb3NvZnQlMjBSU0El
MjBUTFMlMjBDQSUyMDAyLmNybIZLaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3Br
aS9tc2NvcnAvY3JsL01pY3Jvc29mdCUyMFJTQSUyMFRMUyUyMENBJTIwMDIuY3Js
MFcGA1UdIARQME4wQgYJKwYBBAGCNyoBMDUwMwYIKwYBBQUHAgEWJ2h0dHA6Ly93
d3cubWljcm9zb2Z0LmNvbS9wa2kvbXNjb3JwL2NwczAIBgZngQwBAgEwHwYDVR0j
BBgwFoAU/y9/4Qb0OPMt7SWNmML+DvZs/PowHQYDVR0lBBYwFAYIKwYBBQUHAwEG
CCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4ICAQB4OIB/EHxpF64iFZME7XkJjZYn
ZiYIfOfHs6EGDNn7fxvpZS9HVy1jOWv/RvzEbMuSV3b/fItaJN/zATBg5/6hb5Jq
HGIcnKmb+tYrKlYhSOngHSu/8/OYP1dFFIqcVe0769kwXaKUzLh6UVRaS+mB7GFc
sXmPMbv5NM7mCUEdMkOaoSmubfw/WzmmRGrcSmtCxtIwMcp8Jf13Esunq//4+9w3
M/JXa8ubmXyrY63zt/Oz/NkVJvja89ueovscy6s5sw2r+Su4bRsJjmxwCbakp56K
rbh7z417LzW88MMuATvOyk/O8Rbw2KYVSEiQgO54kHI0YkHkJ/6IoeAT1pmCfHUE
Rd+Ec8T+/lE2BPLVqp8SjogDYiybb0IR5Gn2vYyUdzsS2h/C5qGNd2t5ehxfjQoL
G6Y3GJZQRxkSX6TLPYU0U63wWb4yeSxabpBlARaZMaAoqDa3cX53WCnrAXDz8vuH
yAtX2/Jq7IpybFK5kFzbxfI02Ik0aCWJUnXPL8L6esTskwvkzX8rSI/bjPrzcJL5
B9pONLy6wc8/Arfu2eNlMbs8s/g8c5zkEc3fBZ9tJ1dqlnMAVgB2+fwI3aK4F34N
uyfZW7Xu65KkPhbMnO0GVGM7X4Lkyjm4ysQ9PIRV3MwMfXH+RBSXlIayLTcYG4gl
XF1a/qnao6nMjyTIyQ==
-----END CERTIFICATE-----
`
t.Run("singlepublickey", func(t *testing.T) {
block, _ := pem.Decode([]byte(Single))
cert, err := x509.ParseCertificate(block.Bytes)
assert.Equal(t, err, nil)
hash := GenerateCertPublicKeyHash(cert)
hashstr := base64.StdEncoding.EncodeToString(hash)
assert.Equal(t, "xI/4mNm8xF9uDT4vA9G1+aKAaybwNlkRECnN8vGAHTM=", hashstr)
})
}

View File

@@ -1,377 +0,0 @@
package xtls
import (
"crypto/hmac"
"crypto/x509"
"encoding/base64"
"strings"
"sync"
"time"
xtls "github.com/xtls/go"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/ocsp"
"github.com/xtls/xray-core/common/platform/filesystem"
"github.com/xtls/xray-core/common/protocol/tls/cert"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/tls"
)
var globalSessionCache = xtls.NewLRUClientSessionCache(128)
// ParseCertificate converts a cert.Certificate to Certificate.
func ParseCertificate(c *cert.Certificate) *Certificate {
if c != nil {
certPEM, keyPEM := c.ToPEM()
return &Certificate{
Certificate: certPEM,
Key: keyPEM,
}
}
return nil
}
func (c *Config) loadSelfCertPool() (*x509.CertPool, error) {
root := x509.NewCertPool()
for _, cert := range c.Certificate {
if !root.AppendCertsFromPEM(cert.Certificate) {
return nil, newError("failed to append cert").AtWarning()
}
}
return root, nil
}
// BuildCertificates builds a list of TLS certificates from proto definition.
func (c *Config) BuildCertificates() []*xtls.Certificate {
certs := make([]*xtls.Certificate, 0, len(c.Certificate))
for _, entry := range c.Certificate {
if entry.Usage != Certificate_ENCIPHERMENT {
continue
}
keyPair, err := xtls.X509KeyPair(entry.Certificate, entry.Key)
if err != nil {
newError("ignoring invalid X509 key pair").Base(err).AtWarning().WriteToLog()
continue
}
keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
if err != nil {
newError("ignoring invalid certificate").Base(err).AtWarning().WriteToLog()
continue
}
certs = append(certs, &keyPair)
if !entry.OneTimeLoading {
var isOcspstapling bool
hotReloadInterval := uint64(3600)
if entry.OcspStapling != 0 {
hotReloadInterval = entry.OcspStapling
isOcspstapling = true
}
index := len(certs) - 1
go func(entry *Certificate, cert *xtls.Certificate, index int) {
t := time.NewTicker(time.Duration(hotReloadInterval) * time.Second)
for {
if entry.CertificatePath != "" && entry.KeyPath != "" {
newCert, err := filesystem.ReadFile(entry.CertificatePath)
if err != nil {
newError("failed to parse certificate").Base(err).AtError().WriteToLog()
<-t.C
continue
}
newKey, err := filesystem.ReadFile(entry.KeyPath)
if err != nil {
newError("failed to parse key").Base(err).AtError().WriteToLog()
<-t.C
continue
}
if string(newCert) != string(entry.Certificate) && string(newKey) != string(entry.Key) {
newKeyPair, err := xtls.X509KeyPair(newCert, newKey)
if err != nil {
newError("ignoring invalid X509 key pair").Base(err).AtError().WriteToLog()
<-t.C
continue
}
if newKeyPair.Leaf, err = x509.ParseCertificate(newKeyPair.Certificate[0]); err != nil {
newError("ignoring invalid certificate").Base(err).AtError().WriteToLog()
<-t.C
continue
}
cert = &newKeyPair
}
}
if isOcspstapling {
if newOCSPData, err := ocsp.GetOCSPForCert(cert.Certificate); err != nil {
newError("ignoring invalid OCSP").Base(err).AtWarning().WriteToLog()
} else if string(newOCSPData) != string(cert.OCSPStaple) {
cert.OCSPStaple = newOCSPData
}
}
certs[index] = cert
<-t.C
}
}(entry, certs[index], index)
}
}
return certs
}
func isCertificateExpired(c *xtls.Certificate) bool {
if c.Leaf == nil && len(c.Certificate) > 0 {
if pc, err := x509.ParseCertificate(c.Certificate[0]); err == nil {
c.Leaf = pc
}
}
// If leaf is not there, the certificate is probably not used yet. We trust user to provide a valid certificate.
return c.Leaf != nil && c.Leaf.NotAfter.Before(time.Now().Add(-time.Minute))
}
func issueCertificate(rawCA *Certificate, domain string) (*xtls.Certificate, error) {
parent, err := cert.ParseCertificate(rawCA.Certificate, rawCA.Key)
if err != nil {
return nil, newError("failed to parse raw certificate").Base(err)
}
newCert, err := cert.Generate(parent, cert.CommonName(domain), cert.DNSNames(domain))
if err != nil {
return nil, newError("failed to generate new certificate for ", domain).Base(err)
}
newCertPEM, newKeyPEM := newCert.ToPEM()
cert, err := xtls.X509KeyPair(newCertPEM, newKeyPEM)
return &cert, err
}
func (c *Config) getCustomCA() []*Certificate {
certs := make([]*Certificate, 0, len(c.Certificate))
for _, certificate := range c.Certificate {
if certificate.Usage == Certificate_AUTHORITY_ISSUE {
certs = append(certs, certificate)
}
}
return certs
}
func getGetCertificateFunc(c *xtls.Config, ca []*Certificate) func(hello *xtls.ClientHelloInfo) (*xtls.Certificate, error) {
var access sync.RWMutex
return func(hello *xtls.ClientHelloInfo) (*xtls.Certificate, error) {
domain := hello.ServerName
certExpired := false
access.RLock()
certificate, found := c.NameToCertificate[domain]
access.RUnlock()
if found {
if !isCertificateExpired(certificate) {
return certificate, nil
}
certExpired = true
}
if certExpired {
newCerts := make([]xtls.Certificate, 0, len(c.Certificates))
access.Lock()
for _, certificate := range c.Certificates {
if !isCertificateExpired(&certificate) {
newCerts = append(newCerts, certificate)
}
}
c.Certificates = newCerts
access.Unlock()
}
var issuedCertificate *xtls.Certificate
// Create a new certificate from existing CA if possible
for _, rawCert := range ca {
if rawCert.Usage == Certificate_AUTHORITY_ISSUE {
newCert, err := issueCertificate(rawCert, domain)
if err != nil {
newError("failed to issue new certificate for ", domain).Base(err).WriteToLog()
continue
}
access.Lock()
c.Certificates = append(c.Certificates, *newCert)
issuedCertificate = &c.Certificates[len(c.Certificates)-1]
access.Unlock()
break
}
}
if issuedCertificate == nil {
return nil, newError("failed to create a new certificate for ", domain)
}
access.Lock()
c.BuildNameToCertificate()
access.Unlock()
return issuedCertificate, nil
}
}
func getNewGetCertificateFunc(certs []*xtls.Certificate, rejectUnknownSNI bool) func(hello *xtls.ClientHelloInfo) (*xtls.Certificate, error) {
return func(hello *xtls.ClientHelloInfo) (*xtls.Certificate, error) {
if len(certs) == 0 {
return nil, errNoCertificates
}
sni := strings.ToLower(hello.ServerName)
if !rejectUnknownSNI && (len(certs) == 1 || sni == "") {
return certs[0], nil
}
gsni := "*"
if index := strings.IndexByte(sni, '.'); index != -1 {
gsni += sni[index:]
}
for _, keyPair := range certs {
if keyPair.Leaf.Subject.CommonName == sni || keyPair.Leaf.Subject.CommonName == gsni {
return keyPair, nil
}
for _, name := range keyPair.Leaf.DNSNames {
if name == sni || name == gsni {
return keyPair, nil
}
}
}
if rejectUnknownSNI {
return nil, errNoCertificates
}
return certs[0], nil
}
}
func (c *Config) parseServerName() string {
return c.ServerName
}
func (c *Config) verifyPeerCert(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
if c.PinnedPeerCertificateChainSha256 != nil {
hashValue := tls.GenerateCertChainHash(rawCerts)
for _, v := range c.PinnedPeerCertificateChainSha256 {
if hmac.Equal(hashValue, v) {
return nil
}
}
return newError("peer cert is unrecognized: ", base64.StdEncoding.EncodeToString(hashValue))
}
return nil
}
// GetXTLSConfig converts this Config into xtls.Config.
func (c *Config) GetXTLSConfig(opts ...Option) *xtls.Config {
root, err := c.getCertPool()
if err != nil {
newError("failed to load system root certificate").AtError().Base(err).WriteToLog()
}
if c == nil {
return &xtls.Config{
ClientSessionCache: globalSessionCache,
RootCAs: root,
InsecureSkipVerify: false,
NextProtos: nil,
SessionTicketsDisabled: true,
}
}
config := &xtls.Config{
ClientSessionCache: globalSessionCache,
RootCAs: root,
InsecureSkipVerify: c.AllowInsecure,
NextProtos: c.NextProtocol,
SessionTicketsDisabled: !c.EnableSessionResumption,
VerifyPeerCertificate: c.verifyPeerCert,
}
for _, opt := range opts {
opt(config)
}
caCerts := c.getCustomCA()
if len(caCerts) > 0 {
config.GetCertificate = getGetCertificateFunc(config, caCerts)
} else {
config.GetCertificate = getNewGetCertificateFunc(c.BuildCertificates(), c.RejectUnknownSni)
}
if sn := c.parseServerName(); len(sn) > 0 {
config.ServerName = sn
}
if len(config.NextProtos) == 0 {
config.NextProtos = []string{"h2", "http/1.1"}
}
switch c.MinVersion {
case "1.0":
config.MinVersion = xtls.VersionTLS10
case "1.1":
config.MinVersion = xtls.VersionTLS11
case "1.2":
config.MinVersion = xtls.VersionTLS12
case "1.3":
config.MinVersion = xtls.VersionTLS13
}
switch c.MaxVersion {
case "1.0":
config.MaxVersion = xtls.VersionTLS10
case "1.1":
config.MaxVersion = xtls.VersionTLS11
case "1.2":
config.MaxVersion = xtls.VersionTLS12
case "1.3":
config.MaxVersion = xtls.VersionTLS13
}
if len(c.CipherSuites) > 0 {
id := make(map[string]uint16)
for _, s := range xtls.CipherSuites() {
id[s.Name] = s.ID
}
for _, n := range strings.Split(c.CipherSuites, ":") {
if id[n] != 0 {
config.CipherSuites = append(config.CipherSuites, id[n])
}
}
}
config.PreferServerCipherSuites = c.PreferServerCipherSuites
return config
}
// Option for building XTLS config.
type Option func(*xtls.Config)
// WithDestination sets the server name in XTLS config.
func WithDestination(dest net.Destination) Option {
return func(config *xtls.Config) {
if dest.Address.Family().IsDomain() && config.ServerName == "" {
config.ServerName = dest.Address.Domain()
}
}
}
// WithNextProto sets the ALPN values in XTLS config.
func WithNextProto(protocol ...string) Option {
return func(config *xtls.Config) {
if len(config.NextProtos) == 0 {
config.NextProtos = protocol
}
}
}
// ConfigFromStreamSettings fetches Config from stream settings. Nil if not found.
func ConfigFromStreamSettings(settings *internet.MemoryStreamConfig) *Config {
if settings == nil {
return nil
}
config, ok := settings.SecuritySettings.(*Config)
if !ok {
return nil
}
return config
}

View File

@@ -1,478 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.21.12
// source: transport/internet/xtls/config.proto
package xtls
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 Certificate_Usage int32
const (
Certificate_ENCIPHERMENT Certificate_Usage = 0
Certificate_AUTHORITY_VERIFY Certificate_Usage = 1
Certificate_AUTHORITY_ISSUE Certificate_Usage = 2
)
// Enum value maps for Certificate_Usage.
var (
Certificate_Usage_name = map[int32]string{
0: "ENCIPHERMENT",
1: "AUTHORITY_VERIFY",
2: "AUTHORITY_ISSUE",
}
Certificate_Usage_value = map[string]int32{
"ENCIPHERMENT": 0,
"AUTHORITY_VERIFY": 1,
"AUTHORITY_ISSUE": 2,
}
)
func (x Certificate_Usage) Enum() *Certificate_Usage {
p := new(Certificate_Usage)
*p = x
return p
}
func (x Certificate_Usage) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Certificate_Usage) Descriptor() protoreflect.EnumDescriptor {
return file_transport_internet_xtls_config_proto_enumTypes[0].Descriptor()
}
func (Certificate_Usage) Type() protoreflect.EnumType {
return &file_transport_internet_xtls_config_proto_enumTypes[0]
}
func (x Certificate_Usage) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Certificate_Usage.Descriptor instead.
func (Certificate_Usage) EnumDescriptor() ([]byte, []int) {
return file_transport_internet_xtls_config_proto_rawDescGZIP(), []int{0, 0}
}
type Certificate struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// TLS certificate in x509 format.
Certificate []byte `protobuf:"bytes,1,opt,name=certificate,proto3" json:"certificate,omitempty"`
// TLS key in x509 format.
Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
Usage Certificate_Usage `protobuf:"varint,3,opt,name=usage,proto3,enum=xray.transport.internet.xtls.Certificate_Usage" json:"usage,omitempty"`
OcspStapling uint64 `protobuf:"varint,4,opt,name=ocsp_stapling,json=ocspStapling,proto3" json:"ocsp_stapling,omitempty"`
// TLS certificate path
CertificatePath string `protobuf:"bytes,5,opt,name=certificate_path,json=certificatePath,proto3" json:"certificate_path,omitempty"`
// TLS Key path
KeyPath string `protobuf:"bytes,6,opt,name=key_path,json=keyPath,proto3" json:"key_path,omitempty"`
// If true, one-Time Loading
OneTimeLoading bool `protobuf:"varint,7,opt,name=One_time_loading,json=OneTimeLoading,proto3" json:"One_time_loading,omitempty"`
}
func (x *Certificate) Reset() {
*x = Certificate{}
if protoimpl.UnsafeEnabled {
mi := &file_transport_internet_xtls_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Certificate) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Certificate) ProtoMessage() {}
func (x *Certificate) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_xtls_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 Certificate.ProtoReflect.Descriptor instead.
func (*Certificate) Descriptor() ([]byte, []int) {
return file_transport_internet_xtls_config_proto_rawDescGZIP(), []int{0}
}
func (x *Certificate) GetCertificate() []byte {
if x != nil {
return x.Certificate
}
return nil
}
func (x *Certificate) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
func (x *Certificate) GetUsage() Certificate_Usage {
if x != nil {
return x.Usage
}
return Certificate_ENCIPHERMENT
}
func (x *Certificate) GetOcspStapling() uint64 {
if x != nil {
return x.OcspStapling
}
return 0
}
func (x *Certificate) GetCertificatePath() string {
if x != nil {
return x.CertificatePath
}
return ""
}
func (x *Certificate) GetKeyPath() string {
if x != nil {
return x.KeyPath
}
return ""
}
func (x *Certificate) GetOneTimeLoading() bool {
if x != nil {
return x.OneTimeLoading
}
return false
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Whether or not to allow self-signed certificates.
AllowInsecure bool `protobuf:"varint,1,opt,name=allow_insecure,json=allowInsecure,proto3" json:"allow_insecure,omitempty"`
// List of certificates to be served on server.
Certificate []*Certificate `protobuf:"bytes,2,rep,name=certificate,proto3" json:"certificate,omitempty"`
// Override server name.
ServerName string `protobuf:"bytes,3,opt,name=server_name,json=serverName,proto3" json:"server_name,omitempty"`
// Lists of string as ALPN values.
NextProtocol []string `protobuf:"bytes,4,rep,name=next_protocol,json=nextProtocol,proto3" json:"next_protocol,omitempty"`
// Whether or not to enable session (ticket) resumption.
EnableSessionResumption bool `protobuf:"varint,5,opt,name=enable_session_resumption,json=enableSessionResumption,proto3" json:"enable_session_resumption,omitempty"`
// If true, root certificates on the system will not be loaded for
// verification.
DisableSystemRoot bool `protobuf:"varint,6,opt,name=disable_system_root,json=disableSystemRoot,proto3" json:"disable_system_root,omitempty"`
// The minimum TLS version.
MinVersion string `protobuf:"bytes,7,opt,name=min_version,json=minVersion,proto3" json:"min_version,omitempty"`
// The maximum TLS version.
MaxVersion string `protobuf:"bytes,8,opt,name=max_version,json=maxVersion,proto3" json:"max_version,omitempty"`
// Specify cipher suites, except for TLS 1.3.
CipherSuites string `protobuf:"bytes,9,opt,name=cipher_suites,json=cipherSuites,proto3" json:"cipher_suites,omitempty"`
// Whether the server selects its most preferred ciphersuite.
PreferServerCipherSuites bool `protobuf:"varint,10,opt,name=prefer_server_cipher_suites,json=preferServerCipherSuites,proto3" json:"prefer_server_cipher_suites,omitempty"`
RejectUnknownSni bool `protobuf:"varint,12,opt,name=reject_unknown_sni,json=rejectUnknownSni,proto3" json:"reject_unknown_sni,omitempty"`
// @Document A pinned certificate chain sha256 hash.
// @Document If the server's hash does not match this value, the connection will be aborted.
// @Document This value replace allow_insecure.
// @Critical
PinnedPeerCertificateChainSha256 [][]byte `protobuf:"bytes,13,rep,name=pinned_peer_certificate_chain_sha256,json=pinnedPeerCertificateChainSha256,proto3" json:"pinned_peer_certificate_chain_sha256,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_transport_internet_xtls_config_proto_msgTypes[1]
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_transport_internet_xtls_config_proto_msgTypes[1]
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_transport_internet_xtls_config_proto_rawDescGZIP(), []int{1}
}
func (x *Config) GetAllowInsecure() bool {
if x != nil {
return x.AllowInsecure
}
return false
}
func (x *Config) GetCertificate() []*Certificate {
if x != nil {
return x.Certificate
}
return nil
}
func (x *Config) GetServerName() string {
if x != nil {
return x.ServerName
}
return ""
}
func (x *Config) GetNextProtocol() []string {
if x != nil {
return x.NextProtocol
}
return nil
}
func (x *Config) GetEnableSessionResumption() bool {
if x != nil {
return x.EnableSessionResumption
}
return false
}
func (x *Config) GetDisableSystemRoot() bool {
if x != nil {
return x.DisableSystemRoot
}
return false
}
func (x *Config) GetMinVersion() string {
if x != nil {
return x.MinVersion
}
return ""
}
func (x *Config) GetMaxVersion() string {
if x != nil {
return x.MaxVersion
}
return ""
}
func (x *Config) GetCipherSuites() string {
if x != nil {
return x.CipherSuites
}
return ""
}
func (x *Config) GetPreferServerCipherSuites() bool {
if x != nil {
return x.PreferServerCipherSuites
}
return false
}
func (x *Config) GetRejectUnknownSni() bool {
if x != nil {
return x.RejectUnknownSni
}
return false
}
func (x *Config) GetPinnedPeerCertificateChainSha256() [][]byte {
if x != nil {
return x.PinnedPeerCertificateChainSha256
}
return nil
}
var File_transport_internet_xtls_config_proto protoreflect.FileDescriptor
var file_transport_internet_xtls_config_proto_rawDesc = []byte{
0x0a, 0x24, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
0x78, 0x74, 0x6c, 0x73, 0x22, 0xe3, 0x02, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69,
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x45, 0x0a, 0x05, 0x75, 0x73, 0x61, 0x67,
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74,
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
0x74, 0x2e, 0x78, 0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x65, 0x2e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x12,
0x23, 0x0a, 0x0d, 0x6f, 0x63, 0x73, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67,
0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x53, 0x74, 0x61, 0x70,
0x6c, 0x69, 0x6e, 0x67, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f,
0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12,
0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28,
0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x12, 0x28, 0x0a, 0x10, 0x4f, 0x6e,
0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x07,
0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x4f, 0x6e, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x61,
0x64, 0x69, 0x6e, 0x67, 0x22, 0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a,
0x0c, 0x45, 0x4e, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12,
0x14, 0x0a, 0x10, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52,
0x49, 0x46, 0x59, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49,
0x54, 0x59, 0x5f, 0x49, 0x53, 0x53, 0x55, 0x45, 0x10, 0x02, 0x22, 0xd2, 0x04, 0x0a, 0x06, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69,
0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61,
0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x4b, 0x0a, 0x0b,
0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x78, 0x74, 0x6c, 0x73,
0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x63, 0x65,
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6e, 0x65,
0x78, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x03, 0x28,
0x09, 0x52, 0x0c, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12,
0x3a, 0x0a, 0x19, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f,
0x6e, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01,
0x28, 0x08, 0x52, 0x17, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x64,
0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x72, 0x6f,
0x6f, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c,
0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6d,
0x69, 0x6e, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0a, 0x6d, 0x69, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b,
0x6d, 0x61, 0x78, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a,
0x0d, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65, 0x73, 0x18, 0x09,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74,
0x65, 0x73, 0x12, 0x3d, 0x0a, 0x1b, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x5f, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65,
0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x53,
0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65,
0x73, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x6e, 0x6b, 0x6e,
0x6f, 0x77, 0x6e, 0x5f, 0x73, 0x6e, 0x69, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72,
0x65, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x53, 0x6e, 0x69, 0x12,
0x4e, 0x0a, 0x24, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x63,
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e,
0x5f, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x20, 0x70,
0x69, 0x6e, 0x6e, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x42,
0x76, 0x0a, 0x20, 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, 0x2e, 0x78,
0x74, 0x6c, 0x73, 0x50, 0x01, 0x5a, 0x31, 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, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x1c, 0x58, 0x72, 0x61, 0x79, 0x2e,
0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x65, 0x74, 0x2e, 0x58, 0x74, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_transport_internet_xtls_config_proto_rawDescOnce sync.Once
file_transport_internet_xtls_config_proto_rawDescData = file_transport_internet_xtls_config_proto_rawDesc
)
func file_transport_internet_xtls_config_proto_rawDescGZIP() []byte {
file_transport_internet_xtls_config_proto_rawDescOnce.Do(func() {
file_transport_internet_xtls_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_xtls_config_proto_rawDescData)
})
return file_transport_internet_xtls_config_proto_rawDescData
}
var file_transport_internet_xtls_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_transport_internet_xtls_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_transport_internet_xtls_config_proto_goTypes = []interface{}{
(Certificate_Usage)(0), // 0: xray.transport.internet.xtls.Certificate.Usage
(*Certificate)(nil), // 1: xray.transport.internet.xtls.Certificate
(*Config)(nil), // 2: xray.transport.internet.xtls.Config
}
var file_transport_internet_xtls_config_proto_depIdxs = []int32{
0, // 0: xray.transport.internet.xtls.Certificate.usage:type_name -> xray.transport.internet.xtls.Certificate.Usage
1, // 1: xray.transport.internet.xtls.Config.certificate:type_name -> xray.transport.internet.xtls.Certificate
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_transport_internet_xtls_config_proto_init() }
func file_transport_internet_xtls_config_proto_init() {
if File_transport_internet_xtls_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_transport_internet_xtls_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Certificate); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_transport_internet_xtls_config_proto_msgTypes[1].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_transport_internet_xtls_config_proto_rawDesc,
NumEnums: 1,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_xtls_config_proto_goTypes,
DependencyIndexes: file_transport_internet_xtls_config_proto_depIdxs,
EnumInfos: file_transport_internet_xtls_config_proto_enumTypes,
MessageInfos: file_transport_internet_xtls_config_proto_msgTypes,
}.Build()
File_transport_internet_xtls_config_proto = out.File
file_transport_internet_xtls_config_proto_rawDesc = nil
file_transport_internet_xtls_config_proto_goTypes = nil
file_transport_internet_xtls_config_proto_depIdxs = nil
}

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