Compare commits

..

12 Commits
v1.8.12 ... ax

Author SHA1 Message Date
Shelikhoo
64c2986853 Added experiment to avoid sending the termination signal
(cherry picked from commit c5357e1f000054ba5836468922cae52a830c8019)
2021-10-22 18:31:54 +08:00
Shelikhoo
778876df9e VMess AEAD based packet length
(cherry picked from commit 08221600082a79376bdc262f2ffec1a3129ae98d)
2021-10-22 18:30:30 +08:00
世界
5bf2b31883 Add hook to init and listen observatory statuses 2021-10-22 17:59:41 +08:00
世界
390a76ff61 Export instance context 2021-10-22 17:59:41 +08:00
世界
486f96838d Parse port in dns address 2021-10-22 17:59:41 +08:00
世界
710b283204 Add more default ttl 2021-10-22 17:59:41 +08:00
世界
073ba6f1c5 Add ApplySockopt 2021-10-22 17:59:41 +08:00
世界
a4f657f787 Remove unused 2021-10-22 17:59:40 +08:00
世界
ea94d07f65 Add domainStrategy to outbound &
Add preferIPv4/6 to domainStrategy
2021-10-22 17:59:27 +08:00
世界
14aa152a8a Add skipFakeDNS to inbound session 2021-10-22 17:59:26 +08:00
世界
e316cd4c66 Hook to replace DOHL dialer 2021-10-22 17:59:26 +08:00
世界
16d96aa54d Add uid and app status in routing rule 2021-10-22 17:59:26 +08:00
532 changed files with 8239 additions and 23004 deletions

View File

@@ -1,87 +0,0 @@
name: Bug report
description: "Submit Xray-core bug"
body:
- type: checkboxes
attributes:
label: Integrity requirements
description: |-
Please check all of the following options to prove that you have read and understood the requirements, otherwise this issue will be closed.
options:
- label: I confirm that I have read the documentation, understand the meaning of all the configuration items I wrote, and did not pile up seemingly useful options or default values.
required: true
- label: I searched issues and did not find any similar issues.
required: true
- type: input
attributes:
label: Version
description: Version of Xray-core
validations:
required: true
- type: textarea
attributes:
label: Description
description: Please provide a detailed description of the error. And the information you think valuable.
validations:
required: true
- type: textarea
attributes:
label: Reproduction Method
description: |-
Based on the configuration you provided below, provide the method to reproduce the bug.
validations:
required: true
- type: markdown
attributes:
value: |-
## Configuration and Log Section
### For config
Please provide the configuration files that can reproduce the problem, including the server and client.
Don't just paste a big exported config file here. Eliminate useless inbound/outbound, rules, options, this can help determine the problem, if you really want to get help.
### For logs
Please set the log level to debug first.
Restart Xray-core, then operate according to the reproduction method, try to reduce the irrelevant part in the log.
Remember to delete parts with personal information (such as UUID and IP).
Provide the log of Xray-core, not the log output by the panel or other things.
### Finally
After removing parts that do not affect reproduction, provide the actual running **complete** file, do not only provide inbound or outbound or a few lines of logs based on your own judgment.
Put the content between the preset ```<details><pre><code>``` ```</code></pre></details>``` in the text box.
If the problem is very clear that only related to one end (such as core startup failure/crash after correctly writing the config according to the documents), N/A can be filled in for unnecessary areas below.
- type: textarea
attributes:
label: Client config
value: |-
<details><pre><code>
</code></pre></details>
validations:
required: true
- type: textarea
attributes:
label: Server config
value: |-
<details><pre><code>
</code></pre></details>
validations:
required: true
- type: textarea
attributes:
label: Client log
value: |-
<details><pre><code>
</code></pre></details>
validations:
required: true
- type: textarea
attributes:
label: Server log
value: |-
<details><pre><code>
</code></pre></details>
validations:
required: true

View File

@@ -1,87 +0,0 @@
name: bug反馈
description: "提交 Xray-core bug"
body:
- type: checkboxes
attributes:
label: 完整性要求
description: |-
请勾选以下所有选项以证明您已经阅读并理解了以下要求,否则该 issue 将被关闭。
options:
- label: 我保证阅读了文档,了解所有我编写的配置文件项的含义,而不是大量堆砌看似有用的选项或默认值。
required: true
- label: 我搜索了issues没有发现已提出的类似问题。
required: true
- type: input
attributes:
label: 版本
description: 使用的Xray-core版本
validations:
required: true
- type: textarea
attributes:
label: 描述
description: 请提供错误的详细描述。以及你认为有价值的信息。
validations:
required: true
- type: textarea
attributes:
label: 重现方式
description: |-
基于你下面提供的配置提供重现BUG方法。
validations:
required: true
- type: markdown
attributes:
value: |-
## 配置与日志部分
### 对于配置文件
请提供可以重现问题的配置文件,包括服务端和客户端。
不要直接在这里黏贴一大段导出的 config 文件。去掉无用的出入站、规则、选项,这可以帮助确定问题,如果你真的想得到帮助。
### 对于日志
请先将日志等级设置为 debug.
重启 Xray-core ,再按复现方式操作,尽量减少日志中的无关部分。
记得删除有关个人信息如UUID与IP的部分。
提供 Xray-core 的日志,而不是面板或者别的东西输出的日志。
### 最后
在去掉不影响复现的部分后,提供实际运行的**完整**文件,不要出于自己的判断只提供入站出站或者几行日志。
把内容放在文本框预置的 ```<details><pre><code>``` 和 ```</code></pre></details>``` 中间。
如果问题十分明确只出现在某一端(如按文档正确编写配置后核心启动失败/崩溃)可以在下面不需要的项目填入N/A.
- type: textarea
attributes:
label: 客户端配置
value: |-
<details><pre><code>
</code></pre></details>
validations:
required: true
- type: textarea
attributes:
label: 服务端配置
value: |-
<details><pre><code>
</code></pre></details>
validations:
required: true
- type: textarea
attributes:
label: 客户端日志
value: |-
<details><pre><code>
</code></pre></details>
validations:
required: true
- type: textarea
attributes:
label: 服务端日志
value: |-
<details><pre><code>
</code></pre></details>
validations:
required: true

View File

@@ -2,6 +2,7 @@
"android-arm64": { "friendlyName": "android-arm64-v8a" }, "android-arm64": { "friendlyName": "android-arm64-v8a" },
"darwin-amd64": { "friendlyName": "macos-64" }, "darwin-amd64": { "friendlyName": "macos-64" },
"darwin-arm64": { "friendlyName": "macos-arm64-v8a" }, "darwin-arm64": { "friendlyName": "macos-arm64-v8a" },
"dragonfly-amd64": { "friendlyName": "dragonfly-64" },
"freebsd-386": { "friendlyName": "freebsd-32" }, "freebsd-386": { "friendlyName": "freebsd-32" },
"freebsd-amd64": { "friendlyName": "freebsd-64" }, "freebsd-amd64": { "friendlyName": "freebsd-64" },
"freebsd-arm64": { "friendlyName": "freebsd-arm64-v8a" }, "freebsd-arm64": { "friendlyName": "freebsd-arm64-v8a" },
@@ -21,7 +22,6 @@
"linux-ppc64le": { "friendlyName": "linux-ppc64le" }, "linux-ppc64le": { "friendlyName": "linux-ppc64le" },
"linux-ppc64": { "friendlyName": "linux-ppc64" }, "linux-ppc64": { "friendlyName": "linux-ppc64" },
"linux-riscv64": { "friendlyName": "linux-riscv64" }, "linux-riscv64": { "friendlyName": "linux-riscv64" },
"linux-loong64": { "friendlyName": "linux-loong64" },
"linux-s390x": { "friendlyName": "linux-s390x" }, "linux-s390x": { "friendlyName": "linux-s390x" },
"openbsd-386": { "friendlyName": "openbsd-32" }, "openbsd-386": { "friendlyName": "openbsd-32" },
"openbsd-amd64": { "friendlyName": "openbsd-64" }, "openbsd-amd64": { "friendlyName": "openbsd-64" },
@@ -31,4 +31,4 @@
"windows-amd64": { "friendlyName": "windows-64" }, "windows-amd64": { "friendlyName": "windows-64" },
"windows-arm64": { "friendlyName": "windows-arm64-v8a" }, "windows-arm64": { "friendlyName": "windows-arm64-v8a" },
"windows-arm7": { "friendlyName": "windows-arm32-v7a" } "windows-arm7": { "friendlyName": "windows-arm32-v7a" }
} }

View File

@@ -9,7 +9,3 @@ updates:
directory: "/" # Location of package manifests directory: "/" # Location of package manifests
schedule: schedule:
interval: "daily" interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

View File

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

View File

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

View File

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

View File

@@ -1,11 +1,5 @@
name: Build and Release name: Build and Release
# NOTE: This Github Actions file depends on the Makefile.
# Building the correct package requires the correct binaries generated by the Makefile. To
# ensure the correct output, the Makefile must accept the appropriate input and compile the
# correct file with the correct name. If you need to modify this file, please ensure it won't
# disrupt the Makefile.
on: on:
workflow_dispatch: workflow_dispatch:
release: release:
@@ -26,60 +20,16 @@ on:
- "go.sum" - "go.sum"
- ".github/workflows/*.yml" - ".github/workflows/*.yml"
jobs: jobs:
prepare:
runs-on: ubuntu-latest
steps:
- name: Restore Cache
uses: actions/cache/restore@v4
with:
path: resources
key: xray-geodat-
- name: Update Geodat
id: update
uses: nick-fields/retry@v3
with:
timeout_minutes: 60
retry_wait_seconds: 60
max_attempts: 60
command: |
[ -d 'resources' ] || mkdir resources
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite')
for i in "${LIST[@]}"
do
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3}'))
FILE_NAME="${INFO[2]}.dat"
echo -e "Verifying HASH key..."
HASH="$(curl -sL "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
if [ -s "./resources/${FILE_NAME}" ] && [ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ]; then
continue
else
echo -e "Downloading https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat..."
curl -L "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat" -o ./resources/${FILE_NAME}
echo -e "Verifying HASH key..."
[ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ] || { echo -e "The HASH key of ${FILE_NAME} does not match cloud one."; exit 1; }
echo "unhit=true" >> $GITHUB_OUTPUT
fi
done
- name: Save Cache
uses: actions/cache/save@v4
if: ${{ steps.update.outputs.unhit }}
with:
path: resources
key: xray-geodat-${{ github.sha }}-${{ github.run_number }}
build: build:
needs: prepare
permissions:
contents: write
strategy: strategy:
matrix: matrix:
# Include amd64 on all platforms. # Include amd64 on all platforms.
goos: [windows, freebsd, openbsd, linux, darwin] goos: [windows, freebsd, openbsd, linux, dragonfly, darwin]
goarch: [amd64, 386] goarch: [amd64, 386]
exclude: exclude:
# Exclude i386 on darwin # Exclude i386 on darwin and dragonfly.
- goarch: 386
goos: dragonfly
- goarch: 386 - goarch: 386
goos: darwin goos: darwin
include: include:
@@ -109,14 +59,12 @@ jobs:
goarch: arm goarch: arm
goarm: 7 goarm: 7
# BEGIN Other architectures # BEGIN Other architectures
# BEGIN riscv64 & ARM64 & LOONG64 # BEGIN riscv64 & ARM64
- goos: linux - goos: linux
goarch: arm64 goarch: arm64
- goos: linux - goos: linux
goarch: riscv64 goarch: riscv64
- goos: linux # END riscv64 & ARM64
goarch: loong64
# END riscv64 & ARM64 & LOONG64
# BEGIN MIPS # BEGIN MIPS
- goos: linux - goos: linux
goarch: mips64 goarch: mips64
@@ -162,49 +110,75 @@ jobs:
CGO_ENABLED: 0 CGO_ENABLED: 0
steps: steps:
- name: Checkout codebase - name: Checkout codebase
uses: actions/checkout@v4 uses: actions/checkout@v2
- name: Show workflow information - name: Show workflow information
id: get_filename
run: | run: |
export _NAME=$(jq ".[\"$GOOS-$GOARCH$GOARM$GOMIPS\"].friendlyName" -r < .github/build/friendly-filenames.json) 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 "GOOS: $GOOS, GOARCH: $GOARCH, GOARM: $GOARM, GOMIPS: $GOMIPS, RELEASE_NAME: $_NAME"
echo "::set-output name=ASSET_NAME::$_NAME"
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v2
with: with:
go-version-file: go.mod go-version: ^1.17.2
check-latest: true
- name: Get project dependencies - name: Get project dependencies
run: go mod download 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 - name: Build Xray
run: | run: |
mkdir -p build_assets mkdir -p build_assets
make go build -v -o build_assets/xray -trimpath -ldflags "-s -w -buildid=" ./main
find . -maxdepth 1 -type f -regex '.*\(wxray\|xray\|xray_softfloat\)\(\|.exe\)' -exec mv {} ./build_assets/ \;
- name: Build Mips softfloat Xray
- name: Restore Cache if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle'
uses: actions/cache/restore@v4 run: |
with: GOMIPS=softfloat go build -v -o build_assets/xray_softfloat -trimpath -ldflags "-s -w -buildid=" ./main
path: resources
key: xray-geodat- - name: Rename Windows Xray
if: matrix.goos == 'windows'
- name: Copy README.md & LICENSE run: |
cd ./build_assets || exit 1
mv xray xray.exe
- name: Prepare to release
run: | run: |
mv -f resources/* build_assets
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE 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 - name: Create ZIP archive
shell: bash shell: bash
run: | run: |
pushd build_assets || exit 1 pushd build_assets || exit 1
touch -mt $(date +%Y01010000) * touch -mt $(date +%Y01010000) *
zip -9vr ../Xray-${{ env.ASSET_NAME }}.zip . zip -9vr ../Xray-$ASSET_NAME.zip .
popd || exit 1 popd || exit 1
FILE=./Xray-${{ env.ASSET_NAME }}.zip FILE=./Xray-$ASSET_NAME.zip
DGST=$FILE.dgst DGST=$FILE.dgst
for METHOD in {"md5","sha1","sha256","sha512"} for METHOD in {"md5","sha1","sha256","sha512"}
do do
@@ -213,20 +187,20 @@ jobs:
- name: Change the name - name: Change the name
run: | run: |
mv build_assets Xray-${{ env.ASSET_NAME }} mv build_assets Xray-$ASSET_NAME
- name: Upload files to Artifacts - name: Upload files to Artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v2
with: with:
name: Xray-${{ env.ASSET_NAME }} name: Xray-${{ steps.get_filename.outputs.ASSET_NAME }}
path: | path: |
./Xray-${{ env.ASSET_NAME }}/* ./Xray-${{ steps.get_filename.outputs.ASSET_NAME }}/*
- name: Upload binaries to release - name: Upload binaries to release
uses: svenstaro/upload-release-action@v2 uses: svenstaro/upload-release-action@v2
if: github.event_name == 'release' if: github.event_name == 'release'
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ./Xray-${{ env.ASSET_NAME }}.zip* file: ./Xray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip*
tag: ${{ github.ref }} tag: ${{ github.ref }}
file_glob: true file_glob: true

View File

@@ -19,26 +19,30 @@ on:
jobs: jobs:
test: test:
permissions:
contents: read
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [windows-latest, ubuntu-latest, macos-latest] os: [windows-latest, ubuntu-latest, macos-latest]
steps: steps:
- name: Checkout codebase
uses: actions/checkout@v4
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v2
with: with:
go-version-file: go.mod go-version: ^1.17.2
check-latest: true - name: Checkout codebase
- name: Restore Cache uses: actions/checkout@v2
uses: actions/cache/restore@v4
with: - name: Prepare geo*dat
path: resources if: ${{ matrix.os != 'windows-latest' }}
key: xray-geodat- run: |
enableCrossOsArchive: true 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 - name: Test
run: go test -timeout 1h -v ./... run: go test -timeout 1h -v ./...

6
.gitignore vendored
View File

@@ -18,13 +18,11 @@
.idea .idea
*.zip *.zip
*.tar.gz *.tar.gz
xray v2ray
xray_softfloat v2ctl
mockgen mockgen
vprotogen vprotogen
!infra/vprotogen/ !infra/vprotogen/
errorgen errorgen
!common/errors/errorgen/ !common/errors/errorgen/
*.dat *.dat
.vscode
/build_assets

View File

@@ -1,40 +0,0 @@
NAME = xray
VERSION=$(shell git describe --always --dirty)
# NOTE: This MAKEFILE can be used to build Xray-core locally and in Automatic workflows. It is \
provided for convinience in automatic building and functions as a part of it.
# NOTE: If you need to modify this file, please be aware that:\
- This file is not the main Makefile; it only accepts environment variables and builds the \
binary.\
- Automatic building expects the correct binaries to be built by this Makefile. If you \
intend to propose a change to this Makefile, carefully review the file below and ensure \
that the change will not accidently break the automatic building:\
.github/workflows/release.yml \
Otherwise it is recommended to contact the project maintainers.
LDFLAGS = -X github.com/xtls/xray-core/core.build=$(VERSION) -s -w -buildid=
PARAMS = -trimpath -ldflags "$(LDFLAGS)" -v
MAIN = ./main
PREFIX ?= $(shell go env GOPATH)
ifeq ($(GOOS),windows)
OUTPUT = $(NAME).exe
ADDITION = go build -o w$(NAME).exe -trimpath -ldflags "-H windowsgui $(LDFLAGS)" -v $(MAIN)
else
OUTPUT = $(NAME)
endif
ifeq ($(shell echo "$(GOARCH)" | grep -Pq "(mips|mipsle)" && echo true),true) #
ADDITION = GOMIPS=softfloat go build -o $(NAME)_softfloat -trimpath -ldflags "$(LDFLAGS)" -v $(MAIN)
endif
.PHONY: clean
build:
go build -o $(OUTPUT) $(PARAMS) $(MAIN)
$(ADDITION)
install:
go build -o $(PREFIX)/bin/$(OUTPUT) $(PARAMS) $(MAIN)
clean:
go clean -v -i $(PWD)
rm -f xray xray.exe wxray.exe xray_softfloat

205
README.md
View File

@@ -1,16 +1,85 @@
# Project X # Project X
[Project X](https://github.com/XTLS) originates from XTLS protocol, providing a set of network tools such as [Xray-core](https://github.com/XTLS/Xray-core) and [REALITY](https://github.com/XTLS/REALITY). [Project X](https://github.com/XTLS) originates from XTLS protocol, provides a set of network tools such as [Xray-core](https://github.com/XTLS/Xray-core) and [Xray-flutter](https://github.com/XTLS/Xray-flutter).
[README](https://github.com/XTLS/Xray-core#readme) is open, so feel free to submit your project [here](https://github.com/XTLS/Xray-core/pulls).
## License ## License
[Mozilla Public License Version 2.0](https://github.com/XTLS/Xray-core/blob/main/LICENSE) [Mozilla Public License Version 2.0](https://github.com/XTLS/Xray-core/blob/main/LICENSE)
## Documentation ## Installation
[Project X Official Website](https://xtls.github.io) - Linux Script
- [Xray-install](https://github.com/XTLS/Xray-install)
- [Xray-script](https://github.com/kirin10000/Xray-script)
- Docker
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
- Xray-docker
- One Click
- [ProxySU](https://github.com/proxysu/ProxySU)
- [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
- [Xray4Magisk](https://github.com/CerteKim/Xray4Magisk)
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
- Homebrew
- `brew install xray`
- [(Tap) Repository 0](https://github.com/N4FA/homebrew-xray)
- [(Tap) Repository 1](https://github.com/xiruizhao/homebrew-xray)
## Usage
[Xray-examples](https://github.com/XTLS/Xray-examples) / [VLESS-TCP-XTLS-WHATEVER](https://github.com/XTLS/Xray-examples/tree/main/VLESS-TCP-XTLS-WHATEVER)
## GUI Clients
- OpenWrt
- [PassWall](https://github.com/xiaorouji/openwrt-passwall)
- [Hello World](https://github.com/jerrykuku/luci-app-vssr)
- [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
- [v2rayN](https://github.com/2dust/v2rayN)
- [Qv2ray](https://github.com/Qv2ray/Qv2ray) (This project had been archived and currently inactive)
- [Netch (NetFilter & TUN/TAP)](https://github.com/NetchX/Netch)
- Android
- [v2rayNG](https://github.com/2dust/v2rayNG)
- [AnXray](https://github.com/XTLS/AnXray)
- [Kitsunebi](https://github.com/rurirei/Kitsunebi/tree/release_xtls)
- iOS & macOS (with M1 chip)
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
- macOS (Intel chip & M1 chip)
- [Qv2ray](https://github.com/Qv2ray/Qv2ray) (This project had been archived and currently inactive)
## Credits
This repo relies on the following third-party projects:
- Special thanks:
- [v2fly/v2ray-core](https://github.com/v2fly/v2ray-core)
- In production:
- [gorilla/websocket](https://github.com/gorilla/websocket)
- [lucas-clemente/quic-go](https://github.com/lucas-clemente/quic-go)
- [pires/go-proxyproto](https://github.com/pires/go-proxyproto)
- [seiflotfy/cuckoofilter](https://github.com/seiflotfy/cuckoofilter)
- [google/starlark-go](https://github.com/google/starlark-go)
- For testing only:
- [miekg/dns](https://github.com/miekg/dns)
- [h12w/socks](https://github.com/h12w/socks)
## Compilation
### Windows
```
go build -o xray.exe -trimpath -ldflags "-s -w -buildid=" ./main
```
### Linux / macOS
```
go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
```
## Telegram ## Telegram
@@ -18,132 +87,6 @@
[Project X Channel](https://t.me/projectXtls) [Project X Channel](https://t.me/projectXtls)
## Installation
- Linux Script
- [XTLS/Xray-install](https://github.com/XTLS/Xray-install) (**Official**)
- [tempest](https://github.com/team-cloudchaser/tempest) (supports [`systemd`](https://systemd.io) and [OpenRC](https://github.com/OpenRC/openrc); Linux-only)
- Docker
- [ghcr.io/xtls/xray-core](https://ghcr.io/xtls/xray-core) (**Official**)
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
- Web Panel
- [X-UI-English](https://github.com/NidukaAkalanka/x-ui-english), [3X-UI](https://github.com/MHSanaei/3x-ui), [X-UI](https://github.com/alireza0/x-ui), [X-UI](https://github.com/diditra/x-ui)
- [Xray-UI](https://github.com/qist/xray-ui), [X-UI](https://github.com/sing-web/x-ui)
- [Hiddify](https://github.com/hiddify/hiddify-config)
- [Marzban](https://github.com/Gozargah/Marzban)
- [Libertea](https://github.com/VZiChoushaDui/Libertea)
- One Click
- [Xray-REALITY](https://github.com/zxcvos/Xray-script), [xray-reality](https://github.com/sajjaddg/xray-reality), [reality-ezpz](https://github.com/aleskxyz/reality-ezpz)
- [Xray_bash_onekey](https://github.com/hello-yunshu/Xray_bash_onekey), [XTool](https://github.com/LordPenguin666/XTool)
- [v2ray-agent](https://github.com/mack-a/v2ray-agent), [Xray_onekey](https://github.com/wulabing/Xray_onekey), [ProxySU](https://github.com/proxysu/ProxySU)
- Magisk
- [Xray4Magisk](https://github.com/Asterisk4Magisk/Xray4Magisk)
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
- Homebrew
- `brew install xray`
## Usage
- Example
- [VLESS-XTLS-uTLS-REALITY](https://github.com/XTLS/REALITY#readme)
- [VLESS-TCP-XTLS-Vision](https://github.com/XTLS/Xray-examples/tree/main/VLESS-TCP-XTLS-Vision)
- [All-in-One-fallbacks-Nginx](https://github.com/XTLS/Xray-examples/tree/main/All-in-One-fallbacks-Nginx)
- Xray-examples
- [XTLS/Xray-examples](https://github.com/XTLS/Xray-examples)
- [chika0801/Xray-examples](https://github.com/chika0801/Xray-examples)
- [lxhao61/integrated-examples](https://github.com/lxhao61/integrated-examples)
- Tutorial
- [XTLS Vision](https://github.com/chika0801/Xray-install)
- [REALITY (English)](https://cscot.pages.dev/2023/03/02/Xray-REALITY-tutorial/)
- [XTLS-Iran-Reality (English)](https://github.com/SasukeFreestyle/XTLS-Iran-Reality)
- [Xray REALITY with 'steal oneself' (English)](https://computerscot.github.io/vless-xtls-utls-reality-steal-oneself.html)
- [Xray with WireGuard inbound (English)](https://g800.pages.dev/wireguard)
## GUI Clients
- OpenWrt
- [PassWall](https://github.com/xiaorouji/openwrt-passwall), [PassWall 2](https://github.com/xiaorouji/openwrt-passwall2)
- [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
- [v2rayN](https://github.com/2dust/v2rayN)
- [NekoRay](https://github.com/Matsuridayo/nekoray)
- [Furious](https://github.com/LorenEteval/Furious)
- [HiddifyN](https://github.com/hiddify/HiddifyN)
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
- Android
- [v2rayNG](https://github.com/2dust/v2rayNG)
- [HiddifyNG](https://github.com/hiddify/HiddifyNG)
- [X-flutter](https://github.com/XTLS/X-flutter)
- iOS & macOS arm64
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)
- macOS arm64 & x64
- [V2rayU](https://github.com/yanue/V2rayU)
- [V2RayXS](https://github.com/tzmax/V2RayXS)
- [Furious](https://github.com/LorenEteval/Furious)
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
- Linux
- [v2rayA](https://github.com/v2rayA/v2rayA)
- [NekoRay](https://github.com/Matsuridayo/nekoray)
- [Furious](https://github.com/LorenEteval/Furious)
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
- iOS & macOS arm64
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
- Xray Tools
- [xray-knife](https://github.com/lilendian0x00/xray-knife)
- Xray Wrapper
- [XTLS/libXray](https://github.com/XTLS/libXray)
- [xtlsapi](https://github.com/hiddify/xtlsapi)
- [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite)
- [XrayKit](https://github.com/arror/XrayKit)
- [Xray-core-python](https://github.com/LorenEteval/Xray-core-python)
- [xray-api](https://github.com/XVGuardian/xray-api)
- [XrayR](https://github.com/XrayR-project/XrayR)
- [XrayR-release](https://github.com/XrayR-project/XrayR-release)
- [XrayR-V2Board](https://github.com/missuo/XrayR-V2Board)
- [Clash.Meta](https://github.com/MetaCubeX/Clash.Meta)
- [Clash Verge](https://github.com/zzzgydi/clash-verge)
- [clashN](https://github.com/2dust/clashN)
- [Clash Meta for Android](https://github.com/MetaCubeX/ClashMetaForAndroid)
- [meta_for_ios](https://t.me/meta_for_ios)
- [sing-box](https://github.com/SagerNet/sing-box)
- [installReality](https://github.com/BoxXt/installReality)
- [sbox-reality](https://github.com/Misaka-blog/sbox-reality)
- [sing-box-for-ios](https://github.com/SagerNet/sing-box-for-ios)
## Contributing
[Code of Conduct](https://github.com/XTLS/Xray-core/blob/main/CODE_OF_CONDUCT.md)
## Credits
- [Xray-core v1.0.0](https://github.com/XTLS/Xray-core/releases/tag/v1.0.0) was forked from [v2fly-core 9a03cc5](https://github.com/v2fly/v2ray-core/commit/9a03cc5c98d04cc28320fcee26dbc236b3291256), and we have made & accumulated a huge number of enhancements over time, check [the release notes for each version](https://github.com/XTLS/Xray-core/releases).
- For third-party projects used in [Xray-core](https://github.com/XTLS/Xray-core), check your local or [the latest go.mod](https://github.com/XTLS/Xray-core/blob/main/go.mod).
## Compilation
### Windows (PowerShell)
```powershell
$env:CGO_ENABLED=0
go build -o xray.exe -trimpath -ldflags "-s -w -buildid=" ./main
```
### Linux / macOS
```bash
CGO_ENABLED=0 go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
```
### Reproducible Releases
```bash
make
```
## Stargazers over time ## Stargazers over time
[![Stargazers over time](https://starchart.cc/XTLS/Xray-core.svg)](https://starchart.cc/XTLS/Xray-core) [![Stargazers over time](https://starchart.cc/XTLS/Xray-core.svg)](https://starchart.cc/XTLS/Xray-core)

View File

@@ -7,11 +7,12 @@ import (
"net" "net"
"sync" "sync"
"google.golang.org/grpc"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/done"
core "github.com/xtls/xray-core/core" core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"google.golang.org/grpc"
) )
// Commander is a Xray feature that provides gRPC methods to external clients. // Commander is a Xray feature that provides gRPC methods to external clients.
@@ -21,14 +22,12 @@ type Commander struct {
services []Service services []Service
ohm outbound.Manager ohm outbound.Manager
tag string tag string
listen string
} }
// NewCommander creates a new Commander based on the given config. // NewCommander creates a new Commander based on the given config.
func NewCommander(ctx context.Context, config *Config) (*Commander, error) { func NewCommander(ctx context.Context, config *Config) (*Commander, error) {
c := &Commander{ c := &Commander{
tag: config.Tag, tag: config.Tag,
listen: config.Listen,
} }
common.Must(core.RequireFeatures(ctx, func(om outbound.Manager) { common.Must(core.RequireFeatures(ctx, func(om outbound.Manager) {
@@ -68,29 +67,16 @@ func (c *Commander) Start() error {
} }
c.Unlock() c.Unlock()
var listen = func(listener net.Listener) {
if err := c.server.Serve(listener); err != nil {
newError("failed to start grpc server").Base(err).AtError().WriteToLog()
}
}
if len(c.listen) > 0 {
if l, err := net.Listen("tcp", c.listen); err != nil {
newError("API server failed to listen on ", c.listen).Base(err).AtError().WriteToLog()
return err
} else {
newError("API server listening on ", l.Addr()).AtInfo().WriteToLog()
go listen(l)
}
return nil
}
listener := &OutboundListener{ listener := &OutboundListener{
buffer: make(chan net.Conn, 4), buffer: make(chan net.Conn, 4),
done: done.New(), done: done.New(),
} }
go listen(listener) go func() {
if err := c.server.Serve(listener); err != nil {
newError("failed to start grpc server").Base(err).AtError().WriteToLog()
}
}()
if err := c.ohm.RemoveHandler(context.Background(), c.tag); err != nil { if err := c.ohm.RemoveHandler(context.Background(), c.tag); err != nil {
newError("failed to remove existing handler").WriteToLog() newError("failed to remove existing handler").WriteToLog()

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.28.1 // protoc-gen-go v1.27.1
// protoc v4.25.3 // protoc v3.18.0
// source: app/commander/config.proto // source: app/commander/config.proto
package commander package commander
@@ -29,8 +29,6 @@ type Config struct {
// Tag of the outbound handler that handles grpc connections. // Tag of the outbound handler that handles grpc connections.
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"` Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
// Network address of commander grpc service.
Listen string `protobuf:"bytes,3,opt,name=listen,proto3" json:"listen,omitempty"`
// Services that supported by this server. All services must implement Service // Services that supported by this server. All services must implement Service
// interface. // interface.
Service []*serial.TypedMessage `protobuf:"bytes,2,rep,name=service,proto3" json:"service,omitempty"` Service []*serial.TypedMessage `protobuf:"bytes,2,rep,name=service,proto3" json:"service,omitempty"`
@@ -75,13 +73,6 @@ func (x *Config) GetTag() string {
return "" return ""
} }
func (x *Config) GetListen() string {
if x != nil {
return x.Listen
}
return ""
}
func (x *Config) GetService() []*serial.TypedMessage { func (x *Config) GetService() []*serial.TypedMessage {
if x != nil { if x != nil {
return x.Service return x.Service
@@ -136,21 +127,20 @@ var file_app_commander_config_proto_rawDesc = []byte{
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72,
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,
0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0x6e, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x6f, 0x74, 0x6f, 0x22, 0x56, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a,
0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12,
0x16, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x3a, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x3a, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73,
0x63, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x67, 0x65, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52,
0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42,
0x69, 0x63, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74,
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
0x72, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x6e, 0x64, 0x65, 0x72, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e,
0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0xaa, 0x02, 0x12, 0x58, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x33,
0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -12,10 +12,6 @@ import "common/serial/typed_message.proto";
message Config { message Config {
// Tag of the outbound handler that handles grpc connections. // Tag of the outbound handler that handles grpc connections.
string tag = 1; string tag = 1;
// Network address of commander grpc service.
string listen = 3;
// Services that supported by this server. All services must implement Service // Services that supported by this server. All services must implement Service
// interface. // interface.
repeated xray.common.serial.TypedMessage service = 2; repeated xray.common.serial.TypedMessage service = 2;

View File

@@ -37,7 +37,7 @@ func (l *OutboundListener) Accept() (net.Conn, error) {
} }
} }
// Close implements net.Listener. // Close implement net.Listener.
func (l *OutboundListener) Close() error { func (l *OutboundListener) Close() error {
common.Must(l.done.Close()) common.Must(l.done.Close())
L: L:

View File

@@ -3,9 +3,10 @@ package commander
import ( import (
"context" "context"
"github.com/xtls/xray-core/common"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/reflection" "google.golang.org/grpc/reflection"
"github.com/xtls/xray-core/common"
) )
// Service is a Commander service. // Service is a Commander service.

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.27.1
// protoc v4.23.1 // protoc v3.18.0
// source: app/dispatcher/config.proto // source: app/dispatcher/config.proto
package dispatcher package dispatcher

View File

@@ -4,6 +4,7 @@ package dispatcher
import ( import (
"context" "context"
"github.com/xtls/xray-core/features/dns"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -15,7 +16,6 @@ import (
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
@@ -92,17 +92,13 @@ type DefaultDispatcher struct {
router routing.Router router routing.Router
policy policy.Manager policy policy.Manager
stats stats.Manager stats stats.Manager
dns dns.Client hosts dns.HostsLookup
fdns dns.FakeDNSEngine
} }
func init() { func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
d := new(DefaultDispatcher) d := new(DefaultDispatcher)
if err := core.RequireFeatures(ctx, func(om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dc dns.Client) error { if err := core.RequireFeatures(ctx, func(om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dc dns.Client) error {
core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
d.fdns = fdns
})
return d.Init(config.(*Config), om, router, pm, sm, dc) return d.Init(config.(*Config), om, router, pm, sm, dc)
}); err != nil { }); err != nil {
return nil, err return nil, err
@@ -112,12 +108,14 @@ func init() {
} }
// Init initializes DefaultDispatcher. // Init initializes DefaultDispatcher.
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dns dns.Client) error { func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dc dns.Client) error {
d.ohm = om d.ohm = om
d.router = router d.router = router
d.policy = pm d.policy = pm
d.stats = sm d.stats = sm
d.dns = dns if hosts, ok := dc.(dns.HostsLookup); ok {
d.hosts = hosts
}
return nil return nil
} }
@@ -180,26 +178,27 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
return inboundLink, outboundLink return inboundLink, outboundLink
} }
func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool { func shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
domain := result.Domain() domain := result.Domain()
if domain == "" {
return false
}
for _, d := range request.ExcludeForDomain { for _, d := range request.ExcludeForDomain {
if strings.ToLower(domain) == d { if strings.ToLower(domain) == d {
return false return false
} }
} }
var fakeDNSEngine dns.FakeDNSEngine
core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
fakeDNSEngine = fdns
})
protocolString := result.Protocol() protocolString := result.Protocol()
if resComp, ok := result.(SnifferResultComposite); ok { if resComp, ok := result.(SnifferResultComposite); ok {
protocolString = resComp.ProtocolForDomainResult() protocolString = resComp.ProtocolForDomainResult()
} }
for _, p := range request.OverrideDestinationForProtocol { for _, p := range request.OverrideDestinationForProtocol {
if strings.HasPrefix(protocolString, p) || strings.HasPrefix(p, protocolString) { if strings.HasPrefix(protocolString, p) {
return true return true
} }
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && protocolString != "bittorrent" && p == "fakedns" && if fkr0, ok := fakeDNSEngine.(dns.FakeDNSEngineRev0); ok && protocolString != "bittorrent" && p == "fakedns" &&
fkr0.IsIPInIPPool(destination.Address) { destination.Address.Family().IsIP() && fkr0.IsIPInIPPool(destination.Address) {
newError("Using sniffer ", protocolString, " since the fake DNS missed").WriteToLog(session.ExportIDToError(ctx)) newError("Using sniffer ", protocolString, " since the fake DNS missed").WriteToLog(session.ExportIDToError(ctx))
return true return true
} }
@@ -218,47 +217,53 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
if !destination.IsValid() { if !destination.IsValid() {
panic("Dispatcher: Invalid destination.") panic("Dispatcher: Invalid destination.")
} }
outbounds := session.OutboundsFromContext(ctx) ob := &session.Outbound{
if len(outbounds) == 0 { Target: destination,
outbounds = []*session.Outbound{{}}
ctx = session.ContextWithOutbounds(ctx, outbounds)
} }
ob := outbounds[len(outbounds) - 1] ctx = session.ContextWithOutbound(ctx, ob)
ob.OriginalTarget = destination
ob.Target = destination inbound, outbound := d.getLink(ctx)
content := session.ContentFromContext(ctx) content := session.ContentFromContext(ctx)
if content == nil { if content == nil {
content = new(session.Content) content = new(session.Content)
ctx = session.ContextWithContent(ctx, content) ctx = session.ContextWithContent(ctx, content)
} }
sniffingRequest := content.SniffingRequest sniffingRequest := content.SniffingRequest
inbound, outbound := d.getLink(ctx) switch {
if !sniffingRequest.Enabled { case !sniffingRequest.Enabled:
go d.routedDispatch(ctx, outbound, destination) go d.routedDispatch(ctx, outbound, destination)
} else { case destination.Network != net.Network_TCP:
// Only metadata sniff will be used for non tcp connection
result, err := sniffer(ctx, nil, true)
if err == nil {
content.Protocol = result.Protocol()
if shouldOverride(ctx, result, sniffingRequest, destination) {
domain := result.Domain()
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
destination.Address = net.ParseAddress(domain)
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
ob.RouteTarget = destination
} else {
ob.Target = destination
}
}
}
go d.routedDispatch(ctx, outbound, destination)
default:
go func() { go func() {
cReader := &cachedReader{ cReader := &cachedReader{
reader: outbound.Reader.(*pipe.Reader), reader: outbound.Reader.(*pipe.Reader),
} }
outbound.Reader = cReader outbound.Reader = cReader
result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly, destination.Network) result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly)
if err == nil { if err == nil {
content.Protocol = result.Protocol() content.Protocol = result.Protocol()
} }
if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) { if err == nil && shouldOverride(ctx, result, sniffingRequest, destination) {
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)
protocol := result.Protocol() if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
if resComp, ok := result.(SnifferResultComposite); ok {
protocol = resComp.ProtocolForDomainResult()
}
isFakeIP := false
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && fkr0.IsIPInIPPool(ob.Target.Address) {
isFakeIP = true
}
if sniffingRequest.RouteOnly && protocol != "fakedns" && protocol != "fakedns+others" && !isFakeIP {
ob.RouteTarget = destination ob.RouteTarget = destination
} else { } else {
ob.Target = destination ob.Target = destination
@@ -275,56 +280,63 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
if !destination.IsValid() { if !destination.IsValid() {
return newError("Dispatcher: Invalid destination.") return newError("Dispatcher: Invalid destination.")
} }
outbounds := session.OutboundsFromContext(ctx) ob := &session.Outbound{
if len(outbounds) == 0 { Target: destination,
outbounds = []*session.Outbound{{}}
ctx = session.ContextWithOutbounds(ctx, outbounds)
} }
ob := outbounds[len(outbounds) - 1] ctx = session.ContextWithOutbound(ctx, ob)
ob.OriginalTarget = destination
ob.Target = destination
content := session.ContentFromContext(ctx) content := session.ContentFromContext(ctx)
if content == nil { if content == nil {
content = new(session.Content) content = new(session.Content)
ctx = session.ContextWithContent(ctx, content) ctx = session.ContextWithContent(ctx, content)
} }
sniffingRequest := content.SniffingRequest sniffingRequest := content.SniffingRequest
if !sniffingRequest.Enabled { switch {
d.routedDispatch(ctx, outbound, destination) case !sniffingRequest.Enabled:
} else { go d.routedDispatch(ctx, outbound, destination)
cReader := &cachedReader{ case destination.Network != net.Network_TCP:
reader: outbound.Reader.(*pipe.Reader), // Only metadata sniff will be used for non tcp connection
} result, err := sniffer(ctx, nil, true)
outbound.Reader = cReader
result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly, destination.Network)
if err == nil { if err == nil {
content.Protocol = result.Protocol() content.Protocol = result.Protocol()
} if shouldOverride(ctx, result, sniffingRequest, destination) {
if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) { 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) if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
protocol := result.Protocol() ob.RouteTarget = destination
if resComp, ok := result.(SnifferResultComposite); ok { } else {
protocol = resComp.ProtocolForDomainResult() ob.Target = destination
} }
isFakeIP := false
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && fkr0.IsIPInIPPool(ob.Target.Address) {
isFakeIP = true
}
if sniffingRequest.RouteOnly && protocol != "fakedns" && protocol != "fakedns+others" && !isFakeIP {
ob.RouteTarget = destination
} else {
ob.Target = destination
} }
} }
d.routedDispatch(ctx, outbound, destination) go d.routedDispatch(ctx, outbound, destination)
default:
go func() {
cReader := &cachedReader{
reader: outbound.Reader.(*pipe.Reader),
}
outbound.Reader = cReader
result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly)
if err == nil {
content.Protocol = result.Protocol()
}
if err == nil && shouldOverride(ctx, result, sniffingRequest, destination) {
domain := result.Domain()
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
destination.Address = net.ParseAddress(domain)
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
ob.RouteTarget = destination
} else {
ob.Target = destination
}
}
d.routedDispatch(ctx, outbound, destination)
}()
} }
return nil return nil
} }
func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, network net.Network) (SniffResult, error) { func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool) (SniffResult, error) {
payload := buf.New() payload := buf.New()
defer payload.Release() defer payload.Release()
@@ -350,7 +362,7 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
cReader.Cache(payload) cReader.Cache(payload)
if !payload.IsEmpty() { if !payload.IsEmpty() {
result, err := sniffer.Sniff(ctx, payload.Bytes(), network) result, err := sniffer.Sniff(ctx, payload.Bytes())
if err != common.ErrNoClue { if err != common.ErrNoClue {
return result, err return result, err
} }
@@ -369,11 +381,11 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
} }
return contentResult, contentErr return contentResult, contentErr
} }
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) { func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
outbounds := session.OutboundsFromContext(ctx) ob := session.OutboundFromContext(ctx)
ob := outbounds[len(outbounds) - 1] if d.hosts != nil && destination.Address.Family().IsDomain() {
if hosts, ok := d.dns.(dns.HostsLookup); ok && destination.Address.Family().IsDomain() { proxied := d.hosts.LookupHosts(ob.Target.String())
proxied := hosts.LookupHosts(ob.Target.String())
if proxied != nil { if proxied != nil {
ro := ob.RouteTarget == destination ro := ob.RouteTarget == destination
destination.Address = *proxied destination.Address = *proxied
@@ -387,13 +399,9 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
var handler outbound.Handler var handler outbound.Handler
routingLink := routing_session.AsRoutingContext(ctx)
inTag := routingLink.GetInboundTag()
isPickRoute := 0
if forcedOutboundTag := session.GetForcedOutboundTagFromContext(ctx); forcedOutboundTag != "" { if forcedOutboundTag := session.GetForcedOutboundTagFromContext(ctx); forcedOutboundTag != "" {
ctx = session.SetForcedOutboundTagToContext(ctx, "") ctx = session.SetForcedOutboundTagToContext(ctx, "")
if h := d.ohm.GetHandler(forcedOutboundTag); h != nil { if h := d.ohm.GetHandler(forcedOutboundTag); h != nil {
isPickRoute = 1
newError("taking platform initialized detour [", forcedOutboundTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx)) newError("taking platform initialized detour [", forcedOutboundTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
handler = h handler = h
} else { } else {
@@ -403,14 +411,13 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
return return
} }
} else if d.router != nil { } else if d.router != nil {
if route, err := d.router.PickRoute(routingLink); err == nil { if route, err := d.router.PickRoute(routing_session.AsRoutingContext(ctx)); err == nil {
outTag := route.GetOutboundTag() tag := route.GetOutboundTag()
if h := d.ohm.GetHandler(outTag); h != nil { if h := d.ohm.GetHandler(tag); h != nil {
isPickRoute = 2 newError("taking detour [", tag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
newError("taking detour [", outTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
handler = h handler = h
} else { } else {
newError("non existing outTag: ", outTag).AtWarning().WriteToLog(session.ExportIDToError(ctx)) newError("non existing outTag: ", tag).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))
@@ -428,18 +435,9 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
return return
} }
ob.Tag = handler.Tag()
if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil { if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil {
if tag := handler.Tag(); tag != "" { if tag := handler.Tag(); tag != "" {
if inTag == "" { accessMessage.Detour = tag
accessMessage.Detour = tag
} else if isPickRoute == 1 {
accessMessage.Detour = inTag + " ==> " + tag
} else if isPickRoute == 2 {
accessMessage.Detour = inTag + " -> " + tag
} else {
accessMessage.Detour = inTag + " >> " + tag
}
} }
log.Record(accessMessage) log.Record(accessMessage)
} }

View File

@@ -11,27 +11,25 @@ import (
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
) )
// newFakeDNSSniffer Creates a Fake DNS metadata sniffer // newFakeDNSSniffer Create a Fake DNS metadata sniffer
func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error) { func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error) {
var fakeDNSEngine dns.FakeDNSEngine var fakeDNSEngine dns.FakeDNSEngine
{ err := core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
fakeDNSEngineFeat := core.MustFromContext(ctx).GetFeature((*dns.FakeDNSEngine)(nil)) fakeDNSEngine = fdns
if fakeDNSEngineFeat != nil { })
fakeDNSEngine = fakeDNSEngineFeat.(dns.FakeDNSEngine) if err != nil {
} return protocolSnifferWithMetadata{}, err
} }
if fakeDNSEngine == nil { if fakeDNSEngine == nil {
errNotInit := newError("FakeDNSEngine is not initialized, but such a sniffer is used").AtError() errNotInit := newError("FakeDNSEngine is not initialized, but such a sniffer is used").AtError()
return protocolSnifferWithMetadata{}, errNotInit return protocolSnifferWithMetadata{}, errNotInit
} }
return protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) { return protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) {
outbounds := session.OutboundsFromContext(ctx) Target := session.OutboundFromContext(ctx).Target
ob := outbounds[len(outbounds) - 1] if Target.Network == net.Network_TCP || Target.Network == net.Network_UDP {
if ob.Target.Network == net.Network_TCP || ob.Target.Network == net.Network_UDP { domainFromFakeDNS := fakeDNSEngine.GetDomainFromFakeDNS(Target.Address)
domainFromFakeDNS := fakeDNSEngine.GetDomainFromFakeDNS(ob.Target.Address)
if domainFromFakeDNS != "" { if domainFromFakeDNS != "" {
newError("fake dns got domain: ", domainFromFakeDNS, " for ip: ", ob.Target.Address.String()).WriteToLog(session.ExportIDToError(ctx)) newError("fake dns got domain: ", domainFromFakeDNS, " for ip: ", Target.Address.String()).WriteToLog(session.ExportIDToError(ctx))
return &fakeDNSSniffResult{domainName: domainFromFakeDNS}, nil return &fakeDNSSniffResult{domainName: domainFromFakeDNS}, nil
} }
} }
@@ -39,7 +37,7 @@ func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error)
if ipAddressInRangeValueI := ctx.Value(ipAddressInRange); ipAddressInRangeValueI != nil { if ipAddressInRangeValueI := ctx.Value(ipAddressInRange); ipAddressInRangeValueI != nil {
ipAddressInRangeValue := ipAddressInRangeValueI.(*ipAddressInRangeOpt) ipAddressInRangeValue := ipAddressInRangeValueI.(*ipAddressInRangeOpt)
if fkr0, ok := fakeDNSEngine.(dns.FakeDNSEngineRev0); ok { if fkr0, ok := fakeDNSEngine.(dns.FakeDNSEngineRev0); ok {
inPool := fkr0.IsIPInIPPool(ob.Target.Address) inPool := fkr0.IsIPInIPPool(Target.Address)
ipAddressInRangeValue.addressInRange = &inPool ipAddressInRangeValue.addressInRange = &inPool
} }
} }
@@ -86,8 +84,7 @@ func (f DNSThenOthersSniffResult) Domain() string {
} }
func newFakeDNSThenOthers(ctx context.Context, fakeDNSSniffer protocolSnifferWithMetadata, others []protocolSnifferWithMetadata) ( func newFakeDNSThenOthers(ctx context.Context, fakeDNSSniffer protocolSnifferWithMetadata, others []protocolSnifferWithMetadata) (
protocolSnifferWithMetadata, error, protocolSnifferWithMetadata, error) { // nolint: unparam
) { // nolint: unparam
// ctx may be used in the future // ctx may be used in the future
_ = ctx _ = ctx
return protocolSnifferWithMetadata{ return protocolSnifferWithMetadata{

View File

@@ -4,10 +4,8 @@ import (
"context" "context"
"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/protocol/bittorrent" "github.com/xtls/xray-core/common/protocol/bittorrent"
"github.com/xtls/xray-core/common/protocol/http" "github.com/xtls/xray-core/common/protocol/http"
"github.com/xtls/xray-core/common/protocol/quic"
"github.com/xtls/xray-core/common/protocol/tls" "github.com/xtls/xray-core/common/protocol/tls"
) )
@@ -24,7 +22,6 @@ type protocolSnifferWithMetadata struct {
// for both TCP and UDP connections // for both TCP and UDP connections
// It will not be shown as a traffic type for routing unless there is no other successful sniffing. // It will not be shown as a traffic type for routing unless there is no other successful sniffing.
metadataSniffer bool metadataSniffer bool
network net.Network
} }
type Sniffer struct { type Sniffer struct {
@@ -34,11 +31,9 @@ type Sniffer struct {
func NewSniffer(ctx context.Context) *Sniffer { func NewSniffer(ctx context.Context) *Sniffer {
ret := &Sniffer{ ret := &Sniffer{
sniffer: []protocolSnifferWithMetadata{ sniffer: []protocolSnifferWithMetadata{
{func(c context.Context, b []byte) (SniffResult, error) { return http.SniffHTTP(b) }, false, net.Network_TCP}, {func(c context.Context, b []byte) (SniffResult, error) { return http.SniffHTTP(b) }, false},
{func(c context.Context, b []byte) (SniffResult, error) { return tls.SniffTLS(b) }, false, net.Network_TCP}, {func(c context.Context, b []byte) (SniffResult, error) { return tls.SniffTLS(b) }, false},
{func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffBittorrent(b) }, false, net.Network_TCP}, {func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffBittorrent(b) }, false},
{func(c context.Context, b []byte) (SniffResult, error) { return quic.SniffQUIC(b) }, false, net.Network_UDP},
{func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffUTP(b) }, false, net.Network_UDP},
}, },
} }
if sniffer, err := newFakeDNSSniffer(ctx); err == nil { if sniffer, err := newFakeDNSSniffer(ctx); err == nil {
@@ -54,11 +49,11 @@ func NewSniffer(ctx context.Context) *Sniffer {
var errUnknownContent = newError("unknown content") var errUnknownContent = newError("unknown content")
func (s *Sniffer) Sniff(c context.Context, payload []byte, network net.Network) (SniffResult, error) { func (s *Sniffer) Sniff(c context.Context, payload []byte) (SniffResult, error) {
var pendingSniffer []protocolSnifferWithMetadata var pendingSniffer []protocolSnifferWithMetadata
for _, si := range s.sniffer { for _, si := range s.sniffer {
s := si.protocolSniffer s := si.protocolSniffer
if si.metadataSniffer || si.network != network { if si.metadataSniffer {
continue continue
} }
result, err := s(c, payload) result, err := s(c, payload)

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.27.1
// protoc v4.23.1 // protoc v3.18.0
// source: app/dns/config.proto // source: app/dns/config.proto
package dns package dns
@@ -134,7 +134,6 @@ type NameServer struct {
PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"` PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
Geoip []*router.GeoIP `protobuf:"bytes,3,rep,name=geoip,proto3" json:"geoip,omitempty"` Geoip []*router.GeoIP `protobuf:"bytes,3,rep,name=geoip,proto3" json:"geoip,omitempty"`
OriginalRules []*NameServer_OriginalRule `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"` OriginalRules []*NameServer_OriginalRule `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
QueryStrategy QueryStrategy `protobuf:"varint,7,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
} }
func (x *NameServer) Reset() { func (x *NameServer) Reset() {
@@ -211,13 +210,6 @@ func (x *NameServer) GetOriginalRules() []*NameServer_OriginalRule {
return nil return nil
} }
func (x *NameServer) GetQueryStrategy() QueryStrategy {
if x != nil {
return x.QueryStrategy
}
return QueryStrategy_USE_IP
}
type Config struct { type Config struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -227,14 +219,14 @@ type Config struct {
// the moment. A special value 'localhost' as a domain address can be set to // the moment. A special value 'localhost' as a domain address can be set to
// use DNS on local system. // use DNS on local system.
// //
// Deprecated: Marked as deprecated in app/dns/config.proto. // Deprecated: Do not use.
NameServers []*net.Endpoint `protobuf:"bytes,1,rep,name=NameServers,proto3" json:"NameServers,omitempty"` NameServers []*net.Endpoint `protobuf:"bytes,1,rep,name=NameServers,proto3" json:"NameServers,omitempty"`
// NameServer list used by this DNS client. // NameServer list used by this DNS client.
NameServer []*NameServer `protobuf:"bytes,5,rep,name=name_server,json=nameServer,proto3" json:"name_server,omitempty"` NameServer []*NameServer `protobuf:"bytes,5,rep,name=name_server,json=nameServer,proto3" json:"name_server,omitempty"`
// Static hosts. Domain to IP. // Static hosts. Domain to IP.
// Deprecated. Use static_hosts. // Deprecated. Use static_hosts.
// //
// Deprecated: Marked as deprecated in app/dns/config.proto. // Deprecated: Do not use.
Hosts map[string]*net.IPOrDomain `protobuf:"bytes,2,rep,name=Hosts,proto3" json:"Hosts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Hosts map[string]*net.IPOrDomain `protobuf:"bytes,2,rep,name=Hosts,proto3" json:"Hosts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes // Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes
// (IPv6). // (IPv6).
@@ -281,7 +273,7 @@ func (*Config) Descriptor() ([]byte, []int) {
return file_app_dns_config_proto_rawDescGZIP(), []int{1} return file_app_dns_config_proto_rawDescGZIP(), []int{1}
} }
// Deprecated: Marked as deprecated in app/dns/config.proto. // Deprecated: Do not use.
func (x *Config) GetNameServers() []*net.Endpoint { func (x *Config) GetNameServers() []*net.Endpoint {
if x != nil { if x != nil {
return x.NameServers return x.NameServers
@@ -296,7 +288,7 @@ func (x *Config) GetNameServer() []*NameServer {
return nil return nil
} }
// Deprecated: Marked as deprecated in app/dns/config.proto. // Deprecated: Do not use.
func (x *Config) GetHosts() map[string]*net.IPOrDomain { func (x *Config) GetHosts() map[string]*net.IPOrDomain {
if x != nil { if x != nil {
return x.Hosts return x.Hosts
@@ -546,7 +538,7 @@ var file_app_dns_config_proto_rawDesc = []byte{
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x65, 0x73, 0x74, 0x69,
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x61, 0x70, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x61, 0x70,
0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb2, 0x04, 0x0a, 0x0a, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xee, 0x03, 0x0a, 0x0a, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65,
0x72, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x72, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
@@ -567,81 +559,77 @@ var file_app_dns_config_proto_rawDesc = []byte{
0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52,
0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x42, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x1a, 0x5e,
0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20,
0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f,
0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65,
0x67, 0x79, 0x1a, 0x5e, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36,
0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12,
0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75,
0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0xef, 0x05, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x67, 0x12, 0x3f, 0x0a, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73,
0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0xef, 0x05, 0x0a, 0x06, 0x43, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3f, 0x0a, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x72, 0x73, 0x12, 0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65,
0x76, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65,
0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x39, 0x0a,
0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78,
0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66,
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x02, 0x18,
0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x01, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65,
0x72, 0x12, 0x39, 0x0a, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69,
0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72,
0x79, 0x42, 0x02, 0x18, 0x01, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73,
0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
0x74, 0x69, 0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x22, 0x0a, 0x0c,
0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08, 0x20, 0x01,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65,
0x67, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72,
0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61,
0x61, 0x63, 0x68, 0x65, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x74, 0x65, 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46,
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64,
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x36,
0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16,
0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49,
0x08, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x1a, 0x55, 0x0a, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45,
0x63, 0x6b, 0x12, 0x36, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x28, 0x08, 0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x1a, 0x55, 0x0a, 0x0a, 0x48, 0x6f, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61,
0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x69, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x92, 0x01,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x05, 0x76, 0x61, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a,
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74,
0x01, 0x1a, 0x92, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20,
0x67, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69,
0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20,
0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61,
0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x69, 0x6e, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x2a, 0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61,
0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08,
0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64,
0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f,
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x2a, 0x45, 0x0a, 0x12, 0x72, 0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x2a,
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x35, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07,
0x53, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4b, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45,
0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x02, 0x42, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
0x78, 0x10, 0x03, 0x2a, 0x35, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69,
0x74, 0x65, 0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x00, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72,
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa,
0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x02, 0x42, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06,
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c,
0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f,
0x64, 0x6e, 0x73, 0xaa, 0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44,
0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@@ -676,20 +664,19 @@ var file_app_dns_config_proto_depIdxs = []int32{
4, // 1: xray.app.dns.NameServer.prioritized_domain:type_name -> xray.app.dns.NameServer.PriorityDomain 4, // 1: xray.app.dns.NameServer.prioritized_domain:type_name -> xray.app.dns.NameServer.PriorityDomain
9, // 2: xray.app.dns.NameServer.geoip:type_name -> xray.app.router.GeoIP 9, // 2: xray.app.dns.NameServer.geoip:type_name -> xray.app.router.GeoIP
5, // 3: xray.app.dns.NameServer.original_rules:type_name -> xray.app.dns.NameServer.OriginalRule 5, // 3: xray.app.dns.NameServer.original_rules:type_name -> xray.app.dns.NameServer.OriginalRule
1, // 4: xray.app.dns.NameServer.query_strategy:type_name -> xray.app.dns.QueryStrategy 8, // 4: xray.app.dns.Config.NameServers:type_name -> xray.common.net.Endpoint
8, // 5: xray.app.dns.Config.NameServers:type_name -> xray.common.net.Endpoint 2, // 5: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer
2, // 6: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer 6, // 6: xray.app.dns.Config.Hosts:type_name -> xray.app.dns.Config.HostsEntry
6, // 7: xray.app.dns.Config.Hosts:type_name -> xray.app.dns.Config.HostsEntry 7, // 7: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
7, // 8: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping 1, // 8: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
1, // 9: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy 0, // 9: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
0, // 10: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType 10, // 10: xray.app.dns.Config.HostsEntry.value:type_name -> xray.common.net.IPOrDomain
10, // 11: xray.app.dns.Config.HostsEntry.value:type_name -> xray.common.net.IPOrDomain 0, // 11: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType
0, // 12: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType 12, // [12:12] is the sub-list for method output_type
13, // [13:13] is the sub-list for method output_type 12, // [12:12] is the sub-list for method input_type
13, // [13:13] is the sub-list for method input_type 12, // [12:12] is the sub-list for extension type_name
13, // [13:13] is the sub-list for extension type_name 12, // [12:12] is the sub-list for extension extendee
13, // [13:13] is the sub-list for extension extendee 0, // [0:12] is the sub-list for field type_name
0, // [0:13] is the sub-list for field type_name
} }
func init() { file_app_dns_config_proto_init() } func init() { file_app_dns_config_proto_init() }

View File

@@ -28,7 +28,6 @@ message NameServer {
repeated PriorityDomain prioritized_domain = 2; repeated PriorityDomain prioritized_domain = 2;
repeated xray.app.router.GeoIP geoip = 3; repeated xray.app.router.GeoIP geoip = 3;
repeated OriginalRule original_rules = 4; repeated OriginalRule original_rules = 4;
QueryStrategy query_strategy = 7;
} }
enum DomainMatchingType { enum DomainMatchingType {

View File

@@ -181,7 +181,9 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
} }
// Normalize the FQDN form query // Normalize the FQDN form query
domain = strings.TrimSuffix(domain, ".") if strings.HasSuffix(domain, ".") {
domain = domain[:len(domain)-1]
}
// Static host lookup // Static host lookup
switch addrs := s.hosts.Lookup(domain, option); { switch addrs := s.hosts.Lookup(domain, option); {
@@ -213,8 +215,7 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog() newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog()
errs = append(errs, err) errs = append(errs, err)
} }
// 5 for RcodeRefused in miekg/dns, hardcode to reduce binary size if err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch {
if err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch && err != dns.ErrEmptyResponse && dns.RCodeFromError(err) != 5 {
return nil, err return nil, err
} }
} }

View File

@@ -13,7 +13,6 @@ import (
_ "github.com/xtls/xray-core/app/proxyman/outbound" _ "github.com/xtls/xray-core/app/proxyman/outbound"
"github.com/xtls/xray-core/app/router" "github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"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/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
@@ -261,7 +260,7 @@ func TestUDPServer(t *testing.T) {
IPv6Enable: true, IPv6Enable: true,
FakeEnable: false, FakeEnable: false,
}) })
if !errors.AllEqual(feature_dns.ErrEmptyResponse, errors.Cause(err)) { if err != feature_dns.ErrEmptyResponse {
t.Fatal("error: ", err) t.Fatal("error: ", err)
} }
if len(ips) != 0 { if len(ips) != 0 {

View File

@@ -1,22 +1,19 @@
package dns package dns
import ( import (
"context"
"encoding/binary" "encoding/binary"
"strings" "strings"
"time" "time"
"golang.org/x/net/dns/dnsmessage"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/core"
dns_feature "github.com/xtls/xray-core/features/dns" dns_feature "github.com/xtls/xray-core/features/dns"
"golang.org/x/net/dns/dnsmessage"
) )
// Fqdn normalizes domain make sure it ends with '.' // Fqdn normalize domain make sure it ends with '.'
func Fqdn(domain string) string { func Fqdn(domain string) string {
if len(domain) > 0 && strings.HasSuffix(domain, ".") { if len(domain) > 0 && strings.HasSuffix(domain, ".") {
return domain return domain
@@ -166,7 +163,7 @@ func buildReqMsgs(domain string, option dns_feature.IPOption, reqIDGen func() ui
return reqs return reqs
} }
// parseResponse parses DNS answers from the returned payload // parseResponse parse DNS answers from the returned payload
func parseResponse(payload []byte) (*IPRecord, error) { func parseResponse(payload []byte) (*IPRecord, error) {
var parser dnsmessage.Parser var parser dnsmessage.Parser
h, err := parser.Start(payload) h, err := parser.Start(payload)
@@ -181,7 +178,7 @@ func parseResponse(payload []byte) (*IPRecord, error) {
ipRecord := &IPRecord{ ipRecord := &IPRecord{
ReqID: h.ID, ReqID: h.ID,
RCode: h.RCode, RCode: h.RCode,
Expire: now.Add(time.Second * 600), Expire: now.Add(time.Minute * 30),
} }
L: L:
@@ -229,19 +226,3 @@ L:
return ipRecord, nil return ipRecord, nil
} }
// toDnsContext create a new background context with parent inbound, session and dns log
func toDnsContext(ctx context.Context, addr string) context.Context {
dnsCtx := core.ToBackgroundDetachedContext(ctx)
if inbound := session.InboundFromContext(ctx); inbound != nil {
dnsCtx = session.ContextWithInbound(dnsCtx, inbound)
}
dnsCtx = session.ContextWithContent(dnsCtx, session.ContentFromContext(ctx))
dnsCtx = log.ContextWithAccessMessage(dnsCtx, &log.AccessMessage{
From: "DNS",
To: addr,
Status: log.AccessAccepted,
Reason: "",
})
return dnsCtx
}

View File

@@ -7,10 +7,11 @@ import (
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/miekg/dns" "github.com/miekg/dns"
"golang.org/x/net/dns/dnsmessage"
"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"
dns_feature "github.com/xtls/xray-core/features/dns" dns_feature "github.com/xtls/xray-core/features/dns"
"golang.org/x/net/dns/dnsmessage"
) )
func Test_parseResponse(t *testing.T) { func Test_parseResponse(t *testing.T) {

View File

@@ -5,7 +5,6 @@ import (
"math" "math"
"math/big" "math/big"
gonet "net" gonet "net"
"sync"
"time" "time"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
@@ -17,7 +16,6 @@ import (
type Holder struct { type Holder struct {
domainToIP cache.Lru domainToIP cache.Lru
ipRange *gonet.IPNet ipRange *gonet.IPNet
mu *sync.Mutex
config *FakeDnsPool config *FakeDnsPool
} }
@@ -51,7 +49,6 @@ func (fkdns *Holder) Start() error {
func (fkdns *Holder) Close() error { func (fkdns *Holder) Close() error {
fkdns.domainToIP = nil fkdns.domainToIP = nil
fkdns.ipRange = nil fkdns.ipRange = nil
fkdns.mu = nil
return nil return nil
} }
@@ -70,7 +67,7 @@ func NewFakeDNSHolder() (*Holder, error) {
} }
func NewFakeDNSHolderConfigOnly(conf *FakeDnsPool) (*Holder, error) { func NewFakeDNSHolderConfigOnly(conf *FakeDnsPool) (*Holder, error) {
return &Holder{nil, nil, nil, conf}, nil return &Holder{nil, nil, conf}, nil
} }
func (fkdns *Holder) initializeFromConfig() error { func (fkdns *Holder) initializeFromConfig() error {
@@ -92,14 +89,11 @@ func (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error {
} }
fkdns.domainToIP = cache.NewLru(lruSize) fkdns.domainToIP = cache.NewLru(lruSize)
fkdns.ipRange = ipRange fkdns.ipRange = ipRange
fkdns.mu = new(sync.Mutex)
return nil return nil
} }
// GetFakeIPForDomain checks and generates a fake IP for a domain name // GetFakeIPForDomain check and generate a fake IP for a domain name
func (fkdns *Holder) GetFakeIPForDomain(domain string) []net.Address { func (fkdns *Holder) GetFakeIPForDomain(domain string) []net.Address {
fkdns.mu.Lock()
defer fkdns.mu.Unlock()
if v, ok := fkdns.domainToIP.Get(domain); ok { if v, ok := fkdns.domainToIP.Get(domain); ok {
return []net.Address{v.(net.Address)} return []net.Address{v.(net.Address)}
} }
@@ -129,7 +123,7 @@ func (fkdns *Holder) GetFakeIPForDomain(domain string) []net.Address {
return []net.Address{ip} return []net.Address{ip}
} }
// GetDomainFromFakeDNS checks if an IP is a fake IP and have corresponding domain name // GetDomainFromFakeDNS check if an IP is a fake IP and have corresponding domain name
func (fkdns *Holder) GetDomainFromFakeDNS(ip net.Address) string { func (fkdns *Holder) GetDomainFromFakeDNS(ip net.Address) string {
if !ip.Family().IsIP() || !fkdns.ipRange.Contains(ip.IP()) { if !ip.Family().IsIP() || !fkdns.ipRange.Contains(ip.IP()) {
return "" return ""

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.27.1
// protoc v4.23.1 // protoc v3.18.0
// source: app/dns/fakedns/fakedns.proto // source: app/dns/fakedns/fakedns.proto
package fakedns package fakedns

View File

@@ -1,16 +1,16 @@
package fakedns package fakedns
import ( import (
gonet "net"
"strconv"
"testing" "testing"
gonet "net"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"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/uuid" "github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
"golang.org/x/sync/errgroup"
) )
var ipPrefix = "198.1" var ipPrefix = "198.1"
@@ -67,31 +67,6 @@ func TestFakeDnsHolderCreateMappingManySingleDomain(t *testing.T) {
assert.Equal(t, addr[0].IP().String(), addr2[0].IP().String()) assert.Equal(t, addr[0].IP().String(), addr2[0].IP().String())
} }
func TestGetFakeIPForDomainConcurrently(t *testing.T) {
fkdns, err := NewFakeDNSHolder()
common.Must(err)
total := 200
addr := make([][]net.Address, total)
var errg errgroup.Group
for i := 0; i < total; i++ {
errg.Go(testGetFakeIP(i, addr, fkdns))
}
errg.Wait()
for i := 0; i < total; i++ {
for j := i + 1; j < total; j++ {
assert.NotEqual(t, addr[i][0].IP().String(), addr[j][0].IP().String())
}
}
}
func testGetFakeIP(index int, addr [][]net.Address, fkdns *Holder) func() error {
return func() error {
addr[index] = fkdns.GetFakeIPForDomain("fakednstest" + strconv.Itoa(index) + ".example.com")
return nil
}
}
func TestFakeDnsHolderCreateMappingAndRollOver(t *testing.T) { func TestFakeDnsHolderCreateMappingAndRollOver(t *testing.T) {
fkdns, err := NewFakeDNSHolderConfigOnly(&FakeDnsPool{ fkdns, err := NewFakeDNSHolderConfigOnly(&FakeDnsPool{
IpPool: dns.FakeIPv4Pool, IpPool: dns.FakeIPv4Pool,
@@ -173,31 +148,31 @@ func TestFakeDNSMulti(t *testing.T) {
}) })
t.Run("allocateTwoAddressForTwoPool", func(t *testing.T) { t.Run("allocateTwoAddressForTwoPool", func(t *testing.T) {
address := fakeMulti.GetFakeIPForDomain("fakednstest.example.com") address := fakeMulti.GetFakeIPForDomain("fakednstest.v2fly.org")
assert.Len(t, address, 2, "should be 2 address one for each pool") assert.Len(t, address, 2, "should be 2 address one for each pool")
t.Run("eachOfThemShouldResolve:0", func(t *testing.T) { t.Run("eachOfThemShouldResolve:0", func(t *testing.T) {
domain := fakeMulti.GetDomainFromFakeDNS(address[0]) domain := fakeMulti.GetDomainFromFakeDNS(address[0])
assert.Equal(t, "fakednstest.example.com", domain) assert.Equal(t, "fakednstest.v2fly.org", domain)
}) })
t.Run("eachOfThemShouldResolve:1", func(t *testing.T) { t.Run("eachOfThemShouldResolve:1", func(t *testing.T) {
domain := fakeMulti.GetDomainFromFakeDNS(address[1]) domain := fakeMulti.GetDomainFromFakeDNS(address[1])
assert.Equal(t, "fakednstest.example.com", domain) assert.Equal(t, "fakednstest.v2fly.org", domain)
}) })
}) })
t.Run("understandIPTypeSelector", func(t *testing.T) { t.Run("understandIPTypeSelector", func(t *testing.T) {
t.Run("ipv4", func(t *testing.T) { t.Run("ipv4", func(t *testing.T) {
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv4.example.com", true, false) address := fakeMulti.GetFakeIPForDomain3("fakednstestipv4.v2fly.org", true, false)
assert.Len(t, address, 1, "should be 1 address") assert.Len(t, address, 1, "should be 1 address")
assert.True(t, address[0].Family().IsIPv4()) assert.True(t, address[0].Family().IsIPv4())
}) })
t.Run("ipv6", func(t *testing.T) { t.Run("ipv6", func(t *testing.T) {
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv6.example.com", false, true) address := fakeMulti.GetFakeIPForDomain3("fakednstestipv6.v2fly.org", false, true)
assert.Len(t, address, 1, "should be 1 address") assert.Len(t, address, 1, "should be 1 address")
assert.True(t, address[0].Family().IsIPv6()) assert.True(t, address[0].Family().IsIPv6())
}) })
t.Run("ipv46", func(t *testing.T) { t.Run("ipv46", func(t *testing.T) {
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv46.example.com", true, true) address := fakeMulti.GetFakeIPForDomain3("fakednstestipv46.v2fly.org", true, true)
assert.Len(t, address, 2, "should be 2 address") assert.Len(t, address, 2, "should be 2 address")
assert.True(t, address[0].Family().IsIPv4()) assert.True(t, address[0].Family().IsIPv4())
assert.True(t, address[1].Family().IsIPv6()) assert.True(t, address[1].Family().IsIPv6())

View File

@@ -35,7 +35,7 @@ type Client struct {
var errExpectedIPNonMatch = errors.New("expectIPs not match") var errExpectedIPNonMatch = errors.New("expectIPs not match")
// NewServer creates a name server object according to the network destination url. // NewServer creates a name server object according to the network destination url.
func NewServer(dest net.Destination, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (Server, error) { func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, error) {
if address := dest.Address; address.Family().IsDomain() { if address := dest.Address; address.Family().IsDomain() {
u, err := url.Parse(address.Domain()) u, err := url.Parse(address.Domain())
if err != nil { if err != nil {
@@ -45,15 +45,15 @@ func NewServer(dest net.Destination, dispatcher routing.Dispatcher, queryStrateg
case strings.EqualFold(u.String(), "localhost"): case strings.EqualFold(u.String(), "localhost"):
return NewLocalNameServer(), nil return NewLocalNameServer(), nil
case strings.EqualFold(u.Scheme, "https"): // DOH Remote mode case strings.EqualFold(u.Scheme, "https"): // DOH Remote mode
return NewDoHNameServer(u, dispatcher, queryStrategy) return NewDoHNameServer(u, dispatcher)
case strings.EqualFold(u.Scheme, "https+local"): // DOH Local mode case strings.EqualFold(u.Scheme, "https+local"): // DOH Local mode
return NewDoHLocalNameServer(u, queryStrategy), nil return NewDoHLocalNameServer(u), nil
case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode
return NewQUICNameServer(u, queryStrategy) return NewQUICNameServer(u)
case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode
return NewTCPNameServer(u, dispatcher, queryStrategy) return NewTCPNameServer(u, dispatcher)
case strings.EqualFold(u.Scheme, "tcp+local"): // DNS-over-TCP Local mode case strings.EqualFold(u.Scheme, "tcp+local"): // DNS-over-TCP Local mode
return NewTCPLocalNameServer(u, queryStrategy) return NewTCPLocalNameServer(u)
case strings.EqualFold(u.String(), "fakedns"): case strings.EqualFold(u.String(), "fakedns"):
return NewFakeDNSServer(), nil return NewFakeDNSServer(), nil
} }
@@ -68,19 +68,12 @@ func NewServer(dest net.Destination, dispatcher routing.Dispatcher, queryStrateg
} }
// NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs. // NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
func NewClient( func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container router.GeoIPMatcherContainer, matcherInfos *[]*DomainMatcherInfo, updateDomainRule func(strmatcher.Matcher, int, []*DomainMatcherInfo) error) (*Client, error) {
ctx context.Context,
ns *NameServer,
clientIP net.IP,
container router.GeoIPMatcherContainer,
matcherInfos *[]*DomainMatcherInfo,
updateDomainRule func(strmatcher.Matcher, int, []*DomainMatcherInfo) error,
) (*Client, error) {
client := &Client{} client := &Client{}
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error { err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
// Create a new server for each client for now // Create a new server for each client for now
server, err := NewServer(ns.Address.AsDestination(), dispatcher, ns.GetQueryStrategy()) server, err := NewServer(ns.Address.AsDestination(), dispatcher)
if err != nil { if err != nil {
return newError("failed to create nameserver").Base(err).AtWarning() return newError("failed to create nameserver").Base(err).AtWarning()
} }
@@ -167,7 +160,7 @@ func NewClient(
func NewSimpleClient(ctx context.Context, endpoint *net.Endpoint, clientIP net.IP) (*Client, error) { func NewSimpleClient(ctx context.Context, endpoint *net.Endpoint, clientIP net.IP) (*Client, error) {
client := &Client{} client := &Client{}
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error { err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
server, err := NewServer(endpoint.AsDestination(), dispatcher, QueryStrategy_USE_IP) server, err := NewServer(endpoint.AsDestination(), dispatcher)
if err != nil { if err != nil {
return newError("failed to create nameserver").Base(err).AtWarning() return newError("failed to create nameserver").Base(err).AtWarning()
} }
@@ -193,7 +186,7 @@ func (c *Client) Name() string {
return c.server.Name() return c.server.Name()
} }
// QueryIP sends DNS query to the name server with the client's IP. // QueryIP send DNS query to the name server with the client's IP.
func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption, disableCache bool) ([]net.IP, error) { func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption, disableCache bool) ([]net.IP, error) {
ctx, cancel := context.WithTimeout(ctx, 4*time.Second) ctx, cancel := context.WithTimeout(ctx, 4*time.Second)
ips, err := c.server.QueryIP(ctx, domain, c.clientIP, option, disableCache) ips, err := c.server.QueryIP(ctx, domain, c.clientIP, option, disableCache)
@@ -225,24 +218,3 @@ func (c *Client) MatchExpectedIPs(domain string, ips []net.IP) ([]net.IP, error)
newError("domain ", domain, " expectIPs ", newIps, " matched at server ", c.Name()).AtDebug().WriteToLog() newError("domain ", domain, " expectIPs ", newIps, " matched at server ", c.Name()).AtDebug().WriteToLog()
return newIps, nil return newIps, nil
} }
func ResolveIpOptionOverride(queryStrategy QueryStrategy, ipOption dns.IPOption) dns.IPOption {
switch queryStrategy {
case QueryStrategy_USE_IP:
return ipOption
case QueryStrategy_USE_IP4:
return dns.IPOption{
IPv4Enable: ipOption.IPv4Enable,
IPv6Enable: false,
FakeEnable: false,
}
case QueryStrategy_USE_IP6:
return dns.IPOption{
IPv4Enable: false,
IPv6Enable: ipOption.IPv6Enable,
FakeEnable: false,
}
default:
return ipOption
}
}

View File

@@ -11,6 +11,8 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"golang.org/x/net/dns/dnsmessage"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
@@ -22,7 +24,6 @@ import (
dns_feature "github.com/xtls/xray-core/features/dns" dns_feature "github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"golang.org/x/net/dns/dnsmessage"
) )
// DoHNameServer implemented DNS over HTTPS (RFC8484) Wire Format, // DoHNameServer implemented DNS over HTTPS (RFC8484) Wire Format,
@@ -31,20 +32,19 @@ import (
type DoHNameServer struct { type DoHNameServer struct {
dispatcher routing.Dispatcher dispatcher routing.Dispatcher
sync.RWMutex sync.RWMutex
ips map[string]*record ips map[string]*record
pub *pubsub.Service pub *pubsub.Service
cleanup *task.Periodic cleanup *task.Periodic
reqID uint32 reqID uint32
httpClient *http.Client httpClient *http.Client
dohURL string dohURL string
name string name string
queryStrategy QueryStrategy
} }
// NewDoHNameServer creates DOH server object for remote resolving. // NewDoHNameServer creates DOH server object for remote resolving.
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (*DoHNameServer, error) { func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher) (*DoHNameServer, error) {
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", queryStrategy) s := baseDOHNameServer(url, "DOH")
s.dispatcher = dispatcher s.dispatcher = dispatcher
tr := &http.Transport{ tr := &http.Transport{
@@ -53,11 +53,23 @@ func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy
TLSHandshakeTimeout: 30 * time.Second, TLSHandshakeTimeout: 30 * time.Second,
ForceAttemptHTTP2: true, ForceAttemptHTTP2: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dispatcherCtx := context.Background()
dest, err := net.ParseDestination(network + ":" + addr) dest, err := net.ParseDestination(network + ":" + addr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
link, err := s.dispatcher.Dispatch(toDnsContext(ctx, s.dohURL), dest)
dispatcherCtx = session.ContextWithContent(dispatcherCtx, session.ContentFromContext(ctx))
dispatcherCtx = session.ContextWithInbound(dispatcherCtx, session.InboundFromContext(ctx))
dispatcherCtx = log.ContextWithAccessMessage(dispatcherCtx, &log.AccessMessage{
From: "DoH",
To: s.dohURL,
Status: log.AccessAccepted,
Reason: "",
})
link, err := s.dispatcher.Dispatch(dispatcherCtx, dest)
select { select {
case <-ctx.Done(): case <-ctx.Done():
return nil, ctx.Err() return nil, ctx.Err()
@@ -91,9 +103,9 @@ func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy
} }
// NewDoHLocalNameServer creates DOH client object for local resolving // NewDoHLocalNameServer creates DOH client object for local resolving
func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameServer { func NewDoHLocalNameServer(url *url.URL) *DoHNameServer {
url.Scheme = "https" url.Scheme = "https"
s := baseDOHNameServer(url, "DOHL", queryStrategy) s := baseDOHNameServer(url, "DOHL")
tr := &http.Transport{ tr := &http.Transport{
IdleConnTimeout: 90 * time.Second, IdleConnTimeout: 90 * time.Second,
ForceAttemptHTTP2: true, ForceAttemptHTTP2: true,
@@ -102,9 +114,9 @@ func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameSe
if err != nil { if err != nil {
return nil, err return nil, err
} }
conn, err := internet.DialSystem(ctx, dest, nil) conn, err := internet.DialSystemDNS(ctx, dest, nil)
log.Record(&log.AccessMessage{ log.Record(&log.AccessMessage{
From: "DNS", From: "DoH",
To: s.dohURL, To: s.dohURL,
Status: log.AccessAccepted, Status: log.AccessAccepted,
Detour: "local", Detour: "local",
@@ -123,13 +135,12 @@ func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameSe
return s return s
} }
func baseDOHNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) *DoHNameServer { func baseDOHNameServer(url *url.URL, prefix string) *DoHNameServer {
s := &DoHNameServer{ s := &DoHNameServer{
ips: make(map[string]*record), ips: make(map[string]*record),
pub: pubsub.NewService(), pub: pubsub.NewService(),
name: prefix + "//" + url.Host, name: prefix + "//" + url.Host,
dohURL: url.String(), dohURL: url.String(),
queryStrategy: queryStrategy,
} }
s.cleanup = &task.Periodic{ s.cleanup = &task.Periodic{
Interval: time.Minute, Interval: time.Minute,
@@ -355,10 +366,6 @@ func (s *DoHNameServer) findIPsForDomain(domain string, option dns_feature.IPOpt
// QueryIP implements Server. // QueryIP implements Server.
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) { // nolint: dupl func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) { // nolint: dupl
fqdn := Fqdn(domain) fqdn := Fqdn(domain)
option = ResolveIpOptionOverride(s.queryStrategy, option)
if !option.IPv4Enable && !option.IPv6Enable {
return nil, dns_feature.ErrEmptyResponse
}
if disableCache { if disableCache {
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog() newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()

View File

@@ -7,6 +7,7 @@ import (
"time" "time"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
. "github.com/xtls/xray-core/app/dns" . "github.com/xtls/xray-core/app/dns"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
@@ -17,7 +18,7 @@ func TestDOHNameServer(t *testing.T) {
url, err := url.Parse("https+local://1.1.1.1/dns-query") url, err := url.Parse("https+local://1.1.1.1/dns-query")
common.Must(err) common.Must(err)
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP) s := NewDoHLocalNameServer(url)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
IPv4Enable: true, IPv4Enable: true,
@@ -34,7 +35,7 @@ func TestDOHNameServerWithCache(t *testing.T) {
url, err := url.Parse("https+local://1.1.1.1/dns-query") url, err := url.Parse("https+local://1.1.1.1/dns-query")
common.Must(err) common.Must(err)
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP) s := NewDoHLocalNameServer(url)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
IPv4Enable: true, IPv4Enable: true,
@@ -57,49 +58,3 @@ func TestDOHNameServerWithCache(t *testing.T) {
t.Fatal(r) t.Fatal(r)
} }
} }
func TestDOHNameServerWithIPv4Override(t *testing.T) {
url, err := url.Parse("https+local://1.1.1.1/dns-query")
common.Must(err)
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP4)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
IPv4Enable: true,
IPv6Enable: true,
}, false)
cancel()
common.Must(err)
if len(ips) == 0 {
t.Error("expect some ips, but got 0")
}
for _, ip := range ips {
if len(ip) != net.IPv4len {
t.Error("expect only IPv4 response from DNS query")
}
}
}
func TestDOHNameServerWithIPv6Override(t *testing.T) {
url, err := url.Parse("https+local://1.1.1.1/dns-query")
common.Must(err)
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP6)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
IPv4Enable: true,
IPv6Enable: true,
}, false)
cancel()
common.Must(err)
if len(ips) == 0 {
t.Error("expect some ips, but got 0")
}
for _, ip := range ips {
if len(ip) != net.IPv6len {
t.Error("expect only IPv6 response from DNS query")
}
}
}

View File

@@ -3,11 +3,10 @@ package dns
import ( import (
"context" "context"
"strings" "strings"
"time"
"github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/dns/localdns" "github.com/xtls/xray-core/features/dns/localdns"
) )
@@ -20,7 +19,6 @@ const errEmptyResponse = "No address associated with hostname"
// QueryIP implements Server. // QueryIP implements Server.
func (s *LocalNameServer) QueryIP(_ context.Context, domain string, _ net.IP, option dns.IPOption, _ bool) (ips []net.IP, err error) { func (s *LocalNameServer) QueryIP(_ context.Context, domain string, _ net.IP, option dns.IPOption, _ bool) (ips []net.IP, err error) {
start := time.Now()
ips, err = s.client.LookupIP(domain, option) ips, err = s.client.LookupIP(domain, option)
if err != nil && strings.HasSuffix(err.Error(), errEmptyResponse) { if err != nil && strings.HasSuffix(err.Error(), errEmptyResponse) {
@@ -29,7 +27,6 @@ func (s *LocalNameServer) QueryIP(_ context.Context, domain string, _ net.IP, op
if len(ips) > 0 { if len(ips) > 0 {
newError("Localhost got answer: ", domain, " -> ", ips).AtInfo().WriteToLog() newError("Localhost got answer: ", domain, " -> ", ips).AtInfo().WriteToLog()
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
} }
return return

View File

@@ -5,9 +5,10 @@ import (
"testing" "testing"
"time" "time"
"github.com/xtls/xray-core/common/net"
. "github.com/xtls/xray-core/app/dns" . "github.com/xtls/xray-core/app/dns"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
) )

View File

@@ -1,18 +1,15 @@
package dns package dns
import ( import (
"bytes"
"context" "context"
"encoding/binary"
"net/url" "net/url"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/quic-go/quic-go" "github.com/lucas-clemente/quic-go"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"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"
@@ -26,29 +23,28 @@ import (
// NextProtoDQ - During connection establishment, DNS/QUIC support is indicated // NextProtoDQ - During connection establishment, DNS/QUIC support is indicated
// by selecting the ALPN token "dq" in the crypto handshake. // by selecting the ALPN token "dq" in the crypto handshake.
const NextProtoDQ = "doq" const NextProtoDQ = "doq-i00"
const handshakeTimeout = time.Second * 8 const handshakeTimeout = time.Second * 8
// QUICNameServer implemented DNS over QUIC // QUICNameServer implemented DNS over QUIC
type QUICNameServer struct { type QUICNameServer struct {
sync.RWMutex sync.RWMutex
ips map[string]*record ips map[string]*record
pub *pubsub.Service pub *pubsub.Service
cleanup *task.Periodic cleanup *task.Periodic
reqID uint32 reqID uint32
name string name string
destination *net.Destination destination *net.Destination
connection quic.Connection session quic.Session
queryStrategy QueryStrategy
} }
// NewQUICNameServer creates DNS-over-QUIC client object for local resolving // NewQUICNameServer creates DNS-over-QUIC client object for local resolving
func NewQUICNameServer(url *url.URL, queryStrategy QueryStrategy) (*QUICNameServer, error) { func NewQUICNameServer(url *url.URL) (*QUICNameServer, error) {
newError("DNS: created Local DNS-over-QUIC client for ", url.String()).AtInfo().WriteToLog() newError("DNS: created Local DNS-over-QUIC client for ", url.String()).AtInfo().WriteToLog()
var err error var err error
port := net.Port(853) port := net.Port(784)
if url.Port() != "" { if url.Port() != "" {
port, err = net.PortFromString(url.Port()) port, err = net.PortFromString(url.Port())
if err != nil { if err != nil {
@@ -58,11 +54,10 @@ func NewQUICNameServer(url *url.URL, queryStrategy QueryStrategy) (*QUICNameServ
dest := net.UDPDestination(net.ParseAddress(url.Hostname()), port) dest := net.UDPDestination(net.ParseAddress(url.Hostname()), port)
s := &QUICNameServer{ s := &QUICNameServer{
ips: make(map[string]*record), ips: make(map[string]*record),
pub: pubsub.NewService(), pub: pubsub.NewService(),
name: url.String(), name: url.String(),
destination: &dest, destination: &dest,
queryStrategy: queryStrategy,
} }
s.cleanup = &task.Periodic{ s.cleanup = &task.Periodic{
Interval: time.Minute, Interval: time.Minute,
@@ -196,18 +191,13 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP
return return
} }
dnsReqBuf := buf.New()
binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
dnsReqBuf.Write(b.Bytes())
b.Release()
conn, err := s.openStream(dnsCtx) conn, err := s.openStream(dnsCtx)
if err != nil { if err != nil {
newError("failed to open quic connection").Base(err).AtError().WriteToLog() newError("failed to open quic session").Base(err).AtError().WriteToLog()
return return
} }
_, err = conn.Write(dnsReqBuf.Bytes()) _, err = conn.Write(b.Bytes())
if err != nil { if err != nil {
newError("failed to send query").Base(err).AtError().WriteToLog() newError("failed to send query").Base(err).AtError().WriteToLog()
return return
@@ -217,21 +207,9 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP
respBuf := buf.New() respBuf := buf.New()
defer respBuf.Release() defer respBuf.Release()
n, err := respBuf.ReadFullFrom(conn, 2) n, err := respBuf.ReadFrom(conn)
if err != nil && n == 0 { if err != nil && n == 0 {
newError("failed to read response length").Base(err).AtError().WriteToLog() newError("failed to read response").Base(err).AtError().WriteToLog()
return
}
var length int16
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
if err != nil {
newError("failed to parse response length").Base(err).AtError().WriteToLog()
return
}
respBuf.Clear()
n, err = respBuf.ReadFullFrom(conn, int32(length))
if err != nil && n == 0 {
newError("failed to read response length").Base(err).AtError().WriteToLog()
return return
} }
@@ -290,10 +268,6 @@ func (s *QUICNameServer) findIPsForDomain(domain string, option dns_feature.IPOp
// QueryIP is called from dns.Server->queryIPTimeout // QueryIP is called from dns.Server->queryIPTimeout
func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) { func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
fqdn := Fqdn(domain) fqdn := Fqdn(domain)
option = ResolveIpOptionOverride(s.queryStrategy, option)
if !option.IPv4Enable && !option.IPv6Enable {
return nil, dns_feature.ErrEmptyResponse
}
if disableCache { if disableCache {
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog() newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
@@ -301,7 +275,6 @@ func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP ne
ips, err := s.findIPsForDomain(fqdn, option) ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound { if err != errRecordNotFound {
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog() newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
return ips, err return ips, err
} }
} }
@@ -333,12 +306,10 @@ func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP ne
close(done) close(done)
}() }()
s.sendQuery(ctx, fqdn, clientIP, option) s.sendQuery(ctx, fqdn, clientIP, option)
start := time.Now()
for { for {
ips, err := s.findIPsForDomain(fqdn, option) ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound { if err != errRecordNotFound {
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
return ips, err return ips, err
} }
@@ -350,7 +321,7 @@ func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP ne
} }
} }
func isActive(s quic.Connection) bool { func isActive(s quic.Session) bool {
select { select {
case <-s.Context().Done(): case <-s.Context().Done():
return false return false
@@ -359,17 +330,17 @@ func isActive(s quic.Connection) bool {
} }
} }
func (s *QUICNameServer) getConnection() (quic.Connection, error) { func (s *QUICNameServer) getSession() (quic.Session, error) {
var conn quic.Connection var session quic.Session
s.RLock() s.RLock()
conn = s.connection session = s.session
if conn != nil && isActive(conn) { if session != nil && isActive(session) {
s.RUnlock() s.RUnlock()
return conn, nil return session, nil
} }
if conn != nil { if session != nil {
// we're recreating the connection, let's create a new one // we're recreating the session, let's create a new one
_ = conn.CloseWithError(0, "") _ = session.CloseWithError(0, "")
} }
s.RUnlock() s.RUnlock()
@@ -377,48 +348,42 @@ func (s *QUICNameServer) getConnection() (quic.Connection, error) {
defer s.Unlock() defer s.Unlock()
var err error var err error
conn, err = s.openConnection() session, err = s.openSession()
if err != nil { if err != nil {
// This does not look too nice, but QUIC (or maybe quic-go) // This does not look too nice, but QUIC (or maybe quic-go)
// doesn't seem stable enough. // doesn't seem stable enough.
// Maybe retransmissions aren't fully implemented in quic-go? // Maybe retransmissions aren't fully implemented in quic-go?
// Anyways, the simple solution is to make a second try when // Anyways, the simple solution is to make a second try when
// it fails to open the QUIC connection. // it fails to open the QUIC session.
conn, err = s.openConnection() session, err = s.openSession()
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
s.connection = conn s.session = session
return conn, nil return session, nil
} }
func (s *QUICNameServer) openConnection() (quic.Connection, error) { func (s *QUICNameServer) openSession() (quic.Session, error) {
tlsConfig := tls.Config{} tlsConfig := tls.Config{}
quicConfig := &quic.Config{ quicConfig := &quic.Config{
HandshakeIdleTimeout: handshakeTimeout, HandshakeIdleTimeout: handshakeTimeout,
} }
tlsConfig.ServerName = s.destination.Address.String()
conn, err := quic.DialAddr(context.Background(), s.destination.NetAddr(), tlsConfig.GetTLSConfig(tls.WithNextProto("http/1.1", http2.NextProtoTLS, NextProtoDQ)), quicConfig) session, err := quic.DialAddrContext(context.Background(), s.destination.NetAddr(), tlsConfig.GetTLSConfig(tls.WithNextProto("http/1.1", http2.NextProtoTLS, NextProtoDQ)), quicConfig)
log.Record(&log.AccessMessage{
From: "DNS",
To: s.destination,
Status: log.AccessAccepted,
Detour: "local",
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return conn, nil return session, nil
} }
func (s *QUICNameServer) openStream(ctx context.Context) (quic.Stream, error) { func (s *QUICNameServer) openStream(ctx context.Context) (quic.Stream, error) {
conn, err := s.getConnection() session, err := s.getSession()
if err != nil { if err != nil {
return nil, err return nil, err
} }
// open a new stream // open a new stream
return conn.OpenStreamSync(ctx) return session.OpenStreamSync(ctx)
} }

View File

@@ -6,17 +6,19 @@ import (
"testing" "testing"
"time" "time"
"github.com/xtls/xray-core/features/dns"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
. "github.com/xtls/xray-core/app/dns" . "github.com/xtls/xray-core/app/dns"
"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/features/dns"
) )
func TestQUICNameServer(t *testing.T) { func TestQUICNameServer(t *testing.T) {
url, err := url.Parse("quic://dns.adguard.com") url, err := url.Parse("quic://dns.adguard.com")
common.Must(err) common.Must(err)
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP) s, err := NewQUICNameServer(url)
common.Must(err) common.Must(err)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{ ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
@@ -40,49 +42,3 @@ func TestQUICNameServer(t *testing.T) {
t.Fatal(r) t.Fatal(r)
} }
} }
func TestQUICNameServerWithIPv4Override(t *testing.T) {
url, err := url.Parse("quic://dns.adguard.com")
common.Must(err)
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP4)
common.Must(err)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
}, false)
cancel()
common.Must(err)
if len(ips) == 0 {
t.Error("expect some ips, but got 0")
}
for _, ip := range ips {
if len(ip) != net.IPv4len {
t.Error("expect only IPv4 response from DNS query")
}
}
}
func TestQUICNameServerWithIPv6Override(t *testing.T) {
url, err := url.Parse("quic://dns.adguard.com")
common.Must(err)
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP6)
common.Must(err)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
}, false)
cancel()
common.Must(err)
if len(ips) == 0 {
t.Error("expect some ips, but got 0")
}
for _, ip := range ips {
if len(ip) != net.IPv6len {
t.Error("expect only IPv6 response from DNS query")
}
}
}

View File

@@ -9,9 +9,10 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"golang.org/x/net/dns/dnsmessage"
"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/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc" "github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/protocol/dns" "github.com/xtls/xray-core/common/protocol/dns"
@@ -21,35 +22,29 @@ import (
dns_feature "github.com/xtls/xray-core/features/dns" dns_feature "github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"golang.org/x/net/dns/dnsmessage"
) )
// TCPNameServer implemented DNS over TCP (RFC7766). // TCPNameServer implemented DNS over TCP (RFC7766).
type TCPNameServer struct { type TCPNameServer struct {
sync.RWMutex sync.RWMutex
name string name string
destination *net.Destination destination *net.Destination
ips map[string]*record ips map[string]*record
pub *pubsub.Service pub *pubsub.Service
cleanup *task.Periodic cleanup *task.Periodic
reqID uint32 reqID uint32
dial func(context.Context) (net.Conn, error) dial func(context.Context) (net.Conn, error)
queryStrategy QueryStrategy
} }
// NewTCPNameServer creates DNS over TCP server object for remote resolving. // NewTCPNameServer creates DNS over TCP server object for remote resolving.
func NewTCPNameServer( func NewTCPNameServer(url *url.URL, dispatcher routing.Dispatcher) (*TCPNameServer, error) {
url *url.URL, s, err := baseTCPNameServer(url, "TCP")
dispatcher routing.Dispatcher,
queryStrategy QueryStrategy,
) (*TCPNameServer, error) {
s, err := baseTCPNameServer(url, "TCP", queryStrategy)
if err != nil { if err != nil {
return nil, err return nil, err
} }
s.dial = func(ctx context.Context) (net.Conn, error) { s.dial = func(ctx context.Context) (net.Conn, error) {
link, err := dispatcher.Dispatch(toDnsContext(ctx, s.destination.String()), *s.destination) link, err := dispatcher.Dispatch(ctx, *s.destination)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -64,8 +59,8 @@ func NewTCPNameServer(
} }
// NewTCPLocalNameServer creates DNS over TCP client object for local resolving // NewTCPLocalNameServer creates DNS over TCP client object for local resolving
func NewTCPLocalNameServer(url *url.URL, queryStrategy QueryStrategy) (*TCPNameServer, error) { func NewTCPLocalNameServer(url *url.URL) (*TCPNameServer, error) {
s, err := baseTCPNameServer(url, "TCPL", queryStrategy) s, err := baseTCPNameServer(url, "TCPL")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -77,22 +72,22 @@ func NewTCPLocalNameServer(url *url.URL, queryStrategy QueryStrategy) (*TCPNameS
return s, nil return s, nil
} }
func baseTCPNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) (*TCPNameServer, error) { func baseTCPNameServer(url *url.URL, prefix string) (*TCPNameServer, error) {
var err error
port := net.Port(53) port := net.Port(53)
if url.Port() != "" { if url.Port() != "" {
var err error port, err = net.PortFromString(url.Port())
if port, err = net.PortFromString(url.Port()); err != nil { if err != nil {
return nil, err return nil, err
} }
} }
dest := net.TCPDestination(net.ParseAddress(url.Hostname()), port) dest := net.TCPDestination(net.ParseAddress(url.Hostname()), port)
s := &TCPNameServer{ s := &TCPNameServer{
destination: &dest, destination: &dest,
ips: make(map[string]*record), ips: make(map[string]*record),
pub: pubsub.NewService(), pub: pubsub.NewService(),
name: prefix + "//" + dest.NetAddr(), name: prefix + "//" + dest.NetAddr(),
queryStrategy: queryStrategy,
} }
s.cleanup = &task.Periodic{ s.cleanup = &task.Periodic{
Interval: time.Minute, Interval: time.Minute,
@@ -313,10 +308,6 @@ func (s *TCPNameServer) findIPsForDomain(domain string, option dns_feature.IPOpt
// QueryIP implements Server. // QueryIP implements Server.
func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) { func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
fqdn := Fqdn(domain) fqdn := Fqdn(domain)
option = ResolveIpOptionOverride(s.queryStrategy, option)
if !option.IPv4Enable && !option.IPv6Enable {
return nil, dns_feature.ErrEmptyResponse
}
if disableCache { if disableCache {
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog() newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
@@ -324,7 +315,6 @@ func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, clientIP net
ips, err := s.findIPsForDomain(fqdn, option) ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound { if err != errRecordNotFound {
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog() newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
return ips, err return ips, err
} }
} }
@@ -356,12 +346,10 @@ func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, clientIP net
close(done) close(done)
}() }()
s.sendQuery(ctx, fqdn, clientIP, option) s.sendQuery(ctx, fqdn, clientIP, option)
start := time.Now()
for { for {
ips, err := s.findIPsForDomain(fqdn, option) ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound { if err != errRecordNotFound {
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
return ips, err return ips, err
} }

View File

@@ -7,6 +7,7 @@ import (
"time" "time"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
. "github.com/xtls/xray-core/app/dns" . "github.com/xtls/xray-core/app/dns"
"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"
@@ -16,7 +17,7 @@ import (
func TestTCPLocalNameServer(t *testing.T) { func TestTCPLocalNameServer(t *testing.T) {
url, err := url.Parse("tcp+local://8.8.8.8") url, err := url.Parse("tcp+local://8.8.8.8")
common.Must(err) common.Must(err)
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP) s, err := NewTCPLocalNameServer(url)
common.Must(err) common.Must(err)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
@@ -33,7 +34,7 @@ func TestTCPLocalNameServer(t *testing.T) {
func TestTCPLocalNameServerWithCache(t *testing.T) { func TestTCPLocalNameServerWithCache(t *testing.T) {
url, err := url.Parse("tcp+local://8.8.8.8") url, err := url.Parse("tcp+local://8.8.8.8")
common.Must(err) common.Must(err)
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP) s, err := NewTCPLocalNameServer(url)
common.Must(err) common.Must(err)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
@@ -57,51 +58,3 @@ func TestTCPLocalNameServerWithCache(t *testing.T) {
t.Fatal(r) t.Fatal(r)
} }
} }
func TestTCPLocalNameServerWithIPv4Override(t *testing.T) {
url, err := url.Parse("tcp+local://8.8.8.8")
common.Must(err)
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP4)
common.Must(err)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
IPv4Enable: true,
IPv6Enable: true,
}, false)
cancel()
common.Must(err)
if len(ips) == 0 {
t.Error("expect some ips, but got 0")
}
for _, ip := range ips {
if len(ip) != net.IPv4len {
t.Error("expect only IPv4 response from DNS query")
}
}
}
func TestTCPLocalNameServerWithIPv6Override(t *testing.T) {
url, err := url.Parse("tcp+local://8.8.8.8")
common.Must(err)
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP6)
common.Must(err)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
IPv4Enable: true,
IPv6Enable: true,
}, false)
cancel()
common.Must(err)
if len(ips) == 0 {
t.Error("expect some ips, but got 0")
}
for _, ip := range ips {
if len(ip) != net.IPv6len {
t.Error("expect only IPv6 response from DNS query")
}
}
}

View File

@@ -7,6 +7,8 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"golang.org/x/net/dns/dnsmessage"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
@@ -18,7 +20,6 @@ import (
dns_feature "github.com/xtls/xray-core/features/dns" dns_feature "github.com/xtls/xray-core/features/dns"
"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"
"golang.org/x/net/dns/dnsmessage"
) )
// ClassicNameServer implemented traditional UDP DNS. // ClassicNameServer implemented traditional UDP DNS.
@@ -194,7 +195,21 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, client
for _, req := range reqs { for _, req := range reqs {
s.addPendingRequest(req) s.addPendingRequest(req)
b, _ := dns.PackMessage(req.msg) b, _ := dns.PackMessage(req.msg)
s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b) udpCtx := context.Background()
if inbound := session.InboundFromContext(ctx); inbound != nil {
udpCtx = session.ContextWithInbound(udpCtx, inbound)
}
udpCtx = session.ContextWithContent(udpCtx, &session.Content{
Protocol: "dns",
})
udpCtx = log.ContextWithAccessMessage(udpCtx, &log.AccessMessage{
From: "DNS",
To: s.address,
Status: log.AccessAccepted,
Reason: "",
})
s.udpServer.Dispatch(udpCtx, *s.address, b)
} }
} }

View File

@@ -5,10 +5,11 @@ package command
import ( import (
"context" "context"
grpc "google.golang.org/grpc"
"github.com/xtls/xray-core/app/log" "github.com/xtls/xray-core/app/log"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
grpc "google.golang.org/grpc"
) )
type LoggerServer struct { type LoggerServer struct {

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.27.1
// protoc v4.23.1 // protoc v3.18.0
// source: app/log/command/config.proto // source: app/log/command/config.proto
package command package command

View File

@@ -1,8 +1,4 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT. // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc v4.23.1
// source: app/log/command/config.proto
package command package command
@@ -18,10 +14,6 @@ import (
// Requires gRPC-Go v1.32.0 or later. // Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7 const _ = grpc.SupportPackageIsVersion7
const (
LoggerService_RestartLogger_FullMethodName = "/xray.app.log.command.LoggerService/RestartLogger"
)
// LoggerServiceClient is the client API for LoggerService service. // LoggerServiceClient is the client API for LoggerService service.
// //
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
@@ -39,7 +31,7 @@ func NewLoggerServiceClient(cc grpc.ClientConnInterface) LoggerServiceClient {
func (c *loggerServiceClient) RestartLogger(ctx context.Context, in *RestartLoggerRequest, opts ...grpc.CallOption) (*RestartLoggerResponse, error) { func (c *loggerServiceClient) RestartLogger(ctx context.Context, in *RestartLoggerRequest, opts ...grpc.CallOption) (*RestartLoggerResponse, error) {
out := new(RestartLoggerResponse) out := new(RestartLoggerResponse)
err := c.cc.Invoke(ctx, LoggerService_RestartLogger_FullMethodName, in, out, opts...) err := c.cc.Invoke(ctx, "/xray.app.log.command.LoggerService/RestartLogger", in, out, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -84,7 +76,7 @@ func _LoggerService_RestartLogger_Handler(srv interface{}, ctx context.Context,
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: LoggerService_RestartLogger_FullMethodName, FullMethod: "/xray.app.log.command.LoggerService/RestartLogger",
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(LoggerServiceServer).RestartLogger(ctx, req.(*RestartLoggerRequest)) return srv.(LoggerServiceServer).RestartLogger(ctx, req.(*RestartLoggerRequest))

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.27.1
// protoc v4.23.1 // protoc v3.18.0
// source: app/log/config.proto // source: app/log/config.proto
package log package log

View File

@@ -2,7 +2,7 @@ package log
import ( import (
"sync" "sync"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
) )

View File

@@ -5,6 +5,7 @@ import (
"testing" "testing"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/xtls/xray-core/app/log" "github.com/xtls/xray-core/app/log"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
clog "github.com/xtls/xray-core/common/log" clog "github.com/xtls/xray-core/common/log"

View File

@@ -1,149 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.33.0
// protoc v4.23.1
// source: app/metrics/config.proto
package metrics
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// Config is the settings for metrics.
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Tag of the outbound handler that handles metrics http connections.
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_metrics_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_metrics_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_metrics_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
var File_app_metrics_config_proto protoreflect.FileDescriptor
var file_app_metrics_config_proto_rawDesc = []byte{
0x0a, 0x18, 0x61, 0x70, 0x70, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x63, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x1a, 0x0a, 0x06,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x42, 0x52, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
0x50, 0x01, 0x5a, 0x25, 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, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0xaa, 0x02, 0x10, 0x58, 0x72, 0x61, 0x79,
0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_metrics_config_proto_rawDescOnce sync.Once
file_app_metrics_config_proto_rawDescData = file_app_metrics_config_proto_rawDesc
)
func file_app_metrics_config_proto_rawDescGZIP() []byte {
file_app_metrics_config_proto_rawDescOnce.Do(func() {
file_app_metrics_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_metrics_config_proto_rawDescData)
})
return file_app_metrics_config_proto_rawDescData
}
var file_app_metrics_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_app_metrics_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: xray.app.metrics.Config
}
var file_app_metrics_config_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_app_metrics_config_proto_init() }
func file_app_metrics_config_proto_init() {
if File_app_metrics_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_metrics_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_metrics_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_app_metrics_config_proto_goTypes,
DependencyIndexes: file_app_metrics_config_proto_depIdxs,
MessageInfos: file_app_metrics_config_proto_msgTypes,
}.Build()
File_app_metrics_config_proto = out.File
file_app_metrics_config_proto_rawDesc = nil
file_app_metrics_config_proto_goTypes = nil
file_app_metrics_config_proto_depIdxs = nil
}

View File

@@ -1,13 +0,0 @@
syntax = "proto3";
package xray.app.metrics;
option csharp_namespace = "Xray.App.Metrics";
option go_package = "github.com/xtls/xray-core/app/metrics";
option java_package = "com.xray.app.metrics";
option java_multiple_files = true;
// Config is the settings for metrics.
message Config {
// Tag of the outbound handler that handles metrics http connections.
string tag = 1;
}

View File

@@ -1,118 +0,0 @@
package metrics
import (
"context"
"expvar"
"net/http"
_ "net/http/pprof"
"strings"
"github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/app/stats"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/signal/done"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/extension"
"github.com/xtls/xray-core/features/outbound"
feature_stats "github.com/xtls/xray-core/features/stats"
)
type MetricsHandler struct {
ohm outbound.Manager
statsManager feature_stats.Manager
observatory extension.Observatory
tag string
}
// NewMetricsHandler creates a new MetricsHandler based on the given config.
func NewMetricsHandler(ctx context.Context, config *Config) (*MetricsHandler, error) {
c := &MetricsHandler{
tag: config.Tag,
}
common.Must(core.RequireFeatures(ctx, func(om outbound.Manager, sm feature_stats.Manager) {
c.statsManager = sm
c.ohm = om
}))
expvar.Publish("stats", expvar.Func(func() interface{} {
manager, ok := c.statsManager.(*stats.Manager)
if !ok {
return nil
}
resp := map[string]map[string]map[string]int64{
"inbound": {},
"outbound": {},
"user": {},
}
manager.VisitCounters(func(name string, counter feature_stats.Counter) bool {
nameSplit := strings.Split(name, ">>>")
typeName, tagOrUser, direction := nameSplit[0], nameSplit[1], nameSplit[3]
if item, found := resp[typeName][tagOrUser]; found {
item[direction] = counter.Value()
} else {
resp[typeName][tagOrUser] = map[string]int64{
direction: counter.Value(),
}
}
return true
})
return resp
}))
expvar.Publish("observatory", expvar.Func(func() interface{} {
if c.observatory == nil {
common.Must(core.RequireFeatures(ctx, func(observatory extension.Observatory) error {
c.observatory = observatory
return nil
}))
if c.observatory == nil {
return nil
}
}
resp := map[string]*observatory.OutboundStatus{}
if o, err := c.observatory.GetObservation(context.Background()); err != nil {
return err
} else {
for _, x := range o.(*observatory.ObservationResult).GetStatus() {
resp[x.OutboundTag] = x
}
}
return resp
}))
return c, nil
}
func (p *MetricsHandler) Type() interface{} {
return (*MetricsHandler)(nil)
}
func (p *MetricsHandler) Start() error {
listener := &OutboundListener{
buffer: make(chan net.Conn, 4),
done: done.New(),
}
go func() {
if err := http.Serve(listener, http.DefaultServeMux); err != nil {
newError("failed to start metrics server").Base(err).AtError().WriteToLog()
}
}()
if err := p.ohm.RemoveHandler(context.Background(), p.tag); err != nil {
newError("failed to remove existing handler").WriteToLog()
}
return p.ohm.AddHandler(context.Background(), &Outbound{
tag: p.tag,
listener: listener,
})
}
func (p *MetricsHandler) Close() error {
return nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
return NewMetricsHandler(ctx, cfg.(*Config))
}))
}

View File

@@ -1,109 +0,0 @@
package metrics
import (
"context"
"sync"
"github.com/xtls/xray-core/common"
"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/transport"
)
// OutboundListener is a net.Listener for listening metrics http connections.
type OutboundListener struct {
buffer chan net.Conn
done *done.Instance
}
func (l *OutboundListener) add(conn net.Conn) {
select {
case l.buffer <- conn:
case <-l.done.Wait():
conn.Close()
default:
conn.Close()
}
}
// Accept implements net.Listener.
func (l *OutboundListener) Accept() (net.Conn, error) {
select {
case <-l.done.Wait():
return nil, newError("listen closed")
case c := <-l.buffer:
return c, nil
}
}
// Close implement net.Listener.
func (l *OutboundListener) Close() error {
common.Must(l.done.Close())
L:
for {
select {
case c := <-l.buffer:
c.Close()
default:
break L
}
}
return nil
}
// Addr implements net.Listener.
func (l *OutboundListener) Addr() net.Addr {
return &net.TCPAddr{
IP: net.IP{0, 0, 0, 0},
Port: 0,
}
}
// Outbound is an outbound.Handler that handles metrics http connections.
type Outbound struct {
tag string
listener *OutboundListener
access sync.RWMutex
closed bool
}
// Dispatch implements outbound.Handler.
func (co *Outbound) Dispatch(ctx context.Context, link *transport.Link) {
co.access.RLock()
if co.closed {
common.Interrupt(link.Reader)
common.Interrupt(link.Writer)
co.access.RUnlock()
return
}
closeSignal := done.New()
c := cnc.NewConnection(cnc.ConnectionInputMulti(link.Writer), cnc.ConnectionOutputMulti(link.Reader), cnc.ConnectionOnClose(closeSignal))
co.listener.add(c)
co.access.RUnlock()
<-closeSignal.Wait()
}
// Tag implements outbound.Handler.
func (co *Outbound) Tag() string {
return co.tag
}
// Start implements common.Runnable.
func (co *Outbound) Start() error {
co.access.Lock()
co.closed = false
co.access.Unlock()
return nil
}
// Close implements common.Closable.
func (co *Outbound) Close() error {
co.access.Lock()
defer co.access.Unlock()
co.closed = true
return co.listener.Close()
}

View File

@@ -1,14 +0,0 @@
package burst
import (
"math"
"time"
)
//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen
const (
rttFailed = time.Duration(math.MaxInt64 - iota)
rttUntested
rttUnqualified
)

View File

@@ -1,108 +0,0 @@
package burst
import (
"context"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/signal/done"
"github.com/xtls/xray-core/features/extension"
"github.com/xtls/xray-core/features/outbound"
"google.golang.org/protobuf/proto"
"sync"
)
type Observer struct {
config *Config
ctx context.Context
statusLock sync.Mutex
hp *HealthPing
finished *done.Instance
ohm outbound.Manager
}
func (o *Observer) GetObservation(ctx context.Context) (proto.Message, error) {
return &observatory.ObservationResult{Status: o.createResult()}, nil
}
func (o *Observer) createResult() []*observatory.OutboundStatus {
var result []*observatory.OutboundStatus
o.hp.access.Lock()
defer o.hp.access.Unlock()
for name, value := range o.hp.Results {
status := observatory.OutboundStatus{
Alive: value.getStatistics().All != value.getStatistics().Fail,
Delay: value.getStatistics().Average.Milliseconds(),
LastErrorReason: "",
OutboundTag: name,
LastSeenTime: 0,
LastTryTime: 0,
HealthPing: &observatory.HealthPingMeasurementResult{
All: int64(value.getStatistics().All),
Fail: int64(value.getStatistics().Fail),
Deviation: int64(value.getStatistics().Deviation),
Average: int64(value.getStatistics().Average),
Max: int64(value.getStatistics().Max),
Min: int64(value.getStatistics().Min),
},
}
result = append(result, &status)
}
return result
}
func (o *Observer) Type() interface{} {
return extension.ObservatoryType()
}
func (o *Observer) Start() error {
if o.config != nil && len(o.config.SubjectSelector) != 0 {
o.finished = done.New()
o.hp.StartScheduler(func() ([]string, error) {
hs, ok := o.ohm.(outbound.HandlerSelector)
if !ok {
return nil, newError("outbound.Manager is not a HandlerSelector")
}
outbounds := hs.Select(o.config.SubjectSelector)
return outbounds, nil
})
}
return nil
}
func (o *Observer) Close() error {
if o.finished != nil {
o.hp.StopScheduler()
return o.finished.Close()
}
return nil
}
func New(ctx context.Context, config *Config) (*Observer, error) {
var outboundManager outbound.Manager
err := core.RequireFeatures(ctx, func(om outbound.Manager) {
outboundManager = om
})
if err != nil {
return nil, newError("Cannot get depended features").Base(err)
}
hp := NewHealthPing(ctx, config.PingConfig)
return &Observer{
config: config,
ctx: ctx,
ohm: outboundManager,
hp: hp,
}, nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
}))
}

View File

@@ -1,276 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.33.0
// protoc v4.23.1
// source: app/observatory/burst/config.proto
package burst
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// @Document The selectors for outbound under observation
SubjectSelector []string `protobuf:"bytes,2,rep,name=subject_selector,json=subjectSelector,proto3" json:"subject_selector,omitempty"`
PingConfig *HealthPingConfig `protobuf:"bytes,3,opt,name=ping_config,json=pingConfig,proto3" json:"ping_config,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_burst_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_burst_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_observatory_burst_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetSubjectSelector() []string {
if x != nil {
return x.SubjectSelector
}
return nil
}
func (x *Config) GetPingConfig() *HealthPingConfig {
if x != nil {
return x.PingConfig
}
return nil
}
type HealthPingConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// destination url, need 204 for success return
// default https://connectivitycheck.gstatic.com/generate_204
Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"`
// connectivity check url
Connectivity string `protobuf:"bytes,2,opt,name=connectivity,proto3" json:"connectivity,omitempty"`
// health check interval, int64 values of time.Duration
Interval int64 `protobuf:"varint,3,opt,name=interval,proto3" json:"interval,omitempty"`
// sampling count is the amount of recent ping results which are kept for calculation
SamplingCount int32 `protobuf:"varint,4,opt,name=samplingCount,proto3" json:"samplingCount,omitempty"`
// ping timeout, int64 values of time.Duration
Timeout int64 `protobuf:"varint,5,opt,name=timeout,proto3" json:"timeout,omitempty"`
}
func (x *HealthPingConfig) Reset() {
*x = HealthPingConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_burst_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *HealthPingConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HealthPingConfig) ProtoMessage() {}
func (x *HealthPingConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_burst_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HealthPingConfig.ProtoReflect.Descriptor instead.
func (*HealthPingConfig) Descriptor() ([]byte, []int) {
return file_app_observatory_burst_config_proto_rawDescGZIP(), []int{1}
}
func (x *HealthPingConfig) GetDestination() string {
if x != nil {
return x.Destination
}
return ""
}
func (x *HealthPingConfig) GetConnectivity() string {
if x != nil {
return x.Connectivity
}
return ""
}
func (x *HealthPingConfig) GetInterval() int64 {
if x != nil {
return x.Interval
}
return 0
}
func (x *HealthPingConfig) GetSamplingCount() int32 {
if x != nil {
return x.SamplingCount
}
return 0
}
func (x *HealthPingConfig) GetTimeout() int64 {
if x != nil {
return x.Timeout
}
return 0
}
var File_app_observatory_burst_config_proto protoreflect.FileDescriptor
var file_app_observatory_burst_config_proto_rawDesc = []byte{
0x0a, 0x22, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
0x79, 0x2f, 0x62, 0x75, 0x72, 0x73, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1f, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e,
0x62, 0x75, 0x72, 0x73, 0x74, 0x22, 0x87, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65,
0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x52, 0x0a, 0x0b, 0x70,
0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x31, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x62, 0x75, 0x72,
0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22,
0xb4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69,
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f,
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x69,
0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73,
0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07,
0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74,
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
0x72, 0x79, 0x2e, 0x62, 0x75, 0x72, 0x73, 0x74, 0x50, 0x01, 0x5a, 0x2f, 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, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76,
0x61, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x62, 0x75, 0x72, 0x73, 0x74, 0xaa, 0x02, 0x1a, 0x58, 0x72,
0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
0x72, 0x79, 0x2e, 0x42, 0x75, 0x72, 0x73, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_observatory_burst_config_proto_rawDescOnce sync.Once
file_app_observatory_burst_config_proto_rawDescData = file_app_observatory_burst_config_proto_rawDesc
)
func file_app_observatory_burst_config_proto_rawDescGZIP() []byte {
file_app_observatory_burst_config_proto_rawDescOnce.Do(func() {
file_app_observatory_burst_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_observatory_burst_config_proto_rawDescData)
})
return file_app_observatory_burst_config_proto_rawDescData
}
var file_app_observatory_burst_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_app_observatory_burst_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: xray.core.app.observatory.burst.Config
(*HealthPingConfig)(nil), // 1: xray.core.app.observatory.burst.HealthPingConfig
}
var file_app_observatory_burst_config_proto_depIdxs = []int32{
1, // 0: xray.core.app.observatory.burst.Config.ping_config:type_name -> xray.core.app.observatory.burst.HealthPingConfig
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_app_observatory_burst_config_proto_init() }
func file_app_observatory_burst_config_proto_init() {
if File_app_observatory_burst_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_observatory_burst_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_observatory_burst_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*HealthPingConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_observatory_burst_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_app_observatory_burst_config_proto_goTypes,
DependencyIndexes: file_app_observatory_burst_config_proto_depIdxs,
MessageInfos: file_app_observatory_burst_config_proto_msgTypes,
}.Build()
File_app_observatory_burst_config_proto = out.File
file_app_observatory_burst_config_proto_rawDesc = nil
file_app_observatory_burst_config_proto_goTypes = nil
file_app_observatory_burst_config_proto_depIdxs = nil
}

View File

@@ -1,29 +0,0 @@
syntax = "proto3";
package xray.core.app.observatory.burst;
option csharp_namespace = "Xray.App.Observatory.Burst";
option go_package = "github.com/xtls/xray-core/app/observatory/burst";
option java_package = "com.xray.app.observatory.burst";
option java_multiple_files = true;
message Config {
/* @Document The selectors for outbound under observation
*/
repeated string subject_selector = 2;
HealthPingConfig ping_config = 3;
}
message HealthPingConfig {
// destination url, need 204 for success return
// default https://connectivitycheck.gstatic.com/generate_204
string destination = 1;
// connectivity check url
string connectivity = 2;
// health check interval, int64 values of time.Duration
int64 interval = 3;
// sampling count is the amount of recent ping results which are kept for calculation
int32 samplingCount = 4;
// ping timeout, int64 values of time.Duration
int64 timeout = 5;
}

View File

@@ -1,9 +0,0 @@
package burst
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -1,253 +0,0 @@
package burst
import (
"context"
"fmt"
"strings"
"sync"
"time"
"github.com/xtls/xray-core/common/dice"
)
// HealthPingSettings holds settings for health Checker
type HealthPingSettings struct {
Destination string `json:"destination"`
Connectivity string `json:"connectivity"`
Interval time.Duration `json:"interval"`
SamplingCount int `json:"sampling"`
Timeout time.Duration `json:"timeout"`
}
// HealthPing is the health checker for balancers
type HealthPing struct {
ctx context.Context
access sync.Mutex
ticker *time.Ticker
tickerClose chan struct{}
Settings *HealthPingSettings
Results map[string]*HealthPingRTTS
}
// NewHealthPing creates a new HealthPing with settings
func NewHealthPing(ctx context.Context, config *HealthPingConfig) *HealthPing {
settings := &HealthPingSettings{}
if config != nil {
settings = &HealthPingSettings{
Connectivity: strings.TrimSpace(config.Connectivity),
Destination: strings.TrimSpace(config.Destination),
Interval: time.Duration(config.Interval),
SamplingCount: int(config.SamplingCount),
Timeout: time.Duration(config.Timeout),
}
}
if settings.Destination == "" {
// Destination URL, need 204 for success return default to chromium
// https://github.com/chromium/chromium/blob/main/components/safety_check/url_constants.cc#L10
// https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/safety_check/url_constants.cc#10
settings.Destination = "https://connectivitycheck.gstatic.com/generate_204"
}
if settings.Interval == 0 {
settings.Interval = time.Duration(1) * time.Minute
} else if settings.Interval < 10 {
newError("health check interval is too small, 10s is applied").AtWarning().WriteToLog()
settings.Interval = time.Duration(10) * time.Second
}
if settings.SamplingCount <= 0 {
settings.SamplingCount = 10
}
if settings.Timeout <= 0 {
// results are saved after all health pings finish,
// a larger timeout could possibly makes checks run longer
settings.Timeout = time.Duration(5) * time.Second
}
return &HealthPing{
ctx: ctx,
Settings: settings,
Results: nil,
}
}
// StartScheduler implements the HealthChecker
func (h *HealthPing) StartScheduler(selector func() ([]string, error)) {
if h.ticker != nil {
return
}
interval := h.Settings.Interval * time.Duration(h.Settings.SamplingCount)
ticker := time.NewTicker(interval)
tickerClose := make(chan struct{})
h.ticker = ticker
h.tickerClose = tickerClose
go func() {
tags, err := selector()
if err != nil {
newError("error select outbounds for initial health check: ", err).AtWarning().WriteToLog()
return
}
h.Check(tags)
}()
go func() {
for {
go func() {
tags, err := selector()
if err != nil {
newError("error select outbounds for scheduled health check: ", err).AtWarning().WriteToLog()
return
}
h.doCheck(tags, interval, h.Settings.SamplingCount)
h.Cleanup(tags)
}()
select {
case <-ticker.C:
continue
case <-tickerClose:
return
}
}
}()
}
// StopScheduler implements the HealthChecker
func (h *HealthPing) StopScheduler() {
if h.ticker == nil {
return
}
h.ticker.Stop()
h.ticker = nil
close(h.tickerClose)
h.tickerClose = nil
}
// Check implements the HealthChecker
func (h *HealthPing) Check(tags []string) error {
if len(tags) == 0 {
return nil
}
newError("perform one-time health check for tags ", tags).AtInfo().WriteToLog()
h.doCheck(tags, 0, 1)
return nil
}
type rtt struct {
handler string
value time.Duration
}
// doCheck performs the 'rounds' amount checks in given 'duration'. You should make
// sure all tags are valid for current balancer
func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int) {
count := len(tags) * rounds
if count == 0 {
return
}
ch := make(chan *rtt, count)
for _, tag := range tags {
handler := tag
client := newPingClient(
h.ctx,
h.Settings.Destination,
h.Settings.Timeout,
handler,
)
for i := 0; i < rounds; i++ {
delay := time.Duration(0)
if duration > 0 {
delay = time.Duration(dice.Roll(int(duration)))
}
time.AfterFunc(delay, func() {
newError("checking ", handler).AtDebug().WriteToLog()
delay, err := client.MeasureDelay()
if err == nil {
ch <- &rtt{
handler: handler,
value: delay,
}
return
}
if !h.checkConnectivity() {
newError("network is down").AtWarning().WriteToLog()
ch <- &rtt{
handler: handler,
value: 0,
}
return
}
newError(fmt.Sprintf(
"error ping %s with %s: %s",
h.Settings.Destination,
handler,
err,
)).AtWarning().WriteToLog()
ch <- &rtt{
handler: handler,
value: rttFailed,
}
})
}
}
for i := 0; i < count; i++ {
rtt := <-ch
if rtt.value > 0 {
// should not put results when network is down
h.PutResult(rtt.handler, rtt.value)
}
}
}
// PutResult put a ping rtt to results
func (h *HealthPing) PutResult(tag string, rtt time.Duration) {
h.access.Lock()
defer h.access.Unlock()
if h.Results == nil {
h.Results = make(map[string]*HealthPingRTTS)
}
r, ok := h.Results[tag]
if !ok {
// validity is 2 times to sampling period, since the check are
// distributed in the time line randomly, in extreme cases,
// previous checks are distributed on the left, and latters
// on the right
validity := h.Settings.Interval * time.Duration(h.Settings.SamplingCount) * 2
r = NewHealthPingResult(h.Settings.SamplingCount, validity)
h.Results[tag] = r
}
r.Put(rtt)
}
// Cleanup removes results of removed handlers,
// tags should be all valid tags of the Balancer now
func (h *HealthPing) Cleanup(tags []string) {
h.access.Lock()
defer h.access.Unlock()
for tag := range h.Results {
found := false
for _, v := range tags {
if tag == v {
found = true
break
}
}
if !found {
delete(h.Results, tag)
}
}
}
// checkConnectivity checks the network connectivity, it returns
// true if network is good or "connectivity check url" not set
func (h *HealthPing) checkConnectivity() bool {
if h.Settings.Connectivity == "" {
return true
}
tester := newDirectPingClient(
h.Settings.Connectivity,
h.Settings.Timeout,
)
if _, err := tester.MeasureDelay(); err != nil {
return false
}
return true
}

View File

@@ -1,143 +0,0 @@
package burst
import (
"math"
"time"
)
// HealthPingStats is the statistics of HealthPingRTTS
type HealthPingStats struct {
All int
Fail int
Deviation time.Duration
Average time.Duration
Max time.Duration
Min time.Duration
}
// HealthPingRTTS holds ping rtts for health Checker
type HealthPingRTTS struct {
idx int
cap int
validity time.Duration
rtts []*pingRTT
lastUpdateAt time.Time
stats *HealthPingStats
}
type pingRTT struct {
time time.Time
value time.Duration
}
// NewHealthPingResult returns a *HealthPingResult with specified capacity
func NewHealthPingResult(cap int, validity time.Duration) *HealthPingRTTS {
return &HealthPingRTTS{cap: cap, validity: validity}
}
// Get gets statistics of the HealthPingRTTS
func (h *HealthPingRTTS) Get() *HealthPingStats {
return h.getStatistics()
}
// GetWithCache get statistics and write cache for next call
// Make sure use Mutex.Lock() before calling it, RWMutex.RLock()
// is not an option since it writes cache
func (h *HealthPingRTTS) GetWithCache() *HealthPingStats {
lastPutAt := h.rtts[h.idx].time
now := time.Now()
if h.stats == nil || h.lastUpdateAt.Before(lastPutAt) || h.findOutdated(now) >= 0 {
h.stats = h.getStatistics()
h.lastUpdateAt = now
}
return h.stats
}
// Put puts a new rtt to the HealthPingResult
func (h *HealthPingRTTS) Put(d time.Duration) {
if h.rtts == nil {
h.rtts = make([]*pingRTT, h.cap)
for i := 0; i < h.cap; i++ {
h.rtts[i] = &pingRTT{}
}
h.idx = -1
}
h.idx = h.calcIndex(1)
now := time.Now()
h.rtts[h.idx].time = now
h.rtts[h.idx].value = d
}
func (h *HealthPingRTTS) calcIndex(step int) int {
idx := h.idx
idx += step
if idx >= h.cap {
idx %= h.cap
}
return idx
}
func (h *HealthPingRTTS) getStatistics() *HealthPingStats {
stats := &HealthPingStats{}
stats.Fail = 0
stats.Max = 0
stats.Min = rttFailed
sum := time.Duration(0)
cnt := 0
validRTTs := make([]time.Duration, 0)
for _, rtt := range h.rtts {
switch {
case rtt.value == 0 || time.Since(rtt.time) > h.validity:
continue
case rtt.value == rttFailed:
stats.Fail++
continue
}
cnt++
sum += rtt.value
validRTTs = append(validRTTs, rtt.value)
if stats.Max < rtt.value {
stats.Max = rtt.value
}
if stats.Min > rtt.value {
stats.Min = rtt.value
}
}
stats.All = cnt + stats.Fail
if cnt == 0 {
stats.Min = 0
return stats
}
stats.Average = time.Duration(int(sum) / cnt)
var std float64
if cnt < 2 {
// no enough data for standard deviation, we assume it's half of the average rtt
// if we don't do this, standard deviation of 1 round tested nodes is 0, will always
// selected before 2 or more rounds tested nodes
std = float64(stats.Average / 2)
} else {
variance := float64(0)
for _, rtt := range validRTTs {
variance += math.Pow(float64(rtt-stats.Average), 2)
}
std = math.Sqrt(variance / float64(cnt))
}
stats.Deviation = time.Duration(std)
return stats
}
func (h *HealthPingRTTS) findOutdated(now time.Time) int {
for i := h.cap - 1; i < 2*h.cap; i++ {
// from oldest to latest
idx := h.calcIndex(i)
validity := h.rtts[idx].time.Add(h.validity)
if h.lastUpdateAt.After(validity) {
return idx
}
if validity.Before(now) {
return idx
}
}
return -1
}

View File

@@ -1,106 +0,0 @@
package burst_test
import (
"math"
reflect "reflect"
"testing"
"time"
"github.com/xtls/xray-core/app/observatory/burst"
)
func TestHealthPingResults(t *testing.T) {
rtts := []int64{60, 140, 60, 140, 60, 60, 140, 60, 140}
hr := burst.NewHealthPingResult(4, time.Hour)
for _, rtt := range rtts {
hr.Put(time.Duration(rtt))
}
rttFailed := time.Duration(math.MaxInt64)
expected := &burst.HealthPingStats{
All: 4,
Fail: 0,
Deviation: 40,
Average: 100,
Max: 140,
Min: 60,
}
actual := hr.Get()
if !reflect.DeepEqual(expected, actual) {
t.Errorf("expected: %v, actual: %v", expected, actual)
}
hr.Put(rttFailed)
hr.Put(rttFailed)
expected.Fail = 2
actual = hr.Get()
if !reflect.DeepEqual(expected, actual) {
t.Errorf("failed half-failures test, expected: %v, actual: %v", expected, actual)
}
hr.Put(rttFailed)
hr.Put(rttFailed)
expected = &burst.HealthPingStats{
All: 4,
Fail: 4,
Deviation: 0,
Average: 0,
Max: 0,
Min: 0,
}
actual = hr.Get()
if !reflect.DeepEqual(expected, actual) {
t.Errorf("failed all-failures test, expected: %v, actual: %v", expected, actual)
}
}
func TestHealthPingResultsIgnoreOutdated(t *testing.T) {
rtts := []int64{60, 140, 60, 140}
hr := burst.NewHealthPingResult(4, time.Duration(10)*time.Millisecond)
for i, rtt := range rtts {
if i == 2 {
// wait for previous 2 outdated
time.Sleep(time.Duration(10) * time.Millisecond)
}
hr.Put(time.Duration(rtt))
}
hr.Get()
expected := &burst.HealthPingStats{
All: 2,
Fail: 0,
Deviation: 40,
Average: 100,
Max: 140,
Min: 60,
}
actual := hr.Get()
if !reflect.DeepEqual(expected, actual) {
t.Errorf("failed 'half-outdated' test, expected: %v, actual: %v", expected, actual)
}
// wait for all outdated
time.Sleep(time.Duration(10) * time.Millisecond)
expected = &burst.HealthPingStats{
All: 0,
Fail: 0,
Deviation: 0,
Average: 0,
Max: 0,
Min: 0,
}
actual = hr.Get()
if !reflect.DeepEqual(expected, actual) {
t.Errorf("failed 'outdated / not-tested' test, expected: %v, actual: %v", expected, actual)
}
hr.Put(time.Duration(60))
expected = &burst.HealthPingStats{
All: 1,
Fail: 0,
// 1 sample, std=0.5rtt
Deviation: 30,
Average: 60,
Max: 60,
Min: 60,
}
actual = hr.Get()
if !reflect.DeepEqual(expected, actual) {
t.Errorf("expected: %v, actual: %v", expected, actual)
}
}

View File

@@ -1,69 +0,0 @@
package burst
import (
"context"
"net/http"
"time"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/tagged"
)
type pingClient struct {
destination string
httpClient *http.Client
}
func newPingClient(ctx context.Context, destination string, timeout time.Duration, handler string) *pingClient {
return &pingClient{
destination: destination,
httpClient: newHTTPClient(ctx, handler, timeout),
}
}
func newDirectPingClient(destination string, timeout time.Duration) *pingClient {
return &pingClient{
destination: destination,
httpClient: &http.Client{Timeout: timeout},
}
}
func newHTTPClient(ctxv context.Context, handler string, timeout time.Duration) *http.Client {
tr := &http.Transport{
DisableKeepAlives: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dest, err := net.ParseDestination(network + ":" + addr)
if err != nil {
return nil, err
}
return tagged.Dialer(ctxv, dest, handler)
},
}
return &http.Client{
Transport: tr,
Timeout: timeout,
// don't follow redirect
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
}
// MeasureDelay returns the delay time of the request to dest
func (s *pingClient) MeasureDelay() (time.Duration, error) {
if s.httpClient == nil {
panic("pingClient no initialized")
}
req, err := http.NewRequest(http.MethodHead, s.destination, nil)
if err != nil {
return rttFailed, err
}
start := time.Now()
resp, err := s.httpClient.Do(req)
if err != nil {
return rttFailed, err
}
// don't wait for body
resp.Body.Close()
return time.Since(start), nil
}

View File

@@ -1,47 +0,0 @@
package command
import (
"context"
"github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/common"
core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/extension"
"google.golang.org/grpc"
)
type service struct {
UnimplementedObservatoryServiceServer
v *core.Instance
observatory extension.Observatory
}
func (s *service) GetOutboundStatus(ctx context.Context, request *GetOutboundStatusRequest) (*GetOutboundStatusResponse, error) {
resp, err := s.observatory.GetObservation(ctx)
if err != nil {
return nil, err
}
retdata := resp.(*observatory.ObservationResult)
return &GetOutboundStatusResponse{
Status: retdata,
}, nil
}
func (s *service) Register(server *grpc.Server) {
RegisterObservatoryServiceServer(server, s)
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
s := core.MustFromContext(ctx)
sv := &service{v: s}
err := s.RequireFeatures(func(Observatory extension.Observatory) {
sv.observatory = Observatory
})
if err != nil {
return nil, err
}
return sv, nil
}))
}

View File

@@ -1,278 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.33.0
// protoc v4.23.1
// source: app/observatory/command/command.proto
package command
import (
observatory "github.com/xtls/xray-core/app/observatory"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type GetOutboundStatusRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *GetOutboundStatusRequest) Reset() {
*x = GetOutboundStatusRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_command_command_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetOutboundStatusRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetOutboundStatusRequest) ProtoMessage() {}
func (x *GetOutboundStatusRequest) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_command_command_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetOutboundStatusRequest.ProtoReflect.Descriptor instead.
func (*GetOutboundStatusRequest) Descriptor() ([]byte, []int) {
return file_app_observatory_command_command_proto_rawDescGZIP(), []int{0}
}
type GetOutboundStatusResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Status *observatory.ObservationResult `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
}
func (x *GetOutboundStatusResponse) Reset() {
*x = GetOutboundStatusResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_command_command_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetOutboundStatusResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetOutboundStatusResponse) ProtoMessage() {}
func (x *GetOutboundStatusResponse) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_command_command_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetOutboundStatusResponse.ProtoReflect.Descriptor instead.
func (*GetOutboundStatusResponse) Descriptor() ([]byte, []int) {
return file_app_observatory_command_command_proto_rawDescGZIP(), []int{1}
}
func (x *GetOutboundStatusResponse) GetStatus() *observatory.ObservationResult {
if x != nil {
return x.Status
}
return nil
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_command_command_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_command_command_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_observatory_command_command_proto_rawDescGZIP(), []int{2}
}
var File_app_observatory_command_command_proto protoreflect.FileDescriptor
var file_app_observatory_command_command_proto_rawDesc = []byte{
0x0a, 0x25, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x21, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
0x72, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x1c, 0x61, 0x70, 0x70, 0x2f,
0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x63, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1a, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x4f,
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x22, 0x61, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x44, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x4f, 0x62,
0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52,
0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x32, 0xa7, 0x01, 0x0a, 0x12, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x90, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74,
0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3b,
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f,
0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3c, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65,
0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
0x47, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x80, 0x01, 0x0a, 0x25,
0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f,
0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
0x72, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x21, 0x58, 0x72, 0x61,
0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72,
0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_observatory_command_command_proto_rawDescOnce sync.Once
file_app_observatory_command_command_proto_rawDescData = file_app_observatory_command_command_proto_rawDesc
)
func file_app_observatory_command_command_proto_rawDescGZIP() []byte {
file_app_observatory_command_command_proto_rawDescOnce.Do(func() {
file_app_observatory_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_observatory_command_command_proto_rawDescData)
})
return file_app_observatory_command_command_proto_rawDescData
}
var file_app_observatory_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_app_observatory_command_command_proto_goTypes = []interface{}{
(*GetOutboundStatusRequest)(nil), // 0: xray.core.app.observatory.command.GetOutboundStatusRequest
(*GetOutboundStatusResponse)(nil), // 1: xray.core.app.observatory.command.GetOutboundStatusResponse
(*Config)(nil), // 2: xray.core.app.observatory.command.Config
(*observatory.ObservationResult)(nil), // 3: xray.core.app.observatory.ObservationResult
}
var file_app_observatory_command_command_proto_depIdxs = []int32{
3, // 0: xray.core.app.observatory.command.GetOutboundStatusResponse.status:type_name -> xray.core.app.observatory.ObservationResult
0, // 1: xray.core.app.observatory.command.ObservatoryService.GetOutboundStatus:input_type -> xray.core.app.observatory.command.GetOutboundStatusRequest
1, // 2: xray.core.app.observatory.command.ObservatoryService.GetOutboundStatus:output_type -> xray.core.app.observatory.command.GetOutboundStatusResponse
2, // [2:3] is the sub-list for method output_type
1, // [1:2] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_app_observatory_command_command_proto_init() }
func file_app_observatory_command_command_proto_init() {
if File_app_observatory_command_command_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_observatory_command_command_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetOutboundStatusRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_observatory_command_command_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetOutboundStatusResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_observatory_command_command_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_observatory_command_command_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_app_observatory_command_command_proto_goTypes,
DependencyIndexes: file_app_observatory_command_command_proto_depIdxs,
MessageInfos: file_app_observatory_command_command_proto_msgTypes,
}.Build()
File_app_observatory_command_command_proto = out.File
file_app_observatory_command_command_proto_rawDesc = nil
file_app_observatory_command_command_proto_goTypes = nil
file_app_observatory_command_command_proto_depIdxs = nil
}

View File

@@ -1,24 +0,0 @@
syntax = "proto3";
package xray.core.app.observatory.command;
option csharp_namespace = "Xray.Core.App.Observatory.Command";
option go_package = "github.com/xtls/xray-core/app/observatory/command";
option java_package = "com.xray.core.app.observatory.command";
option java_multiple_files = true;
import "app/observatory/config.proto";
message GetOutboundStatusRequest {
}
message GetOutboundStatusResponse {
xray.core.app.observatory.ObservationResult status = 1;
}
service ObservatoryService {
rpc GetOutboundStatus(GetOutboundStatusRequest)
returns (GetOutboundStatusResponse) {}
}
message Config {}

View File

@@ -1,109 +0,0 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc v4.23.1
// source: app/observatory/command/command.proto
package command
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
const (
ObservatoryService_GetOutboundStatus_FullMethodName = "/xray.core.app.observatory.command.ObservatoryService/GetOutboundStatus"
)
// ObservatoryServiceClient is the client API for ObservatoryService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type ObservatoryServiceClient interface {
GetOutboundStatus(ctx context.Context, in *GetOutboundStatusRequest, opts ...grpc.CallOption) (*GetOutboundStatusResponse, error)
}
type observatoryServiceClient struct {
cc grpc.ClientConnInterface
}
func NewObservatoryServiceClient(cc grpc.ClientConnInterface) ObservatoryServiceClient {
return &observatoryServiceClient{cc}
}
func (c *observatoryServiceClient) GetOutboundStatus(ctx context.Context, in *GetOutboundStatusRequest, opts ...grpc.CallOption) (*GetOutboundStatusResponse, error) {
out := new(GetOutboundStatusResponse)
err := c.cc.Invoke(ctx, ObservatoryService_GetOutboundStatus_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ObservatoryServiceServer is the server API for ObservatoryService service.
// All implementations must embed UnimplementedObservatoryServiceServer
// for forward compatibility
type ObservatoryServiceServer interface {
GetOutboundStatus(context.Context, *GetOutboundStatusRequest) (*GetOutboundStatusResponse, error)
mustEmbedUnimplementedObservatoryServiceServer()
}
// UnimplementedObservatoryServiceServer must be embedded to have forward compatible implementations.
type UnimplementedObservatoryServiceServer struct {
}
func (UnimplementedObservatoryServiceServer) GetOutboundStatus(context.Context, *GetOutboundStatusRequest) (*GetOutboundStatusResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetOutboundStatus not implemented")
}
func (UnimplementedObservatoryServiceServer) mustEmbedUnimplementedObservatoryServiceServer() {}
// UnsafeObservatoryServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ObservatoryServiceServer will
// result in compilation errors.
type UnsafeObservatoryServiceServer interface {
mustEmbedUnimplementedObservatoryServiceServer()
}
func RegisterObservatoryServiceServer(s grpc.ServiceRegistrar, srv ObservatoryServiceServer) {
s.RegisterService(&ObservatoryService_ServiceDesc, srv)
}
func _ObservatoryService_GetOutboundStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetOutboundStatusRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ObservatoryServiceServer).GetOutboundStatus(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ObservatoryService_GetOutboundStatus_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ObservatoryServiceServer).GetOutboundStatus(ctx, req.(*GetOutboundStatusRequest))
}
return interceptor(ctx, in, info, handler)
}
// ObservatoryService_ServiceDesc is the grpc.ServiceDesc for ObservatoryService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ObservatoryService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "xray.core.app.observatory.command.ObservatoryService",
HandlerType: (*ObservatoryServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetOutboundStatus",
Handler: _ObservatoryService_GetOutboundStatus_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "app/observatory/command/command.proto",
}

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.27.1
// protoc v4.23.1 // protoc v3.18.0
// source: app/observatory/config.proto // source: app/observatory/config.proto
package observatory package observatory
@@ -67,124 +67,36 @@ func (x *ObservationResult) GetStatus() []*OutboundStatus {
return nil return nil
} }
type HealthPingMeasurementResult struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
All int64 `protobuf:"varint,1,opt,name=all,proto3" json:"all,omitempty"`
Fail int64 `protobuf:"varint,2,opt,name=fail,proto3" json:"fail,omitempty"`
Deviation int64 `protobuf:"varint,3,opt,name=deviation,proto3" json:"deviation,omitempty"`
Average int64 `protobuf:"varint,4,opt,name=average,proto3" json:"average,omitempty"`
Max int64 `protobuf:"varint,5,opt,name=max,proto3" json:"max,omitempty"`
Min int64 `protobuf:"varint,6,opt,name=min,proto3" json:"min,omitempty"`
}
func (x *HealthPingMeasurementResult) Reset() {
*x = HealthPingMeasurementResult{}
if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *HealthPingMeasurementResult) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HealthPingMeasurementResult) ProtoMessage() {}
func (x *HealthPingMeasurementResult) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HealthPingMeasurementResult.ProtoReflect.Descriptor instead.
func (*HealthPingMeasurementResult) Descriptor() ([]byte, []int) {
return file_app_observatory_config_proto_rawDescGZIP(), []int{1}
}
func (x *HealthPingMeasurementResult) GetAll() int64 {
if x != nil {
return x.All
}
return 0
}
func (x *HealthPingMeasurementResult) GetFail() int64 {
if x != nil {
return x.Fail
}
return 0
}
func (x *HealthPingMeasurementResult) GetDeviation() int64 {
if x != nil {
return x.Deviation
}
return 0
}
func (x *HealthPingMeasurementResult) GetAverage() int64 {
if x != nil {
return x.Average
}
return 0
}
func (x *HealthPingMeasurementResult) GetMax() int64 {
if x != nil {
return x.Max
}
return 0
}
func (x *HealthPingMeasurementResult) GetMin() int64 {
if x != nil {
return x.Min
}
return 0
}
type OutboundStatus struct { type OutboundStatus struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// @Document Whether this outbound is usable // @Document Whether this outbound is usable
// @Restriction ReadOnlyForUser //@Restriction ReadOnlyForUser
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"` Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
// @Document The time for probe request to finish. // @Document The time for probe request to finish.
// @Type time.ms //@Type time.ms
// @Restriction ReadOnlyForUser //@Restriction ReadOnlyForUser
Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"` Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"`
// @Document The last error caused this outbound failed to relay probe request // @Document The last error caused this outbound failed to relay probe request
// @Restriction NotMachineReadable //@Restriction NotMachineReadable
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"` LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
// @Document The outbound tag for this Server // @Document The outbound tag for this Server
// @Type id.outboundTag //@Type id.outboundTag
OutboundTag string `protobuf:"bytes,4,opt,name=outbound_tag,json=outboundTag,proto3" json:"outbound_tag,omitempty"` OutboundTag string `protobuf:"bytes,4,opt,name=outbound_tag,json=outboundTag,proto3" json:"outbound_tag,omitempty"`
// @Document The time this outbound is known to be alive // @Document The time this outbound is known to be alive
// @Type id.outboundTag //@Type id.outboundTag
LastSeenTime int64 `protobuf:"varint,5,opt,name=last_seen_time,json=lastSeenTime,proto3" json:"last_seen_time,omitempty"` LastSeenTime int64 `protobuf:"varint,5,opt,name=last_seen_time,json=lastSeenTime,proto3" json:"last_seen_time,omitempty"`
// @Document The time this outbound is tried // @Document The time this outbound is tried
// @Type id.outboundTag //@Type id.outboundTag
LastTryTime int64 `protobuf:"varint,6,opt,name=last_try_time,json=lastTryTime,proto3" json:"last_try_time,omitempty"` LastTryTime int64 `protobuf:"varint,6,opt,name=last_try_time,json=lastTryTime,proto3" json:"last_try_time,omitempty"`
HealthPing *HealthPingMeasurementResult `protobuf:"bytes,7,opt,name=health_ping,json=healthPing,proto3" json:"health_ping,omitempty"`
} }
func (x *OutboundStatus) Reset() { func (x *OutboundStatus) Reset() {
*x = OutboundStatus{} *x = OutboundStatus{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_config_proto_msgTypes[2] mi := &file_app_observatory_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -197,7 +109,7 @@ func (x *OutboundStatus) String() string {
func (*OutboundStatus) ProtoMessage() {} func (*OutboundStatus) ProtoMessage() {}
func (x *OutboundStatus) ProtoReflect() protoreflect.Message { func (x *OutboundStatus) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_config_proto_msgTypes[2] mi := &file_app_observatory_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -210,7 +122,7 @@ func (x *OutboundStatus) ProtoReflect() protoreflect.Message {
// Deprecated: Use OutboundStatus.ProtoReflect.Descriptor instead. // Deprecated: Use OutboundStatus.ProtoReflect.Descriptor instead.
func (*OutboundStatus) Descriptor() ([]byte, []int) { func (*OutboundStatus) Descriptor() ([]byte, []int) {
return file_app_observatory_config_proto_rawDescGZIP(), []int{2} return file_app_observatory_config_proto_rawDescGZIP(), []int{1}
} }
func (x *OutboundStatus) GetAlive() bool { func (x *OutboundStatus) GetAlive() bool {
@@ -255,34 +167,27 @@ func (x *OutboundStatus) GetLastTryTime() int64 {
return 0 return 0
} }
func (x *OutboundStatus) GetHealthPing() *HealthPingMeasurementResult {
if x != nil {
return x.HealthPing
}
return nil
}
type ProbeResult struct { type ProbeResult struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// @Document Whether this outbound is usable // @Document Whether this outbound is usable
// @Restriction ReadOnlyForUser //@Restriction ReadOnlyForUser
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"` Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
// @Document The time for probe request to finish. // @Document The time for probe request to finish.
// @Type time.ms //@Type time.ms
// @Restriction ReadOnlyForUser //@Restriction ReadOnlyForUser
Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"` Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"`
// @Document The error caused this outbound failed to relay probe request // @Document The error caused this outbound failed to relay probe request
// @Restriction NotMachineReadable //@Restriction NotMachineReadable
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"` LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
} }
func (x *ProbeResult) Reset() { func (x *ProbeResult) Reset() {
*x = ProbeResult{} *x = ProbeResult{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_config_proto_msgTypes[3] mi := &file_app_observatory_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -295,7 +200,7 @@ func (x *ProbeResult) String() string {
func (*ProbeResult) ProtoMessage() {} func (*ProbeResult) ProtoMessage() {}
func (x *ProbeResult) ProtoReflect() protoreflect.Message { func (x *ProbeResult) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_config_proto_msgTypes[3] mi := &file_app_observatory_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -308,7 +213,7 @@ func (x *ProbeResult) ProtoReflect() protoreflect.Message {
// Deprecated: Use ProbeResult.ProtoReflect.Descriptor instead. // Deprecated: Use ProbeResult.ProtoReflect.Descriptor instead.
func (*ProbeResult) Descriptor() ([]byte, []int) { func (*ProbeResult) Descriptor() ([]byte, []int) {
return file_app_observatory_config_proto_rawDescGZIP(), []int{3} return file_app_observatory_config_proto_rawDescGZIP(), []int{2}
} }
func (x *ProbeResult) GetAlive() bool { func (x *ProbeResult) GetAlive() bool {
@@ -338,14 +243,14 @@ type Intensity struct {
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// @Document The time interval for a probe request in ms. // @Document The time interval for a probe request in ms.
// @Type time.ms //@Type time.ms
ProbeInterval uint32 `protobuf:"varint,1,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"` ProbeInterval uint32 `protobuf:"varint,1,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
} }
func (x *Intensity) Reset() { func (x *Intensity) Reset() {
*x = Intensity{} *x = Intensity{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_config_proto_msgTypes[4] mi := &file_app_observatory_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -358,7 +263,7 @@ func (x *Intensity) String() string {
func (*Intensity) ProtoMessage() {} func (*Intensity) ProtoMessage() {}
func (x *Intensity) ProtoReflect() protoreflect.Message { func (x *Intensity) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_config_proto_msgTypes[4] mi := &file_app_observatory_config_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -371,7 +276,7 @@ func (x *Intensity) ProtoReflect() protoreflect.Message {
// Deprecated: Use Intensity.ProtoReflect.Descriptor instead. // Deprecated: Use Intensity.ProtoReflect.Descriptor instead.
func (*Intensity) Descriptor() ([]byte, []int) { func (*Intensity) Descriptor() ([]byte, []int) {
return file_app_observatory_config_proto_rawDescGZIP(), []int{4} return file_app_observatory_config_proto_rawDescGZIP(), []int{3}
} }
func (x *Intensity) GetProbeInterval() uint32 { func (x *Intensity) GetProbeInterval() uint32 {
@@ -396,7 +301,7 @@ type Config struct {
func (x *Config) Reset() { func (x *Config) Reset() {
*x = Config{} *x = Config{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_config_proto_msgTypes[5] mi := &file_app_observatory_config_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -409,7 +314,7 @@ func (x *Config) String() string {
func (*Config) ProtoMessage() {} func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message { func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_config_proto_msgTypes[5] mi := &file_app_observatory_config_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -422,7 +327,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
// Deprecated: Use Config.ProtoReflect.Descriptor instead. // Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) { func (*Config) Descriptor() ([]byte, []int) {
return file_app_observatory_config_proto_rawDescGZIP(), []int{5} return file_app_observatory_config_proto_rawDescGZIP(), []int{4}
} }
func (x *Config) GetSubjectSelector() []string { func (x *Config) GetSubjectSelector() []string {
@@ -465,62 +370,47 @@ var file_app_observatory_config_proto_rawDesc = []byte{
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f,
0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
0x73, 0x22, 0x9f, 0x01, 0x0a, 0x1b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x73, 0x22, 0xd5, 0x01, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74,
0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20,
0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65,
0x61, 0x6c, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79,
0x03, 0x52, 0x04, 0x66, 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x61, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x72,
0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c, 0x61, 0x73,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c,
0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65, 0x12, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x04, 0x20, 0x01,
0x10, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6d, 0x61, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12,
0x78, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x24, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x74, 0x69, 0x6d,
0x6d, 0x69, 0x6e, 0x22, 0xae, 0x02, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65,
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x74, 0x72,
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6c, 0x61,
0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x73, 0x74, 0x54, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x65, 0x0a, 0x0b, 0x50, 0x72, 0x6f,
0x61, 0x79, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x62, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76,
0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x14,
0x61, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64,
0x0a, 0x0c, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x04, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x67, 0x12, 0x24, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x74, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e,
0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x22, 0x32, 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a,
0x65, 0x65, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18,
0x74, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65,
0x6c, 0x61, 0x73, 0x74, 0x54, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x57, 0x0a, 0x0b, 0x68, 0x72, 0x76, 0x61, 0x6c, 0x22, 0xa6, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63,
0x32, 0x36, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65,
0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x48, 0x65, 0x61, 0x63, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x72,
0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65, 0x6f, 0x62, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70,
0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0a, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x72, 0x6f, 0x62, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65,
0x50, 0x69, 0x6e, 0x67, 0x22, 0x65, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x73, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52,
0x75, 0x6c, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x2d,
0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x0a, 0x12, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72,
0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x65, 0x6e, 0x61, 0x62,
0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x42, 0x5e, 0x0a,
0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62,
0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x32, 0x0a, 0x09, 0x49, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74,
0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x62, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72,
0x52, 0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0xaa, 0x02, 0x14, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70,
0xa6, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, 0x6c,
0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x75,
0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x55,
0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x62,
0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x2d, 0x0a, 0x12, 0x65, 0x6e, 0x61,
0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18,
0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6e,
0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x42, 0x5e, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61,
0x74, 0x6f, 0x72, 0x79, 0x50, 0x01, 0x5a, 0x29, 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, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
0x79, 0xaa, 0x02, 0x14, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4f, 0x62, 0x73,
0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@@ -535,23 +425,21 @@ func file_app_observatory_config_proto_rawDescGZIP() []byte {
return file_app_observatory_config_proto_rawDescData return file_app_observatory_config_proto_rawDescData
} }
var file_app_observatory_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_app_observatory_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_app_observatory_config_proto_goTypes = []interface{}{ var file_app_observatory_config_proto_goTypes = []interface{}{
(*ObservationResult)(nil), // 0: xray.core.app.observatory.ObservationResult (*ObservationResult)(nil), // 0: xray.core.app.observatory.ObservationResult
(*HealthPingMeasurementResult)(nil), // 1: xray.core.app.observatory.HealthPingMeasurementResult (*OutboundStatus)(nil), // 1: xray.core.app.observatory.OutboundStatus
(*OutboundStatus)(nil), // 2: xray.core.app.observatory.OutboundStatus (*ProbeResult)(nil), // 2: xray.core.app.observatory.ProbeResult
(*ProbeResult)(nil), // 3: xray.core.app.observatory.ProbeResult (*Intensity)(nil), // 3: xray.core.app.observatory.Intensity
(*Intensity)(nil), // 4: xray.core.app.observatory.Intensity (*Config)(nil), // 4: xray.core.app.observatory.Config
(*Config)(nil), // 5: xray.core.app.observatory.Config
} }
var file_app_observatory_config_proto_depIdxs = []int32{ var file_app_observatory_config_proto_depIdxs = []int32{
2, // 0: xray.core.app.observatory.ObservationResult.status:type_name -> xray.core.app.observatory.OutboundStatus 1, // 0: xray.core.app.observatory.ObservationResult.status:type_name -> xray.core.app.observatory.OutboundStatus
1, // 1: xray.core.app.observatory.OutboundStatus.health_ping:type_name -> xray.core.app.observatory.HealthPingMeasurementResult 1, // [1:1] is the sub-list for method output_type
2, // [2:2] is the sub-list for method output_type 1, // [1:1] is the sub-list for method input_type
2, // [2:2] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee
2, // [2:2] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name
0, // [0:2] is the sub-list for field type_name
} }
func init() { file_app_observatory_config_proto_init() } func init() { file_app_observatory_config_proto_init() }
@@ -573,18 +461,6 @@ func file_app_observatory_config_proto_init() {
} }
} }
file_app_observatory_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { file_app_observatory_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*HealthPingMeasurementResult); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_observatory_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*OutboundStatus); i { switch v := v.(*OutboundStatus); i {
case 0: case 0:
return &v.state return &v.state
@@ -596,7 +472,7 @@ func file_app_observatory_config_proto_init() {
return nil return nil
} }
} }
file_app_observatory_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { file_app_observatory_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ProbeResult); i { switch v := v.(*ProbeResult); i {
case 0: case 0:
return &v.state return &v.state
@@ -608,7 +484,7 @@ func file_app_observatory_config_proto_init() {
return nil return nil
} }
} }
file_app_observatory_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { file_app_observatory_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Intensity); i { switch v := v.(*Intensity); i {
case 0: case 0:
return &v.state return &v.state
@@ -620,7 +496,7 @@ func file_app_observatory_config_proto_init() {
return nil return nil
} }
} }
file_app_observatory_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { file_app_observatory_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i { switch v := v.(*Config); i {
case 0: case 0:
return &v.state return &v.state
@@ -639,7 +515,7 @@ func file_app_observatory_config_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_observatory_config_proto_rawDesc, RawDescriptor: file_app_observatory_config_proto_rawDesc,
NumEnums: 0, NumEnums: 0,
NumMessages: 6, NumMessages: 5,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View File

@@ -10,15 +10,6 @@ message ObservationResult {
repeated OutboundStatus status = 1; repeated OutboundStatus status = 1;
} }
message HealthPingMeasurementResult {
int64 all = 1;
int64 fail = 2;
int64 deviation = 3;
int64 average = 4;
int64 max = 5;
int64 min = 6;
}
message OutboundStatus{ message OutboundStatus{
/* @Document Whether this outbound is usable /* @Document Whether this outbound is usable
@Restriction ReadOnlyForUser @Restriction ReadOnlyForUser
@@ -45,8 +36,6 @@ message OutboundStatus{
@Type id.outboundTag @Type id.outboundTag
*/ */
int64 last_try_time = 6; int64 last_try_time = 6;
HealthPingMeasurementResult health_ping = 7;
} }
message ProbeResult{ message ProbeResult{

View File

@@ -2,6 +2,7 @@ package observatory
import ( import (
"context" "context"
"github.com/xtls/xray-core/core"
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
@@ -9,16 +10,16 @@ import (
"sync" "sync"
"time" "time"
"github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
v2net "github.com/xtls/xray-core/common/net" v2net "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/done"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/extension" "github.com/xtls/xray-core/features/extension"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/transport/internet/tagged" "github.com/xtls/xray-core/transport/internet/tagged"
"google.golang.org/protobuf/proto"
) )
type Observer struct { type Observer struct {
@@ -31,6 +32,8 @@ type Observer struct {
finished *done.Instance finished *done.Instance
ohm outbound.Manager ohm outbound.Manager
StatusUpdate func(result *OutboundStatus)
} }
func (o *Observer) GetObservation(ctx context.Context) (proto.Message, error) { func (o *Observer) GetObservation(ctx context.Context) (proto.Message, error) {
@@ -65,45 +68,22 @@ func (o *Observer) background() {
} }
outbounds := hs.Select(o.config.SubjectSelector) outbounds := hs.Select(o.config.SubjectSelector)
sort.Strings(outbounds)
o.updateStatus(outbounds) o.updateStatus(outbounds)
sleepTime := time.Second * 10
if o.config.ProbeInterval != 0 {
sleepTime = time.Duration(o.config.ProbeInterval)
}
if !o.config.EnableConcurrency {
sort.Strings(outbounds)
for _, v := range outbounds {
result := o.probe(v)
o.updateStatusForResult(v, &result)
if o.finished.Done() {
return
}
time.Sleep(sleepTime)
}
continue
}
ch := make(chan struct{}, len(outbounds))
for _, v := range outbounds { for _, v := range outbounds {
go func(v string) { result := o.probe(v)
result := o.probe(v) o.updateStatusForResult(v, &result)
o.updateStatusForResult(v, &result) if o.finished.Done() {
ch <- struct{}{}
}(v)
}
for range outbounds {
select {
case <-ch:
case <-o.finished.Wait():
return return
} }
sleepTime := time.Second * 10
if o.config.ProbeInterval != 0 {
sleepTime = time.Duration(o.config.ProbeInterval)
}
time.Sleep(sleepTime)
} }
time.Sleep(sleepTime)
} }
} }
@@ -124,7 +104,7 @@ func (o *Observer) probe(outbound string) ProbeResult {
DialContext: func(ctx context.Context, network string, addr string) (net.Conn, error) { DialContext: func(ctx context.Context, network string, addr string) (net.Conn, error) {
var connection net.Conn var connection net.Conn
taskErr := task.Run(ctx, func() error { taskErr := task.Run(ctx, func() error {
// MUST use Xray's built in context system // MUST use V2Fly's built in context system
dest, err := v2net.ParseDestination(network + ":" + addr) dest, err := v2net.ParseDestination(network + ":" + addr)
if err != nil { if err != nil {
return newError("cannot understand address").Base(err) return newError("cannot understand address").Base(err)
@@ -155,7 +135,7 @@ func (o *Observer) probe(outbound string) ProbeResult {
var GETTime time.Duration var GETTime time.Duration
err := task.Run(o.ctx, func() error { err := task.Run(o.ctx, func() error {
startTime := time.Now() startTime := time.Now()
probeURL := "https://www.google.com/generate_204" probeURL := "https://api.v2fly.org/checkConnection.svgz"
if o.config.ProbeUrl != "" { if o.config.ProbeUrl != "" {
probeURL = o.config.ProbeUrl probeURL = o.config.ProbeUrl
} }
@@ -205,6 +185,10 @@ func (o *Observer) updateStatusForResult(outbound string, result *ProbeResult) {
status.LastErrorReason = result.LastErrorReason status.LastErrorReason = result.LastErrorReason
status.Delay = 99999999 status.Delay = 99999999
} }
if o.StatusUpdate != nil {
o.StatusUpdate(status)
}
} }
func (o *Observer) findStatusLocationLockHolderOnly(outbound string) int { func (o *Observer) findStatusLocationLockHolderOnly(outbound string) int {

View File

@@ -0,0 +1,12 @@
package observatory
func (o *Observer) UpdateStatus(result *OutboundStatus) {
o.statusLock.Lock()
defer o.statusLock.Unlock()
if location := o.findStatusLocationLockHolderOnly(result.OutboundTag); location != -1 {
o.status[location] = result
} else {
o.status = append(o.status, result)
}
}

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.27.1
// protoc v4.23.1 // protoc v3.18.0
// source: app/policy/config.proto // source: app/policy/config.proto
package policy package policy

View File

@@ -3,12 +3,13 @@ package command
import ( import (
"context" "context"
grpc "google.golang.org/grpc"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/inbound" "github.com/xtls/xray-core/features/inbound"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/proxy" "github.com/xtls/xray-core/proxy"
grpc "google.golang.org/grpc"
) )
// InboundOperation is the interface for operations that applies to inbound handlers. // InboundOperation is the interface for operations that applies to inbound handlers.

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.27.1
// protoc v4.23.1 // protoc v3.18.0
// source: app/proxyman/command/command.proto // source: app/proxyman/command/command.proto
package command package command

View File

@@ -1,8 +1,4 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT. // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc v4.23.1
// source: app/proxyman/command/command.proto
package command package command
@@ -18,15 +14,6 @@ import (
// Requires gRPC-Go v1.32.0 or later. // Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7 const _ = grpc.SupportPackageIsVersion7
const (
HandlerService_AddInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AddInbound"
HandlerService_RemoveInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/RemoveInbound"
HandlerService_AlterInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AlterInbound"
HandlerService_AddOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AddOutbound"
HandlerService_RemoveOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/RemoveOutbound"
HandlerService_AlterOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AlterOutbound"
)
// HandlerServiceClient is the client API for HandlerService service. // HandlerServiceClient is the client API for HandlerService service.
// //
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
@@ -49,7 +36,7 @@ func NewHandlerServiceClient(cc grpc.ClientConnInterface) HandlerServiceClient {
func (c *handlerServiceClient) AddInbound(ctx context.Context, in *AddInboundRequest, opts ...grpc.CallOption) (*AddInboundResponse, error) { func (c *handlerServiceClient) AddInbound(ctx context.Context, in *AddInboundRequest, opts ...grpc.CallOption) (*AddInboundResponse, error) {
out := new(AddInboundResponse) out := new(AddInboundResponse)
err := c.cc.Invoke(ctx, HandlerService_AddInbound_FullMethodName, in, out, opts...) err := c.cc.Invoke(ctx, "/xray.app.proxyman.command.HandlerService/AddInbound", in, out, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -58,7 +45,7 @@ func (c *handlerServiceClient) AddInbound(ctx context.Context, in *AddInboundReq
func (c *handlerServiceClient) RemoveInbound(ctx context.Context, in *RemoveInboundRequest, opts ...grpc.CallOption) (*RemoveInboundResponse, error) { func (c *handlerServiceClient) RemoveInbound(ctx context.Context, in *RemoveInboundRequest, opts ...grpc.CallOption) (*RemoveInboundResponse, error) {
out := new(RemoveInboundResponse) out := new(RemoveInboundResponse)
err := c.cc.Invoke(ctx, HandlerService_RemoveInbound_FullMethodName, in, out, opts...) err := c.cc.Invoke(ctx, "/xray.app.proxyman.command.HandlerService/RemoveInbound", in, out, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -67,7 +54,7 @@ func (c *handlerServiceClient) RemoveInbound(ctx context.Context, in *RemoveInbo
func (c *handlerServiceClient) AlterInbound(ctx context.Context, in *AlterInboundRequest, opts ...grpc.CallOption) (*AlterInboundResponse, error) { func (c *handlerServiceClient) AlterInbound(ctx context.Context, in *AlterInboundRequest, opts ...grpc.CallOption) (*AlterInboundResponse, error) {
out := new(AlterInboundResponse) out := new(AlterInboundResponse)
err := c.cc.Invoke(ctx, HandlerService_AlterInbound_FullMethodName, in, out, opts...) err := c.cc.Invoke(ctx, "/xray.app.proxyman.command.HandlerService/AlterInbound", in, out, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -76,7 +63,7 @@ func (c *handlerServiceClient) AlterInbound(ctx context.Context, in *AlterInboun
func (c *handlerServiceClient) AddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error) { func (c *handlerServiceClient) AddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error) {
out := new(AddOutboundResponse) out := new(AddOutboundResponse)
err := c.cc.Invoke(ctx, HandlerService_AddOutbound_FullMethodName, in, out, opts...) err := c.cc.Invoke(ctx, "/xray.app.proxyman.command.HandlerService/AddOutbound", in, out, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -85,7 +72,7 @@ func (c *handlerServiceClient) AddOutbound(ctx context.Context, in *AddOutboundR
func (c *handlerServiceClient) RemoveOutbound(ctx context.Context, in *RemoveOutboundRequest, opts ...grpc.CallOption) (*RemoveOutboundResponse, error) { func (c *handlerServiceClient) RemoveOutbound(ctx context.Context, in *RemoveOutboundRequest, opts ...grpc.CallOption) (*RemoveOutboundResponse, error) {
out := new(RemoveOutboundResponse) out := new(RemoveOutboundResponse)
err := c.cc.Invoke(ctx, HandlerService_RemoveOutbound_FullMethodName, in, out, opts...) err := c.cc.Invoke(ctx, "/xray.app.proxyman.command.HandlerService/RemoveOutbound", in, out, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -94,7 +81,7 @@ func (c *handlerServiceClient) RemoveOutbound(ctx context.Context, in *RemoveOut
func (c *handlerServiceClient) AlterOutbound(ctx context.Context, in *AlterOutboundRequest, opts ...grpc.CallOption) (*AlterOutboundResponse, error) { func (c *handlerServiceClient) AlterOutbound(ctx context.Context, in *AlterOutboundRequest, opts ...grpc.CallOption) (*AlterOutboundResponse, error) {
out := new(AlterOutboundResponse) out := new(AlterOutboundResponse)
err := c.cc.Invoke(ctx, HandlerService_AlterOutbound_FullMethodName, in, out, opts...) err := c.cc.Invoke(ctx, "/xray.app.proxyman.command.HandlerService/AlterOutbound", in, out, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -159,7 +146,7 @@ func _HandlerService_AddInbound_Handler(srv interface{}, ctx context.Context, de
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: HandlerService_AddInbound_FullMethodName, FullMethod: "/xray.app.proxyman.command.HandlerService/AddInbound",
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).AddInbound(ctx, req.(*AddInboundRequest)) return srv.(HandlerServiceServer).AddInbound(ctx, req.(*AddInboundRequest))
@@ -177,7 +164,7 @@ func _HandlerService_RemoveInbound_Handler(srv interface{}, ctx context.Context,
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: HandlerService_RemoveInbound_FullMethodName, FullMethod: "/xray.app.proxyman.command.HandlerService/RemoveInbound",
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).RemoveInbound(ctx, req.(*RemoveInboundRequest)) return srv.(HandlerServiceServer).RemoveInbound(ctx, req.(*RemoveInboundRequest))
@@ -195,7 +182,7 @@ func _HandlerService_AlterInbound_Handler(srv interface{}, ctx context.Context,
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: HandlerService_AlterInbound_FullMethodName, FullMethod: "/xray.app.proxyman.command.HandlerService/AlterInbound",
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).AlterInbound(ctx, req.(*AlterInboundRequest)) return srv.(HandlerServiceServer).AlterInbound(ctx, req.(*AlterInboundRequest))
@@ -213,7 +200,7 @@ func _HandlerService_AddOutbound_Handler(srv interface{}, ctx context.Context, d
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: HandlerService_AddOutbound_FullMethodName, FullMethod: "/xray.app.proxyman.command.HandlerService/AddOutbound",
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).AddOutbound(ctx, req.(*AddOutboundRequest)) return srv.(HandlerServiceServer).AddOutbound(ctx, req.(*AddOutboundRequest))
@@ -231,7 +218,7 @@ func _HandlerService_RemoveOutbound_Handler(srv interface{}, ctx context.Context
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: HandlerService_RemoveOutbound_FullMethodName, FullMethod: "/xray.app.proxyman.command.HandlerService/RemoveOutbound",
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).RemoveOutbound(ctx, req.(*RemoveOutboundRequest)) return srv.(HandlerServiceServer).RemoveOutbound(ctx, req.(*RemoveOutboundRequest))
@@ -249,7 +236,7 @@ func _HandlerService_AlterOutbound_Handler(srv interface{}, ctx context.Context,
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: HandlerService_AlterOutbound_FullMethodName, FullMethod: "/xray.app.proxyman.command.HandlerService/AlterOutbound",
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).AlterOutbound(ctx, req.(*AlterOutboundRequest)) return srv.(HandlerServiceServer).AlterOutbound(ctx, req.(*AlterOutboundRequest))

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.27.1
// protoc v4.23.1 // protoc v3.18.0
// source: app/proxyman/config.proto // source: app/proxyman/config.proto
package proxyman package proxyman
@@ -69,6 +69,64 @@ func (KnownProtocols) EnumDescriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{0} return file_app_proxyman_config_proto_rawDescGZIP(), []int{0}
} }
type DomainStrategy int32
const (
DomainStrategy_AS_IS DomainStrategy = 0
DomainStrategy_USE_IP DomainStrategy = 1
DomainStrategy_USE_IP4 DomainStrategy = 2
DomainStrategy_USE_IP6 DomainStrategy = 3
DomainStrategy_PREFER_IP4 DomainStrategy = 4
DomainStrategy_PREFER_IP6 DomainStrategy = 5
)
// Enum value maps for DomainStrategy.
var (
DomainStrategy_name = map[int32]string{
0: "AS_IS",
1: "USE_IP",
2: "USE_IP4",
3: "USE_IP6",
4: "PREFER_IP4",
5: "PREFER_IP6",
}
DomainStrategy_value = map[string]int32{
"AS_IS": 0,
"USE_IP": 1,
"USE_IP4": 2,
"USE_IP6": 3,
"PREFER_IP4": 4,
"PREFER_IP6": 5,
}
)
func (x DomainStrategy) Enum() *DomainStrategy {
p := new(DomainStrategy)
*p = x
return p
}
func (x DomainStrategy) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (DomainStrategy) Descriptor() protoreflect.EnumDescriptor {
return file_app_proxyman_config_proto_enumTypes[1].Descriptor()
}
func (DomainStrategy) Type() protoreflect.EnumType {
return &file_app_proxyman_config_proto_enumTypes[1]
}
func (x DomainStrategy) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use DomainStrategy.Descriptor instead.
func (DomainStrategy) EnumDescriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1}
}
type AllocationStrategy_Type int32 type AllocationStrategy_Type int32
const ( const (
@@ -105,11 +163,11 @@ func (x AllocationStrategy_Type) String() string {
} }
func (AllocationStrategy_Type) Descriptor() protoreflect.EnumDescriptor { func (AllocationStrategy_Type) Descriptor() protoreflect.EnumDescriptor {
return file_app_proxyman_config_proto_enumTypes[1].Descriptor() return file_app_proxyman_config_proto_enumTypes[2].Descriptor()
} }
func (AllocationStrategy_Type) Type() protoreflect.EnumType { func (AllocationStrategy_Type) Type() protoreflect.EnumType {
return &file_app_proxyman_config_proto_enumTypes[1] return &file_app_proxyman_config_proto_enumTypes[2]
} }
func (x AllocationStrategy_Type) Number() protoreflect.EnumNumber { func (x AllocationStrategy_Type) Number() protoreflect.EnumNumber {
@@ -238,8 +296,7 @@ type SniffingConfig struct {
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"` DomainsExcluded []string `protobuf:"bytes,3,rep,name=domains_excluded,json=domainsExcluded,proto3" json:"domains_excluded,omitempty"`
// Whether should only try to sniff metadata without waiting for client input. // Whether should only try to sniff metadata without waiting for client input.
// Can be used to support SMTP like protocol where server send the first // Can be used to support SMTP like protocol where server send the first message.
// message.
MetadataOnly bool `protobuf:"varint,4,opt,name=metadata_only,json=metadataOnly,proto3" json:"metadata_only,omitempty"` MetadataOnly bool `protobuf:"varint,4,opt,name=metadata_only,json=metadataOnly,proto3" json:"metadata_only,omitempty"`
RouteOnly bool `protobuf:"varint,5,opt,name=route_only,json=routeOnly,proto3" json:"route_only,omitempty"` RouteOnly bool `protobuf:"varint,5,opt,name=route_only,json=routeOnly,proto3" json:"route_only,omitempty"`
} }
@@ -316,8 +373,8 @@ type ReceiverConfig struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// PortList specifies the ports which the Receiver should listen on. // PortRange specifies the ports which the Receiver should listen on.
PortList *net.PortList `protobuf:"bytes,1,opt,name=port_list,json=portList,proto3" json:"port_list,omitempty"` PortRange *net.PortRange `protobuf:"bytes,1,opt,name=port_range,json=portRange,proto3" json:"port_range,omitempty"`
// Listen specifies the IP address that the Receiver should listen on. // Listen specifies the IP address that the Receiver should listen on.
Listen *net.IPOrDomain `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"` Listen *net.IPOrDomain `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"`
AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy,proto3" json:"allocation_strategy,omitempty"` AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy,proto3" json:"allocation_strategy,omitempty"`
@@ -326,7 +383,7 @@ type ReceiverConfig struct {
// Override domains for the given protocol. // Override domains for the given protocol.
// Deprecated. Use sniffing_settings. // Deprecated. Use sniffing_settings.
// //
// Deprecated: Marked as deprecated in app/proxyman/config.proto. // Deprecated: Do not use.
DomainOverride []KnownProtocols `protobuf:"varint,7,rep,packed,name=domain_override,json=domainOverride,proto3,enum=xray.app.proxyman.KnownProtocols" json:"domain_override,omitempty"` DomainOverride []KnownProtocols `protobuf:"varint,7,rep,packed,name=domain_override,json=domainOverride,proto3,enum=xray.app.proxyman.KnownProtocols" json:"domain_override,omitempty"`
SniffingSettings *SniffingConfig `protobuf:"bytes,8,opt,name=sniffing_settings,json=sniffingSettings,proto3" json:"sniffing_settings,omitempty"` SniffingSettings *SniffingConfig `protobuf:"bytes,8,opt,name=sniffing_settings,json=sniffingSettings,proto3" json:"sniffing_settings,omitempty"`
} }
@@ -363,9 +420,9 @@ func (*ReceiverConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{3} return file_app_proxyman_config_proto_rawDescGZIP(), []int{3}
} }
func (x *ReceiverConfig) GetPortList() *net.PortList { func (x *ReceiverConfig) GetPortRange() *net.PortRange {
if x != nil { if x != nil {
return x.PortList return x.PortRange
} }
return nil return nil
} }
@@ -398,7 +455,7 @@ func (x *ReceiverConfig) GetReceiveOriginalDestination() bool {
return false return false
} }
// Deprecated: Marked as deprecated in app/proxyman/config.proto. // Deprecated: Do not use.
func (x *ReceiverConfig) GetDomainOverride() []KnownProtocols { func (x *ReceiverConfig) GetDomainOverride() []KnownProtocols {
if x != nil { if x != nil {
return x.DomainOverride return x.DomainOverride
@@ -524,7 +581,7 @@ type SenderConfig struct {
StreamSettings *internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"` StreamSettings *internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
ProxySettings *internet.ProxyConfig `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"` ProxySettings *internet.ProxyConfig `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"`
MultiplexSettings *MultiplexingConfig `protobuf:"bytes,4,opt,name=multiplex_settings,json=multiplexSettings,proto3" json:"multiplex_settings,omitempty"` MultiplexSettings *MultiplexingConfig `protobuf:"bytes,4,opt,name=multiplex_settings,json=multiplexSettings,proto3" json:"multiplex_settings,omitempty"`
ViaCidr string `protobuf:"bytes,5,opt,name=via_cidr,json=viaCidr,proto3" json:"via_cidr,omitempty"` DomainStrategy DomainStrategy `protobuf:"varint,5,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.app.proxyman.DomainStrategy" json:"domain_strategy,omitempty"`
} }
func (x *SenderConfig) Reset() { func (x *SenderConfig) Reset() {
@@ -587,11 +644,11 @@ func (x *SenderConfig) GetMultiplexSettings() *MultiplexingConfig {
return nil return nil
} }
func (x *SenderConfig) GetViaCidr() string { func (x *SenderConfig) GetDomainStrategy() DomainStrategy {
if x != nil { if x != nil {
return x.ViaCidr return x.DomainStrategy
} }
return "" return DomainStrategy_AS_IS
} }
type MultiplexingConfig struct { type MultiplexingConfig struct {
@@ -602,11 +659,7 @@ type MultiplexingConfig struct {
// Whether or not Mux is enabled. // Whether or not Mux is enabled.
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
// Max number of concurrent connections that one Mux connection can handle. // Max number of concurrent connections that one Mux connection can handle.
Concurrency int32 `protobuf:"varint,2,opt,name=concurrency,proto3" json:"concurrency,omitempty"` Concurrency uint32 `protobuf:"varint,2,opt,name=concurrency,proto3" json:"concurrency,omitempty"`
// Transport XUDP in another Mux.
XudpConcurrency int32 `protobuf:"varint,3,opt,name=xudpConcurrency,proto3" json:"xudpConcurrency,omitempty"`
// "reject" (default), "allow" or "skip".
XudpProxyUDP443 string `protobuf:"bytes,4,opt,name=xudpProxyUDP443,proto3" json:"xudpProxyUDP443,omitempty"`
} }
func (x *MultiplexingConfig) Reset() { func (x *MultiplexingConfig) Reset() {
@@ -648,27 +701,13 @@ func (x *MultiplexingConfig) GetEnabled() bool {
return false return false
} }
func (x *MultiplexingConfig) GetConcurrency() int32 { func (x *MultiplexingConfig) GetConcurrency() uint32 {
if x != nil { if x != nil {
return x.Concurrency return x.Concurrency
} }
return 0 return 0
} }
func (x *MultiplexingConfig) GetXudpConcurrency() int32 {
if x != nil {
return x.XudpConcurrency
}
return 0
}
func (x *MultiplexingConfig) GetXudpProxyUDP443() string {
if x != nil {
return x.XudpProxyUDP443
}
return ""
}
type AllocationStrategy_AllocationStrategyConcurrency struct { type AllocationStrategy_AllocationStrategyConcurrency struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -817,93 +856,97 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f, 0x61, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f,
0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65,
0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x8d, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x90, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f,
0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f,
0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e,
0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x67, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01,
0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52,
0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63,
0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03,
0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74,
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c,
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4e, 0x0a, 0x0f, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12,
0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,
0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69,
0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72,
0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72,
0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4b,
0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x42, 0x02, 0x18,
0x01, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
0x65, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65,
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e,
0x2e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
0x10, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x73, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74,
0x61, 0x67, 0x12, 0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 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, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
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,
0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75,
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xfc, 0x02, 0x0a,
0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a,
0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f,
0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f,
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74,
0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e,
0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03,
0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50,
0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78,
0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c,
0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4b, 0x6e, 0x6f, 0x77, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x4e, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75,
0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,
0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x4a, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e, 0x67, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x6f, 0x6d,
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d,
0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, 0x50, 0x0a, 0x12, 0x4d,
0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01,
0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63,
0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2a, 0x23, 0x0a,
0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x10, 0x72, 0x65, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12,
0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x4c, 0x53,
0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x10, 0x01, 0x2a, 0x61, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x49, 0x53, 0x10, 0x00, 0x12,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55,
0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x52, 0x45, 0x46, 0x45, 0x52, 0x5f,
0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xcb, 0x02, 0x0a, 0x0c, 0x53, 0x65, 0x49, 0x50, 0x34, 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x52, 0x45, 0x46, 0x45, 0x52, 0x5f,
0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x03, 0x76, 0x69, 0x49, 0x50, 0x36, 0x10, 0x05, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61,
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c,
0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f,
0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e,
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78,
0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65,
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70,
0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78,
0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69,
0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08,
0x76, 0x69, 0x61, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x76, 0x69, 0x61, 0x43, 0x69, 0x64, 0x72, 0x22, 0xa4, 0x01, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74,
0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18,
0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63,
0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x63,
0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75,
0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x03, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72,
0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78,
0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x78,
0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x2a, 0x23,
0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73,
0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x4c,
0x53, 0x10, 0x01, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f,
0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70,
0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
} }
var ( var (
@@ -918,48 +961,50 @@ func file_app_proxyman_config_proto_rawDescGZIP() []byte {
return file_app_proxyman_config_proto_rawDescData return file_app_proxyman_config_proto_rawDescData
} }
var file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10) var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_app_proxyman_config_proto_goTypes = []interface{}{ var file_app_proxyman_config_proto_goTypes = []interface{}{
(KnownProtocols)(0), // 0: xray.app.proxyman.KnownProtocols (KnownProtocols)(0), // 0: xray.app.proxyman.KnownProtocols
(AllocationStrategy_Type)(0), // 1: xray.app.proxyman.AllocationStrategy.Type (DomainStrategy)(0), // 1: xray.app.proxyman.DomainStrategy
(*InboundConfig)(nil), // 2: xray.app.proxyman.InboundConfig (AllocationStrategy_Type)(0), // 2: xray.app.proxyman.AllocationStrategy.Type
(*AllocationStrategy)(nil), // 3: xray.app.proxyman.AllocationStrategy (*InboundConfig)(nil), // 3: xray.app.proxyman.InboundConfig
(*SniffingConfig)(nil), // 4: xray.app.proxyman.SniffingConfig (*AllocationStrategy)(nil), // 4: xray.app.proxyman.AllocationStrategy
(*ReceiverConfig)(nil), // 5: xray.app.proxyman.ReceiverConfig (*SniffingConfig)(nil), // 5: xray.app.proxyman.SniffingConfig
(*InboundHandlerConfig)(nil), // 6: xray.app.proxyman.InboundHandlerConfig (*ReceiverConfig)(nil), // 6: xray.app.proxyman.ReceiverConfig
(*OutboundConfig)(nil), // 7: xray.app.proxyman.OutboundConfig (*InboundHandlerConfig)(nil), // 7: xray.app.proxyman.InboundHandlerConfig
(*SenderConfig)(nil), // 8: xray.app.proxyman.SenderConfig (*OutboundConfig)(nil), // 8: xray.app.proxyman.OutboundConfig
(*MultiplexingConfig)(nil), // 9: xray.app.proxyman.MultiplexingConfig (*SenderConfig)(nil), // 9: xray.app.proxyman.SenderConfig
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency (*MultiplexingConfig)(nil), // 10: xray.app.proxyman.MultiplexingConfig
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 11: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh (*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 11: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
(*net.PortList)(nil), // 12: xray.common.net.PortList (*AllocationStrategy_AllocationStrategyRefresh)(nil), // 12: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
(*net.IPOrDomain)(nil), // 13: xray.common.net.IPOrDomain (*net.PortRange)(nil), // 13: xray.common.net.PortRange
(*internet.StreamConfig)(nil), // 14: xray.transport.internet.StreamConfig (*net.IPOrDomain)(nil), // 14: xray.common.net.IPOrDomain
(*serial.TypedMessage)(nil), // 15: xray.common.serial.TypedMessage (*internet.StreamConfig)(nil), // 15: xray.transport.internet.StreamConfig
(*internet.ProxyConfig)(nil), // 16: xray.transport.internet.ProxyConfig (*serial.TypedMessage)(nil), // 16: xray.common.serial.TypedMessage
(*internet.ProxyConfig)(nil), // 17: xray.transport.internet.ProxyConfig
} }
var file_app_proxyman_config_proto_depIdxs = []int32{ var file_app_proxyman_config_proto_depIdxs = []int32{
1, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type 2, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type
10, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency 11, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
11, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh 12, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
12, // 3: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList 13, // 3: xray.app.proxyman.ReceiverConfig.port_range:type_name -> xray.common.net.PortRange
13, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain 14, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
3, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy 4, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy
14, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig 15, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
0, // 7: xray.app.proxyman.ReceiverConfig.domain_override:type_name -> xray.app.proxyman.KnownProtocols 0, // 7: xray.app.proxyman.ReceiverConfig.domain_override:type_name -> xray.app.proxyman.KnownProtocols
4, // 8: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig 5, // 8: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
15, // 9: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage 16, // 9: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
15, // 10: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage 16, // 10: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
13, // 11: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain 14, // 11: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
14, // 12: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig 15, // 12: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
16, // 13: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig 17, // 13: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
9, // 14: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig 10, // 14: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
15, // [15:15] is the sub-list for method output_type 1, // 15: xray.app.proxyman.SenderConfig.domain_strategy:type_name -> xray.app.proxyman.DomainStrategy
15, // [15:15] is the sub-list for method input_type 16, // [16:16] is the sub-list for method output_type
15, // [15:15] is the sub-list for extension type_name 16, // [16:16] is the sub-list for method input_type
15, // [15:15] is the sub-list for extension extendee 16, // [16:16] is the sub-list for extension type_name
0, // [0:15] is the sub-list for field type_name 16, // [16:16] is the sub-list for extension extendee
0, // [0:16] is the sub-list for field type_name
} }
func init() { file_app_proxyman_config_proto_init() } func init() { file_app_proxyman_config_proto_init() }
@@ -1094,7 +1139,7 @@ func file_app_proxyman_config_proto_init() {
File: protoimpl.DescBuilder{ File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_proxyman_config_proto_rawDesc, RawDescriptor: file_app_proxyman_config_proto_rawDesc,
NumEnums: 2, NumEnums: 3,
NumMessages: 10, NumMessages: 10,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,

View File

@@ -27,13 +27,17 @@ message AllocationStrategy {
Type type = 1; Type type = 1;
message AllocationStrategyConcurrency { uint32 value = 1; } message AllocationStrategyConcurrency {
uint32 value = 1;
}
// Number of handlers (ports) running in parallel. // Number of handlers (ports) running in parallel.
// Default value is 3 if unset. // Default value is 3 if unset.
AllocationStrategyConcurrency concurrency = 2; AllocationStrategyConcurrency concurrency = 2;
message AllocationStrategyRefresh { uint32 value = 1; } message AllocationStrategyRefresh {
uint32 value = 1;
}
// Number of minutes before a handler is regenerated. // Number of minutes before a handler is regenerated.
// Default value is 5 if unset. // Default value is 5 if unset.
@@ -55,16 +59,15 @@ message SniffingConfig {
repeated string domains_excluded = 3; repeated string domains_excluded = 3;
// Whether should only try to sniff metadata without waiting for client input. // Whether should only try to sniff metadata without waiting for client input.
// Can be used to support SMTP like protocol where server send the first // Can be used to support SMTP like protocol where server send the first message.
// message.
bool metadata_only = 4; bool metadata_only = 4;
bool route_only = 5; bool route_only = 5;
} }
message ReceiverConfig { message ReceiverConfig {
// PortList specifies the ports which the Receiver should listen on. // PortRange specifies the ports which the Receiver should listen on.
xray.common.net.PortList port_list = 1; xray.common.net.PortRange port_range = 1;
// Listen specifies the IP address that the Receiver should listen on. // Listen specifies the IP address that the Receiver should listen on.
xray.common.net.IPOrDomain listen = 2; xray.common.net.IPOrDomain listen = 2;
AllocationStrategy allocation_strategy = 3; AllocationStrategy allocation_strategy = 3;
@@ -73,7 +76,7 @@ message ReceiverConfig {
reserved 6; reserved 6;
// Override domains for the given protocol. // Override domains for the given protocol.
// Deprecated. Use sniffing_settings. // Deprecated. Use sniffing_settings.
repeated KnownProtocols domain_override = 7 [ deprecated = true ]; repeated KnownProtocols domain_override = 7 [deprecated = true];
SniffingConfig sniffing_settings = 8; SniffingConfig sniffing_settings = 8;
} }
@@ -85,22 +88,27 @@ message InboundHandlerConfig {
message OutboundConfig {} message OutboundConfig {}
enum DomainStrategy {
AS_IS = 0;
USE_IP = 1;
USE_IP4 = 2;
USE_IP6 = 3;
PREFER_IP4 = 4;
PREFER_IP6 = 5;
}
message SenderConfig { message SenderConfig {
// Send traffic through the given IP. Only IP is allowed. // Send traffic through the given IP. Only IP is allowed.
xray.common.net.IPOrDomain via = 1; xray.common.net.IPOrDomain via = 1;
xray.transport.internet.StreamConfig stream_settings = 2; xray.transport.internet.StreamConfig stream_settings = 2;
xray.transport.internet.ProxyConfig proxy_settings = 3; xray.transport.internet.ProxyConfig proxy_settings = 3;
MultiplexingConfig multiplex_settings = 4; MultiplexingConfig multiplex_settings = 4;
string via_cidr = 5; DomainStrategy domain_strategy = 5;
} }
message MultiplexingConfig { message MultiplexingConfig {
// Whether or not Mux is enabled. // Whether or not Mux is enabled.
bool enabled = 1; bool enabled = 1;
// Max number of concurrent connections that one Mux connection can handle. // Max number of concurrent connections that one Mux connection can handle.
int32 concurrency = 2; uint32 concurrency = 2;
// Transport XUDP in another Mux.
int32 xudpConcurrency = 3;
// "reject" (default), "allow" or "skip".
string xudpProxyUDP443 = 4;
} }

View File

@@ -67,7 +67,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
uplinkCounter, downlinkCounter := getStatCounter(core.MustFromContext(ctx), tag) uplinkCounter, downlinkCounter := getStatCounter(core.MustFromContext(ctx), tag)
nl := p.Network() nl := p.Network()
pl := receiverConfig.PortList pr := receiverConfig.PortRange
address := receiverConfig.Listen.AsAddress() address := receiverConfig.Listen.AsAddress()
if address == nil { if address == nil {
address = net.AnyIP address = net.AnyIP
@@ -87,7 +87,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
} }
mss.SocketSettings.ReceiveOriginalDestAddress = true mss.SocketSettings.ReceiveOriginalDestAddress = true
} }
if pl == nil { if pr == nil {
if net.HasNetwork(nl, net.Network_UNIX) { if net.HasNetwork(nl, net.Network_UNIX) {
newError("creating unix domain socket worker on ", address).AtDebug().WriteToLog() newError("creating unix domain socket worker on ", address).AtDebug().WriteToLog()
@@ -105,43 +105,41 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
h.workers = append(h.workers, worker) h.workers = append(h.workers, worker)
} }
} }
if pl != nil { if pr != nil {
for _, pr := range pl.Range { for port := pr.From; port <= pr.To; port++ {
for port := pr.From; port <= pr.To; port++ { if net.HasNetwork(nl, net.Network_TCP) {
if net.HasNetwork(nl, net.Network_TCP) { newError("creating stream worker on ", address, ":", port).AtDebug().WriteToLog()
newError("creating stream worker on ", address, ":", port).AtDebug().WriteToLog()
worker := &tcpWorker{ worker := &tcpWorker{
address: address, address: address,
port: net.Port(port), port: net.Port(port),
proxy: p, proxy: p,
stream: mss, stream: mss,
recvOrigDest: receiverConfig.ReceiveOriginalDestination, recvOrigDest: receiverConfig.ReceiveOriginalDestination,
tag: tag, tag: tag,
dispatcher: h.mux, dispatcher: h.mux,
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(), sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
ctx: ctx, ctx: ctx,
}
h.workers = append(h.workers, worker)
} }
h.workers = append(h.workers, worker)
}
if net.HasNetwork(nl, net.Network_UDP) { if net.HasNetwork(nl, net.Network_UDP) {
worker := &udpWorker{ worker := &udpWorker{
tag: tag, tag: tag,
proxy: p, proxy: p,
address: address, address: address,
port: net.Port(port), port: net.Port(port),
dispatcher: h.mux, dispatcher: h.mux,
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(), sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
stream: mss, stream: mss,
ctx: ctx, ctx: ctx,
}
h.workers = append(h.workers, worker)
} }
h.workers = append(h.workers, worker)
} }
} }
} }

View File

@@ -69,18 +69,15 @@ func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *p
} }
func (h *DynamicInboundHandler) allocatePort() net.Port { func (h *DynamicInboundHandler) allocatePort() net.Port {
allPorts := []int32{} from := int(h.receiverConfig.PortRange.From)
for _, pr := range h.receiverConfig.PortList.Range { delta := int(h.receiverConfig.PortRange.To) - from + 1
for i := pr.From; i <= pr.To; i++ {
allPorts = append(allPorts, int32(i))
}
}
h.portMutex.Lock() h.portMutex.Lock()
defer h.portMutex.Unlock() defer h.portMutex.Unlock()
for { for {
r := dice.Roll(len(allPorts)) r := dice.Roll(delta)
port := net.Port(allPorts[r]) port := net.Port(from + r)
_, used := h.portsInUse[port] _, used := h.portsInUse[port]
if !used { if !used {
h.portsInUse[port] = true h.portsInUse[port] = true

View File

@@ -6,6 +6,8 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/proxyman"
"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"
@@ -18,7 +20,6 @@ import (
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/proxy" "github.com/xtls/xray-core/proxy"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tcp" "github.com/xtls/xray-core/transport/internet/tcp"
"github.com/xtls/xray-core/transport/internet/udp" "github.com/xtls/xray-core/transport/internet/udp"
"github.com/xtls/xray-core/transport/pipe" "github.com/xtls/xray-core/transport/pipe"
@@ -60,7 +61,6 @@ func (w *tcpWorker) callback(conn stat.Connection) {
sid := session.NewID() sid := session.NewID()
ctx = session.ContextWithID(ctx, sid) ctx = session.ContextWithID(ctx, sid)
outbounds := []*session.Outbound{{}}
if w.recvOrigDest { if w.recvOrigDest {
var dest net.Destination var dest net.Destination
switch getTProxyType(w.stream) { switch getTProxyType(w.stream) {
@@ -75,10 +75,11 @@ func (w *tcpWorker) callback(conn stat.Connection) {
dest = net.DestinationFromAddr(conn.LocalAddr()) dest = net.DestinationFromAddr(conn.LocalAddr())
} }
if dest.IsValid() { if dest.IsValid() {
outbounds[0].Target = dest ctx = session.ContextWithOutbound(ctx, &session.Outbound{
Target: dest,
})
} }
} }
ctx = session.ContextWithOutbounds(ctx, outbounds)
if w.uplinkCounter != nil || w.downlinkCounter != nil { if w.uplinkCounter != nil || w.downlinkCounter != nil {
conn = &stat.CounterConnection{ conn = &stat.CounterConnection{
@@ -108,7 +109,9 @@ func (w *tcpWorker) callback(conn stat.Connection) {
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx)) newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx))
} }
cancel() cancel()
conn.Close() if err := conn.Close(); err != nil {
newError("failed to close connection").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
} }
func (w *tcpWorker) Proxy() proxy.Inbound { func (w *tcpWorker) Proxy() proxy.Inbound {
@@ -309,10 +312,9 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
ctx = session.ContextWithID(ctx, sid) ctx = session.ContextWithID(ctx, sid)
if originalDest.IsValid() { if originalDest.IsValid() {
outbounds := []*session.Outbound{{ ctx = session.ContextWithOutbound(ctx, &session.Outbound{
Target: originalDest, Target: originalDest,
}} })
ctx = session.ContextWithOutbounds(ctx, outbounds)
} }
ctx = session.ContextWithInbound(ctx, &session.Inbound{ ctx = session.ContextWithInbound(ctx, &session.Inbound{
Source: source, Source: source,
@@ -363,7 +365,7 @@ func (w *udpWorker) clean() error {
} }
for addr, conn := range w.activeConn { for addr, conn := range w.activeConn {
if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 2*60 { if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 5*60 { // TODO Timeout too small
if !conn.inactive { if !conn.inactive {
conn.setInactive() conn.setInactive()
delete(w.activeConn, addr) delete(w.activeConn, addr)

View File

@@ -2,11 +2,11 @@ package outbound
import ( import (
"context" "context"
"crypto/rand" "github.com/xtls/xray-core/features/dns"
"errors" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/proxyman"
"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/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/net/cnc"
@@ -18,13 +18,8 @@ import (
"github.com/xtls/xray-core/proxy" "github.com/xtls/xray-core/proxy"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/pipe" "github.com/xtls/xray-core/transport/pipe"
"io"
"math/big"
gonet "net"
"os"
) )
func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) { func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {
@@ -59,20 +54,20 @@ type Handler struct {
streamSettings *internet.MemoryStreamConfig streamSettings *internet.MemoryStreamConfig
proxy proxy.Outbound proxy proxy.Outbound
outboundManager outbound.Manager outboundManager outbound.Manager
dnsClient dns.Client
mux *mux.ClientManager mux *mux.ClientManager
xudp *mux.ClientManager
udp443 string
uplinkCounter stats.Counter uplinkCounter stats.Counter
downlinkCounter stats.Counter downlinkCounter stats.Counter
} }
// NewHandler creates a new Handler based on the given configuration. // NewHandler create a new Handler based on the given configuration.
func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbound.Handler, error) { func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbound.Handler, error) {
v := core.MustFromContext(ctx) v := core.MustFromContext(ctx)
uplinkCounter, downlinkCounter := getStatCounter(v, config.Tag) uplinkCounter, downlinkCounter := getStatCounter(v, config.Tag)
h := &Handler{ h := &Handler{
tag: config.Tag, tag: config.Tag,
outboundManager: v.GetFeature(outbound.ManagerType()).(outbound.Manager), outboundManager: v.GetFeature(outbound.ManagerType()).(outbound.Manager),
dnsClient: v.GetFeature(dns.ClientType()).(dns.Client),
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
} }
@@ -111,50 +106,22 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
} }
if h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil { if h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil {
if config := h.senderSettings.MultiplexSettings; config.Enabled { config := h.senderSettings.MultiplexSettings
if config.Concurrency < 0 { if config.Concurrency < 1 || config.Concurrency > 1024 {
h.mux = &mux.ClientManager{Enabled: false} return nil, newError("invalid mux concurrency: ", config.Concurrency).AtWarning()
} }
if config.Concurrency == 0 { h.mux = &mux.ClientManager{
config.Concurrency = 8 // same as before Enabled: h.senderSettings.MultiplexSettings.Enabled,
} Picker: &mux.IncrementalWorkerPicker{
if config.Concurrency > 0 { Factory: &mux.DialingWorkerFactory{
h.mux = &mux.ClientManager{ Proxy: proxyHandler,
Enabled: true, Dialer: h,
Picker: &mux.IncrementalWorkerPicker{ Strategy: mux.ClientStrategy{
Factory: &mux.DialingWorkerFactory{ MaxConcurrency: config.Concurrency,
Proxy: proxyHandler, MaxConnection: 128,
Dialer: h,
Strategy: mux.ClientStrategy{
MaxConcurrency: uint32(config.Concurrency),
MaxConnection: 128,
},
},
}, },
} },
} },
if config.XudpConcurrency < 0 {
h.xudp = &mux.ClientManager{Enabled: false}
}
if config.XudpConcurrency == 0 {
h.xudp = nil // same as before
}
if config.XudpConcurrency > 0 {
h.xudp = &mux.ClientManager{
Enabled: true,
Picker: &mux.IncrementalWorkerPicker{
Factory: &mux.DialingWorkerFactory{
Proxy: proxyHandler,
Dialer: h,
Strategy: mux.ClientStrategy{
MaxConcurrency: uint32(config.XudpConcurrency),
MaxConnection: 128,
},
},
},
}
}
h.udp443 = config.XudpProxyUDP443
} }
} }
@@ -169,59 +136,73 @@ func (h *Handler) Tag() string {
// Dispatch implements proxy.Outbound.Dispatch. // Dispatch implements proxy.Outbound.Dispatch.
func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) { func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
outbounds := session.OutboundsFromContext(ctx) if h.mux != nil && (h.mux.Enabled || session.MuxPreferedFromContext(ctx)) {
ob := outbounds[len(outbounds) - 1] if err := h.mux.Dispatch(ctx, link); err != nil {
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil && ob.OriginalTarget.Address != ob.Target.Address { newError("failed to process mux outbound traffic").Base(err).WriteToLog(session.ExportIDToError(ctx))
link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address} common.Interrupt(link.Writer)
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
}
if h.mux != nil {
test := func(err error) {
if err != nil {
err := newError("failed to process mux outbound traffic").Base(err)
session.SubmitOutboundErrorToOriginator(ctx, err)
err.WriteToLog(session.ExportIDToError(ctx))
common.Interrupt(link.Writer)
}
} }
if ob.Target.Network == net.Network_UDP && ob.Target.Port == 443 {
switch h.udp443 {
case "reject":
test(newError("XUDP rejected UDP/443 traffic").AtInfo())
return
case "skip":
goto out
}
}
if h.xudp != nil && ob.Target.Network == net.Network_UDP {
if !h.xudp.Enabled {
goto out
}
test(h.xudp.Dispatch(ctx, link))
return
}
if h.mux.Enabled {
test(h.mux.Dispatch(ctx, link))
return
}
}
out:
err := h.proxy.Process(ctx, link, h)
if err != nil {
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, context.Canceled) {
err = nil
}
}
if err != nil {
// Ensure outbound ray is properly closed.
err := newError("failed to process outbound traffic").Base(err)
session.SubmitOutboundErrorToOriginator(ctx, err)
err.WriteToLog(session.ExportIDToError(ctx))
common.Interrupt(link.Writer)
} else { } else {
common.Close(link.Writer) outbound := session.OutboundFromContext(ctx)
destination := outbound.Target
var domainString string
if destination.Address.Family().IsDomain() {
domainString = destination.Address.Domain()
} else if outbound.RouteTarget.Address != nil && outbound.RouteTarget.Address.Family().IsDomain() {
domainString = outbound.RouteTarget.Address.Domain()
} else {
domainString = ""
}
if h.senderSettings != nil && h.senderSettings.DomainStrategy != proxyman.DomainStrategy_AS_IS && domainString != "" {
var ips []net.IP
var err error
option := dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
}
switch h.senderSettings.DomainStrategy {
case proxyman.DomainStrategy_USE_IP4:
option.IPv6Enable = false
case proxyman.DomainStrategy_USE_IP6:
option.IPv4Enable = false
}
ips, err = h.dnsClient.LookupIP(domainString, option)
if err == nil {
switch h.senderSettings.DomainStrategy {
case proxyman.DomainStrategy_PREFER_IP4:
ips = reorderAddresses(ips, false)
case proxyman.DomainStrategy_PREFER_IP6:
ips = reorderAddresses(ips, true)
}
destination.Address = net.IPAddress(ips[0])
outbound.Target = destination
}
}
err := h.proxy.Process(ctx, link, h)
if err != nil {
// Ensure outbound ray is properly closed.
newError("failed to process outbound traffic").Base(err).WriteToLog(session.ExportIDToError(ctx))
common.Interrupt(link.Writer)
} else {
common.Must(common.Close(link.Writer))
}
common.Interrupt(link.Reader)
} }
common.Interrupt(link.Reader) }
func reorderAddresses(ips []net.IP, preferIPv6 bool) []net.IP {
var result []net.IP
for i := 0; i < 2; i++ {
for _, ip := range ips {
if (preferIPv6 == (i == 0)) == (ip.To4() == nil) {
result = append(result, ip)
}
}
}
return result
} }
// Address implements internet.Dialer. // Address implements internet.Dialer.
@@ -232,10 +213,6 @@ func (h *Handler) Address() net.Address {
return h.senderSettings.Via.AsAddress() return h.senderSettings.Via.AsAddress()
} }
func (h *Handler) DestIpAddress() net.IP {
return internet.DestIpAddress()
}
// Dial implements internet.Dialer. // Dial implements internet.Dialer.
func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connection, error) { func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connection, error) {
if h.senderSettings != nil { if h.senderSettings != nil {
@@ -244,11 +221,10 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
handler := h.outboundManager.GetHandler(tag) handler := h.outboundManager.GetHandler(tag)
if handler != nil { if handler != nil {
newError("proxying to ", tag, " for dest ", dest).AtDebug().WriteToLog(session.ExportIDToError(ctx)) newError("proxying to ", tag, " for dest ", dest).AtDebug().WriteToLog(session.ExportIDToError(ctx))
outbounds := session.OutboundsFromContext(ctx) ctx = session.ContextWithOutbound(ctx, &session.Outbound{
ctx = session.ContextWithOutbounds(ctx, append(outbounds, &session.Outbound{
Target: dest, Target: dest,
Tag: tag, })
})) // add another outbound in session ctx
opts := pipe.OptionsFromContext(ctx) opts := pipe.OptionsFromContext(ctx)
uplinkReader, uplinkWriter := pipe.New(opts...) uplinkReader, uplinkWriter := pipe.New(opts...)
downlinkReader, downlinkWriter := pipe.New(opts...) downlinkReader, downlinkWriter := pipe.New(opts...)
@@ -268,26 +244,17 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
} }
if h.senderSettings.Via != nil { if h.senderSettings.Via != nil {
outbounds := session.OutboundsFromContext(ctx) outbound := session.OutboundFromContext(ctx)
ob := outbounds[len(outbounds) - 1] if outbound == nil {
if h.senderSettings.ViaCidr == "" { outbound = new(session.Outbound)
ob.Gateway = h.senderSettings.Via.AsAddress() ctx = session.ContextWithOutbound(ctx, outbound)
} else { //Get a random address.
ob.Gateway = ParseRandomIPv6(h.senderSettings.Via.AsAddress(), h.senderSettings.ViaCidr)
} }
outbound.Gateway = h.senderSettings.Via.AsAddress()
} }
} }
if conn, err := h.getUoTConnection(ctx, dest); err != os.ErrInvalid {
return conn, err
}
conn, err := internet.Dial(ctx, dest, h.streamSettings) conn, err := internet.Dial(ctx, dest, h.streamSettings)
conn = h.getStatCouterConnection(conn) return h.getStatCouterConnection(conn), err
outbounds := session.OutboundsFromContext(ctx)
ob := outbounds[len(outbounds) - 1]
ob.Conn = conn
return conn, err
} }
func (h *Handler) getStatCouterConnection(conn stat.Connection) stat.Connection { func (h *Handler) getStatCouterConnection(conn stat.Connection) stat.Connection {
@@ -316,22 +283,3 @@ func (h *Handler) Close() error {
common.Close(h.mux) common.Close(h.mux)
return nil return nil
} }
func ParseRandomIPv6(address net.Address, prefix string) net.Address {
_, network, _ := gonet.ParseCIDR(address.IP().String() + "/" + prefix)
maskSize, totalBits := network.Mask.Size()
subnetSize := big.NewInt(1).Lsh(big.NewInt(1), uint(totalBits-maskSize))
// random
randomBigInt, _ := rand.Int(rand.Reader, subnetSize)
startIPBigInt := big.NewInt(0).SetBytes(network.IP.To16())
randomIPBigInt := big.NewInt(0).Add(startIPBigInt, randomBigInt)
randomIPBytes := randomIPBigInt.Bytes()
randomIPBytes = append(make([]byte, 16-len(randomIPBytes)), randomIPBytes...)
return net.ParseAddress(gonet.IP(randomIPBytes).String())
}

View File

@@ -2,23 +2,18 @@ package outbound_test
import ( import (
"context" "context"
"fmt"
"sync"
"sync/atomic"
"testing" "testing"
"time"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/app/policy" "github.com/xtls/xray-core/app/policy"
"github.com/xtls/xray-core/app/proxyman"
. "github.com/xtls/xray-core/app/proxyman/outbound" . "github.com/xtls/xray-core/app/proxyman/outbound"
"github.com/xtls/xray-core/app/stats" "github.com/xtls/xray-core/app/stats"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/session"
core "github.com/xtls/xray-core/core" core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/proxy/freedom" "github.com/xtls/xray-core/proxy/freedom"
"github.com/xtls/xray-core/transport/internet/stat"
) )
func TestInterfaces(t *testing.T) { func TestInterfaces(t *testing.T) {
@@ -45,7 +40,6 @@ func TestOutboundWithoutStatCounter(t *testing.T) {
v, _ := core.New(config) v, _ := core.New(config)
v.AddFeature((outbound.Manager)(new(Manager))) v.AddFeature((outbound.Manager)(new(Manager)))
ctx := context.WithValue(context.Background(), xrayKey, v) ctx := context.WithValue(context.Background(), xrayKey, v)
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{ h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
Tag: "tag", Tag: "tag",
ProxySettings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
@@ -75,7 +69,6 @@ func TestOutboundWithStatCounter(t *testing.T) {
v, _ := core.New(config) v, _ := core.New(config)
v.AddFeature((outbound.Manager)(new(Manager))) v.AddFeature((outbound.Manager)(new(Manager)))
ctx := context.WithValue(context.Background(), xrayKey, v) ctx := context.WithValue(context.Background(), xrayKey, v)
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{ h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
Tag: "tag", Tag: "tag",
ProxySettings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
@@ -86,91 +79,3 @@ func TestOutboundWithStatCounter(t *testing.T) {
t.Errorf("Expected conn to be CounterConnection") t.Errorf("Expected conn to be CounterConnection")
} }
} }
func TestTagsCache(t *testing.T) {
test_duration := 10 * time.Second
threads_num := 50
delay := 10 * time.Millisecond
tags_prefix := "node"
tags := sync.Map{}
counter := atomic.Uint64{}
ohm, err := New(context.Background(), &proxyman.OutboundConfig{})
if err != nil {
t.Error("failed to create outbound handler manager")
}
config := &core.Config{
App: []*serial.TypedMessage{},
}
v, _ := core.New(config)
v.AddFeature(ohm)
ctx := context.WithValue(context.Background(), xrayKey, v)
stop_add_rm := false
wg_add_rm := sync.WaitGroup{}
addHandlers := func() {
defer wg_add_rm.Done()
for !stop_add_rm {
time.Sleep(delay)
idx := counter.Add(1)
tag := fmt.Sprintf("%s%d", tags_prefix, idx)
cfg := &core.OutboundHandlerConfig{
Tag: tag,
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}
if h, err := NewHandler(ctx, cfg); err == nil {
if err := ohm.AddHandler(ctx, h); err == nil {
// t.Log("add handler:", tag)
tags.Store(tag, nil)
} else {
t.Error("failed to add handler:", tag)
}
} else {
t.Error("failed to create handler:", tag)
}
}
}
rmHandlers := func() {
defer wg_add_rm.Done()
for !stop_add_rm {
time.Sleep(delay)
tags.Range(func(key interface{}, value interface{}) bool {
if _, ok := tags.LoadAndDelete(key); ok {
// t.Log("remove handler:", key)
ohm.RemoveHandler(ctx, key.(string))
return false
}
return true
})
}
}
selectors := []string{tags_prefix}
wg_get := sync.WaitGroup{}
stop_get := false
getTags := func() {
defer wg_get.Done()
for !stop_get {
time.Sleep(delay)
_ = ohm.Select(selectors)
// t.Logf("get tags: %v", tag)
}
}
for i := 0; i < threads_num; i++ {
wg_add_rm.Add(2)
go rmHandlers()
go addHandlers()
wg_get.Add(1)
go getTags()
}
time.Sleep(test_duration)
stop_add_rm = true
wg_add_rm.Wait()
stop_get = true
wg_get.Wait()
}

View File

@@ -4,7 +4,6 @@ package outbound
import ( import (
"context" "context"
"sort"
"strings" "strings"
"sync" "sync"
@@ -22,14 +21,12 @@ type Manager struct {
taggedHandler map[string]outbound.Handler taggedHandler map[string]outbound.Handler
untaggedHandlers []outbound.Handler untaggedHandlers []outbound.Handler
running bool running bool
tagsCache *sync.Map
} }
// New creates a new Manager. // New creates a new Manager.
func New(ctx context.Context, config *proxyman.OutboundConfig) (*Manager, error) { func New(ctx context.Context, config *proxyman.OutboundConfig) (*Manager, error) {
m := &Manager{ m := &Manager{
taggedHandler: make(map[string]outbound.Handler), taggedHandler: make(map[string]outbound.Handler),
tagsCache: &sync.Map{},
} }
return m, nil return m, nil
} }
@@ -106,8 +103,6 @@ func (m *Manager) AddHandler(ctx context.Context, handler outbound.Handler) erro
m.access.Lock() m.access.Lock()
defer m.access.Unlock() defer m.access.Unlock()
m.tagsCache = &sync.Map{}
if m.defaultHandler == nil { if m.defaultHandler == nil {
m.defaultHandler = handler m.defaultHandler = handler
} }
@@ -137,8 +132,6 @@ func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
m.access.Lock() m.access.Lock()
defer m.access.Unlock() defer m.access.Unlock()
m.tagsCache = &sync.Map{}
delete(m.taggedHandler, tag) delete(m.taggedHandler, tag)
if m.defaultHandler != nil && m.defaultHandler.Tag() == tag { if m.defaultHandler != nil && m.defaultHandler.Tag() == tag {
m.defaultHandler = nil m.defaultHandler = nil
@@ -149,29 +142,24 @@ func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
// Select implements outbound.HandlerSelector. // Select implements outbound.HandlerSelector.
func (m *Manager) Select(selectors []string) []string { func (m *Manager) Select(selectors []string) []string {
key := strings.Join(selectors, ",")
if cache, ok := m.tagsCache.Load(key); ok {
return cache.([]string)
}
m.access.RLock() m.access.RLock()
defer m.access.RUnlock() defer m.access.RUnlock()
tags := make([]string, 0, len(selectors)) tags := make([]string, 0, len(selectors))
for tag := range m.taggedHandler { for tag := range m.taggedHandler {
match := false
for _, selector := range selectors { for _, selector := range selectors {
if strings.HasPrefix(tag, selector) { if strings.HasPrefix(tag, selector) {
tags = append(tags, tag) match = true
break break
} }
} }
if match {
tags = append(tags, tag)
}
} }
sort.Strings(tags)
m.tagsCache.Store(key, tags)
return tags return tags
} }

View File

@@ -1,34 +0,0 @@
package outbound
import (
"context"
"os"
"github.com/sagernet/sing/common/uot"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
)
func (h *Handler) getUoTConnection(ctx context.Context, dest net.Destination) (stat.Connection, error) {
if dest.Address == nil {
return nil, newError("nil destination address")
}
if !dest.Address.Family().IsDomain() {
return nil, os.ErrInvalid
}
var uotVersion int
if dest.Address.Domain() == uot.MagicAddress {
uotVersion = uot.Version
} else if dest.Address.Domain() == uot.LegacyMagicAddress {
uotVersion = uot.LegacyVersion
} else {
return nil, os.ErrInvalid
}
packetConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{IP: net.AnyIP.IP(), Port: 0}, h.streamSettings.SocketSettings)
if err != nil {
return nil, newError("unable to listen socket").Base(err)
}
conn := uot.NewServerConn(packetConn, uotVersion)
return h.getStatCouterConnection(conn), nil
}

View File

@@ -4,6 +4,8 @@ import (
"context" "context"
"time" "time"
"github.com/golang/protobuf/proto"
"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/session" "github.com/xtls/xray-core/common/session"
@@ -11,7 +13,6 @@ import (
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/pipe" "github.com/xtls/xray-core/transport/pipe"
"google.golang.org/protobuf/proto"
) )
// Bridge is a component in reverse proxy, that relays connections from Portal to local address. // Bridge is a component in reverse proxy, that relays connections from Portal to local address.

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.27.1
// protoc v4.23.1 // protoc v3.18.0
// source: app/reverse/config.proto // source: app/reverse/config.proto
package reverse package reverse

View File

@@ -5,6 +5,8 @@ import (
"sync" "sync"
"time" "time"
"github.com/golang/protobuf/proto"
"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/mux" "github.com/xtls/xray-core/common/mux"
@@ -14,7 +16,6 @@ import (
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/pipe" "github.com/xtls/xray-core/transport/pipe"
"google.golang.org/protobuf/proto"
) )
type Portal struct { type Portal struct {
@@ -62,13 +63,12 @@ func (p *Portal) Close() error {
} }
func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) error { func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) error {
outbounds := session.OutboundsFromContext(ctx) outboundMeta := session.OutboundFromContext(ctx)
ob := outbounds[len(outbounds) - 1] if outboundMeta == nil {
if ob == nil {
return newError("outbound metadata not found").AtError() return newError("outbound metadata not found").AtError()
} }
if isDomain(ob.Target, p.domain) { if isDomain(outboundMeta.Target, p.domain) {
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{}) muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
if err != nil { if err != nil {
return newError("failed to create mux client worker").Base(err).AtWarning() return newError("failed to create mux client worker").Base(err).AtWarning()
@@ -207,10 +207,9 @@ func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
downlinkReader, downlinkWriter := pipe.New(opt...) downlinkReader, downlinkWriter := pipe.New(opt...)
ctx := context.Background() ctx := context.Background()
outbounds := []*session.Outbound{{ ctx = session.ContextWithOutbound(ctx, &session.Outbound{
Target: net.UDPDestination(net.DomainAddress(internalDomain), 0), Target: net.UDPDestination(net.DomainAddress(internalDomain), 0),
}} })
ctx = session.ContextWithOutbounds(ctx, outbounds)
f := client.Dispatch(ctx, &transport.Link{ f := client.Dispatch(ctx, &transport.Link{
Reader: uplinkReader, Reader: uplinkReader,
Writer: downlinkWriter, Writer: downlinkWriter,

View File

@@ -14,7 +14,7 @@ import (
) )
const ( const (
internalDomain = "reverse.internal.v2fly.org" // make reverse proxy compatible with v2fly internalDomain = "reverse.internal.example.com"
) )
func isDomain(dest net.Destination, domain string) bool { func isDomain(dest net.Destination, domain string) bool {

View File

@@ -2,11 +2,8 @@ package router
import ( import (
"context" "context"
sync "sync"
"github.com/xtls/xray-core/app/observatory" "github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/extension" "github.com/xtls/xray-core/features/extension"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
) )
@@ -15,152 +12,40 @@ type BalancingStrategy interface {
PickOutbound([]string) string PickOutbound([]string) string
} }
type BalancingPrincipleTarget interface { type RandomStrategy struct{}
GetPrincipleTarget([]string) []string
}
type RoundRobinStrategy struct {
FallbackTag string
ctx context.Context
observatory extension.Observatory
mu sync.Mutex
index int
}
func (s *RoundRobinStrategy) InjectContext(ctx context.Context) {
s.ctx = ctx
}
func (s *RoundRobinStrategy) GetPrincipleTarget(strings []string) []string {
return strings
}
func (s *RoundRobinStrategy) PickOutbound(tags []string) string {
if len(s.FallbackTag) > 0 && s.observatory == nil {
common.Must(core.RequireFeatures(s.ctx, func(observatory extension.Observatory) error {
s.observatory = observatory
return nil
}))
}
if s.observatory != nil {
observeReport, err := s.observatory.GetObservation(s.ctx)
if err == nil {
aliveTags := make([]string, 0)
if result, ok := observeReport.(*observatory.ObservationResult); ok {
status := result.Status
statusMap := make(map[string]*observatory.OutboundStatus)
for _, outboundStatus := range status {
statusMap[outboundStatus.OutboundTag] = outboundStatus
}
for _, candidate := range tags {
if outboundStatus, found := statusMap[candidate]; found {
if outboundStatus.Alive {
aliveTags = append(aliveTags, candidate)
}
} else {
// unfound candidate is considered alive
aliveTags = append(aliveTags, candidate)
}
}
tags = aliveTags
}
}
}
func (s *RandomStrategy) PickOutbound(tags []string) string {
n := len(tags) n := len(tags)
if n == 0 { if n == 0 {
// goes to fallbackTag panic("0 tags")
return ""
} }
s.mu.Lock() return tags[dice.Roll(n)]
defer s.mu.Unlock()
tag := tags[s.index%n]
s.index = (s.index + 1) % n
return tag
} }
type Balancer struct { type Balancer struct {
selectors []string selectors []string
strategy BalancingStrategy strategy BalancingStrategy
ohm outbound.Manager ohm outbound.Manager
fallbackTag string
override override
} }
// PickOutbound picks the tag of a outbound
func (b *Balancer) PickOutbound() (string, error) { func (b *Balancer) PickOutbound() (string, error) {
candidates, err := b.SelectOutbounds() hs, ok := b.ohm.(outbound.HandlerSelector)
if err != nil { if !ok {
if b.fallbackTag != "" { return "", newError("outbound.Manager is not a HandlerSelector")
newError("fallback to [", b.fallbackTag, "], due to error: ", err).AtInfo().WriteToLog()
return b.fallbackTag, nil
}
return "", err
} }
var tag string tags := hs.Select(b.selectors)
if o := b.override.Get(); o != "" { if len(tags) == 0 {
tag = o return "", newError("no available outbounds selected")
} else {
tag = b.strategy.PickOutbound(candidates)
} }
tag := b.strategy.PickOutbound(tags)
if tag == "" { if tag == "" {
if b.fallbackTag != "" {
newError("fallback to [", b.fallbackTag, "], due to empty tag returned").AtInfo().WriteToLog()
return b.fallbackTag, nil
}
// will use default handler
return "", newError("balancing strategy returns empty tag") return "", newError("balancing strategy returns empty tag")
} }
return tag, nil return tag, nil
} }
func (b *Balancer) InjectContext(ctx context.Context) { func (b *Balancer) InjectContext(ctx context.Context) {
if contextReceiver, ok := b.strategy.(extension.ContextReceiver); ok { if contextReceiver, ok := b.strategy.(extension.ContextReceiver); ok {
contextReceiver.InjectContext(ctx) contextReceiver.InjectContext(ctx)
} }
} }
// SelectOutbounds select outbounds with selectors of the Balancer
func (b *Balancer) SelectOutbounds() ([]string, error) {
hs, ok := b.ohm.(outbound.HandlerSelector)
if !ok {
return nil, newError("outbound.Manager is not a HandlerSelector")
}
tags := hs.Select(b.selectors)
return tags, nil
}
// GetPrincipleTarget implements routing.BalancerPrincipleTarget
func (r *Router) GetPrincipleTarget(tag string) ([]string, error) {
if b, ok := r.balancers[tag]; ok {
if s, ok := b.strategy.(BalancingPrincipleTarget); ok {
candidates, err := b.SelectOutbounds()
if err != nil {
return nil, newError("unable to select outbounds").Base(err)
}
return s.GetPrincipleTarget(candidates), nil
}
return nil, newError("unsupported GetPrincipleTarget")
}
return nil, newError("cannot find tag")
}
// SetOverrideTarget implements routing.BalancerOverrider
func (r *Router) SetOverrideTarget(tag, target string) error {
if b, ok := r.balancers[tag]; ok {
b.override.Put(target)
return nil
}
return newError("cannot find tag")
}
// GetOverrideTarget implements routing.BalancerOverrider
func (r *Router) GetOverrideTarget(tag string) (string, error) {
if b, ok := r.balancers[tag]; ok {
return b.override.Get(), nil
}
return "", newError("cannot find tag")
}

View File

@@ -1,50 +0,0 @@
package router
import (
sync "sync"
)
func (r *Router) OverrideBalancer(balancer string, target string) error {
var b *Balancer
for tag, bl := range r.balancers {
if tag == balancer {
b = bl
break
}
}
if b == nil {
return newError("balancer '", balancer, "' not found")
}
b.override.Put(target)
return nil
}
type overrideSettings struct {
target string
}
type override struct {
access sync.RWMutex
settings overrideSettings
}
// Get gets the override settings
func (o *override) Get() string {
o.access.RLock()
defer o.access.RUnlock()
return o.settings.target
}
// Put updates the override settings
func (o *override) Put(target string) {
o.access.Lock()
defer o.access.Unlock()
o.settings.target = target
}
// Clear clears the override settings
func (o *override) Clear() {
o.access.Lock()
defer o.access.Unlock()
o.settings.target = ""
}

View File

@@ -6,11 +6,12 @@ import (
"context" "context"
"time" "time"
"google.golang.org/grpc"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/features/stats"
"google.golang.org/grpc"
) )
// routingServer is an implementation of RoutingService. // routingServer is an implementation of RoutingService.
@@ -19,55 +20,6 @@ type routingServer struct {
routingStats stats.Channel routingStats stats.Channel
} }
func (s *routingServer) GetBalancerInfo(ctx context.Context, request *GetBalancerInfoRequest) (*GetBalancerInfoResponse, error) {
var ret GetBalancerInfoResponse
ret.Balancer = &BalancerMsg{}
if bo, ok := s.router.(routing.BalancerOverrider); ok {
{
res, err := bo.GetOverrideTarget(request.GetTag())
if err != nil {
return nil, err
}
ret.Balancer.Override = &OverrideInfo{
Target: res,
}
}
}
if pt, ok := s.router.(routing.BalancerPrincipleTarget); ok {
{
res, err := pt.GetPrincipleTarget(request.GetTag())
if err != nil {
newError("unable to obtain principle target").Base(err).AtInfo().WriteToLog()
} else {
ret.Balancer.PrincipleTarget = &PrincipleTargetInfo{Tag: res}
}
}
}
return &ret, nil
}
func (s *routingServer) OverrideBalancerTarget(ctx context.Context, request *OverrideBalancerTargetRequest) (*OverrideBalancerTargetResponse, error) {
if bo, ok := s.router.(routing.BalancerOverrider); ok {
return &OverrideBalancerTargetResponse{}, bo.SetOverrideTarget(request.BalancerTag, request.Target)
}
return nil, newError("unsupported router implementation")
}
func (s *routingServer) AddRule(ctx context.Context, request *AddRuleRequest) (*AddRuleResponse, error) {
if bo, ok := s.router.(routing.Router); ok {
return &AddRuleResponse{}, bo.AddRule(request.Config, request.ShouldAppend)
}
return nil, newError("unsupported router implementation")
}
func (s *routingServer) RemoveRule(ctx context.Context, request *RemoveRuleRequest) (*RemoveRuleResponse, error) {
if bo, ok := s.router.(routing.Router); ok {
return &RemoveRuleResponse{}, bo.RemoveRule(request.RuleTag)
}
return nil, newError("unsupported router implementation")
}
// NewRoutingServer creates a statistics service with statistics manager. // NewRoutingServer creates a statistics service with statistics manager.
func NewRoutingServer(router routing.Router, routingStats stats.Channel) RoutingServiceServer { func NewRoutingServer(router routing.Router, routingStats stats.Channel) RoutingServiceServer {
return &routingServer{ return &routingServer{

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,6 @@ option java_package = "com.xray.app.router.command";
option java_multiple_files = true; option java_multiple_files = true;
import "common/net/network.proto"; import "common/net/network.proto";
import "common/serial/typed_message.proto";
// RoutingContext is the context with information relative to routing process. // RoutingContext is the context with information relative to routing process.
// It conforms to the structure of xray.features.routing.Context and // It conforms to the structure of xray.features.routing.Context and
@@ -61,56 +60,10 @@ message TestRouteRequest {
bool PublishResult = 3; bool PublishResult = 3;
} }
message PrincipleTargetInfo {
repeated string tag = 1;
}
message OverrideInfo {
string target = 2;
}
message BalancerMsg {
OverrideInfo override = 5;
PrincipleTargetInfo principle_target = 6;
}
message GetBalancerInfoRequest {
string tag = 1;
}
message GetBalancerInfoResponse {
BalancerMsg balancer = 1;
}
message OverrideBalancerTargetRequest {
string balancerTag = 1;
string target = 2;
}
message OverrideBalancerTargetResponse {}
message AddRuleRequest {
xray.common.serial.TypedMessage config = 1;
bool shouldAppend = 2;
}
message AddRuleResponse {}
message RemoveRuleRequest {
string ruleTag = 1;
}
message RemoveRuleResponse {}
service RoutingService { service RoutingService {
rpc SubscribeRoutingStats(SubscribeRoutingStatsRequest) rpc SubscribeRoutingStats(SubscribeRoutingStatsRequest)
returns (stream RoutingContext) {} returns (stream RoutingContext) {}
rpc TestRoute(TestRouteRequest) returns (RoutingContext) {} rpc TestRoute(TestRouteRequest) returns (RoutingContext) {}
rpc GetBalancerInfo(GetBalancerInfoRequest) returns (GetBalancerInfoResponse){}
rpc OverrideBalancerTarget(OverrideBalancerTargetRequest) returns (OverrideBalancerTargetResponse) {}
rpc AddRule(AddRuleRequest) returns (AddRuleResponse) {}
rpc RemoveRule(RemoveRuleRequest) returns (RemoveRuleResponse) {}
} }
message Config {} message Config {}

View File

@@ -1,8 +1,4 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT. // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc v4.23.1
// source: app/router/command/command.proto
package command package command
@@ -18,25 +14,12 @@ import (
// Requires gRPC-Go v1.32.0 or later. // Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7 const _ = grpc.SupportPackageIsVersion7
const (
RoutingService_SubscribeRoutingStats_FullMethodName = "/xray.app.router.command.RoutingService/SubscribeRoutingStats"
RoutingService_TestRoute_FullMethodName = "/xray.app.router.command.RoutingService/TestRoute"
RoutingService_GetBalancerInfo_FullMethodName = "/xray.app.router.command.RoutingService/GetBalancerInfo"
RoutingService_OverrideBalancerTarget_FullMethodName = "/xray.app.router.command.RoutingService/OverrideBalancerTarget"
RoutingService_AddRule_FullMethodName = "/xray.app.router.command.RoutingService/AddRule"
RoutingService_RemoveRule_FullMethodName = "/xray.app.router.command.RoutingService/RemoveRule"
)
// RoutingServiceClient is the client API for RoutingService service. // RoutingServiceClient is the client API for RoutingService service.
// //
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type RoutingServiceClient interface { type RoutingServiceClient interface {
SubscribeRoutingStats(ctx context.Context, in *SubscribeRoutingStatsRequest, opts ...grpc.CallOption) (RoutingService_SubscribeRoutingStatsClient, error) SubscribeRoutingStats(ctx context.Context, in *SubscribeRoutingStatsRequest, opts ...grpc.CallOption) (RoutingService_SubscribeRoutingStatsClient, error)
TestRoute(ctx context.Context, in *TestRouteRequest, opts ...grpc.CallOption) (*RoutingContext, error) TestRoute(ctx context.Context, in *TestRouteRequest, opts ...grpc.CallOption) (*RoutingContext, error)
GetBalancerInfo(ctx context.Context, in *GetBalancerInfoRequest, opts ...grpc.CallOption) (*GetBalancerInfoResponse, error)
OverrideBalancerTarget(ctx context.Context, in *OverrideBalancerTargetRequest, opts ...grpc.CallOption) (*OverrideBalancerTargetResponse, error)
AddRule(ctx context.Context, in *AddRuleRequest, opts ...grpc.CallOption) (*AddRuleResponse, error)
RemoveRule(ctx context.Context, in *RemoveRuleRequest, opts ...grpc.CallOption) (*RemoveRuleResponse, error)
} }
type routingServiceClient struct { type routingServiceClient struct {
@@ -48,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], RoutingService_SubscribeRoutingStats_FullMethodName, 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
} }
@@ -81,43 +64,7 @@ func (x *routingServiceSubscribeRoutingStatsClient) Recv() (*RoutingContext, err
func (c *routingServiceClient) TestRoute(ctx context.Context, in *TestRouteRequest, opts ...grpc.CallOption) (*RoutingContext, error) { func (c *routingServiceClient) TestRoute(ctx context.Context, in *TestRouteRequest, opts ...grpc.CallOption) (*RoutingContext, error) {
out := new(RoutingContext) out := new(RoutingContext)
err := c.cc.Invoke(ctx, RoutingService_TestRoute_FullMethodName, in, out, opts...) err := c.cc.Invoke(ctx, "/xray.app.router.command.RoutingService/TestRoute", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *routingServiceClient) GetBalancerInfo(ctx context.Context, in *GetBalancerInfoRequest, opts ...grpc.CallOption) (*GetBalancerInfoResponse, error) {
out := new(GetBalancerInfoResponse)
err := c.cc.Invoke(ctx, RoutingService_GetBalancerInfo_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *routingServiceClient) OverrideBalancerTarget(ctx context.Context, in *OverrideBalancerTargetRequest, opts ...grpc.CallOption) (*OverrideBalancerTargetResponse, error) {
out := new(OverrideBalancerTargetResponse)
err := c.cc.Invoke(ctx, RoutingService_OverrideBalancerTarget_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *routingServiceClient) AddRule(ctx context.Context, in *AddRuleRequest, opts ...grpc.CallOption) (*AddRuleResponse, error) {
out := new(AddRuleResponse)
err := c.cc.Invoke(ctx, RoutingService_AddRule_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *routingServiceClient) RemoveRule(ctx context.Context, in *RemoveRuleRequest, opts ...grpc.CallOption) (*RemoveRuleResponse, error) {
out := new(RemoveRuleResponse)
err := c.cc.Invoke(ctx, RoutingService_RemoveRule_FullMethodName, in, out, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -130,10 +77,6 @@ func (c *routingServiceClient) RemoveRule(ctx context.Context, in *RemoveRuleReq
type RoutingServiceServer interface { type RoutingServiceServer interface {
SubscribeRoutingStats(*SubscribeRoutingStatsRequest, RoutingService_SubscribeRoutingStatsServer) error SubscribeRoutingStats(*SubscribeRoutingStatsRequest, RoutingService_SubscribeRoutingStatsServer) error
TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error) TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error)
GetBalancerInfo(context.Context, *GetBalancerInfoRequest) (*GetBalancerInfoResponse, error)
OverrideBalancerTarget(context.Context, *OverrideBalancerTargetRequest) (*OverrideBalancerTargetResponse, error)
AddRule(context.Context, *AddRuleRequest) (*AddRuleResponse, error)
RemoveRule(context.Context, *RemoveRuleRequest) (*RemoveRuleResponse, error)
mustEmbedUnimplementedRoutingServiceServer() mustEmbedUnimplementedRoutingServiceServer()
} }
@@ -147,18 +90,6 @@ func (UnimplementedRoutingServiceServer) SubscribeRoutingStats(*SubscribeRouting
func (UnimplementedRoutingServiceServer) TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error) { func (UnimplementedRoutingServiceServer) TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error) {
return nil, status.Errorf(codes.Unimplemented, "method TestRoute not implemented") return nil, status.Errorf(codes.Unimplemented, "method TestRoute not implemented")
} }
func (UnimplementedRoutingServiceServer) GetBalancerInfo(context.Context, *GetBalancerInfoRequest) (*GetBalancerInfoResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetBalancerInfo not implemented")
}
func (UnimplementedRoutingServiceServer) OverrideBalancerTarget(context.Context, *OverrideBalancerTargetRequest) (*OverrideBalancerTargetResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method OverrideBalancerTarget not implemented")
}
func (UnimplementedRoutingServiceServer) AddRule(context.Context, *AddRuleRequest) (*AddRuleResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddRule not implemented")
}
func (UnimplementedRoutingServiceServer) RemoveRule(context.Context, *RemoveRuleRequest) (*RemoveRuleResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method RemoveRule not implemented")
}
func (UnimplementedRoutingServiceServer) mustEmbedUnimplementedRoutingServiceServer() {} func (UnimplementedRoutingServiceServer) mustEmbedUnimplementedRoutingServiceServer() {}
// UnsafeRoutingServiceServer may be embedded to opt out of forward compatibility for this service. // UnsafeRoutingServiceServer may be embedded to opt out of forward compatibility for this service.
@@ -203,7 +134,7 @@ func _RoutingService_TestRoute_Handler(srv interface{}, ctx context.Context, dec
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: RoutingService_TestRoute_FullMethodName, FullMethod: "/xray.app.router.command.RoutingService/TestRoute",
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RoutingServiceServer).TestRoute(ctx, req.(*TestRouteRequest)) return srv.(RoutingServiceServer).TestRoute(ctx, req.(*TestRouteRequest))
@@ -211,78 +142,6 @@ func _RoutingService_TestRoute_Handler(srv interface{}, ctx context.Context, dec
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _RoutingService_GetBalancerInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetBalancerInfoRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RoutingServiceServer).GetBalancerInfo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: RoutingService_GetBalancerInfo_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RoutingServiceServer).GetBalancerInfo(ctx, req.(*GetBalancerInfoRequest))
}
return interceptor(ctx, in, info, handler)
}
func _RoutingService_OverrideBalancerTarget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(OverrideBalancerTargetRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RoutingServiceServer).OverrideBalancerTarget(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: RoutingService_OverrideBalancerTarget_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RoutingServiceServer).OverrideBalancerTarget(ctx, req.(*OverrideBalancerTargetRequest))
}
return interceptor(ctx, in, info, handler)
}
func _RoutingService_AddRule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddRuleRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RoutingServiceServer).AddRule(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: RoutingService_AddRule_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RoutingServiceServer).AddRule(ctx, req.(*AddRuleRequest))
}
return interceptor(ctx, in, info, handler)
}
func _RoutingService_RemoveRule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RemoveRuleRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RoutingServiceServer).RemoveRule(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: RoutingService_RemoveRule_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RoutingServiceServer).RemoveRule(ctx, req.(*RemoveRuleRequest))
}
return interceptor(ctx, in, info, handler)
}
// RoutingService_ServiceDesc is the grpc.ServiceDesc for RoutingService service. // RoutingService_ServiceDesc is the grpc.ServiceDesc for RoutingService service.
// It's only intended for direct use with grpc.RegisterService, // It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy) // and not to be introspected or modified (even as a copy)
@@ -294,22 +153,6 @@ var RoutingService_ServiceDesc = grpc.ServiceDesc{
MethodName: "TestRoute", MethodName: "TestRoute",
Handler: _RoutingService_TestRoute_Handler, Handler: _RoutingService_TestRoute_Handler,
}, },
{
MethodName: "GetBalancerInfo",
Handler: _RoutingService_GetBalancerInfo_Handler,
},
{
MethodName: "OverrideBalancerTarget",
Handler: _RoutingService_OverrideBalancerTarget_Handler,
},
{
MethodName: "AddRule",
Handler: _RoutingService_AddRule_Handler,
},
{
MethodName: "RemoveRule",
Handler: _RoutingService_RemoveRule_Handler,
},
}, },
Streams: []grpc.StreamDesc{ Streams: []grpc.StreamDesc{
{ {

View File

@@ -8,6 +8,9 @@ import (
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts" "github.com/google/go-cmp/cmp/cmpopts"
"google.golang.org/grpc"
"google.golang.org/grpc/test/bufconn"
"github.com/xtls/xray-core/app/router" "github.com/xtls/xray-core/app/router"
. "github.com/xtls/xray-core/app/router/command" . "github.com/xtls/xray-core/app/router/command"
"github.com/xtls/xray-core/app/stats" "github.com/xtls/xray-core/app/stats"
@@ -15,9 +18,6 @@ import (
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/testing/mocks" "github.com/xtls/xray-core/testing/mocks"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/test/bufconn"
) )
func TestServiceSubscribeRoutingStats(t *testing.T) { func TestServiceSubscribeRoutingStats(t *testing.T) {
@@ -81,7 +81,7 @@ func TestServiceSubscribeRoutingStats(t *testing.T) {
// Client goroutine // Client goroutine
go func() { go func() {
defer lis.Close() defer lis.Close()
conn, err := grpc.DialContext(context.Background(), "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithTransportCredentials(insecure.NewCredentials())) conn, err := grpc.DialContext(context.Background(), "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
if err != nil { if err != nil {
errCh <- err errCh <- err
return return
@@ -215,7 +215,7 @@ func TestServiceSubscribeSubsetOfFields(t *testing.T) {
// Client goroutine // Client goroutine
go func() { go func() {
defer lis.Close() defer lis.Close()
conn, err := grpc.DialContext(context.Background(), "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithTransportCredentials(insecure.NewCredentials())) conn, err := grpc.DialContext(context.Background(), "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
if err != nil { if err != nil {
errCh <- err errCh <- err
return return
@@ -284,7 +284,7 @@ func TestSerivceTestRoute(t *testing.T) {
r := new(router.Router) r := new(router.Router)
mockCtl := gomock.NewController(t) mockCtl := gomock.NewController(t)
defer mockCtl.Finish() defer mockCtl.Finish()
common.Must(r.Init(context.TODO(), &router.Config{ common.Must(r.Init(&router.Config{
Rule: []*router.RoutingRule{ Rule: []*router.RoutingRule{
{ {
InboundTag: []string{"in"}, InboundTag: []string{"in"},
@@ -319,7 +319,7 @@ func TestSerivceTestRoute(t *testing.T) {
TargetTag: &router.RoutingRule_Tag{Tag: "out"}, TargetTag: &router.RoutingRule_Tag{Tag: "out"},
}, },
}, },
}, mocks.NewDNSClient(mockCtl), mocks.NewOutboundManager(mockCtl), nil)) }, mocks.NewDNSClient(mockCtl), mocks.NewOutboundManager(mockCtl)))
lis := bufconn.Listen(1024 * 1024) lis := bufconn.Listen(1024 * 1024)
bufDialer := func(context.Context, string) (net.Conn, error) { bufDialer := func(context.Context, string) (net.Conn, error) {
@@ -338,7 +338,7 @@ func TestSerivceTestRoute(t *testing.T) {
// Client goroutine // Client goroutine
go func() { go func() {
defer lis.Close() defer lis.Close()
conn, err := grpc.DialContext(context.Background(), "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithTransportCredentials(insecure.NewCredentials())) conn, err := grpc.DialContext(context.Background(), "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
if err != nil { if err != nil {
errCh <- err errCh <- err
} }

View File

@@ -28,6 +28,14 @@ func (c routingContext) GetTargetPort() net.Port {
return net.Port(c.RoutingContext.GetTargetPort()) return net.Port(c.RoutingContext.GetTargetPort())
} }
func (c routingContext) GetUid() uint32 {
return 0
}
func (c routingContext) GetAppStatus() []string {
return nil
}
// GetSkipDNSResolve is a mock implementation here to match the interface, // GetSkipDNSResolve is a mock implementation here to match the interface,
// SkipDNSResolve is set from dns module, no use if coming from a protobuf object? // SkipDNSResolve is set from dns module, no use if coming from a protobuf object?
// TODO: please confirm @Vigilans // TODO: please confirm @Vigilans

View File

@@ -1,9 +1,11 @@
package router package router
import ( import (
"regexp"
"strings" "strings"
"go.starlark.net/starlark"
"go.starlark.net/syntax"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/strmatcher" "github.com/xtls/xray-core/common/strmatcher"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
@@ -283,22 +285,44 @@ func (m *ProtocolMatcher) Apply(ctx routing.Context) bool {
} }
type AttributeMatcher struct { type AttributeMatcher struct {
configuredKeys map[string]*regexp.Regexp program *starlark.Program
}
func NewAttributeMatcher(code string) (*AttributeMatcher, error) {
starFile, err := syntax.Parse("attr.star", "satisfied=("+code+")", 0)
if err != nil {
return nil, newError("attr rule").Base(err)
}
p, err := starlark.FileProgram(starFile, func(name string) bool {
return name == "attrs"
})
if err != nil {
return nil, err
}
return &AttributeMatcher{
program: p,
}, nil
} }
// Match implements attributes matching. // Match implements attributes matching.
func (m *AttributeMatcher) Match(attrs map[string]string) bool { func (m *AttributeMatcher) Match(attrs map[string]string) bool {
// header keys are case insensitive most likely. So we do a convert attrsDict := new(starlark.Dict)
httpHeaders := make(map[string]string)
for key, value := range attrs { for key, value := range attrs {
httpHeaders[strings.ToLower(key)] = value attrsDict.SetKey(starlark.String(key), starlark.String(value))
} }
for key, regex := range m.configuredKeys {
if a, ok := httpHeaders[key]; !ok || !regex.MatchString(a) { predefined := make(starlark.StringDict)
return false predefined["attrs"] = attrsDict
}
thread := &starlark.Thread{
Name: "matcher",
} }
return true results, err := m.program.Init(thread, predefined)
if err != nil {
newError("attr matcher").Base(err).WriteToLog()
}
satisfied := results["satisfied"]
return satisfied != nil && bool(satisfied.Truth())
} }
// Apply implements Condition. // Apply implements Condition.
@@ -309,3 +333,49 @@ func (m *AttributeMatcher) Apply(ctx routing.Context) bool {
} }
return m.Match(attributes) return m.Match(attributes)
} }
type UidMatcher struct {
uidList map[uint32]bool
}
func NewUidMatcher(list *net.UidList) *UidMatcher {
m := UidMatcher{uidList: map[uint32]bool{}}
for _, uid := range list.Uid {
m.uidList[uid] = true
}
return &m
}
func (u UidMatcher) Apply(ctx routing.Context) bool {
return u.uidList[ctx.GetUid()]
}
type AppStatusMatcher struct {
appStatus map[string]bool
}
func NewAppStatusMatcher(appStatus []string) *AppStatusMatcher {
m := &AppStatusMatcher{
appStatus: map[string]bool{},
}
for _, status := range appStatus {
m.appStatus[status] = true
}
return m
}
// Apply implements Condition.
func (m *AppStatusMatcher) Apply(ctx routing.Context) bool {
status := ctx.GetAppStatus()
if len(status) == 0 {
return false
}
for _, s := range status {
if !m.appStatus[s] {
return false
}
}
return true
}

View File

@@ -1,49 +1,81 @@
package router package router
import ( import (
"net/netip" "encoding/binary"
"strconv" "sort"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"go4.org/netipx"
) )
type ipv6 struct {
a uint64
b uint64
}
type GeoIPMatcher struct { type GeoIPMatcher struct {
countryCode string countryCode string
reverseMatch bool reverseMatch bool
ip4 *netipx.IPSet ip4 []uint32
ip6 *netipx.IPSet prefix4 []uint8
ip6 []ipv6
prefix6 []uint8
}
func normalize4(ip uint32, prefix uint8) uint32 {
return (ip >> (32 - prefix)) << (32 - prefix)
}
func normalize6(ip ipv6, prefix uint8) ipv6 {
if prefix <= 64 {
ip.a = (ip.a >> (64 - prefix)) << (64 - prefix)
ip.b = 0
} else {
ip.b = (ip.b >> (128 - prefix)) << (128 - prefix)
}
return ip
} }
func (m *GeoIPMatcher) Init(cidrs []*CIDR) error { func (m *GeoIPMatcher) Init(cidrs []*CIDR) error {
var builder4, builder6 netipx.IPSetBuilder ip4Count := 0
ip6Count := 0
for _, cidr := range cidrs { for _, cidr := range cidrs {
ip := net.IP(cidr.GetIp()) ip := cidr.Ip
ipPrefixString := ip.String() + "/" + strconv.Itoa(int(cidr.GetPrefix()))
ipPrefix, err := netip.ParsePrefix(ipPrefixString)
if err != nil {
return err
}
switch len(ip) { switch len(ip) {
case net.IPv4len: case 4:
builder4.AddPrefix(ipPrefix) ip4Count++
case net.IPv6len: case 16:
builder6.AddPrefix(ipPrefix) ip6Count++
default:
return newError("unexpect ip length: ", len(ip))
} }
} }
if ip4, err := builder4.IPSet(); err != nil { cidrList := CIDRList(cidrs)
return err sort.Sort(&cidrList)
} else {
m.ip4 = ip4
}
if ip6, err := builder6.IPSet(); err != nil { m.ip4 = make([]uint32, 0, ip4Count)
return err m.prefix4 = make([]uint8, 0, ip4Count)
} else { m.ip6 = make([]ipv6, 0, ip6Count)
m.ip6 = ip6 m.prefix6 = make([]uint8, 0, ip6Count)
for _, cidr := range cidrList {
ip := cidr.Ip
prefix := uint8(cidr.Prefix)
switch len(ip) {
case 4:
m.ip4 = append(m.ip4, normalize4(binary.BigEndian.Uint32(ip), prefix))
m.prefix4 = append(m.prefix4, prefix)
case 16:
ip6 := ipv6{
a: binary.BigEndian.Uint64(ip[0:8]),
b: binary.BigEndian.Uint64(ip[8:16]),
}
ip6 = normalize6(ip6, prefix)
m.ip6 = append(m.ip6, ip6)
m.prefix6 = append(m.prefix6, prefix)
}
} }
return nil return nil
@@ -53,37 +85,91 @@ func (m *GeoIPMatcher) SetReverseMatch(isReverseMatch bool) {
m.reverseMatch = isReverseMatch m.reverseMatch = isReverseMatch
} }
func (m *GeoIPMatcher) match4(ip net.IP) bool { func (m *GeoIPMatcher) match4(ip uint32) bool {
nip, ok := netipx.FromStdIP(ip) if len(m.ip4) == 0 {
if !ok {
return false return false
} }
return m.ip4.Contains(nip) if ip < m.ip4[0] {
return false
}
size := uint32(len(m.ip4))
l := uint32(0)
r := size
for l < r {
x := ((l + r) >> 1)
if ip < m.ip4[x] {
r = x
continue
}
nip := normalize4(ip, m.prefix4[x])
if nip == m.ip4[x] {
return true
}
l = x + 1
}
return l > 0 && normalize4(ip, m.prefix4[l-1]) == m.ip4[l-1]
} }
func (m *GeoIPMatcher) match6(ip net.IP) bool { func less6(a ipv6, b ipv6) bool {
nip, ok := netipx.FromStdIP(ip) return a.a < b.a || (a.a == b.a && a.b < b.b)
if !ok { }
func (m *GeoIPMatcher) match6(ip ipv6) bool {
if len(m.ip6) == 0 {
return false return false
} }
return m.ip6.Contains(nip) if less6(ip, m.ip6[0]) {
return false
}
size := uint32(len(m.ip6))
l := uint32(0)
r := size
for l < r {
x := (l + r) / 2
if less6(ip, m.ip6[x]) {
r = x
continue
}
if normalize6(ip, m.prefix6[x]) == m.ip6[x] {
return true
}
l = x + 1
}
return l > 0 && normalize6(ip, m.prefix6[l-1]) == m.ip6[l-1]
} }
// Match returns true if the given ip is included by the GeoIP. // Match returns true if the given ip is included by the GeoIP.
func (m *GeoIPMatcher) Match(ip net.IP) bool { func (m *GeoIPMatcher) Match(ip net.IP) bool {
isMatched := false
switch len(ip) { switch len(ip) {
case net.IPv4len: case 4:
isMatched = m.match4(ip) if m.reverseMatch {
case net.IPv6len: return !m.match4(binary.BigEndian.Uint32(ip))
isMatched = m.match6(ip) }
return m.match4(binary.BigEndian.Uint32(ip))
case 16:
if m.reverseMatch {
return !m.match6(ipv6{
a: binary.BigEndian.Uint64(ip[0:8]),
b: binary.BigEndian.Uint64(ip[8:16]),
})
}
return m.match6(ipv6{
a: binary.BigEndian.Uint64(ip[0:8]),
b: binary.BigEndian.Uint64(ip[8:16]),
})
default:
return false
} }
if m.reverseMatch {
return !isMatched
}
return isMatched
} }
// GeoIPMatcherContainer is a container for GeoIPMatchers. It keeps unique copies of GeoIPMatcher by country code. // GeoIPMatcherContainer is a container for GeoIPMatchers. It keeps unique copies of GeoIPMatcher by country code.

View File

@@ -5,12 +5,13 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/app/router" "github.com/xtls/xray-core/app/router"
"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/platform" "github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/common/platform/filesystem" "github.com/xtls/xray-core/common/platform/filesystem"
"google.golang.org/protobuf/proto"
) )
func init() { func init() {
@@ -53,7 +54,7 @@ func TestGeoIPMatcherContainer(t *testing.T) {
} }
func TestGeoIPMatcher(t *testing.T) { func TestGeoIPMatcher(t *testing.T) {
cidrList := []*router.CIDR{ cidrList := router.CIDRList{
{Ip: []byte{0, 0, 0, 0}, Prefix: 8}, {Ip: []byte{0, 0, 0, 0}, Prefix: 8},
{Ip: []byte{10, 0, 0, 0}, Prefix: 8}, {Ip: []byte{10, 0, 0, 0}, Prefix: 8},
{Ip: []byte{100, 64, 0, 0}, Prefix: 10}, {Ip: []byte{100, 64, 0, 0}, Prefix: 10},
@@ -124,40 +125,8 @@ func TestGeoIPMatcher(t *testing.T) {
} }
} }
func TestGeoIPMatcherRegression(t *testing.T) {
cidrList := []*router.CIDR{
{Ip: []byte{98, 108, 20, 0}, Prefix: 22},
{Ip: []byte{98, 108, 20, 0}, Prefix: 23},
}
matcher := &router.GeoIPMatcher{}
common.Must(matcher.Init(cidrList))
testCases := []struct {
Input string
Output bool
}{
{
Input: "98.108.22.11",
Output: true,
},
{
Input: "98.108.25.0",
Output: false,
},
}
for _, testCase := range testCases {
ip := net.ParseAddress(testCase.Input).IP()
actual := matcher.Match(ip)
if actual != testCase.Output {
t.Error("expect input", testCase.Input, "to be", testCase.Output, ", but actually", actual)
}
}
}
func TestGeoIPReverseMatcher(t *testing.T) { func TestGeoIPReverseMatcher(t *testing.T) {
cidrList := []*router.CIDR{ cidrList := router.CIDRList{
{Ip: []byte{8, 8, 8, 8}, Prefix: 32}, {Ip: []byte{8, 8, 8, 8}, Prefix: 32},
{Ip: []byte{91, 108, 4, 0}, Prefix: 16}, {Ip: []byte{91, 108, 4, 0}, Prefix: 16},
} }

View File

@@ -6,6 +6,8 @@ import (
"strconv" "strconv"
"testing" "testing"
"github.com/golang/protobuf/proto"
. "github.com/xtls/xray-core/app/router" . "github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
@@ -17,7 +19,6 @@ import (
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
routing_session "github.com/xtls/xray-core/features/routing/session" routing_session "github.com/xtls/xray-core/features/routing/session"
"google.golang.org/protobuf/proto"
) )
func init() { func init() {
@@ -307,10 +308,8 @@ func TestRoutingRule(t *testing.T) {
}, },
{ {
rule: &RoutingRule{ rule: &RoutingRule{
Protocol: []string{"http"}, Protocol: []string{"http"},
Attributes: map[string]string{ Attributes: "attrs[':path'].startswith('/test')",
":path": "/test",
},
}, },
test: []ruleTest{ test: []ruleTest{
{ {
@@ -319,19 +318,6 @@ func TestRoutingRule(t *testing.T) {
}, },
}, },
}, },
{
rule: &RoutingRule{
Attributes: map[string]string{
"Custom": "p([a-z]+)ch",
},
},
test: []ruleTest{
{
input: withContent(&session.Content{Attributes: map[string]string{"custom": "peach"}}),
output: true,
},
},
},
} }
for _, test := range cases { for _, test := range cases {

View File

@@ -1,17 +1,52 @@
package router package router
import ( import (
"regexp"
"strings"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
) )
// CIDRList is an alias of []*CIDR to provide sort.Interface.
type CIDRList []*CIDR
// Len implements sort.Interface.
func (l *CIDRList) Len() int {
return len(*l)
}
// Less implements sort.Interface.
func (l *CIDRList) Less(i int, j int) bool {
ci := (*l)[i]
cj := (*l)[j]
if len(ci.Ip) < len(cj.Ip) {
return true
}
if len(ci.Ip) > len(cj.Ip) {
return false
}
for k := 0; k < len(ci.Ip); k++ {
if ci.Ip[k] < cj.Ip[k] {
return true
}
if ci.Ip[k] > cj.Ip[k] {
return false
}
}
return ci.Prefix < cj.Prefix
}
// Swap implements sort.Interface.
func (l *CIDRList) Swap(i int, j int) {
(*l)[i], (*l)[j] = (*l)[j], (*l)[i]
}
type Rule struct { type Rule struct {
Tag string Tag string
RuleTag string
Balancer *Balancer Balancer *Balancer
Condition Condition Condition Condition
} }
@@ -108,11 +143,19 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
} }
if len(rr.Attributes) > 0 { if len(rr.Attributes) > 0 {
configuredKeys := make(map[string]*regexp.Regexp) cond, err := NewAttributeMatcher(rr.Attributes)
for key, value := range rr.Attributes { if err != nil {
configuredKeys[strings.ToLower(key)] = regexp.MustCompile(value) return nil, err
} }
conds.Add(&AttributeMatcher{configuredKeys}) conds.Add(cond)
}
if rr.UidList != nil && len(rr.UidList.Uid) > 0 {
conds.Add(NewUidMatcher(rr.UidList))
}
if len(rr.AppStatus) > 0 {
conds.Add(NewAppStatusMatcher(rr.AppStatus))
} }
if conds.Len() == 0 { if conds.Len() == 0 {
@@ -122,49 +165,10 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
return conds, nil return conds, nil
} }
// Build builds the balancing rule func (br *BalancingRule) Build(ohm outbound.Manager) (*Balancer, error) {
func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatcher) (*Balancer, error) { return &Balancer{
switch strings.ToLower(br.Strategy) { selectors: br.OutboundSelector,
case "leastping": strategy: &RandomStrategy{},
return &Balancer{ ohm: ohm,
selectors: br.OutboundSelector, }, nil
strategy: &LeastPingStrategy{},
fallbackTag: br.FallbackTag,
ohm: ohm,
}, nil
case "roundrobin":
return &Balancer{
selectors: br.OutboundSelector,
strategy: &RoundRobinStrategy{FallbackTag: br.FallbackTag},
fallbackTag: br.FallbackTag,
ohm: ohm,
}, nil
case "leastload":
i, err := br.StrategySettings.GetInstance()
if err != nil {
return nil, err
}
s, ok := i.(*StrategyLeastLoadConfig)
if !ok {
return nil, newError("not a StrategyLeastLoadConfig").AtError()
}
leastLoadStrategy := NewLeastLoadStrategy(s)
return &Balancer{
selectors: br.OutboundSelector,
ohm: ohm,
fallbackTag: br.FallbackTag,
strategy: leastLoadStrategy,
}, nil
case "random":
fallthrough
case "":
return &Balancer{
selectors: br.OutboundSelector,
ohm: ohm,
fallbackTag: br.FallbackTag,
strategy: &RandomStrategy{FallbackTag: br.FallbackTag},
}, nil
default:
return nil, newError("unrecognized balancer type")
}
} }

View File

@@ -1,14 +1,13 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.27.1
// protoc v4.23.1 // protoc v3.18.0
// source: app/router/config.proto // source: app/router/config.proto
package router package router
import ( import (
net "github.com/xtls/xray-core/common/net" net "github.com/xtls/xray-core/common/net"
serial "github.com/xtls/xray-core/common/serial"
protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect" reflect "reflect"
@@ -132,7 +131,7 @@ func (x Config_DomainStrategy) Number() protoreflect.EnumNumber {
// Deprecated: Use Config_DomainStrategy.Descriptor instead. // Deprecated: Use Config_DomainStrategy.Descriptor instead.
func (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) { func (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{10, 0} return file_app_router_config_proto_rawDescGZIP(), []int{8, 0}
} }
// Domain for routing decision. // Domain for routing decision.
@@ -478,17 +477,15 @@ type RoutingRule struct {
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// Types that are assignable to TargetTag: // Types that are assignable to TargetTag:
//
// *RoutingRule_Tag // *RoutingRule_Tag
// *RoutingRule_BalancingTag // *RoutingRule_BalancingTag
TargetTag isRoutingRule_TargetTag `protobuf_oneof:"target_tag"` TargetTag isRoutingRule_TargetTag `protobuf_oneof:"target_tag"`
RuleTag string `protobuf:"bytes,18,opt,name=rule_tag,json=ruleTag,proto3" json:"rule_tag,omitempty"`
// List of domains for target domain matching. // List of domains for target domain matching.
Domain []*Domain `protobuf:"bytes,2,rep,name=domain,proto3" json:"domain,omitempty"` Domain []*Domain `protobuf:"bytes,2,rep,name=domain,proto3" json:"domain,omitempty"`
// List of CIDRs for target IP address matching. // List of CIDRs for target IP address matching.
// Deprecated. Use geoip below. // Deprecated. Use geoip below.
// //
// Deprecated: Marked as deprecated in app/router/config.proto. // Deprecated: Do not use.
Cidr []*CIDR `protobuf:"bytes,3,rep,name=cidr,proto3" json:"cidr,omitempty"` Cidr []*CIDR `protobuf:"bytes,3,rep,name=cidr,proto3" json:"cidr,omitempty"`
// List of GeoIPs for target IP address matching. If this entry exists, the // List of GeoIPs for target IP address matching. If this entry exists, the
// cidr above will have no effect. GeoIP fields with the same country code are // cidr above will have no effect. GeoIP fields with the same country code are
@@ -498,30 +495,32 @@ type RoutingRule struct {
// A range of port [from, to]. If the destination port is in this range, this // A range of port [from, to]. If the destination port is in this range, this
// rule takes effect. Deprecated. Use port_list. // rule takes effect. Deprecated. Use port_list.
// //
// Deprecated: Marked as deprecated in app/router/config.proto. // Deprecated: Do not use.
PortRange *net.PortRange `protobuf:"bytes,4,opt,name=port_range,json=portRange,proto3" json:"port_range,omitempty"` PortRange *net.PortRange `protobuf:"bytes,4,opt,name=port_range,json=portRange,proto3" json:"port_range,omitempty"`
// List of ports. // List of ports.
PortList *net.PortList `protobuf:"bytes,14,opt,name=port_list,json=portList,proto3" json:"port_list,omitempty"` PortList *net.PortList `protobuf:"bytes,14,opt,name=port_list,json=portList,proto3" json:"port_list,omitempty"`
// List of networks. Deprecated. Use networks. // List of networks. Deprecated. Use networks.
// //
// Deprecated: Marked as deprecated in app/router/config.proto. // Deprecated: Do not use.
NetworkList *net.NetworkList `protobuf:"bytes,5,opt,name=network_list,json=networkList,proto3" json:"network_list,omitempty"` NetworkList *net.NetworkList `protobuf:"bytes,5,opt,name=network_list,json=networkList,proto3" json:"network_list,omitempty"`
// List of networks for matching. // List of networks for matching.
Networks []net.Network `protobuf:"varint,13,rep,packed,name=networks,proto3,enum=xray.common.net.Network" json:"networks,omitempty"` Networks []net.Network `protobuf:"varint,13,rep,packed,name=networks,proto3,enum=xray.common.net.Network" json:"networks,omitempty"`
// List of CIDRs for source IP address matching. // List of CIDRs for source IP address matching.
// //
// Deprecated: Marked as deprecated in app/router/config.proto. // Deprecated: Do not use.
SourceCidr []*CIDR `protobuf:"bytes,6,rep,name=source_cidr,json=sourceCidr,proto3" json:"source_cidr,omitempty"` SourceCidr []*CIDR `protobuf:"bytes,6,rep,name=source_cidr,json=sourceCidr,proto3" json:"source_cidr,omitempty"`
// List of GeoIPs for source IP address matching. If this entry exists, the // List of GeoIPs for source IP address matching. If this entry exists, the
// source_cidr above will have no effect. // source_cidr above will have no effect.
SourceGeoip []*GeoIP `protobuf:"bytes,11,rep,name=source_geoip,json=sourceGeoip,proto3" json:"source_geoip,omitempty"` SourceGeoip []*GeoIP `protobuf:"bytes,11,rep,name=source_geoip,json=sourceGeoip,proto3" json:"source_geoip,omitempty"`
// List of ports for source port matching. // List of ports for source port matching.
SourcePortList *net.PortList `protobuf:"bytes,16,opt,name=source_port_list,json=sourcePortList,proto3" json:"source_port_list,omitempty"` SourcePortList *net.PortList `protobuf:"bytes,16,opt,name=source_port_list,json=sourcePortList,proto3" json:"source_port_list,omitempty"`
UserEmail []string `protobuf:"bytes,7,rep,name=user_email,json=userEmail,proto3" json:"user_email,omitempty"` UserEmail []string `protobuf:"bytes,7,rep,name=user_email,json=userEmail,proto3" json:"user_email,omitempty"`
InboundTag []string `protobuf:"bytes,8,rep,name=inbound_tag,json=inboundTag,proto3" json:"inbound_tag,omitempty"` InboundTag []string `protobuf:"bytes,8,rep,name=inbound_tag,json=inboundTag,proto3" json:"inbound_tag,omitempty"`
Protocol []string `protobuf:"bytes,9,rep,name=protocol,proto3" json:"protocol,omitempty"` Protocol []string `protobuf:"bytes,9,rep,name=protocol,proto3" json:"protocol,omitempty"`
Attributes map[string]string `protobuf:"bytes,15,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Attributes string `protobuf:"bytes,15,opt,name=attributes,proto3" json:"attributes,omitempty"`
DomainMatcher string `protobuf:"bytes,17,opt,name=domain_matcher,json=domainMatcher,proto3" json:"domain_matcher,omitempty"` DomainMatcher string `protobuf:"bytes,17,opt,name=domain_matcher,json=domainMatcher,proto3" json:"domain_matcher,omitempty"`
UidList *net.UidList `protobuf:"bytes,18,opt,name=uid_list,json=uidList,proto3" json:"uid_list,omitempty"`
AppStatus []string `protobuf:"bytes,19,rep,name=app_status,json=appStatus,proto3" json:"app_status,omitempty"`
} }
func (x *RoutingRule) Reset() { func (x *RoutingRule) Reset() {
@@ -577,13 +576,6 @@ func (x *RoutingRule) GetBalancingTag() string {
return "" return ""
} }
func (x *RoutingRule) GetRuleTag() string {
if x != nil {
return x.RuleTag
}
return ""
}
func (x *RoutingRule) GetDomain() []*Domain { func (x *RoutingRule) GetDomain() []*Domain {
if x != nil { if x != nil {
return x.Domain return x.Domain
@@ -591,7 +583,7 @@ func (x *RoutingRule) GetDomain() []*Domain {
return nil return nil
} }
// Deprecated: Marked as deprecated in app/router/config.proto. // Deprecated: Do not use.
func (x *RoutingRule) GetCidr() []*CIDR { func (x *RoutingRule) GetCidr() []*CIDR {
if x != nil { if x != nil {
return x.Cidr return x.Cidr
@@ -606,7 +598,7 @@ func (x *RoutingRule) GetGeoip() []*GeoIP {
return nil return nil
} }
// Deprecated: Marked as deprecated in app/router/config.proto. // Deprecated: Do not use.
func (x *RoutingRule) GetPortRange() *net.PortRange { func (x *RoutingRule) GetPortRange() *net.PortRange {
if x != nil { if x != nil {
return x.PortRange return x.PortRange
@@ -621,7 +613,7 @@ func (x *RoutingRule) GetPortList() *net.PortList {
return nil return nil
} }
// Deprecated: Marked as deprecated in app/router/config.proto. // Deprecated: Do not use.
func (x *RoutingRule) GetNetworkList() *net.NetworkList { func (x *RoutingRule) GetNetworkList() *net.NetworkList {
if x != nil { if x != nil {
return x.NetworkList return x.NetworkList
@@ -636,7 +628,7 @@ func (x *RoutingRule) GetNetworks() []net.Network {
return nil return nil
} }
// Deprecated: Marked as deprecated in app/router/config.proto. // Deprecated: Do not use.
func (x *RoutingRule) GetSourceCidr() []*CIDR { func (x *RoutingRule) GetSourceCidr() []*CIDR {
if x != nil { if x != nil {
return x.SourceCidr return x.SourceCidr
@@ -679,11 +671,11 @@ func (x *RoutingRule) GetProtocol() []string {
return nil return nil
} }
func (x *RoutingRule) GetAttributes() map[string]string { func (x *RoutingRule) GetAttributes() string {
if x != nil { if x != nil {
return x.Attributes return x.Attributes
} }
return nil return ""
} }
func (x *RoutingRule) GetDomainMatcher() string { func (x *RoutingRule) GetDomainMatcher() string {
@@ -693,6 +685,20 @@ func (x *RoutingRule) GetDomainMatcher() string {
return "" return ""
} }
func (x *RoutingRule) GetUidList() *net.UidList {
if x != nil {
return x.UidList
}
return nil
}
func (x *RoutingRule) GetAppStatus() []string {
if x != nil {
return x.AppStatus
}
return nil
}
type isRoutingRule_TargetTag interface { type isRoutingRule_TargetTag interface {
isRoutingRule_TargetTag() isRoutingRule_TargetTag()
} }
@@ -716,11 +722,9 @@ type BalancingRule struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"` Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
OutboundSelector []string `protobuf:"bytes,2,rep,name=outbound_selector,json=outboundSelector,proto3" json:"outbound_selector,omitempty"` OutboundSelector []string `protobuf:"bytes,2,rep,name=outbound_selector,json=outboundSelector,proto3" json:"outbound_selector,omitempty"`
Strategy string `protobuf:"bytes,3,opt,name=strategy,proto3" json:"strategy,omitempty"` Strategy string `protobuf:"bytes,3,opt,name=strategy,proto3" json:"strategy,omitempty"`
StrategySettings *serial.TypedMessage `protobuf:"bytes,4,opt,name=strategy_settings,json=strategySettings,proto3" json:"strategy_settings,omitempty"`
FallbackTag string `protobuf:"bytes,5,opt,name=fallback_tag,json=fallbackTag,proto3" json:"fallback_tag,omitempty"`
} }
func (x *BalancingRule) Reset() { func (x *BalancingRule) Reset() {
@@ -776,167 +780,6 @@ func (x *BalancingRule) GetStrategy() string {
return "" return ""
} }
func (x *BalancingRule) GetStrategySettings() *serial.TypedMessage {
if x != nil {
return x.StrategySettings
}
return nil
}
func (x *BalancingRule) GetFallbackTag() string {
if x != nil {
return x.FallbackTag
}
return ""
}
type StrategyWeight struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Regexp bool `protobuf:"varint,1,opt,name=regexp,proto3" json:"regexp,omitempty"`
Match string `protobuf:"bytes,2,opt,name=match,proto3" json:"match,omitempty"`
Value float32 `protobuf:"fixed32,3,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *StrategyWeight) Reset() {
*x = StrategyWeight{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_config_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *StrategyWeight) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StrategyWeight) ProtoMessage() {}
func (x *StrategyWeight) ProtoReflect() protoreflect.Message {
mi := &file_app_router_config_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StrategyWeight.ProtoReflect.Descriptor instead.
func (*StrategyWeight) Descriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{8}
}
func (x *StrategyWeight) GetRegexp() bool {
if x != nil {
return x.Regexp
}
return false
}
func (x *StrategyWeight) GetMatch() string {
if x != nil {
return x.Match
}
return ""
}
func (x *StrategyWeight) GetValue() float32 {
if x != nil {
return x.Value
}
return 0
}
type StrategyLeastLoadConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// weight settings
Costs []*StrategyWeight `protobuf:"bytes,2,rep,name=costs,proto3" json:"costs,omitempty"`
// RTT baselines for selecting, int64 values of time.Duration
Baselines []int64 `protobuf:"varint,3,rep,packed,name=baselines,proto3" json:"baselines,omitempty"`
// expected nodes count to select
Expected int32 `protobuf:"varint,4,opt,name=expected,proto3" json:"expected,omitempty"`
// max acceptable rtt, filter away high delay nodes. default 0
MaxRTT int64 `protobuf:"varint,5,opt,name=maxRTT,proto3" json:"maxRTT,omitempty"`
// acceptable failure rate
Tolerance float32 `protobuf:"fixed32,6,opt,name=tolerance,proto3" json:"tolerance,omitempty"`
}
func (x *StrategyLeastLoadConfig) Reset() {
*x = StrategyLeastLoadConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_config_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *StrategyLeastLoadConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StrategyLeastLoadConfig) ProtoMessage() {}
func (x *StrategyLeastLoadConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_router_config_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StrategyLeastLoadConfig.ProtoReflect.Descriptor instead.
func (*StrategyLeastLoadConfig) Descriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{9}
}
func (x *StrategyLeastLoadConfig) GetCosts() []*StrategyWeight {
if x != nil {
return x.Costs
}
return nil
}
func (x *StrategyLeastLoadConfig) GetBaselines() []int64 {
if x != nil {
return x.Baselines
}
return nil
}
func (x *StrategyLeastLoadConfig) GetExpected() int32 {
if x != nil {
return x.Expected
}
return 0
}
func (x *StrategyLeastLoadConfig) GetMaxRTT() int64 {
if x != nil {
return x.MaxRTT
}
return 0
}
func (x *StrategyLeastLoadConfig) GetTolerance() float32 {
if x != nil {
return x.Tolerance
}
return 0
}
type Config struct { type Config struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -950,7 +793,7 @@ type Config struct {
func (x *Config) Reset() { func (x *Config) Reset() {
*x = Config{} *x = Config{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_app_router_config_proto_msgTypes[10] mi := &file_app_router_config_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -963,7 +806,7 @@ func (x *Config) String() string {
func (*Config) ProtoMessage() {} func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message { func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_router_config_proto_msgTypes[10] mi := &file_app_router_config_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -976,7 +819,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
// Deprecated: Use Config.ProtoReflect.Descriptor instead. // Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) { func (*Config) Descriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{10} return file_app_router_config_proto_rawDescGZIP(), []int{8}
} }
func (x *Config) GetDomainStrategy() Config_DomainStrategy { func (x *Config) GetDomainStrategy() Config_DomainStrategy {
@@ -1007,7 +850,6 @@ type Domain_Attribute struct {
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
// Types that are assignable to TypedValue: // Types that are assignable to TypedValue:
//
// *Domain_Attribute_BoolValue // *Domain_Attribute_BoolValue
// *Domain_Attribute_IntValue // *Domain_Attribute_IntValue
TypedValue isDomain_Attribute_TypedValue `protobuf_oneof:"typed_value"` TypedValue isDomain_Attribute_TypedValue `protobuf_oneof:"typed_value"`
@@ -1016,7 +858,7 @@ type Domain_Attribute struct {
func (x *Domain_Attribute) Reset() { func (x *Domain_Attribute) Reset() {
*x = Domain_Attribute{} *x = Domain_Attribute{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_app_router_config_proto_msgTypes[11] mi := &file_app_router_config_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1029,7 +871,7 @@ func (x *Domain_Attribute) String() string {
func (*Domain_Attribute) ProtoMessage() {} func (*Domain_Attribute) ProtoMessage() {}
func (x *Domain_Attribute) ProtoReflect() protoreflect.Message { func (x *Domain_Attribute) ProtoReflect() protoreflect.Message {
mi := &file_app_router_config_proto_msgTypes[11] mi := &file_app_router_config_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1094,171 +936,142 @@ var File_app_router_config_proto protoreflect.FileDescriptor
var file_app_router_config_proto_rawDesc = []byte{ var file_app_router_config_proto_rawDesc = []byte{
0x0a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e, 0x0a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x1a, 0x15, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x63, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x70, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x63, 0x6f, 0x6d,
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x75, 0x69, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb3, 0x6f, 0x22, 0xb3, 0x02, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x30, 0x0a, 0x04,
0x02, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x30, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d,
0x61, 0x69, 0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x12, 0x3f, 0x0a, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72,
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x69, 0x62, 0x75, 0x74, 0x65, 0x1a, 0x6c, 0x0a, 0x09, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
0x65, 0x12, 0x3f, 0x0a, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x03, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1f, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c,
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x41, 0x74, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c,
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c,
0x74, 0x65, 0x1a, 0x6c, 0x0a, 0x09, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x56,
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x76, 0x61,
0x79, 0x12, 0x1f, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x6c, 0x75, 0x65, 0x22, 0x32, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x50,
0x02, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x6c, 0x61, 0x69, 0x6e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10,
0x75, 0x65, 0x12, 0x1d, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x02, 0x12, 0x08, 0x0a,
0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x03, 0x22, 0x2e, 0x0a, 0x04, 0x43, 0x49, 0x44, 0x52, 0x12,
0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12,
0x22, 0x32, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x6c, 0x61, 0x69, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x6e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x01, 0x12, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x7a, 0x0a, 0x05, 0x47, 0x65, 0x6f, 0x49, 0x50,
0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65,
0x6c, 0x6c, 0x10, 0x03, 0x22, 0x2e, 0x0a, 0x04, 0x43, 0x49, 0x44, 0x52, 0x12, 0x0e, 0x0a, 0x02, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43,
0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x64, 0x65, 0x12, 0x29, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28,
0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x0b, 0x32, 0x15, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
0x65, 0x66, 0x69, 0x78, 0x22, 0x7a, 0x0a, 0x05, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x12, 0x21, 0x0a, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x12, 0x23,
0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x0a, 0x0d, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18,
0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x4d, 0x61,
0x12, 0x29, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x74, 0x63, 0x68, 0x22, 0x39, 0x0a, 0x09, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x4c, 0x69, 0x73, 0x74,
0x12, 0x2c, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x5d,
0x0a, 0x07, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x2f, 0x0a, 0x06,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x3d, 0x0a,
0x0b, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x05,
0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65,
0x6f, 0x53, 0x69, 0x74, 0x65, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x89, 0x07, 0x0a,
0x0b, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x03,
0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x74, 0x61, 0x67,
0x12, 0x25, 0x0a, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61,
0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e,
0x63, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x12, 0x2f, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x2d, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72,
0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x42, 0x02, 0x18,
0x01, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x12, 0x2c, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70,
0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05,
0x67, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x3d, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72, 0x61,
0x6e, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74,
0x52, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52,
0x61, 0x6e, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73,
0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69,
0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x43, 0x0a, 0x0c,
0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69, 0x73, 0x74,
0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69, 0x73,
0x74, 0x12, 0x34, 0x0a, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x0d, 0x20,
0x03, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x08, 0x6e,
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3a, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43,
0x49, 0x44, 0x52, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43,
0x69, 0x64, 0x72, 0x12, 0x39, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, 0x65,
0x6f, 0x69, 0x70, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49,
0x50, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x43,
0x0a, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69,
0x73, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4c,
0x69, 0x73, 0x74, 0x52, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x4c,
0x69, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69,
0x6c, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61,
0x69, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x61,
0x67, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x54, 0x61, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18,
0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12,
0x1e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0f, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12,
0x25, 0x0a, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65,
0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d,
0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x08, 0x75, 0x69, 0x64, 0x5f, 0x6c, 0x69,
0x73, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x55, 0x69, 0x64, 0x4c, 0x69,
0x73, 0x74, 0x52, 0x07, 0x75, 0x69, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61,
0x70, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x09, 0x52,
0x09, 0x61, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x74, 0x61,
0x72, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x22, 0x6a, 0x0a, 0x0d, 0x42, 0x61, 0x6c, 0x61,
0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b, 0x0a, 0x11, 0x6f,
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72,
0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x61,
0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x74, 0x72, 0x61,
0x74, 0x65, 0x67, 0x79, 0x22, 0x9b, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x4f, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
0x12, 0x30, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c,
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
0x2e, 0x43, 0x49, 0x44, 0x52, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x75,
0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x6c, 0x65, 0x12, 0x45, 0x0a, 0x0e, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f,
0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x78, 0x72, 0x61,
0x22, 0x39, 0x0a, 0x09, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x6c,
0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x62, 0x61, 0x6c, 0x61,
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x22, 0x47, 0x0a, 0x0e, 0x44, 0x6f, 0x6d,
0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x5d, 0x0a, 0x07, 0x47, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x41,
0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x73, 0x49, 0x73, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x49, 0x70, 0x10, 0x01,
0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x70, 0x49, 0x66, 0x4e, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68,
0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x70, 0x4f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64,
0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x10, 0x03, 0x42, 0x4f, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x24, 0x67, 0x69, 0x74,
0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x3d, 0x0a, 0x0b, 0x47, 0x65, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
0x6f, 0x53, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65,
0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x72, 0xaa, 0x02, 0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75,
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x74, 0x65, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xbd, 0x07, 0x0a, 0x0b, 0x52, 0x6f,
0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x03, 0x74, 0x61, 0x67,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x25, 0x0a,
0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x0c,
0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e,
0x67, 0x54, 0x61, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x61, 0x67,
0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x67, 0x12,
0x2f, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x17, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x12, 0x2d, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15,
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
0x2e, 0x43, 0x49, 0x44, 0x52, 0x42, 0x02, 0x18, 0x01, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x12,
0x2c, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16,
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x3d, 0x0a,
0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x02, 0x18,
0x01, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x09,
0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74,
0x4c, 0x69, 0x73, 0x74, 0x12, 0x43, 0x0a, 0x0c, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f,
0x6c, 0x69, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74,
0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6e, 0x65,
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x08, 0x6e, 0x65, 0x74,
0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65,
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12,
0x3a, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x06,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x42, 0x02, 0x18, 0x01, 0x52,
0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x69, 0x64, 0x72, 0x12, 0x39, 0x0a, 0x0c, 0x73,
0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0b, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x43, 0x0a, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e,
0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0e, 0x73, 0x6f, 0x75,
0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75,
0x73, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52,
0x09, 0x75, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e,
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52,
0x0a, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x4c, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69,
0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52, 0x6f,
0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62,
0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69,
0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f,
0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x1a, 0x3d, 0x0a, 0x0f,
0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x74,
0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x22, 0xdc, 0x01, 0x0a, 0x0d, 0x42, 0x61,
0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74,
0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b, 0x0a,
0x11, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74,
0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75,
0x6e, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x74,
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x74,
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4d, 0x0a, 0x11, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
0x67, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 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, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x52, 0x10, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x53, 0x65, 0x74,
0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
0x6b, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x66, 0x61, 0x6c,
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x54, 0x61, 0x67, 0x22, 0x54, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x61,
0x74, 0x65, 0x67, 0x79, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65,
0x67, 0x65, 0x78, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x67, 0x65,
0x78, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xc0,
0x01, 0x0a, 0x17, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x4c, 0x65, 0x61, 0x73, 0x74,
0x4c, 0x6f, 0x61, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x05, 0x63, 0x6f,
0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x72, 0x61,
0x74, 0x65, 0x67, 0x79, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x05, 0x63, 0x6f, 0x73, 0x74,
0x73, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x03,
0x20, 0x03, 0x28, 0x03, 0x52, 0x09, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x12,
0x1a, 0x0a, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
0x05, 0x52, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d,
0x61, 0x78, 0x52, 0x54, 0x54, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6d, 0x61, 0x78,
0x52, 0x54, 0x54, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65,
0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63,
0x65, 0x22, 0x9b, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4f, 0x0a, 0x0f,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x30, 0x0a,
0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52, 0x6f,
0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12,
0x45, 0x0a, 0x0e, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6c,
0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63,
0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69,
0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x22, 0x47, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49, 0x73,
0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x49, 0x70, 0x10, 0x01, 0x12, 0x10, 0x0a,
0x0c, 0x49, 0x70, 0x49, 0x66, 0x4e, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x02, 0x12,
0x0e, 0x0a, 0x0a, 0x49, 0x70, 0x4f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x10, 0x03, 0x42,
0x4f, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x24, 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, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0xaa, 0x02,
0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@@ -1274,32 +1087,29 @@ func file_app_router_config_proto_rawDescGZIP() []byte {
} }
var file_app_router_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_app_router_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_app_router_config_proto_msgTypes = make([]protoimpl.MessageInfo, 13) var file_app_router_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_app_router_config_proto_goTypes = []interface{}{ var file_app_router_config_proto_goTypes = []interface{}{
(Domain_Type)(0), // 0: xray.app.router.Domain.Type (Domain_Type)(0), // 0: xray.app.router.Domain.Type
(Config_DomainStrategy)(0), // 1: xray.app.router.Config.DomainStrategy (Config_DomainStrategy)(0), // 1: xray.app.router.Config.DomainStrategy
(*Domain)(nil), // 2: xray.app.router.Domain (*Domain)(nil), // 2: xray.app.router.Domain
(*CIDR)(nil), // 3: xray.app.router.CIDR (*CIDR)(nil), // 3: xray.app.router.CIDR
(*GeoIP)(nil), // 4: xray.app.router.GeoIP (*GeoIP)(nil), // 4: xray.app.router.GeoIP
(*GeoIPList)(nil), // 5: xray.app.router.GeoIPList (*GeoIPList)(nil), // 5: xray.app.router.GeoIPList
(*GeoSite)(nil), // 6: xray.app.router.GeoSite (*GeoSite)(nil), // 6: xray.app.router.GeoSite
(*GeoSiteList)(nil), // 7: xray.app.router.GeoSiteList (*GeoSiteList)(nil), // 7: xray.app.router.GeoSiteList
(*RoutingRule)(nil), // 8: xray.app.router.RoutingRule (*RoutingRule)(nil), // 8: xray.app.router.RoutingRule
(*BalancingRule)(nil), // 9: xray.app.router.BalancingRule (*BalancingRule)(nil), // 9: xray.app.router.BalancingRule
(*StrategyWeight)(nil), // 10: xray.app.router.StrategyWeight (*Config)(nil), // 10: xray.app.router.Config
(*StrategyLeastLoadConfig)(nil), // 11: xray.app.router.StrategyLeastLoadConfig (*Domain_Attribute)(nil), // 11: xray.app.router.Domain.Attribute
(*Config)(nil), // 12: xray.app.router.Config (*net.PortRange)(nil), // 12: xray.common.net.PortRange
(*Domain_Attribute)(nil), // 13: xray.app.router.Domain.Attribute (*net.PortList)(nil), // 13: xray.common.net.PortList
nil, // 14: xray.app.router.RoutingRule.AttributesEntry (*net.NetworkList)(nil), // 14: xray.common.net.NetworkList
(*net.PortRange)(nil), // 15: xray.common.net.PortRange (net.Network)(0), // 15: xray.common.net.Network
(*net.PortList)(nil), // 16: xray.common.net.PortList (*net.UidList)(nil), // 16: xray.common.net.UidList
(*net.NetworkList)(nil), // 17: xray.common.net.NetworkList
(net.Network)(0), // 18: xray.common.net.Network
(*serial.TypedMessage)(nil), // 19: xray.common.serial.TypedMessage
} }
var file_app_router_config_proto_depIdxs = []int32{ var file_app_router_config_proto_depIdxs = []int32{
0, // 0: xray.app.router.Domain.type:type_name -> xray.app.router.Domain.Type 0, // 0: xray.app.router.Domain.type:type_name -> xray.app.router.Domain.Type
13, // 1: xray.app.router.Domain.attribute:type_name -> xray.app.router.Domain.Attribute 11, // 1: xray.app.router.Domain.attribute:type_name -> xray.app.router.Domain.Attribute
3, // 2: xray.app.router.GeoIP.cidr:type_name -> xray.app.router.CIDR 3, // 2: xray.app.router.GeoIP.cidr:type_name -> xray.app.router.CIDR
4, // 3: xray.app.router.GeoIPList.entry:type_name -> xray.app.router.GeoIP 4, // 3: xray.app.router.GeoIPList.entry:type_name -> xray.app.router.GeoIP
2, // 4: xray.app.router.GeoSite.domain:type_name -> xray.app.router.Domain 2, // 4: xray.app.router.GeoSite.domain:type_name -> xray.app.router.Domain
@@ -1307,24 +1117,22 @@ var file_app_router_config_proto_depIdxs = []int32{
2, // 6: xray.app.router.RoutingRule.domain:type_name -> xray.app.router.Domain 2, // 6: xray.app.router.RoutingRule.domain:type_name -> xray.app.router.Domain
3, // 7: xray.app.router.RoutingRule.cidr:type_name -> xray.app.router.CIDR 3, // 7: xray.app.router.RoutingRule.cidr:type_name -> xray.app.router.CIDR
4, // 8: xray.app.router.RoutingRule.geoip:type_name -> xray.app.router.GeoIP 4, // 8: xray.app.router.RoutingRule.geoip:type_name -> xray.app.router.GeoIP
15, // 9: xray.app.router.RoutingRule.port_range:type_name -> xray.common.net.PortRange 12, // 9: xray.app.router.RoutingRule.port_range:type_name -> xray.common.net.PortRange
16, // 10: xray.app.router.RoutingRule.port_list:type_name -> xray.common.net.PortList 13, // 10: xray.app.router.RoutingRule.port_list:type_name -> xray.common.net.PortList
17, // 11: xray.app.router.RoutingRule.network_list:type_name -> xray.common.net.NetworkList 14, // 11: xray.app.router.RoutingRule.network_list:type_name -> xray.common.net.NetworkList
18, // 12: xray.app.router.RoutingRule.networks:type_name -> xray.common.net.Network 15, // 12: xray.app.router.RoutingRule.networks:type_name -> xray.common.net.Network
3, // 13: xray.app.router.RoutingRule.source_cidr:type_name -> xray.app.router.CIDR 3, // 13: xray.app.router.RoutingRule.source_cidr:type_name -> xray.app.router.CIDR
4, // 14: xray.app.router.RoutingRule.source_geoip:type_name -> xray.app.router.GeoIP 4, // 14: xray.app.router.RoutingRule.source_geoip:type_name -> xray.app.router.GeoIP
16, // 15: xray.app.router.RoutingRule.source_port_list:type_name -> xray.common.net.PortList 13, // 15: xray.app.router.RoutingRule.source_port_list:type_name -> xray.common.net.PortList
14, // 16: xray.app.router.RoutingRule.attributes:type_name -> xray.app.router.RoutingRule.AttributesEntry 16, // 16: xray.app.router.RoutingRule.uid_list:type_name -> xray.common.net.UidList
19, // 17: xray.app.router.BalancingRule.strategy_settings:type_name -> xray.common.serial.TypedMessage 1, // 17: xray.app.router.Config.domain_strategy:type_name -> xray.app.router.Config.DomainStrategy
10, // 18: xray.app.router.StrategyLeastLoadConfig.costs:type_name -> xray.app.router.StrategyWeight 8, // 18: xray.app.router.Config.rule:type_name -> xray.app.router.RoutingRule
1, // 19: xray.app.router.Config.domain_strategy:type_name -> xray.app.router.Config.DomainStrategy 9, // 19: xray.app.router.Config.balancing_rule:type_name -> xray.app.router.BalancingRule
8, // 20: xray.app.router.Config.rule:type_name -> xray.app.router.RoutingRule 20, // [20:20] is the sub-list for method output_type
9, // 21: xray.app.router.Config.balancing_rule:type_name -> xray.app.router.BalancingRule 20, // [20:20] is the sub-list for method input_type
22, // [22:22] is the sub-list for method output_type 20, // [20:20] is the sub-list for extension type_name
22, // [22:22] is the sub-list for method input_type 20, // [20:20] is the sub-list for extension extendee
22, // [22:22] is the sub-list for extension type_name 0, // [0:20] is the sub-list for field type_name
22, // [22:22] is the sub-list for extension extendee
0, // [0:22] is the sub-list for field type_name
} }
func init() { file_app_router_config_proto_init() } func init() { file_app_router_config_proto_init() }
@@ -1430,30 +1238,6 @@ func file_app_router_config_proto_init() {
} }
} }
file_app_router_config_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { file_app_router_config_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*StrategyWeight); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_router_config_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*StrategyLeastLoadConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_router_config_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i { switch v := v.(*Config); i {
case 0: case 0:
return &v.state return &v.state
@@ -1465,7 +1249,7 @@ func file_app_router_config_proto_init() {
return nil return nil
} }
} }
file_app_router_config_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { file_app_router_config_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Domain_Attribute); i { switch v := v.(*Domain_Attribute); i {
case 0: case 0:
return &v.state return &v.state
@@ -1482,7 +1266,7 @@ func file_app_router_config_proto_init() {
(*RoutingRule_Tag)(nil), (*RoutingRule_Tag)(nil),
(*RoutingRule_BalancingTag)(nil), (*RoutingRule_BalancingTag)(nil),
} }
file_app_router_config_proto_msgTypes[11].OneofWrappers = []interface{}{ file_app_router_config_proto_msgTypes[9].OneofWrappers = []interface{}{
(*Domain_Attribute_BoolValue)(nil), (*Domain_Attribute_BoolValue)(nil),
(*Domain_Attribute_IntValue)(nil), (*Domain_Attribute_IntValue)(nil),
} }
@@ -1492,7 +1276,7 @@ func file_app_router_config_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_router_config_proto_rawDesc, RawDescriptor: file_app_router_config_proto_rawDesc,
NumEnums: 2, NumEnums: 2,
NumMessages: 13, NumMessages: 10,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View File

@@ -6,9 +6,9 @@ option go_package = "github.com/xtls/xray-core/app/router";
option java_package = "com.xray.app.router"; option java_package = "com.xray.app.router";
option java_multiple_files = true; option java_multiple_files = true;
import "common/serial/typed_message.proto";
import "common/net/port.proto"; import "common/net/port.proto";
import "common/net/network.proto"; import "common/net/network.proto";
import "common/net/uid.proto";
// Domain for routing decision. // Domain for routing decision.
message Domain { message Domain {
@@ -79,7 +79,6 @@ message RoutingRule {
// Tag of routing balancer. // Tag of routing balancer.
string balancing_tag = 12; string balancing_tag = 12;
} }
string rule_tag = 18;
// List of domains for target domain matching. // List of domains for target domain matching.
repeated Domain domain = 2; repeated Domain domain = 2;
@@ -121,36 +120,19 @@ message RoutingRule {
repeated string inbound_tag = 8; repeated string inbound_tag = 8;
repeated string protocol = 9; repeated string protocol = 9;
map<string, string> attributes = 15; string attributes = 15;
string domain_matcher = 17; string domain_matcher = 17;
xray.common.net.UidList uid_list = 18;
repeated string app_status = 19;
} }
message BalancingRule { message BalancingRule {
string tag = 1; string tag = 1;
repeated string outbound_selector = 2; repeated string outbound_selector = 2;
string strategy = 3; string strategy = 3;
xray.common.serial.TypedMessage strategy_settings = 4;
string fallback_tag = 5;
}
message StrategyWeight {
bool regexp = 1;
string match = 2;
float value =3;
}
message StrategyLeastLoadConfig {
// weight settings
repeated StrategyWeight costs = 2;
// RTT baselines for selecting, int64 values of time.Duration
repeated int64 baselines = 3;
// expected nodes count to select
int32 expected = 4;
// max acceptable rtt, filter away high delay nodes. default 0
int64 maxRTT = 5;
// acceptable failure rate
float tolerance = 6;
} }
message Config { message Config {

View File

@@ -4,10 +4,8 @@ package router
import ( import (
"context" "context"
sync "sync"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
@@ -21,11 +19,6 @@ type Router struct {
rules []*Rule rules []*Rule
balancers map[string]*Balancer balancers map[string]*Balancer
dns dns.Client dns dns.Client
ctx context.Context
ohm outbound.Manager
dispatcher routing.Dispatcher
mu sync.Mutex
} }
// Route is an implementation of routing.Route. // Route is an implementation of routing.Route.
@@ -36,20 +29,16 @@ type Route struct {
} }
// Init initializes the Router. // Init initializes the Router.
func (r *Router) Init(ctx context.Context, config *Config, d dns.Client, ohm outbound.Manager, dispatcher routing.Dispatcher) error { func (r *Router) Init(config *Config, d dns.Client, ohm outbound.Manager) error {
r.domainStrategy = config.DomainStrategy r.domainStrategy = config.DomainStrategy
r.dns = d r.dns = d
r.ctx = ctx
r.ohm = ohm
r.dispatcher = dispatcher
r.balancers = make(map[string]*Balancer, len(config.BalancingRule)) r.balancers = make(map[string]*Balancer, len(config.BalancingRule))
for _, rule := range config.BalancingRule { for _, rule := range config.BalancingRule {
balancer, err := rule.Build(ohm, dispatcher) balancer, err := rule.Build(ohm)
if err != nil { if err != nil {
return err return err
} }
balancer.InjectContext(ctx)
r.balancers[rule.Tag] = balancer r.balancers[rule.Tag] = balancer
} }
@@ -62,7 +51,6 @@ func (r *Router) Init(ctx context.Context, config *Config, d dns.Client, ohm out
rr := &Rule{ rr := &Rule{
Condition: cond, Condition: cond,
Tag: rule.GetTag(), Tag: rule.GetTag(),
RuleTag: rule.GetRuleTag(),
} }
btag := rule.GetBalancingTag() btag := rule.GetBalancingTag()
if len(btag) > 0 { if len(btag) > 0 {
@@ -91,96 +79,6 @@ func (r *Router) PickRoute(ctx routing.Context) (routing.Route, error) {
return &Route{Context: ctx, outboundTag: tag}, nil return &Route{Context: ctx, outboundTag: tag}, nil
} }
// AddRule implements routing.Router.
func (r *Router) AddRule(config *serial.TypedMessage, shouldAppend bool) error {
inst, err := config.GetInstance()
if err != nil {
return err
}
if c, ok := inst.(*Config); ok {
return r.ReloadRules(c, shouldAppend)
}
return newError("AddRule: config type error")
}
func (r *Router) ReloadRules(config *Config, shouldAppend bool) error {
r.mu.Lock()
defer r.mu.Unlock()
if !shouldAppend {
r.balancers = make(map[string]*Balancer, len(config.BalancingRule))
r.rules = make([]*Rule, 0, len(config.Rule))
}
for _, rule := range config.BalancingRule {
_, found := r.balancers[rule.Tag]
if found {
return newError("duplicate balancer tag")
}
balancer, err := rule.Build(r.ohm, r.dispatcher)
if err != nil {
return err
}
balancer.InjectContext(r.ctx)
r.balancers[rule.Tag] = balancer
}
for _, rule := range config.Rule {
if r.RuleExists(rule.GetRuleTag()) {
return newError("duplicate ruleTag ", rule.GetRuleTag())
}
cond, err := rule.BuildCondition()
if err != nil {
return err
}
rr := &Rule{
Condition: cond,
Tag: rule.GetTag(),
RuleTag: rule.GetRuleTag(),
}
btag := rule.GetBalancingTag()
if len(btag) > 0 {
brule, found := r.balancers[btag]
if !found {
return newError("balancer ", btag, " not found")
}
rr.Balancer = brule
}
r.rules = append(r.rules, rr)
}
return nil
}
func (r *Router) RuleExists(tag string) bool {
if tag != "" {
for _, rule := range r.rules {
if rule.RuleTag == tag {
return true
}
}
}
return false
}
// RemoveRule implements routing.Router.
func (r *Router) RemoveRule(tag string) error {
r.mu.Lock()
defer r.mu.Unlock()
newRules := []*Rule{}
if tag != "" {
for _, rule := range r.rules {
if rule.RuleTag != tag {
newRules = append(newRules, rule)
}
}
r.rules = newRules
return nil
}
return newError("empty tag name!")
}
func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context, error) { func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context, error) {
// SkipDNSResolve is set from DNS module. // SkipDNSResolve is set from DNS module.
// the DOH remote server maybe a domain name, // the DOH remote server maybe a domain name,
@@ -214,16 +112,16 @@ func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context,
} }
// Start implements common.Runnable. // Start implements common.Runnable.
func (r *Router) Start() error { func (*Router) Start() error {
return nil return nil
} }
// Close implements common.Closable. // Close implements common.Closable.
func (r *Router) Close() error { func (*Router) Close() error {
return nil return nil
} }
// Type implements common.HasType. // Type implement common.HasType.
func (*Router) Type() interface{} { func (*Router) Type() interface{} {
return routing.RouterType() return routing.RouterType()
} }
@@ -241,8 +139,8 @@ func (r *Route) GetOutboundTag() string {
func init() { func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
r := new(Router) r := new(Router)
if err := core.RequireFeatures(ctx, func(d dns.Client, ohm outbound.Manager, dispatcher routing.Dispatcher) error { if err := core.RequireFeatures(ctx, func(d dns.Client, ohm outbound.Manager) error {
return r.Init(ctx, config.(*Config), d, ohm, dispatcher) return r.Init(config.(*Config), d, ohm)
}); err != nil { }); err != nil {
return nil, err return nil, err
} }

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