Compare commits

...

71 Commits

Author SHA1 Message Date
AkinoKaede
d67cf3d598 v1.3.1 2021-03-02 22:59:27 +08:00
kokeri
ca633fc8c5 Chore: Add GitHub Actions (#251)
Co-authored-by: xinb <netwhilt@outlook.com>
Co-authored-by: 秋のかえで <autmaple@protonmail.com>
Co-authored-by: Jim Han <50871214+JimhHan@users.noreply.github.com>
2021-03-02 22:46:50 +08:00
Xray9
c345d4818e Fix available mux picker in reverse portal (#274) 2021-03-01 07:26:53 +00:00
Jim Han
7fb1f65354 Fix https://github.com/XTLS/Xray-core/issues/289 (#300) 2021-03-01 02:43:27 +00:00
RPRX
4b97edae74 Fix https://github.com/XTLS/Xray-core/issues/320 2021-03-01 01:29:17 +00:00
Kid
8aabbeefe1 Add /opt to assets location (#312) 2021-02-27 23:09:44 +08:00
RPRX
48fab4d398 Add Xray_onekey 2021-02-22 02:21:17 +00:00
RPRX
8b9c0ae593 Enable (X)TLS hot reloading by default (#281)
Super BiuBiu
2021-02-20 02:15:57 +00:00
秋のかえで
347d9735da Remove (x)tls.WithNextProto("h2") in tcp/hub.go (#260) 2021-02-18 11:50:09 +00:00
Jim Han
9aa49be703 Restrict tag to be unique (#258) 2021-02-18 09:53:10 +00:00
RPRX
fed8610d3f Fix Freedom Outbound UDP redirect
已检查 b.UDP 各源头:Mux(VLESS、VMess)、Trojan、Shadowsocks、Socks、TPROXY(Dokodemo-door)
2021-02-17 13:37:55 +00:00
RPRX
d22c2d034c Avoid panic in KDF func for Go 1.16
2a206c7fcc
2021-02-17 03:02:03 +00:00
RPRX
4c10a9eb4e Add Xray-yes 2021-02-15 10:50:30 +00:00
RPRX
4ff1ff1d7d Add Netch (NetFilter & TUN/TAP) 2021-02-15 09:10:19 +00:00
RPRX
573b7807c0 v1.3.0 2021-02-12 15:59:56 +00:00
eMeab
81d993158f Support hot reloading of certificate and key files (#225) 2021-02-12 15:33:19 +00:00
秋のかえで
df39991bb3 Refactor: Add Shadowsocks Validator (#233) 2021-02-12 15:17:31 +00:00
Monsoon
1b87264c53 Support loading config from different formats (#228) 2021-02-12 14:12:58 +00:00
秋のかえで
96d7156eba Fix a typo (#236) 2021-02-12 13:23:30 +00:00
RPRX
d170416219 Add environment variable XRAY_CONE_DISABLED option 2021-02-11 15:37:02 +00:00
RPRX
8ca8a7126b Add XUDP support by simply renaming vudp to xudp
https://t.me/projectXray/243505
2021-02-11 11:33:08 +00:00
RPRX
1174ff3090 Refactor: VLESS & VMess & Mux UDP FullCone NAT
https://t.me/projectXray/242770
2021-02-11 01:28:21 +00:00
RPRX
523c416bb5 v1.2.4 2021-01-31 11:56:39 +00:00
eMeab
c13b8ec9bb Fix OCSP Stapling (#172)
Co-authored-by: RPRX <63339210+rprx@users.noreply.github.com>
2021-01-30 23:17:07 +00:00
Jim Han
4cd343f2d5 Fix tests (#201)
Co-authored-by: RPRX <63339210+rprx@users.noreply.github.com>
2021-01-30 13:01:20 +00:00
RPRX
d032a8deb7 Fix acceptProxyProtocol
https://github.com/XTLS/Xray-core/pull/182#issuecomment-768336178
2021-01-28 12:08:57 +00:00
RPRX
303fd6e261 Standardize Socks Outbound Authentication Behavior 2021-01-28 03:11:17 +00:00
RPRX
c880b916ee Avoid panic in BytesTo func 2021-01-27 01:09:58 +00:00
RPRX
ceff4185dc Improve the request for UDP Associate in Socks5 2021-01-26 23:53:01 +00:00
RPRX
59c7c4897c Add luci-app-xray (openwrt-xray) 2021-01-26 22:50:28 +00:00
RPRX
8ffc430351 Fix VLESS & Trojan fallbacks xver 2021-01-23 21:06:15 +00:00
RPRX
7da97635b2 v1.2.3 2021-01-22 04:00:03 +00:00
Arthur Morgan
ba41513967 Changes from v2fly-core (#173) 2021-01-22 03:35:56 +00:00
Bohan Yang
5bc1bf30ae Fix fallbacks xver when original address is not TCP address (#182)
Co-authored-by: RPRX <63339210+rprx@users.noreply.github.com>
2021-01-22 03:26:57 +00:00
Arthur Morgan
5aa053a65f Convert domain names to lowercase before matching (#195)
Co-authored-by: RPRX <63339210+rprx@users.noreply.github.com>
2021-01-21 23:37:55 +00:00
秋のかえで
0b4858d016 Feature: Exclude some domains in sniffing destOverride (#151)
Co-authored-by: RPRX <63339210+rprx@users.noreply.github.com>
2021-01-21 20:50:09 +00:00
Jim Han
7f5e34c857 Regenerate .pb.go files (#187)
Co-authored-by: RPRX <63339210+rprx@users.noreply.github.com>
2021-01-21 18:58:19 +00:00
RPRX
b60cf02603 Optimize TPROXY Inbound UDP write back
Enhanced stability.
2021-01-20 23:58:59 +00:00
RPRX
ae98dc75cf Set unix.SO_REUSEPORT=1 for TPROXY Inbound FakeUDP
Solved some issues.
2021-01-19 14:50:21 +00:00
RPRX
8ff43519fd Fix Shadowsocks tests; AEAD drop small UDP packets
https://t.me/projectXray/172063
2021-01-19 10:35:30 +00:00
RPRX
33755d6e90 Refactor: Shadowsocks AEAD Single-port Multi-user (Needs Optimizations)
https://t.me/projectXray/170851
2021-01-18 22:52:35 +00:00
RPRX
99863aa2ac Add SNI shunt support for Trojan fallbacks 2021-01-18 07:41:00 +00:00
RPRX
8eed8a0824 v1.2.2 2021-01-15 13:18:37 +00:00
RPRX
88f6537540 Make necessary maps in non-empty names before copy 2021-01-15 11:36:31 +00:00
RPRX
f0efc0cfde As substring to match in VLESS fallbacks SNI shunt 2021-01-15 09:43:39 +00:00
RPRX
f13ac3cb55 Fix VLESS fallbacks SNI shunt 2021-01-14 21:55:52 +00:00
eMeab
638e8384b6 Optimized log (#167) 2021-01-14 14:45:23 +00:00
eMeab
d85162ea44 Add SNI shunt support for VLESS (#141) 2021-01-13 15:13:51 +00:00
Arthur Morgan
11a851f957 Fix non-local DoH requests & Apply routing (#147) 2021-01-13 07:53:08 +00:00
RPRX
822afb0cc8 Improve UUID generator
https://github.com/XTLS/Xray-core/issues/158
2021-01-12 18:23:54 +00:00
RPRX
157918859f Add pre-checking conversion for VLESS & VMess UUID
https://github.com/XTLS/Xray-core/issues/158
2021-01-12 11:31:02 +00:00
RPRX
40271c09a0 Support for VLESS & VMess UUID v5 mapping standard
https://github.com/XTLS/Xray-core/issues/158
2021-01-11 17:56:33 +00:00
maskedeken
96adf3fbca Trojan: Do not panic when UDP dispatcher failed to write response (#153) 2021-01-11 09:30:57 +00:00
RPRX
e254424c43 v1.2.1 2021-01-10 07:58:53 +00:00
RPRX
ee15cc253f Improve configuration detector (cone or symmetric) 2021-01-10 07:50:21 +00:00
RPRX
43eb5d1b25 16 -> 60, 8 -> 300
https://github.com/XTLS/Xray-core/issues/129#issuecomment-757355137

十分感谢 @GleenJi 等协助测试
2021-01-10 04:50:26 +00:00
RPRX
700966508f Improve the response to UDP Associate in Socks5 2021-01-09 16:36:20 +00:00
RPRX
7427a55ef1 Adjust Trojan Outbound postRequest 2021-01-08 12:00:46 +00:00
RPRX
fb0e517158 Adjust Trojan & Socks handleUDPPayload 2021-01-08 06:00:51 +00:00
maskedeken
d5aeb6c545 Refine Trojan packet reader & writer (#142) 2021-01-08 03:55:25 +00:00
RPRX
161e18299c Fix TPROXY UDP/IPv6
https://github.com/XTLS/Xray-core/issues/137#issuecomment-756064627

十分感谢 @Ninedyz @changyp6
2021-01-07 12:21:27 +00:00
eMeab
be9421fedf Optimized log (#121) 2021-01-04 05:05:38 +00:00
RPRX
8fc2d3b61f v1.2.0 2021-01-01 12:30:16 +00:00
秋のかえで
9d4038427d Enable loading TOML & YAML by confdir (#120) 2021-01-01 12:16:22 +00:00
秋のかえで
38ec9208d8 Change TOML package to github.com/pelletier/go-toml (#119) 2021-01-01 11:37:38 +00:00
RPRX
7df135a5c4 Disable session resumption by default
https://github.com/v2fly/v2ray-core/issues/557#issuecomment-751962569
2021-01-01 11:33:09 +00:00
RPRX
c41a1a56fe Refactor: TPROXY inbound UDP write back
https://t.me/projectXray/119670

虽然不一定是最终的版本,但值得记录,感谢协助测试的各位朋友,特别感谢 @yichya @huyz
2020-12-31 15:57:15 +00:00
RPRX
310a938511 VLESS & VMess are not ready to accept FullCone yet 2020-12-30 08:10:26 +00:00
RPRX
2da07e0f8a Refactor: FullCone TPROXY Inbound & Socks Outbound
https://t.me/projectXray/116037
2020-12-29 11:50:17 +00:00
RPRX
13ad3fddf6 Refactor: *net.UDPAddr -> *net.Destination
https://t.me/projectXray/111998
2020-12-28 09:40:28 +00:00
RPRX
6bcac6cb10 Move common/net/connection.go into cnc folder 2020-12-28 03:20:39 +08:00
104 changed files with 2569 additions and 927 deletions

33
.github/build/friendly-filenames.json vendored Normal file
View File

@@ -0,0 +1,33 @@
{
"android-arm64": { "friendlyName": "android-arm64-v8a"},
"darwin-amd64": { "friendlyName": "macos-64" },
"darwin-arm64": { "friendlyName": "macos-arm64-v8a" },
"dragonfly-amd64": { "friendlyName": "dragonfly-64" },
"freebsd-386": { "friendlyName": "freebsd-32" },
"freebsd-amd64": { "friendlyName": "freebsd-64" },
"freebsd-arm64": { "friendlyName": "freebsd-arm64-v8a" },
"freebsd-arm7": { "friendlyName": "freebsd-arm32-v7a" },
"linux-386": { "friendlyName": "linux-32" },
"linux-amd64": { "friendlyName": "linux-64" },
"linux-arm5": { "friendlyName": "linux-arm32-v5" },
"linux-arm64": { "friendlyName": "linux-arm64-v8a" },
"linux-arm6": { "friendlyName": "linux-arm32-v6" },
"linux-arm7": { "friendlyName": "linux-arm32-v7a" },
"linux-mips64le": { "friendlyName": "linux-mips64le" },
"linux-mips64": { "friendlyName": "linux-mips64" },
"linux-mipsle": { "friendlyName": "linux-mips32le" },
"linux-mipslesoftfloat": { "friendlyName": "linux-mips32le-softfloat" },
"linux-mips": { "friendlyName": "linux-mips32" },
"linux-mipssoftfloat": { "friendlyName": "linux-mips32-softfloat" },
"linux-riscv64": { "friendlyName": "linux-riscv64" },
"linux-ppc64": { "friendlyName": "linux-ppc64" },
"linux-ppc64le": { "friendlyName": "linux-rppc64le" },
"linux-s390x": { "friendlyName": "linux-s390x" },
"openbsd-386": { "friendlyName": "openbsd-32" },
"openbsd-amd64": { "friendlyName": "openbsd-64" },
"openbsd-arm64": { "friendlyName": "openbsd-arm64-v8a" },
"openbsd-arm7": { "friendlyName": "openbsd-arm32-v7a" },
"windows-amd64": { "friendlyName": "windows-64" },
"windows-386": { "friendlyName": "windows-32" },
"windows-arm7": { "friendlyName": "windows-arm32-v7a" }
}

212
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,212 @@
name: Build and Release
on:
workflow_dispatch:
release:
types: [published]
push:
branches:
- main
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
jobs:
build:
strategy:
matrix:
# Include amd64 on all platforms.
goos: [windows, freebsd, openbsd, linux, dragonfly, darwin]
goarch: [amd64, 386]
exclude:
# Exclude i386 on darwin and dragonfly.
- goarch: 386
goos: dragonfly
- goarch: 386
goos: darwin
include:
# BEIGIN MacOS ARM64
- goos: darwin
goarch: arm64
# END MacOS ARM64
# BEGIN Linux ARM 5 6 7
- goos: linux
goarch: arm
goarm: 7
- goos: linux
goarch: arm
goarm: 6
- goos: linux
goarch: arm
goarm: 5
# END Linux ARM 5 6 7
# BEGIN Android ARM 8
- goos: android
goarch: arm64
# END Android ARM 8
# Windows ARM 7
- goos: windows
goarch: arm
goarm: 7
# BEGIN Other architectures
# BEGIN riscv64 & ARM64
- goos: linux
goarch: arm64
- goos: linux
goarch: riscv64
# END riscv64 & ARM64
# BEGIN MIPS
- goos: linux
goarch: mips64
- goos: linux
goarch: mips64le
- goos: linux
goarch: mipsle
- goos: linux
goarch: mips
# END MIPS
# BEGIN PPC
- goos: linux
goarch: ppc64
- goos: linux
goarch: ppc64le
# END PPC
# BEGIN FreeBSD ARM
- goos: freebsd
goarch: arm64
- goos: freebsd
goarch: arm
goarm: 7
# END FreeBSD ARM
# BEGIN S390X
- goos: linux
goarch: s390x
# END S390X
# END Other architectures
# BEGIN OPENBSD ARM
- goos: openbsd
goarch: arm64
- goos: openbsd
goarch: arm
goarm: 7
# END OPENBSD ARM
fail-fast: false
#配置编译环境
runs-on: ubuntu-20.04
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
GOARM: ${{ matrix.goarm }}
CGO_ENABLED: 0
steps:
- name: Checkout codebase
uses: actions/checkout@v2
- name: Show workflow information
id: get_filename
run: |
export _NAME=$(jq ".[\"$GOOS-$GOARCH$GOARM$GOMIPS\"].friendlyName" -r < .github/build/friendly-filenames.json)
echo "GOOS: $GOOS, GOARCH: $GOARCH, GOARM: $GOARM, GOMIPS: $GOMIPS, RELEASE_NAME: $_NAME"
echo "::set-output name=ASSET_NAME::$_NAME"
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ^1.16
- name: Get project dependencies
run: go mod download
- name: Replace Custom to Commit ID
if: github.event_name != 'release'
run: |
ID=$(git rev-parse --short ${{ github.sha }})
if [ "${{ github.event_name }}" == 'pull_request' ]
then
ID=$(git rev-parse --short ${{ github.event.pull_request.head.sha }})
fi
sed -i '/build/ s/Custom/'$ID'/' ./core/core.go
- name: Build Xray
run: |
mkdir -p build_assets
go build -v -o build_assets/xray -trimpath -ldflags "-s -w -buildid=" ./main
- name: Build Mips softfloat Xray
if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle'
run: |
GOMIPS=softfloat go build -v -o build_assets/xray_softfloat -trimpath -ldflags "-s -w -buildid=" ./main
- name: Rename Windows Xray
if: matrix.goos == 'windows'
run: |
cd ./build_assets || exit 1
mv xray xray.exe
- name: Prepare to release
run: |
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
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}'))
LASTEST_TAG="$(curl -sL "https://api.github.com/repos/v2fly/${INFO[0]}/releases" | jq -r ".[0].tag_name" || echo "latest")"
FILE_NAME="${INFO[2]}.dat"
echo -e "Downloading ${FILE_NAME}..."
curl -L "https://github.com/v2fly/${INFO[0]}/releases/download/${LASTEST_TAG}/${INFO[1]}.dat" -o ./build_assets/${FILE_NAME}
echo -e "Verifying HASH key..."
HASH="$(curl -sL "https://github.com/v2fly/${INFO[0]}/releases/download/${LASTEST_TAG}/${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
shell: bash
run: |
pushd build_assets || exit 1
touch -mt 202101010000 *
zip -9vr ../Xray-$ASSET_NAME.zip .
for CORE in $(ls xray*)
do
COREDGST=$CORE.dgst
for METHOD in {"md5","sha1","sha256","sha512"}
do
openssl dgst -$METHOD $CORE | sed 's/([^)]*)//g' >>$COREDGST
done
done
popd || exit 1
FILE=./Xray-$ASSET_NAME.zip
DGST=$FILE.dgst
for METHOD in {"md5","sha1","sha256","sha512"}
do
openssl dgst -$METHOD $FILE | sed 's/([^)]*)//g' >>$DGST
done
- name: Change the name
run: |
mv build_assets Xray-$ASSET_NAME
- name: Upload files to Artifacts
uses: actions/upload-artifact@v2
with:
name: Xray-${{ steps.get_filename.outputs.ASSET_NAME }}
path: |
./Xray-${{ steps.get_filename.outputs.ASSET_NAME }}/*
- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
if: github.event_name == 'release'
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ./Xray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip*
tag: ${{ github.ref }}
file_glob: true

48
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: Test
on:
push:
branches:
- main
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
steps:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ^1.16
- name: Checkout codebase
uses: actions/checkout@v2
- name: Prepare geo*dat
if: ${{ matrix.os != 'windows-latest' }}
run: |
mkdir resources
wget -O ./resources/geoip.dat https://github.com/v2fly/geoip/releases/latest/download/geoip.dat
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
run: go test -timeout 1h -v ./...

View File

@@ -17,6 +17,8 @@
- One Click - One Click
- [ProxySU](https://github.com/proxysu/ProxySU) - [ProxySU](https://github.com/proxysu/ProxySU)
- [v2ray-agent](https://github.com/mack-a/v2ray-agent) - [v2ray-agent](https://github.com/mack-a/v2ray-agent)
- [Xray-yes](https://github.com/jiuqi9997/Xray-yes)
- [Xray_onekey](https://github.com/wulabing/Xray_onekey)
- Magisk - Magisk
- [Xray4Magisk](https://github.com/CerteKim/Xray4Magisk) - [Xray4Magisk](https://github.com/CerteKim/Xray4Magisk)
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk) - [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
@@ -34,9 +36,11 @@
- [PassWall](https://github.com/xiaorouji/openwrt-passwall) - [PassWall](https://github.com/xiaorouji/openwrt-passwall)
- [Hello World](https://github.com/jerrykuku/luci-app-vssr) - [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))
- Windows - Windows
- [v2rayN](https://github.com/2dust/v2rayN) - [v2rayN](https://github.com/2dust/v2rayN)
- [Qv2ray](https://github.com/Qv2ray/Qv2ray) - [Qv2ray](https://github.com/Qv2ray/Qv2ray)
- [Netch (NetFilter & TUN/TAP)](https://github.com/NetchX/Netch)
- Android - Android
- [v2rayNG](https://github.com/2dust/v2rayNG) - [v2rayNG](https://github.com/2dust/v2rayNG)
- [Kitsunebi](https://github.com/rurirei/Kitsunebi/tree/release_xtls) - [Kitsunebi](https://github.com/rurirei/Kitsunebi/tree/release_xtls)

View File

@@ -6,6 +6,7 @@ import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/done"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
) )
@@ -79,7 +80,7 @@ func (co *Outbound) Dispatch(ctx context.Context, link *transport.Link) {
} }
closeSignal := done.New() closeSignal := done.New()
c := net.NewConnection(net.ConnectionInputMulti(link.Writer), net.ConnectionOutputMulti(link.Reader), net.ConnectionOnClose(closeSignal)) c := cnc.NewConnection(cnc.ConnectionInputMulti(link.Writer), cnc.ConnectionOutputMulti(link.Reader), cnc.ConnectionOnClose(closeSignal))
co.listener.add(c) co.listener.add(c)
co.access.RUnlock() co.access.RUnlock()
<-closeSignal.Wait() <-closeSignal.Wait()

View File

@@ -175,12 +175,21 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
return inboundLink, outboundLink return inboundLink, outboundLink
} }
func shouldOverride(result SniffResult, domainOverride []string) bool { func shouldOverride(result SniffResult, request session.SniffingRequest) bool {
for _, p := range domainOverride { domain := result.Domain()
if strings.HasPrefix(result.Protocol(), p) { for _, d := range request.ExcludeForDomain {
if domain == d {
return false
}
}
protocol := result.Protocol()
for _, p := range request.OverrideDestinationForProtocol {
if strings.HasPrefix(protocol, p) {
return true return true
} }
} }
return false return false
} }
@@ -213,7 +222,7 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
if err == nil { if err == nil {
content.Protocol = result.Protocol() content.Protocol = result.Protocol()
} }
if err == nil && shouldOverride(result, sniffingRequest.OverrideDestinationForProtocol) { if err == nil && shouldOverride(result, sniffingRequest) {
domain := result.Domain() domain := result.Domain()
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx)) newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
destination.Address = net.ParseAddress(domain) destination.Address = net.ParseAddress(domain)
@@ -263,14 +272,18 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
skipRoutePick = content.SkipRoutePick skipRoutePick = content.SkipRoutePick
} }
routingLink := routing_session.AsRoutingContext(ctx)
inTag := routingLink.GetInboundTag()
isPickRoute := false
if d.router != nil && !skipRoutePick { if d.router != nil && !skipRoutePick {
if route, err := d.router.PickRoute(routing_session.AsRoutingContext(ctx)); err == nil { if route, err := d.router.PickRoute(routingLink); err == nil {
tag := route.GetOutboundTag() outTag := route.GetOutboundTag()
if h := d.ohm.GetHandler(tag); h != nil { isPickRoute = true
newError("taking detour [", tag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx)) if h := d.ohm.GetHandler(outTag); h != nil {
newError("taking detour [", outTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
handler = h handler = h
} else { } else {
newError("non existing tag: ", tag).AtWarning().WriteToLog(session.ExportIDToError(ctx)) newError("non existing outTag: ", outTag).AtWarning().WriteToLog(session.ExportIDToError(ctx))
} }
} else { } else {
newError("default route for ", destination).WriteToLog(session.ExportIDToError(ctx)) newError("default route for ", destination).WriteToLog(session.ExportIDToError(ctx))
@@ -290,7 +303,19 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil { if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil {
if tag := handler.Tag(); tag != "" { if tag := handler.Tag(); tag != "" {
accessMessage.Detour = tag if isPickRoute {
if inTag != "" {
accessMessage.Detour = inTag + " -> " + tag
} else {
accessMessage.Detour = tag
}
} else {
if inTag != "" {
accessMessage.Detour = inTag + " >> " + tag
} else {
accessMessage.Detour = tag
}
}
} }
log.Record(accessMessage) log.Record(accessMessage)
} }

View File

@@ -14,6 +14,7 @@ import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/protocol/dns" "github.com/xtls/xray-core/common/protocol/dns"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal/pubsub" "github.com/xtls/xray-core/common/signal/pubsub"
@@ -28,6 +29,7 @@ import (
// which is compatible with traditional dns over udp(RFC1035), // which is compatible with traditional dns over udp(RFC1035),
// thus most of the DOH implementation is copied from udpns.go // thus most of the DOH implementation is copied from udpns.go
type DoHNameServer struct { type DoHNameServer struct {
dispatcher routing.Dispatcher
sync.RWMutex sync.RWMutex
ips map[string]record ips map[string]record
pub *pubsub.Service pub *pubsub.Service
@@ -44,40 +46,8 @@ func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, clientIP net.
newError("DNS: created Remote DOH client for ", url.String()).AtInfo().WriteToLog() newError("DNS: created Remote DOH client for ", url.String()).AtInfo().WriteToLog()
s := baseDOHNameServer(url, "DOH", clientIP) s := baseDOHNameServer(url, "DOH", clientIP)
// Dispatched connection will be closed (interrupted) after each request s.dispatcher = dispatcher
// This makes DOH inefficient without a keep-alived connection
// See: core/app/proxyman/outbound/handler.go:113
// Using mux (https request wrapped in a stream layer) improves the situation.
// Recommend to use NewDoHLocalNameServer (DOHL:) if xray instance is running on
// a normal network eg. the server side of xray
tr := &http.Transport{
MaxIdleConns: 30,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 30 * time.Second,
ForceAttemptHTTP2: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dest, err := net.ParseDestination(network + ":" + addr)
if err != nil {
return nil, err
}
link, err := dispatcher.Dispatch(ctx, dest)
if err != nil {
return nil, err
}
return net.NewConnection(
net.ConnectionInputMulti(link.Writer),
net.ConnectionOutputMulti(link.Reader),
), nil
},
}
dispatchedClient := &http.Client{
Transport: tr,
Timeout: 60 * time.Second,
}
s.httpClient = dispatchedClient
return s, nil return s, nil
} }
@@ -210,6 +180,11 @@ func (s *DoHNameServer) newReqID() uint16 {
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, option IPOption) { func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, option IPOption) {
newError(s.name, " querying: ", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx)) newError(s.name, " querying: ", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx))
if s.name+"." == "DOH//"+domain {
newError(s.name, " tries to resolve itself! Use IP or set \"hosts\" instead.").AtError().WriteToLog(session.ExportIDToError(ctx))
return
}
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP)) reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP))
var deadline time.Time var deadline time.Time
@@ -231,12 +206,12 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, option IPO
} }
dnsCtx = session.ContextWithContent(dnsCtx, &session.Content{ dnsCtx = session.ContextWithContent(dnsCtx, &session.Content{
Protocol: "https", Protocol: "https",
SkipRoutePick: true, //SkipRoutePick: true,
}) })
// forced to use mux for DOH // forced to use mux for DOH
dnsCtx = session.ContextWithMuxPrefered(dnsCtx, true) // dnsCtx = session.ContextWithMuxPrefered(dnsCtx, true)
var cancel context.CancelFunc var cancel context.CancelFunc
dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline) dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline)
@@ -244,17 +219,17 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, option IPO
b, err := dns.PackMessage(r.msg) b, err := dns.PackMessage(r.msg)
if err != nil { if err != nil {
newError("failed to pack dns query").Base(err).AtError().WriteToLog() newError("failed to pack dns query for ", domain).Base(err).AtError().WriteToLog()
return return
} }
resp, err := s.dohHTTPSContext(dnsCtx, b.Bytes()) resp, err := s.dohHTTPSContext(dnsCtx, b.Bytes())
if err != nil { if err != nil {
newError("failed to retrieve response").Base(err).AtError().WriteToLog() newError("failed to retrieve response for ", domain).Base(err).AtError().WriteToLog()
return return
} }
rec, err := parseResponse(resp) rec, err := parseResponse(resp)
if err != nil { if err != nil {
newError("failed to handle DOH response").Base(err).AtError().WriteToLog() newError("failed to handle DOH response for ", domain).Base(err).AtError().WriteToLog()
return return
} }
s.updateIP(r, rec) s.updateIP(r, rec)
@@ -272,7 +247,44 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
req.Header.Add("Accept", "application/dns-message") req.Header.Add("Accept", "application/dns-message")
req.Header.Add("Content-Type", "application/dns-message") req.Header.Add("Content-Type", "application/dns-message")
resp, err := s.httpClient.Do(req.WithContext(ctx)) hc := s.httpClient
// Dispatched connection will be closed (interrupted) after each request
// This makes DOH inefficient without a keep-alived connection
// See: core/app/proxyman/outbound/handler.go:113
// Using mux (https request wrapped in a stream layer) improves the situation.
// Recommend to use NewDoHLocalNameServer (DOHL:) if xray instance is running on
// a normal network eg. the server side of xray
if s.dispatcher != nil {
tr := &http.Transport{
MaxIdleConns: 30,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 30 * time.Second,
ForceAttemptHTTP2: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dest, err := net.ParseDestination(network + ":" + addr)
if err != nil {
return nil, err
}
link, err := s.dispatcher.Dispatch(ctx, dest)
if err != nil {
return nil, err
}
return cnc.NewConnection(
cnc.ConnectionInputMulti(link.Writer),
cnc.ConnectionOutputMulti(link.Reader),
), nil
},
}
hc = &http.Client{
Timeout: time.Second * 180,
Transport: tr,
}
}
resp, err := hc.Do(req.WithContext(ctx))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -364,6 +364,7 @@ func (s *Server) lookupIPInternal(domain string, option IPOption) ([]net.IP, err
if domain == "" { if domain == "" {
return nil, newError("empty domain name") return nil, newError("empty domain name")
} }
domain = strings.ToLower(domain)
// normalize the FQDN form query // normalize the FQDN form query
if domain[len(domain)-1] == '.' { if domain[len(domain)-1] == '.' {

View File

@@ -101,8 +101,8 @@ func (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
rr, _ := dns.NewRR("localhost-b. IN A 127.0.0.4") rr, _ := dns.NewRR("localhost-b. IN A 127.0.0.4")
ans.Answer = append(ans.Answer, rr) ans.Answer = append(ans.Answer, rr)
case q.Name == "Mijia\\ Cloud." && q.Qtype == dns.TypeA: case q.Name == "mijia\\ cloud." && q.Qtype == dns.TypeA:
rr, _ := dns.NewRR("Mijia\\ Cloud. IN A 127.0.0.1") rr, _ := dns.NewRR("mijia\\ cloud. IN A 127.0.0.1")
ans.Answer = append(ans.Answer, rr) ans.Answer = append(ans.Answer, rr)
} }
} }

View File

@@ -44,7 +44,7 @@ func (s *service) Register(server *grpc.Server) {
RegisterLoggerServiceServer(server, ls) RegisterLoggerServiceServer(server, ls)
// For compatibility purposes // For compatibility purposes
vCoreDesc := _LoggerService_serviceDesc vCoreDesc := LoggerService_ServiceDesc
vCoreDesc.ServiceName = "v2ray.core.app.log.command.LoggerService" vCoreDesc.ServiceName = "v2ray.core.app.log.command.LoggerService"
server.RegisterService(&vCoreDesc, ls) server.RegisterService(&vCoreDesc, ls)
} }

View File

@@ -11,6 +11,7 @@ import (
// This is a compile-time assertion to ensure that this generated file // This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against. // is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7 const _ = grpc.SupportPackageIsVersion7
// LoggerServiceClient is the client API for LoggerService service. // LoggerServiceClient is the client API for LoggerService service.
@@ -62,7 +63,7 @@ type UnsafeLoggerServiceServer interface {
} }
func RegisterLoggerServiceServer(s grpc.ServiceRegistrar, srv LoggerServiceServer) { func RegisterLoggerServiceServer(s grpc.ServiceRegistrar, srv LoggerServiceServer) {
s.RegisterService(&_LoggerService_serviceDesc, srv) s.RegisterService(&LoggerService_ServiceDesc, srv)
} }
func _LoggerService_RestartLogger_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _LoggerService_RestartLogger_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
@@ -83,7 +84,10 @@ func _LoggerService_RestartLogger_Handler(srv interface{}, ctx context.Context,
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
var _LoggerService_serviceDesc = grpc.ServiceDesc{ // LoggerService_ServiceDesc is the grpc.ServiceDesc for LoggerService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var LoggerService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "xray.app.log.command.LoggerService", ServiceName: "xray.app.log.command.LoggerService",
HandlerType: (*LoggerServiceServer)(nil), HandlerType: (*LoggerServiceServer)(nil),
Methods: []grpc.MethodDesc{ Methods: []grpc.MethodDesc{

View File

@@ -140,7 +140,7 @@ func (s *service) Register(server *grpc.Server) {
RegisterHandlerServiceServer(server, hs) RegisterHandlerServiceServer(server, hs)
// For compatibility purposes // For compatibility purposes
vCoreDesc := _HandlerService_serviceDesc vCoreDesc := HandlerService_ServiceDesc
vCoreDesc.ServiceName = "v2ray.core.app.proxyman.command.HandlerService" vCoreDesc.ServiceName = "v2ray.core.app.proxyman.command.HandlerService"
server.RegisterService(&vCoreDesc, hs) server.RegisterService(&vCoreDesc, hs)
} }

View File

@@ -11,6 +11,7 @@ import (
// This is a compile-time assertion to ensure that this generated file // This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against. // is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7 const _ = grpc.SupportPackageIsVersion7
// HandlerServiceClient is the client API for HandlerService service. // HandlerServiceClient is the client API for HandlerService service.
@@ -132,7 +133,7 @@ type UnsafeHandlerServiceServer interface {
} }
func RegisterHandlerServiceServer(s grpc.ServiceRegistrar, srv HandlerServiceServer) { func RegisterHandlerServiceServer(s grpc.ServiceRegistrar, srv HandlerServiceServer) {
s.RegisterService(&_HandlerService_serviceDesc, srv) s.RegisterService(&HandlerService_ServiceDesc, srv)
} }
func _HandlerService_AddInbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _HandlerService_AddInbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
@@ -243,7 +244,10 @@ func _HandlerService_AlterOutbound_Handler(srv interface{}, ctx context.Context,
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
var _HandlerService_serviceDesc = grpc.ServiceDesc{ // HandlerService_ServiceDesc is the grpc.ServiceDesc for HandlerService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var HandlerService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "xray.app.proxyman.command.HandlerService", ServiceName: "xray.app.proxyman.command.HandlerService",
HandlerType: (*HandlerServiceServer)(nil), HandlerType: (*HandlerServiceServer)(nil),
Methods: []grpc.MethodDesc{ Methods: []grpc.MethodDesc{

View File

@@ -241,6 +241,7 @@ type SniffingConfig struct {
// Override target destination if sniff'ed protocol is in the given list. // Override target destination if sniff'ed protocol is in the given list.
// Supported values are "http", "tls". // Supported values are "http", "tls".
DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"` DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
DomainsExcluded []string `protobuf:"bytes,3,rep,name=domains_excluded,json=domainsExcluded,proto3" json:"domains_excluded,omitempty"`
} }
func (x *SniffingConfig) Reset() { func (x *SniffingConfig) Reset() {
@@ -289,6 +290,13 @@ func (x *SniffingConfig) GetDestinationOverride() []string {
return nil return nil
} }
func (x *SniffingConfig) GetDomainsExcluded() []string {
if x != nil {
return x.DomainsExcluded
}
return nil
}
type ReceiverConfig struct { type ReceiverConfig struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -756,92 +764,95 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12,
0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52,
0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72,
0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0x5d, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0x88, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69,
0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62,
0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c,
0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65,
0x72, 0x69, 0x64, 0x65, 0x22, 0x90, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73,
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x5f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52,
0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x22, 0x90, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e,
0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x67,
0x67, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61,
0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x33,
0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, 0x73,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,
0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4e, 0x0a, 0x0f, 0x73,
0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04,
0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53,
0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72,
0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x72,
0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f,
0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28,
0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e,
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4b, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a,
0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x42, 0x02, 0x18, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
0x01, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
0x65, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e,
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e, 0x64,
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x4e, 0x0a,
0x2e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x10, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x73, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e, 0x69,
0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e, 0x69,
0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04, 0x08,
0x61, 0x67, 0x12, 0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x4d,
0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x73, 0x12, 0x47, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54,
0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x10, 0x72, 0x65, 0x63,
0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47, 0x0a,
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xb0, 0x02, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65,
0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75,
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xb0, 0x02, 0x0a, 0x0c, 0x53, 0x65, 0x6e,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x03, 0x76, 0x69, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d,
0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65,
0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d,
0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78,
0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79,
0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74,
0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c,
0x50, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f,
0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69,
0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x50, 0x0a, 0x12, 0x4d,
0x79, 0x2a, 0x23, 0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x6f, 0x6c, 0x73, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01,
0x03, 0x54, 0x4c, 0x53, 0x10, 0x01, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63,
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2a, 0x23, 0x0a,
0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12,
0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x4c, 0x53,
0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x10, 0x01, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
0x72, 0x6f, 0x74, 0x6f, 0x33, 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

@@ -56,6 +56,7 @@ message SniffingConfig {
// Override target destination if sniff'ed protocol is in the given list. // Override target destination if sniff'ed protocol is in the given list.
// Supported values are "http", "tls". // Supported values are "http", "tls".
repeated string destination_override = 2; repeated string destination_override = 2;
repeated string domains_excluded = 3;
} }
message ReceiverConfig { message ReceiverConfig {

View File

@@ -136,6 +136,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
stream: mss, stream: mss,
ctx: ctx,
} }
h.workers = append(h.workers, worker) h.workers = append(h.workers, worker)
} }

View File

@@ -156,6 +156,7 @@ func (h *DynamicInboundHandler) refresh() error {
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
stream: h.streamSettings, stream: h.streamSettings,
ctx: h.ctx,
} }
if err := worker.Start(); err != nil { if err := worker.Start(); err != nil {
newError("failed to create UDP worker").Base(err).AtWarning().WriteToLog() newError("failed to create UDP worker").Base(err).AtWarning().WriteToLog()

View File

@@ -42,6 +42,9 @@ func (m *Manager) AddHandler(ctx context.Context, handler inbound.Handler) error
tag := handler.Tag() tag := handler.Tag()
if len(tag) > 0 { if len(tag) > 0 {
if _, found := m.taggedHandlers[tag]; found {
return newError("existing tag found: " + tag)
}
m.taggedHandlers[tag] = handler m.taggedHandlers[tag] = handler
} else { } else {
m.untaggedHandler = append(m.untaggedHandler, handler) m.untaggedHandler = append(m.untaggedHandler, handler)

View File

@@ -97,6 +97,7 @@ func (w *tcpWorker) callback(conn internet.Connection) {
if w.sniffingConfig != nil { if w.sniffingConfig != nil {
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
} }
ctx = session.ContextWithContent(ctx, content) ctx = session.ContextWithContent(ctx, content)
@@ -239,6 +240,9 @@ type udpWorker struct {
checker *task.Periodic checker *task.Periodic
activeConn map[connID]*udpConn activeConn map[connID]*udpConn
ctx context.Context
cone bool
} }
func (w *udpWorker) getConnection(id connID) (*udpConn, bool) { func (w *udpWorker) getConnection(id connID) (*udpConn, bool) {
@@ -279,7 +283,10 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
src: source, src: source,
} }
if originalDest.IsValid() { if originalDest.IsValid() {
id.dest = originalDest if !w.cone {
id.dest = originalDest
}
b.UDP = &originalDest
} }
conn, existing := w.getConnection(id) conn, existing := w.getConnection(id)
@@ -336,7 +343,7 @@ func (w *udpWorker) clean() error {
} }
for addr, conn := range w.activeConn { for addr, conn := range w.activeConn {
if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 8 { // TODO Timeout too small if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 300 {
delete(w.activeConn, addr) delete(w.activeConn, addr)
conn.Close() conn.Close()
} }
@@ -357,8 +364,10 @@ func (w *udpWorker) Start() error {
return err return err
} }
w.cone = w.ctx.Value("cone").(bool)
w.checker = &task.Periodic{ w.checker = &task.Periodic{
Interval: time.Second * 16, Interval: time.Minute,
Execute: w.clean, Execute: w.clean,
} }
@@ -441,6 +450,7 @@ func (w *dsWorker) callback(conn internet.Connection) {
if w.sniffingConfig != nil { if w.sniffingConfig != nil {
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
} }
ctx = session.ContextWithContent(ctx, content) ctx = session.ContextWithContent(ctx, content)

View File

@@ -7,6 +7,7 @@ import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/mux" "github.com/xtls/xray-core/common/mux"
"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/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
@@ -173,7 +174,7 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (internet.Conn
downlinkReader, downlinkWriter := pipe.New(opts...) downlinkReader, downlinkWriter := pipe.New(opts...)
go handler.Dispatch(ctx, &transport.Link{Reader: uplinkReader, Writer: downlinkWriter}) go handler.Dispatch(ctx, &transport.Link{Reader: uplinkReader, Writer: downlinkWriter})
conn := net.NewConnection(net.ConnectionInputMulti(uplinkWriter), net.ConnectionOutputMulti(downlinkReader)) conn := cnc.NewConnection(cnc.ConnectionInputMulti(uplinkWriter), cnc.ConnectionOutputMulti(downlinkReader))
if config := tls.ConfigFromStreamSettings(h.streamSettings); config != nil { if config := tls.ConfigFromStreamSettings(h.streamSettings); config != nil {
tlsConfig := config.GetTLSConfig(tls.WithDestination(dest)) tlsConfig := config.GetTLSConfig(tls.WithDestination(dest))

View File

@@ -109,6 +109,9 @@ func (m *Manager) AddHandler(ctx context.Context, handler outbound.Handler) erro
tag := handler.Tag() tag := handler.Tag()
if len(tag) > 0 { if len(tag) > 0 {
if _, found := m.taggedHandler[tag]; found {
return newError("existing tag found: " + tag)
}
m.taggedHandler[tag] = handler m.taggedHandler[tag] = handler
} else { } else {
m.untaggedHandlers = append(m.untaggedHandlers, handler) m.untaggedHandlers = append(m.untaggedHandlers, handler)

View File

@@ -157,6 +157,9 @@ func (p *StaticMuxPicker) PickAvailable() (*mux.ClientWorker, error) {
if w.draining { if w.draining {
continue continue
} }
if w.client.Closed() {
continue
}
if w.client.ActiveConnections() < minConn { if w.client.ActiveConnections() < minConn {
minConn = w.client.ActiveConnections() minConn = w.client.ActiveConnections()
minIdx = i minIdx = i

View File

@@ -85,7 +85,7 @@ func (s *service) Register(server *grpc.Server) {
RegisterRoutingServiceServer(server, rs) RegisterRoutingServiceServer(server, rs)
// For compatibility purposes // For compatibility purposes
vCoreDesc := _RoutingService_serviceDesc vCoreDesc := RoutingService_ServiceDesc
vCoreDesc.ServiceName = "v2ray.core.app.router.command.RoutingService" vCoreDesc.ServiceName = "v2ray.core.app.router.command.RoutingService"
server.RegisterService(&vCoreDesc, rs) server.RegisterService(&vCoreDesc, rs)
})) }))

View File

@@ -11,6 +11,7 @@ import (
// This is a compile-time assertion to ensure that this generated file // This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against. // is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7 const _ = grpc.SupportPackageIsVersion7
// RoutingServiceClient is the client API for RoutingService service. // RoutingServiceClient is the client API for RoutingService service.
@@ -30,7 +31,7 @@ func NewRoutingServiceClient(cc grpc.ClientConnInterface) RoutingServiceClient {
} }
func (c *routingServiceClient) SubscribeRoutingStats(ctx context.Context, in *SubscribeRoutingStatsRequest, opts ...grpc.CallOption) (RoutingService_SubscribeRoutingStatsClient, error) { func (c *routingServiceClient) SubscribeRoutingStats(ctx context.Context, in *SubscribeRoutingStatsRequest, opts ...grpc.CallOption) (RoutingService_SubscribeRoutingStatsClient, error) {
stream, err := c.cc.NewStream(ctx, &_RoutingService_serviceDesc.Streams[0], "/xray.app.router.command.RoutingService/SubscribeRoutingStats", opts...) stream, err := c.cc.NewStream(ctx, &RoutingService_ServiceDesc.Streams[0], "/xray.app.router.command.RoutingService/SubscribeRoutingStats", opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -99,7 +100,7 @@ type UnsafeRoutingServiceServer interface {
} }
func RegisterRoutingServiceServer(s grpc.ServiceRegistrar, srv RoutingServiceServer) { func RegisterRoutingServiceServer(s grpc.ServiceRegistrar, srv RoutingServiceServer) {
s.RegisterService(&_RoutingService_serviceDesc, srv) s.RegisterService(&RoutingService_ServiceDesc, srv)
} }
func _RoutingService_SubscribeRoutingStats_Handler(srv interface{}, stream grpc.ServerStream) error { func _RoutingService_SubscribeRoutingStats_Handler(srv interface{}, stream grpc.ServerStream) error {
@@ -141,7 +142,10 @@ func _RoutingService_TestRoute_Handler(srv interface{}, ctx context.Context, dec
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
var _RoutingService_serviceDesc = grpc.ServiceDesc{ // RoutingService_ServiceDesc is the grpc.ServiceDesc for RoutingService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var RoutingService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "xray.app.router.command.RoutingService", ServiceName: "xray.app.router.command.RoutingService",
HandlerType: (*RoutingServiceServer)(nil), HandlerType: (*RoutingServiceServer)(nil),
Methods: []grpc.MethodDesc{ Methods: []grpc.MethodDesc{

View File

@@ -91,7 +91,7 @@ func (m *DomainMatcher) Apply(ctx routing.Context) bool {
if len(domain) == 0 { if len(domain) == 0 {
return false return false
} }
return m.ApplyDomain(domain) return m.ApplyDomain(strings.ToLower(domain))
} }
type MultiGeoIPMatcher struct { type MultiGeoIPMatcher struct {

View File

@@ -18,10 +18,10 @@ func init() {
common.Must(err) common.Must(err)
if _, err := os.Stat(platform.GetAssetLocation("geoip.dat")); err != nil && os.IsNotExist(err) { if _, err := os.Stat(platform.GetAssetLocation("geoip.dat")); err != nil && os.IsNotExist(err) {
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "release", "config", "geoip.dat"))) common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "resources", "geoip.dat")))
} }
if _, err := os.Stat(platform.GetAssetLocation("geosite.dat")); err != nil && os.IsNotExist(err) { if _, err := os.Stat(platform.GetAssetLocation("geosite.dat")); err != nil && os.IsNotExist(err) {
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geosite.dat"), filepath.Join(wd, "..", "..", "release", "config", "geosite.dat"))) common.Must(filesystem.CopyFile(platform.GetAssetLocation("geosite.dat"), filepath.Join(wd, "..", "..", "resources", "geosite.dat")))
} }
} }

View File

@@ -113,7 +113,7 @@ func (s *service) Register(server *grpc.Server) {
RegisterStatsServiceServer(server, ss) RegisterStatsServiceServer(server, ss)
// For compatibility purposes // For compatibility purposes
vCoreDesc := _StatsService_serviceDesc vCoreDesc := StatsService_ServiceDesc
vCoreDesc.ServiceName = "v2ray.core.app.stats.command.StatsService" vCoreDesc.ServiceName = "v2ray.core.app.stats.command.StatsService"
server.RegisterService(&vCoreDesc, ss) server.RegisterService(&vCoreDesc, ss)
} }

View File

@@ -11,6 +11,7 @@ import (
// This is a compile-time assertion to ensure that this generated file // This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against. // is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7 const _ = grpc.SupportPackageIsVersion7
// StatsServiceClient is the client API for StatsService service. // StatsServiceClient is the client API for StatsService service.
@@ -90,7 +91,7 @@ type UnsafeStatsServiceServer interface {
} }
func RegisterStatsServiceServer(s grpc.ServiceRegistrar, srv StatsServiceServer) { func RegisterStatsServiceServer(s grpc.ServiceRegistrar, srv StatsServiceServer) {
s.RegisterService(&_StatsService_serviceDesc, srv) s.RegisterService(&StatsService_ServiceDesc, srv)
} }
func _StatsService_GetStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _StatsService_GetStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
@@ -147,7 +148,10 @@ func _StatsService_GetSysStats_Handler(srv interface{}, ctx context.Context, dec
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
var _StatsService_serviceDesc = grpc.ServiceDesc{ // StatsService_ServiceDesc is the grpc.ServiceDesc for StatsService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var StatsService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "xray.app.stats.command.StatsService", ServiceName: "xray.app.stats.command.StatsService",
HandlerType: (*StatsServiceServer)(nil), HandlerType: (*StatsServiceServer)(nil),
Methods: []grpc.MethodDesc{ Methods: []grpc.MethodDesc{

View File

@@ -2,9 +2,9 @@ package buf
import ( import (
"io" "io"
"net"
"github.com/xtls/xray-core/common/bytespool" "github.com/xtls/xray-core/common/bytespool"
"github.com/xtls/xray-core/common/net"
) )
const ( const (
@@ -21,7 +21,7 @@ type Buffer struct {
v []byte v []byte
start int32 start int32
end int32 end int32
UDP *net.UDPAddr UDP *net.Destination
} }
// New creates a Buffer with 0 length and 2K capacity. // New creates a Buffer with 0 length and 2K capacity.
@@ -49,6 +49,7 @@ func (b *Buffer) Release() {
b.v = nil b.v = nil
b.Clear() b.Clear()
pool.Put(p) pool.Put(p)
b.UDP = nil
} }
// Clear clears the content of the buffer, results an empty buffer with // Clear clears the content of the buffer, results an empty buffer with
@@ -109,6 +110,9 @@ func (b *Buffer) BytesTo(to int32) []byte {
if to < 0 { if to < 0 {
to += b.Len() to += b.Len()
} }
if to < 0 {
to = 0
}
return b.v[b.start : b.start+to] return b.v[b.start : b.start+to]
} }

View File

@@ -330,7 +330,7 @@ func (m *ClientWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.Buffere
return buf.Copy(NewStreamReader(reader), buf.Discard) return buf.Copy(NewStreamReader(reader), buf.Discard)
} }
rr := s.NewReader(reader) rr := s.NewReader(reader, &meta.Target)
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()

View File

@@ -81,6 +81,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
} }
} else if b.UDP != nil {
b.WriteByte(byte(TargetNetworkUDP))
addrParser.WriteAddressPort(b, b.UDP.Address, b.UDP.Port)
} }
len1 := b.Len() len1 := b.Len()
@@ -119,7 +122,7 @@ 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 { if f.SessionStatus == SessionStatusNew || (f.SessionStatus == SessionStatusKeep && b.Len() != 4) {
if b.Len() < 8 { if b.Len() < 8 {
return newError("insufficient buffer: ", b.Len()) return newError("insufficient buffer: ", b.Len())
} }

View File

@@ -5,6 +5,7 @@ import (
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
) )
@@ -12,13 +13,15 @@ import (
type PacketReader struct { type PacketReader struct {
reader io.Reader reader io.Reader
eof bool eof bool
dest *net.Destination
} }
// NewPacketReader creates a new PacketReader. // NewPacketReader creates a new PacketReader.
func NewPacketReader(reader io.Reader) *PacketReader { func NewPacketReader(reader io.Reader, dest *net.Destination) *PacketReader {
return &PacketReader{ return &PacketReader{
reader: reader, reader: reader,
eof: false, eof: false,
dest: dest,
} }
} }
@@ -43,6 +46,9 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
return nil, err return nil, err
} }
r.eof = true r.eof = true
if r.dest != nil && r.dest.Network == net.Network_UDP {
b.UDP = r.dest
}
return buf.MultiBuffer{b}, nil return buf.MultiBuffer{b}, nil
} }

View File

@@ -145,7 +145,7 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
return nil return nil
} }
rr := s.NewReader(reader) 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) common.Interrupt(s.input)
@@ -168,7 +168,7 @@ func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.Buffere
return buf.Copy(NewStreamReader(reader), buf.Discard) return buf.Copy(NewStreamReader(reader), buf.Discard)
} }
rr := s.NewReader(reader) rr := s.NewReader(reader, &meta.Target)
err := buf.Copy(rr, s.output) err := buf.Copy(rr, s.output)
if err != nil && buf.IsWriteError(err) { if err != nil && buf.IsWriteError(err) {

View File

@@ -5,6 +5,7 @@ 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/protocol" "github.com/xtls/xray-core/common/protocol"
) )
@@ -152,9 +153,9 @@ func (s *Session) Close() error {
} }
// NewReader creates a buf.Reader based on the transfer type of this Session. // NewReader creates a buf.Reader based on the transfer type of this Session.
func (s *Session) NewReader(reader *buf.BufferedReader) buf.Reader { func (s *Session) NewReader(reader *buf.BufferedReader, dest *net.Destination) buf.Reader {
if s.transferType == protocol.TransferTypeStream { if s.transferType == protocol.TransferTypeStream {
return NewStreamReader(reader) return NewStreamReader(reader)
} }
return NewPacketReader(reader) return NewPacketReader(reader, dest)
} }

View File

@@ -63,6 +63,9 @@ func (w *Writer) writeMetaOnly() error {
func writeMetaWithFrame(writer buf.Writer, meta FrameMetadata, data buf.MultiBuffer) error { func writeMetaWithFrame(writer buf.Writer, meta FrameMetadata, data buf.MultiBuffer) error {
frame := buf.New() frame := buf.New()
if len(data) == 1 {
frame.UDP = data[0].UDP
}
if err := meta.WriteTo(frame); err != nil { if err := meta.WriteTo(frame); err != nil {
return err return err
} }

View File

@@ -1,12 +1,12 @@
package net package cnc
import ( import (
"io" "io"
"net"
"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/net"
"github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/done"
) )
@@ -88,8 +88,8 @@ type connection struct {
writer buf.Writer writer buf.Writer
done *done.Instance done *done.Instance
onClose io.Closer onClose io.Closer
local Addr local net.Addr
remote Addr remote net.Addr
} }
func (c *connection) Read(b []byte) (int, error) { func (c *connection) Read(b []byte) (int, error) {

View File

@@ -30,6 +30,7 @@ func GetAssetLocation(file string) string {
defPath, defPath,
filepath.Join("/usr/local/share/xray/", file), filepath.Join("/usr/local/share/xray/", file),
filepath.Join("/usr/share/xray/", file), filepath.Join("/usr/share/xray/", file),
filepath.Join("/opt/share/xray/", file),
} { } {
if _, err := os.Stat(p); os.IsNotExist(err) { if _, err := os.Stat(p); os.IsNotExist(err) {
continue continue

View File

@@ -55,7 +55,7 @@ func TestAddressReading(t *testing.T) {
}, },
{ {
Options: []AddressOption{AddressFamilyByte(0x03, net.AddressFamilyDomain)}, Options: []AddressOption{AddressFamilyByte(0x03, net.AddressFamilyDomain)},
Input: []byte{3, 9, 118, 50, 114, 97, 121, 46, 99, 111, 109, 0, 80}, Input: []byte{3, 11, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109, 0, 80},
Address: net.DomainAddress("example.com"), Address: net.DomainAddress("example.com"),
Port: net.Port(80), Port: net.Port(80),
}, },
@@ -84,8 +84,9 @@ func TestAddressReading(t *testing.T) {
} }
for _, tc := range data { for _, tc := range data {
b := buf.New()
parser := NewAddressParser(tc.Options...) parser := NewAddressParser(tc.Options...)
b := buf.New()
addr, port, err := parser.ReadAddressPort(b, bytes.NewReader(tc.Input)) addr, port, err := parser.ReadAddressPort(b, bytes.NewReader(tc.Input))
b.Release() b.Release()
if tc.Error { if tc.Error {

View File

@@ -102,7 +102,7 @@ func ReadClientHello(data []byte, h *SniffHeader) error {
return errNotClientHello return errNotClientHello
} }
if nameType == 0 { if nameType == 0 {
serverName := string(d[:nameLen]) serverName := strings.ToLower(string(d[:nameLen]))
// An SNI value may not include a // An SNI value may not include a
// trailing dot. See // trailing dot. See
// https://tools.ietf.org/html/rfc6066#section-3. // https://tools.ietf.org/html/rfc6066#section-3.

View File

@@ -60,6 +60,7 @@ type Outbound struct {
// SniffingRequest controls the behavior of content sniffing. // SniffingRequest controls the behavior of content sniffing.
type SniffingRequest struct { type SniffingRequest struct {
ExcludeForDomain []string
OverrideDestinationForProtocol []string OverrideDestinationForProtocol []string
Enabled bool Enabled bool
} }

View File

@@ -3,6 +3,7 @@ package uuid // import "github.com/xtls/xray-core/common/uuid"
import ( import (
"bytes" "bytes"
"crypto/rand" "crypto/rand"
"crypto/sha1"
"encoding/hex" "encoding/hex"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
@@ -49,6 +50,8 @@ func (u *UUID) Equals(another *UUID) bool {
func New() UUID { func New() UUID {
var uuid UUID var uuid UUID
common.Must2(rand.Read(uuid.Bytes())) common.Must2(rand.Read(uuid.Bytes()))
uuid[6] = (uuid[6] & 0x0f) | (4 << 4)
uuid[8] = (uuid[8]&(0xff>>2) | (0x02 << 6))
return uuid return uuid
} }
@@ -67,8 +70,18 @@ func ParseString(str string) (UUID, error) {
var uuid UUID var uuid UUID
text := []byte(str) text := []byte(str)
if len(text) < 32 { if l := len(text); l < 32 || l > 36 {
return uuid, errors.New("invalid UUID: ", str) if l == 0 || l > 30 {
return uuid, errors.New("invalid UUID: ", str)
}
h := sha1.New()
h.Write(uuid[:])
h.Write(text)
u := h.Sum(nil)[:16]
u[6] = (u[6] & 0x0f) | (5 << 4)
u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
copy(uuid[:], u)
return uuid, nil
} }
b := uuid.Bytes() b := uuid.Bytes()

View File

@@ -35,9 +35,10 @@ func TestParseString(t *testing.T) {
t.Fatal(r) t.Fatal(r)
} }
_, err = ParseString("2418d087") u0, _ := ParseString("example")
if err == nil { u5, _ := ParseString("feb54431-301b-52bb-a6dd-e1e93e81bb9e")
t.Fatal("Expect error but nil") if r := cmp.Diff(u0, u5); r != "" {
t.Fatal(r)
} }
_, err = ParseString("2418d087-648k-4990-86e8-19dca1d006d3") _, err = ParseString("2418d087-648k-4990-86e8-19dca1d006d3")

137
common/xudp/xudp.go Normal file
View File

@@ -0,0 +1,137 @@
package xudp
import (
"io"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
)
var addrParser = protocol.NewAddressParser(
protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4),
protocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain),
protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv6), net.AddressFamilyIPv6),
protocol.PortThenAddress(),
)
func NewPacketWriter(writer buf.Writer, dest net.Destination) *PacketWriter {
return &PacketWriter{
Writer: writer,
Dest: dest,
}
}
type PacketWriter struct {
Writer buf.Writer
Dest net.Destination
}
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
defer buf.ReleaseMulti(mb)
mb2Write := make(buf.MultiBuffer, 0, len(mb))
for _, b := range mb {
length := b.Len()
if length == 0 || length+666 > buf.Size {
continue
}
eb := buf.New()
eb.Write([]byte{0, 0, 0, 0})
if w.Dest.Network == net.Network_UDP {
eb.WriteByte(1) // New
eb.WriteByte(1) // Opt
eb.WriteByte(2) // UDP
addrParser.WriteAddressPort(eb, w.Dest.Address, w.Dest.Port)
w.Dest.Network = net.Network_Unknown
} else {
eb.WriteByte(2) // Keep
eb.WriteByte(1)
if b.UDP != nil {
eb.WriteByte(2)
addrParser.WriteAddressPort(eb, b.UDP.Address, b.UDP.Port)
}
}
l := eb.Len() - 2
eb.SetByte(0, byte(l>>8))
eb.SetByte(1, byte(l))
eb.WriteByte(byte(length >> 8))
eb.WriteByte(byte(length))
eb.Write(b.Bytes())
mb2Write = append(mb2Write, eb)
}
if mb2Write.IsEmpty() {
return nil
}
return w.Writer.WriteMultiBuffer(mb2Write)
}
func NewPacketReader(reader io.Reader) *PacketReader {
return &PacketReader{
Reader: reader,
cache: make([]byte, 2),
}
}
type PacketReader struct {
Reader io.Reader
cache []byte
}
func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
for {
if _, err := io.ReadFull(r.Reader, r.cache); err != nil {
return nil, err
}
l := int32(r.cache[0])<<8 | int32(r.cache[1])
if l < 4 {
return nil, io.EOF
}
b := buf.New()
if _, err := b.ReadFullFrom(r.Reader, l); err != nil {
b.Release()
return nil, err
}
discard := false
switch b.Byte(2) {
case 2:
if l != 4 {
b.Advance(5)
addr, port, err := addrParser.ReadAddressPort(nil, b)
if err != nil {
b.Release()
return nil, err
}
b.UDP = &net.Destination{
Network: net.Network_UDP,
Address: addr,
Port: port,
}
}
case 4:
discard = true
default:
b.Release()
return nil, io.EOF
}
if b.Byte(3) == 1 {
if _, err := io.ReadFull(r.Reader, r.cache); err != nil {
b.Release()
return nil, err
}
length := int32(r.cache[0])<<8 | int32(r.cache[1])
if length > 0 {
b.Clear()
if _, err := b.ReadFullFrom(r.Reader, length); err != nil {
b.Release()
return nil, err
}
if !discard {
return buf.MultiBuffer{b}, nil
}
}
}
b.Release()
}
}

View File

@@ -22,9 +22,13 @@ type ConfigFormat struct {
// ConfigLoader is a utility to load Xray config from external source. // ConfigLoader is a utility to load Xray config from external source.
type ConfigLoader func(input interface{}) (*Config, error) type ConfigLoader func(input interface{}) (*Config, error)
// ConfigBuilder is a builder to build core.Config from filenames and formats
type ConfigBuilder func(files []string, formats []string) (*Config, error)
var ( var (
configLoaderByName = make(map[string]*ConfigFormat) configLoaderByName = make(map[string]*ConfigFormat)
configLoaderByExt = make(map[string]*ConfigFormat) configLoaderByExt = make(map[string]*ConfigFormat)
ConfigBuilderForFiles ConfigBuilder
) )
// RegisterConfigLoader add a new ConfigLoader. // RegisterConfigLoader add a new ConfigLoader.
@@ -46,6 +50,21 @@ func RegisterConfigLoader(format *ConfigFormat) error {
return nil return nil
} }
func GetFormatByExtension(ext string) string {
switch strings.ToLower(ext) {
case "pb", "protobuf":
return "protobuf"
case "yaml", "yml":
return "yaml"
case "toml":
return "toml"
case "json":
return "json"
default:
return ""
}
}
func getExtension(filename string) string { func getExtension(filename string) string {
idx := strings.LastIndexByte(filename, '.') idx := strings.LastIndexByte(filename, '.')
if idx == -1 { if idx == -1 {
@@ -54,23 +73,48 @@ func getExtension(filename string) string {
return filename[idx+1:] return filename[idx+1:]
} }
// LoadConfig loads config with given format from given source. func getFormat(filename string) string {
// input accepts 2 different types: return GetFormatByExtension(getExtension(filename))
// * []string slice of multiple filename/url(s) to open to read }
// * io.Reader that reads a config content (the original way)
func LoadConfig(formatName string, filename string, input interface{}) (*Config, error) { func LoadConfig(formatName string, input interface{}) (*Config, error) {
ext := getExtension(filename) switch v := input.(type) {
if len(ext) > 0 { case cmdarg.Arg:
if f, found := configLoaderByExt[ext]; found {
return f.Loader(input) formats := make([]string, len(v))
hasProtobuf := false
for i, file := range v {
f := getFormat(file)
if f == "" {
f = formatName
}
if f == "protobuf" {
hasProtobuf = true
}
formats[i] = f
}
// only one protobuf config file is allowed
if hasProtobuf {
if len(v) == 1 {
return configLoaderByName["protobuf"].Loader(v)
} else {
return nil, newError("Only one protobuf config file is allowed").AtWarning()
}
}
// to avoid import cycle
return ConfigBuilderForFiles(v, formats)
case io.Reader:
if f, found := configLoaderByName[formatName]; found {
return f.Loader(v)
} else {
return nil, newError("Unable to load config in", formatName).AtWarning()
} }
} }
if f, found := configLoaderByName[formatName]; found { return nil, newError("Unable to load config").AtWarning()
return f.Loader(input)
}
return nil, newError("Unable to load config in ", formatName).AtWarning()
} }
func loadProtobufConfig(data []byte) (*Config, error) { func loadProtobufConfig(data []byte) (*Config, error) {

View File

@@ -18,7 +18,7 @@ import (
) )
var ( var (
version = "1.1.5" version = "1.3.1"
build = "Custom" build = "Custom"
codename = "Xray, Penetrates Everything." codename = "Xray, Penetrates Everything."
intro = "A unified platform for anti-censorship." intro = "A unified platform for anti-censorship."

View File

@@ -6,6 +6,7 @@ import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet/udp" "github.com/xtls/xray-core/transport/internet/udp"
) )
@@ -24,7 +25,7 @@ func CreateObject(v *Instance, config interface{}) (interface{}, error) {
// //
// xray:api:stable // xray:api:stable
func StartInstance(configFormat string, configBytes []byte) (*Instance, error) { func StartInstance(configFormat string, configBytes []byte) (*Instance, error) {
config, err := LoadConfig(configFormat, "", bytes.NewReader(configBytes)) config, err := LoadConfig(configFormat, bytes.NewReader(configBytes))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -53,13 +54,13 @@ func Dial(ctx context.Context, v *Instance, dest net.Destination) (net.Conn, err
if err != nil { if err != nil {
return nil, err return nil, err
} }
var readerOpt net.ConnectionOption var readerOpt cnc.ConnectionOption
if dest.Network == net.Network_TCP { if dest.Network == net.Network_TCP {
readerOpt = net.ConnectionOutputMulti(r.Reader) readerOpt = cnc.ConnectionOutputMulti(r.Reader)
} else { } else {
readerOpt = net.ConnectionOutputMultiUDP(r.Reader) readerOpt = cnc.ConnectionOutputMultiUDP(r.Reader)
} }
return net.NewConnection(net.ConnectionInputMulti(r.Writer), readerOpt), nil return cnc.NewConnection(cnc.ConnectionInputMulti(r.Writer), readerOpt), nil
} }
// DialUDP provides a way to exchange UDP packets through Xray instance to remote servers. // DialUDP provides a way to exchange UDP packets through Xray instance to remote servers.

View File

@@ -2,6 +2,7 @@ package core
import ( import (
"context" "context"
"os"
"reflect" "reflect"
"sync" "sync"
@@ -179,6 +180,8 @@ func NewWithContext(ctx context.Context, config *Config) (*Instance, error) {
} }
func initInstanceWithConfig(config *Config, server *Instance) (bool, error) { func initInstanceWithConfig(config *Config, server *Instance) (bool, error) {
server.ctx = context.WithValue(server.ctx, "cone", os.Getenv("XRAY_CONE_DISABLED") != "true")
if config.Transport != nil { if config.Transport != nil {
features.PrintDeprecatedFeatureWarning("global transport settings") features.PrintDeprecatedFeatureWarning("global transport settings")
} }

22
go.mod
View File

@@ -3,24 +3,24 @@ module github.com/xtls/xray-core
go 1.15 go 1.15
require ( require (
github.com/BurntSushi/toml v0.3.1
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
github.com/golang/mock v1.4.4 github.com/golang/mock v1.5.0
github.com/golang/protobuf v1.4.3 github.com/golang/protobuf v1.4.3
github.com/google/go-cmp v0.5.4 github.com/google/go-cmp v0.5.4
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
github.com/lucas-clemente/quic-go v0.19.3 github.com/lucas-clemente/quic-go v0.19.3
github.com/miekg/dns v1.1.35 github.com/miekg/dns v1.1.40
github.com/pires/go-proxyproto v0.3.3 github.com/pelletier/go-toml v1.8.1
github.com/pires/go-proxyproto v0.4.2
github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c
github.com/stretchr/testify v1.6.1 github.com/stretchr/testify v1.7.0
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499 github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499
go.starlark.net v0.0.0-20201210151846-e81fc95f7bd5 go.starlark.net v0.0.0-20210223155950-e043a3d3c984
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
golang.org/x/net v0.0.0-20201224014010-6772e930b67b golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20201223074533-0d417f636930 golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b
google.golang.org/grpc v1.34.0 google.golang.org/grpc v1.36.0
google.golang.org/protobuf v1.25.0 google.golang.org/protobuf v1.25.0
h12.io/socks v1.0.2 h12.io/socks v1.0.2
) )

54
go.sum
View File

@@ -7,7 +7,6 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
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 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
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=
@@ -20,7 +19,7 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -30,7 +29,7 @@ github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fp
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
@@ -50,8 +49,9 @@ github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200j
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -70,6 +70,7 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
@@ -108,8 +109,8 @@ github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07Vxb
github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
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.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs= github.com/miekg/dns v1.1.40 h1:pyyPFfGMnciYUk/mXpKkVmeMQjfXqt3FAJ2hy7tPiLA=
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
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=
@@ -124,10 +125,12 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
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.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
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.3.3 h1:jOXGrsAfSQVFiD1hWg1aiHpLYsd6SJw/8cLN594sB7Q= github.com/pires/go-proxyproto v0.4.2 h1:VRAvsUCTrmiahoU5fqQqkbY0GWcJ1Q0F7b7CkFaipSU=
github.com/pires/go-proxyproto v0.3.3/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= github.com/pires/go-proxyproto v0.4.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
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=
@@ -168,8 +171,9 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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/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=
@@ -177,8 +181,8 @@ github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499 h1:QHESTXtfgc1ABV+ArlbPVqU
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499/go.mod h1:5TB2+k58gx4A4g2Nf5miSHNDF6CuAzHKpWBooLAshTs= github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499/go.mod h1:5TB2+k58gx4A4g2Nf5miSHNDF6CuAzHKpWBooLAshTs=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.starlark.net v0.0.0-20201210151846-e81fc95f7bd5 h1:F1LaLz0cvAJWMa5r3bogEYXD7/5fgA9a9jOX4DAobN8= go.starlark.net v0.0.0-20210223155950-e043a3d3c984 h1:xwwDQW5We85NaTk2APgoN9202w/l0DVGp+GZMfsrh7s=
go.starlark.net v0.0.0-20201210151846-e81fc95f7bd5/go.mod h1:vxxlMsgCAPH7BR2LtxjJC4WhhZhCGd/b01+CIpj8H4k= go.starlark.net v0.0.0-20210223155950-e043a3d3c984/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -187,14 +191,15 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk
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.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
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/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.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
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=
@@ -209,8 +214,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
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=
@@ -222,8 +227,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -239,10 +244,10 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/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-20201223074533-0d417f636930 h1:vRgIt+nup/B/BwIS0g2oC0haq0iqbV3ZA+u6+0TlNCo= golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b h1:kHlr0tATeLRMEiZJu5CknOw/E8V6h69sXXQFGoPtjcc=
golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
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/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -261,10 +266,13 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
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-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
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=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
@@ -289,8 +297,8 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
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.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
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.34.0 h1:raiipEjMOIC/TO2AvyTxP25XFdLxNIBwzDh3FM3XztI= google.golang.org/grpc v1.36.0 h1:o1bcQ6imQMIOpdrO3SWf2z5RV72WbDwdXuK0MDlc8As=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
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=

View File

@@ -21,7 +21,7 @@ func init() {
common.Must(err) common.Must(err)
if _, err := os.Stat(platform.GetAssetLocation("geoip.dat")); err != nil && os.IsNotExist(err) { if _, err := os.Stat(platform.GetAssetLocation("geoip.dat")); err != nil && os.IsNotExist(err) {
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "release", "config", "geoip.dat"))) common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "resources", "geoip.dat")))
} }
geositeFilePath := filepath.Join(wd, "geosite.dat") geositeFilePath := filepath.Join(wd, "geosite.dat")
@@ -112,6 +112,11 @@ func TestDNSConfigParsing(t *testing.T) {
Domain: "example.com", Domain: "example.com",
ProxiedDomain: "google.com", ProxiedDomain: "google.com",
}, },
{
Type: dns.DomainMatchingType_Full,
Domain: "example.com",
Ip: [][]byte{{127, 0, 0, 1}},
},
{ {
Type: dns.DomainMatchingType_Full, Type: dns.DomainMatchingType_Full,
Domain: "example.com", Domain: "example.com",
@@ -127,11 +132,6 @@ func TestDNSConfigParsing(t *testing.T) {
Domain: ".*\\.com", Domain: ".*\\.com",
Ip: [][]byte{{8, 8, 4, 4}}, Ip: [][]byte{{8, 8, 4, 4}},
}, },
{
Type: dns.DomainMatchingType_Full,
Domain: "example.com",
Ip: [][]byte{{127, 0, 0, 1}},
},
}, },
ClientIp: []byte{10, 0, 0, 1}, ClientIp: []byte{10, 0, 0, 1},
}, },

View File

@@ -460,6 +460,7 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
type RawFieldRule struct { type RawFieldRule struct {
RouterRule RouterRule
Domain *StringList `json:"domain"` Domain *StringList `json:"domain"`
Domains *StringList `json:"domains"`
IP *StringList `json:"ip"` IP *StringList `json:"ip"`
Port *PortList `json:"port"` Port *PortList `json:"port"`
Network *NetworkList `json:"network"` Network *NetworkList `json:"network"`
@@ -500,6 +501,16 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
} }
} }
if rawFieldRule.Domains != nil {
for _, domain := range *rawFieldRule.Domains {
rules, err := parseDomainRule(domain)
if err != nil {
return nil, newError("failed to parse domain rule: ", domain).Base(err)
}
rule.Domain = append(rule.Domain, rules...)
}
}
if rawFieldRule.IP != nil { if rawFieldRule.IP != nil {
geoipList, err := toCidrList(*rawFieldRule.IP) geoipList, err := toCidrList(*rawFieldRule.IP)
if err != nil { if err != nil {

View File

@@ -0,0 +1,44 @@
package serial
import (
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/main/confloader"
"io"
)
func BuildConfig(files []string, formats []string) (*core.Config, error) {
cf := &conf.Config{}
for i, file := range files {
newError("Reading config: ", file).AtInfo().WriteToLog()
r, err := confloader.LoadConfig(file)
if err != nil {
return nil, newError("failed to read config: ", file).Base(err)
}
c, err := ReaderDecoderByFormat[formats[i]](r)
if err != nil {
return nil, newError("failed to decode config: ", file).Base(err)
}
if i == 0 {
*cf = *c
continue
}
cf.Override(c, file)
}
return cf.Build()
}
type readerDecoder func(io.Reader) (*conf.Config, error)
var (
ReaderDecoderByFormat = make(map[string]readerDecoder)
)
func init() {
ReaderDecoderByFormat["json"] = DecodeJSONConfig
ReaderDecoderByFormat["yaml"] = DecodeYAMLConfig
ReaderDecoderByFormat["toml"] = DecodeTOMLConfig
core.ConfigBuilderForFiles = BuildConfig
}

View File

@@ -6,8 +6,8 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"github.com/BurntSushi/toml"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/pelletier/go-toml"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
@@ -86,7 +86,7 @@ func LoadJSONConfig(reader io.Reader) (*core.Config, error) {
} }
// DecodeTOMLConfig reads from reader and decode the config into *conf.Config // DecodeTOMLConfig reads from reader and decode the config into *conf.Config
// using github.com/BurntSushi/toml and map to convert toml to json. // using github.com/pelletier/go-toml and map to convert toml to json.
func DecodeTOMLConfig(reader io.Reader) (*conf.Config, error) { func DecodeTOMLConfig(reader io.Reader) (*conf.Config, error) {
tomlFile, err := ioutil.ReadAll(reader) tomlFile, err := ioutil.ReadAll(reader)
if err != nil { if err != nil {
@@ -94,7 +94,7 @@ func DecodeTOMLConfig(reader io.Reader) (*conf.Config, error) {
} }
configMap := make(map[string]interface{}) configMap := make(map[string]interface{})
if _, err := toml.Decode(string(tomlFile), &configMap); err != nil { if err := toml.Unmarshal(tomlFile, &configMap); err != nil {
return nil, newError("failed to convert toml to map").Base(err) return nil, newError("failed to convert toml to map").Base(err)
} }

View File

@@ -33,35 +33,60 @@ func cipherFromString(c string) shadowsocks.CipherType {
} }
} }
type ShadowsocksUserConfig struct {
Cipher string `json:"method"`
Password string `json:"password"`
Level byte `json:"level"`
Email string `json:"email"`
}
type ShadowsocksServerConfig struct { type ShadowsocksServerConfig struct {
Cipher string `json:"method"` Cipher string `json:"method"`
Password string `json:"password"` Password string `json:"password"`
UDP bool `json:"udp"` Level byte `json:"level"`
Level byte `json:"level"` Email string `json:"email"`
Email string `json:"email"` Users []*ShadowsocksUserConfig `json:"clients"`
NetworkList *NetworkList `json:"network"` NetworkList *NetworkList `json:"network"`
} }
func (v *ShadowsocksServerConfig) Build() (proto.Message, error) { func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
config := new(shadowsocks.ServerConfig) config := new(shadowsocks.ServerConfig)
config.UdpEnabled = v.UDP
config.Network = v.NetworkList.Build() config.Network = v.NetworkList.Build()
if v.Password == "" { if v.Users != nil {
return nil, newError("Shadowsocks password is not specified.") for _, user := range v.Users {
} account := &shadowsocks.Account{
account := &shadowsocks.Account{ Password: user.Password,
Password: v.Password, CipherType: cipherFromString(user.Cipher),
} }
account.CipherType = cipherFromString(v.Cipher) if account.Password == "" {
if account.CipherType == shadowsocks.CipherType_UNKNOWN { return nil, newError("Shadowsocks password is not specified.")
return nil, newError("unknown cipher method: ", v.Cipher) }
} if account.CipherType < 5 || account.CipherType > 7 {
return nil, newError("unsupported cipher method: ", user.Cipher)
config.User = &protocol.User{ }
Email: v.Email, config.Users = append(config.Users, &protocol.User{
Level: uint32(v.Level), Email: user.Email,
Account: serial.ToTypedMessage(account), Level: uint32(user.Level),
Account: serial.ToTypedMessage(account),
})
}
} else {
account := &shadowsocks.Account{
Password: v.Password,
CipherType: cipherFromString(v.Cipher),
}
if account.Password == "" {
return nil, newError("Shadowsocks password is not specified.")
}
if account.CipherType == shadowsocks.CipherType_UNKNOWN {
return nil, newError("unknown cipher method: ", v.Cipher)
}
config.Users = append(config.Users, &protocol.User{
Email: v.Email,
Level: uint32(v.Level),
Account: serial.ToTypedMessage(account),
})
} }
return config, nil return config, nil
@@ -73,7 +98,6 @@ type ShadowsocksServerTarget struct {
Cipher string `json:"method"` Cipher string `json:"method"`
Password string `json:"password"` Password string `json:"password"`
Email string `json:"email"` Email string `json:"email"`
Ota bool `json:"ota"`
Level byte `json:"level"` Level byte `json:"level"`
} }

View File

@@ -18,17 +18,17 @@ func TestShadowsocksServerConfigParsing(t *testing.T) {
runMultiTestCase(t, []TestCase{ runMultiTestCase(t, []TestCase{
{ {
Input: `{ Input: `{
"method": "aes-128-cfb", "method": "aes-128-gcm",
"password": "xray-password" "password": "xray-password"
}`, }`,
Parser: loadJSON(creator), Parser: loadJSON(creator),
Output: &shadowsocks.ServerConfig{ Output: &shadowsocks.ServerConfig{
User: &protocol.User{ Users: []*protocol.User{{
Account: serial.ToTypedMessage(&shadowsocks.Account{ Account: serial.ToTypedMessage(&shadowsocks.Account{
CipherType: shadowsocks.CipherType_AES_128_CFB, CipherType: shadowsocks.CipherType_AES_128_GCM,
Password: "xray-password", Password: "xray-password",
}), }),
}, }},
Network: []net.Network{net.Network_TCP}, Network: []net.Network{net.Network_TCP},
}, },
}, },

View File

@@ -247,12 +247,13 @@ func readFileOrString(f string, s []string) ([]byte, error) {
} }
type TLSCertConfig struct { type TLSCertConfig struct {
CertFile string `json:"certificateFile"` CertFile string `json:"certificateFile"`
CertStr []string `json:"certificate"` CertStr []string `json:"certificate"`
KeyFile string `json:"keyFile"` KeyFile string `json:"keyFile"`
KeyStr []string `json:"key"` KeyStr []string `json:"key"`
Usage string `json:"usage"` Usage string `json:"usage"`
OcspStapling int64 `json:"ocspStapling"` OcspStapling uint64 `json:"ocspStapling"`
OneTimeLoading bool `json:"oneTimeLoading"`
} }
// Build implements Buildable. // Build implements Buildable.
@@ -264,6 +265,7 @@ func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
return nil, newError("failed to parse certificate").Base(err) return nil, newError("failed to parse certificate").Base(err)
} }
certificate.Certificate = cert certificate.Certificate = cert
certificate.CertificatePath = c.CertFile
if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 { if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {
key, err := readFileOrString(c.KeyFile, c.KeyStr) key, err := readFileOrString(c.KeyFile, c.KeyStr)
@@ -271,6 +273,7 @@ func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
return nil, newError("failed to parse key").Base(err) return nil, newError("failed to parse key").Base(err)
} }
certificate.Key = key certificate.Key = key
certificate.KeyPath = c.KeyFile
} }
switch strings.ToLower(c.Usage) { switch strings.ToLower(c.Usage) {
@@ -283,7 +286,11 @@ func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
default: default:
certificate.Usage = tls.Certificate_ENCIPHERMENT certificate.Usage = tls.Certificate_ENCIPHERMENT
} }
if certificate.KeyPath == "" && certificate.CertificatePath == "" {
certificate.OneTimeLoading = true
} else {
certificate.OneTimeLoading = c.OneTimeLoading
}
certificate.OcspStapling = c.OcspStapling certificate.OcspStapling = c.OcspStapling
return certificate, nil return certificate, nil
@@ -294,7 +301,7 @@ type TLSConfig struct {
Certs []*TLSCertConfig `json:"certificates"` Certs []*TLSCertConfig `json:"certificates"`
ServerName string `json:"serverName"` ServerName string `json:"serverName"`
ALPN *StringList `json:"alpn"` ALPN *StringList `json:"alpn"`
DisableSessionResumption bool `json:"disableSessionResumption"` 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"`
@@ -321,7 +328,7 @@ func (c *TLSConfig) Build() (proto.Message, error) {
if c.ALPN != nil && len(*c.ALPN) > 0 { if c.ALPN != nil && len(*c.ALPN) > 0 {
config.NextProtocol = []string(*c.ALPN) config.NextProtocol = []string(*c.ALPN)
} }
config.DisableSessionResumption = c.DisableSessionResumption config.EnableSessionResumption = c.EnableSessionResumption
config.DisableSystemRoot = c.DisableSystemRoot config.DisableSystemRoot = c.DisableSystemRoot
config.MinVersion = c.MinVersion config.MinVersion = c.MinVersion
config.MaxVersion = c.MaxVersion config.MaxVersion = c.MaxVersion
@@ -331,23 +338,24 @@ func (c *TLSConfig) Build() (proto.Message, error) {
} }
type XTLSCertConfig struct { type XTLSCertConfig struct {
CertFile string `json:"certificateFile"` CertFile string `json:"certificateFile"`
CertStr []string `json:"certificate"` CertStr []string `json:"certificate"`
KeyFile string `json:"keyFile"` KeyFile string `json:"keyFile"`
KeyStr []string `json:"key"` KeyStr []string `json:"key"`
Usage string `json:"usage"` Usage string `json:"usage"`
OcspStapling int64 `json:"ocspStapling"` OcspStapling uint64 `json:"ocspStapling"`
OneTimeLoading bool `json:"oneTimeLoading"`
} }
// Build implements Buildable. // Build implements Buildable.
func (c *XTLSCertConfig) Build() (*xtls.Certificate, error) { func (c *XTLSCertConfig) Build() (*xtls.Certificate, error) {
certificate := new(xtls.Certificate) certificate := new(xtls.Certificate)
cert, err := readFileOrString(c.CertFile, c.CertStr) cert, err := readFileOrString(c.CertFile, c.CertStr)
if err != nil { if err != nil {
return nil, newError("failed to parse certificate").Base(err) return nil, newError("failed to parse certificate").Base(err)
} }
certificate.Certificate = cert certificate.Certificate = cert
certificate.CertificatePath = c.CertFile
if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 { if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {
key, err := readFileOrString(c.KeyFile, c.KeyStr) key, err := readFileOrString(c.KeyFile, c.KeyStr)
@@ -355,6 +363,7 @@ func (c *XTLSCertConfig) Build() (*xtls.Certificate, error) {
return nil, newError("failed to parse key").Base(err) return nil, newError("failed to parse key").Base(err)
} }
certificate.Key = key certificate.Key = key
certificate.KeyPath = c.KeyFile
} }
switch strings.ToLower(c.Usage) { switch strings.ToLower(c.Usage) {
@@ -367,7 +376,11 @@ func (c *XTLSCertConfig) Build() (*xtls.Certificate, error) {
default: default:
certificate.Usage = xtls.Certificate_ENCIPHERMENT certificate.Usage = xtls.Certificate_ENCIPHERMENT
} }
if certificate.KeyPath == "" && certificate.CertificatePath == "" {
certificate.OneTimeLoading = true
} else {
certificate.OneTimeLoading = c.OneTimeLoading
}
certificate.OcspStapling = c.OcspStapling certificate.OcspStapling = c.OcspStapling
return certificate, nil return certificate, nil
@@ -378,7 +391,7 @@ type XTLSConfig struct {
Certs []*XTLSCertConfig `json:"certificates"` Certs []*XTLSCertConfig `json:"certificates"`
ServerName string `json:"serverName"` ServerName string `json:"serverName"`
ALPN *StringList `json:"alpn"` ALPN *StringList `json:"alpn"`
DisableSessionResumption bool `json:"disableSessionResumption"` 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"`
@@ -405,7 +418,7 @@ func (c *XTLSConfig) Build() (proto.Message, error) {
if c.ALPN != nil && len(*c.ALPN) > 0 { if c.ALPN != nil && len(*c.ALPN) > 0 {
config.NextProtocol = []string(*c.ALPN) config.NextProtocol = []string(*c.ALPN)
} }
config.DisableSessionResumption = c.DisableSessionResumption config.EnableSessionResumption = c.EnableSessionResumption
config.DisableSystemRoot = c.DisableSystemRoot config.DisableSystemRoot = c.DisableSystemRoot
config.MinVersion = c.MinVersion config.MinVersion = c.MinVersion
config.MaxVersion = c.MaxVersion config.MaxVersion = c.MaxVersion

View File

@@ -85,6 +85,7 @@ func (c *TrojanClientConfig) Build() (proto.Message, error) {
// TrojanInboundFallback is fallback configuration // TrojanInboundFallback is fallback configuration
type TrojanInboundFallback struct { type TrojanInboundFallback struct {
Name string `json:"name"`
Alpn string `json:"alpn"` Alpn string `json:"alpn"`
Path string `json:"path"` Path string `json:"path"`
Type string `json:"type"` Type string `json:"type"`
@@ -144,6 +145,7 @@ func (c *TrojanServerConfig) Build() (proto.Message, error) {
_ = json.Unmarshal(fb.Dest, &s) _ = json.Unmarshal(fb.Dest, &s)
} }
config.Fallbacks = append(config.Fallbacks, &trojan.Fallback{ config.Fallbacks = append(config.Fallbacks, &trojan.Fallback{
Name: fb.Name,
Alpn: fb.Alpn, Alpn: fb.Alpn,
Path: fb.Path, Path: fb.Path,
Type: fb.Type, Type: fb.Type,

View File

@@ -11,12 +11,14 @@ import (
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/proxy/vless" "github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/proxy/vless/inbound" "github.com/xtls/xray-core/proxy/vless/inbound"
"github.com/xtls/xray-core/proxy/vless/outbound" "github.com/xtls/xray-core/proxy/vless/outbound"
) )
type VLessInboundFallback struct { type VLessInboundFallback struct {
Name string `json:"name"`
Alpn string `json:"alpn"` Alpn string `json:"alpn"`
Path string `json:"path"` Path string `json:"path"`
Type string `json:"type"` Type string `json:"type"`
@@ -45,6 +47,12 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
return nil, newError(`VLESS clients: invalid user`).Base(err) return nil, newError(`VLESS clients: invalid user`).Base(err)
} }
u, err := uuid.ParseString(account.Id)
if err != nil {
return nil, err
}
account.Id = u.String()
switch account.Flow { switch account.Flow {
case "", "xtls-rprx-origin", "xtls-rprx-direct": case "", "xtls-rprx-origin", "xtls-rprx-direct":
case "xtls-rprx-splice": case "xtls-rprx-splice":
@@ -78,6 +86,7 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
_ = json.Unmarshal(fb.Dest, &s) _ = json.Unmarshal(fb.Dest, &s)
} }
config.Fallbacks = append(config.Fallbacks, &inbound.Fallback{ config.Fallbacks = append(config.Fallbacks, &inbound.Fallback{
Name: fb.Name,
Alpn: fb.Alpn, Alpn: fb.Alpn,
Path: fb.Path, Path: fb.Path,
Type: fb.Type, Type: fb.Type,
@@ -167,6 +176,12 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
return nil, newError(`VLESS users: invalid user`).Base(err) return nil, newError(`VLESS users: invalid user`).Base(err)
} }
u, err := uuid.ParseString(account.Id)
if err != nil {
return nil, err
}
account.Id = u.String()
switch account.Flow { switch account.Flow {
case "", "xtls-rprx-origin", "xtls-rprx-origin-udp443", "xtls-rprx-direct", "xtls-rprx-direct-udp443": case "", "xtls-rprx-origin", "xtls-rprx-origin-udp443", "xtls-rprx-direct", "xtls-rprx-direct-udp443":
case "xtls-rprx-splice", "xtls-rprx-splice-udp443": case "xtls-rprx-splice", "xtls-rprx-splice-udp443":

View File

@@ -8,6 +8,7 @@ import (
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/proxy/vmess" "github.com/xtls/xray-core/proxy/vmess"
"github.com/xtls/xray-core/proxy/vmess/inbound" "github.com/xtls/xray-core/proxy/vmess/inbound"
"github.com/xtls/xray-core/proxy/vmess/outbound" "github.com/xtls/xray-core/proxy/vmess/outbound"
@@ -105,6 +106,13 @@ func (c *VMessInboundConfig) Build() (proto.Message, error) {
if err := json.Unmarshal(rawData, account); err != nil { if err := json.Unmarshal(rawData, account); err != nil {
return nil, newError("invalid VMess user").Base(err) return nil, newError("invalid VMess user").Base(err)
} }
u, err := uuid.ParseString(account.ID)
if err != nil {
return nil, err
}
account.ID = u.String()
user.Account = serial.ToTypedMessage(account.Build()) user.Account = serial.ToTypedMessage(account.Build())
config.User[idx] = user config.User[idx] = user
} }
@@ -149,6 +157,13 @@ func (c *VMessOutboundConfig) Build() (proto.Message, error) {
if err := json.Unmarshal(rawUser, account); err != nil { if err := json.Unmarshal(rawUser, account); err != nil {
return nil, newError("invalid VMess user").Base(err) return nil, newError("invalid VMess user").Base(err)
} }
u, err := uuid.ParseString(account.ID)
if err != nil {
return nil, err
}
account.ID = u.String()
user.Account = serial.ToTypedMessage(account.Build()) user.Account = serial.ToTypedMessage(account.Build())
spec.User = append(spec.User, user) spec.User = append(spec.User, user)
} }

View File

@@ -58,29 +58,38 @@ func toProtocolList(s []string) ([]proxyman.KnownProtocols, error) {
} }
type SniffingConfig struct { type SniffingConfig struct {
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
DestOverride *StringList `json:"destOverride"` DestOverride *StringList `json:"destOverride"`
DomainsExcluded *StringList `json:"domainsExcluded"`
} }
// Build implements Buildable. // Build implements Buildable.
func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) { func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {
var p []string var p []string
if c.DestOverride != nil { if c.DestOverride != nil {
for _, domainOverride := range *c.DestOverride { for _, protocol := range *c.DestOverride {
switch strings.ToLower(domainOverride) { switch strings.ToLower(protocol) {
case "http": case "http":
p = append(p, "http") p = append(p, "http")
case "tls", "https", "ssl": case "tls", "https", "ssl":
p = append(p, "tls") p = append(p, "tls")
default: default:
return nil, newError("unknown protocol: ", domainOverride) return nil, newError("unknown protocol: ", protocol)
} }
} }
} }
var d []string
if c.DomainsExcluded != nil {
for _, domain := range *c.DomainsExcluded {
d = append(d, strings.ToLower(domain))
}
}
return &proxyman.SniffingConfig{ return &proxyman.SniffingConfig{
Enabled: c.Enabled, Enabled: c.Enabled,
DestinationOverride: p, DestinationOverride: p,
DomainsExcluded: d,
}, nil }, nil
} }

View File

@@ -8,15 +8,33 @@ import (
) )
var cmdUUID = &base.Command{ var cmdUUID = &base.Command{
UsageLine: "{{.Exec}} uuid", UsageLine: `{{.Exec}} uuid [-i "example"]`,
Short: "Generate new UUIDs", Short: `Generate UUIDv4 or UUIDv5`,
Long: ` Long: `
Generate new UUIDs. Generate UUIDv4 or UUIDv5.
`,
Run: executeUUID, UUIDv4 (random): {{.Exec}} uuid
UUIDv5 (from input): {{.Exec}} uuid -i "example"
`,
} }
func executeUUID(cmd *base.Command, args []string) { func init() {
u := uuid.New() cmdUUID.Run = executeUUID // break init loop
fmt.Println(u.String()) }
var input = cmdUUID.Flag.String("i", "", "")
func executeUUID(cmd *base.Command, args []string) {
var output string
if l := len(*input); l == 0 {
u := uuid.New()
output = u.String()
} else if l <= 30 {
u, _ := uuid.ParseString(*input)
output = u.String()
} else {
output = "Input must be within 30 bytes."
}
fmt.Println(output)
} }

View File

@@ -8,15 +8,14 @@ import (
"os/signal" "os/signal"
"path" "path"
"path/filepath" "path/filepath"
"regexp"
"runtime" "runtime"
"runtime/debug" "runtime/debug"
"strings"
"syscall" "syscall"
"github.com/xtls/xray-core/common/cmdarg" "github.com/xtls/xray-core/common/cmdarg"
"github.com/xtls/xray-core/common/platform" "github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/main/commands/base" "github.com/xtls/xray-core/main/commands/base"
) )
@@ -82,9 +81,11 @@ func executeRun(cmd *base.Command, args []string) {
} }
defer server.Close() defer server.Close()
conf.FileCache = nil /*
conf.IPCache = nil conf.FileCache = nil
conf.SiteCache = nil conf.IPCache = nil
conf.SiteCache = nil
*/
// Explicitly triggering GC to remove garbage from config loading. // Explicitly triggering GC to remove garbage from config loading.
runtime.GC() runtime.GC()
@@ -116,7 +117,11 @@ func readConfDir(dirPath string) {
log.Fatalln(err) log.Fatalln(err)
} }
for _, f := range confs { for _, f := range confs {
if strings.HasSuffix(f.Name(), ".json") { matched, err := regexp.MatchString(`^.+\.(json|toml|yaml|yml)$`, f.Name())
if err != nil {
log.Fatalln(err)
}
if matched {
configFiles.Set(path.Join(dirPath, f.Name())) configFiles.Set(path.Join(dirPath, f.Name()))
} }
} }
@@ -153,30 +158,25 @@ func getConfigFilePath() cmdarg.Arg {
} }
func getConfigFormat() string { func getConfigFormat() string {
switch strings.ToLower(*format) { f := core.GetFormatByExtension(*format)
case "pb", "protobuf": if f == "" {
return "protobuf" f = "json"
case "yaml", "yml":
return "yaml"
case "toml":
return "toml"
default:
return "json"
} }
return f
} }
func startXray() (core.Server, error) { func startXray() (core.Server, error) {
configFiles := getConfigFilePath() configFiles := getConfigFilePath()
config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles) //config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles)
//config, err := core.LoadConfigs(getConfigFormat(), configFiles) c, err := core.LoadConfig(getConfigFormat(), configFiles)
if err != nil { if err != nil {
return nil, newError("failed to load config files: [", configFiles.String(), "]").Base(err) return nil, newError("failed to load config files: [", configFiles.String(), "]").Base(err)
} }
server, err := core.New(config) server, err := core.New(c)
if err != nil { if err != nil {
return nil, newError("failed to create server").Base(err) return nil, newError("failed to create server").Base(err)
} }

View File

@@ -163,36 +163,60 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
if !destinationOverridden { if !destinationOverridden {
writer = &buf.SequentialWriter{Writer: conn} writer = &buf.SequentialWriter{Writer: conn}
} else { } else {
sockopt := &internet.SocketConfig{ back := conn.RemoteAddr().(*net.UDPAddr)
Tproxy: internet.SocketConfig_TProxy, if !dest.Address.Family().IsIP() {
if len(back.IP) == 4 {
dest.Address = net.AnyIP
} else {
dest.Address = net.AnyIPv6
}
} }
if dest.Address.Family().IsIP() { addr := &net.UDPAddr{
sockopt.BindAddress = dest.Address.IP() IP: dest.Address.IP(),
sockopt.BindPort = uint32(dest.Port) Port: int(dest.Port),
} }
var mark int
if d.sockopt != nil { if d.sockopt != nil {
sockopt.Mark = d.sockopt.Mark mark = int(d.sockopt.Mark)
} }
tConn, err := internet.DialSystem(ctx, net.DestinationFromAddr(conn.RemoteAddr()), sockopt) pConn, err := FakeUDP(addr, mark)
if err != nil { if err != nil {
return err return err
} }
defer tConn.Close() writer = NewPacketWriter(pConn, &dest, mark, back)
defer writer.(*PacketWriter).Close()
writer = &buf.SequentialWriter{Writer: tConn} /*
tReader := buf.NewPacketReader(tConn) sockopt := &internet.SocketConfig{
requestCount++ Tproxy: internet.SocketConfig_TProxy,
tproxyRequest = func() error {
defer func() {
if atomic.AddInt32(&requestCount, -1) == 0 {
timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
}
}()
if err := buf.Copy(tReader, link.Writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport request (TPROXY conn)").Base(err)
} }
return nil if dest.Address.Family().IsIP() {
} sockopt.BindAddress = dest.Address.IP()
sockopt.BindPort = uint32(dest.Port)
}
if d.sockopt != nil {
sockopt.Mark = d.sockopt.Mark
}
tConn, err := internet.DialSystem(ctx, net.DestinationFromAddr(conn.RemoteAddr()), sockopt)
if err != nil {
return err
}
defer tConn.Close()
writer = &buf.SequentialWriter{Writer: tConn}
tReader := buf.NewPacketReader(tConn)
requestCount++
tproxyRequest = func() error {
defer func() {
if atomic.AddInt32(&requestCount, -1) == 0 {
timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
}
}()
if err := buf.Copy(tReader, link.Writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport request (TPROXY conn)").Base(err)
}
return nil
}
*/
} }
} }
@@ -215,3 +239,74 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
return nil return nil
} }
func NewPacketWriter(conn net.PacketConn, d *net.Destination, mark int, back *net.UDPAddr) buf.Writer {
writer := &PacketWriter{
conn: conn,
conns: make(map[net.Destination]net.PacketConn),
mark: mark,
back: back,
}
writer.conns[*d] = conn
return writer
}
type PacketWriter struct {
conn net.PacketConn
conns map[net.Destination]net.PacketConn
mark int
back *net.UDPAddr
}
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
for {
mb2, b := buf.SplitFirst(mb)
mb = mb2
if b == nil {
break
}
var err error
if b.UDP != nil && b.UDP.Address.Family().IsIP() {
conn := w.conns[*b.UDP]
if conn == nil {
conn, err = FakeUDP(
&net.UDPAddr{
IP: b.UDP.Address.IP(),
Port: int(b.UDP.Port),
},
w.mark,
)
if err != nil {
newError(err).WriteToLog()
b.Release()
continue
}
w.conns[*b.UDP] = conn
}
_, err = conn.WriteTo(b.Bytes(), w.back)
if err != nil {
newError(err).WriteToLog()
w.conns[*b.UDP] = nil
conn.Close()
}
b.Release()
} else {
_, err = w.conn.WriteTo(b.Bytes(), w.back)
b.Release()
if err != nil {
buf.ReleaseMulti(mb)
return err
}
}
}
return nil
}
func (w *PacketWriter) Close() error {
for _, conn := range w.conns {
if conn != nil {
conn.Close()
}
}
return nil
}

View File

@@ -0,0 +1,66 @@
// +build linux
package dokodemo
import (
"fmt"
"net"
"os"
"syscall"
"golang.org/x/sys/unix"
)
func FakeUDP(addr *net.UDPAddr, mark int) (net.PacketConn, error) {
var af int
var sockaddr syscall.Sockaddr
if len(addr.IP) == 4 {
af = syscall.AF_INET
sockaddr = &syscall.SockaddrInet4{Port: addr.Port}
copy(sockaddr.(*syscall.SockaddrInet4).Addr[:], addr.IP)
} else {
af = syscall.AF_INET6
sockaddr = &syscall.SockaddrInet6{Port: addr.Port}
copy(sockaddr.(*syscall.SockaddrInet6).Addr[:], addr.IP)
}
var fd int
var err error
if fd, err = syscall.Socket(af, syscall.SOCK_DGRAM, 0); err != nil {
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("socket open: %s", err)}
}
if mark != 0 {
if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_MARK, mark); err != nil {
syscall.Close(fd)
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("set socket option: SO_MARK: %s", err)}
}
}
if err = syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
syscall.Close(fd)
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("set socket option: IP_TRANSPARENT: %s", err)}
}
syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1)
if err = syscall.Bind(fd, sockaddr); err != nil {
syscall.Close(fd)
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("socket bind: %s", err)}
}
fdFile := os.NewFile(uintptr(fd), fmt.Sprintf("net-udp-fake-%s", addr.String()))
defer fdFile.Close()
packetConn, err := net.FilePacketConn(fdFile)
if err != nil {
syscall.Close(fd)
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("convert file descriptor to connection: %s", err)}
}
return packetConn, nil
}

View File

@@ -0,0 +1,12 @@
// +build !linux
package dokodemo
import (
"fmt"
"net"
)
func FakeUDP(addr *net.UDPAddr, mark int) (net.PacketConn, error) {
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("!linux")}
}

View File

@@ -97,13 +97,16 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return newError("target not specified.") return newError("target not specified.")
} }
destination := outbound.Target destination := outbound.Target
UDPOverride := net.UDPDestination(nil, 0)
if h.config.DestinationOverride != nil { if h.config.DestinationOverride != nil {
server := h.config.DestinationOverride.Server server := h.config.DestinationOverride.Server
if isValidAddress(server.Address) { if isValidAddress(server.Address) {
destination.Address = server.Address.AsAddress() destination.Address = server.Address.AsAddress()
UDPOverride.Address = destination.Address
} }
if server.Port != 0 { if server.Port != 0 {
destination.Port = net.Port(server.Port) destination.Port = net.Port(server.Port)
UDPOverride.Port = destination.Port
} }
} }
newError("opening connection to ", destination).WriteToLog(session.ExportIDToError(ctx)) newError("opening connection to ", destination).WriteToLog(session.ExportIDToError(ctx))
@@ -149,7 +152,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
if destination.Network == net.Network_TCP { if destination.Network == net.Network_TCP {
writer = buf.NewWriter(conn) writer = buf.NewWriter(conn)
} else { } else {
writer = NewPacketWriter(conn) writer = NewPacketWriter(conn, h, ctx, UDPOverride)
} }
if err := buf.Copy(input, writer, buf.UpdateActivity(timer)); err != nil { if err := buf.Copy(input, writer, buf.UpdateActivity(timer)); err != nil {
@@ -215,14 +218,18 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
return nil, err return nil, err
} }
b.Resize(0, int32(n)) b.Resize(0, int32(n))
b.UDP = d.(*net.UDPAddr) b.UDP = &net.Destination{
Address: net.IPAddress(d.(*net.UDPAddr).IP),
Port: net.Port(d.(*net.UDPAddr).Port),
Network: net.Network_UDP,
}
if r.Counter != nil { if r.Counter != nil {
r.Counter.Add(int64(n)) r.Counter.Add(int64(n))
} }
return buf.MultiBuffer{b}, nil return buf.MultiBuffer{b}, nil
} }
func NewPacketWriter(conn net.Conn) buf.Writer { func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride net.Destination) buf.Writer {
iConn := conn iConn := conn
statConn, ok := iConn.(*internet.StatCouterConnection) statConn, ok := iConn.(*internet.StatCouterConnection)
if ok { if ok {
@@ -236,6 +243,9 @@ func NewPacketWriter(conn net.Conn) buf.Writer {
return &PacketWriter{ return &PacketWriter{
PacketConnWrapper: c, PacketConnWrapper: c,
Counter: counter, Counter: counter,
Handler: h,
Context: ctx,
UDPOverride: UDPOverride,
} }
} }
return &buf.SequentialWriter{Writer: conn} return &buf.SequentialWriter{Writer: conn}
@@ -244,6 +254,9 @@ func NewPacketWriter(conn net.Conn) buf.Writer {
type PacketWriter struct { type PacketWriter struct {
*internet.PacketConnWrapper *internet.PacketConnWrapper
stats.Counter stats.Counter
*Handler
context.Context
UDPOverride net.Destination
} }
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
@@ -256,7 +269,24 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
var n int var n int
var err error var err error
if b.UDP != nil { if b.UDP != nil {
n, err = w.PacketConnWrapper.WriteTo(b.Bytes(), b.UDP) if w.UDPOverride.Address != nil {
b.UDP.Address = w.UDPOverride.Address
}
if w.UDPOverride.Port != 0 {
b.UDP.Port = w.UDPOverride.Port
}
if w.Handler.config.useIP() && b.UDP.Address.Family().IsDomain() {
ip := w.Handler.resolveIP(w.Context, b.UDP.Address.Domain(), nil)
if ip != nil {
b.UDP.Address = ip
}
}
destAddr, _ := net.ResolveUDPAddr("udp", b.UDP.NetAddr())
if destAddr == nil {
b.Release()
continue
}
n, err = w.PacketConnWrapper.WriteTo(b.Bytes(), destAddr)
} else { } else {
n, err = w.PacketConnWrapper.Write(b.Bytes()) n, err = w.PacketConnWrapper.Write(b.Bytes())
} }

View File

@@ -7,6 +7,8 @@ import (
"crypto/md5" "crypto/md5"
"crypto/sha1" "crypto/sha1"
"io" "io"
"reflect"
"strconv"
"golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/hkdf" "golang.org/x/crypto/hkdf"
@@ -31,6 +33,31 @@ func (a *MemoryAccount) Equals(another protocol.Account) bool {
return false return false
} }
func (a *MemoryAccount) GetCipherName() string {
switch a.Cipher.(type) {
case *AesCfb:
keyBytes := a.Cipher.(*AesCfb).KeyBytes
return "AES_" + strconv.FormatInt(int64(keyBytes*8), 10) + "_CFB"
case *ChaCha20:
if a.Cipher.(*ChaCha20).IVBytes == 8 {
return "CHACHA20"
}
return "CHACHA20_IETF"
case *AEADCipher:
switch reflect.ValueOf(a.Cipher.(*AEADCipher).AEADAuthCreator).Pointer() {
case reflect.ValueOf(createAesGcm).Pointer():
keyBytes := a.Cipher.(*AEADCipher).KeyBytes
return "AES_" + strconv.FormatInt(int64(keyBytes*8), 10) + "_GCM"
case reflect.ValueOf(createChacha20Poly1305).Pointer():
return "CHACHA20_POLY1305"
}
case *NoneCipher:
return "NONE"
}
return ""
}
func createAesGcm(key []byte) cipher.AEAD { func createAesGcm(key []byte) cipher.AEAD {
block, err := aes.NewCipher(key) block, err := aes.NewCipher(key)
common.Must(err) common.Must(err)

View File

@@ -154,13 +154,8 @@ type ServerConfig struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// UdpEnabled specified whether or not to enable UDP for Shadowsocks. Users []*protocol.User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"`
// Deprecated. Use 'network' field. Network []net.Network `protobuf:"varint,2,rep,packed,name=network,proto3,enum=xray.common.net.Network" json:"network,omitempty"`
//
// Deprecated: Do not use.
UdpEnabled bool `protobuf:"varint,1,opt,name=udp_enabled,json=udpEnabled,proto3" json:"udp_enabled,omitempty"`
User *protocol.User `protobuf:"bytes,2,opt,name=user,proto3" json:"user,omitempty"`
Network []net.Network `protobuf:"varint,3,rep,packed,name=network,proto3,enum=xray.common.net.Network" json:"network,omitempty"`
} }
func (x *ServerConfig) Reset() { func (x *ServerConfig) Reset() {
@@ -195,17 +190,9 @@ func (*ServerConfig) Descriptor() ([]byte, []int) {
return file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{1} return file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{1}
} }
// Deprecated: Do not use. func (x *ServerConfig) GetUsers() []*protocol.User {
func (x *ServerConfig) GetUdpEnabled() bool {
if x != nil { if x != nil {
return x.UdpEnabled return x.Users
}
return false
}
func (x *ServerConfig) GetUser() *protocol.User {
if x != nil {
return x.User
} }
return nil return nil
} }
@@ -282,39 +269,37 @@ var file_proxy_shadowsocks_config_proto_rawDesc = []byte{
0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f,
0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x2e, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x2e, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70,
0x65, 0x52, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x22, 0x97, 0x01, 0x65, 0x52, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x22, 0x74, 0x0a,
0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x30, 0x0a,
0x0a, 0x0b, 0x75, 0x64, 0x70, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78,
0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x75, 0x64, 0x70, 0x45, 0x6e, 0x61, 0x62, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x6c, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12,
0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x32, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e,
0x73, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x03, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77,
0x20, 0x03, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x72, 0x6b, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e,
0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20,
0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65,
0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x72, 0x2a, 0x9f, 0x01, 0x0a, 0x0a, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65,
0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2a, 0x9f, 0x01, 0x0a, 0x0a, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x43, 0x46, 0x42, 0x10, 0x01, 0x12, 0x0f,
0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x43, 0x46, 0x42, 0x10, 0x02, 0x12,
0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x43, 0x46, 0x42, 0x0c, 0x0a, 0x08, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x10, 0x03, 0x12, 0x11, 0x0a,
0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x43, 0x46, 0x0d, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x49, 0x45, 0x54, 0x46, 0x10, 0x04,
0x42, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x10, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43, 0x4d, 0x10,
0x03, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x49, 0x45, 0x05, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x47, 0x43, 0x4d,
0x54, 0x46, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x10, 0x06, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x50,
0x47, 0x43, 0x4d, 0x10, 0x05, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x10, 0x07, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e,
0x5f, 0x47, 0x43, 0x4d, 0x10, 0x06, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x45, 0x10, 0x08, 0x42, 0x64, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x32, 0x30, 0x5f, 0x50, 0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x10, 0x07, 0x12, 0x08, 0x0a, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b,
0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x08, 0x42, 0x64, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x73, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70,
0x73, 0x6f, 0x63, 0x6b, 0x73, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73,
0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0xaa, 0x02, 0x16, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x68,
0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x6f, 0x63, 0x6b, 0x73, 0xaa, 0x02, 0x16, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x33,
0x79, 0x2e, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@@ -342,7 +327,7 @@ var file_proxy_shadowsocks_config_proto_goTypes = []interface{}{
} }
var file_proxy_shadowsocks_config_proto_depIdxs = []int32{ var file_proxy_shadowsocks_config_proto_depIdxs = []int32{
0, // 0: xray.proxy.shadowsocks.Account.cipher_type:type_name -> xray.proxy.shadowsocks.CipherType 0, // 0: xray.proxy.shadowsocks.Account.cipher_type:type_name -> xray.proxy.shadowsocks.CipherType
4, // 1: xray.proxy.shadowsocks.ServerConfig.user:type_name -> xray.common.protocol.User 4, // 1: xray.proxy.shadowsocks.ServerConfig.users:type_name -> xray.common.protocol.User
5, // 2: xray.proxy.shadowsocks.ServerConfig.network:type_name -> xray.common.net.Network 5, // 2: xray.proxy.shadowsocks.ServerConfig.network:type_name -> xray.common.net.Network
6, // 3: xray.proxy.shadowsocks.ClientConfig.server:type_name -> xray.common.protocol.ServerEndpoint 6, // 3: xray.proxy.shadowsocks.ClientConfig.server:type_name -> xray.common.protocol.ServerEndpoint
4, // [4:4] is the sub-list for method output_type 4, // [4:4] is the sub-list for method output_type

View File

@@ -28,11 +28,8 @@ enum CipherType {
} }
message ServerConfig { message ServerConfig {
// UdpEnabled specified whether or not to enable UDP for Shadowsocks. repeated xray.common.protocol.User users = 1;
// Deprecated. Use 'network' field. repeated xray.common.net.Network network = 2;
bool udp_enabled = 1 [deprecated = true];
xray.common.protocol.User user = 2;
repeated xray.common.net.Network network = 3;
} }
message ClientConfig { message ClientConfig {

View File

@@ -1,6 +1,7 @@
package shadowsocks package shadowsocks
import ( import (
"crypto/cipher"
"crypto/hmac" "crypto/hmac"
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
@@ -10,6 +11,7 @@ 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/crypto"
"github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/dice"
"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"
@@ -28,12 +30,33 @@ var addrParser = protocol.NewAddressParser(
}), }),
) )
type FullReader struct {
reader io.Reader
buffer []byte
}
func (r *FullReader) Read(p []byte) (n int, err error) {
if r.buffer != nil {
n := copy(p, r.buffer)
if n == len(r.buffer) {
r.buffer = nil
} else {
r.buffer = r.buffer[n:]
}
if n == len(p) {
return n, nil
} else {
m, err := r.reader.Read(p[n:])
return n + m, err
}
}
return r.reader.Read(p)
}
// ReadTCPSession reads a Shadowsocks TCP session from the given reader, returns its header and remaining parts. // ReadTCPSession reads a Shadowsocks TCP session from the given reader, returns its header and remaining parts.
func ReadTCPSession(user *protocol.MemoryUser, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) { func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {
account := user.Account.(*MemoryAccount)
hashkdf := hmac.New(sha256.New, []byte("SSBSKDF")) hashkdf := hmac.New(sha256.New, []byte("SSBSKDF"))
hashkdf.Write(account.Key)
behaviorSeed := crc32.ChecksumIEEE(hashkdf.Sum(nil)) behaviorSeed := crc32.ChecksumIEEE(hashkdf.Sum(nil))
@@ -44,28 +67,69 @@ func ReadTCPSession(user *protocol.MemoryUser, reader io.Reader) (*protocol.Requ
DrainSize := BaseDrainSize + 16 + 38 + RandDrainRolled DrainSize := BaseDrainSize + 16 + 38 + RandDrainRolled
readSizeRemain := DrainSize readSizeRemain := DrainSize
var r2 buf.Reader
buffer := buf.New() buffer := buf.New()
defer buffer.Release() defer buffer.Release()
ivLen := account.Cipher.IVSize() var user *protocol.MemoryUser
var iv []byte var ivLen int32
if ivLen > 0 { var err error
if _, err := buffer.ReadFullFrom(reader, ivLen); err != nil {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed to read IV").Base(err)
}
iv = append([]byte(nil), buffer.BytesTo(ivLen)...) count := validator.Count()
} if count == 0 {
r, err := account.Cipher.NewDecryptionReader(account.Key, iv, reader)
if err != nil {
readSizeRemain -= int(buffer.Len()) readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain) DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed to initialize decoding stream").Base(err).AtError() return nil, nil, newError("invalid user")
} else if count > 1 {
var aead cipher.AEAD
if _, err := buffer.ReadFullFrom(reader, 50); err != nil {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed to read 50 bytes").Base(err)
}
bs := buffer.Bytes()
user, aead, _, ivLen, err = validator.Get(bs, protocol.RequestCommandTCP)
if user != nil {
reader = &FullReader{reader, bs[ivLen:]}
auth := &crypto.AEADAuthenticator{
AEAD: aead,
NonceGenerator: crypto.GenerateInitialAEADNonce(),
}
r2 = crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
Auth: auth,
}, reader, protocol.TransferTypeStream, nil)
} else {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed to match an user").Base(err)
}
} else {
user, ivLen = validator.GetOnlyUser()
account := user.Account.(*MemoryAccount)
hashkdf.Write(account.Key)
var iv []byte
if ivLen > 0 {
if _, err := buffer.ReadFullFrom(reader, ivLen); err != nil {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed to read IV").Base(err)
}
iv = append([]byte(nil), buffer.BytesTo(ivLen)...)
}
r, err := account.Cipher.NewDecryptionReader(account.Key, iv, reader)
if err != nil {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed to initialize decoding stream").Base(err).AtError()
}
r2 = r
} }
br := &buf.BufferedReader{Reader: r}
br := &buf.BufferedReader{Reader: r2}
request := &protocol.RequestHeader{ request := &protocol.RequestHeader{
Version: Version, Version: Version,
@@ -185,18 +249,41 @@ func EncodeUDPPacket(request *protocol.RequestHeader, payload []byte) (*buf.Buff
return buffer, nil return buffer, nil
} }
func DecodeUDPPacket(user *protocol.MemoryUser, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) { func DecodeUDPPacket(validator *Validator, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) {
account := user.Account.(*MemoryAccount) bs := payload.Bytes()
if len(bs) <= 32 {
var iv []byte return nil, nil, newError("len(bs) <= 32")
if !account.Cipher.IsAEAD() && account.Cipher.IVSize() > 0 {
// Keep track of IV as it gets removed from payload in DecodePacket.
iv = make([]byte, account.Cipher.IVSize())
copy(iv, payload.BytesTo(account.Cipher.IVSize()))
} }
if err := account.Cipher.DecodePacket(account.Key, payload); err != nil { var user *protocol.MemoryUser
return nil, nil, newError("failed to decrypt UDP payload").Base(err) var err error
count := validator.Count()
if count == 0 {
return nil, nil, newError("invalid user")
} else if count > 1 {
var d []byte
user, _, d, _, err = validator.Get(bs, protocol.RequestCommandUDP)
if user != nil {
payload.Clear()
payload.Write(d)
} else {
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
}
} else {
user, _ = validator.GetOnlyUser()
account := user.Account.(*MemoryAccount)
var iv []byte
if !account.Cipher.IsAEAD() && account.Cipher.IVSize() > 0 {
// Keep track of IV as it gets removed from payload in DecodePacket.
iv = make([]byte, account.Cipher.IVSize())
copy(iv, payload.BytesTo(account.Cipher.IVSize()))
}
if err = account.Cipher.DecodePacket(account.Key, payload); err != nil {
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
}
} }
request := &protocol.RequestHeader{ request := &protocol.RequestHeader{
@@ -230,15 +317,16 @@ func (v *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
buffer.Release() buffer.Release()
return nil, err return nil, err
} }
u, payload, err := DecodeUDPPacket(v.User, buffer) validator := new(Validator)
validator.Add(v.User)
u, payload, err := DecodeUDPPacket(validator, buffer)
if err != nil { if err != nil {
buffer.Release() buffer.Release()
return nil, err return nil, err
} }
payload.UDP = &net.UDPAddr{ dest := u.Destination()
IP: u.Address.IP(), payload.UDP = &dest
Port: int(u.Port),
}
return buf.MultiBuffer{payload}, nil return buf.MultiBuffer{payload}, nil
} }
@@ -254,18 +342,15 @@ func (w *UDPWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
if b == nil { if b == nil {
break break
} }
var packet *buf.Buffer request := w.Request
var err error
if b.UDP != nil { if b.UDP != nil {
request := &protocol.RequestHeader{ request = &protocol.RequestHeader{
User: w.Request.User, User: w.Request.User,
Address: net.IPAddress(b.UDP.IP), Address: b.UDP.Address,
Port: net.Port(b.UDP.Port), Port: b.UDP.Port,
} }
packet, err = EncodeUDPPacket(request, b.Bytes())
} else {
packet, err = EncodeUDPPacket(w.Request, b.Bytes())
} }
packet, err := EncodeUDPPacket(request, b.Bytes())
b.Release() b.Release()
if err != nil { if err != nil {
buf.ReleaseMulti(mb) buf.ReleaseMulti(mb)

View File

@@ -28,7 +28,7 @@ func TestUDPEncoding(t *testing.T) {
Email: "love@example.com", Email: "love@example.com",
Account: toAccount(&Account{ Account: toAccount(&Account{
Password: "shadowsocks-password", Password: "shadowsocks-password",
CipherType: CipherType_AES_128_CFB, CipherType: CipherType_AES_128_GCM,
}), }),
}, },
} }
@@ -38,14 +38,16 @@ func TestUDPEncoding(t *testing.T) {
encodedData, err := EncodeUDPPacket(request, data.Bytes()) encodedData, err := EncodeUDPPacket(request, data.Bytes())
common.Must(err) common.Must(err)
decodedRequest, decodedData, err := DecodeUDPPacket(request.User, encodedData) validator := new(Validator)
validator.Add(request.User)
decodedRequest, decodedData, err := DecodeUDPPacket(validator, encodedData)
common.Must(err) common.Must(err)
if r := cmp.Diff(decodedData.Bytes(), data.Bytes()); r != "" { if r := cmp.Diff(decodedData.Bytes(), data.Bytes()); r != "" {
t.Error("data: ", r) t.Error("data: ", r)
} }
if r := cmp.Diff(decodedRequest, request); r != "" { if r := cmp.Diff(decodedRequest, request, cmp.Comparer(func(a1, a2 protocol.Account) bool { return a1.Equals(a2) })); r != "" {
t.Error("request: ", r) t.Error("request: ", r)
} }
} }
@@ -65,7 +67,7 @@ func TestTCPRequest(t *testing.T) {
Email: "love@example.com", Email: "love@example.com",
Account: toAccount(&Account{ Account: toAccount(&Account{
Password: "tcp-password", Password: "tcp-password",
CipherType: CipherType_CHACHA20, CipherType: CipherType_CHACHA20_POLY1305,
}), }),
}, },
}, },
@@ -81,7 +83,7 @@ func TestTCPRequest(t *testing.T) {
Email: "love@example.com", Email: "love@example.com",
Account: toAccount(&Account{ Account: toAccount(&Account{
Password: "password", Password: "password",
CipherType: CipherType_AES_256_CFB, CipherType: CipherType_AES_256_GCM,
}), }),
}, },
}, },
@@ -97,7 +99,7 @@ func TestTCPRequest(t *testing.T) {
Email: "love@example.com", Email: "love@example.com",
Account: toAccount(&Account{ Account: toAccount(&Account{
Password: "password", Password: "password",
CipherType: CipherType_CHACHA20_IETF, CipherType: CipherType_AES_128_GCM,
}), }),
}, },
}, },
@@ -117,9 +119,11 @@ func TestTCPRequest(t *testing.T) {
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{data})) common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{data}))
decodedRequest, reader, err := ReadTCPSession(request.User, cache) validator := new(Validator)
validator.Add(request.User)
decodedRequest, reader, err := ReadTCPSession(validator, cache)
common.Must(err) common.Must(err)
if r := cmp.Diff(decodedRequest, request); r != "" { if r := cmp.Diff(decodedRequest, request, cmp.Comparer(func(a1, a2 protocol.Account) bool { return a1.Equals(a2) })); r != "" {
t.Error("request: ", r) t.Error("request: ", r)
} }
@@ -139,7 +143,7 @@ func TestUDPReaderWriter(t *testing.T) {
user := &protocol.MemoryUser{ user := &protocol.MemoryUser{
Account: toAccount(&Account{ Account: toAccount(&Account{
Password: "test-password", Password: "test-password",
CipherType: CipherType_CHACHA20_IETF, CipherType: CipherType_CHACHA20_POLY1305,
}), }),
} }
cache := buf.New() cache := buf.New()

View File

@@ -22,39 +22,51 @@ import (
type Server struct { type Server struct {
config *ServerConfig config *ServerConfig
user *protocol.MemoryUser validator *Validator
policyManager policy.Manager policyManager policy.Manager
cone bool
} }
// NewServer create a new Shadowsocks server. // NewServer create a new Shadowsocks server.
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) { func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
if config.GetUser() == nil { validator := new(Validator)
return nil, newError("user is not specified") for _, user := range config.Users {
} u, err := user.ToMemoryUser()
if err != nil {
return nil, newError("failed to get shadowsocks user").Base(err).AtError()
}
mUser, err := config.User.ToMemoryUser() if err := validator.Add(u); err != nil {
if err != nil { return nil, newError("failed to add user").Base(err).AtError()
return nil, newError("failed to parse user account").Base(err) }
} }
v := core.MustFromContext(ctx) v := core.MustFromContext(ctx)
s := &Server{ s := &Server{
config: config, config: config,
user: mUser, validator: validator,
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
cone: ctx.Value("cone").(bool),
} }
return s, nil return s, nil
} }
// AddUser implements proxy.UserManager.AddUser().
func (s *Server) AddUser(ctx context.Context, u *protocol.MemoryUser) error {
return s.validator.Add(u)
}
// RemoveUser implements proxy.UserManager.RemoveUser().
func (s *Server) RemoveUser(ctx context.Context, e string) error {
return s.validator.Del(e)
}
func (s *Server) Network() []net.Network { func (s *Server) Network() []net.Network {
list := s.config.Network list := s.config.Network
if len(list) == 0 { if len(list) == 0 {
list = append(list, net.Network_TCP) list = append(list, net.Network_TCP)
} }
if s.config.UdpEnabled {
list = append(list, net.Network_UDP)
}
return list return list
} }
@@ -63,13 +75,13 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
case net.Network_TCP: case net.Network_TCP:
return s.handleConnection(ctx, conn, dispatcher) return s.handleConnection(ctx, conn, dispatcher)
case net.Network_UDP: case net.Network_UDP:
return s.handlerUDPPayload(ctx, conn, dispatcher) return s.handleUDPPayload(ctx, conn, dispatcher)
default: default:
return newError("unknown network: ", network) return newError("unknown network: ", network)
} }
} }
func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error { func (s *Server) handleUDPPayload(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error {
udpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) { udpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) {
request := protocol.RequestHeaderFromContext(ctx) request := protocol.RequestHeaderFromContext(ctx)
if request == nil { if request == nil {
@@ -81,8 +93,8 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
if payload.UDP != nil { if payload.UDP != nil {
request = &protocol.RequestHeader{ request = &protocol.RequestHeader{
User: request.User, User: request.User,
Address: net.IPAddress(payload.UDP.IP), Address: payload.UDP.Address,
Port: net.Port(payload.UDP.Port), Port: payload.UDP.Port,
} }
} }
@@ -101,9 +113,12 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
if inbound == nil { if inbound == nil {
panic("no inbound metadata") panic("no inbound metadata")
} }
inbound.User = s.user
var dest net.Destination if s.validator.Count() == 1 {
inbound.User, _ = s.validator.GetOnlyUser()
}
var dest *net.Destination
reader := buf.NewPacketReader(conn) reader := buf.NewPacketReader(conn)
for { for {
@@ -113,9 +128,23 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
} }
for _, payload := range mpayload { for _, payload := range mpayload {
request, data, err := DecodeUDPPacket(s.user, payload) var request *protocol.RequestHeader
var data *buf.Buffer
var err error
if inbound.User != nil {
validator := new(Validator)
validator.Add(inbound.User)
request, data, err = DecodeUDPPacket(validator, payload)
} else {
request, data, err = DecodeUDPPacket(s.validator, payload)
if err == nil {
inbound.User = request.User
}
}
if err != nil { if err != nil {
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() { if inbound.Source.IsValid() {
newError("dropping invalid UDP packet from: ", inbound.Source).Base(err).WriteToLog(session.ExportIDToError(ctx)) newError("dropping invalid UDP packet from: ", inbound.Source).Base(err).WriteToLog(session.ExportIDToError(ctx))
log.Record(&log.AccessMessage{ log.Record(&log.AccessMessage{
From: inbound.Source, From: inbound.Source,
@@ -128,29 +157,28 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
continue continue
} }
destination := request.Destination()
currentPacketCtx := ctx currentPacketCtx := ctx
if inbound.Source.IsValid() { if inbound.Source.IsValid() {
currentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{ currentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: inbound.Source, From: inbound.Source,
To: request.Destination(), To: destination,
Status: log.AccessAccepted, Status: log.AccessAccepted,
Reason: "", Reason: "",
Email: request.User.Email, Email: request.User.Email,
}) })
} }
newError("tunnelling request to ", request.Destination()).WriteToLog(session.ExportIDToError(currentPacketCtx)) newError("tunnelling request to ", destination).WriteToLog(session.ExportIDToError(currentPacketCtx))
data.UDP = &net.UDPAddr{ data.UDP = &destination
IP: request.Address.IP(),
Port: int(request.Port),
}
if dest.Network == 0 { if !s.cone || dest == nil {
dest = request.Destination() // JUST FOLLOW THE FIREST PACKET dest = &destination
} }
currentPacketCtx = protocol.ContextWithRequestHeader(currentPacketCtx, request) currentPacketCtx = protocol.ContextWithRequestHeader(currentPacketCtx, request)
udpServer.Dispatch(currentPacketCtx, dest, data) udpServer.Dispatch(currentPacketCtx, *dest, data)
} }
} }
@@ -158,11 +186,13 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
} }
func (s *Server) handleConnection(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error { func (s *Server) handleConnection(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error {
sessionPolicy := s.policyManager.ForLevel(s.user.Level) sessionPolicy := s.policyManager.ForLevel(0)
conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)) if err := conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
return newError("unable to set read deadline").Base(err).AtWarning()
}
bufferedReader := buf.BufferedReader{Reader: buf.NewReader(conn)} bufferedReader := buf.BufferedReader{Reader: buf.NewReader(conn)}
request, bodyReader, err := ReadTCPSession(s.user, &bufferedReader) request, bodyReader, err := ReadTCPSession(s.validator, &bufferedReader)
if err != nil { if err != nil {
log.Record(&log.AccessMessage{ log.Record(&log.AccessMessage{
From: conn.RemoteAddr(), From: conn.RemoteAddr(),
@@ -178,7 +208,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
if inbound == nil { if inbound == nil {
panic("no inbound metadata") panic("no inbound metadata")
} }
inbound.User = s.user inbound.User = request.User
dest := request.Destination() dest := request.Destination()
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{ ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
@@ -190,6 +220,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
}) })
newError("tunnelling request to ", dest).WriteToLog(session.ExportIDToError(ctx)) newError("tunnelling request to ", dest).WriteToLog(session.ExportIDToError(ctx))
sessionPolicy = s.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, cancel, sessionPolicy.Timeouts.ConnectionIdle)

View File

@@ -0,0 +1,113 @@
package shadowsocks
import (
"crypto/cipher"
"strings"
"sync"
"github.com/xtls/xray-core/common/protocol"
)
// Validator stores valid Shadowsocks users.
type Validator struct {
// Considering email's usage here, map + sync.Mutex/RWMutex may have better performance.
email sync.Map
users sync.Map
}
// Add a Shadowsocks user, Email must be empty or unique.
func (v *Validator) Add(u *protocol.MemoryUser) error {
account := u.Account.(*MemoryAccount)
if !account.Cipher.IsAEAD() && v.Count() > 0 {
return newError("The cipher do not support Single-port Multi-user")
}
if u.Email != "" {
_, loaded := v.email.LoadOrStore(strings.ToLower(u.Email), u)
if loaded {
return newError("User ", u.Email, " already exists.")
}
}
v.users.Store(string(account.Key)+"&"+account.GetCipherName(), u)
return nil
}
// Del a Shadowsocks user with a non-empty Email.
func (v *Validator) Del(e string) error {
if e == "" {
return newError("Email must not be empty.")
}
le := strings.ToLower(e)
u, _ := v.email.Load(le)
if u == nil {
return newError("User ", e, " not found.")
}
account := u.(*protocol.MemoryUser).Account.(*MemoryAccount)
v.email.Delete(le)
v.users.Delete(string(account.Key) + "&" + account.GetCipherName())
return nil
}
// Count the number of Shadowsocks users
func (v *Validator) Count() int {
length := 0
v.users.Range(func(_, _ interface{}) bool {
length++
return true
})
return length
}
// Get a Shadowsocks user and the user's cipher.
func (v *Validator) Get(bs []byte, command protocol.RequestCommand) (u *protocol.MemoryUser, aead cipher.AEAD, ret []byte, ivLen int32, err error) {
var dataSize int
switch command {
case protocol.RequestCommandTCP:
dataSize = 16
case protocol.RequestCommandUDP:
dataSize = 8192
}
var aeadCipher *AEADCipher
subkey := make([]byte, 32)
data := make([]byte, dataSize)
v.users.Range(func(key, user interface{}) bool {
account := user.(*protocol.MemoryUser).Account.(*MemoryAccount)
aeadCipher = account.Cipher.(*AEADCipher)
ivLen = aeadCipher.IVSize()
subkey = subkey[:aeadCipher.KeyBytes]
hkdfSHA1(account.Key, bs[:ivLen], subkey)
aead = aeadCipher.AEADAuthCreator(subkey)
switch command {
case protocol.RequestCommandTCP:
ret, err = aead.Open(data[:0], data[4:16], bs[ivLen:ivLen+18], nil)
case protocol.RequestCommandUDP:
ret, err = aead.Open(data[:0], data[8180:8192], bs[ivLen:], nil)
}
if err == nil {
u = user.(*protocol.MemoryUser)
return false
}
return true
})
return
}
// Get the only user without authentication
func (v *Validator) GetOnlyUser() (u *protocol.MemoryUser, ivLen int32) {
v.users.Range(func(_, user interface{}) bool {
u = user.(*protocol.MemoryUser)
return false
})
ivLen = u.Account.(*MemoryAccount).Cipher.IVSize()
return
}

View File

@@ -138,11 +138,12 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
defer udpConn.Close() defer udpConn.Close()
requestFunc = func() error { requestFunc = func() error {
defer timer.SetTimeout(p.Timeouts.DownlinkOnly) defer timer.SetTimeout(p.Timeouts.DownlinkOnly)
return buf.Copy(link.Reader, &buf.SequentialWriter{Writer: NewUDPWriter(request, udpConn)}, buf.UpdateActivity(timer)) writer := &UDPWriter{Writer: udpConn, Request: request}
return buf.Copy(link.Reader, writer, buf.UpdateActivity(timer))
} }
responseFunc = func() error { responseFunc = func() error {
defer timer.SetTimeout(p.Timeouts.UplinkOnly) defer timer.SetTimeout(p.Timeouts.UplinkOnly)
reader := &UDPReader{reader: udpConn} reader := &UDPReader{Reader: udpConn}
return buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)) return buf.Copy(reader, link.Writer, buf.UpdateActivity(timer))
} }
} }

View File

@@ -39,10 +39,10 @@ var addrParser = protocol.NewAddressParser(
) )
type ServerSession struct { type ServerSession struct {
config *ServerConfig config *ServerConfig
address net.Address address net.Address
port net.Port port net.Port
clientAddress net.Address localAddress net.Address
} }
func (s *ServerSession) handshake4(cmd byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) { func (s *ServerSession) handshake4(cmd byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {
@@ -192,14 +192,11 @@ func (s *ServerSession) handshake5(nMethod byte, reader io.Reader, writer io.Wri
//nolint:gocritic // Use if else chain for clarity //nolint:gocritic // Use if else chain for clarity
if request.Command == protocol.RequestCommandUDP { if request.Command == protocol.RequestCommandUDP {
if s.config.Address != nil { if s.config.Address != nil {
// Use configured IP as remote address in the response to UdpAssociate // Use configured IP as remote address in the response to UDP Associate
responseAddress = s.config.Address.AsAddress() responseAddress = s.config.Address.AsAddress()
} else if s.clientAddress == net.LocalHostIP || s.clientAddress == net.LocalHostIPv6 {
// For localhost clients use loopback IP
responseAddress = s.clientAddress
} else { } else {
// For non-localhost clients use inbound listening address // Use conn.LocalAddr() IP as remote address in the response by default
responseAddress = s.address responseAddress = s.localAddress
} }
} }
if err := writeSocks5Response(writer, statusSuccess, responseAddress, responsePort); err != nil { if err := writeSocks5Response(writer, statusSuccess, responseAddress, responsePort); err != nil {
@@ -360,47 +357,59 @@ func EncodeUDPPacket(request *protocol.RequestHeader, data []byte) (*buf.Buffer,
} }
type UDPReader struct { type UDPReader struct {
reader io.Reader Reader io.Reader
}
func NewUDPReader(reader io.Reader) *UDPReader {
return &UDPReader{reader: reader}
} }
func (r *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) { func (r *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
b := buf.New() buffer := buf.New()
if _, err := b.ReadFrom(r.reader); err != nil { _, err := buffer.ReadFrom(r.Reader)
if err != nil {
buffer.Release()
return nil, err return nil, err
} }
if _, err := DecodeUDPPacket(b); err != nil { u, err := DecodeUDPPacket(buffer)
if err != nil {
buffer.Release()
return nil, err return nil, err
} }
return buf.MultiBuffer{b}, nil dest := u.Destination()
buffer.UDP = &dest
return buf.MultiBuffer{buffer}, nil
} }
type UDPWriter struct { type UDPWriter struct {
request *protocol.RequestHeader Writer io.Writer
writer io.Writer Request *protocol.RequestHeader
} }
func NewUDPWriter(request *protocol.RequestHeader, writer io.Writer) *UDPWriter { func (w *UDPWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
return &UDPWriter{ for {
request: request, mb2, b := buf.SplitFirst(mb)
writer: writer, mb = mb2
if b == nil {
break
}
request := w.Request
if b.UDP != nil {
request = &protocol.RequestHeader{
Address: b.UDP.Address,
Port: b.UDP.Port,
}
}
packet, err := EncodeUDPPacket(request, b.Bytes())
b.Release()
if err != nil {
buf.ReleaseMulti(mb)
return err
}
_, err = w.Writer.Write(packet.Bytes())
packet.Release()
if err != nil {
buf.ReleaseMulti(mb)
return err
}
} }
} return nil
// Write implements io.Writer.
func (w *UDPWriter) Write(b []byte) (int, error) {
eb, err := EncodeUDPPacket(w.request, b)
if err != nil {
return 0, err
}
defer eb.Release()
if _, err := w.writer.Write(eb.Bytes()); err != nil {
return 0, err
}
return len(b), nil
} }
func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) { func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {
@@ -413,16 +422,6 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
defer b.Release() defer b.Release()
common.Must2(b.Write([]byte{socks5Version, 0x01, authByte})) common.Must2(b.Write([]byte{socks5Version, 0x01, authByte}))
if authByte == authPassword {
account := request.User.Account.(*Account)
common.Must(b.WriteByte(0x01))
common.Must(b.WriteByte(byte(len(account.Username))))
common.Must2(b.WriteString(account.Username))
common.Must(b.WriteByte(byte(len(account.Password))))
common.Must2(b.WriteString(account.Password))
}
if err := buf.WriteAllBytes(writer, b.Bytes()); err != nil { if err := buf.WriteAllBytes(writer, b.Bytes()); err != nil {
return nil, err return nil, err
} }
@@ -440,6 +439,17 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
} }
if authByte == authPassword { if authByte == authPassword {
b.Clear()
account := request.User.Account.(*Account)
common.Must(b.WriteByte(0x01))
common.Must(b.WriteByte(byte(len(account.Username))))
common.Must2(b.WriteString(account.Username))
common.Must(b.WriteByte(byte(len(account.Password))))
common.Must2(b.WriteString(account.Password))
if err := buf.WriteAllBytes(writer, b.Bytes()); err != nil {
return nil, err
}
b.Clear() b.Clear()
if _, err := b.ReadFullFrom(reader, 2); err != nil { if _, err := b.ReadFullFrom(reader, 2); err != nil {
return nil, err return nil, err
@@ -456,8 +466,12 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
command = byte(cmdUDPAssociate) command = byte(cmdUDPAssociate)
} }
common.Must2(b.Write([]byte{socks5Version, command, 0x00 /* reserved */})) common.Must2(b.Write([]byte{socks5Version, command, 0x00 /* reserved */}))
if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil { if request.Command == protocol.RequestCommandUDP {
return nil, err common.Must2(b.Write([]byte{1, 0, 0, 0, 0, 0, 0 /* RFC 1928 */}))
} else {
if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil {
return nil, err
}
} }
if err := buf.WriteAllBytes(writer, b.Bytes()); err != nil { if err := buf.WriteAllBytes(writer, b.Bytes()); err != nil {

View File

@@ -20,14 +20,14 @@ func TestUDPEncoding(t *testing.T) {
Address: net.IPAddress([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}), Address: net.IPAddress([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}),
Port: 1024, Port: 1024,
} }
writer := &buf.SequentialWriter{Writer: NewUDPWriter(request, b)} writer := &UDPWriter{Writer: b, Request: request}
content := []byte{'a'} content := []byte{'a'}
payload := buf.New() payload := buf.New()
payload.Write(content) payload.Write(content)
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{payload})) common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{payload}))
reader := NewUDPReader(b) reader := &UDPReader{Reader: b}
decodedPayload, err := reader.ReadMultiBuffer() decodedPayload, err := reader.ReadMultiBuffer()
common.Must(err) common.Must(err)

View File

@@ -26,6 +26,7 @@ import (
type Server struct { type Server struct {
config *ServerConfig config *ServerConfig
policyManager policy.Manager policyManager policy.Manager
cone bool
} }
// NewServer creates a new Server object. // NewServer creates a new Server object.
@@ -34,6 +35,7 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
s := &Server{ s := &Server{
config: config, config: config,
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
cone: ctx.Value("cone").(bool),
} }
return s, nil return s, nil
} }
@@ -89,10 +91,10 @@ func (s *Server) processTCP(ctx context.Context, conn internet.Connection, dispa
} }
svrSession := &ServerSession{ svrSession := &ServerSession{
config: s.config, config: s.config,
address: inbound.Gateway.Address, address: inbound.Gateway.Address,
port: inbound.Gateway.Port, port: inbound.Gateway.Port,
clientAddress: inbound.Source.Address, localAddress: net.IPAddress(conn.LocalAddr().(*net.TCPAddr).IP),
} }
reader := &buf.BufferedReader{Reader: buf.NewReader(conn)} reader := &buf.BufferedReader{Reader: buf.NewReader(conn)}
@@ -202,8 +204,8 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn internet.Connection,
if payload.UDP != nil { if payload.UDP != nil {
request = &protocol.RequestHeader{ request = &protocol.RequestHeader{
User: request.User, User: request.User,
Address: net.IPAddress(payload.UDP.IP), Address: payload.UDP.Address,
Port: net.Port(payload.UDP.Port), Port: payload.UDP.Port,
} }
} }
@@ -218,11 +220,12 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn internet.Connection,
conn.Write(udpMessage.Bytes()) conn.Write(udpMessage.Bytes())
}) })
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() { inbound := session.InboundFromContext(ctx)
if inbound != nil && inbound.Source.IsValid() {
newError("client UDP connection from ", inbound.Source).WriteToLog(session.ExportIDToError(ctx)) newError("client UDP connection from ", inbound.Source).WriteToLog(session.ExportIDToError(ctx))
} }
var dest net.Destination var dest *net.Destination
reader := buf.NewPacketReader(conn) reader := buf.NewPacketReader(conn)
for { for {
@@ -244,28 +247,28 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn internet.Connection,
payload.Release() payload.Release()
continue continue
} }
destination := request.Destination()
currentPacketCtx := ctx currentPacketCtx := ctx
newError("send packet to ", request.Destination(), " with ", payload.Len(), " bytes").AtDebug().WriteToLog(session.ExportIDToError(ctx)) newError("send packet to ", destination, " with ", payload.Len(), " bytes").AtDebug().WriteToLog(session.ExportIDToError(ctx))
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() { if inbound != nil && inbound.Source.IsValid() {
currentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{ currentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: inbound.Source, From: inbound.Source,
To: request.Destination(), To: destination,
Status: log.AccessAccepted, Status: log.AccessAccepted,
Reason: "", Reason: "",
}) })
} }
payload.UDP = &net.UDPAddr{ payload.UDP = &destination
IP: request.Address.IP(),
Port: int(request.Port),
}
if dest.Network == 0 { if !s.cone || dest == nil {
dest = request.Destination() // JUST FOLLOW THE FIREST PACKET dest = &destination
} }
currentPacketCtx = protocol.ContextWithRequestHeader(currentPacketCtx, request) currentPacketCtx = protocol.ContextWithRequestHeader(currentPacketCtx, request)
udpServer.Dispatch(currentPacketCtx, dest, payload) udpServer.Dispatch(currentPacketCtx, *dest, payload)
} }
} }
} }

View File

@@ -7,6 +7,7 @@ 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/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/platform"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
@@ -145,12 +146,13 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
postRequest := func() error { postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly) defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
var bodyWriter buf.Writer
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn)) bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
connWriter.Writer = bufferWriter connWriter.Writer = bufferWriter
connWriter.Target = destination connWriter.Target = destination
connWriter.Account = account connWriter.Account = account
var bodyWriter buf.Writer
if destination.Network == net.Network_UDP { if destination.Network == net.Network_UDP {
bodyWriter = &PacketWriter{Writer: connWriter, Target: destination} bodyWriter = &PacketWriter{Writer: connWriter, Target: destination}
} else { } else {
@@ -167,6 +169,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
return newError("failed to flush payload").Base(err).AtWarning() return newError("failed to flush payload").Base(err).AtWarning()
} }
// Send header if not sent yet
if _, err = connWriter.Write([]byte{}); err != nil {
return err.(*errors.Error).AtWarning()
}
if err = buf.Copy(link.Reader, bodyWriter, buf.UpdateActivity(timer)); err != nil { if err = buf.Copy(link.Reader, bodyWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transfer request payload").Base(err).AtInfo() return newError("failed to transfer request payload").Base(err).AtInfo()
} }

View File

@@ -86,11 +86,12 @@ type Fallback struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Alpn string `protobuf:"bytes,1,opt,name=alpn,proto3" json:"alpn,omitempty"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` Alpn string `protobuf:"bytes,2,opt,name=alpn,proto3" json:"alpn,omitempty"`
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
Dest string `protobuf:"bytes,4,opt,name=dest,proto3" json:"dest,omitempty"` Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"`
Xver uint64 `protobuf:"varint,5,opt,name=xver,proto3" json:"xver,omitempty"` Dest string `protobuf:"bytes,5,opt,name=dest,proto3" json:"dest,omitempty"`
Xver uint64 `protobuf:"varint,6,opt,name=xver,proto3" json:"xver,omitempty"`
} }
func (x *Fallback) Reset() { func (x *Fallback) Reset() {
@@ -125,6 +126,13 @@ func (*Fallback) Descriptor() ([]byte, []int) {
return file_proxy_trojan_config_proto_rawDescGZIP(), []int{1} return file_proxy_trojan_config_proto_rawDescGZIP(), []int{1}
} }
func (x *Fallback) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *Fallback) GetAlpn() string { func (x *Fallback) GetAlpn() string {
if x != nil { if x != nil {
return x.Alpn return x.Alpn
@@ -275,33 +283,34 @@ var file_proxy_trojan_config_proto_rawDesc = []byte{
0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73,
0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73,
0x77, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x22, 0x6e, 0x0a, 0x08, 0x46, 0x61, 0x6c, 0x6c, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x22, 0x82, 0x01, 0x0a, 0x08, 0x46, 0x61, 0x6c,
0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c, 0x70,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12, 0x0a,
0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74,
0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20,
0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65,
0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0x4c, 0x0a,
0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e,
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x7b, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x7b, 0x0a, 0x0c, 0x53,
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x30, 0x0a, 0x05, 0x75,
0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61,
0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x39, 0x0a, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x62, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x39, 0x0a,
0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72,
0x63, 0x6b, 0x73, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x09, 0x66,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61,
0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70,
0x6f, 0x78, 0x79, 0x2e, 0x54, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72,
0x6f, 0x33, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x54, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -15,11 +15,12 @@ message Account {
} }
message Fallback { message Fallback {
string alpn = 1; string name = 1;
string path = 2; string alpn = 2;
string type = 3; string path = 3;
string dest = 4; string type = 4;
uint64 xver = 5; string dest = 5;
uint64 xver = 6;
} }
message ClientConfig { message ClientConfig {

View File

@@ -134,33 +134,11 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
if b == nil { if b == nil {
break break
} }
target := w.Target target := &w.Target
if b.UDP != nil { if b.UDP != nil {
target.Address = net.IPAddress(b.UDP.IP) target = b.UDP
target.Port = net.Port(b.UDP.Port)
} }
if _, err := w.writePacket(b.Bytes(), target); err != nil { if _, err := w.writePacket(b.Bytes(), *target); err != nil {
buf.ReleaseMulti(mb)
return err
}
}
return nil
}
// WriteMultiBufferWithMetadata writes udp packet with destination specified
func (w *PacketWriter) WriteMultiBufferWithMetadata(mb buf.MultiBuffer, dest net.Destination) error {
for {
mb2, b := buf.SplitFirst(mb)
mb = mb2
if b == nil {
break
}
source := dest
if b.UDP != nil {
source.Address = net.IPAddress(b.UDP.IP)
source.Port = net.Port(b.UDP.Port)
}
if _, err := w.writePacket(b.Bytes(), source); err != nil {
buf.ReleaseMulti(mb) buf.ReleaseMulti(mb)
return err return err
} }
@@ -261,12 +239,6 @@ func (c *ConnReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
return buf.MultiBuffer{b}, err return buf.MultiBuffer{b}, err
} }
// PacketPayload combines udp payload and destination
type PacketPayload struct {
Target net.Destination
Buffer buf.MultiBuffer
}
// PacketReader is UDP Connection Reader Wrapper for trojan protocol // PacketReader is UDP Connection Reader Wrapper for trojan protocol
type PacketReader struct { type PacketReader struct {
io.Reader io.Reader
@@ -274,15 +246,6 @@ type PacketReader struct {
// ReadMultiBuffer implements buf.Reader // ReadMultiBuffer implements buf.Reader
func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) { func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
p, err := r.ReadMultiBufferWithMetadata()
if p != nil {
return p.Buffer, err
}
return nil, err
}
// ReadMultiBufferWithMetadata reads udp packet with destination
func (r *PacketReader) ReadMultiBufferWithMetadata() (*PacketPayload, error) {
addr, port, err := addrParser.ReadAddressPort(nil, r) addr, port, err := addrParser.ReadAddressPort(nil, r)
if err != nil { if err != nil {
return nil, newError("failed to read address and port").Base(err) return nil, newError("failed to read address and port").Base(err)
@@ -312,10 +275,7 @@ func (r *PacketReader) ReadMultiBufferWithMetadata() (*PacketPayload, error) {
} }
b := buf.New() b := buf.New()
b.UDP = &net.UDPAddr{ b.UDP = &dest
IP: addr.IP(),
Port: int(port.Value()),
}
mb = append(mb, b) mb = append(mb, b)
n, err := b.ReadFullFrom(r, int32(length)) n, err := b.ReadFullFrom(r, int32(length))
if err != nil { if err != nil {
@@ -326,7 +286,7 @@ func (r *PacketReader) ReadMultiBufferWithMetadata() (*PacketPayload, error) {
remain -= int(n) remain -= int(n)
} }
return &PacketPayload{Target: dest, Buffer: 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 { func ReadV(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn *xtls.Conn, rawConn syscall.RawConn, counter stats.Counter, sctx context.Context) error {

View File

@@ -71,21 +71,22 @@ func TestUDPRequest(t *testing.T) {
common.Must(connReader.ParseHeader()) common.Must(connReader.ParseHeader())
packetReader := &PacketReader{Reader: connReader} packetReader := &PacketReader{Reader: connReader}
p, err := packetReader.ReadMultiBufferWithMetadata() mb, err := packetReader.ReadMultiBuffer()
common.Must(err) common.Must(err)
if p.Buffer.IsEmpty() { if mb.IsEmpty() {
t.Error("no request data") t.Error("no request data")
} }
if r := cmp.Diff(p.Target, destination); r != "" { mb2, b := buf.SplitFirst(mb)
defer buf.ReleaseMulti(mb2)
dest := *b.UDP
if r := cmp.Diff(dest, destination); r != "" {
t.Error("destination: ", r) t.Error("destination: ", r)
} }
mb, decoded := buf.SplitFirst(p.Buffer) if r := cmp.Diff(b.Bytes(), payload); r != "" {
buf.ReleaseMulti(mb)
if r := cmp.Diff(decoded.Bytes(), payload); r != "" {
t.Error("data: ", r) t.Error("data: ", r)
} }
} }

View File

@@ -5,6 +5,7 @@ import (
"crypto/tls" "crypto/tls"
"io" "io"
"strconv" "strconv"
"strings"
"syscall" "syscall"
"time" "time"
@@ -46,7 +47,8 @@ func init() {
type Server struct { type Server struct {
policyManager policy.Manager policyManager policy.Manager
validator *Validator validator *Validator
fallbacks map[string]map[string]*Fallback // or nil fallbacks map[string]map[string]map[string]*Fallback // or nil
cone bool
} }
// NewServer creates a new trojan inbound handler. // NewServer creates a new trojan inbound handler.
@@ -67,22 +69,52 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
server := &Server{ server := &Server{
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
validator: validator, validator: validator,
cone: ctx.Value("cone").(bool),
} }
if config.Fallbacks != nil { if config.Fallbacks != nil {
server.fallbacks = make(map[string]map[string]*Fallback) server.fallbacks = make(map[string]map[string]map[string]*Fallback)
for _, fb := range config.Fallbacks { for _, fb := range config.Fallbacks {
if server.fallbacks[fb.Alpn] == nil { if server.fallbacks[fb.Name] == nil {
server.fallbacks[fb.Alpn] = make(map[string]*Fallback) server.fallbacks[fb.Name] = make(map[string]map[string]*Fallback)
} }
server.fallbacks[fb.Alpn][fb.Path] = fb if server.fallbacks[fb.Name][fb.Alpn] == nil {
server.fallbacks[fb.Name][fb.Alpn] = make(map[string]*Fallback)
}
server.fallbacks[fb.Name][fb.Alpn][fb.Path] = fb
} }
if server.fallbacks[""] != nil { if server.fallbacks[""] != nil {
for alpn, pfb := range server.fallbacks { for name, apfb := range server.fallbacks {
if alpn != "" { // && alpn != "h2" { if name != "" {
for path, fb := range server.fallbacks[""] { for alpn := range server.fallbacks[""] {
if pfb[path] == nil { if apfb[alpn] == nil {
pfb[path] = fb apfb[alpn] = make(map[string]*Fallback)
}
}
}
}
}
for _, apfb := range server.fallbacks {
if apfb[""] != nil {
for alpn, pfb := range apfb {
if alpn != "" { // && alpn != "h2" {
for path, fb := range apfb[""] {
if pfb[path] == nil {
pfb[path] = fb
}
}
}
}
}
}
if server.fallbacks[""] != nil {
for name, apfb := range server.fallbacks {
if name != "" {
for alpn, pfb := range server.fallbacks[""] {
for path, fb := range pfb {
if apfb[alpn][path] == nil {
apfb[alpn][path] = fb
}
} }
} }
} }
@@ -139,8 +171,8 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
var user *protocol.MemoryUser var user *protocol.MemoryUser
apfb := s.fallbacks napfb := s.fallbacks
isfb := apfb != nil isfb := napfb != nil
shouldFallback := false shouldFallback := false
if firstLen < 58 || first.Byte(56) != '\r' { if firstLen < 58 || first.Byte(56) != '\r' {
@@ -171,7 +203,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
} }
if isfb && shouldFallback { if isfb && shouldFallback {
return s.fallback(ctx, sid, err, sessionPolicy, conn, iConn, apfb, first, firstLen, bufferedReader) return s.fallback(ctx, sid, err, sessionPolicy, conn, iConn, napfb, first, firstLen, bufferedReader)
} else if shouldFallback { } else if shouldFallback {
return newError("invalid protocol or invalid user") return newError("invalid protocol or invalid user")
} }
@@ -250,20 +282,27 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
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 {
udpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) { udpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) {
common.Must(clientWriter.WriteMultiBufferWithMetadata(buf.MultiBuffer{packet.Payload}, packet.Source)) udpPayload := packet.Payload
if udpPayload.UDP == nil {
udpPayload.UDP = &packet.Source
}
if err := clientWriter.WriteMultiBuffer(buf.MultiBuffer{udpPayload}); err != nil {
newError("failed to write response").Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))
}
}) })
inbound := session.InboundFromContext(ctx) inbound := session.InboundFromContext(ctx)
user := inbound.User user := inbound.User
var dest net.Destination var dest *net.Destination
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return nil return nil
default: default:
p, err := clientReader.ReadMultiBufferWithMetadata() mb, err := clientReader.ReadMultiBuffer()
if err != nil { if err != nil {
if errors.Cause(err) != io.EOF { if errors.Cause(err) != io.EOF {
return newError("unexpected EOF").Base(err) return newError("unexpected EOF").Base(err)
@@ -271,21 +310,31 @@ func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReade
return nil return nil
} }
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{ mb2, b := buf.SplitFirst(mb)
From: inbound.Source, if b == nil {
To: p.Target, continue
Status: log.AccessAccepted, }
Reason: "", destination := *b.UDP
Email: user.Email,
})
newError("tunnelling request to ", p.Target).WriteToLog(session.ExportIDToError(ctx))
if dest.Network == 0 { currentPacketCtx := ctx
dest = p.Target // JUST FOLLOW THE FIREST PACKET if inbound.Source.IsValid() {
currentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: inbound.Source,
To: destination,
Status: log.AccessAccepted,
Reason: "",
Email: user.Email,
})
}
newError("tunnelling request to ", destination).WriteToLog(session.ExportIDToError(ctx))
if !s.cone || dest == nil {
dest = &destination
} }
for _, b := range p.Buffer { udpServer.Dispatch(currentPacketCtx, *dest, b) // first packet
udpServer.Dispatch(ctx, dest, b) for _, payload := range mb2 {
udpServer.Dispatch(currentPacketCtx, *dest, payload)
} }
} }
} }
@@ -342,25 +391,53 @@ func (s *Server) handleConnection(ctx context.Context, sessionPolicy policy.Sess
return nil return nil
} }
func (s *Server) fallback(ctx context.Context, sid errors.ExportOption, err error, sessionPolicy policy.Session, connection internet.Connection, iConn internet.Connection, apfb map[string]map[string]*Fallback, first *buf.Buffer, firstLen int64, reader buf.Reader) error { func (s *Server) fallback(ctx context.Context, sid errors.ExportOption, err error, sessionPolicy policy.Session, connection internet.Connection, iConn internet.Connection, napfb map[string]map[string]map[string]*Fallback, first *buf.Buffer, firstLen int64, reader buf.Reader) error {
if err := connection.SetReadDeadline(time.Time{}); err != nil { if err := connection.SetReadDeadline(time.Time{}); err != nil {
newError("unable to set back read deadline").Base(err).AtWarning().WriteToLog(sid) newError("unable to set back read deadline").Base(err).AtWarning().WriteToLog(sid)
} }
newError("fallback starts").Base(err).AtInfo().WriteToLog(sid) newError("fallback starts").Base(err).AtInfo().WriteToLog(sid)
name := ""
alpn := "" alpn := ""
if len(apfb) > 1 || apfb[""] == nil { if tlsConn, ok := iConn.(*tls.Conn); ok {
if tlsConn, ok := iConn.(*tls.Conn); ok { cs := tlsConn.ConnectionState()
alpn = tlsConn.ConnectionState().NegotiatedProtocol name = cs.ServerName
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid) alpn = cs.NegotiatedProtocol
} else if xtlsConn, ok := iConn.(*xtls.Conn); ok { newError("realName = " + name).AtInfo().WriteToLog(sid)
alpn = xtlsConn.ConnectionState().NegotiatedProtocol newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid) } else if xtlsConn, ok := iConn.(*xtls.Conn); ok {
} cs := xtlsConn.ConnectionState()
if apfb[alpn] == nil { name = cs.ServerName
alpn = "" alpn = cs.NegotiatedProtocol
newError("realName = " + name).AtInfo().WriteToLog(sid)
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
}
name = strings.ToLower(name)
alpn = strings.ToLower(alpn)
if len(napfb) > 1 || napfb[""] == nil {
if name != "" && napfb[name] == nil {
match := ""
for n := range napfb {
if n != "" && strings.Contains(name, n) && len(n) > len(match) {
match = n
}
}
name = match
} }
} }
if napfb[name] == nil {
name = ""
}
apfb := napfb[name]
if apfb == nil {
return newError(`failed to find the default "name" config`).AtWarning()
}
if apfb[alpn] == nil {
alpn = ""
}
pfb := apfb[alpn] pfb := apfb[alpn]
if pfb == nil { if pfb == nil {
return newError(`failed to find the default "alpn" config`).AtWarning() return newError(`failed to find the default "alpn" config`).AtWarning()
@@ -423,38 +500,48 @@ func (s *Server) fallback(ctx context.Context, sid errors.ExportOption, err erro
postRequest := func() error { postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly) defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
if fb.Xver != 0 { if fb.Xver != 0 {
ipType := 4
remoteAddr, remotePort, err := net.SplitHostPort(connection.RemoteAddr().String()) remoteAddr, remotePort, err := net.SplitHostPort(connection.RemoteAddr().String())
if err != nil { if err != nil {
return err ipType = 0
} }
localAddr, localPort, err := net.SplitHostPort(connection.LocalAddr().String()) localAddr, localPort, err := net.SplitHostPort(connection.LocalAddr().String())
if err != nil { if err != nil {
return err ipType = 0
} }
ipv4 := true if ipType == 4 {
for i := 0; i < len(remoteAddr); i++ { for i := 0; i < len(remoteAddr); i++ {
if remoteAddr[i] == ':' { if remoteAddr[i] == ':' {
ipv4 = false ipType = 6
break break
}
} }
} }
pro := buf.New() pro := buf.New()
defer pro.Release() defer pro.Release()
switch fb.Xver { switch fb.Xver {
case 1: case 1:
if ipv4 { if ipType == 0 {
common.Must2(pro.Write([]byte("PROXY UNKNOWN\r\n")))
break
}
if ipType == 4 {
common.Must2(pro.Write([]byte("PROXY TCP4 " + remoteAddr + " " + localAddr + " " + remotePort + " " + localPort + "\r\n"))) common.Must2(pro.Write([]byte("PROXY TCP4 " + remoteAddr + " " + localAddr + " " + remotePort + " " + localPort + "\r\n")))
} else { } else {
common.Must2(pro.Write([]byte("PROXY TCP6 " + remoteAddr + " " + localAddr + " " + remotePort + " " + localPort + "\r\n"))) common.Must2(pro.Write([]byte("PROXY TCP6 " + remoteAddr + " " + localAddr + " " + remotePort + " " + localPort + "\r\n")))
} }
case 2: case 2:
common.Must2(pro.Write([]byte("\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x21"))) // signature + v2 + PROXY common.Must2(pro.Write([]byte("\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"))) // signature
if ipv4 { if ipType == 0 {
common.Must2(pro.Write([]byte("\x11\x00\x0C"))) // AF_INET + STREAM + 12 bytes common.Must2(pro.Write([]byte("\x20\x00\x00\x00"))) // v2 + LOCAL + UNSPEC + UNSPEC + 0 bytes
break
}
if ipType == 4 {
common.Must2(pro.Write([]byte("\x21\x11\x00\x0C"))) // v2 + PROXY + AF_INET + STREAM + 12 bytes
common.Must2(pro.Write(net.ParseIP(remoteAddr).To4())) common.Must2(pro.Write(net.ParseIP(remoteAddr).To4()))
common.Must2(pro.Write(net.ParseIP(localAddr).To4())) common.Must2(pro.Write(net.ParseIP(localAddr).To4()))
} else { } else {
common.Must2(pro.Write([]byte("\x21\x00\x24"))) // AF_INET6 + STREAM + 36 bytes common.Must2(pro.Write([]byte("\x21\x21\x00\x24"))) // v2 + PROXY + AF_INET6 + STREAM + 36 bytes
common.Must2(pro.Write(net.ParseIP(remoteAddr).To16())) common.Must2(pro.Write(net.ParseIP(remoteAddr).To16()))
common.Must2(pro.Write(net.ParseIP(localAddr).To16())) common.Must2(pro.Write(net.ParseIP(localAddr).To16()))
} }

View File

@@ -278,10 +278,7 @@ func (m *Addons) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if skippy < 0 { if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthAddons
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthAddons return ErrInvalidLengthAddons
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {

View File

@@ -31,11 +31,12 @@ type Fallback struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Alpn string `protobuf:"bytes,1,opt,name=alpn,proto3" json:"alpn,omitempty"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` Alpn string `protobuf:"bytes,2,opt,name=alpn,proto3" json:"alpn,omitempty"`
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
Dest string `protobuf:"bytes,4,opt,name=dest,proto3" json:"dest,omitempty"` Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"`
Xver uint64 `protobuf:"varint,5,opt,name=xver,proto3" json:"xver,omitempty"` Dest string `protobuf:"bytes,5,opt,name=dest,proto3" json:"dest,omitempty"`
Xver uint64 `protobuf:"varint,6,opt,name=xver,proto3" json:"xver,omitempty"`
} }
func (x *Fallback) Reset() { func (x *Fallback) Reset() {
@@ -70,6 +71,13 @@ func (*Fallback) Descriptor() ([]byte, []int) {
return file_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{0} return file_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{0}
} }
func (x *Fallback) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *Fallback) GetAlpn() string { func (x *Fallback) GetAlpn() string {
if x != nil { if x != nil {
return x.Alpn return x.Alpn
@@ -178,31 +186,33 @@ var file_proxy_vless_inbound_config_proto_rawDesc = []byte{
0x74, 0x6f, 0x12, 0x18, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x74, 0x6f, 0x12, 0x18, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76,
0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x1a, 0x1a, 0x63, 0x6f, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x1a, 0x1a, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73,
0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6e, 0x0a, 0x08, 0x46, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x82, 0x01, 0x0a, 0x08, 0x46, 0x61, 0x6c,
0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c, 0x70,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12, 0x0a,
0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74,
0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20,
0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0xa0, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65,
0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0xa0, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x6c, 0x69, 0x65,
0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x52, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x63, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1e,
0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x09, 0x66, 0x61, 0x6c, 0x0a, 0x0a, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40,
0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x0a, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76,
0x52, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x42, 0x6a, 0x0a, 0x1c, 0x63, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x46, 0x61, 0x6c,
0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73,
0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2d, 0x67, 0x42, 0x6a, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x50, 0x01, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
0x6c, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02, 0x18, 0x58, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72,
0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x64, 0xaa, 0x02, 0x18, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56,
0x6c, 0x65, 0x73, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -9,11 +9,12 @@ option java_multiple_files = true;
import "common/protocol/user.proto"; import "common/protocol/user.proto";
message Fallback { message Fallback {
string alpn = 1; string name = 1;
string path = 2; string alpn = 2;
string type = 3; string path = 3;
string dest = 4; string type = 4;
uint64 xver = 5; string dest = 5;
uint64 xver = 6;
} }
message Config { message Config {

View File

@@ -6,6 +6,7 @@ import (
"context" "context"
"io" "io"
"strconv" "strconv"
"strings"
"syscall" "syscall"
"time" "time"
@@ -63,7 +64,7 @@ type Handler struct {
policyManager policy.Manager policyManager policy.Manager
validator *vless.Validator validator *vless.Validator
dns dns.Client dns dns.Client
fallbacks map[string]map[string]*Fallback // or nil fallbacks map[string]map[string]map[string]*Fallback // or nil
// regexps map[string]*regexp.Regexp // or nil // regexps map[string]*regexp.Regexp // or nil
} }
@@ -88,13 +89,16 @@ func New(ctx context.Context, config *Config, dc dns.Client) (*Handler, error) {
} }
if config.Fallbacks != nil { if config.Fallbacks != nil {
handler.fallbacks = make(map[string]map[string]*Fallback) handler.fallbacks = make(map[string]map[string]map[string]*Fallback)
// handler.regexps = make(map[string]*regexp.Regexp) // handler.regexps = make(map[string]*regexp.Regexp)
for _, fb := range config.Fallbacks { for _, fb := range config.Fallbacks {
if handler.fallbacks[fb.Alpn] == nil { if handler.fallbacks[fb.Name] == nil {
handler.fallbacks[fb.Alpn] = make(map[string]*Fallback) handler.fallbacks[fb.Name] = make(map[string]map[string]*Fallback)
} }
handler.fallbacks[fb.Alpn][fb.Path] = fb if handler.fallbacks[fb.Name][fb.Alpn] == nil {
handler.fallbacks[fb.Name][fb.Alpn] = make(map[string]*Fallback)
}
handler.fallbacks[fb.Name][fb.Alpn][fb.Path] = fb
/* /*
if fb.Path != "" { if fb.Path != "" {
if r, err := regexp.Compile(fb.Path); err != nil { if r, err := regexp.Compile(fb.Path); err != nil {
@@ -106,11 +110,37 @@ func New(ctx context.Context, config *Config, dc dns.Client) (*Handler, error) {
*/ */
} }
if handler.fallbacks[""] != nil { if handler.fallbacks[""] != nil {
for alpn, pfb := range handler.fallbacks { for name, apfb := range handler.fallbacks {
if alpn != "" { // && alpn != "h2" { if name != "" {
for path, fb := range handler.fallbacks[""] { for alpn := range handler.fallbacks[""] {
if pfb[path] == nil { if apfb[alpn] == nil {
pfb[path] = fb apfb[alpn] = make(map[string]*Fallback)
}
}
}
}
}
for _, apfb := range handler.fallbacks {
if apfb[""] != nil {
for alpn, pfb := range apfb {
if alpn != "" { // && alpn != "h2" {
for path, fb := range apfb[""] {
if pfb[path] == nil {
pfb[path] = fb
}
}
}
}
}
}
if handler.fallbacks[""] != nil {
for name, apfb := range handler.fallbacks {
if name != "" {
for alpn, pfb := range handler.fallbacks[""] {
for path, fb := range pfb {
if apfb[alpn][path] == nil {
apfb[alpn][path] = fb
}
} }
} }
} }
@@ -171,8 +201,8 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
var requestAddons *encoding.Addons var requestAddons *encoding.Addons
var err error var err error
apfb := h.fallbacks napfb := h.fallbacks
isfb := apfb != nil isfb := napfb != nil
if isfb && firstLen < 18 { if isfb && firstLen < 18 {
err = newError("fallback directly") err = newError("fallback directly")
@@ -187,19 +217,47 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
} }
newError("fallback starts").Base(err).AtInfo().WriteToLog(sid) newError("fallback starts").Base(err).AtInfo().WriteToLog(sid)
name := ""
alpn := "" alpn := ""
if len(apfb) > 1 || apfb[""] == nil { if tlsConn, ok := iConn.(*tls.Conn); ok {
if tlsConn, ok := iConn.(*tls.Conn); ok { cs := tlsConn.ConnectionState()
alpn = tlsConn.ConnectionState().NegotiatedProtocol name = cs.ServerName
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid) alpn = cs.NegotiatedProtocol
} else if xtlsConn, ok := iConn.(*xtls.Conn); ok { newError("realName = " + name).AtInfo().WriteToLog(sid)
alpn = xtlsConn.ConnectionState().NegotiatedProtocol newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid) } else if xtlsConn, ok := iConn.(*xtls.Conn); ok {
} cs := xtlsConn.ConnectionState()
if apfb[alpn] == nil { name = cs.ServerName
alpn = "" alpn = cs.NegotiatedProtocol
newError("realName = " + name).AtInfo().WriteToLog(sid)
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
}
name = strings.ToLower(name)
alpn = strings.ToLower(alpn)
if len(napfb) > 1 || napfb[""] == nil {
if name != "" && napfb[name] == nil {
match := ""
for n := range napfb {
if n != "" && strings.Contains(name, n) && len(n) > len(match) {
match = n
}
}
name = match
} }
} }
if napfb[name] == nil {
name = ""
}
apfb := napfb[name]
if apfb == nil {
return newError(`failed to find the default "name" config`).AtWarning()
}
if apfb[alpn] == nil {
alpn = ""
}
pfb := apfb[alpn] pfb := apfb[alpn]
if pfb == nil { if pfb == nil {
return newError(`failed to find the default "alpn" config`).AtWarning() return newError(`failed to find the default "alpn" config`).AtWarning()
@@ -277,39 +335,48 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
postRequest := func() error { postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly) defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
if fb.Xver != 0 { if fb.Xver != 0 {
ipType := 4
remoteAddr, remotePort, err := net.SplitHostPort(connection.RemoteAddr().String()) remoteAddr, remotePort, err := net.SplitHostPort(connection.RemoteAddr().String())
if err != nil { if err != nil {
return err ipType = 0
} }
localAddr, localPort, err := net.SplitHostPort(connection.LocalAddr().String()) localAddr, localPort, err := net.SplitHostPort(connection.LocalAddr().String())
if err != nil { if err != nil {
return err ipType = 0
} }
ipv4 := true if ipType == 4 {
for i := 0; i < len(remoteAddr); i++ { for i := 0; i < len(remoteAddr); i++ {
if remoteAddr[i] == ':' { if remoteAddr[i] == ':' {
ipv4 = false ipType = 6
break break
}
} }
} }
pro := buf.New() pro := buf.New()
defer pro.Release() defer pro.Release()
switch fb.Xver { switch fb.Xver {
case 1: case 1:
if ipv4 { if ipType == 0 {
pro.Write([]byte("PROXY UNKNOWN\r\n"))
break
}
if ipType == 4 {
pro.Write([]byte("PROXY TCP4 " + remoteAddr + " " + localAddr + " " + remotePort + " " + localPort + "\r\n")) pro.Write([]byte("PROXY TCP4 " + remoteAddr + " " + localAddr + " " + remotePort + " " + localPort + "\r\n"))
} else { } else {
pro.Write([]byte("PROXY TCP6 " + remoteAddr + " " + localAddr + " " + remotePort + " " + localPort + "\r\n")) pro.Write([]byte("PROXY TCP6 " + remoteAddr + " " + localAddr + " " + remotePort + " " + localPort + "\r\n"))
} }
case 2: case 2:
pro.Write([]byte("\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x21")) // signature + v2 + PROXY pro.Write([]byte("\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A")) // signature
if ipv4 { if ipType == 0 {
pro.Write([]byte("\x11\x00\x0C")) // AF_INET + STREAM + 12 bytes pro.Write([]byte("\x20\x00\x00\x00")) // v2 + LOCAL + UNSPEC + UNSPEC + 0 bytes
break
}
if ipType == 4 {
pro.Write([]byte("\x21\x11\x00\x0C")) // v2 + PROXY + AF_INET + STREAM + 12 bytes
pro.Write(net.ParseIP(remoteAddr).To4()) pro.Write(net.ParseIP(remoteAddr).To4())
pro.Write(net.ParseIP(localAddr).To4()) pro.Write(net.ParseIP(localAddr).To4())
} else { } else {
pro.Write([]byte("\x21\x00\x24")) // AF_INET6 + STREAM + 36 bytes pro.Write([]byte("\x21\x21\x00\x24")) // v2 + PROXY + AF_INET6 + STREAM + 36 bytes
pro.Write(net.ParseIP(remoteAddr).To16()) pro.Write(net.ParseIP(remoteAddr).To16())
pro.Write(net.ParseIP(localAddr).To16()) pro.Write(net.ParseIP(localAddr).To16())
} }

View File

@@ -16,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" "github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/common/xudp"
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/features/stats"
@@ -48,6 +49,7 @@ type Handler struct {
serverList *protocol.ServerList serverList *protocol.ServerList
serverPicker protocol.ServerPicker serverPicker protocol.ServerPicker
policyManager policy.Manager policyManager policy.Manager
cone bool
} }
// New creates a new VLess outbound handler. // New creates a new VLess outbound handler.
@@ -66,6 +68,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
serverList: serverList, serverList: serverList,
serverPicker: protocol.NewRoundRobinServerPicker(serverList), serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
cone: ctx.Value("cone").(bool),
} }
return handler, nil return handler, nil
@@ -175,6 +178,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
clientReader := link.Reader // .(*pipe.Reader) clientReader := link.Reader // .(*pipe.Reader)
clientWriter := link.Writer // .(*pipe.Writer) clientWriter := link.Writer // .(*pipe.Writer)
if request.Command == protocol.RequestCommandUDP && h.cone {
request.Command = protocol.RequestCommandMux
request.Address = net.DomainAddress("v1.mux.cool")
request.Port = net.Port(666)
}
postRequest := func() error { postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly) defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
@@ -185,6 +194,9 @@ 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 {
serverWriter = xudp.NewPacketWriter(serverWriter, target)
}
if err := buf.CopyOnceTimeout(clientReader, serverWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout { if err := buf.CopyOnceTimeout(clientReader, serverWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
return err // ... return err // ...
} }
@@ -216,6 +228,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
// default: serverReader := buf.NewReader(conn) // default: serverReader := buf.NewReader(conn)
serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons) serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons)
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
serverReader = xudp.NewPacketReader(conn)
}
if rawConn != nil { if rawConn != nil {
var counter stats.Counter var counter stats.Counter

View File

@@ -6,11 +6,20 @@ import (
"hash" "hash"
) )
type hash2 struct {
hash.Hash
}
func KDF(key []byte, path ...string) []byte { func KDF(key []byte, path ...string) []byte {
hmacf := hmac.New(sha256.New, []byte(KDFSaltConstVMessAEADKDF)) hmacf := hmac.New(sha256.New, []byte(KDFSaltConstVMessAEADKDF))
for _, v := range path { for _, v := range path {
first := true
hmacf = hmac.New(func() hash.Hash { hmacf = hmac.New(func() hash.Hash {
if first {
first = false
return hash2{hmacf}
}
return hmacf return hmacf
}, []byte(v)) }, []byte(v))
} }

View File

@@ -15,6 +15,7 @@ import (
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal" "github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/common/xudp"
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/proxy/vmess" "github.com/xtls/xray-core/proxy/vmess"
@@ -28,6 +29,7 @@ type Handler struct {
serverList *protocol.ServerList serverList *protocol.ServerList
serverPicker protocol.ServerPicker serverPicker protocol.ServerPicker
policyManager policy.Manager policyManager policy.Manager
cone bool
} }
// New creates a new VMess outbound handler. // New creates a new VMess outbound handler.
@@ -46,6 +48,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
serverList: serverList, serverList: serverList,
serverPicker: protocol.NewRoundRobinServerPicker(serverList), serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
cone: ctx.Value("cone").(bool),
} }
return handler, nil return handler, nil
@@ -122,6 +125,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
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)
if request.Command == protocol.RequestCommandUDP && h.cone {
request.Command = protocol.RequestCommandMux
request.Address = net.DomainAddress("v1.mux.cool")
request.Port = net.Port(666)
}
requestDone := func() error { requestDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly) defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
@@ -131,6 +140,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
} }
bodyWriter := session.EncodeRequestBody(request, writer) bodyWriter := session.EncodeRequestBody(request, writer)
bodyWriter2 := bodyWriter
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
bodyWriter = xudp.NewPacketWriter(bodyWriter, target)
}
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)
} }
@@ -144,7 +157,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
} }
if request.Option.Has(protocol.RequestOptionChunkStream) { if request.Option.Has(protocol.RequestOptionChunkStream) {
if err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil { if err := bodyWriter2.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {
return err return err
} }
} }
@@ -163,6 +176,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
h.handleCommand(rec.Destination(), header.Command) h.handleCommand(rec.Destination(), header.Command)
bodyReader := session.DecodeResponseBody(request, reader) bodyReader := session.DecodeResponseBody(request, reader)
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
bodyReader = xudp.NewPacketReader(&buf.BufferedReader{Reader: bodyReader})
}
return buf.Copy(bodyReader, output, buf.UpdateActivity(timer)) return buf.Copy(bodyReader, output, buf.UpdateActivity(timer))
} }

View File

@@ -118,7 +118,7 @@ func genTestBinaryPath() {
} }
func GetSourcePath() string { func GetSourcePath() string {
return filepath.Join("example.com", "core", "main") return filepath.Join("github.com", "xtls", "xray-core", "main")
} }
func CloseAllServers(servers []*exec.Cmd) { func CloseAllServers(servers []*exec.Cmd) {

View File

@@ -17,6 +17,8 @@ func BuildXray() error {
fmt.Printf("Building Xray into path (%s)\n", testBinaryPath) fmt.Printf("Building Xray into path (%s)\n", testBinaryPath)
cmd := exec.Command("go", "build", "-o="+testBinaryPath, GetSourcePath()) cmd := exec.Command("go", "build", "-o="+testBinaryPath, GetSourcePath())
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run() return cmd.Run()
} }

View File

@@ -52,10 +52,10 @@ func TestShadowsocksAES256TCP(t *testing.T) {
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{ ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{
User: &protocol.User{ Users: []*protocol.User{{
Account: account, Account: account,
Level: 1, Level: 1,
}, }},
Network: []net.Network{net.Network_TCP}, Network: []net.Network{net.Network_TCP},
}), }),
}, },
@@ -150,10 +150,10 @@ func TestShadowsocksAES128UDP(t *testing.T) {
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{ ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{
User: &protocol.User{ Users: []*protocol.User{{
Account: account, Account: account,
Level: 1, Level: 1,
}, }},
Network: []net.Network{net.Network_UDP}, Network: []net.Network{net.Network_UDP},
}), }),
}, },
@@ -276,10 +276,10 @@ func TestShadowsocksChacha20TCP(t *testing.T) {
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{ ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{
User: &protocol.User{ Users: []*protocol.User{{
Account: account, Account: account,
Level: 1, Level: 1,
}, }},
Network: []net.Network{net.Network_TCP}, Network: []net.Network{net.Network_TCP},
}), }),
}, },
@@ -369,10 +369,10 @@ func TestShadowsocksChacha20Poly1305TCP(t *testing.T) {
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{ ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{
User: &protocol.User{ Users: []*protocol.User{{
Account: account, Account: account,
Level: 1, Level: 1,
}, }},
Network: []net.Network{net.Network_TCP}, Network: []net.Network{net.Network_TCP},
}), }),
}, },
@@ -461,10 +461,10 @@ func TestShadowsocksAES256GCMTCP(t *testing.T) {
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{ ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{
User: &protocol.User{ Users: []*protocol.User{{
Account: account, Account: account,
Level: 1, Level: 1,
}, }},
Network: []net.Network{net.Network_TCP}, Network: []net.Network{net.Network_TCP},
}), }),
}, },
@@ -560,10 +560,10 @@ func TestShadowsocksAES128GCMUDP(t *testing.T) {
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{ ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{
User: &protocol.User{ Users: []*protocol.User{{
Account: account, Account: account,
Level: 1, Level: 1,
}, }},
Network: []net.Network{net.Network_UDP}, Network: []net.Network{net.Network_UDP},
}), }),
}, },
@@ -658,10 +658,10 @@ func TestShadowsocksAES128GCMUDPMux(t *testing.T) {
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{ ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{
User: &protocol.User{ Users: []*protocol.User{{
Account: account, Account: account,
Level: 1, Level: 1,
}, }},
Network: []net.Network{net.Network_TCP}, Network: []net.Network{net.Network_TCP},
}), }),
}, },
@@ -757,10 +757,10 @@ func TestShadowsocksNone(t *testing.T) {
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{ ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{
User: &protocol.User{ Users: []*protocol.User{{
Account: account, Account: account,
Level: 1, Level: 1,
}, }},
Network: []net.Network{net.Network_TCP}, Network: []net.Network{net.Network_TCP},
}), }),
}, },

View File

@@ -583,7 +583,7 @@ func TestHTTP2(t *testing.T) {
var errg errgroup.Group var errg errgroup.Group
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
errg.Go(testTCPConn(clientPort, 10240*1024, time.Second*40)) errg.Go(testTCPConn(clientPort, 1024*1024, time.Second*40))
} }
if err := errg.Wait(); err != nil { if err := errg.Wait(); err != nil {
t.Error(err) t.Error(err)

View File

@@ -10,6 +10,8 @@ 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/net/cnc"
"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/tls" "github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/pipe" "github.com/xtls/xray-core/transport/pipe"
@@ -21,7 +23,7 @@ var (
globalDialerAccess sync.Mutex globalDialerAccess sync.Mutex
) )
func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.Config) (*http.Client, error) { func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.Config, sockopt *internet.SocketConfig) (*http.Client, error) {
globalDialerAccess.Lock() globalDialerAccess.Lock()
defer globalDialerAccess.Unlock() defer globalDialerAccess.Unlock()
@@ -48,17 +50,24 @@ func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.C
} }
address := net.ParseAddress(rawHost) address := net.ParseAddress(rawHost)
pconn, err := internet.DialSystem(ctx, net.TCPDestination(address, port), nil) dctx := context.Background()
dctx = session.ContextWithID(dctx, session.IDFromContext(ctx))
dctx = session.ContextWithOutbound(dctx, session.OutboundFromContext(ctx))
pconn, err := internet.DialSystem(dctx, net.TCPDestination(address, port), sockopt)
if err != nil { if err != nil {
newError("failed to dial to " + addr).Base(err).AtError().WriteToLog()
return nil, err return nil, err
} }
cn := gotls.Client(pconn, tlsConfig) cn := gotls.Client(pconn, tlsConfig)
if err := cn.Handshake(); err != nil { if err := cn.Handshake(); err != nil {
newError("failed to dial to " + addr).Base(err).AtError().WriteToLog()
return nil, err return nil, err
} }
if !tlsConfig.InsecureSkipVerify { if !tlsConfig.InsecureSkipVerify {
if err := cn.VerifyHostname(tlsConfig.ServerName); err != nil { if err := cn.VerifyHostname(tlsConfig.ServerName); err != nil {
newError("failed to dial to " + addr).Base(err).AtError().WriteToLog()
return nil, err return nil, err
} }
} }
@@ -89,7 +98,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
if tlsConfig == nil { if tlsConfig == nil {
return nil, newError("TLS must be enabled for http transport.").AtWarning() return nil, newError("TLS must be enabled for http transport.").AtWarning()
} }
client, err := getHTTPClient(ctx, dest, tlsConfig) client, err := getHTTPClient(ctx, dest, tlsConfig, streamSettings.SocketSettings)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -124,10 +133,10 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
bwriter := buf.NewBufferedWriter(pwriter) bwriter := buf.NewBufferedWriter(pwriter)
common.Must(bwriter.SetBuffered(false)) common.Must(bwriter.SetBuffered(false))
return net.NewConnection( return cnc.NewConnection(
net.ConnectionOutput(response.Body), cnc.ConnectionOutput(response.Body),
net.ConnectionInput(bwriter), cnc.ConnectionInput(bwriter),
net.ConnectionOnClose(common.ChainedClosable{breader, bwriter, response.Body}), cnc.ConnectionOnClose(common.ChainedClosable{breader, bwriter, response.Body}),
), nil ), nil
} }

View File

@@ -2,10 +2,8 @@ package http
import ( import (
"context" "context"
"fmt"
"io" "io"
"net/http" "net/http"
"os"
"strings" "strings"
"time" "time"
@@ -14,6 +12,7 @@ import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
http_proto "github.com/xtls/xray-core/common/protocol/http" http_proto "github.com/xtls/xray-core/common/protocol/http"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
@@ -36,7 +35,6 @@ func (l *Listener) Addr() net.Addr {
func (l *Listener) Close() error { func (l *Listener) Close() error {
if l.locker != nil { if l.locker != nil {
fmt.Fprintln(os.Stderr, "RELEASE LOCK")
l.locker.Release() l.locker.Release()
} }
return l.server.Close() return l.server.Close()
@@ -88,21 +86,21 @@ func (l *Listener) ServeHTTP(writer http.ResponseWriter, request *http.Request)
} }
} }
forwardedAddrs := http_proto.ParseXForwardedFor(request.Header) forwardedAddress := http_proto.ParseXForwardedFor(request.Header)
if len(forwardedAddrs) > 0 && forwardedAddrs[0].Family().IsIP() { if len(forwardedAddress) > 0 && forwardedAddress[0].Family().IsIP() {
remoteAddr = &net.TCPAddr{ remoteAddr = &net.TCPAddr{
IP: forwardedAddrs[0].IP(), IP: forwardedAddress[0].IP(),
Port: int(0), Port: 0,
} }
} }
done := done.New() done := done.New()
conn := net.NewConnection( conn := cnc.NewConnection(
net.ConnectionOutput(request.Body), cnc.ConnectionOutput(request.Body),
net.ConnectionInput(flushWriter{w: writer, d: done}), cnc.ConnectionInput(flushWriter{w: writer, d: done}),
net.ConnectionOnClose(common.ChainedClosable{done, request.Body}), cnc.ConnectionOnClose(common.ChainedClosable{done, request.Body}),
net.ConnectionLocalAddr(l.Addr()), cnc.ConnectionLocalAddr(l.Addr()),
net.ConnectionRemoteAddr(remoteAddr), cnc.ConnectionRemoteAddr(remoteAddr),
) )
l.handler(conn) l.handler(conn)
<-done.Wait() <-done.Wait()
@@ -164,7 +162,7 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
Net: "unix", Net: "unix",
}, streamSettings.SocketSettings) }, streamSettings.SocketSettings)
if err != nil { if err != nil {
newError("failed to listen on ", address).Base(err).WriteToLog(session.ExportIDToError(ctx)) newError("failed to listen on ", address).Base(err).AtError().WriteToLog(session.ExportIDToError(ctx))
return return
} }
locker := ctx.Value(address.Domain()) locker := ctx.Value(address.Domain())
@@ -177,7 +175,7 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
Port: int(port), Port: int(port),
}, streamSettings.SocketSettings) }, streamSettings.SocketSettings)
if err != nil { if err != nil {
newError("failed to listen on ", address, ":", port).Base(err).WriteToLog(session.ExportIDToError(ctx)) newError("failed to listen on ", address, ":", port).Base(err).AtError().WriteToLog(session.ExportIDToError(ctx))
return return
} }
} }
@@ -185,12 +183,12 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
if config == nil { if config == nil {
err = server.Serve(streamListener) err = server.Serve(streamListener)
if err != nil { if err != nil {
newError("stoping serving H2C").Base(err).WriteToLog(session.ExportIDToError(ctx)) newError("stopping serving H2C").Base(err).WriteToLog(session.ExportIDToError(ctx))
} }
} else { } else {
err = server.ServeTLS(streamListener, "", "") err = server.ServeTLS(streamListener, "", "")
if err != nil { if err != nil {
newError("stoping serving TLS").Base(err).WriteToLog(session.ExportIDToError(ctx)) newError("stopping serving TLS").Base(err).WriteToLog(session.ExportIDToError(ctx))
} }
} }
}() }()

View File

@@ -73,10 +73,10 @@ func ListenTCP(ctx context.Context, address net.Address, port net.Port, streamSe
l.listener = listener l.listener = listener
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil { if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
l.tlsConfig = config.GetTLSConfig(tls.WithNextProto("h2")) l.tlsConfig = config.GetTLSConfig()
} }
if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil { if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {
l.xtlsConfig = config.GetXTLSConfig(xtls.WithNextProto("h2")) l.xtlsConfig = config.GetXTLSConfig()
} }
if tcpSettings.HeaderSettings != nil { if tcpSettings.HeaderSettings != nil {

View File

@@ -9,6 +9,7 @@ import (
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/ocsp" "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/common/protocol/tls/cert"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
) )
@@ -42,8 +43,8 @@ func (c *Config) loadSelfCertPool() (*x509.CertPool, error) {
} }
// BuildCertificates builds a list of TLS certificates from proto definition. // BuildCertificates builds a list of TLS certificates from proto definition.
func (c *Config) BuildCertificates() []tls.Certificate { func (c *Config) BuildCertificates() []*tls.Certificate {
certs := make([]tls.Certificate, 0, len(c.Certificate)) certs := make([]*tls.Certificate, 0, len(c.Certificate))
for _, entry := range c.Certificate { for _, entry := range c.Certificate {
if entry.Usage != Certificate_ENCIPHERMENT { if entry.Usage != Certificate_ENCIPHERMENT {
continue continue
@@ -53,19 +54,62 @@ func (c *Config) BuildCertificates() []tls.Certificate {
newError("ignoring invalid X509 key pair").Base(err).AtWarning().WriteToLog() newError("ignoring invalid X509 key pair").Base(err).AtWarning().WriteToLog()
continue continue
} }
certs = append(certs, keyPair) keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
if entry.OcspStapling != 0 { if err != nil {
go func(cert *tls.Certificate) { newError("ignoring invalid certificate").Base(err).AtWarning().WriteToLog()
t := time.NewTicker(time.Duration(entry.OcspStapling) * time.Second) continue
}
certs = append(certs, &keyPair)
if !entry.OneTimeLoading {
var isOcspstapling bool
hotReloadCertInterval := uint64(3600)
if entry.OcspStapling != 0 {
hotReloadCertInterval = entry.OcspStapling
isOcspstapling = true
}
index := len(certs) - 1
go func(cert *tls.Certificate, index int) {
t := time.NewTicker(time.Duration(hotReloadCertInterval) * time.Second)
for { for {
if newData, err := ocsp.GetOCSPForCert(cert.Certificate); err != nil { if entry.CertificatePath != "" && entry.KeyPath != "" {
newError("ignoring invalid OCSP").Base(err).AtWarning().WriteToLog() newCert, err := filesystem.ReadFile(entry.CertificatePath)
} else if string(newData) != string(cert.OCSPStaple) { if err != nil {
cert.OCSPStaple = newData 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 := tls.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 <-t.C
} }
}(&certs[len(certs)-1]) }(certs[len(certs)-1], index)
} }
} }
return certs return certs
@@ -169,6 +213,33 @@ func getGetCertificateFunc(c *tls.Config, ca []*Certificate) func(hello *tls.Cli
} }
} }
func getNewGetCertficateFunc(certs []*tls.Certificate) func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
return func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
if len(certs) == 0 {
return nil, newError("empty certs")
}
sni := strings.ToLower(hello.ServerName)
if 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
}
}
}
return certs[0], nil
}
}
func (c *Config) IsExperiment8357() bool { func (c *Config) IsExperiment8357() bool {
return strings.HasPrefix(c.ServerName, exp8357) return strings.HasPrefix(c.ServerName, exp8357)
} }
@@ -194,7 +265,7 @@ func (c *Config) GetTLSConfig(opts ...Option) *tls.Config {
RootCAs: root, RootCAs: root,
InsecureSkipVerify: false, InsecureSkipVerify: false,
NextProtos: nil, NextProtos: nil,
SessionTicketsDisabled: false, SessionTicketsDisabled: true,
} }
} }
@@ -203,19 +274,18 @@ func (c *Config) GetTLSConfig(opts ...Option) *tls.Config {
RootCAs: root, RootCAs: root,
InsecureSkipVerify: c.AllowInsecure, InsecureSkipVerify: c.AllowInsecure,
NextProtos: c.NextProtocol, NextProtos: c.NextProtocol,
SessionTicketsDisabled: c.DisableSessionResumption, SessionTicketsDisabled: !c.EnableSessionResumption,
} }
for _, opt := range opts { for _, opt := range opts {
opt(config) opt(config)
} }
config.Certificates = c.BuildCertificates()
config.BuildNameToCertificate()
caCerts := c.getCustomCA() caCerts := c.getCustomCA()
if len(caCerts) > 0 { if len(caCerts) > 0 {
config.GetCertificate = getGetCertificateFunc(config, caCerts) config.GetCertificate = getGetCertificateFunc(config, caCerts)
} else {
config.GetCertificate = getNewGetCertficateFunc(c.BuildCertificates())
} }
if sn := c.parseServerName(); len(sn) > 0 { if sn := c.parseServerName(); len(sn) > 0 {

View File

@@ -84,7 +84,13 @@ type Certificate struct {
// TLS key in x509 format. // TLS key in x509 format.
Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` 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.tls.Certificate_Usage" json:"usage,omitempty"` Usage Certificate_Usage `protobuf:"varint,3,opt,name=usage,proto3,enum=xray.transport.internet.tls.Certificate_Usage" json:"usage,omitempty"`
OcspStapling int64 `protobuf:"varint,4,opt,name=ocsp_stapling,json=ocspStapling,proto3" json:"ocsp_stapling,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() { func (x *Certificate) Reset() {
@@ -140,13 +146,34 @@ func (x *Certificate) GetUsage() Certificate_Usage {
return Certificate_ENCIPHERMENT return Certificate_ENCIPHERMENT
} }
func (x *Certificate) GetOcspStapling() int64 { func (x *Certificate) GetOcspStapling() uint64 {
if x != nil { if x != nil {
return x.OcspStapling return x.OcspStapling
} }
return 0 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 { type Config struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -160,8 +187,8 @@ type Config struct {
ServerName string `protobuf:"bytes,3,opt,name=server_name,json=serverName,proto3" json:"server_name,omitempty"` ServerName string `protobuf:"bytes,3,opt,name=server_name,json=serverName,proto3" json:"server_name,omitempty"`
// Lists of string as ALPN values. // Lists of string as ALPN values.
NextProtocol []string `protobuf:"bytes,4,rep,name=next_protocol,json=nextProtocol,proto3" json:"next_protocol,omitempty"` NextProtocol []string `protobuf:"bytes,4,rep,name=next_protocol,json=nextProtocol,proto3" json:"next_protocol,omitempty"`
// Whether or not to disable session (ticket) resumption. // Whether or not to enable session (ticket) resumption.
DisableSessionResumption bool `protobuf:"varint,5,opt,name=disable_session_resumption,json=disableSessionResumption,proto3" json:"disable_session_resumption,omitempty"` 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 // If true, root certificates on the system will not be loaded for
// verification. // verification.
DisableSystemRoot bool `protobuf:"varint,6,opt,name=disable_system_root,json=disableSystemRoot,proto3" json:"disable_system_root,omitempty"` DisableSystemRoot bool `protobuf:"varint,6,opt,name=disable_system_root,json=disableSystemRoot,proto3" json:"disable_system_root,omitempty"`
@@ -235,9 +262,9 @@ func (x *Config) GetNextProtocol() []string {
return nil return nil
} }
func (x *Config) GetDisableSessionResumption() bool { func (x *Config) GetEnableSessionResumption() bool {
if x != nil { if x != nil {
return x.DisableSessionResumption return x.EnableSessionResumption
} }
return false return false
} }
@@ -284,7 +311,7 @@ var file_transport_internet_tls_config_proto_rawDesc = []byte{
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74,
0x6c, 0x73, 0x22, 0xf2, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x6c, 0x73, 0x22, 0xe2, 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, 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, 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, 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28,
@@ -294,12 +321,19 @@ var file_transport_internet_tls_config_proto_rawDesc = []byte{
0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x2e, 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, 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, 0x6f, 0x63, 0x73, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20,
0x01, 0x28, 0x03, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x53, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e, 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, 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, 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, 0xd5, 0x03, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x49, 0x53, 0x53, 0x55, 0x45, 0x10, 0x02, 0x22, 0xd3, 0x03, 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,
@@ -311,32 +345,32 @@ var file_transport_internet_tls_config_proto_rawDesc = []byte{
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 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, 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, 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, 0x3c, 0x0a, 0x1a, 0x64, 0x65, 0x78, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x3a, 0x0a, 0x19, 0x65,
0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65,
0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17,
0x18, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73,
0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x69, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x69, 0x73, 0x61, 0x62,
0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x6c, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x06,
0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x79, 0x73,
0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x69, 0x6e, 0x74, 0x65, 0x6d, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x69, 0x6e, 0x5f, 0x76,
0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x69,
0x6d, 0x69, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x61, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x61, 0x78, 0x5f,
0x78, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d,
0x0a, 0x6d, 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x69, 0x70,
0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09,
0x28, 0x09, 0x52, 0x0c, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x52, 0x0c, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x12, 0x3d,
0x12, 0x3d, 0x0a, 0x1b, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x0a, 0x1b, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f,
0x72, 0x5f, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65, 0x73, 0x18, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65, 0x73, 0x18, 0x0a, 0x20,
0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x53, 0x65, 0x72, 0x01, 0x28, 0x08, 0x52, 0x18, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x65,
0x76, 0x65, 0x72, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x42, 0x72, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x42, 0x73, 0x0a,
0x73, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c, 0x73,
0x6c, 0x73, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
0x65, 0x74, 0x2f, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x1b, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x2f, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x1b, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e,
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x54,
0x2e, 0x54, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -21,7 +21,16 @@ message Certificate {
Usage usage = 3; Usage usage = 3;
int64 ocsp_stapling = 4; uint64 ocsp_stapling = 4;
// TLS certificate path
string certificate_path = 5;
// TLS Key path
string key_path = 6;
// If true, one-Time Loading
bool One_time_loading = 7;
} }
message Config { message Config {
@@ -37,8 +46,8 @@ message Config {
// Lists of string as ALPN values. // Lists of string as ALPN values.
repeated string next_protocol = 4; repeated string next_protocol = 4;
// Whether or not to disable session (ticket) resumption. // Whether or not to enable session (ticket) resumption.
bool disable_session_resumption = 5; bool enable_session_resumption = 5;
// If true, root certificates on the system will not be loaded for // If true, root certificates on the system will not be loaded for
// verification. // verification.

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