mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-12-18 21:24:37 +03:00
Compare commits
1 Commits
v25.12.2
...
dev-sniff-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95c2113250 |
29
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
29
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -7,8 +7,6 @@ body:
|
|||||||
description: |-
|
description: |-
|
||||||
Please check all of the following options to prove that you have read and understood the requirements, otherwise this issue will be closed.
|
Please check all of the following options to prove that you have read and understood the requirements, otherwise this issue will be closed.
|
||||||
options:
|
options:
|
||||||
- label: I have read all the comments in the issue template and ensured that this issue meet the requirements.
|
|
||||||
required: true
|
|
||||||
- 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.
|
- 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
|
required: true
|
||||||
- label: I provided the complete config and logs, rather than just providing the truncated parts based on my own judgment.
|
- label: I provided the complete config and logs, rather than just providing the truncated parts based on my own judgment.
|
||||||
@@ -40,8 +38,6 @@ body:
|
|||||||
### For config
|
### For config
|
||||||
Please provide the configuration files that can reproduce the problem, including the server and client.
|
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.
|
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.
|
||||||
After removing parts that do not affect reproduction, provide the actual running **complete** file.
|
|
||||||
meaning of complete: This config can be directly used to start the core, **not a truncated part of the config**. For fields like keys, use newly generated valid parameters that have not been actually used to fill in.
|
|
||||||
|
|
||||||
### For logs
|
### For logs
|
||||||
Please set the log level to debug and dnsLog to true first.
|
Please set the log level to debug and dnsLog to true first.
|
||||||
@@ -50,29 +46,42 @@ body:
|
|||||||
Provide the log of Xray-core, not the log output by the panel or other things.
|
Provide the log of Xray-core, not the log output by the panel or other things.
|
||||||
|
|
||||||
### Finally
|
### Finally
|
||||||
The specific content to be filled in each of the following text boxes needs to be placed between ```<details><pre><code>``` and ```</code></pre></details>```, like this
|
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.
|
||||||
<details><pre><code>
|
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.
|
||||||
(config)
|
|
||||||
</code></pre></details>
|
|
||||||
```
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Client config
|
label: Client config
|
||||||
|
value: |-
|
||||||
|
<details><pre><code>
|
||||||
|
|
||||||
|
</code></pre></details>
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Server config
|
label: Server config
|
||||||
|
value: |-
|
||||||
|
<details><pre><code>
|
||||||
|
|
||||||
|
</code></pre></details>
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Client log
|
label: Client log
|
||||||
|
value: |-
|
||||||
|
<details><pre><code>
|
||||||
|
|
||||||
|
</code></pre></details>
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Server log
|
label: Server log
|
||||||
|
value: |-
|
||||||
|
<details><pre><code>
|
||||||
|
|
||||||
|
</code></pre></details>
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
29
.github/ISSUE_TEMPLATE/bug_report_zh.yml
vendored
29
.github/ISSUE_TEMPLATE/bug_report_zh.yml
vendored
@@ -7,8 +7,6 @@ body:
|
|||||||
description: |-
|
description: |-
|
||||||
请勾选以下所有选项以证明您已经阅读并理解了以下要求,否则该 issue 将被关闭。
|
请勾选以下所有选项以证明您已经阅读并理解了以下要求,否则该 issue 将被关闭。
|
||||||
options:
|
options:
|
||||||
- label: 我读完了 issue 模板中的所有注释,确保填写符合要求。
|
|
||||||
required: true
|
|
||||||
- label: 我保证阅读了文档,了解所有我编写的配置文件项的含义,而不是大量堆砌看似有用的选项或默认值。
|
- label: 我保证阅读了文档,了解所有我编写的配置文件项的含义,而不是大量堆砌看似有用的选项或默认值。
|
||||||
required: true
|
required: true
|
||||||
- label: 我提供了完整的配置文件和日志,而不是出于自己的判断只给出截取的部分。
|
- label: 我提供了完整的配置文件和日志,而不是出于自己的判断只给出截取的部分。
|
||||||
@@ -40,8 +38,6 @@ body:
|
|||||||
### 对于配置文件
|
### 对于配置文件
|
||||||
请提供可以重现问题的配置文件,包括服务端和客户端。
|
请提供可以重现问题的配置文件,包括服务端和客户端。
|
||||||
不要直接在这里黏贴一大段导出的 config 文件。去掉无用的出入站、规则、选项,这可以帮助确定问题,如果你真的想得到帮助。
|
不要直接在这里黏贴一大段导出的 config 文件。去掉无用的出入站、规则、选项,这可以帮助确定问题,如果你真的想得到帮助。
|
||||||
在去掉不影响复现的部分后,提供实际运行的**完整**文件。
|
|
||||||
完整的含义:可以直接使用这个配置启动核心,**不是截取的部分配置**。对于密钥等参数使用重新生成未实际使用的有效参数填充。
|
|
||||||
|
|
||||||
### 对于日志
|
### 对于日志
|
||||||
请先将日志等级设置为 debug, dnsLog 设置为true.
|
请先将日志等级设置为 debug, dnsLog 设置为true.
|
||||||
@@ -50,29 +46,42 @@ body:
|
|||||||
提供 Xray-core 的日志,而不是面板或者别的东西输出的日志。
|
提供 Xray-core 的日志,而不是面板或者别的东西输出的日志。
|
||||||
|
|
||||||
### 最后
|
### 最后
|
||||||
把下面的每格具体内容需要放在 ```<details><pre><code>``` 和 ```</code></pre></details>``` 中间,如
|
在去掉不影响复现的部分后,提供实际运行的**完整**文件,不要出于自己的判断只提供入站出站或者几行日志。
|
||||||
```
|
把内容放在文本框预置的 ```<details><pre><code>``` 和 ```</code></pre></details>``` 中间。
|
||||||
<details><pre><code>
|
如果问题十分明确只出现在某一端(如按文档正确编写配置后核心启动失败/崩溃),可以在下面不需要的项目填入N/A.
|
||||||
(config)
|
|
||||||
</code></pre></details>
|
|
||||||
```
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: 客户端配置
|
label: 客户端配置
|
||||||
|
value: |-
|
||||||
|
<details><pre><code>
|
||||||
|
|
||||||
|
</code></pre></details>
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: 服务端配置
|
label: 服务端配置
|
||||||
|
value: |-
|
||||||
|
<details><pre><code>
|
||||||
|
|
||||||
|
</code></pre></details>
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: 客户端日志
|
label: 客户端日志
|
||||||
|
value: |-
|
||||||
|
<details><pre><code>
|
||||||
|
|
||||||
|
</code></pre></details>
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: 服务端日志
|
label: 服务端日志
|
||||||
|
value: |-
|
||||||
|
<details><pre><code>
|
||||||
|
|
||||||
|
</code></pre></details>
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
74
.github/docker/Dockerfile
vendored
74
.github/docker/Dockerfile
vendored
@@ -1,62 +1,28 @@
|
|||||||
# syntax=docker/dockerfile:latest
|
# syntax=docker/dockerfile:1
|
||||||
FROM --platform=$BUILDPLATFORM golang:latest AS build
|
FROM --platform=$BUILDPLATFORM golang:alpine AS build
|
||||||
|
|
||||||
# Build xray-core
|
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
ARG TARGETOS
|
ARG TARGETOS
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags "-s -w -buildid=" ./main
|
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
|
||||||
|
ADD https://github.com/v2fly/geoip/releases/latest/download/geoip.dat /v2fly/geoip.dat
|
||||||
|
ADD https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat /v2fly/geosite.dat
|
||||||
|
ADD https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat /loyalsoldier/geoip.dat
|
||||||
|
ADD https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat /loyalsoldier/geosite.dat
|
||||||
|
|
||||||
# Download geodat into a staging directory
|
# chainguard/static contains only tzdata and ca-certificates, can be built with multiarch static binaries.
|
||||||
ADD https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geoip.dat /tmp/geodat/geoip.dat
|
FROM --platform=linux/amd64 chainguard/static:latest
|
||||||
ADD https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat /tmp/geodat/geosite.dat
|
WORKDIR /var/log/xray
|
||||||
|
COPY .github/docker/files/config.json /etc/xray/config.json
|
||||||
|
COPY --from=build --chmod=755 /src/xray /usr/bin/xray
|
||||||
|
|
||||||
RUN mkdir -p /tmp/empty
|
USER root
|
||||||
|
WORKDIR /root
|
||||||
# Create config files with empty JSON content
|
VOLUME /etc/xray
|
||||||
RUN mkdir -p /tmp/usr/local/etc/xray
|
ARG TZ=Asia/Shanghai
|
||||||
RUN cat <<EOF >/tmp/usr/local/etc/xray/00_log.json
|
|
||||||
{
|
|
||||||
"log": {
|
|
||||||
"error": "/var/log/xray/error.log",
|
|
||||||
"loglevel": "warning",
|
|
||||||
"access": "none",
|
|
||||||
"dnsLog": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/01_api.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/02_dns.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/03_routing.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/04_policy.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/05_inbounds.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/06_outbounds.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/07_transport.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/08_stats.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/09_reverse.json
|
|
||||||
|
|
||||||
# Create log files
|
|
||||||
RUN mkdir -p /tmp/var/log/xray && touch \
|
|
||||||
/tmp/var/log/xray/access.log \
|
|
||||||
/tmp/var/log/xray/error.log
|
|
||||||
|
|
||||||
# Build finally image
|
|
||||||
FROM gcr.io/distroless/static:nonroot
|
|
||||||
|
|
||||||
COPY --from=build --chown=0:0 --chmod=755 /src/xray /usr/local/bin/xray
|
|
||||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /usr/local/share/xray
|
|
||||||
COPY --from=build --chown=0:0 --chmod=644 /tmp/geodat/*.dat /usr/local/share/xray/
|
|
||||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /usr/local/etc/xray
|
|
||||||
COPY --from=build --chown=0:0 --chmod=644 /tmp/usr/local/etc/xray/*.json /usr/local/etc/xray/
|
|
||||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /var/log/xray
|
|
||||||
COPY --from=build --chown=65532:65532 --chmod=600 /tmp/var/log/xray/*.log /var/log/xray/
|
|
||||||
|
|
||||||
VOLUME /usr/local/etc/xray
|
|
||||||
VOLUME /var/log/xray
|
|
||||||
|
|
||||||
ARG TZ=Etc/UTC
|
|
||||||
ENV TZ=$TZ
|
ENV TZ=$TZ
|
||||||
|
ENTRYPOINT [ "/usr/bin/xray" ]
|
||||||
|
CMD [ "-confdir", "/etc/xray/" ]
|
||||||
|
|
||||||
ENTRYPOINT [ "/usr/local/bin/xray" ]
|
ARG flavor=v2fly
|
||||||
CMD [ "-confdir", "/usr/local/etc/xray/" ]
|
COPY --from=build --chmod=644 /$flavor /usr/share/xray
|
||||||
|
|||||||
71
.github/docker/Dockerfile.usa
vendored
71
.github/docker/Dockerfile.usa
vendored
@@ -1,71 +0,0 @@
|
|||||||
# syntax=docker/dockerfile:latest
|
|
||||||
FROM --platform=$BUILDPLATFORM golang:latest AS build
|
|
||||||
|
|
||||||
# Build xray-core
|
|
||||||
WORKDIR /src
|
|
||||||
COPY . .
|
|
||||||
ARG TARGETOS
|
|
||||||
ARG TARGETARCH
|
|
||||||
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags "-s -w -buildid=" ./main
|
|
||||||
|
|
||||||
# Download geodat into a staging directory
|
|
||||||
ADD https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geoip.dat /tmp/geodat/geoip.dat
|
|
||||||
ADD https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat /tmp/geodat/geosite.dat
|
|
||||||
|
|
||||||
RUN mkdir -p /tmp/empty
|
|
||||||
|
|
||||||
# Create config files with empty JSON content
|
|
||||||
RUN mkdir -p /tmp/usr/local/etc/xray
|
|
||||||
RUN cat <<EOF >/tmp/usr/local/etc/xray/00_log.json
|
|
||||||
{
|
|
||||||
"log": {
|
|
||||||
"error": "/var/log/xray/error.log",
|
|
||||||
"loglevel": "warning",
|
|
||||||
"access": "none",
|
|
||||||
"dnsLog": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/01_api.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/02_dns.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/03_routing.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/04_policy.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/05_inbounds.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/06_outbounds.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/07_transport.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/08_stats.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/09_reverse.json
|
|
||||||
|
|
||||||
# Create log files
|
|
||||||
RUN mkdir -p /tmp/var/log/xray && touch \
|
|
||||||
/tmp/var/log/xray/access.log \
|
|
||||||
/tmp/var/log/xray/error.log
|
|
||||||
|
|
||||||
# Build finally image
|
|
||||||
# Note on Distroless Base Image and Architecture Support:
|
|
||||||
# - The official 'gcr.io/distroless/static' image provided by Google only supports a limited set of architectures for Linux:
|
|
||||||
# - linux/amd64
|
|
||||||
# - linux/arm/v7
|
|
||||||
# - linux/arm64/v8
|
|
||||||
# - linux/ppc64le
|
|
||||||
# - linux/s390x
|
|
||||||
# - Upon inspection, the blob contents of the Distroless images across these architectures are nearly identical, with only minor differences in metadata (e.g., 'Architecture' field in the manifest).
|
|
||||||
# - Due to this similarity in content, it is feasible to forcibly specify a single platform (e.g., '--platform=linux/amd64') for unsupported architectures, as the core image content remains compatible with statically compiled binaries like Go applications.
|
|
||||||
FROM --platform=linux/amd64 gcr.io/distroless/static:nonroot
|
|
||||||
|
|
||||||
COPY --from=build --chown=0:0 --chmod=755 /src/xray /usr/local/bin/xray
|
|
||||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /usr/local/share/xray
|
|
||||||
COPY --from=build --chown=0:0 --chmod=644 /tmp/geodat/*.dat /usr/local/share/xray/
|
|
||||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /usr/local/etc/xray
|
|
||||||
COPY --from=build --chown=0:0 --chmod=644 /tmp/usr/local/etc/xray/*.json /usr/local/etc/xray/
|
|
||||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /var/log/xray
|
|
||||||
COPY --from=build --chown=65532:65532 --chmod=600 /tmp/var/log/xray/*.log /var/log/xray/
|
|
||||||
|
|
||||||
VOLUME /usr/local/etc/xray
|
|
||||||
VOLUME /var/log/xray
|
|
||||||
|
|
||||||
ARG TZ=Etc/UTC
|
|
||||||
ENV TZ=$TZ
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/usr/local/bin/xray" ]
|
|
||||||
CMD [ "-confdir", "/usr/local/etc/xray/" ]
|
|
||||||
18
.github/docker/files/config.json
vendored
Normal file
18
.github/docker/files/config.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"inbounds": [{
|
||||||
|
"port": 9000,
|
||||||
|
"protocol": "vmess",
|
||||||
|
"settings": {
|
||||||
|
"clients": [
|
||||||
|
{
|
||||||
|
"id": "1eb6e917-774b-4a84-aff6-b058577c60a5",
|
||||||
|
"level": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"outbounds": [{
|
||||||
|
"protocol": "freedom",
|
||||||
|
"settings": {}
|
||||||
|
}]
|
||||||
|
}
|
||||||
155
.github/workflows/docker.yml
vendored
155
.github/workflows/docker.yml
vendored
@@ -1,133 +1,76 @@
|
|||||||
name: Build and Push Docker Image
|
name: Build docker image
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types:
|
types: [published]
|
||||||
- published
|
push:
|
||||||
- released
|
branches:
|
||||||
|
- main
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
tag:
|
|
||||||
description: "Docker image tag:"
|
|
||||||
required: true
|
|
||||||
latest:
|
|
||||||
description: "Set to latest"
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push:
|
build-image:
|
||||||
if: (github.event.action != 'published') || (github.event.action == 'published' && github.event.release.prerelease == true)
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
|
||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set repository and image name to lowercase
|
- uses: actions/checkout@v4
|
||||||
env:
|
- name: Docker metadata
|
||||||
IMAGE_NAME: "${{ github.repository }}"
|
id: meta
|
||||||
run: |
|
uses: docker/metadata-action@v5
|
||||||
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
|
with:
|
||||||
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
|
images: ghcr.io/${{ github.repository_owner }}/xray-core
|
||||||
|
flavor: latest=auto
|
||||||
- name: Validate and extract tag
|
tags: |
|
||||||
run: |
|
type=sha
|
||||||
SOURCE_TAG="${{ github.event.inputs.tag }}"
|
type=ref,event=branch
|
||||||
if [[ -z "$SOURCE_TAG" ]]; then
|
type=ref,event=pr
|
||||||
SOURCE_TAG="${{ github.ref_name }}"
|
type=semver,pattern={{version}}
|
||||||
fi
|
- name: Docker metadata Loyalsoldier flavor
|
||||||
if [[ -z "$SOURCE_TAG" ]]; then
|
id: loyalsoldier
|
||||||
SOURCE_TAG="${{ github.event.release.tag_name }}"
|
uses: docker/metadata-action@v5
|
||||||
fi
|
with:
|
||||||
|
images: ghcr.io/${{ github.repository_owner }}/xray-core
|
||||||
if [[ -z "$SOURCE_TAG" ]]; then
|
flavor: |
|
||||||
echo "Error: Could not determine a valid tag source. Input tag and context tag (github.ref_name) are both empty."
|
latest=auto
|
||||||
exit 1
|
suffix=-ls,onlatest=true
|
||||||
fi
|
tags: |
|
||||||
|
type=sha
|
||||||
if [[ "$SOURCE_TAG" =~ ^v[0-9]+\.[0-9] ]]; then
|
type=ref,event=branch
|
||||||
IMAGE_TAG="${SOURCE_TAG#v}"
|
type=ref,event=pr
|
||||||
else
|
type=semver,pattern={{version}}
|
||||||
IMAGE_TAG="$SOURCE_TAG"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Docker image tag: '$IMAGE_TAG'."
|
|
||||||
echo "IMAGE_TAG=$IMAGE_TAG" >>${GITHUB_ENV}
|
|
||||||
|
|
||||||
LATEST=false
|
|
||||||
if [[ "${{ github.event_name }}" == "release" && "${{ github.event.release.prerelease }}" == "false" ]] || [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ github.event.inputs.latest }}" == "true" ]]; then
|
|
||||||
LATEST=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Latest: '$LATEST'."
|
|
||||||
echo "LATEST=$LATEST" >>${GITHUB_ENV}
|
|
||||||
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Set up Docker Buildx
|
||||||
- name: Build Docker image (main architectures)
|
uses: docker/setup-buildx-action@v3
|
||||||
id: build_main_arches
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: .github/docker/Dockerfile
|
|
||||||
platforms: |
|
platforms: |
|
||||||
linux/amd64
|
linux/amd64
|
||||||
linux/arm/v7
|
linux/arm64
|
||||||
linux/arm64/v8
|
linux/loong64
|
||||||
linux/ppc64le
|
linux/riscv64
|
||||||
linux/s390x
|
|
||||||
provenance: false
|
provenance: false
|
||||||
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
file: .github/docker/Dockerfile
|
||||||
|
push: true
|
||||||
- name: Build Docker image (additional architectures)
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
id: build_additional_arches
|
- name: Build and push Loyalsoldier flavor
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: .github/docker/Dockerfile.usa
|
|
||||||
platforms: |
|
platforms: |
|
||||||
linux/386
|
linux/amd64
|
||||||
linux/arm/v6
|
linux/arm64
|
||||||
linux/riscv64
|
|
||||||
linux/loong64
|
linux/loong64
|
||||||
|
linux/riscv64
|
||||||
provenance: false
|
provenance: false
|
||||||
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
file: .github/docker/Dockerfile
|
||||||
|
build-args: flavor=loyalsoldier
|
||||||
- name: Create manifest list and push
|
push: true
|
||||||
run: |
|
tags: |
|
||||||
echo "Creating multi-arch manifest with tag: '${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}'."
|
${{ steps.loyalsoldier.outputs.tags }}
|
||||||
docker buildx imagetools create \
|
|
||||||
--tag ${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }} \
|
|
||||||
${{ env.FULL_IMAGE_NAME }}@${{ steps.build_main_arches.outputs.digest }} \
|
|
||||||
${{ env.FULL_IMAGE_NAME }}@${{ steps.build_additional_arches.outputs.digest }}
|
|
||||||
|
|
||||||
if [[ "${{ env.LATEST }}" == "true" ]]; then
|
|
||||||
echo "Adding 'latest' tag to manifest: '${{ env.FULL_IMAGE_NAME }}:latest'."
|
|
||||||
docker buildx imagetools create \
|
|
||||||
--tag ${{ env.FULL_IMAGE_NAME }}:latest \
|
|
||||||
${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Inspect image
|
|
||||||
run: |
|
|
||||||
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
|
||||||
|
|
||||||
if [[ "${{ env.LATEST }}" == "true" ]]; then
|
|
||||||
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:latest
|
|
||||||
fi
|
|
||||||
|
|||||||
43
.github/workflows/release-win7.yml
vendored
43
.github/workflows/release-win7.yml
vendored
@@ -9,38 +9,7 @@ on:
|
|||||||
types: [opened, synchronize, reopened]
|
types: [opened, synchronize, reopened]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-assets:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Restore Geodat Cache
|
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-geodat-
|
|
||||||
|
|
||||||
- name: Check Assets Existence
|
|
||||||
id: check-assets
|
|
||||||
run: |
|
|
||||||
[ -d 'resources' ] || mkdir resources
|
|
||||||
LIST=('geoip.dat' 'geosite.dat')
|
|
||||||
for FILE_NAME in "${LIST[@]}"
|
|
||||||
do
|
|
||||||
echo -e "Checking ${FILE_NAME}..."
|
|
||||||
if [ -s "./resources/${FILE_NAME}" ]; then
|
|
||||||
echo -e "${FILE_NAME} exists."
|
|
||||||
else
|
|
||||||
echo -e "${FILE_NAME} does not exist."
|
|
||||||
echo "missing=true" >> $GITHUB_OUTPUT
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Sleep for 90 seconds if Assets Missing
|
|
||||||
if: steps.check-assets.outputs.missing == 'true'
|
|
||||||
run: sleep 90
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
needs: check-assets
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
strategy:
|
strategy:
|
||||||
@@ -63,7 +32,7 @@ jobs:
|
|||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codebase
|
- name: Checkout codebase
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Show workflow information
|
- name: Show workflow information
|
||||||
run: |
|
run: |
|
||||||
@@ -72,7 +41,7 @@ jobs:
|
|||||||
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -82,7 +51,7 @@ jobs:
|
|||||||
GOSDK=$(go env GOROOT)
|
GOSDK=$(go env GOROOT)
|
||||||
rm -r $GOSDK/*
|
rm -r $GOSDK/*
|
||||||
cd $GOSDK
|
cd $GOSDK
|
||||||
curl -O -L -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://github.com/XTLS/go-win7/releases/latest/download/go-for-win7-linux-amd64.zip
|
curl -O -L https://github.com/XTLS/go-win7/releases/latest/download/go-for-win7-linux-amd64.zip
|
||||||
unzip ./go-for-win7-linux-amd64.zip -d $GOSDK
|
unzip ./go-for-win7-linux-amd64.zip -d $GOSDK
|
||||||
rm ./go-for-win7-linux-amd64.zip
|
rm ./go-for-win7-linux-amd64.zip
|
||||||
|
|
||||||
@@ -94,11 +63,11 @@ jobs:
|
|||||||
mkdir -p build_assets
|
mkdir -p build_assets
|
||||||
COMMID=$(git describe --always --dirty)
|
COMMID=$(git describe --always --dirty)
|
||||||
echo 'Building Xray for Windows 7...'
|
echo 'Building Xray for Windows 7...'
|
||||||
go build -o build_assets/xray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
go build -o build_assets/xray.exe -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||||
echo 'CreateObject("Wscript.Shell").Run "xray.exe -config config.json",0' > build_assets/xray_no_window.vbs
|
echo 'CreateObject("Wscript.Shell").Run "xray.exe -config config.json",0' > build_assets/xray_no_window.vbs
|
||||||
echo 'Start-Process -FilePath ".\xray.exe" -ArgumentList "-config .\config.json" -WindowStyle Hidden' > build_assets/xray_no_window.ps1
|
echo 'Start-Process -FilePath ".\xray.exe" -ArgumentList "-config .\config.json" -WindowStyle Hidden' > build_assets/xray_no_window.ps1
|
||||||
# The line below is for without running conhost.exe version. Commented for not being used. Provided for reference.
|
# The line below is for without running conhost.exe version. Commented for not being used. Provided for reference.
|
||||||
# go build -o build_assets/wxray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-H windowsgui -X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
# go build -o build_assets/wxray.exe -trimpath -buildvcs=false -ldflags="-H windowsgui -X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||||
|
|
||||||
- name: Restore Geodat Cache
|
- name: Restore Geodat Cache
|
||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v4
|
||||||
@@ -132,7 +101,7 @@ jobs:
|
|||||||
mv build_assets Xray-${{ env.ASSET_NAME }}
|
mv build_assets Xray-${{ env.ASSET_NAME }}
|
||||||
|
|
||||||
- name: Upload files to Artifacts
|
- name: Upload files to Artifacts
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Xray-${{ env.ASSET_NAME }}
|
name: Xray-${{ env.ASSET_NAME }}
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
82
.github/workflows/release.yml
vendored
82
.github/workflows/release.yml
vendored
@@ -9,53 +9,7 @@ on:
|
|||||||
types: [opened, synchronize, reopened]
|
types: [opened, synchronize, reopened]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-assets:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Restore Geodat Cache
|
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-geodat-
|
|
||||||
|
|
||||||
- name: Check Assets Existence
|
|
||||||
id: check-assets
|
|
||||||
run: |
|
|
||||||
[ -d 'resources' ] || mkdir resources
|
|
||||||
LIST=('geoip.dat' 'geosite.dat')
|
|
||||||
for FILE_NAME in "${LIST[@]}"
|
|
||||||
do
|
|
||||||
echo -e "Checking ${FILE_NAME}..."
|
|
||||||
if [ -s "./resources/${FILE_NAME}" ]; then
|
|
||||||
echo -e "${FILE_NAME} exists."
|
|
||||||
else
|
|
||||||
echo -e "${FILE_NAME} does not exist."
|
|
||||||
echo "missing=true" >> $GITHUB_OUTPUT
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Trigger Asset Update Workflow if Assets Missing
|
|
||||||
if: steps.check-assets.outputs.missing == 'true'
|
|
||||||
uses: actions/github-script@v8
|
|
||||||
with:
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
script: |
|
|
||||||
const { owner, repo } = context.repo;
|
|
||||||
await github.rest.actions.createWorkflowDispatch({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
workflow_id: 'scheduled-assets-update.yml',
|
|
||||||
ref: context.ref
|
|
||||||
});
|
|
||||||
console.log('Triggered scheduled-assets-update.yml due to missing assets on branch:', context.ref);
|
|
||||||
|
|
||||||
- name: Sleep for 90 seconds if Assets Missing
|
|
||||||
if: steps.check-assets.outputs.missing == 'true'
|
|
||||||
run: sleep 90
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
needs: check-assets
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
strategy:
|
strategy:
|
||||||
@@ -88,11 +42,6 @@ jobs:
|
|||||||
- goos: android
|
- goos: android
|
||||||
goarch: arm64
|
goarch: arm64
|
||||||
# END Android ARM 8
|
# END Android ARM 8
|
||||||
# BEGIN Android AMD64
|
|
||||||
- goos: android
|
|
||||||
goarch: amd64
|
|
||||||
patch-assetname: android-amd64
|
|
||||||
# END Android AMD64
|
|
||||||
# Windows ARM
|
# Windows ARM
|
||||||
- goos: windows
|
- goos: windows
|
||||||
goarch: arm64
|
goarch: arm64
|
||||||
@@ -153,20 +102,7 @@ jobs:
|
|||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codebase
|
- name: Checkout codebase
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up NDK
|
|
||||||
if: matrix.goos == 'android'
|
|
||||||
run: |
|
|
||||||
wget -qO android-ndk.zip https://dl.google.com/android/repository/android-ndk-r28b-linux.zip
|
|
||||||
unzip android-ndk.zip
|
|
||||||
rm android-ndk.zip
|
|
||||||
declare -A arches=(
|
|
||||||
["amd64"]="x86_64-linux-android24-clang"
|
|
||||||
["arm64"]="aarch64-linux-android24-clang"
|
|
||||||
)
|
|
||||||
echo CC="$(realpath android-ndk-*/toolchains/llvm/prebuilt/linux-x86_64/bin)/${arches[${{ matrix.goarch }}]}" >> $GITHUB_ENV
|
|
||||||
echo CGO_ENABLED=1 >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Show workflow information
|
- name: Show workflow information
|
||||||
run: |
|
run: |
|
||||||
@@ -176,33 +112,31 @@ jobs:
|
|||||||
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
|
||||||
- name: Get project dependencies
|
- name: Get project dependencies
|
||||||
run: go mod download
|
run: go mod download
|
||||||
|
|
||||||
- name: Build Xray
|
- name: Build Xray
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build_assets
|
mkdir -p build_assets
|
||||||
COMMID=$(git describe --always --dirty)
|
COMMID=$(git describe --always --dirty)
|
||||||
if [[ ${GOOS} == 'windows' ]]; then
|
if [[ ${GOOS} == 'windows' ]]; then
|
||||||
echo 'Building Xray for Windows...'
|
echo 'Building Xray for Windows...'
|
||||||
go build -o build_assets/xray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
go build -o build_assets/xray.exe -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||||
echo 'CreateObject("Wscript.Shell").Run "xray.exe -config config.json",0' > build_assets/xray_no_window.vbs
|
echo 'CreateObject("Wscript.Shell").Run "xray.exe -config config.json",0' > build_assets/xray_no_window.vbs
|
||||||
echo 'Start-Process -FilePath ".\xray.exe" -ArgumentList "-config .\config.json" -WindowStyle Hidden' > build_assets/xray_no_window.ps1
|
echo 'Start-Process -FilePath ".\xray.exe" -ArgumentList "-config .\config.json" -WindowStyle Hidden' > build_assets/xray_no_window.ps1
|
||||||
# The line below is for without running conhost.exe version. Commented for not being used. Provided for reference.
|
# The line below is for without running conhost.exe version. Commented for not being used. Provided for reference.
|
||||||
# go build -o build_assets/wxray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-H windowsgui -X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
# go build -o build_assets/wxray.exe -trimpath -buildvcs=false -ldflags="-H windowsgui -X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||||
else
|
else
|
||||||
echo 'Building Xray...'
|
echo 'Building Xray...'
|
||||||
|
go build -o build_assets/xray -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||||
if [[ ${GOARCH} == 'mips' || ${GOARCH} == 'mipsle' ]]; then
|
if [[ ${GOARCH} == 'mips' || ${GOARCH} == 'mipsle' ]]; then
|
||||||
go build -o build_assets/xray -trimpath -buildvcs=false -gcflags="-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
|
||||||
echo 'Building soft-float Xray for MIPS/MIPSLE 32-bit...'
|
echo 'Building soft-float Xray for MIPS/MIPSLE 32-bit...'
|
||||||
GOMIPS=softfloat go build -o build_assets/xray_softfloat -trimpath -buildvcs=false -gcflags="-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
GOMIPS=softfloat go build -o build_assets/xray_softfloat -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||||
else
|
|
||||||
go build -o build_assets/xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -238,7 +172,7 @@ jobs:
|
|||||||
mv build_assets Xray-${{ env.ASSET_NAME }}
|
mv build_assets Xray-${{ env.ASSET_NAME }}
|
||||||
|
|
||||||
- name: Upload files to Artifacts
|
- name: Upload files to Artifacts
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Xray-${{ env.ASSET_NAME }}
|
name: Xray-${{ env.ASSET_NAME }}
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: Scheduled assets update
|
name: Scheduled assets update
|
||||||
|
|
||||||
# NOTE: This Github Actions is required by other actions, for preparing other packaging assets in a
|
# NOTE: This Github Actions is required by other actions, for preparing other packaging assets in a
|
||||||
# routine manner, for example: GeoIP/GeoSite.
|
# routine manner, for example: GeoIP/GeoSite.
|
||||||
# Currently updating:
|
# Currently updating:
|
||||||
# - Geodat (GeoIP/Geosite)
|
# - Geodat (GeoIP/Geosite)
|
||||||
@@ -9,7 +9,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
# Update GeoData on every day (22:30 UTC)
|
# Update GeoData on every day (22:30 UTC)
|
||||||
- cron: "30 22 * * *"
|
- cron: '30 22 * * *'
|
||||||
push:
|
push:
|
||||||
# Prevent triggering update request storm
|
# Prevent triggering update request storm
|
||||||
paths:
|
paths:
|
||||||
@@ -45,12 +45,12 @@ jobs:
|
|||||||
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3,$4}'))
|
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3,$4}'))
|
||||||
FILE_NAME="${INFO[3]}.dat"
|
FILE_NAME="${INFO[3]}.dat"
|
||||||
echo -e "Verifying HASH key..."
|
echo -e "Verifying HASH key..."
|
||||||
HASH="$(curl -sL -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
|
HASH="$(curl -sL "https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
|
||||||
if [ -s "./resources/${FILE_NAME}" ] && [ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ]; then
|
if [ -s "./resources/${FILE_NAME}" ] && [ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ]; then
|
||||||
continue
|
continue
|
||||||
else
|
else
|
||||||
echo -e "Downloading https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat..."
|
echo -e "Downloading https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat..."
|
||||||
curl -L -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat" -o ./resources/${FILE_NAME}
|
curl -L "https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat" -o ./resources/${FILE_NAME}
|
||||||
echo -e "Verifying HASH key..."
|
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; }
|
[ "$(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
|
echo "unhit=true" >> $GITHUB_OUTPUT
|
||||||
|
|||||||
33
.github/workflows/test.yml
vendored
33
.github/workflows/test.yml
vendored
@@ -6,36 +6,7 @@ on:
|
|||||||
types: [opened, synchronize, reopened]
|
types: [opened, synchronize, reopened]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-assets:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Restore Geodat Cache
|
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-geodat-
|
|
||||||
- name: Check Assets Existence
|
|
||||||
id: check-assets
|
|
||||||
run: |
|
|
||||||
[ -d 'resources' ] || mkdir resources
|
|
||||||
LIST=('geoip.dat' 'geosite.dat')
|
|
||||||
for FILE_NAME in "${LIST[@]}"
|
|
||||||
do
|
|
||||||
echo -e "Checking ${FILE_NAME}..."
|
|
||||||
if [ -s "./resources/${FILE_NAME}" ]; then
|
|
||||||
echo -e "${FILE_NAME} exists."
|
|
||||||
else
|
|
||||||
echo -e "${FILE_NAME} does not exist."
|
|
||||||
echo "missing=true" >> $GITHUB_OUTPUT
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
- name: Sleep for 90 seconds if Assets Missing
|
|
||||||
if: steps.check-assets.outputs.missing == 'true'
|
|
||||||
run: sleep 90
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
needs: check-assets
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
@@ -45,9 +16,9 @@ jobs:
|
|||||||
os: [windows-latest, ubuntu-latest, macos-latest]
|
os: [windows-latest, ubuntu-latest, macos-latest]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codebase
|
- name: Checkout codebase
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v4
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
|||||||
47
.gitignore
vendored
47
.gitignore
vendored
@@ -11,23 +11,13 @@
|
|||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
*.out
|
*.out
|
||||||
|
|
||||||
# macOS specific files
|
# Dependency directories (remove the comment below to include it)
|
||||||
.DS_Store
|
# vendor/
|
||||||
|
|
||||||
# IDE/editor specific files
|
*.DS_Store
|
||||||
.idea/
|
.idea
|
||||||
.vscode/
|
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
|
|
||||||
# Archives and compressed files
|
|
||||||
*.zip
|
*.zip
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
*.tar
|
|
||||||
*.gz
|
|
||||||
*.bz2
|
|
||||||
|
|
||||||
# Go build binaries
|
|
||||||
xray
|
xray
|
||||||
xray_softfloat
|
xray_softfloat
|
||||||
mockgen
|
mockgen
|
||||||
@@ -36,33 +26,8 @@ vprotogen
|
|||||||
errorgen
|
errorgen
|
||||||
!common/errors/errorgen/
|
!common/errors/errorgen/
|
||||||
*.dat
|
*.dat
|
||||||
|
.vscode
|
||||||
# Build assets
|
/build_assets
|
||||||
/build_assets/
|
|
||||||
|
|
||||||
# Output from dlv test
|
# Output from dlv test
|
||||||
**/debug.*
|
**/debug.*
|
||||||
|
|
||||||
# Certificates and keys
|
|
||||||
*.crt
|
|
||||||
*.key
|
|
||||||
|
|
||||||
# Dependency directories (uncomment if needed)
|
|
||||||
# vendor/
|
|
||||||
|
|
||||||
# Logs
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# Coverage reports
|
|
||||||
coverage.*
|
|
||||||
|
|
||||||
# Node modules (in case of frontend assets)
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# System files
|
|
||||||
Thumbs.db
|
|
||||||
ehthumbs.db
|
|
||||||
|
|
||||||
# Other common ignores
|
|
||||||
*.bak
|
|
||||||
*.tmp
|
|
||||||
|
|||||||
68
README.md
68
README.md
@@ -4,30 +4,11 @@
|
|||||||
|
|
||||||
[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).
|
[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).
|
||||||
|
|
||||||
## Sponsors
|
|
||||||
|
|
||||||
[](https://docs.rw)
|
|
||||||
|
|
||||||
[](https://happ.su)
|
|
||||||
|
|
||||||
[**Sponsor Xray-core**](https://github.com/XTLS/Xray-core/issues/3668)
|
|
||||||
|
|
||||||
## Donation & NFTs
|
## Donation & NFTs
|
||||||
|
|
||||||
### [Collect a Project X NFT to support the development of Project X!](https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1)
|
|
||||||
|
|
||||||
[<img alt="Project X NFT" width="150px" src="https://raw2.seadn.io/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/7fa9ce900fb39b44226348db330e32/8b7fa9ce900fb39b44226348db330e32.svg" />](https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1)
|
|
||||||
|
|
||||||
- **TRX(Tron)/USDT/USDC: `TNrDh5VSfwd4RPrwsohr6poyNTfFefNYan`**
|
|
||||||
- **TON: `UQApeV-u2gm43aC1uP76xAC1m6vCylstaN1gpfBmre_5IyTH`**
|
|
||||||
- **BTC: `1JpqcziZZuqv3QQJhZGNGBVdCBrGgkL6cT`**
|
|
||||||
- **XMR: `4ABHQZ3yJZkBnLoqiKvb3f8eqUnX4iMPb6wdant5ZLGQELctcerceSGEfJnoCk6nnyRZm73wrwSgvZ2WmjYLng6R7sR67nq`**
|
|
||||||
- **SOL/USDT/USDC: `3x5NuXHzB5APG6vRinPZcsUv5ukWUY1tBGRSJiEJWtZa`**
|
|
||||||
- **ETH/USDT/USDC: `0xDc3Fe44F0f25D13CACb1C4896CD0D321df3146Ee`**
|
- **ETH/USDT/USDC: `0xDc3Fe44F0f25D13CACb1C4896CD0D321df3146Ee`**
|
||||||
- **Project X NFT: https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1**
|
- **Project X NFT: [Announcement of NFTs by Project X](https://github.com/XTLS/Xray-core/discussions/3633)**
|
||||||
- **VLESS NFT: https://opensea.io/collection/vless**
|
- **REALITY NFT: [XHTTP: Beyond REALITY](https://github.com/XTLS/Xray-core/discussions/4113)**
|
||||||
- **REALITY NFT: https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/2**
|
|
||||||
- **Related links: [VLESS Post-Quantum Encryption](https://github.com/XTLS/Xray-core/pull/5067), [XHTTP: Beyond REALITY](https://github.com/XTLS/Xray-core/discussions/4113), [Announcement of NFTs by Project X](https://github.com/XTLS/Xray-core/discussions/3633)**
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
@@ -57,15 +38,12 @@
|
|||||||
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
|
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
|
||||||
- [wulabing/xray_docker](https://github.com/wulabing/xray_docker)
|
- [wulabing/xray_docker](https://github.com/wulabing/xray_docker)
|
||||||
- Web Panel - **WARNING: Please DO NOT USE plain HTTP panels like 3X-UI**, as they are believed to be bribed by Iran GFW for supporting plain HTTP by default and refused to change (https://github.com/XTLS/Xray-core/pull/3884#issuecomment-2439595331), which has already put many users' data security in danger in the past few years. **If you are already using 3X-UI, please switch to the following panels, which are verified to support HTTPS and SSH port forwarding only:**
|
- Web Panel - **WARNING: Please DO NOT USE plain HTTP panels like 3X-UI**, as they are believed to be bribed by Iran GFW for supporting plain HTTP by default and refused to change (https://github.com/XTLS/Xray-core/pull/3884#issuecomment-2439595331), which has already put many users' data security in danger in the past few years. **If you are already using 3X-UI, please switch to the following panels, which are verified to support HTTPS and SSH port forwarding only:**
|
||||||
- [Remnawave](https://github.com/remnawave/panel)
|
|
||||||
- [X-Panel](https://github.com/xeefei/X-Panel)
|
|
||||||
- [PasarGuard](https://github.com/PasarGuard/panel)
|
|
||||||
- [Marzban](https://github.com/Gozargah/Marzban)
|
- [Marzban](https://github.com/Gozargah/Marzban)
|
||||||
- [Xray-UI](https://github.com/qist/xray-ui)
|
- [Xray-UI](https://github.com/qist/xray-ui)
|
||||||
- [Hiddify](https://github.com/hiddify/Hiddify-Manager)
|
- [Hiddify](https://github.com/hiddify/Hiddify-Manager)
|
||||||
- One Click
|
- 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-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), [VPainLess](https://github.com/vpainless/vpainless)
|
- [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)
|
- [v2ray-agent](https://github.com/mack-a/v2ray-agent), [Xray_onekey](https://github.com/wulabing/Xray_onekey), [ProxySU](https://github.com/proxysu/ProxySU)
|
||||||
- Magisk
|
- Magisk
|
||||||
- [Xray4Magisk](https://github.com/Asterisk4Magisk/Xray4Magisk)
|
- [Xray4Magisk](https://github.com/Asterisk4Magisk/Xray4Magisk)
|
||||||
@@ -102,45 +80,31 @@
|
|||||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
- [v2rayN](https://github.com/2dust/v2rayN)
|
||||||
- [Furious](https://github.com/LorenEteval/Furious)
|
- [Furious](https://github.com/LorenEteval/Furious)
|
||||||
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
|
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
|
||||||
- Android
|
- Android
|
||||||
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
||||||
- [X-flutter](https://github.com/XTLS/X-flutter)
|
- [X-flutter](https://github.com/XTLS/X-flutter)
|
||||||
- [SaeedDev94/Xray](https://github.com/SaeedDev94/Xray)
|
- [SaeedDev94/Xray](https://github.com/SaeedDev94/Xray)
|
||||||
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
- iOS & macOS arm64
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
|
||||||
- iOS & macOS arm64 & tvOS
|
|
||||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215) ([tvOS](https://apps.apple.com/us/app/happ-proxy-utility-for-tv/id6748297274))
|
|
||||||
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)
|
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)
|
||||||
- [OneXray](https://github.com/OneXray/OneXray)
|
|
||||||
- macOS arm64 & x64
|
- macOS arm64 & x64
|
||||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215)
|
|
||||||
- [V2rayU](https://github.com/yanue/V2rayU)
|
- [V2rayU](https://github.com/yanue/V2rayU)
|
||||||
- [V2RayXS](https://github.com/tzmax/V2RayXS)
|
- [V2RayXS](https://github.com/tzmax/V2RayXS)
|
||||||
- [Furious](https://github.com/LorenEteval/Furious)
|
- [Furious](https://github.com/LorenEteval/Furious)
|
||||||
- [OneXray](https://github.com/OneXray/OneXray)
|
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
|
||||||
- [GoXRay](https://github.com/goxray/desktop)
|
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
|
||||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
|
||||||
- Linux
|
- Linux
|
||||||
- [v2rayA](https://github.com/v2rayA/v2rayA)
|
- [v2rayA](https://github.com/v2rayA/v2rayA)
|
||||||
- [Furious](https://github.com/LorenEteval/Furious)
|
- [Furious](https://github.com/LorenEteval/Furious)
|
||||||
- [GorzRay](https://github.com/ketetefid/GorzRay)
|
|
||||||
- [GoXRay](https://github.com/goxray/desktop)
|
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
|
||||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
|
||||||
|
|
||||||
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
||||||
|
|
||||||
- iOS & macOS arm64 & tvOS
|
- iOS & macOS arm64
|
||||||
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
||||||
- [Loon](https://apps.apple.com/us/app/loon/id1373567447)
|
|
||||||
- Xray Tools
|
- Xray Tools
|
||||||
- [xray-knife](https://github.com/lilendian0x00/xray-knife)
|
- [xray-knife](https://github.com/lilendian0x00/xray-knife)
|
||||||
- [xray-checker](https://github.com/kutovoys/xray-checker)
|
- [xray-checker](https://github.com/kutovoys/xray-checker)
|
||||||
- Xray Wrapper
|
- Xray Wrapper
|
||||||
- [XTLS/libXray](https://github.com/XTLS/libXray)
|
- [XTLS/libXray](https://github.com/XTLS/libXray)
|
||||||
- [xtls-sdk](https://github.com/remnawave/xtls-sdk)
|
|
||||||
- [xtlsapi](https://github.com/hiddify/xtlsapi)
|
- [xtlsapi](https://github.com/hiddify/xtlsapi)
|
||||||
- [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite)
|
- [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite)
|
||||||
- [Xray-core-python](https://github.com/LorenEteval/Xray-core-python)
|
- [Xray-core-python](https://github.com/LorenEteval/Xray-core-python)
|
||||||
@@ -148,17 +112,15 @@
|
|||||||
- [XrayR](https://github.com/XrayR-project/XrayR)
|
- [XrayR](https://github.com/XrayR-project/XrayR)
|
||||||
- [XrayR-release](https://github.com/XrayR-project/XrayR-release)
|
- [XrayR-release](https://github.com/XrayR-project/XrayR-release)
|
||||||
- [XrayR-V2Board](https://github.com/missuo/XrayR-V2Board)
|
- [XrayR-V2Board](https://github.com/missuo/XrayR-V2Board)
|
||||||
- Cores
|
- [Clash.Meta](https://github.com/MetaCubeX/Clash.Meta)
|
||||||
- [Amnezia VPN](https://github.com/amnezia-vpn)
|
- [clashN](https://github.com/2dust/clashN)
|
||||||
- [mihomo](https://github.com/MetaCubeX/mihomo)
|
- [Clash Meta for Android](https://github.com/MetaCubeX/ClashMetaForAndroid)
|
||||||
- [sing-box](https://github.com/SagerNet/sing-box)
|
- [sing-box](https://github.com/SagerNet/sing-box)
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
[Code of Conduct](https://github.com/XTLS/Xray-core/blob/main/CODE_OF_CONDUCT.md)
|
[Code of Conduct](https://github.com/XTLS/Xray-core/blob/main/CODE_OF_CONDUCT.md)
|
||||||
|
|
||||||
[](https://deepwiki.com/XTLS/Xray-core)
|
|
||||||
|
|
||||||
## Credits
|
## 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).
|
- [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).
|
||||||
@@ -184,13 +146,7 @@ CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -ldflags="-s -w -buildi
|
|||||||
Make sure that you are using the same Go version, and remember to set the git commit id (7 bytes):
|
Make sure that you are using the same Go version, and remember to set the git commit id (7 bytes):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=REPLACE -s -w -buildid=" -v ./main
|
CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=REPLACE -s -w -buildid=" -v ./main
|
||||||
```
|
|
||||||
|
|
||||||
If you are compiling a 32-bit MIPS/MIPSLE target, use this command instead:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -gcflags="-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=REPLACE -s -w -buildid=" -v ./main
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Stargazers over time
|
## Stargazers over time
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/net/cnc"
|
"github.com/xtls/xray-core/common/net/cnc"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
|
||||||
"github.com/xtls/xray-core/common/signal/done"
|
"github.com/xtls/xray-core/common/signal/done"
|
||||||
"github.com/xtls/xray-core/transport"
|
"github.com/xtls/xray-core/transport"
|
||||||
)
|
)
|
||||||
@@ -109,13 +108,3 @@ func (co *Outbound) Close() error {
|
|||||||
co.closed = true
|
co.closed = true
|
||||||
return co.listener.Close()
|
return co.listener.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SenderSettings implements outbound.Handler.
|
|
||||||
func (co *Outbound) SenderSettings() *serial.TypedMessage {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProxySettings implements outbound.Handler.
|
|
||||||
func (co *Outbound) ProxySettings() *serial.TypedMessage {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -29,25 +29,35 @@ var errSniffingTimeout = errors.New("timeout on sniffing")
|
|||||||
|
|
||||||
type cachedReader struct {
|
type cachedReader struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
reader buf.TimeoutReader // *pipe.Reader or *buf.TimeoutWrapperReader
|
reader *pipe.Reader
|
||||||
cache buf.MultiBuffer
|
cache buf.MultiBuffer
|
||||||
|
|
||||||
|
ReadBufferTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *cachedReader) Cache(b *buf.Buffer, deadline time.Duration) error {
|
func (r *cachedReader) Cache(b *buf.Buffer) {
|
||||||
mb, err := r.reader.ReadMultiBufferTimeout(deadline)
|
var timeout time.Duration
|
||||||
if err != nil {
|
if r.ReadBufferTimeout == 0 {
|
||||||
return err
|
timeout = time.Millisecond * 100
|
||||||
|
} else {
|
||||||
|
timeout = r.ReadBufferTimeout
|
||||||
}
|
}
|
||||||
|
mb, _ := r.reader.ReadMultiBufferTimeout(timeout)
|
||||||
r.Lock()
|
r.Lock()
|
||||||
if !mb.IsEmpty() {
|
if !mb.IsEmpty() {
|
||||||
r.cache, _ = buf.MergeMulti(r.cache, mb)
|
r.cache, _ = buf.MergeMulti(r.cache, mb)
|
||||||
}
|
}
|
||||||
b.Clear()
|
cacheLen := r.cache.Len()
|
||||||
rawBytes := b.Extend(min(r.cache.Len(), b.Cap()))
|
if cacheLen <= b.Cap() {
|
||||||
|
b.Clear()
|
||||||
|
} else {
|
||||||
|
b.Release()
|
||||||
|
*b = *buf.NewWithSize(cacheLen)
|
||||||
|
}
|
||||||
|
rawBytes := b.Extend(cacheLen)
|
||||||
n := r.cache.Copy(rawBytes)
|
n := r.cache.Copy(rawBytes)
|
||||||
b.Resize(0, int32(n))
|
b.Resize(0, int32(n))
|
||||||
r.Unlock()
|
r.Unlock()
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *cachedReader) readInternal() buf.MultiBuffer {
|
func (r *cachedReader) readInternal() buf.MultiBuffer {
|
||||||
@@ -87,9 +97,7 @@ func (r *cachedReader) Interrupt() {
|
|||||||
r.cache = buf.ReleaseMulti(r.cache)
|
r.cache = buf.ReleaseMulti(r.cache)
|
||||||
}
|
}
|
||||||
r.Unlock()
|
r.Unlock()
|
||||||
if p, ok := r.reader.(*pipe.Reader); ok {
|
r.reader.Interrupt()
|
||||||
p.Interrupt()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultDispatcher is a default implementation of Dispatcher.
|
// DefaultDispatcher is a default implementation of Dispatcher.
|
||||||
@@ -98,6 +106,7 @@ type DefaultDispatcher struct {
|
|||||||
router routing.Router
|
router routing.Router
|
||||||
policy policy.Manager
|
policy policy.Manager
|
||||||
stats stats.Manager
|
stats stats.Manager
|
||||||
|
dns dns.Client
|
||||||
fdns dns.FakeDNSEngine
|
fdns dns.FakeDNSEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +117,7 @@ func init() {
|
|||||||
core.OptionalFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
core.OptionalFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||||
d.fdns = fdns
|
d.fdns = fdns
|
||||||
})
|
})
|
||||||
return d.Init(config.(*Config), om, router, pm, sm)
|
return d.Init(config.(*Config), om, router, pm, sm, dc)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -117,11 +126,12 @@ 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) error {
|
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dns 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
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,47 +206,6 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
|
|||||||
return inboundLink, outboundLink
|
return inboundLink, outboundLink
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDispatcher) WrapLink(ctx context.Context, link *transport.Link) *transport.Link {
|
|
||||||
sessionInbound := session.InboundFromContext(ctx)
|
|
||||||
var user *protocol.MemoryUser
|
|
||||||
if sessionInbound != nil {
|
|
||||||
user = sessionInbound.User
|
|
||||||
}
|
|
||||||
|
|
||||||
link.Reader = &buf.TimeoutWrapperReader{Reader: link.Reader}
|
|
||||||
|
|
||||||
if user != nil && len(user.Email) > 0 {
|
|
||||||
p := d.policy.ForLevel(user.Level)
|
|
||||||
if p.Stats.UserUplink {
|
|
||||||
name := "user>>>" + user.Email + ">>>traffic>>>uplink"
|
|
||||||
if c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
|
|
||||||
link.Reader.(*buf.TimeoutWrapperReader).Counter = c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if p.Stats.UserDownlink {
|
|
||||||
name := "user>>>" + user.Email + ">>>traffic>>>downlink"
|
|
||||||
if c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
|
|
||||||
link.Writer = &SizeStatWriter{
|
|
||||||
Counter: c,
|
|
||||||
Writer: link.Writer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if p.Stats.UserOnline {
|
|
||||||
name := "user>>>" + user.Email + ">>>online"
|
|
||||||
if om, _ := stats.GetOrRegisterOnlineMap(d.stats, name); om != nil {
|
|
||||||
sessionInbounds := session.InboundFromContext(ctx)
|
|
||||||
userIP := sessionInbounds.Source.Address.String()
|
|
||||||
om.AddIP(userIP)
|
|
||||||
// log Online user with ips
|
|
||||||
// errors.LogDebug(ctx, "user>>>" + user.Email + ">>>online", om.Count(), om.List())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return link
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
||||||
domain := result.Domain()
|
domain := result.Domain()
|
||||||
if domain == "" {
|
if domain == "" {
|
||||||
@@ -357,13 +326,12 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
|||||||
content = new(session.Content)
|
content = new(session.Content)
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
}
|
}
|
||||||
outbound = d.WrapLink(ctx, outbound)
|
|
||||||
sniffingRequest := content.SniffingRequest
|
sniffingRequest := content.SniffingRequest
|
||||||
if !sniffingRequest.Enabled {
|
if !sniffingRequest.Enabled {
|
||||||
d.routedDispatch(ctx, outbound, destination)
|
d.routedDispatch(ctx, outbound, destination)
|
||||||
} else {
|
} else {
|
||||||
cReader := &cachedReader{
|
cReader := &cachedReader{
|
||||||
reader: outbound.Reader.(buf.TimeoutReader),
|
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, destination.Network)
|
||||||
@@ -395,11 +363,13 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, network net.Network) (SniffResult, error) {
|
func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, network net.Network) (SniffResult, error) {
|
||||||
payload := buf.NewWithSize(32767)
|
payload := buf.New()
|
||||||
defer payload.Release()
|
defer payload.Release()
|
||||||
|
|
||||||
sniffer := NewSniffer(ctx)
|
sniffer := NewSniffer(ctx)
|
||||||
|
|
||||||
|
cReader.ReadBufferTimeout = sniffer.Timeout
|
||||||
|
|
||||||
metaresult, metadataErr := sniffer.SniffMetadata(ctx)
|
metaresult, metadataErr := sniffer.SniffMetadata(ctx)
|
||||||
|
|
||||||
if metadataOnly {
|
if metadataOnly {
|
||||||
@@ -407,36 +377,26 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
|
|||||||
}
|
}
|
||||||
|
|
||||||
contentResult, contentErr := func() (SniffResult, error) {
|
contentResult, contentErr := func() (SniffResult, error) {
|
||||||
cacheDeadline := 200 * time.Millisecond
|
|
||||||
totalAttempt := 0
|
totalAttempt := 0
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil, ctx.Err()
|
return nil, ctx.Err()
|
||||||
default:
|
default:
|
||||||
cachingStartingTimeStamp := time.Now()
|
totalAttempt++
|
||||||
err := cReader.Cache(payload, cacheDeadline)
|
if totalAttempt > 2 {
|
||||||
if err != nil {
|
return nil, errSniffingTimeout
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
cachingTimeElapsed := time.Since(cachingStartingTimeStamp)
|
|
||||||
cacheDeadline -= cachingTimeElapsed
|
|
||||||
|
|
||||||
|
cReader.Cache(payload)
|
||||||
if !payload.IsEmpty() {
|
if !payload.IsEmpty() {
|
||||||
result, err := sniffer.Sniff(ctx, payload.Bytes(), network)
|
result, err := sniffer.Sniff(ctx, payload.Bytes(), network)
|
||||||
switch err {
|
if err != common.ErrNoClue {
|
||||||
case common.ErrNoClue: // No Clue: protocol not matches, and sniffer cannot determine whether there will be a match or not
|
|
||||||
totalAttempt++
|
|
||||||
case protocol.ErrProtoNeedMoreData: // Protocol Need More Data: protocol matches, but need more data to complete sniffing
|
|
||||||
// in this case, do not add totalAttempt(allow to read until timeout)
|
|
||||||
default:
|
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
totalAttempt++
|
|
||||||
}
|
}
|
||||||
if totalAttempt >= 2 || cacheDeadline <= 0 {
|
if payload.IsFull() {
|
||||||
return nil, errSniffingTimeout
|
return nil, errUnknownContent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -452,6 +412,18 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
|
|||||||
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)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
ob := outbounds[len(outbounds)-1]
|
ob := outbounds[len(outbounds)-1]
|
||||||
|
if hosts, ok := d.dns.(dns.HostsLookup); ok && destination.Address.Family().IsDomain() {
|
||||||
|
proxied := hosts.LookupHosts(ob.Target.String())
|
||||||
|
if proxied != nil {
|
||||||
|
ro := ob.RouteTarget == destination
|
||||||
|
destination.Address = *proxied
|
||||||
|
if ro {
|
||||||
|
ob.RouteTarget = destination
|
||||||
|
} else {
|
||||||
|
ob.Target = destination
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var handler outbound.Handler
|
var handler outbound.Handler
|
||||||
|
|
||||||
@@ -483,9 +455,6 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
|||||||
handler = h
|
handler = h
|
||||||
} else {
|
} else {
|
||||||
errors.LogWarning(ctx, "non existing outTag: ", outTag)
|
errors.LogWarning(ctx, "non existing outTag: ", outTag)
|
||||||
common.Close(link.Writer)
|
|
||||||
common.Interrupt(link.Reader)
|
|
||||||
return // DO NOT CHANGE: the traffic shouldn't be processed by default outbound if the specified outbound tag doesn't exist (yet), e.g., VLESS Reverse Proxy
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errors.LogInfo(ctx, "default route for ", destination)
|
errors.LogInfo(ctx, "default route for ", destination)
|
||||||
|
|||||||
@@ -2,15 +2,16 @@ package dispatcher
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"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/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
|
||||||
"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/quic"
|
||||||
"github.com/xtls/xray-core/common/protocol/tls"
|
"github.com/xtls/xray-core/common/protocol/tls"
|
||||||
|
"github.com/xtls/xray-core/common/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SniffResult interface {
|
type SniffResult interface {
|
||||||
@@ -31,9 +32,11 @@ type protocolSnifferWithMetadata struct {
|
|||||||
|
|
||||||
type Sniffer struct {
|
type Sniffer struct {
|
||||||
sniffer []protocolSnifferWithMetadata
|
sniffer []protocolSnifferWithMetadata
|
||||||
|
Timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSniffer(ctx context.Context) *Sniffer {
|
func NewSniffer(ctx context.Context) *Sniffer {
|
||||||
|
content := session.ContentFromContext(ctx)
|
||||||
ret := &Sniffer{
|
ret := &Sniffer{
|
||||||
sniffer: []protocolSnifferWithMetadata{
|
sniffer: []protocolSnifferWithMetadata{
|
||||||
{func(c context.Context, b []byte) (SniffResult, error) { return http.SniffHTTP(b, c) }, false, net.Network_TCP},
|
{func(c context.Context, b []byte) (SniffResult, error) { return http.SniffHTTP(b, c) }, false, net.Network_TCP},
|
||||||
@@ -42,6 +45,7 @@ func NewSniffer(ctx context.Context) *Sniffer {
|
|||||||
{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 quic.SniffQUIC(b) }, false, net.Network_UDP},
|
||||||
{func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffUTP(b) }, false, net.Network_UDP},
|
{func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffUTP(b) }, false, net.Network_UDP},
|
||||||
},
|
},
|
||||||
|
Timeout: content.SniffingRequest.Timeout,
|
||||||
}
|
}
|
||||||
if sniffer, err := newFakeDNSSniffer(ctx); err == nil {
|
if sniffer, err := newFakeDNSSniffer(ctx); err == nil {
|
||||||
others := ret.sniffer
|
others := ret.sniffer
|
||||||
@@ -59,17 +63,14 @@ var errUnknownContent = errors.New("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, network net.Network) (SniffResult, error) {
|
||||||
var pendingSniffer []protocolSnifferWithMetadata
|
var pendingSniffer []protocolSnifferWithMetadata
|
||||||
for _, si := range s.sniffer {
|
for _, si := range s.sniffer {
|
||||||
protocolSniffer := si.protocolSniffer
|
s := si.protocolSniffer
|
||||||
if si.metadataSniffer || si.network != network {
|
if si.metadataSniffer || si.network != network {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
result, err := protocolSniffer(c, payload)
|
result, err := s(c, payload)
|
||||||
if err == common.ErrNoClue {
|
if err == common.ErrNoClue {
|
||||||
pendingSniffer = append(pendingSniffer, si)
|
pendingSniffer = append(pendingSniffer, si)
|
||||||
continue
|
continue
|
||||||
} else if err == protocol.ErrProtoNeedMoreData { // Sniffer protocol matched, but need more data to complete sniffing
|
|
||||||
s.sniffer = []protocolSnifferWithMetadata{si}
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil && result != nil {
|
if err == nil && result != nil {
|
||||||
|
|||||||
@@ -1,339 +0,0 @@
|
|||||||
package dns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
go_errors "errors"
|
|
||||||
"runtime"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
|
||||||
"github.com/xtls/xray-core/common/task"
|
|
||||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
|
||||||
|
|
||||||
"golang.org/x/net/dns/dnsmessage"
|
|
||||||
"golang.org/x/sync/singleflight"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
minSizeForEmptyRebuild = 512
|
|
||||||
shrinkAbsoluteThreshold = 10240
|
|
||||||
shrinkRatioThreshold = 0.65
|
|
||||||
migrationBatchSize = 4096
|
|
||||||
)
|
|
||||||
|
|
||||||
type CacheController struct {
|
|
||||||
name string
|
|
||||||
disableCache bool
|
|
||||||
serveStale bool
|
|
||||||
serveExpiredTTL int32
|
|
||||||
|
|
||||||
ips map[string]*record
|
|
||||||
dirtyips map[string]*record
|
|
||||||
|
|
||||||
sync.RWMutex
|
|
||||||
pub *pubsub.Service
|
|
||||||
cacheCleanup *task.Periodic
|
|
||||||
highWatermark int
|
|
||||||
requestGroup singleflight.Group
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCacheController(name string, disableCache bool, serveStale bool, serveExpiredTTL uint32) *CacheController {
|
|
||||||
c := &CacheController{
|
|
||||||
name: name,
|
|
||||||
disableCache: disableCache,
|
|
||||||
serveStale: serveStale,
|
|
||||||
serveExpiredTTL: -int32(serveExpiredTTL),
|
|
||||||
ips: make(map[string]*record),
|
|
||||||
pub: pubsub.NewService(),
|
|
||||||
}
|
|
||||||
|
|
||||||
c.cacheCleanup = &task.Periodic{
|
|
||||||
Interval: 300 * time.Second,
|
|
||||||
Execute: c.CacheCleanup,
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// CacheCleanup clears expired items from cache
|
|
||||||
func (c *CacheController) CacheCleanup() error {
|
|
||||||
expiredKeys, err := c.collectExpiredKeys()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(expiredKeys) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
c.writeAndShrink(expiredKeys)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheController) collectExpiredKeys() ([]string, error) {
|
|
||||||
c.RLock()
|
|
||||||
defer c.RUnlock()
|
|
||||||
|
|
||||||
if len(c.ips) == 0 {
|
|
||||||
return nil, errors.New("nothing to do. stopping...")
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip collection if a migration is in progress
|
|
||||||
if c.dirtyips != nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
if c.serveStale && c.serveExpiredTTL != 0 {
|
|
||||||
now = now.Add(time.Duration(c.serveExpiredTTL) * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
expiredKeys := make([]string, 0, len(c.ips)/4) // pre-allocate
|
|
||||||
|
|
||||||
for domain, rec := range c.ips {
|
|
||||||
if (rec.A != nil && rec.A.Expire.Before(now)) ||
|
|
||||||
(rec.AAAA != nil && rec.AAAA.Expire.Before(now)) {
|
|
||||||
expiredKeys = append(expiredKeys, domain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return expiredKeys, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheController) writeAndShrink(expiredKeys []string) {
|
|
||||||
c.Lock()
|
|
||||||
defer c.Unlock()
|
|
||||||
|
|
||||||
// double check to prevent upper call multiple cleanup tasks
|
|
||||||
if c.dirtyips != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
lenBefore := len(c.ips)
|
|
||||||
if lenBefore > c.highWatermark {
|
|
||||||
c.highWatermark = lenBefore
|
|
||||||
}
|
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
if c.serveStale && c.serveExpiredTTL != 0 {
|
|
||||||
now = now.Add(time.Duration(c.serveExpiredTTL) * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, domain := range expiredKeys {
|
|
||||||
rec := c.ips[domain]
|
|
||||||
if rec == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if rec.A != nil && rec.A.Expire.Before(now) {
|
|
||||||
rec.A = nil
|
|
||||||
}
|
|
||||||
if rec.AAAA != nil && rec.AAAA.Expire.Before(now) {
|
|
||||||
rec.AAAA = nil
|
|
||||||
}
|
|
||||||
if rec.A == nil && rec.AAAA == nil {
|
|
||||||
delete(c.ips, domain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lenAfter := len(c.ips)
|
|
||||||
|
|
||||||
if lenAfter == 0 {
|
|
||||||
if c.highWatermark >= minSizeForEmptyRebuild {
|
|
||||||
errors.LogDebug(context.Background(), c.name,
|
|
||||||
" rebuilding empty cache map to reclaim memory.",
|
|
||||||
" size_before_cleanup=", lenBefore,
|
|
||||||
" peak_size_before_rebuild=", c.highWatermark,
|
|
||||||
)
|
|
||||||
|
|
||||||
c.ips = make(map[string]*record)
|
|
||||||
c.highWatermark = 0
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if reductionFromPeak := c.highWatermark - lenAfter; reductionFromPeak > shrinkAbsoluteThreshold &&
|
|
||||||
float64(reductionFromPeak) > float64(c.highWatermark)*shrinkRatioThreshold {
|
|
||||||
errors.LogDebug(context.Background(), c.name,
|
|
||||||
" shrinking cache map to reclaim memory.",
|
|
||||||
" new_size=", lenAfter,
|
|
||||||
" peak_size_before_shrink=", c.highWatermark,
|
|
||||||
" reduction_since_peak=", reductionFromPeak,
|
|
||||||
)
|
|
||||||
|
|
||||||
c.dirtyips = c.ips
|
|
||||||
c.ips = make(map[string]*record, int(float64(lenAfter)*1.1))
|
|
||||||
c.highWatermark = lenAfter
|
|
||||||
go c.migrate()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
type migrationEntry struct {
|
|
||||||
key string
|
|
||||||
value *record
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheController) migrate() {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
errors.LogError(context.Background(), c.name, " panic during cache migration: ", r)
|
|
||||||
c.Lock()
|
|
||||||
c.dirtyips = nil
|
|
||||||
// c.ips = make(map[string]*record)
|
|
||||||
// c.highWatermark = 0
|
|
||||||
c.Unlock()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
c.RLock()
|
|
||||||
dirtyips := c.dirtyips
|
|
||||||
c.RUnlock()
|
|
||||||
|
|
||||||
// double check to prevent upper call multiple cleanup tasks
|
|
||||||
if dirtyips == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
errors.LogDebug(context.Background(), c.name, " starting background cache migration for ", len(dirtyips), " items")
|
|
||||||
|
|
||||||
batch := make([]migrationEntry, 0, migrationBatchSize)
|
|
||||||
for domain, recD := range dirtyips {
|
|
||||||
batch = append(batch, migrationEntry{domain, recD})
|
|
||||||
|
|
||||||
if len(batch) >= migrationBatchSize {
|
|
||||||
c.flush(batch)
|
|
||||||
batch = batch[:0]
|
|
||||||
runtime.Gosched()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(batch) > 0 {
|
|
||||||
c.flush(batch)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Lock()
|
|
||||||
c.dirtyips = nil
|
|
||||||
c.Unlock()
|
|
||||||
|
|
||||||
errors.LogDebug(context.Background(), c.name, " cache migration completed")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheController) flush(batch []migrationEntry) {
|
|
||||||
c.Lock()
|
|
||||||
defer c.Unlock()
|
|
||||||
|
|
||||||
for _, dirty := range batch {
|
|
||||||
if cur := c.ips[dirty.key]; cur != nil {
|
|
||||||
merge := &record{}
|
|
||||||
if cur.A == nil {
|
|
||||||
merge.A = dirty.value.A
|
|
||||||
} else {
|
|
||||||
merge.A = cur.A
|
|
||||||
}
|
|
||||||
if cur.AAAA == nil {
|
|
||||||
merge.AAAA = dirty.value.AAAA
|
|
||||||
} else {
|
|
||||||
merge.AAAA = cur.AAAA
|
|
||||||
}
|
|
||||||
c.ips[dirty.key] = merge
|
|
||||||
} else {
|
|
||||||
c.ips[dirty.key] = dirty.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheController) updateRecord(req *dnsRequest, rep *IPRecord) {
|
|
||||||
rtt := time.Since(req.start)
|
|
||||||
|
|
||||||
switch req.reqType {
|
|
||||||
case dnsmessage.TypeA:
|
|
||||||
c.pub.Publish(req.domain+"4", rep)
|
|
||||||
case dnsmessage.TypeAAAA:
|
|
||||||
c.pub.Publish(req.domain+"6", rep)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.disableCache {
|
|
||||||
errors.LogInfo(context.Background(), c.name, " got answer: ", req.domain, " ", req.reqType, " -> ", rep.IP, ", rtt: ", rtt)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Lock()
|
|
||||||
lockWait := time.Since(req.start) - rtt
|
|
||||||
|
|
||||||
newRec := &record{}
|
|
||||||
oldRec := c.ips[req.domain]
|
|
||||||
var dirtyRec *record
|
|
||||||
if c.dirtyips != nil {
|
|
||||||
dirtyRec = c.dirtyips[req.domain]
|
|
||||||
}
|
|
||||||
|
|
||||||
var pubRecord *IPRecord
|
|
||||||
var pubSuffix string
|
|
||||||
|
|
||||||
switch req.reqType {
|
|
||||||
case dnsmessage.TypeA:
|
|
||||||
newRec.A = rep
|
|
||||||
if oldRec != nil && oldRec.AAAA != nil {
|
|
||||||
newRec.AAAA = oldRec.AAAA
|
|
||||||
pubRecord = oldRec.AAAA
|
|
||||||
} else if dirtyRec != nil && dirtyRec.AAAA != nil {
|
|
||||||
pubRecord = dirtyRec.AAAA
|
|
||||||
}
|
|
||||||
pubSuffix = "6"
|
|
||||||
case dnsmessage.TypeAAAA:
|
|
||||||
newRec.AAAA = rep
|
|
||||||
if oldRec != nil && oldRec.A != nil {
|
|
||||||
newRec.A = oldRec.A
|
|
||||||
pubRecord = oldRec.A
|
|
||||||
} else if dirtyRec != nil && dirtyRec.A != nil {
|
|
||||||
pubRecord = dirtyRec.A
|
|
||||||
}
|
|
||||||
pubSuffix = "4"
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ips[req.domain] = newRec
|
|
||||||
c.Unlock()
|
|
||||||
|
|
||||||
if pubRecord != nil {
|
|
||||||
_, ttl, err := pubRecord.getIPs()
|
|
||||||
if ttl > 0 && !go_errors.Is(err, errRecordNotFound) {
|
|
||||||
c.pub.Publish(req.domain+pubSuffix, pubRecord)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
errors.LogInfo(context.Background(), c.name, " got answer: ", req.domain, " ", req.reqType, " -> ", rep.IP, ", rtt: ", rtt, ", lock: ", lockWait)
|
|
||||||
|
|
||||||
if !c.serveStale || c.serveExpiredTTL != 0 {
|
|
||||||
common.Must(c.cacheCleanup.Start())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheController) findRecords(domain string) *record {
|
|
||||||
c.RLock()
|
|
||||||
defer c.RUnlock()
|
|
||||||
|
|
||||||
rec := c.ips[domain]
|
|
||||||
if rec == nil && c.dirtyips != nil {
|
|
||||||
rec = c.dirtyips[domain]
|
|
||||||
}
|
|
||||||
return rec
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheController) registerSubscribers(domain string, option dns_feature.IPOption) (sub4 *pubsub.Subscriber, sub6 *pubsub.Subscriber) {
|
|
||||||
// ipv4 and ipv6 belong to different subscription groups
|
|
||||||
if option.IPv4Enable {
|
|
||||||
sub4 = c.pub.Subscribe(domain + "4")
|
|
||||||
}
|
|
||||||
if option.IPv6Enable {
|
|
||||||
sub6 = c.pub.Subscribe(domain + "6")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func closeSubscribers(sub4 *pubsub.Subscriber, sub6 *pubsub.Subscriber) {
|
|
||||||
if sub4 != nil {
|
|
||||||
sub4.Close()
|
|
||||||
}
|
|
||||||
if sub6 != nil {
|
|
||||||
sub6.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -80,7 +80,6 @@ const (
|
|||||||
QueryStrategy_USE_IP QueryStrategy = 0
|
QueryStrategy_USE_IP QueryStrategy = 0
|
||||||
QueryStrategy_USE_IP4 QueryStrategy = 1
|
QueryStrategy_USE_IP4 QueryStrategy = 1
|
||||||
QueryStrategy_USE_IP6 QueryStrategy = 2
|
QueryStrategy_USE_IP6 QueryStrategy = 2
|
||||||
QueryStrategy_USE_SYS QueryStrategy = 3
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Enum value maps for QueryStrategy.
|
// Enum value maps for QueryStrategy.
|
||||||
@@ -89,13 +88,11 @@ var (
|
|||||||
0: "USE_IP",
|
0: "USE_IP",
|
||||||
1: "USE_IP4",
|
1: "USE_IP4",
|
||||||
2: "USE_IP6",
|
2: "USE_IP6",
|
||||||
3: "USE_SYS",
|
|
||||||
}
|
}
|
||||||
QueryStrategy_value = map[string]int32{
|
QueryStrategy_value = map[string]int32{
|
||||||
"USE_IP": 0,
|
"USE_IP": 0,
|
||||||
"USE_IP4": 1,
|
"USE_IP4": 1,
|
||||||
"USE_IP6": 2,
|
"USE_IP6": 2,
|
||||||
"USE_SYS": 3,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -135,19 +132,9 @@ type NameServer struct {
|
|||||||
ClientIp []byte `protobuf:"bytes,5,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
|
ClientIp []byte `protobuf:"bytes,5,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
|
||||||
SkipFallback bool `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"`
|
SkipFallback bool `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"`
|
||||||
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"`
|
||||||
ExpectedGeoip []*router.GeoIP `protobuf:"bytes,3,rep,name=expected_geoip,json=expectedGeoip,proto3" json:"expected_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"`
|
QueryStrategy QueryStrategy `protobuf:"varint,7,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
||||||
ActPrior bool `protobuf:"varint,8,opt,name=actPrior,proto3" json:"actPrior,omitempty"`
|
|
||||||
Tag string `protobuf:"bytes,9,opt,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
TimeoutMs uint64 `protobuf:"varint,10,opt,name=timeoutMs,proto3" json:"timeoutMs,omitempty"`
|
|
||||||
DisableCache *bool `protobuf:"varint,11,opt,name=disableCache,proto3,oneof" json:"disableCache,omitempty"`
|
|
||||||
ServeStale *bool `protobuf:"varint,15,opt,name=serveStale,proto3,oneof" json:"serveStale,omitempty"`
|
|
||||||
ServeExpiredTTL *uint32 `protobuf:"varint,16,opt,name=serveExpiredTTL,proto3,oneof" json:"serveExpiredTTL,omitempty"`
|
|
||||||
FinalQuery bool `protobuf:"varint,12,opt,name=finalQuery,proto3" json:"finalQuery,omitempty"`
|
|
||||||
UnexpectedGeoip []*router.GeoIP `protobuf:"bytes,13,rep,name=unexpected_geoip,json=unexpectedGeoip,proto3" json:"unexpected_geoip,omitempty"`
|
|
||||||
ActUnprior bool `protobuf:"varint,14,opt,name=actUnprior,proto3" json:"actUnprior,omitempty"`
|
|
||||||
PolicyID uint32 `protobuf:"varint,17,opt,name=policyID,proto3" json:"policyID,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) Reset() {
|
func (x *NameServer) Reset() {
|
||||||
@@ -208,9 +195,9 @@ func (x *NameServer) GetPrioritizedDomain() []*NameServer_PriorityDomain {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) GetExpectedGeoip() []*router.GeoIP {
|
func (x *NameServer) GetGeoip() []*router.GeoIP {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.ExpectedGeoip
|
return x.Geoip
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -229,76 +216,6 @@ func (x *NameServer) GetQueryStrategy() QueryStrategy {
|
|||||||
return QueryStrategy_USE_IP
|
return QueryStrategy_USE_IP
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) GetActPrior() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.ActPrior
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *NameServer) GetTag() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Tag
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *NameServer) GetTimeoutMs() uint64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.TimeoutMs
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *NameServer) GetDisableCache() bool {
|
|
||||||
if x != nil && x.DisableCache != nil {
|
|
||||||
return *x.DisableCache
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *NameServer) GetServeStale() bool {
|
|
||||||
if x != nil && x.ServeStale != nil {
|
|
||||||
return *x.ServeStale
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *NameServer) GetServeExpiredTTL() uint32 {
|
|
||||||
if x != nil && x.ServeExpiredTTL != nil {
|
|
||||||
return *x.ServeExpiredTTL
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *NameServer) GetFinalQuery() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.FinalQuery
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *NameServer) GetUnexpectedGeoip() []*router.GeoIP {
|
|
||||||
if x != nil {
|
|
||||||
return x.UnexpectedGeoip
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *NameServer) GetActUnprior() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.ActUnprior
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *NameServer) GetPolicyID() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.PolicyID
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -315,12 +232,9 @@ type Config struct {
|
|||||||
Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
|
Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
// DisableCache disables DNS cache
|
// DisableCache disables DNS cache
|
||||||
DisableCache bool `protobuf:"varint,8,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
|
DisableCache bool `protobuf:"varint,8,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
|
||||||
ServeStale bool `protobuf:"varint,12,opt,name=serveStale,proto3" json:"serveStale,omitempty"`
|
|
||||||
ServeExpiredTTL uint32 `protobuf:"varint,13,opt,name=serveExpiredTTL,proto3" json:"serveExpiredTTL,omitempty"`
|
|
||||||
QueryStrategy QueryStrategy `protobuf:"varint,9,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
QueryStrategy QueryStrategy `protobuf:"varint,9,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
||||||
DisableFallback bool `protobuf:"varint,10,opt,name=disableFallback,proto3" json:"disableFallback,omitempty"`
|
DisableFallback bool `protobuf:"varint,10,opt,name=disableFallback,proto3" json:"disableFallback,omitempty"`
|
||||||
DisableFallbackIfMatch bool `protobuf:"varint,11,opt,name=disableFallbackIfMatch,proto3" json:"disableFallbackIfMatch,omitempty"`
|
DisableFallbackIfMatch bool `protobuf:"varint,11,opt,name=disableFallbackIfMatch,proto3" json:"disableFallbackIfMatch,omitempty"`
|
||||||
EnableParallelQuery bool `protobuf:"varint,14,opt,name=enableParallelQuery,proto3" json:"enableParallelQuery,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -388,20 +302,6 @@ func (x *Config) GetDisableCache() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetServeStale() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.ServeStale
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetServeExpiredTTL() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.ServeExpiredTTL
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetQueryStrategy() QueryStrategy {
|
func (x *Config) GetQueryStrategy() QueryStrategy {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.QueryStrategy
|
return x.QueryStrategy
|
||||||
@@ -423,13 +323,6 @@ func (x *Config) GetDisableFallbackIfMatch() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetEnableParallelQuery() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.EnableParallelQuery
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type NameServer_PriorityDomain struct {
|
type NameServer_PriorityDomain struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -615,7 +508,7 @@ var file_app_dns_config_proto_rawDesc = []byte{
|
|||||||
0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74,
|
0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x1c, 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,
|
0x2f, 0x64, 0x65, 0x73, 0x74, 0x69, 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,
|
0x74, 0x6f, 0x1a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63,
|
||||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdf, 0x07, 0x0a, 0x0a,
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb2, 0x04, 0x0a, 0x0a,
|
||||||
0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64,
|
0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 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,
|
0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 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,
|
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e,
|
||||||
@@ -629,111 +522,75 @@ var file_app_dns_config_proto_rawDesc = []byte{
|
|||||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65,
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65,
|
||||||
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44,
|
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44,
|
||||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x11, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a,
|
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x11, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a,
|
||||||
0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3d, 0x0a, 0x0e, 0x65, 0x78, 0x70, 0x65,
|
0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69,
|
||||||
0x63, 0x74, 0x65, 0x64, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
|
0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
|
||||||
0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52,
|
||||||
0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0d, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74,
|
0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e,
|
||||||
0x65, 0x64, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69,
|
0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25,
|
||||||
0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61,
|
||||||
0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e,
|
0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61,
|
||||||
0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e,
|
0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52,
|
||||||
0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
|
0x75, 0x6c, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74,
|
||||||
0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73,
|
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78,
|
||||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e,
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72,
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65,
|
0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79,
|
||||||
0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72,
|
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x1a, 0x5e, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f,
|
||||||
0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x74,
|
0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79,
|
||||||
0x50, 0x72, 0x69, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x63, 0x74,
|
0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x50, 0x72, 0x69, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x09, 0x20, 0x01,
|
0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61,
|
||||||
0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x6f,
|
0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
|
||||||
0x75, 0x74, 0x4d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
|
0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x6f, 0x75, 0x74, 0x4d, 0x73, 0x12, 0x27, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
|
0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67,
|
||||||
0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0c, 0x64,
|
0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65,
|
||||||
0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x88, 0x01, 0x01, 0x12, 0x23,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04,
|
||||||
0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x53, 0x74, 0x61, 0x6c, 0x65, 0x18, 0x0f, 0x20, 0x01,
|
0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65,
|
||||||
0x28, 0x08, 0x48, 0x01, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x53, 0x74, 0x61, 0x6c, 0x65,
|
0x22, 0x9c, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0b, 0x6e,
|
||||||
0x88, 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x45, 0x78, 0x70, 0x69,
|
0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b,
|
||||||
0x72, 0x65, 0x64, 0x54, 0x54, 0x4c, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x02, 0x52, 0x0f,
|
0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e,
|
||||||
0x73, 0x65, 0x72, 0x76, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x54, 0x54, 0x4c, 0x88,
|
0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65,
|
||||||
0x01, 0x01, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79,
|
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
|
||||||
0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x51, 0x75, 0x65,
|
0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||||
0x72, 0x79, 0x12, 0x41, 0x0a, 0x10, 0x75, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64,
|
0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x68, 0x6f,
|
||||||
0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78,
|
0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47,
|
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
|
||||||
0x65, 0x6f, 0x49, 0x50, 0x52, 0x0f, 0x75, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64,
|
0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73, 0x74, 0x61,
|
||||||
0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x63, 0x74, 0x55, 0x6e, 0x70, 0x72,
|
0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18,
|
||||||
0x69, 0x6f, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x63, 0x74, 0x55, 0x6e,
|
0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69,
|
||||||
0x70, 0x72, 0x69, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49,
|
0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08,
|
||||||
0x44, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49,
|
0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x42,
|
||||||
0x44, 0x1a, 0x5e, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d,
|
0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||||
0x61, 0x69, 0x6e, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||||
0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73,
|
0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74,
|
||||||
0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54,
|
0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||||
0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d,
|
0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c,
|
||||||
0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69,
|
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x69, 0x73,
|
||||||
0x6e, 0x1a, 0x36, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c,
|
0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x36, 0x0a, 0x16,
|
||||||
0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49,
|
||||||
0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20,
|
0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x64, 0x69,
|
||||||
0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x64, 0x69,
|
0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d,
|
||||||
0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x73,
|
0x61, 0x74, 0x63, 0x68, 0x1a, 0x92, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70,
|
||||||
0x65, 0x72, 0x76, 0x65, 0x53, 0x74, 0x61, 0x6c, 0x65, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x73, 0x65,
|
0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,
|
||||||
0x72, 0x76, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x54, 0x54, 0x4c, 0x22, 0x98, 0x05,
|
0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e,
|
||||||
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65,
|
0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67,
|
||||||
0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e,
|
0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f,
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d,
|
0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61,
|
||||||
0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72,
|
0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x02,
|
||||||
0x76, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70,
|
0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f,
|
||||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70,
|
0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78,
|
||||||
0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73,
|
0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x2a,
|
||||||
0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e,
|
||||||
0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73,
|
0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12,
|
||||||
0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63,
|
0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b,
|
||||||
0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01,
|
0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52,
|
||||||
0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62,
|
0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x2a, 0x35, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53,
|
||||||
0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64,
|
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49,
|
||||||
0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73,
|
0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x01,
|
||||||
0x65, 0x72, 0x76, 0x65, 0x53, 0x74, 0x61, 0x6c, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52,
|
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x02, 0x42, 0x46, 0x0a,
|
||||||
0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x53, 0x74, 0x61, 0x6c, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73,
|
0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e,
|
||||||
0x65, 0x72, 0x76, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x54, 0x54, 0x4c, 0x18, 0x0d,
|
0x73, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||||
0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72,
|
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61,
|
||||||
0x65, 0x64, 0x54, 0x54, 0x4c, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73,
|
0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70,
|
||||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e,
|
0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65,
|
|
||||||
0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72,
|
|
||||||
0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73,
|
|
||||||
0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01,
|
|
||||||
0x28, 0x08, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62,
|
|
||||||
0x61, 0x63, 0x6b, 0x12, 0x36, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61,
|
|
||||||
0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20,
|
|
||||||
0x01, 0x28, 0x08, 0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c,
|
|
||||||
0x62, 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x30, 0x0a, 0x13, 0x65,
|
|
||||||
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x51, 0x75, 0x65,
|
|
||||||
0x72, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
|
|
||||||
0x50, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x92, 0x01,
|
|
||||||
0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a,
|
|
||||||
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72,
|
|
||||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
|
||||||
0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74,
|
|
||||||
0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20,
|
|
||||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
|
||||||
0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70,
|
|
||||||
0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20,
|
|
||||||
0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61,
|
|
||||||
0x69, 0x6e, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x2a, 0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61,
|
|
||||||
0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08,
|
|
||||||
0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64,
|
|
||||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f,
|
|
||||||
0x72, 0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x2a,
|
|
||||||
0x42, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
|
||||||
0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07,
|
|
||||||
0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45,
|
|
||||||
0x5f, 0x49, 0x50, 0x36, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x53, 0x59,
|
|
||||||
0x53, 0x10, 0x03, 0x42, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
|
||||||
0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75,
|
|
||||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d,
|
|
||||||
0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 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 (
|
||||||
@@ -764,20 +621,19 @@ var file_app_dns_config_proto_goTypes = []any{
|
|||||||
var file_app_dns_config_proto_depIdxs = []int32{
|
var file_app_dns_config_proto_depIdxs = []int32{
|
||||||
7, // 0: xray.app.dns.NameServer.address:type_name -> xray.common.net.Endpoint
|
7, // 0: xray.app.dns.NameServer.address:type_name -> xray.common.net.Endpoint
|
||||||
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
|
||||||
8, // 2: xray.app.dns.NameServer.expected_geoip:type_name -> xray.app.router.GeoIP
|
8, // 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
|
1, // 4: xray.app.dns.NameServer.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
||||||
8, // 5: xray.app.dns.NameServer.unexpected_geoip:type_name -> xray.app.router.GeoIP
|
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.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
||||||
6, // 7: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
1, // 7: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
||||||
1, // 8: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
0, // 8: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
|
||||||
0, // 9: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
|
0, // 9: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType
|
||||||
0, // 10: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType
|
10, // [10:10] is the sub-list for method output_type
|
||||||
11, // [11:11] is the sub-list for method output_type
|
10, // [10:10] is the sub-list for method input_type
|
||||||
11, // [11:11] is the sub-list for method input_type
|
10, // [10:10] is the sub-list for extension type_name
|
||||||
11, // [11:11] is the sub-list for extension type_name
|
10, // [10:10] is the sub-list for extension extendee
|
||||||
11, // [11:11] is the sub-list for extension extendee
|
0, // [0:10] is the sub-list for field type_name
|
||||||
0, // [0:11] is the sub-list for field type_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_dns_config_proto_init() }
|
func init() { file_app_dns_config_proto_init() }
|
||||||
@@ -785,7 +641,6 @@ func file_app_dns_config_proto_init() {
|
|||||||
if File_app_dns_config_proto != nil {
|
if File_app_dns_config_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
file_app_dns_config_proto_msgTypes[0].OneofWrappers = []any{}
|
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
|
|||||||
@@ -25,19 +25,9 @@ message NameServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
repeated PriorityDomain prioritized_domain = 2;
|
repeated PriorityDomain prioritized_domain = 2;
|
||||||
repeated xray.app.router.GeoIP expected_geoip = 3;
|
repeated xray.app.router.GeoIP geoip = 3;
|
||||||
repeated OriginalRule original_rules = 4;
|
repeated OriginalRule original_rules = 4;
|
||||||
QueryStrategy query_strategy = 7;
|
QueryStrategy query_strategy = 7;
|
||||||
bool actPrior = 8;
|
|
||||||
string tag = 9;
|
|
||||||
uint64 timeoutMs = 10;
|
|
||||||
optional bool disableCache = 11;
|
|
||||||
optional bool serveStale = 15;
|
|
||||||
optional uint32 serveExpiredTTL = 16;
|
|
||||||
bool finalQuery = 12;
|
|
||||||
repeated xray.app.router.GeoIP unexpected_geoip = 13;
|
|
||||||
bool actUnprior = 14;
|
|
||||||
uint32 policyID = 17;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DomainMatchingType {
|
enum DomainMatchingType {
|
||||||
@@ -51,7 +41,6 @@ enum QueryStrategy {
|
|||||||
USE_IP = 0;
|
USE_IP = 0;
|
||||||
USE_IP4 = 1;
|
USE_IP4 = 1;
|
||||||
USE_IP6 = 2;
|
USE_IP6 = 2;
|
||||||
USE_SYS = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message Config {
|
message Config {
|
||||||
@@ -83,13 +72,9 @@ message Config {
|
|||||||
|
|
||||||
// DisableCache disables DNS cache
|
// DisableCache disables DNS cache
|
||||||
bool disableCache = 8;
|
bool disableCache = 8;
|
||||||
bool serveStale = 12;
|
|
||||||
uint32 serveExpiredTTL = 13;
|
|
||||||
|
|
||||||
QueryStrategy query_strategy = 9;
|
QueryStrategy query_strategy = 9;
|
||||||
|
|
||||||
bool disableFallback = 10;
|
bool disableFallback = 10;
|
||||||
bool disableFallbackIfMatch = 11;
|
bool disableFallbackIfMatch = 11;
|
||||||
|
|
||||||
bool enableParallelQuery = 14;
|
|
||||||
}
|
}
|
||||||
|
|||||||
464
app/dns/dns.go
464
app/dns/dns.go
@@ -3,15 +3,11 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
go_errors "errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
|
"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"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
@@ -23,16 +19,16 @@ import (
|
|||||||
// DNS is a DNS rely server.
|
// DNS is a DNS rely server.
|
||||||
type DNS struct {
|
type DNS struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
tag string
|
||||||
|
disableCache bool
|
||||||
disableFallback bool
|
disableFallback bool
|
||||||
disableFallbackIfMatch bool
|
disableFallbackIfMatch bool
|
||||||
enableParallelQuery bool
|
|
||||||
ipOption *dns.IPOption
|
ipOption *dns.IPOption
|
||||||
hosts *StaticHosts
|
hosts *StaticHosts
|
||||||
clients []*Client
|
clients []*Client
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
domainMatcher strmatcher.IndexMatcher
|
domainMatcher strmatcher.IndexMatcher
|
||||||
matcherInfos []*DomainMatcherInfo
|
matcherInfos []*DomainMatcherInfo
|
||||||
checkSystem bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DomainMatcherInfo contains information attached to index returned by Server.domainMatcher
|
// DomainMatcherInfo contains information attached to index returned by Server.domainMatcher
|
||||||
@@ -43,6 +39,13 @@ type DomainMatcherInfo struct {
|
|||||||
|
|
||||||
// New creates a new DNS server with given configuration.
|
// New creates a new DNS server with given configuration.
|
||||||
func New(ctx context.Context, config *Config) (*DNS, error) {
|
func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||||
|
var tag string
|
||||||
|
if len(config.Tag) > 0 {
|
||||||
|
tag = config.Tag
|
||||||
|
} else {
|
||||||
|
tag = generateRandomTag()
|
||||||
|
}
|
||||||
|
|
||||||
var clientIP net.IP
|
var clientIP net.IP
|
||||||
switch len(config.ClientIp) {
|
switch len(config.ClientIp) {
|
||||||
case 0, net.IPv4len, net.IPv6len:
|
case 0, net.IPv4len, net.IPv6len:
|
||||||
@@ -51,36 +54,26 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
|||||||
return nil, errors.New("unexpected client IP length ", len(config.ClientIp))
|
return nil, errors.New("unexpected client IP length ", len(config.ClientIp))
|
||||||
}
|
}
|
||||||
|
|
||||||
var ipOption dns.IPOption
|
var ipOption *dns.IPOption
|
||||||
checkSystem := false
|
|
||||||
switch config.QueryStrategy {
|
switch config.QueryStrategy {
|
||||||
case QueryStrategy_USE_IP:
|
case QueryStrategy_USE_IP:
|
||||||
ipOption = dns.IPOption{
|
ipOption = &dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
}
|
}
|
||||||
case QueryStrategy_USE_SYS:
|
|
||||||
ipOption = dns.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
FakeEnable: false,
|
|
||||||
}
|
|
||||||
checkSystem = true
|
|
||||||
case QueryStrategy_USE_IP4:
|
case QueryStrategy_USE_IP4:
|
||||||
ipOption = dns.IPOption{
|
ipOption = &dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: false,
|
IPv6Enable: false,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
}
|
}
|
||||||
case QueryStrategy_USE_IP6:
|
case QueryStrategy_USE_IP6:
|
||||||
ipOption = dns.IPOption{
|
ipOption = &dns.IPOption{
|
||||||
IPv4Enable: false,
|
IPv4Enable: false,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
return nil, errors.New("unexpected query strategy ", config.QueryStrategy)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hosts, err := NewStaticHosts(config.StaticHosts)
|
hosts, err := NewStaticHosts(config.StaticHosts)
|
||||||
@@ -88,14 +81,8 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
|||||||
return nil, errors.New("failed to create hosts").Base(err)
|
return nil, errors.New("failed to create hosts").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var clients []*Client
|
clients := []*Client{}
|
||||||
domainRuleCount := 0
|
domainRuleCount := 0
|
||||||
|
|
||||||
var defaultTag = config.Tag
|
|
||||||
if len(config.Tag) == 0 {
|
|
||||||
defaultTag = generateRandomTag()
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ns := range config.NameServer {
|
for _, ns := range config.NameServer {
|
||||||
domainRuleCount += len(ns.PrioritizedDomain)
|
domainRuleCount += len(ns.PrioritizedDomain)
|
||||||
}
|
}
|
||||||
@@ -103,6 +90,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
|||||||
// MatcherInfos is ensured to cover the maximum index domainMatcher could return, where matcher's index starts from 1
|
// MatcherInfos is ensured to cover the maximum index domainMatcher could return, where matcher's index starts from 1
|
||||||
matcherInfos := make([]*DomainMatcherInfo, domainRuleCount+1)
|
matcherInfos := make([]*DomainMatcherInfo, domainRuleCount+1)
|
||||||
domainMatcher := &strmatcher.MatcherGroup{}
|
domainMatcher := &strmatcher.MatcherGroup{}
|
||||||
|
geoipContainer := router.GeoIPMatcherContainer{}
|
||||||
|
|
||||||
for _, ns := range config.NameServer {
|
for _, ns := range config.NameServer {
|
||||||
clientIdx := len(clients)
|
clientIdx := len(clients)
|
||||||
@@ -120,32 +108,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
|||||||
case net.IPv4len, net.IPv6len:
|
case net.IPv4len, net.IPv6len:
|
||||||
myClientIP = net.IP(ns.ClientIp)
|
myClientIP = net.IP(ns.ClientIp)
|
||||||
}
|
}
|
||||||
|
client, err := NewClient(ctx, ns, myClientIP, geoipContainer, &matcherInfos, updateDomain)
|
||||||
disableCache := config.DisableCache
|
|
||||||
if ns.DisableCache != nil {
|
|
||||||
disableCache = *ns.DisableCache
|
|
||||||
}
|
|
||||||
|
|
||||||
serveStale := config.ServeStale
|
|
||||||
if ns.ServeStale != nil {
|
|
||||||
serveStale = *ns.ServeStale
|
|
||||||
}
|
|
||||||
|
|
||||||
serveExpiredTTL := config.ServeExpiredTTL
|
|
||||||
if ns.ServeExpiredTTL != nil {
|
|
||||||
serveExpiredTTL = *ns.ServeExpiredTTL
|
|
||||||
}
|
|
||||||
|
|
||||||
var tag = defaultTag
|
|
||||||
if len(ns.Tag) > 0 {
|
|
||||||
tag = ns.Tag
|
|
||||||
}
|
|
||||||
clientIPOption := ResolveIpOptionOverride(ns.QueryStrategy, ipOption)
|
|
||||||
if !clientIPOption.IPv4Enable && !clientIPOption.IPv6Enable {
|
|
||||||
return nil, errors.New("no QueryStrategy available for ", ns.Address)
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := NewClient(ctx, ns, myClientIP, disableCache, serveStale, serveExpiredTTL, tag, clientIPOption, &matcherInfos, updateDomain)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to create client").Base(err)
|
return nil, errors.New("failed to create client").Base(err)
|
||||||
}
|
}
|
||||||
@@ -154,20 +117,20 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
|||||||
|
|
||||||
// If there is no DNS client in config, add a `localhost` DNS client
|
// If there is no DNS client in config, add a `localhost` DNS client
|
||||||
if len(clients) == 0 {
|
if len(clients) == 0 {
|
||||||
clients = append(clients, NewLocalDNSClient(ipOption))
|
clients = append(clients, NewLocalDNSClient())
|
||||||
}
|
}
|
||||||
|
|
||||||
return &DNS{
|
return &DNS{
|
||||||
|
tag: tag,
|
||||||
hosts: hosts,
|
hosts: hosts,
|
||||||
ipOption: &ipOption,
|
ipOption: ipOption,
|
||||||
clients: clients,
|
clients: clients,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
domainMatcher: domainMatcher,
|
domainMatcher: domainMatcher,
|
||||||
matcherInfos: matcherInfos,
|
matcherInfos: matcherInfos,
|
||||||
|
disableCache: config.DisableCache,
|
||||||
disableFallback: config.DisableFallback,
|
disableFallback: config.DisableFallback,
|
||||||
disableFallbackIfMatch: config.DisableFallbackIfMatch,
|
disableFallbackIfMatch: config.DisableFallbackIfMatch,
|
||||||
enableParallelQuery: config.EnableParallelQuery,
|
|
||||||
checkSystem: checkSystem,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,67 +152,94 @@ func (s *DNS) Close() error {
|
|||||||
// IsOwnLink implements proxy.dns.ownLinkVerifier
|
// IsOwnLink implements proxy.dns.ownLinkVerifier
|
||||||
func (s *DNS) IsOwnLink(ctx context.Context) bool {
|
func (s *DNS) IsOwnLink(ctx context.Context) bool {
|
||||||
inbound := session.InboundFromContext(ctx)
|
inbound := session.InboundFromContext(ctx)
|
||||||
if inbound == nil {
|
return inbound != nil && inbound.Tag == s.tag
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, client := range s.clients {
|
|
||||||
if client.tag == inbound.Tag {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookupIP implements dns.Client.
|
// LookupIP implements dns.Client.
|
||||||
func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
|
||||||
// Normalize the FQDN form query
|
|
||||||
domain = strings.TrimSuffix(domain, ".")
|
|
||||||
if domain == "" {
|
if domain == "" {
|
||||||
return nil, 0, errors.New("empty domain name")
|
return nil, errors.New("empty domain name")
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.checkSystem {
|
option.IPv4Enable = option.IPv4Enable && s.ipOption.IPv4Enable
|
||||||
supportIPv4, supportIPv6 := checkRoutes()
|
option.IPv6Enable = option.IPv6Enable && s.ipOption.IPv6Enable
|
||||||
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
|
||||||
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
|
||||||
} else {
|
|
||||||
option.IPv4Enable = option.IPv4Enable && s.ipOption.IPv4Enable
|
|
||||||
option.IPv6Enable = option.IPv6Enable && s.ipOption.IPv6Enable
|
|
||||||
}
|
|
||||||
|
|
||||||
if !option.IPv4Enable && !option.IPv6Enable {
|
if !option.IPv4Enable && !option.IPv6Enable {
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
return nil, dns.ErrEmptyResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normalize the FQDN form query
|
||||||
|
domain = strings.TrimSuffix(domain, ".")
|
||||||
|
|
||||||
// Static host lookup
|
// Static host lookup
|
||||||
switch addrs, err := s.hosts.Lookup(domain, option); {
|
switch addrs := s.hosts.Lookup(domain, option); {
|
||||||
case err != nil:
|
|
||||||
if go_errors.Is(err, dns.ErrEmptyResponse) {
|
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
return nil, 0, errors.New("returning nil for domain ", domain).Base(err)
|
|
||||||
case addrs == nil: // Domain not recorded in static host
|
case addrs == nil: // Domain not recorded in static host
|
||||||
break
|
break
|
||||||
case len(addrs) == 0: // Domain recorded, but no valid IP returned (e.g. IPv4 address with only IPv6 enabled)
|
case len(addrs) == 0: // Domain recorded, but no valid IP returned (e.g. IPv4 address with only IPv6 enabled)
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
return nil, dns.ErrEmptyResponse
|
||||||
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Domain replacement
|
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Domain replacement
|
||||||
errors.LogInfo(s.ctx, "domain replaced: ", domain, " -> ", addrs[0].Domain())
|
errors.LogInfo(s.ctx, "domain replaced: ", domain, " -> ", addrs[0].Domain())
|
||||||
domain = addrs[0].Domain()
|
domain = addrs[0].Domain()
|
||||||
default: // Successfully found ip records in static host
|
default: // Successfully found ip records in static host
|
||||||
errors.LogInfo(s.ctx, "returning ", len(addrs), " IP(s) for domain ", domain, " -> ", addrs)
|
errors.LogInfo(s.ctx, "returning ", len(addrs), " IP(s) for domain ", domain, " -> ", addrs)
|
||||||
ips, err := toNetIP(addrs)
|
return toNetIP(addrs)
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
return ips, 10, nil // Hosts ttl is 10
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name servers lookup
|
// Name servers lookup
|
||||||
if s.enableParallelQuery {
|
errs := []error{}
|
||||||
return s.parallelQuery(domain, option)
|
ctx := session.ContextWithInbound(s.ctx, &session.Inbound{Tag: s.tag})
|
||||||
} else {
|
for _, client := range s.sortClients(domain) {
|
||||||
return s.serialQuery(domain, option)
|
if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
|
||||||
|
errors.LogDebug(s.ctx, "skip DNS resolution for domain ", domain, " at server ", client.Name())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ips, err := client.QueryIP(ctx, domain, option, s.disableCache)
|
||||||
|
if len(ips) > 0 {
|
||||||
|
return ips, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
errors.LogInfoInner(s.ctx, err, "failed to lookup ip for domain ", domain, " at server ", client.Name())
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
// 5 for RcodeRefused in miekg/dns, hardcode to reduce binary size
|
||||||
|
if err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch && err != dns.ErrEmptyResponse && dns.RCodeFromError(err) != 5 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("returning nil for domain ", domain).Base(errors.Combine(errs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupHosts implements dns.HostsLookup.
|
||||||
|
func (s *DNS) LookupHosts(domain string) *net.Address {
|
||||||
|
domain = strings.TrimSuffix(domain, ".")
|
||||||
|
if domain == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Normalize the FQDN form query
|
||||||
|
addrs := s.hosts.Lookup(domain, *s.ipOption)
|
||||||
|
if len(addrs) > 0 {
|
||||||
|
errors.LogInfo(s.ctx, "domain replaced: ", domain, " -> ", addrs[0].String())
|
||||||
|
return &addrs[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIPOption implements ClientWithIPOption.
|
||||||
|
func (s *DNS) GetIPOption() *dns.IPOption {
|
||||||
|
return s.ipOption
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetQueryOption implements ClientWithIPOption.
|
||||||
|
func (s *DNS) SetQueryOption(isIPv4Enable, isIPv6Enable bool) {
|
||||||
|
s.ipOption.IPv4Enable = isIPv4Enable
|
||||||
|
s.ipOption.IPv6Enable = isIPv6Enable
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFakeDNSOption implements ClientWithIPOption.
|
||||||
|
func (s *DNS) SetFakeDNSOption(isFakeEnable bool) {
|
||||||
|
s.ipOption.FakeEnable = isFakeEnable
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DNS) sortClients(domain string) []*Client {
|
func (s *DNS) sortClients(domain string) []*Client {
|
||||||
@@ -260,11 +250,7 @@ func (s *DNS) sortClients(domain string) []*Client {
|
|||||||
|
|
||||||
// Priority domain matching
|
// Priority domain matching
|
||||||
hasMatch := false
|
hasMatch := false
|
||||||
MatchSlice := s.domainMatcher.Match(domain)
|
for _, match := range s.domainMatcher.Match(domain) {
|
||||||
sort.Slice(MatchSlice, func(i, j int) bool {
|
|
||||||
return MatchSlice[i] < MatchSlice[j]
|
|
||||||
})
|
|
||||||
for _, match := range MatchSlice {
|
|
||||||
info := s.matcherInfos[match]
|
info := s.matcherInfos[match]
|
||||||
client := s.clients[info.clientIdx]
|
client := s.clients[info.clientIdx]
|
||||||
domainRule := client.domains[info.domainRuleIdx]
|
domainRule := client.domains[info.domainRuleIdx]
|
||||||
@@ -276,9 +262,6 @@ func (s *DNS) sortClients(domain string) []*Client {
|
|||||||
clients = append(clients, client)
|
clients = append(clients, client)
|
||||||
clientNames = append(clientNames, client.Name())
|
clientNames = append(clientNames, client.Name())
|
||||||
hasMatch = true
|
hasMatch = true
|
||||||
if client.finalQuery {
|
|
||||||
return clients
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(s.disableFallback || s.disableFallbackIfMatch && hasMatch) {
|
if !(s.disableFallback || s.disableFallbackIfMatch && hasMatch) {
|
||||||
@@ -290,9 +273,6 @@ func (s *DNS) sortClients(domain string) []*Client {
|
|||||||
clientUsed[idx] = true
|
clientUsed[idx] = true
|
||||||
clients = append(clients, client)
|
clients = append(clients, client)
|
||||||
clientNames = append(clientNames, client.Name())
|
clientNames = append(clientNames, client.Name())
|
||||||
if client.finalQuery {
|
|
||||||
return clients
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,280 +284,16 @@ func (s *DNS) sortClients(domain string) []*Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(clients) == 0 {
|
if len(clients) == 0 {
|
||||||
if len(s.clients) > 0 {
|
clients = append(clients, s.clients[0])
|
||||||
clients = append(clients, s.clients[0])
|
clientNames = append(clientNames, s.clients[0].Name())
|
||||||
clientNames = append(clientNames, s.clients[0].Name())
|
errors.LogDebug(s.ctx, "domain ", domain, " will use the first DNS: ", clientNames)
|
||||||
errors.LogWarning(s.ctx, "domain ", domain, " will use the first DNS: ", clientNames)
|
|
||||||
} else {
|
|
||||||
errors.LogError(s.ctx, "no DNS clients available for domain ", domain, " and no default clients configured")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return clients
|
return clients
|
||||||
}
|
}
|
||||||
|
|
||||||
func mergeQueryErrors(domain string, errs []error) error {
|
|
||||||
if len(errs) == 0 {
|
|
||||||
return dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
var noRNF error
|
|
||||||
for _, err := range errs {
|
|
||||||
if go_errors.Is(err, errRecordNotFound) {
|
|
||||||
continue // server no response, ignore
|
|
||||||
} else if noRNF == nil {
|
|
||||||
noRNF = err
|
|
||||||
} else if !go_errors.Is(err, noRNF) {
|
|
||||||
return errors.New("returning nil for domain ", domain).Base(errors.Combine(errs...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if go_errors.Is(noRNF, dns.ErrEmptyResponse) {
|
|
||||||
return dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
if noRNF == nil {
|
|
||||||
noRNF = errRecordNotFound
|
|
||||||
}
|
|
||||||
return errors.New("returning nil for domain ", domain).Base(noRNF)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DNS) serialQuery(domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
|
||||||
var errs []error
|
|
||||||
for _, client := range s.sortClients(domain) {
|
|
||||||
if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
|
|
||||||
errors.LogDebug(s.ctx, "skip DNS resolution for domain ", domain, " at server ", client.Name())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ips, ttl, err := client.QueryIP(s.ctx, domain, option)
|
|
||||||
|
|
||||||
if len(ips) > 0 {
|
|
||||||
return ips, ttl, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
errors.LogInfoInner(s.ctx, err, "failed to lookup ip for domain ", domain, " at server ", client.Name(), " in serial query mode")
|
|
||||||
if err == nil {
|
|
||||||
err = dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
return nil, 0, mergeQueryErrors(domain, errs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DNS) parallelQuery(domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
|
||||||
var errs []error
|
|
||||||
clients := s.sortClients(domain)
|
|
||||||
|
|
||||||
resultsChan := asyncQueryAll(domain, option, clients, s.ctx)
|
|
||||||
|
|
||||||
groups, groupOf := makeGroups( /*s.ctx,*/ clients)
|
|
||||||
results := make([]*queryResult, len(clients))
|
|
||||||
pending := make([]int, len(groups))
|
|
||||||
for gi, g := range groups {
|
|
||||||
pending[gi] = g.end - g.start + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
nextGroup := 0
|
|
||||||
for range clients {
|
|
||||||
result := <-resultsChan
|
|
||||||
results[result.index] = &result
|
|
||||||
|
|
||||||
gi := groupOf[result.index]
|
|
||||||
pending[gi]--
|
|
||||||
|
|
||||||
for nextGroup < len(groups) {
|
|
||||||
g := groups[nextGroup]
|
|
||||||
|
|
||||||
// group race, minimum rtt -> return
|
|
||||||
for j := g.start; j <= g.end; j++ {
|
|
||||||
r := results[j]
|
|
||||||
if r != nil && r.err == nil && len(r.ips) > 0 {
|
|
||||||
return r.ips, r.ttl, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// current group is incomplete and no one success -> continue pending
|
|
||||||
if pending[nextGroup] > 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// all failed -> log and continue next group
|
|
||||||
for j := g.start; j <= g.end; j++ {
|
|
||||||
r := results[j]
|
|
||||||
e := r.err
|
|
||||||
if e == nil {
|
|
||||||
e = dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
errors.LogInfoInner(s.ctx, e, "failed to lookup ip for domain ", domain, " at server ", clients[j].Name(), " in parallel query mode")
|
|
||||||
errs = append(errs, e)
|
|
||||||
}
|
|
||||||
nextGroup++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, 0, mergeQueryErrors(domain, errs)
|
|
||||||
}
|
|
||||||
|
|
||||||
type queryResult struct {
|
|
||||||
ips []net.IP
|
|
||||||
ttl uint32
|
|
||||||
err error
|
|
||||||
index int
|
|
||||||
}
|
|
||||||
|
|
||||||
func asyncQueryAll(domain string, option dns.IPOption, clients []*Client, ctx context.Context) chan queryResult {
|
|
||||||
if len(clients) == 0 {
|
|
||||||
ch := make(chan queryResult)
|
|
||||||
close(ch)
|
|
||||||
return ch
|
|
||||||
}
|
|
||||||
|
|
||||||
ch := make(chan queryResult, len(clients))
|
|
||||||
for i, client := range clients {
|
|
||||||
if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
|
|
||||||
errors.LogDebug(ctx, "skip DNS resolution for domain ", domain, " at server ", client.Name())
|
|
||||||
ch <- queryResult{err: dns.ErrEmptyResponse, index: i}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
go func(i int, c *Client) {
|
|
||||||
qctx := ctx
|
|
||||||
if !c.server.IsDisableCache() {
|
|
||||||
nctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), c.timeoutMs*2)
|
|
||||||
qctx = nctx
|
|
||||||
defer cancel()
|
|
||||||
}
|
|
||||||
ips, ttl, err := c.QueryIP(qctx, domain, option)
|
|
||||||
ch <- queryResult{ips: ips, ttl: ttl, err: err, index: i}
|
|
||||||
}(i, client)
|
|
||||||
}
|
|
||||||
return ch
|
|
||||||
}
|
|
||||||
|
|
||||||
type group struct{ start, end int }
|
|
||||||
|
|
||||||
// merge only adjacent and rule-equivalent Client into a single group
|
|
||||||
func makeGroups( /*ctx context.Context,*/ clients []*Client) ([]group, []int) {
|
|
||||||
n := len(clients)
|
|
||||||
if n == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
groups := make([]group, 0, n)
|
|
||||||
groupOf := make([]int, n)
|
|
||||||
|
|
||||||
s, e := 0, 0
|
|
||||||
for i := 1; i < n; i++ {
|
|
||||||
if clients[i-1].policyID == clients[i].policyID {
|
|
||||||
e = i
|
|
||||||
} else {
|
|
||||||
for k := s; k <= e; k++ {
|
|
||||||
groupOf[k] = len(groups)
|
|
||||||
}
|
|
||||||
groups = append(groups, group{start: s, end: e})
|
|
||||||
s, e = i, i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for k := s; k <= e; k++ {
|
|
||||||
groupOf[k] = len(groups)
|
|
||||||
}
|
|
||||||
groups = append(groups, group{start: s, end: e})
|
|
||||||
|
|
||||||
// var b strings.Builder
|
|
||||||
// b.WriteString("dns grouping: total clients=")
|
|
||||||
// b.WriteString(strconv.Itoa(n))
|
|
||||||
// b.WriteString(", groups=")
|
|
||||||
// b.WriteString(strconv.Itoa(len(groups)))
|
|
||||||
|
|
||||||
// for gi, g := range groups {
|
|
||||||
// b.WriteString("\n [")
|
|
||||||
// b.WriteString(strconv.Itoa(g.start))
|
|
||||||
// b.WriteString("..")
|
|
||||||
// b.WriteString(strconv.Itoa(g.end))
|
|
||||||
// b.WriteString("] gid=")
|
|
||||||
// b.WriteString(strconv.Itoa(gi))
|
|
||||||
// b.WriteString(" pid=")
|
|
||||||
// b.WriteString(strconv.FormatUint(uint64(clients[g.start].policyID), 10))
|
|
||||||
// b.WriteString(" members: ")
|
|
||||||
|
|
||||||
// for i := g.start; i <= g.end; i++ {
|
|
||||||
// if i > g.start {
|
|
||||||
// b.WriteString(", ")
|
|
||||||
// }
|
|
||||||
// b.WriteString(strconv.Itoa(i))
|
|
||||||
// b.WriteByte(':')
|
|
||||||
// b.WriteString(clients[i].Name())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// errors.LogDebug(ctx, b.String())
|
|
||||||
|
|
||||||
return groups, groupOf
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||||
return New(ctx, config.(*Config))
|
return New(ctx, config.(*Config))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func probeRoutes() (ipv4 bool, ipv6 bool) {
|
|
||||||
if conn, err := net.Dial("udp4", "192.33.4.12:53"); err == nil {
|
|
||||||
ipv4 = true
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
if conn, err := net.Dial("udp6", "[2001:500:2::c]:53"); err == nil {
|
|
||||||
ipv6 = true
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var routeCache struct {
|
|
||||||
sync.Once
|
|
||||||
sync.RWMutex
|
|
||||||
expire time.Time
|
|
||||||
ipv4, ipv6 bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkRoutes() (bool, bool) {
|
|
||||||
if !isGUIPlatform {
|
|
||||||
routeCache.Once.Do(func() {
|
|
||||||
routeCache.ipv4, routeCache.ipv6 = probeRoutes()
|
|
||||||
})
|
|
||||||
return routeCache.ipv4, routeCache.ipv6
|
|
||||||
}
|
|
||||||
|
|
||||||
routeCache.RWMutex.RLock()
|
|
||||||
now := time.Now()
|
|
||||||
if routeCache.expire.After(now) {
|
|
||||||
routeCache.RWMutex.RUnlock()
|
|
||||||
return routeCache.ipv4, routeCache.ipv6
|
|
||||||
}
|
|
||||||
routeCache.RWMutex.RUnlock()
|
|
||||||
|
|
||||||
routeCache.RWMutex.Lock()
|
|
||||||
defer routeCache.RWMutex.Unlock()
|
|
||||||
|
|
||||||
now = time.Now()
|
|
||||||
if routeCache.expire.After(now) { // double-check
|
|
||||||
return routeCache.ipv4, routeCache.ipv6
|
|
||||||
}
|
|
||||||
routeCache.ipv4, routeCache.ipv6 = probeRoutes() // ~2ms
|
|
||||||
routeCache.expire = now.Add(100 * time.Millisecond) // ttl
|
|
||||||
return routeCache.ipv4, routeCache.ipv6
|
|
||||||
}
|
|
||||||
|
|
||||||
var isGUIPlatform = detectGUIPlatform()
|
|
||||||
|
|
||||||
func detectGUIPlatform() bool {
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "android", "ios", "windows", "darwin":
|
|
||||||
return true
|
|
||||||
case "linux", "freebsd", "openbsd":
|
|
||||||
if t := os.Getenv("XDG_SESSION_TYPE"); t == "wayland" || t == "x11" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if os.Getenv("DISPLAY") != "" || os.Getenv("WAYLAND_DISPLAY") != "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -76,9 +76,6 @@ func (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||||||
case q.Name == "notexist.google.com." && q.Qtype == dns.TypeAAAA:
|
case q.Name == "notexist.google.com." && q.Qtype == dns.TypeAAAA:
|
||||||
ans.MsgHdr.Rcode = dns.RcodeNameError
|
ans.MsgHdr.Rcode = dns.RcodeNameError
|
||||||
|
|
||||||
case q.Name == "notexist.google.com." && q.Qtype == dns.TypeA:
|
|
||||||
ans.MsgHdr.Rcode = dns.RcodeNameError
|
|
||||||
|
|
||||||
case q.Name == "hostname." && q.Qtype == dns.TypeA:
|
case q.Name == "hostname." && q.Qtype == dns.TypeA:
|
||||||
rr, _ := dns.NewRR("hostname. IN A 127.0.0.1")
|
rr, _ := dns.NewRR("hostname. IN A 127.0.0.1")
|
||||||
ans.Answer = append(ans.Answer, rr)
|
ans.Answer = append(ans.Answer, rr)
|
||||||
@@ -120,6 +117,7 @@ func TestUDPServerSubnet(t *testing.T) {
|
|||||||
Handler: &staticHandler{},
|
Handler: &staticHandler{},
|
||||||
UDPSize: 1200,
|
UDPSize: 1200,
|
||||||
}
|
}
|
||||||
|
|
||||||
go dnsServer.ListenAndServe()
|
go dnsServer.ListenAndServe()
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
@@ -157,7 +155,7 @@ func TestUDPServerSubnet(t *testing.T) {
|
|||||||
|
|
||||||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||||
|
|
||||||
ips, _, err := client.LookupIP("google.com", feature_dns.IPOption{
|
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -218,7 +216,7 @@ func TestUDPServer(t *testing.T) {
|
|||||||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||||
|
|
||||||
{
|
{
|
||||||
ips, _, err := client.LookupIP("google.com", feature_dns.IPOption{
|
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -233,7 +231,7 @@ func TestUDPServer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ips, _, err := client.LookupIP("facebook.com", feature_dns.IPOption{
|
ips, err := client.LookupIP("facebook.com", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -248,7 +246,7 @@ func TestUDPServer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
_, _, err := client.LookupIP("notexist.google.com", feature_dns.IPOption{
|
_, err := client.LookupIP("notexist.google.com", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -262,7 +260,7 @@ func TestUDPServer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ips, _, err := client.LookupIP("ipv4only.google.com", feature_dns.IPOption{
|
ips, err := client.LookupIP("ipv4only.google.com", feature_dns.IPOption{
|
||||||
IPv4Enable: false,
|
IPv4Enable: false,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -278,7 +276,7 @@ func TestUDPServer(t *testing.T) {
|
|||||||
dnsServer.Shutdown()
|
dnsServer.Shutdown()
|
||||||
|
|
||||||
{
|
{
|
||||||
ips, _, err := client.LookupIP("google.com", feature_dns.IPOption{
|
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -359,7 +357,7 @@ func TestPrioritizedDomain(t *testing.T) {
|
|||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
{
|
{
|
||||||
ips, _, err := client.LookupIP("google.com", feature_dns.IPOption{
|
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -425,7 +423,7 @@ func TestUDPServerIPv6(t *testing.T) {
|
|||||||
|
|
||||||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||||
{
|
{
|
||||||
ips, _, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
|
ips, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
|
||||||
IPv4Enable: false,
|
IPv4Enable: false,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -494,7 +492,7 @@ func TestStaticHostDomain(t *testing.T) {
|
|||||||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||||
|
|
||||||
{
|
{
|
||||||
ips, _, err := client.LookupIP("example.com", feature_dns.IPOption{
|
ips, err := client.LookupIP("example.com", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -539,7 +537,7 @@ func TestIPMatch(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Port: uint32(port),
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
ExpectedGeoip: []*router.GeoIP{
|
Geoip: []*router.GeoIP{
|
||||||
{
|
{
|
||||||
CountryCode: "local",
|
CountryCode: "local",
|
||||||
Cidr: []*router.CIDR{
|
Cidr: []*router.CIDR{
|
||||||
@@ -563,7 +561,7 @@ func TestIPMatch(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Port: uint32(port),
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
ExpectedGeoip: []*router.GeoIP{
|
Geoip: []*router.GeoIP{
|
||||||
{
|
{
|
||||||
CountryCode: "test",
|
CountryCode: "test",
|
||||||
Cidr: []*router.CIDR{
|
Cidr: []*router.CIDR{
|
||||||
@@ -605,7 +603,7 @@ func TestIPMatch(t *testing.T) {
|
|||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
{
|
{
|
||||||
ips, _, err := client.LookupIP("google.com", feature_dns.IPOption{
|
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -667,7 +665,7 @@ func TestLocalDomain(t *testing.T) {
|
|||||||
// Equivalent of dotless:localhost
|
// Equivalent of dotless:localhost
|
||||||
{Type: DomainMatchingType_Regex, Domain: "^[^.]*localhost[^.]*$"},
|
{Type: DomainMatchingType_Regex, Domain: "^[^.]*localhost[^.]*$"},
|
||||||
},
|
},
|
||||||
ExpectedGeoip: []*router.GeoIP{
|
Geoip: []*router.GeoIP{
|
||||||
{ // Will match localhost, localhost-a and localhost-b,
|
{ // Will match localhost, localhost-a and localhost-b,
|
||||||
CountryCode: "local",
|
CountryCode: "local",
|
||||||
Cidr: []*router.CIDR{
|
Cidr: []*router.CIDR{
|
||||||
@@ -728,7 +726,7 @@ func TestLocalDomain(t *testing.T) {
|
|||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
{ // Will match dotless:
|
{ // Will match dotless:
|
||||||
ips, _, err := client.LookupIP("hostname", feature_dns.IPOption{
|
ips, err := client.LookupIP("hostname", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -743,7 +741,7 @@ func TestLocalDomain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{ // Will match domain:local
|
{ // Will match domain:local
|
||||||
ips, _, err := client.LookupIP("hostname.local", feature_dns.IPOption{
|
ips, err := client.LookupIP("hostname.local", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -758,7 +756,7 @@ func TestLocalDomain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{ // Will match static ip
|
{ // Will match static ip
|
||||||
ips, _, err := client.LookupIP("hostnamestatic", feature_dns.IPOption{
|
ips, err := client.LookupIP("hostnamestatic", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -773,7 +771,7 @@ func TestLocalDomain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{ // Will match domain replacing
|
{ // Will match domain replacing
|
||||||
ips, _, err := client.LookupIP("hostnamealias", feature_dns.IPOption{
|
ips, err := client.LookupIP("hostnamealias", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -787,8 +785,8 @@ func TestLocalDomain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Will match dotless:localhost, but not expectedIPs: 127.0.0.2, 127.0.0.3, then matches at dotless:
|
{ // Will match dotless:localhost, but not expectIPs: 127.0.0.2, 127.0.0.3, then matches at dotless:
|
||||||
ips, _, err := client.LookupIP("localhost", feature_dns.IPOption{
|
ips, err := client.LookupIP("localhost", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -802,8 +800,8 @@ func TestLocalDomain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Will match dotless:localhost, and expectedIPs: 127.0.0.2, 127.0.0.3
|
{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3
|
||||||
ips, _, err := client.LookupIP("localhost-a", feature_dns.IPOption{
|
ips, err := client.LookupIP("localhost-a", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -817,8 +815,8 @@ func TestLocalDomain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Will match dotless:localhost, and expectedIPs: 127.0.0.2, 127.0.0.3
|
{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3
|
||||||
ips, _, err := client.LookupIP("localhost-b", feature_dns.IPOption{
|
ips, err := client.LookupIP("localhost-b", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -833,7 +831,7 @@ func TestLocalDomain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{ // Will match dotless:
|
{ // Will match dotless:
|
||||||
ips, _, err := client.LookupIP("Mijia Cloud", feature_dns.IPOption{
|
ips, err := client.LookupIP("Mijia Cloud", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -897,7 +895,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
Domain: "google.com",
|
Domain: "google.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedGeoip: []*router.GeoIP{
|
Geoip: []*router.GeoIP{
|
||||||
{ // Will only match 8.8.8.8 and 8.8.4.4
|
{ // Will only match 8.8.8.8 and 8.8.4.4
|
||||||
Cidr: []*router.CIDR{
|
Cidr: []*router.CIDR{
|
||||||
{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
|
{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
|
||||||
@@ -922,7 +920,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
Domain: "google.com",
|
Domain: "google.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedGeoip: []*router.GeoIP{
|
Geoip: []*router.GeoIP{
|
||||||
{ // Will match 8.8.8.8 and 8.8.8.7, etc
|
{ // Will match 8.8.8.8 and 8.8.8.7, etc
|
||||||
Cidr: []*router.CIDR{
|
Cidr: []*router.CIDR{
|
||||||
{Ip: []byte{8, 8, 8, 7}, Prefix: 24},
|
{Ip: []byte{8, 8, 8, 7}, Prefix: 24},
|
||||||
@@ -946,7 +944,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
Domain: "api.google.com",
|
Domain: "api.google.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedGeoip: []*router.GeoIP{
|
Geoip: []*router.GeoIP{
|
||||||
{ // Will only match 8.8.7.7 (api.google.com)
|
{ // Will only match 8.8.7.7 (api.google.com)
|
||||||
Cidr: []*router.CIDR{
|
Cidr: []*router.CIDR{
|
||||||
{Ip: []byte{8, 8, 7, 7}, Prefix: 32},
|
{Ip: []byte{8, 8, 7, 7}, Prefix: 32},
|
||||||
@@ -970,7 +968,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
Domain: "v2.api.google.com",
|
Domain: "v2.api.google.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedGeoip: []*router.GeoIP{
|
Geoip: []*router.GeoIP{
|
||||||
{ // Will only match 8.8.7.8 (v2.api.google.com)
|
{ // Will only match 8.8.7.8 (v2.api.google.com)
|
||||||
Cidr: []*router.CIDR{
|
Cidr: []*router.CIDR{
|
||||||
{Ip: []byte{8, 8, 7, 8}, Prefix: 32},
|
{Ip: []byte{8, 8, 7, 8}, Prefix: 32},
|
||||||
@@ -999,7 +997,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
{ // Will match server 1,2 and server 1 returns expected ip
|
{ // Will match server 1,2 and server 1 returns expected ip
|
||||||
ips, _, err := client.LookupIP("google.com", feature_dns.IPOption{
|
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -1014,7 +1012,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{ // Will match server 1,2 and server 1 returns unexpected ip, then server 2 returns expected one
|
{ // Will match server 1,2 and server 1 returns unexpected ip, then server 2 returns expected one
|
||||||
ips, _, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
|
ips, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: false,
|
IPv6Enable: false,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -1029,7 +1027,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{ // Will match server 3,1,2 and server 3 returns expected one
|
{ // Will match server 3,1,2 and server 3 returns expected one
|
||||||
ips, _, err := client.LookupIP("api.google.com", feature_dns.IPOption{
|
ips, err := client.LookupIP("api.google.com", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
@@ -1044,7 +1042,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{ // Will match server 4,3,1,2 and server 4 returns expected one
|
{ // Will match server 4,3,1,2 and server 4 returns expected one
|
||||||
ips, _, err := client.LookupIP("v2.api.google.com", feature_dns.IPOption{
|
ips, err := client.LookupIP("v2.api.google.com", feature_dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package dns
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"math"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -14,12 +13,10 @@ import (
|
|||||||
"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"
|
||||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||||
|
|
||||||
"golang.org/x/net/dns/dnsmessage"
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fqdn normalizes domain make sure it ends with '.'
|
// Fqdn normalizes domain make sure it ends with '.'
|
||||||
// case-sensitive
|
|
||||||
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
|
||||||
@@ -34,29 +31,30 @@ type record struct {
|
|||||||
|
|
||||||
// IPRecord is a cacheable item for a resolved domain
|
// IPRecord is a cacheable item for a resolved domain
|
||||||
type IPRecord struct {
|
type IPRecord struct {
|
||||||
ReqID uint16
|
ReqID uint16
|
||||||
IP []net.IP
|
IP []net.Address
|
||||||
Expire time.Time
|
Expire time.Time
|
||||||
RCode dnsmessage.RCode
|
RCode dnsmessage.RCode
|
||||||
RawHeader *dnsmessage.Header
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IPRecord) getIPs() ([]net.IP, int32, error) {
|
func (r *IPRecord) getIPs() ([]net.Address, error) {
|
||||||
if r == nil {
|
if r == nil || r.Expire.Before(time.Now()) {
|
||||||
return nil, 0, errRecordNotFound
|
return nil, errRecordNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
untilExpire := time.Until(r.Expire).Seconds()
|
|
||||||
ttl := int32(math.Ceil(untilExpire))
|
|
||||||
|
|
||||||
if r.RCode != dnsmessage.RCodeSuccess {
|
if r.RCode != dnsmessage.RCodeSuccess {
|
||||||
return nil, ttl, dns_feature.RCodeError(r.RCode)
|
return nil, dns_feature.RCodeError(r.RCode)
|
||||||
}
|
|
||||||
if len(r.IP) == 0 {
|
|
||||||
return nil, ttl, dns_feature.ErrEmptyResponse
|
|
||||||
}
|
}
|
||||||
|
return r.IP, nil
|
||||||
|
}
|
||||||
|
|
||||||
return r.IP, ttl, nil
|
func isNewer(baseRec *IPRecord, newRec *IPRecord) bool {
|
||||||
|
if newRec == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if baseRec == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return baseRec.Expire.Before(newRec.Expire)
|
||||||
}
|
}
|
||||||
|
|
||||||
var errRecordNotFound = errors.New("record not found")
|
var errRecordNotFound = errors.New("record not found")
|
||||||
@@ -69,59 +67,49 @@ type dnsRequest struct {
|
|||||||
msg *dnsmessage.Message
|
msg *dnsmessage.Message
|
||||||
}
|
}
|
||||||
|
|
||||||
func genEDNS0Options(clientIP net.IP, padding int) *dnsmessage.Resource {
|
func genEDNS0Options(clientIP net.IP) *dnsmessage.Resource {
|
||||||
if len(clientIP) == 0 && padding == 0 {
|
if len(clientIP) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const EDNS0SUBNET = 0x8
|
var netmask int
|
||||||
const EDNS0PADDING = 0xc
|
var family uint16
|
||||||
|
|
||||||
|
if len(clientIP) == 4 {
|
||||||
|
family = 1
|
||||||
|
netmask = 24 // 24 for IPV4, 96 for IPv6
|
||||||
|
} else {
|
||||||
|
family = 2
|
||||||
|
netmask = 96
|
||||||
|
}
|
||||||
|
|
||||||
|
b := make([]byte, 4)
|
||||||
|
binary.BigEndian.PutUint16(b[0:], family)
|
||||||
|
b[2] = byte(netmask)
|
||||||
|
b[3] = 0
|
||||||
|
switch family {
|
||||||
|
case 1:
|
||||||
|
ip := clientIP.To4().Mask(net.CIDRMask(netmask, net.IPv4len*8))
|
||||||
|
needLength := (netmask + 8 - 1) / 8 // division rounding up
|
||||||
|
b = append(b, ip[:needLength]...)
|
||||||
|
case 2:
|
||||||
|
ip := clientIP.Mask(net.CIDRMask(netmask, net.IPv6len*8))
|
||||||
|
needLength := (netmask + 8 - 1) / 8 // division rounding up
|
||||||
|
b = append(b, ip[:needLength]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
const EDNS0SUBNET = 0x08
|
||||||
|
|
||||||
opt := new(dnsmessage.Resource)
|
opt := new(dnsmessage.Resource)
|
||||||
common.Must(opt.Header.SetEDNS0(1350, 0xfe00, true))
|
common.Must(opt.Header.SetEDNS0(1350, 0xfe00, true))
|
||||||
body := dnsmessage.OPTResource{}
|
|
||||||
opt.Body = &body
|
|
||||||
|
|
||||||
if len(clientIP) != 0 {
|
opt.Body = &dnsmessage.OPTResource{
|
||||||
var netmask int
|
Options: []dnsmessage.Option{
|
||||||
var family uint16
|
{
|
||||||
|
|
||||||
if len(clientIP) == 4 {
|
|
||||||
family = 1
|
|
||||||
netmask = 24 // 24 for IPV4, 96 for IPv6
|
|
||||||
} else {
|
|
||||||
family = 2
|
|
||||||
netmask = 96
|
|
||||||
}
|
|
||||||
|
|
||||||
b := make([]byte, 4)
|
|
||||||
binary.BigEndian.PutUint16(b[0:], family)
|
|
||||||
b[2] = byte(netmask)
|
|
||||||
b[3] = 0
|
|
||||||
switch family {
|
|
||||||
case 1:
|
|
||||||
ip := clientIP.To4().Mask(net.CIDRMask(netmask, net.IPv4len*8))
|
|
||||||
needLength := (netmask + 8 - 1) / 8 // division rounding up
|
|
||||||
b = append(b, ip[:needLength]...)
|
|
||||||
case 2:
|
|
||||||
ip := clientIP.Mask(net.CIDRMask(netmask, net.IPv6len*8))
|
|
||||||
needLength := (netmask + 8 - 1) / 8 // division rounding up
|
|
||||||
b = append(b, ip[:needLength]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
body.Options = append(body.Options,
|
|
||||||
dnsmessage.Option{
|
|
||||||
Code: EDNS0SUBNET,
|
Code: EDNS0SUBNET,
|
||||||
Data: b,
|
Data: b,
|
||||||
})
|
},
|
||||||
}
|
},
|
||||||
|
|
||||||
if padding != 0 {
|
|
||||||
body.Options = append(body.Options,
|
|
||||||
dnsmessage.Option{
|
|
||||||
Code: EDNS0PADDING,
|
|
||||||
Data: make([]byte, padding),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return opt
|
return opt
|
||||||
@@ -191,10 +179,9 @@ func parseResponse(payload []byte) (*IPRecord, error) {
|
|||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
ipRecord := &IPRecord{
|
ipRecord := &IPRecord{
|
||||||
ReqID: h.ID,
|
ReqID: h.ID,
|
||||||
RCode: h.RCode,
|
RCode: h.RCode,
|
||||||
Expire: now.Add(time.Second * dns_feature.DefaultTTL),
|
Expire: now.Add(time.Second * 600),
|
||||||
RawHeader: &h,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
L:
|
L:
|
||||||
@@ -209,7 +196,7 @@ L:
|
|||||||
|
|
||||||
ttl := ah.TTL
|
ttl := ah.TTL
|
||||||
if ttl == 0 {
|
if ttl == 0 {
|
||||||
ttl = 1
|
ttl = 600
|
||||||
}
|
}
|
||||||
expire := now.Add(time.Duration(ttl) * time.Second)
|
expire := now.Add(time.Duration(ttl) * time.Second)
|
||||||
if ipRecord.Expire.After(expire) {
|
if ipRecord.Expire.After(expire) {
|
||||||
@@ -223,17 +210,14 @@ L:
|
|||||||
errors.LogInfoInner(context.Background(), err, "failed to parse A record for domain: ", ah.Name)
|
errors.LogInfoInner(context.Background(), err, "failed to parse A record for domain: ", ah.Name)
|
||||||
break L
|
break L
|
||||||
}
|
}
|
||||||
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.A[:]).IP())
|
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.A[:]))
|
||||||
case dnsmessage.TypeAAAA:
|
case dnsmessage.TypeAAAA:
|
||||||
ans, err := parser.AAAAResource()
|
ans, err := parser.AAAAResource()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogInfoInner(context.Background(), err, "failed to parse AAAA record for domain: ", ah.Name)
|
errors.LogInfoInner(context.Background(), err, "failed to parse AAAA record for domain: ", ah.Name)
|
||||||
break L
|
break L
|
||||||
}
|
}
|
||||||
newIP := net.IPAddress(ans.AAAA[:]).IP()
|
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.AAAA[:]))
|
||||||
if len(newIP) == net.IPv6len {
|
|
||||||
ipRecord.IP = append(ipRecord.IP, newIP)
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
if err := parser.SkipAnswer(); err != nil {
|
if err := parser.SkipAnswer(); err != nil {
|
||||||
errors.LogInfoInner(context.Background(), err, "failed to skip answer")
|
errors.LogInfoInner(context.Background(), err, "failed to skip answer")
|
||||||
|
|||||||
@@ -18,31 +18,31 @@ func Test_parseResponse(t *testing.T) {
|
|||||||
|
|
||||||
ans := new(dns.Msg)
|
ans := new(dns.Msg)
|
||||||
ans.Id = 0
|
ans.Id = 0
|
||||||
p = append(p, common.Must2(ans.Pack()))
|
p = append(p, common.Must2(ans.Pack()).([]byte))
|
||||||
|
|
||||||
p = append(p, []byte{})
|
p = append(p, []byte{})
|
||||||
|
|
||||||
ans = new(dns.Msg)
|
ans = new(dns.Msg)
|
||||||
ans.Id = 1
|
ans.Id = 1
|
||||||
ans.Answer = append(ans.Answer,
|
ans.Answer = append(ans.Answer,
|
||||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
|
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
|
||||||
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")),
|
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")).(dns.RR),
|
||||||
common.Must2(dns.NewRR("google.com. IN A 8.8.8.8")),
|
common.Must2(dns.NewRR("google.com. IN A 8.8.8.8")).(dns.RR),
|
||||||
common.Must2(dns.NewRR("google.com. IN A 8.8.4.4")),
|
common.Must2(dns.NewRR("google.com. IN A 8.8.4.4")).(dns.RR),
|
||||||
)
|
)
|
||||||
p = append(p, common.Must2(ans.Pack()))
|
p = append(p, common.Must2(ans.Pack()).([]byte))
|
||||||
|
|
||||||
ans = new(dns.Msg)
|
ans = new(dns.Msg)
|
||||||
ans.Id = 2
|
ans.Id = 2
|
||||||
ans.Answer = append(ans.Answer,
|
ans.Answer = append(ans.Answer,
|
||||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
|
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
|
||||||
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")),
|
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")).(dns.RR),
|
||||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
|
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
|
||||||
common.Must2(dns.NewRR("google.com. IN CNAME test.google.com")),
|
common.Must2(dns.NewRR("google.com. IN CNAME test.google.com")).(dns.RR),
|
||||||
common.Must2(dns.NewRR("google.com. IN AAAA 2001:4860:4860::8888")),
|
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8888")).(dns.RR),
|
||||||
common.Must2(dns.NewRR("google.com. IN AAAA 2001:4860:4860::8844")),
|
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8844")).(dns.RR),
|
||||||
)
|
)
|
||||||
p = append(p, common.Must2(ans.Pack()))
|
p = append(p, common.Must2(ans.Pack()).([]byte))
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -51,7 +51,7 @@ func Test_parseResponse(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"empty",
|
"empty",
|
||||||
&IPRecord{0, []net.IP(nil), time.Time{}, dnsmessage.RCodeSuccess, nil},
|
&IPRecord{0, []net.Address(nil), time.Time{}, dnsmessage.RCodeSuccess},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -63,16 +63,15 @@ func Test_parseResponse(t *testing.T) {
|
|||||||
"a record",
|
"a record",
|
||||||
&IPRecord{
|
&IPRecord{
|
||||||
1,
|
1,
|
||||||
[]net.IP{net.ParseIP("8.8.8.8"), net.ParseIP("8.8.4.4")},
|
[]net.Address{net.ParseAddress("8.8.8.8"), net.ParseAddress("8.8.4.4")},
|
||||||
time.Time{},
|
time.Time{},
|
||||||
dnsmessage.RCodeSuccess,
|
dnsmessage.RCodeSuccess,
|
||||||
nil,
|
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"aaaa record",
|
"aaaa record",
|
||||||
&IPRecord{2, []net.IP{net.ParseIP("2001:4860:4860::8888"), net.ParseIP("2001:4860:4860::8844")}, time.Time{}, dnsmessage.RCodeSuccess, nil},
|
&IPRecord{2, []net.Address{net.ParseAddress("2001::123:8888"), net.ParseAddress("2001::123:8844")}, time.Time{}, dnsmessage.RCodeSuccess},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -85,9 +84,8 @@ func Test_parseResponse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if got != nil {
|
if got != nil {
|
||||||
// reset the time and RawHeader
|
// reset the time
|
||||||
got.Expire = time.Time{}
|
got.Expire = time.Time{}
|
||||||
got.RawHeader = nil
|
|
||||||
}
|
}
|
||||||
if cmp.Diff(got, tt.want) != "" {
|
if cmp.Diff(got, tt.want) != "" {
|
||||||
t.Error(cmp.Diff(got, tt.want))
|
t.Error(cmp.Diff(got, tt.want))
|
||||||
@@ -156,7 +154,7 @@ func Test_genEDNS0Options(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got := genEDNS0Options(tt.args.clientIP, 0); got == nil {
|
if got := genEDNS0Options(tt.args.clientIP); got == nil {
|
||||||
t.Errorf("genEDNS0Options() = %v, want %v", got, tt.want)
|
t.Errorf("genEDNS0Options() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
@@ -33,15 +32,7 @@ func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
|
|||||||
ips := make([]net.Address, 0, len(mapping.Ip)+1)
|
ips := make([]net.Address, 0, len(mapping.Ip)+1)
|
||||||
switch {
|
switch {
|
||||||
case len(mapping.ProxiedDomain) > 0:
|
case len(mapping.ProxiedDomain) > 0:
|
||||||
if mapping.ProxiedDomain[0] == '#' {
|
ips = append(ips, net.DomainAddress(mapping.ProxiedDomain))
|
||||||
rcode, err := strconv.Atoi(mapping.ProxiedDomain[1:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ips = append(ips, dns.RCodeError(rcode))
|
|
||||||
} else {
|
|
||||||
ips = append(ips, net.DomainAddress(mapping.ProxiedDomain))
|
|
||||||
}
|
|
||||||
case len(mapping.Ip) > 0:
|
case len(mapping.Ip) > 0:
|
||||||
for _, ip := range mapping.Ip {
|
for _, ip := range mapping.Ip {
|
||||||
addr := net.IPAddress(ip)
|
addr := net.IPAddress(ip)
|
||||||
@@ -50,6 +41,8 @@ func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
|
|||||||
}
|
}
|
||||||
ips = append(ips, addr)
|
ips = append(ips, addr)
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
return nil, errors.New("neither IP address nor proxied domain specified for domain: ", mapping.Domain).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
sh.ips[id] = ips
|
sh.ips[id] = ips
|
||||||
@@ -68,51 +61,33 @@ func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
|
|||||||
return filtered
|
return filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *StaticHosts) lookupInternal(domain string) ([]net.Address, error) {
|
func (h *StaticHosts) lookupInternal(domain string) []net.Address {
|
||||||
ips := make([]net.Address, 0)
|
var ips []net.Address
|
||||||
found := false
|
|
||||||
for _, id := range h.matchers.Match(domain) {
|
for _, id := range h.matchers.Match(domain) {
|
||||||
for _, v := range h.ips[id] {
|
|
||||||
if err, ok := v.(dns.RCodeError); ok {
|
|
||||||
if uint16(err) == 0 {
|
|
||||||
return nil, dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ips = append(ips, h.ips[id]...)
|
ips = append(ips, h.ips[id]...)
|
||||||
found = true
|
|
||||||
}
|
}
|
||||||
if !found {
|
return ips
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return ips, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) ([]net.Address, error) {
|
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) []net.Address {
|
||||||
switch addrs, err := h.lookupInternal(domain); {
|
switch addrs := h.lookupInternal(domain); {
|
||||||
case err != nil:
|
|
||||||
return nil, err
|
|
||||||
case len(addrs) == 0: // Not recorded in static hosts, return nil
|
case len(addrs) == 0: // Not recorded in static hosts, return nil
|
||||||
return addrs, nil
|
return nil
|
||||||
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Try to unwrap domain
|
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Try to unwrap domain
|
||||||
errors.LogDebug(context.Background(), "found replaced domain: ", domain, " -> ", addrs[0].Domain(), ". Try to unwrap it")
|
errors.LogDebug(context.Background(), "found replaced domain: ", domain, " -> ", addrs[0].Domain(), ". Try to unwrap it")
|
||||||
if maxDepth > 0 {
|
if maxDepth > 0 {
|
||||||
unwrapped, err := h.lookup(addrs[0].Domain(), option, maxDepth-1)
|
unwrapped := h.lookup(addrs[0].Domain(), option, maxDepth-1)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if unwrapped != nil {
|
if unwrapped != nil {
|
||||||
return unwrapped, nil
|
return unwrapped
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return addrs, nil
|
return addrs
|
||||||
default: // IP record found, return a non-nil IP array
|
default: // IP record found, return a non-nil IP array
|
||||||
return filterIP(addrs, option), nil
|
return filterIP(addrs, option)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup returns IP addresses or proxied domain for the given domain, if exists in this StaticHosts.
|
// Lookup returns IP addresses or proxied domain for the given domain, if exists in this StaticHosts.
|
||||||
func (h *StaticHosts) Lookup(domain string, option dns.IPOption) ([]net.Address, error) {
|
func (h *StaticHosts) Lookup(domain string, option dns.IPOption) []net.Address {
|
||||||
return h.lookup(domain, option, 5)
|
return h.lookup(domain, option, 5)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,6 @@ import (
|
|||||||
|
|
||||||
func TestStaticHosts(t *testing.T) {
|
func TestStaticHosts(t *testing.T) {
|
||||||
pb := []*Config_HostMapping{
|
pb := []*Config_HostMapping{
|
||||||
{
|
|
||||||
Type: DomainMatchingType_Subdomain,
|
|
||||||
Domain: "lan",
|
|
||||||
ProxiedDomain: "#3",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Type: DomainMatchingType_Full,
|
Type: DomainMatchingType_Full,
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
@@ -59,14 +54,7 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
{
|
{
|
||||||
_, err := hosts.Lookup("example.com.lan", dns.IPOption{})
|
ips := hosts.Lookup("example.com", dns.IPOption{
|
||||||
if dns.RCodeFromError(err) != 3 {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
ips, _ := hosts.Lookup("example.com", dns.IPOption{
|
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
})
|
||||||
@@ -79,7 +67,7 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
domain, _ := hosts.Lookup("proxy.xray.com", dns.IPOption{
|
domain := hosts.Lookup("proxy.xray.com", dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: false,
|
IPv6Enable: false,
|
||||||
})
|
})
|
||||||
@@ -92,7 +80,7 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
domain, _ := hosts.Lookup("proxy2.xray.com", dns.IPOption{
|
domain := hosts.Lookup("proxy2.xray.com", dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: false,
|
IPv6Enable: false,
|
||||||
})
|
})
|
||||||
@@ -105,7 +93,7 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ips, _ := hosts.Lookup("www.example.cn", dns.IPOption{
|
ips := hosts.Lookup("www.example.cn", dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
})
|
||||||
@@ -118,7 +106,7 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ips, _ := hosts.Lookup("baidu.com", dns.IPOption{
|
ips := hosts.Lookup("baidu.com", dns.IPOption{
|
||||||
IPv4Enable: false,
|
IPv4Enable: false,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/app/router"
|
"github.com/xtls/xray-core/app/router"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/session"
|
|
||||||
"github.com/xtls/xray-core/common/strmatcher"
|
"github.com/xtls/xray-core/common/strmatcher"
|
||||||
"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"
|
||||||
@@ -20,32 +19,23 @@ import (
|
|||||||
type Server interface {
|
type Server interface {
|
||||||
// Name of the Client.
|
// Name of the Client.
|
||||||
Name() string
|
Name() string
|
||||||
|
|
||||||
IsDisableCache() bool
|
|
||||||
|
|
||||||
// QueryIP sends IP queries to its configured server.
|
// QueryIP sends IP queries to its configured server.
|
||||||
QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, uint32, error)
|
QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns.IPOption, disableCache bool) ([]net.IP, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client is the interface for DNS client.
|
// Client is the interface for DNS client.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
server Server
|
server Server
|
||||||
skipFallback bool
|
clientIP net.IP
|
||||||
domains []string
|
skipFallback bool
|
||||||
expectedIPs router.GeoIPMatcher
|
domains []string
|
||||||
unexpectedIPs router.GeoIPMatcher
|
expectIPs []*router.GeoIPMatcher
|
||||||
actPrior bool
|
|
||||||
actUnprior bool
|
|
||||||
tag string
|
|
||||||
timeoutMs time.Duration
|
|
||||||
finalQuery bool
|
|
||||||
ipOption *dns.IPOption
|
|
||||||
checkSystem bool
|
|
||||||
policyID uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(ctx context.Context, dest net.Destination, dispatcher routing.Dispatcher, disableCache bool, serveStale bool, serveExpiredTTL uint32, clientIP net.IP) (Server, error) {
|
func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (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 {
|
||||||
@@ -53,29 +43,24 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis
|
|||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
case strings.EqualFold(u.String(), "localhost"):
|
case strings.EqualFold(u.String(), "localhost"):
|
||||||
return NewLocalNameServer(), nil
|
return NewLocalNameServer(queryStrategy), nil
|
||||||
case strings.EqualFold(u.Scheme, "https"): // DNS-over-HTTPS Remote mode
|
case strings.EqualFold(u.Scheme, "https"): // DNS-over-HTTPS Remote mode
|
||||||
return NewDoHNameServer(u, dispatcher, false, disableCache, serveStale, serveExpiredTTL, clientIP), nil
|
return NewDoHNameServer(u, dispatcher, queryStrategy, false)
|
||||||
case strings.EqualFold(u.Scheme, "h2c"): // DNS-over-HTTPS h2c Remote mode
|
case strings.EqualFold(u.Scheme, "h2c"): // DNS-over-HTTPS h2c Remote mode
|
||||||
return NewDoHNameServer(u, dispatcher, true, disableCache, serveStale, serveExpiredTTL, clientIP), nil
|
return NewDoHNameServer(u, dispatcher, queryStrategy, true)
|
||||||
case strings.EqualFold(u.Scheme, "https+local"): // DNS-over-HTTPS Local mode
|
case strings.EqualFold(u.Scheme, "https+local"): // DNS-over-HTTPS Local mode
|
||||||
return NewDoHNameServer(u, nil, false, disableCache, serveStale, serveExpiredTTL, clientIP), nil
|
return NewDoHLocalNameServer(u, queryStrategy), nil
|
||||||
case strings.EqualFold(u.Scheme, "h2c+local"): // DNS-over-HTTPS h2c Local mode
|
|
||||||
return NewDoHNameServer(u, nil, true, disableCache, serveStale, serveExpiredTTL, clientIP), 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, disableCache, serveStale, serveExpiredTTL, clientIP)
|
return NewQUICNameServer(u, queryStrategy)
|
||||||
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, disableCache, serveStale, serveExpiredTTL, clientIP)
|
return NewTCPNameServer(u, dispatcher, queryStrategy)
|
||||||
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, disableCache, serveStale, serveExpiredTTL, clientIP)
|
return NewTCPLocalNameServer(u, queryStrategy)
|
||||||
case strings.EqualFold(u.String(), "fakedns"):
|
case strings.EqualFold(u.String(), "fakedns"):
|
||||||
var fd dns.FakeDNSEngine
|
var fd dns.FakeDNSEngine
|
||||||
err = core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||||
fd = fdns
|
fd = fdns
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return NewFakeDNSServer(fd), nil
|
return NewFakeDNSServer(fd), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,7 +68,7 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis
|
|||||||
dest.Network = net.Network_UDP
|
dest.Network = net.Network_UDP
|
||||||
}
|
}
|
||||||
if dest.Network == net.Network_UDP { // UDP classic DNS mode
|
if dest.Network == net.Network_UDP { // UDP classic DNS mode
|
||||||
return NewClassicNameServer(dest, dispatcher, disableCache, serveStale, serveExpiredTTL, clientIP), nil
|
return NewClassicNameServer(dest, dispatcher, queryStrategy), nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("No available name server could be created from ", dest).AtWarning()
|
return nil, errors.New("No available name server could be created from ", dest).AtWarning()
|
||||||
}
|
}
|
||||||
@@ -93,9 +78,7 @@ func NewClient(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
ns *NameServer,
|
ns *NameServer,
|
||||||
clientIP net.IP,
|
clientIP net.IP,
|
||||||
disableCache bool, serveStale bool, serveExpiredTTL uint32,
|
container router.GeoIPMatcherContainer,
|
||||||
tag string,
|
|
||||||
ipOption dns.IPOption,
|
|
||||||
matcherInfos *[]*DomainMatcherInfo,
|
matcherInfos *[]*DomainMatcherInfo,
|
||||||
updateDomainRule func(strmatcher.Matcher, int, []*DomainMatcherInfo) error,
|
updateDomainRule func(strmatcher.Matcher, int, []*DomainMatcherInfo) error,
|
||||||
) (*Client, error) {
|
) (*Client, error) {
|
||||||
@@ -103,7 +86,7 @@ func NewClient(
|
|||||||
|
|
||||||
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(ctx, ns.Address.AsDestination(), dispatcher, disableCache, serveStale, serveExpiredTTL, clientIP)
|
server, err := NewServer(ctx, ns.Address.AsDestination(), dispatcher, ns.GetQueryStrategy())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create nameserver").Base(err).AtWarning()
|
return errors.New("failed to create nameserver").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
@@ -158,21 +141,13 @@ func NewClient(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Establish expected IPs
|
// Establish expected IPs
|
||||||
var expectedMatcher router.GeoIPMatcher
|
var matchers []*router.GeoIPMatcher
|
||||||
if len(ns.ExpectedGeoip) > 0 {
|
for _, geoip := range ns.Geoip {
|
||||||
expectedMatcher, err = router.BuildOptimizedGeoIPMatcher(ns.ExpectedGeoip...)
|
matcher, err := container.Add(geoip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create expected ip matcher").Base(err).AtWarning()
|
return errors.New("failed to create ip matcher").Base(err).AtWarning()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Establish unexpected IPs
|
|
||||||
var unexpectedMatcher router.GeoIPMatcher
|
|
||||||
if len(ns.UnexpectedGeoip) > 0 {
|
|
||||||
unexpectedMatcher, err = router.BuildOptimizedGeoIPMatcher(ns.UnexpectedGeoip...)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("failed to create unexpected ip matcher").Base(err).AtWarning()
|
|
||||||
}
|
}
|
||||||
|
matchers = append(matchers, matcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(clientIP) > 0 {
|
if len(clientIP) > 0 {
|
||||||
@@ -180,30 +155,15 @@ func NewClient(
|
|||||||
case *net.IPOrDomain_Domain:
|
case *net.IPOrDomain_Domain:
|
||||||
errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetDomain(), " uses clientIP ", clientIP.String())
|
errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetDomain(), " uses clientIP ", clientIP.String())
|
||||||
case *net.IPOrDomain_Ip:
|
case *net.IPOrDomain_Ip:
|
||||||
errors.LogInfo(ctx, "DNS: client ", net.IP(ns.Address.Address.GetIp()), " uses clientIP ", clientIP.String())
|
errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetIp(), " uses clientIP ", clientIP.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var timeoutMs = 4000 * time.Millisecond
|
|
||||||
if ns.TimeoutMs > 0 {
|
|
||||||
timeoutMs = time.Duration(ns.TimeoutMs) * time.Millisecond
|
|
||||||
}
|
|
||||||
|
|
||||||
checkSystem := ns.QueryStrategy == QueryStrategy_USE_SYS
|
|
||||||
|
|
||||||
client.server = server
|
client.server = server
|
||||||
|
client.clientIP = clientIP
|
||||||
client.skipFallback = ns.SkipFallback
|
client.skipFallback = ns.SkipFallback
|
||||||
client.domains = rules
|
client.domains = rules
|
||||||
client.expectedIPs = expectedMatcher
|
client.expectIPs = matchers
|
||||||
client.unexpectedIPs = unexpectedMatcher
|
|
||||||
client.actPrior = ns.ActPrior
|
|
||||||
client.actUnprior = ns.ActUnprior
|
|
||||||
client.tag = tag
|
|
||||||
client.timeoutMs = timeoutMs
|
|
||||||
client.finalQuery = ns.FinalQuery
|
|
||||||
client.ipOption = &ipOption
|
|
||||||
client.checkSystem = checkSystem
|
|
||||||
client.policyID = ns.PolicyID
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
return client, err
|
return client, err
|
||||||
@@ -215,74 +175,42 @@ func (c *Client) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// QueryIP sends DNS query to the name server with the client's IP.
|
// QueryIP sends DNS query to the name server with the client's IP.
|
||||||
func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption, disableCache bool) ([]net.IP, error) {
|
||||||
if c.checkSystem {
|
ctx, cancel := context.WithTimeout(ctx, 4*time.Second)
|
||||||
supportIPv4, supportIPv6 := checkRoutes()
|
ips, err := c.server.QueryIP(ctx, domain, c.clientIP, option, disableCache)
|
||||||
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
|
||||||
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
|
||||||
} else {
|
|
||||||
option.IPv4Enable = option.IPv4Enable && c.ipOption.IPv4Enable
|
|
||||||
option.IPv6Enable = option.IPv6Enable && c.ipOption.IPv6Enable
|
|
||||||
}
|
|
||||||
|
|
||||||
if !option.IPv4Enable && !option.IPv6Enable {
|
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, c.timeoutMs)
|
|
||||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{Tag: c.tag})
|
|
||||||
ips, ttl, err := c.server.QueryIP(ctx, domain, option)
|
|
||||||
cancel()
|
cancel()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return ips, err
|
||||||
}
|
}
|
||||||
|
return c.MatchExpectedIPs(domain, ips)
|
||||||
|
}
|
||||||
|
|
||||||
if len(ips) == 0 {
|
// MatchExpectedIPs matches queried domain IPs with expected IPs and returns matched ones.
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
func (c *Client) MatchExpectedIPs(domain string, ips []net.IP) ([]net.IP, error) {
|
||||||
|
if len(c.expectIPs) == 0 {
|
||||||
|
return ips, nil
|
||||||
}
|
}
|
||||||
|
newIps := []net.IP{}
|
||||||
if c.expectedIPs != nil && !c.actPrior {
|
for _, ip := range ips {
|
||||||
ips, _ = c.expectedIPs.FilterIPs(ips)
|
for _, matcher := range c.expectIPs {
|
||||||
errors.LogDebug(context.Background(), "domain ", domain, " expectedIPs ", ips, " matched at server ", c.Name())
|
if matcher.Match(ip) {
|
||||||
if len(ips) == 0 {
|
newIps = append(newIps, ip)
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(newIps) == 0 {
|
||||||
if c.unexpectedIPs != nil && !c.actUnprior {
|
return nil, errExpectedIPNonMatch
|
||||||
_, ips = c.unexpectedIPs.FilterIPs(ips)
|
|
||||||
errors.LogDebug(context.Background(), "domain ", domain, " unexpectedIPs ", ips, " matched at server ", c.Name())
|
|
||||||
if len(ips) == 0 {
|
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
errors.LogDebug(context.Background(), "domain ", domain, " expectIPs ", newIps, " matched at server ", c.Name())
|
||||||
if c.expectedIPs != nil && c.actPrior {
|
return newIps, nil
|
||||||
ipsNew, _ := c.expectedIPs.FilterIPs(ips)
|
|
||||||
if len(ipsNew) > 0 {
|
|
||||||
ips = ipsNew
|
|
||||||
errors.LogDebug(context.Background(), "domain ", domain, " priorIPs ", ips, " matched at server ", c.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.unexpectedIPs != nil && c.actUnprior {
|
|
||||||
_, ipsNew := c.unexpectedIPs.FilterIPs(ips)
|
|
||||||
if len(ipsNew) > 0 {
|
|
||||||
ips = ipsNew
|
|
||||||
errors.LogDebug(context.Background(), "domain ", domain, " unpriorIPs ", ips, " matched at server ", c.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ips, ttl, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResolveIpOptionOverride(queryStrategy QueryStrategy, ipOption dns.IPOption) dns.IPOption {
|
func ResolveIpOptionOverride(queryStrategy QueryStrategy, ipOption dns.IPOption) dns.IPOption {
|
||||||
switch queryStrategy {
|
switch queryStrategy {
|
||||||
case QueryStrategy_USE_IP:
|
case QueryStrategy_USE_IP:
|
||||||
return ipOption
|
return ipOption
|
||||||
case QueryStrategy_USE_SYS:
|
|
||||||
return ipOption
|
|
||||||
case QueryStrategy_USE_IP4:
|
case QueryStrategy_USE_IP4:
|
||||||
return dns.IPOption{
|
return dns.IPOption{
|
||||||
IPv4Enable: ipOption.IPv4Enable,
|
IPv4Enable: ipOption.IPv4Enable,
|
||||||
|
|||||||
@@ -1,173 +0,0 @@
|
|||||||
package dns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
go_errors "errors"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"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/signal/pubsub"
|
|
||||||
"github.com/xtls/xray-core/features/dns"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CachedNameserver interface {
|
|
||||||
getCacheController() *CacheController
|
|
||||||
|
|
||||||
sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns.IPOption)
|
|
||||||
}
|
|
||||||
|
|
||||||
// queryIP is called from dns.Server->queryIPTimeout
|
|
||||||
func queryIP(ctx context.Context, s CachedNameserver, domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
|
||||||
fqdn := Fqdn(domain)
|
|
||||||
|
|
||||||
cache := s.getCacheController()
|
|
||||||
if !cache.disableCache {
|
|
||||||
if rec := cache.findRecords(fqdn); rec != nil {
|
|
||||||
ips, ttl, err := merge(option, rec.A, rec.AAAA)
|
|
||||||
if !go_errors.Is(err, errRecordNotFound) {
|
|
||||||
if ttl > 0 {
|
|
||||||
errors.LogDebugInner(ctx, err, cache.name, " cache HIT ", fqdn, " -> ", ips)
|
|
||||||
log.Record(&log.DNSLog{Server: cache.name, Domain: fqdn, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
|
||||||
return ips, uint32(ttl), err
|
|
||||||
}
|
|
||||||
if cache.serveStale && (cache.serveExpiredTTL == 0 || cache.serveExpiredTTL < ttl) {
|
|
||||||
errors.LogDebugInner(ctx, err, cache.name, " cache OPTIMISTE ", fqdn, " -> ", ips)
|
|
||||||
log.Record(&log.DNSLog{Server: cache.name, Domain: fqdn, Result: ips, Status: log.DNSCacheOptimiste, Elapsed: 0, Error: err})
|
|
||||||
go pull(ctx, s, fqdn, option)
|
|
||||||
return ips, 1, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", fqdn, " at ", cache.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fetch(ctx, s, fqdn, option)
|
|
||||||
}
|
|
||||||
|
|
||||||
func pull(ctx context.Context, s CachedNameserver, fqdn string, option dns.IPOption) {
|
|
||||||
nctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 8*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
fetch(nctx, s, fqdn, option)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetch(ctx context.Context, s CachedNameserver, fqdn string, option dns.IPOption) ([]net.IP, uint32, error) {
|
|
||||||
key := fqdn
|
|
||||||
switch {
|
|
||||||
case option.IPv4Enable && option.IPv6Enable:
|
|
||||||
key = key + "46"
|
|
||||||
case option.IPv4Enable:
|
|
||||||
key = key + "4"
|
|
||||||
case option.IPv6Enable:
|
|
||||||
key = key + "6"
|
|
||||||
}
|
|
||||||
|
|
||||||
v, _, _ := s.getCacheController().requestGroup.Do(key, func() (any, error) {
|
|
||||||
return doFetch(ctx, s, fqdn, option), nil
|
|
||||||
})
|
|
||||||
ret := v.(result)
|
|
||||||
|
|
||||||
return ret.ips, ret.ttl, ret.error
|
|
||||||
}
|
|
||||||
|
|
||||||
type result struct {
|
|
||||||
ips []net.IP
|
|
||||||
ttl uint32
|
|
||||||
error
|
|
||||||
}
|
|
||||||
|
|
||||||
func doFetch(ctx context.Context, s CachedNameserver, fqdn string, option dns.IPOption) result {
|
|
||||||
sub4, sub6 := s.getCacheController().registerSubscribers(fqdn, option)
|
|
||||||
defer closeSubscribers(sub4, sub6)
|
|
||||||
|
|
||||||
noResponseErrCh := make(chan error, 2)
|
|
||||||
onEvent := func(sub *pubsub.Subscriber) (*IPRecord, error) {
|
|
||||||
if sub == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, ctx.Err()
|
|
||||||
case err := <-noResponseErrCh:
|
|
||||||
return nil, err
|
|
||||||
case msg := <-sub.Wait():
|
|
||||||
sub.Close()
|
|
||||||
return msg.(*IPRecord), nil // should panic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
start := time.Now()
|
|
||||||
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
|
||||||
|
|
||||||
rec4, err4 := onEvent(sub4)
|
|
||||||
rec6, err6 := onEvent(sub6)
|
|
||||||
|
|
||||||
var errs []error
|
|
||||||
if err4 != nil {
|
|
||||||
errs = append(errs, err4)
|
|
||||||
}
|
|
||||||
if err6 != nil {
|
|
||||||
errs = append(errs, err6)
|
|
||||||
}
|
|
||||||
|
|
||||||
ips, ttl, err := merge(option, rec4, rec6, errs...)
|
|
||||||
var rTTL uint32
|
|
||||||
if ttl > 0 {
|
|
||||||
rTTL = uint32(ttl)
|
|
||||||
} else if ttl == 0 && go_errors.Is(err, errRecordNotFound) {
|
|
||||||
rTTL = 0
|
|
||||||
} else { // edge case: where a fast rep's ttl expires during the rtt of a slower, parallel query
|
|
||||||
rTTL = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Record(&log.DNSLog{Server: s.getCacheController().name, Domain: fqdn, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
|
||||||
return result{ips, rTTL, err}
|
|
||||||
}
|
|
||||||
|
|
||||||
func merge(option dns.IPOption, rec4 *IPRecord, rec6 *IPRecord, errs ...error) ([]net.IP, int32, error) {
|
|
||||||
var allIPs []net.IP
|
|
||||||
var rTTL int32 = dns.DefaultTTL
|
|
||||||
|
|
||||||
mergeReq := option.IPv4Enable && option.IPv6Enable
|
|
||||||
|
|
||||||
if option.IPv4Enable {
|
|
||||||
ips, ttl, err := rec4.getIPs() // it's safe
|
|
||||||
if !mergeReq || go_errors.Is(err, errRecordNotFound) {
|
|
||||||
return ips, ttl, err
|
|
||||||
}
|
|
||||||
if ttl < rTTL {
|
|
||||||
rTTL = ttl
|
|
||||||
}
|
|
||||||
if len(ips) > 0 {
|
|
||||||
allIPs = append(allIPs, ips...)
|
|
||||||
} else {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if option.IPv6Enable {
|
|
||||||
ips, ttl, err := rec6.getIPs() // it's safe
|
|
||||||
if !mergeReq || go_errors.Is(err, errRecordNotFound) {
|
|
||||||
return ips, ttl, err
|
|
||||||
}
|
|
||||||
if ttl < rTTL {
|
|
||||||
rTTL = ttl
|
|
||||||
}
|
|
||||||
if len(ips) > 0 {
|
|
||||||
allIPs = append(allIPs, ips...)
|
|
||||||
} else {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(allIPs) > 0 {
|
|
||||||
return allIPs, rTTL, nil
|
|
||||||
}
|
|
||||||
if len(errs) == 2 && go_errors.Is(errs[0], errs[1]) {
|
|
||||||
return nil, rTTL, errs[0]
|
|
||||||
}
|
|
||||||
return nil, rTTL, errors.Combine(errs...)
|
|
||||||
}
|
|
||||||
@@ -8,21 +8,22 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
utls "github.com/refraction-networking/utls"
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/crypto"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/log"
|
"github.com/xtls/xray-core/common/log"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/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"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
|
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||||
|
"github.com/xtls/xray-core/common/task"
|
||||||
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"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,121 +31,224 @@ import (
|
|||||||
// which is compatible with traditional dns over udp(RFC1035),
|
// which is compatible with traditional dns over udp(RFC1035),
|
||||||
// thus most of the DOH implementation is copied from udpns.go
|
// thus most of the DOH implementation is copied from udpns.go
|
||||||
type DoHNameServer struct {
|
type DoHNameServer struct {
|
||||||
cacheController *CacheController
|
dispatcher routing.Dispatcher
|
||||||
httpClient *http.Client
|
sync.RWMutex
|
||||||
dohURL string
|
ips map[string]*record
|
||||||
clientIP net.IP
|
pub *pubsub.Service
|
||||||
|
cleanup *task.Periodic
|
||||||
|
httpClient *http.Client
|
||||||
|
dohURL string
|
||||||
|
name string
|
||||||
|
queryStrategy QueryStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDoHNameServer creates DOH/DOHL client object for remote/local resolving.
|
// NewDoHNameServer creates DOH server object for remote resolving.
|
||||||
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, h2c bool, disableCache bool, serveStale bool, serveExpiredTTL uint32, clientIP net.IP) *DoHNameServer {
|
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy, h2c bool) (*DoHNameServer, error) {
|
||||||
url.Scheme = "https"
|
url.Scheme = "https"
|
||||||
mode := "DOH"
|
errors.LogInfo(context.Background(), "DNS: created Remote DNS-over-HTTPS client for ", url.String(), ", with h2c ", h2c)
|
||||||
if dispatcher == nil {
|
s := baseDOHNameServer(url, "DOH", queryStrategy)
|
||||||
mode = "DOHL"
|
|
||||||
|
s.dispatcher = dispatcher
|
||||||
|
dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
dest, err := net.ParseDestination(network + ":" + addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dnsCtx := toDnsContext(ctx, s.dohURL)
|
||||||
|
if h2c {
|
||||||
|
dnsCtx = session.ContextWithMitmAlpn11(dnsCtx, false) // for insurance
|
||||||
|
dnsCtx = session.ContextWithMitmServerName(dnsCtx, url.Hostname())
|
||||||
|
}
|
||||||
|
link, err := s.dispatcher.Dispatch(dnsCtx, dest)
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cc := common.ChainedClosable{}
|
||||||
|
if cw, ok := link.Writer.(common.Closable); ok {
|
||||||
|
cc = append(cc, cw)
|
||||||
|
}
|
||||||
|
if cr, ok := link.Reader.(common.Closable); ok {
|
||||||
|
cc = append(cc, cr)
|
||||||
|
}
|
||||||
|
return cnc.NewConnection(
|
||||||
|
cnc.ConnectionInputMulti(link.Writer),
|
||||||
|
cnc.ConnectionOutputMulti(link.Reader),
|
||||||
|
cnc.ConnectionOnClose(cc),
|
||||||
|
), nil
|
||||||
}
|
}
|
||||||
errors.LogInfo(context.Background(), "DNS: created ", mode, " client for ", url.String(), ", with h2c ", h2c)
|
|
||||||
s := &DoHNameServer{
|
s.httpClient = &http.Client{
|
||||||
cacheController: NewCacheController(mode+"//"+url.Host, disableCache, serveStale, serveExpiredTTL),
|
Timeout: time.Second * 180,
|
||||||
dohURL: url.String(),
|
Transport: &http.Transport{
|
||||||
clientIP: clientIP,
|
MaxIdleConns: 30,
|
||||||
|
IdleConnTimeout: 90 * time.Second,
|
||||||
|
TLSHandshakeTimeout: 30 * time.Second,
|
||||||
|
ForceAttemptHTTP2: true,
|
||||||
|
DialContext: dialContext,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if h2c {
|
||||||
|
s.httpClient.Transport = &http2.Transport{
|
||||||
|
IdleConnTimeout: 90 * time.Second,
|
||||||
|
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||||
|
return dialContext(ctx, network, addr)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDoHLocalNameServer creates DOH client object for local resolving
|
||||||
|
func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameServer {
|
||||||
|
url.Scheme = "https"
|
||||||
|
s := baseDOHNameServer(url, "DOHL", queryStrategy)
|
||||||
|
tr := &http.Transport{
|
||||||
|
IdleConnTimeout: 90 * time.Second,
|
||||||
|
ForceAttemptHTTP2: true,
|
||||||
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
dest, err := net.ParseDestination(network + ":" + addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn, err := internet.DialSystem(ctx, dest, nil)
|
||||||
|
log.Record(&log.AccessMessage{
|
||||||
|
From: "DNS",
|
||||||
|
To: s.dohURL,
|
||||||
|
Status: log.AccessAccepted,
|
||||||
|
Detour: "local",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
s.httpClient = &http.Client{
|
s.httpClient = &http.Client{
|
||||||
Transport: &http2.Transport{
|
Timeout: time.Second * 180,
|
||||||
IdleConnTimeout: net.ConnIdleTimeout,
|
Transport: tr,
|
||||||
ReadIdleTimeout: net.ChromeH2KeepAlivePeriod,
|
}
|
||||||
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
|
errors.LogInfo(context.Background(), "DNS: created Local DNS-over-HTTPS client for ", url.String())
|
||||||
dest, err := net.ParseDestination(network + ":" + addr)
|
return s
|
||||||
if err != nil {
|
}
|
||||||
return nil, err
|
|
||||||
}
|
func baseDOHNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) *DoHNameServer {
|
||||||
var conn net.Conn
|
s := &DoHNameServer{
|
||||||
if dispatcher != nil {
|
ips: make(map[string]*record),
|
||||||
dnsCtx := toDnsContext(ctx, s.dohURL)
|
pub: pubsub.NewService(),
|
||||||
if h2c {
|
name: prefix + "//" + url.Host,
|
||||||
dnsCtx = session.ContextWithMitmAlpn11(dnsCtx, false) // for insurance
|
dohURL: url.String(),
|
||||||
dnsCtx = session.ContextWithMitmServerName(dnsCtx, url.Hostname())
|
queryStrategy: queryStrategy,
|
||||||
}
|
}
|
||||||
link, err := dispatcher.Dispatch(dnsCtx, dest)
|
s.cleanup = &task.Periodic{
|
||||||
select {
|
Interval: time.Minute,
|
||||||
case <-ctx.Done():
|
Execute: s.Cleanup,
|
||||||
return nil, ctx.Err()
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cc := common.ChainedClosable{}
|
|
||||||
if cw, ok := link.Writer.(common.Closable); ok {
|
|
||||||
cc = append(cc, cw)
|
|
||||||
}
|
|
||||||
if cr, ok := link.Reader.(common.Closable); ok {
|
|
||||||
cc = append(cc, cr)
|
|
||||||
}
|
|
||||||
conn = cnc.NewConnection(
|
|
||||||
cnc.ConnectionInputMulti(link.Writer),
|
|
||||||
cnc.ConnectionOutputMulti(link.Reader),
|
|
||||||
cnc.ConnectionOnClose(cc),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
log.Record(&log.AccessMessage{
|
|
||||||
From: "DNS",
|
|
||||||
To: s.dohURL,
|
|
||||||
Status: log.AccessAccepted,
|
|
||||||
Detour: "local",
|
|
||||||
})
|
|
||||||
conn, err = internet.DialSystem(ctx, dest, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !h2c {
|
|
||||||
conn = utls.UClient(conn, &utls.Config{ServerName: url.Hostname()}, utls.HelloChrome_Auto)
|
|
||||||
if err := conn.(*utls.UConn).HandshakeContext(ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return conn, nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name implements Server.
|
// Name implements Server.
|
||||||
func (s *DoHNameServer) Name() string {
|
func (s *DoHNameServer) Name() string {
|
||||||
return s.cacheController.name
|
return s.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDisableCache implements Server.
|
// Cleanup clears expired items from cache
|
||||||
func (s *DoHNameServer) IsDisableCache() bool {
|
func (s *DoHNameServer) Cleanup() error {
|
||||||
return s.cacheController.disableCache
|
now := time.Now()
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
|
if len(s.ips) == 0 {
|
||||||
|
return errors.New("nothing to do. stopping...")
|
||||||
|
}
|
||||||
|
|
||||||
|
for domain, record := range s.ips {
|
||||||
|
if record.A != nil && record.A.Expire.Before(now) {
|
||||||
|
record.A = nil
|
||||||
|
}
|
||||||
|
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
||||||
|
record.AAAA = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if record.A == nil && record.AAAA == nil {
|
||||||
|
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||||
|
delete(s.ips, domain)
|
||||||
|
} else {
|
||||||
|
s.ips[domain] = record
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.ips) == 0 {
|
||||||
|
s.ips = make(map[string]*record)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DoHNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||||
|
elapsed := time.Since(req.start)
|
||||||
|
|
||||||
|
s.Lock()
|
||||||
|
rec, found := s.ips[req.domain]
|
||||||
|
if !found {
|
||||||
|
rec = &record{}
|
||||||
|
}
|
||||||
|
updated := false
|
||||||
|
|
||||||
|
switch req.reqType {
|
||||||
|
case dnsmessage.TypeA:
|
||||||
|
if isNewer(rec.A, ipRec) {
|
||||||
|
rec.A = ipRec
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
case dnsmessage.TypeAAAA:
|
||||||
|
addr := make([]net.Address, 0, len(ipRec.IP))
|
||||||
|
for _, ip := range ipRec.IP {
|
||||||
|
if len(ip.IP()) == net.IPv6len {
|
||||||
|
addr = append(addr, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ipRec.IP = addr
|
||||||
|
if isNewer(rec.AAAA, ipRec) {
|
||||||
|
rec.AAAA = ipRec
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||||
|
|
||||||
|
if updated {
|
||||||
|
s.ips[req.domain] = rec
|
||||||
|
}
|
||||||
|
switch req.reqType {
|
||||||
|
case dnsmessage.TypeA:
|
||||||
|
s.pub.Publish(req.domain+"4", nil)
|
||||||
|
case dnsmessage.TypeAAAA:
|
||||||
|
s.pub.Publish(req.domain+"6", nil)
|
||||||
|
}
|
||||||
|
s.Unlock()
|
||||||
|
common.Must(s.cleanup.Start())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DoHNameServer) newReqID() uint16 {
|
func (s *DoHNameServer) newReqID() uint16 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCacheController implements CachedNameserver.
|
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||||
func (s *DoHNameServer) getCacheController() *CacheController {
|
errors.LogInfo(ctx, s.name, " querying: ", domain)
|
||||||
return s.cacheController
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendQuery implements CachedNameserver.
|
if s.name+"." == "DOH//"+domain {
|
||||||
func (s *DoHNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
errors.LogError(ctx, s.name, " tries to resolve itself! Use IP or set \"hosts\" instead.")
|
||||||
errors.LogInfo(ctx, s.Name(), " querying: ", fqdn)
|
|
||||||
|
|
||||||
if s.Name()+"." == "DOH//"+fqdn {
|
|
||||||
errors.LogError(ctx, s.Name(), " tries to resolve itself! Use IP or set \"hosts\" instead")
|
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- errors.New("tries to resolve itself!", s.Name())
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// As we don't want our traffic pattern looks like DoH, we use Random-Length Padding instead of Block-Length Padding recommended in RFC 8467
|
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||||
// Although DoH server like 1.1.1.1 will pad the response to Block-Length 468, at least it is better than no padding for response at all
|
|
||||||
reqs := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, int(crypto.RandBetween(100, 300))))
|
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
@@ -178,29 +282,20 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- er
|
|||||||
|
|
||||||
b, err := dns.PackMessage(r.msg)
|
b, err := dns.PackMessage(r.msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to pack dns query for ", fqdn)
|
errors.LogErrorInner(ctx, err, "failed to pack dns query for ", domain)
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resp, err := s.dohHTTPSContext(dnsCtx, b.Bytes())
|
resp, err := s.dohHTTPSContext(dnsCtx, b.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to retrieve response for ", fqdn)
|
errors.LogErrorInner(ctx, err, "failed to retrieve response for ", domain)
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rec, err := parseResponse(resp)
|
rec, err := parseResponse(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to handle DOH response for ", fqdn)
|
errors.LogErrorInner(ctx, err, "failed to handle DOH response for ", domain)
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.cacheController.updateRecord(r, rec)
|
s.updateIP(r, rec)
|
||||||
}(req)
|
}(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,8 +310,6 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
|
|||||||
req.Header.Add("Accept", "application/dns-message")
|
req.Header.Add("Accept", "application/dns-message")
|
||||||
req.Header.Add("Content-Type", "application/dns-message")
|
req.Header.Add("Content-Type", "application/dns-message")
|
||||||
|
|
||||||
req.Header.Set("X-Padding", strings.Repeat("X", int(crypto.RandBetween(100, 1000))))
|
|
||||||
|
|
||||||
hc := s.httpClient
|
hc := s.httpClient
|
||||||
|
|
||||||
resp, err := hc.Do(req.WithContext(ctx))
|
resp, err := hc.Do(req.WithContext(ctx))
|
||||||
@@ -233,7 +326,107 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
|
|||||||
return io.ReadAll(resp.Body)
|
return io.ReadAll(resp.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryIP implements Server.
|
func (s *DoHNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||||
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
s.RLock()
|
||||||
return queryIP(ctx, s, domain, option)
|
record, found := s.ips[domain]
|
||||||
|
s.RUnlock()
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return nil, errRecordNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
var err4 error
|
||||||
|
var err6 error
|
||||||
|
var ips []net.Address
|
||||||
|
var ip6 []net.Address
|
||||||
|
|
||||||
|
if option.IPv4Enable {
|
||||||
|
ips, err4 = record.A.getIPs()
|
||||||
|
}
|
||||||
|
|
||||||
|
if option.IPv6Enable {
|
||||||
|
ip6, err6 = record.AAAA.getIPs()
|
||||||
|
ips = append(ips, ip6...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ips) > 0 {
|
||||||
|
return toNetIP(ips)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err4 != nil {
|
||||||
|
return nil, err4
|
||||||
|
}
|
||||||
|
|
||||||
|
if err6 != nil {
|
||||||
|
return nil, err6
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {
|
||||||
|
return nil, dns_feature.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errRecordNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
fqdn := Fqdn(domain)
|
||||||
|
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||||
|
if !option.IPv4Enable && !option.IPv6Enable {
|
||||||
|
return nil, dns_feature.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
if disableCache {
|
||||||
|
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
||||||
|
} else {
|
||||||
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
|
if err == nil || err == dns_feature.ErrEmptyResponse {
|
||||||
|
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
|
||||||
|
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||||
|
return ips, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ipv4 and ipv6 belong to different subscription groups
|
||||||
|
var sub4, sub6 *pubsub.Subscriber
|
||||||
|
if option.IPv4Enable {
|
||||||
|
sub4 = s.pub.Subscribe(fqdn + "4")
|
||||||
|
defer sub4.Close()
|
||||||
|
}
|
||||||
|
if option.IPv6Enable {
|
||||||
|
sub6 = s.pub.Subscribe(fqdn + "6")
|
||||||
|
defer sub6.Close()
|
||||||
|
}
|
||||||
|
done := make(chan interface{})
|
||||||
|
go func() {
|
||||||
|
if sub4 != nil {
|
||||||
|
select {
|
||||||
|
case <-sub4.Wait():
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sub6 != nil {
|
||||||
|
select {
|
||||||
|
case <-sub6.Wait():
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
s.sendQuery(ctx, fqdn, clientIP, option)
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
for {
|
||||||
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,12 +17,12 @@ 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 := NewDoHNameServer(url, nil, false, false, false, 0, net.IP(nil))
|
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP)
|
||||||
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", dns_feature.IPOption{
|
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
}, false)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
@@ -34,12 +34,12 @@ 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 := NewDoHNameServer(url, nil, false, false, false, 0, net.IP(nil))
|
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP)
|
||||||
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", dns_feature.IPOption{
|
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
}, false)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
@@ -47,10 +47,10 @@ func TestDOHNameServerWithCache(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips2, _, err := s.QueryIP(ctx2, "google.com", dns_feature.IPOption{
|
ips2, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
}, true)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if r := cmp.Diff(ips2, ips); r != "" {
|
if r := cmp.Diff(ips2, ips); r != "" {
|
||||||
@@ -62,12 +62,12 @@ func TestDOHNameServerWithIPv4Override(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 := NewDoHNameServer(url, nil, false, false, false, 0, net.IP(nil))
|
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP4)
|
||||||
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", dns_feature.IPOption{
|
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: false,
|
IPv6Enable: true,
|
||||||
})
|
}, false)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
@@ -85,12 +85,12 @@ func TestDOHNameServerWithIPv6Override(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 := NewDoHNameServer(url, nil, false, false, false, 0, net.IP(nil))
|
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP6)
|
||||||
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", dns_feature.IPOption{
|
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||||
IPv4Enable: false,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
}, false)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
|
|||||||
@@ -20,14 +20,9 @@ func (FakeDNSServer) Name() string {
|
|||||||
return "FakeDNS"
|
return "FakeDNS"
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDisableCache implements Server.
|
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, opt dns.IPOption, _ bool) ([]net.IP, error) {
|
||||||
func (s *FakeDNSServer) IsDisableCache() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, opt dns.IPOption) ([]net.IP, uint32, error) {
|
|
||||||
if f.fakeDNSEngine == nil {
|
if f.fakeDNSEngine == nil {
|
||||||
return nil, 0, errors.New("Unable to locate a fake DNS Engine").AtError()
|
return nil, errors.New("Unable to locate a fake DNS Engine").AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
var ips []net.Address
|
var ips []net.Address
|
||||||
@@ -39,13 +34,13 @@ func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, opt dns.IPOp
|
|||||||
|
|
||||||
netIP, err := toNetIP(ips)
|
netIP, err := toNetIP(ips)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, errors.New("Unable to convert IP to net ip").Base(err).AtError()
|
return nil, errors.New("Unable to convert IP to net ip").Base(err).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogInfo(ctx, f.Name(), " got answer: ", domain, " -> ", ips)
|
errors.LogInfo(ctx, f.Name(), " got answer: ", domain, " -> ", ips)
|
||||||
|
|
||||||
if len(netIP) > 0 {
|
if len(netIP) > 0 {
|
||||||
return netIP, 1, nil // fakeIP ttl is 1
|
return netIP, nil
|
||||||
}
|
}
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
return nil, dns.ErrEmptyResponse
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
@@ -13,14 +14,25 @@ import (
|
|||||||
|
|
||||||
// LocalNameServer is an wrapper over local DNS feature.
|
// LocalNameServer is an wrapper over local DNS feature.
|
||||||
type LocalNameServer struct {
|
type LocalNameServer struct {
|
||||||
client *localdns.Client
|
client *localdns.Client
|
||||||
|
queryStrategy QueryStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const errEmptyResponse = "No address associated with hostname"
|
||||||
|
|
||||||
// QueryIP implements Server.
|
// QueryIP implements Server.
|
||||||
func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, option dns.IPOption) (ips []net.IP, ttl uint32, err error) {
|
func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, _ net.IP, option dns.IPOption, _ bool) (ips []net.IP, err error) {
|
||||||
|
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||||
|
if !option.IPv4Enable && !option.IPv6Enable {
|
||||||
|
return nil, dns.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
ips, ttl, err = s.client.LookupIP(domain, option)
|
ips, err = s.client.LookupIP(domain, option)
|
||||||
|
|
||||||
|
if err != nil && strings.HasSuffix(err.Error(), errEmptyResponse) {
|
||||||
|
err = dns.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
|
||||||
if len(ips) > 0 {
|
if len(ips) > 0 {
|
||||||
errors.LogInfo(ctx, "Localhost got answer: ", domain, " -> ", ips)
|
errors.LogInfo(ctx, "Localhost got answer: ", domain, " -> ", ips)
|
||||||
@@ -35,20 +47,16 @@ func (s *LocalNameServer) Name() string {
|
|||||||
return "localhost"
|
return "localhost"
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDisableCache implements Server.
|
|
||||||
func (s *LocalNameServer) IsDisableCache() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLocalNameServer creates localdns server object for directly lookup in system DNS.
|
// NewLocalNameServer creates localdns server object for directly lookup in system DNS.
|
||||||
func NewLocalNameServer() *LocalNameServer {
|
func NewLocalNameServer(queryStrategy QueryStrategy) *LocalNameServer {
|
||||||
errors.LogInfo(context.Background(), "DNS: created localhost client")
|
errors.LogInfo(context.Background(), "DNS: created localhost client")
|
||||||
return &LocalNameServer{
|
return &LocalNameServer{
|
||||||
client: localdns.New(),
|
queryStrategy: queryStrategy,
|
||||||
|
client: localdns.New(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLocalDNSClient creates localdns client object for directly lookup in system DNS.
|
// NewLocalDNSClient creates localdns client object for directly lookup in system DNS.
|
||||||
func NewLocalDNSClient(ipOption dns.IPOption) *Client {
|
func NewLocalDNSClient() *Client {
|
||||||
return &Client{server: NewLocalNameServer(), ipOption: &ipOption}
|
return &Client{server: NewLocalNameServer(QueryStrategy_USE_IP)}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,17 +7,18 @@ import (
|
|||||||
|
|
||||||
. "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"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLocalNameServer(t *testing.T) {
|
func TestLocalNameServer(t *testing.T) {
|
||||||
s := NewLocalNameServer()
|
s := NewLocalNameServer(QueryStrategy_USE_IP)
|
||||||
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", dns.IPOption{
|
ips, err := s.QueryIP(ctx, "google.com", net.IP{}, dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
})
|
}, false)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
|
|||||||
@@ -9,14 +9,18 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/quic-go/quic-go"
|
"github.com/quic-go/quic-go"
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/log"
|
"github.com/xtls/xray-core/common/log"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol/dns"
|
"github.com/xtls/xray-core/common/protocol/dns"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
|
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||||
|
"github.com/xtls/xray-core/common/task"
|
||||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||||
"github.com/xtls/xray-core/transport/internet/tls"
|
"github.com/xtls/xray-core/transport/internet/tls"
|
||||||
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,14 +33,19 @@ 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
|
||||||
cacheController *CacheController
|
ips map[string]*record
|
||||||
destination *net.Destination
|
pub *pubsub.Service
|
||||||
connection *quic.Conn
|
cleanup *task.Periodic
|
||||||
clientIP net.IP
|
name string
|
||||||
|
destination *net.Destination
|
||||||
|
connection quic.Connection
|
||||||
|
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, disableCache bool, serveStale bool, serveExpiredTTL uint32, clientIP net.IP) (*QUICNameServer, error) {
|
func NewQUICNameServer(url *url.URL, queryStrategy QueryStrategy) (*QUICNameServer, error) {
|
||||||
|
errors.LogInfo(context.Background(), "DNS: created Local DNS-over-QUIC client for ", url.String())
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
port := net.Port(853)
|
port := net.Port(853)
|
||||||
if url.Port() != "" {
|
if url.Port() != "" {
|
||||||
@@ -48,37 +57,110 @@ func NewQUICNameServer(url *url.URL, disableCache bool, serveStale bool, serveEx
|
|||||||
dest := net.UDPDestination(net.ParseAddress(url.Hostname()), port)
|
dest := net.UDPDestination(net.ParseAddress(url.Hostname()), port)
|
||||||
|
|
||||||
s := &QUICNameServer{
|
s := &QUICNameServer{
|
||||||
cacheController: NewCacheController(url.String(), disableCache, serveStale, serveExpiredTTL),
|
ips: make(map[string]*record),
|
||||||
destination: &dest,
|
pub: pubsub.NewService(),
|
||||||
clientIP: clientIP,
|
name: url.String(),
|
||||||
|
destination: &dest,
|
||||||
|
queryStrategy: queryStrategy,
|
||||||
|
}
|
||||||
|
s.cleanup = &task.Periodic{
|
||||||
|
Interval: time.Minute,
|
||||||
|
Execute: s.Cleanup,
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogInfo(context.Background(), "DNS: created Local DNS-over-QUIC client for ", url.String())
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name implements Server.
|
// Name returns client name
|
||||||
func (s *QUICNameServer) Name() string {
|
func (s *QUICNameServer) Name() string {
|
||||||
return s.cacheController.name
|
return s.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDisableCache implements Server.
|
// Cleanup clears expired items from cache
|
||||||
func (s *QUICNameServer) IsDisableCache() bool {
|
func (s *QUICNameServer) Cleanup() error {
|
||||||
return s.cacheController.disableCache
|
now := time.Now()
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
|
if len(s.ips) == 0 {
|
||||||
|
return errors.New("nothing to do. stopping...")
|
||||||
|
}
|
||||||
|
|
||||||
|
for domain, record := range s.ips {
|
||||||
|
if record.A != nil && record.A.Expire.Before(now) {
|
||||||
|
record.A = nil
|
||||||
|
}
|
||||||
|
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
||||||
|
record.AAAA = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if record.A == nil && record.AAAA == nil {
|
||||||
|
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||||
|
delete(s.ips, domain)
|
||||||
|
} else {
|
||||||
|
s.ips[domain] = record
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.ips) == 0 {
|
||||||
|
s.ips = make(map[string]*record)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *QUICNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||||
|
elapsed := time.Since(req.start)
|
||||||
|
|
||||||
|
s.Lock()
|
||||||
|
rec, found := s.ips[req.domain]
|
||||||
|
if !found {
|
||||||
|
rec = &record{}
|
||||||
|
}
|
||||||
|
updated := false
|
||||||
|
|
||||||
|
switch req.reqType {
|
||||||
|
case dnsmessage.TypeA:
|
||||||
|
if isNewer(rec.A, ipRec) {
|
||||||
|
rec.A = ipRec
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
case dnsmessage.TypeAAAA:
|
||||||
|
addr := make([]net.Address, 0)
|
||||||
|
for _, ip := range ipRec.IP {
|
||||||
|
if len(ip.IP()) == net.IPv6len {
|
||||||
|
addr = append(addr, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ipRec.IP = addr
|
||||||
|
if isNewer(rec.AAAA, ipRec) {
|
||||||
|
rec.AAAA = ipRec
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||||
|
|
||||||
|
if updated {
|
||||||
|
s.ips[req.domain] = rec
|
||||||
|
}
|
||||||
|
switch req.reqType {
|
||||||
|
case dnsmessage.TypeA:
|
||||||
|
s.pub.Publish(req.domain+"4", nil)
|
||||||
|
case dnsmessage.TypeAAAA:
|
||||||
|
s.pub.Publish(req.domain+"6", nil)
|
||||||
|
}
|
||||||
|
s.Unlock()
|
||||||
|
common.Must(s.cleanup.Start())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QUICNameServer) newReqID() uint16 {
|
func (s *QUICNameServer) newReqID() uint16 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCacheController implements CachedNameServer.
|
func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||||
func (s *QUICNameServer) getCacheController() *CacheController { return s.cacheController }
|
errors.LogInfo(ctx, s.name, " querying: ", domain)
|
||||||
|
|
||||||
// sendQuery implements CachedNameServer.
|
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||||
func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
|
||||||
errors.LogInfo(ctx, s.Name(), " querying: ", fqdn)
|
|
||||||
|
|
||||||
reqs := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
@@ -110,46 +192,23 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- e
|
|||||||
b, err := dns.PackMessage(r.msg)
|
b, err := dns.PackMessage(r.msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dnsReqBuf := buf.New()
|
dnsReqBuf := buf.New()
|
||||||
err = binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
||||||
if err != nil {
|
dnsReqBuf.Write(b.Bytes())
|
||||||
errors.LogErrorInner(ctx, err, "binary write failed")
|
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = dnsReqBuf.Write(b.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "buffer write failed")
|
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b.Release()
|
b.Release()
|
||||||
|
|
||||||
conn, err := s.openStream(dnsCtx)
|
conn, err := s.openStream(dnsCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to open quic connection")
|
errors.LogErrorInner(ctx, err, "failed to open quic connection")
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = conn.Write(dnsReqBuf.Bytes())
|
_, err = conn.Write(dnsReqBuf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to send query")
|
errors.LogErrorInner(ctx, err, "failed to send query")
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,49 +219,137 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- e
|
|||||||
n, err := respBuf.ReadFullFrom(conn, 2)
|
n, err := respBuf.ReadFullFrom(conn, 2)
|
||||||
if err != nil && n == 0 {
|
if err != nil && n == 0 {
|
||||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var length uint16
|
var length int16
|
||||||
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
|
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
respBuf.Clear()
|
respBuf.Clear()
|
||||||
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
||||||
if err != nil && n == 0 {
|
if err != nil && n == 0 {
|
||||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rec, err := parseResponse(respBuf.Bytes())
|
rec, err := parseResponse(respBuf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to handle response")
|
errors.LogErrorInner(ctx, err, "failed to handle response")
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.cacheController.updateRecord(r, rec)
|
s.updateIP(r, rec)
|
||||||
}(req)
|
}(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryIP implements Server.
|
func (s *QUICNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||||
func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
s.RLock()
|
||||||
return queryIP(ctx, s, domain, option)
|
record, found := s.ips[domain]
|
||||||
|
s.RUnlock()
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return nil, errRecordNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
var err4 error
|
||||||
|
var err6 error
|
||||||
|
var ips []net.Address
|
||||||
|
var ip6 []net.Address
|
||||||
|
|
||||||
|
if option.IPv4Enable {
|
||||||
|
ips, err4 = record.A.getIPs()
|
||||||
|
}
|
||||||
|
|
||||||
|
if option.IPv6Enable {
|
||||||
|
ip6, err6 = record.AAAA.getIPs()
|
||||||
|
ips = append(ips, ip6...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ips) > 0 {
|
||||||
|
return toNetIP(ips)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err4 != nil {
|
||||||
|
return nil, err4
|
||||||
|
}
|
||||||
|
|
||||||
|
if err6 != nil {
|
||||||
|
return nil, err6
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {
|
||||||
|
return nil, dns_feature.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errRecordNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func isActive(s *quic.Conn) bool {
|
// 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) {
|
||||||
|
fqdn := Fqdn(domain)
|
||||||
|
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||||
|
if !option.IPv4Enable && !option.IPv6Enable {
|
||||||
|
return nil, dns_feature.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
if disableCache {
|
||||||
|
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
||||||
|
} else {
|
||||||
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
|
if err == nil || err == dns_feature.ErrEmptyResponse {
|
||||||
|
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
|
||||||
|
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||||
|
return ips, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ipv4 and ipv6 belong to different subscription groups
|
||||||
|
var sub4, sub6 *pubsub.Subscriber
|
||||||
|
if option.IPv4Enable {
|
||||||
|
sub4 = s.pub.Subscribe(fqdn + "4")
|
||||||
|
defer sub4.Close()
|
||||||
|
}
|
||||||
|
if option.IPv6Enable {
|
||||||
|
sub6 = s.pub.Subscribe(fqdn + "6")
|
||||||
|
defer sub6.Close()
|
||||||
|
}
|
||||||
|
done := make(chan interface{})
|
||||||
|
go func() {
|
||||||
|
if sub4 != nil {
|
||||||
|
select {
|
||||||
|
case <-sub4.Wait():
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sub6 != nil {
|
||||||
|
select {
|
||||||
|
case <-sub6.Wait():
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
s.sendQuery(ctx, fqdn, clientIP, option)
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
for {
|
||||||
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isActive(s quic.Connection) bool {
|
||||||
select {
|
select {
|
||||||
case <-s.Context().Done():
|
case <-s.Context().Done():
|
||||||
return false
|
return false
|
||||||
@@ -211,8 +358,8 @@ func isActive(s *quic.Conn) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QUICNameServer) getConnection() (*quic.Conn, error) {
|
func (s *QUICNameServer) getConnection() (quic.Connection, error) {
|
||||||
var conn *quic.Conn
|
var conn quic.Connection
|
||||||
s.RLock()
|
s.RLock()
|
||||||
conn = s.connection
|
conn = s.connection
|
||||||
if conn != nil && isActive(conn) {
|
if conn != nil && isActive(conn) {
|
||||||
@@ -245,7 +392,7 @@ func (s *QUICNameServer) getConnection() (*quic.Conn, error) {
|
|||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QUICNameServer) openConnection() (*quic.Conn, error) {
|
func (s *QUICNameServer) openConnection() (quic.Connection, error) {
|
||||||
tlsConfig := tls.Config{}
|
tlsConfig := tls.Config{}
|
||||||
quicConfig := &quic.Config{
|
quicConfig := &quic.Config{
|
||||||
HandshakeIdleTimeout: handshakeTimeout,
|
HandshakeIdleTimeout: handshakeTimeout,
|
||||||
@@ -265,7 +412,7 @@ func (s *QUICNameServer) openConnection() (*quic.Conn, error) {
|
|||||||
return conn, nil
|
return conn, 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()
|
conn, err := s.getConnection()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -16,23 +16,24 @@ import (
|
|||||||
func TestQUICNameServer(t *testing.T) {
|
func TestQUICNameServer(t *testing.T) {
|
||||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
url, err := url.Parse("quic://dns.adguard-dns.com")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
s, err := NewQUICNameServer(url, false, false, 0, net.IP(nil))
|
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP)
|
||||||
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", dns.IPOption{
|
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
}, false)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
t.Error("expect some ips, but got 0")
|
t.Error("expect some ips, but got 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips2, _, err := s.QueryIP(ctx2, "google.com", dns.IPOption{
|
ips2, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
}, true)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if r := cmp.Diff(ips2, ips); r != "" {
|
if r := cmp.Diff(ips2, ips); r != "" {
|
||||||
@@ -43,13 +44,13 @@ func TestQUICNameServer(t *testing.T) {
|
|||||||
func TestQUICNameServerWithIPv4Override(t *testing.T) {
|
func TestQUICNameServerWithIPv4Override(t *testing.T) {
|
||||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
url, err := url.Parse("quic://dns.adguard-dns.com")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
s, err := NewQUICNameServer(url, false, false, 0, net.IP(nil))
|
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP4)
|
||||||
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", dns.IPOption{
|
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: false,
|
IPv6Enable: true,
|
||||||
})
|
}, false)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
@@ -66,13 +67,13 @@ func TestQUICNameServerWithIPv4Override(t *testing.T) {
|
|||||||
func TestQUICNameServerWithIPv6Override(t *testing.T) {
|
func TestQUICNameServerWithIPv6Override(t *testing.T) {
|
||||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
url, err := url.Parse("quic://dns.adguard-dns.com")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
s, err := NewQUICNameServer(url, false, false, 0, net.IP(nil))
|
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP6)
|
||||||
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", dns.IPOption{
|
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
|
||||||
IPv4Enable: false,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
}, false)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
|
|||||||
@@ -5,37 +5,46 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/common/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"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
|
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||||
|
"github.com/xtls/xray-core/common/task"
|
||||||
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 {
|
||||||
cacheController *CacheController
|
sync.RWMutex
|
||||||
destination *net.Destination
|
name string
|
||||||
reqID uint32
|
destination *net.Destination
|
||||||
dial func(context.Context) (net.Conn, error)
|
ips map[string]*record
|
||||||
clientIP net.IP
|
pub *pubsub.Service
|
||||||
|
cleanup *task.Periodic
|
||||||
|
reqID uint32
|
||||||
|
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,
|
url *url.URL,
|
||||||
dispatcher routing.Dispatcher,
|
dispatcher routing.Dispatcher,
|
||||||
disableCache bool, serveStale bool, serveExpiredTTL uint32,
|
queryStrategy QueryStrategy,
|
||||||
clientIP net.IP,
|
|
||||||
) (*TCPNameServer, error) {
|
) (*TCPNameServer, error) {
|
||||||
s, err := baseTCPNameServer(url, "TCP", disableCache, serveStale, serveExpiredTTL, clientIP)
|
s, err := baseTCPNameServer(url, "TCP", queryStrategy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -52,13 +61,12 @@ func NewTCPNameServer(
|
|||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogInfo(context.Background(), "DNS: created TCP client initialized for ", url.String())
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, disableCache bool, serveStale bool, serveExpiredTTL uint32, clientIP net.IP) (*TCPNameServer, error) {
|
func NewTCPLocalNameServer(url *url.URL, queryStrategy QueryStrategy) (*TCPNameServer, error) {
|
||||||
s, err := baseTCPNameServer(url, "TCPL", disableCache, serveStale, serveExpiredTTL, clientIP)
|
s, err := baseTCPNameServer(url, "TCPL", queryStrategy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -67,11 +75,10 @@ func NewTCPLocalNameServer(url *url.URL, disableCache bool, serveStale bool, ser
|
|||||||
return internet.DialSystem(ctx, *s.destination, nil)
|
return internet.DialSystem(ctx, *s.destination, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogInfo(context.Background(), "DNS: created Local TCP client initialized for ", url.String())
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func baseTCPNameServer(url *url.URL, prefix string, disableCache bool, serveStale bool, serveExpiredTTL uint32, clientIP net.IP) (*TCPNameServer, error) {
|
func baseTCPNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) (*TCPNameServer, error) {
|
||||||
port := net.Port(53)
|
port := net.Port(53)
|
||||||
if url.Port() != "" {
|
if url.Port() != "" {
|
||||||
var err error
|
var err error
|
||||||
@@ -82,9 +89,15 @@ func baseTCPNameServer(url *url.URL, prefix string, disableCache bool, serveStal
|
|||||||
dest := net.TCPDestination(net.ParseAddress(url.Hostname()), port)
|
dest := net.TCPDestination(net.ParseAddress(url.Hostname()), port)
|
||||||
|
|
||||||
s := &TCPNameServer{
|
s := &TCPNameServer{
|
||||||
cacheController: NewCacheController(prefix+"//"+dest.NetAddr(), disableCache, serveStale, serveExpiredTTL),
|
destination: &dest,
|
||||||
destination: &dest,
|
ips: make(map[string]*record),
|
||||||
clientIP: clientIP,
|
pub: pubsub.NewService(),
|
||||||
|
name: prefix + "//" + dest.NetAddr(),
|
||||||
|
queryStrategy: queryStrategy,
|
||||||
|
}
|
||||||
|
s.cleanup = &task.Periodic{
|
||||||
|
Interval: time.Minute,
|
||||||
|
Execute: s.Cleanup,
|
||||||
}
|
}
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
@@ -92,28 +105,94 @@ func baseTCPNameServer(url *url.URL, prefix string, disableCache bool, serveStal
|
|||||||
|
|
||||||
// Name implements Server.
|
// Name implements Server.
|
||||||
func (s *TCPNameServer) Name() string {
|
func (s *TCPNameServer) Name() string {
|
||||||
return s.cacheController.name
|
return s.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDisableCache implements Server.
|
// Cleanup clears expired items from cache
|
||||||
func (s *TCPNameServer) IsDisableCache() bool {
|
func (s *TCPNameServer) Cleanup() error {
|
||||||
return s.cacheController.disableCache
|
now := time.Now()
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
|
if len(s.ips) == 0 {
|
||||||
|
return errors.New("nothing to do. stopping...")
|
||||||
|
}
|
||||||
|
|
||||||
|
for domain, record := range s.ips {
|
||||||
|
if record.A != nil && record.A.Expire.Before(now) {
|
||||||
|
record.A = nil
|
||||||
|
}
|
||||||
|
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
||||||
|
record.AAAA = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if record.A == nil && record.AAAA == nil {
|
||||||
|
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||||
|
delete(s.ips, domain)
|
||||||
|
} else {
|
||||||
|
s.ips[domain] = record
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.ips) == 0 {
|
||||||
|
s.ips = make(map[string]*record)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TCPNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||||
|
elapsed := time.Since(req.start)
|
||||||
|
|
||||||
|
s.Lock()
|
||||||
|
rec, found := s.ips[req.domain]
|
||||||
|
if !found {
|
||||||
|
rec = &record{}
|
||||||
|
}
|
||||||
|
updated := false
|
||||||
|
|
||||||
|
switch req.reqType {
|
||||||
|
case dnsmessage.TypeA:
|
||||||
|
if isNewer(rec.A, ipRec) {
|
||||||
|
rec.A = ipRec
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
case dnsmessage.TypeAAAA:
|
||||||
|
addr := make([]net.Address, 0)
|
||||||
|
for _, ip := range ipRec.IP {
|
||||||
|
if len(ip.IP()) == net.IPv6len {
|
||||||
|
addr = append(addr, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ipRec.IP = addr
|
||||||
|
if isNewer(rec.AAAA, ipRec) {
|
||||||
|
rec.AAAA = ipRec
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||||
|
|
||||||
|
if updated {
|
||||||
|
s.ips[req.domain] = rec
|
||||||
|
}
|
||||||
|
switch req.reqType {
|
||||||
|
case dnsmessage.TypeA:
|
||||||
|
s.pub.Publish(req.domain+"4", nil)
|
||||||
|
case dnsmessage.TypeAAAA:
|
||||||
|
s.pub.Publish(req.domain+"6", nil)
|
||||||
|
}
|
||||||
|
s.Unlock()
|
||||||
|
common.Must(s.cleanup.Start())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TCPNameServer) newReqID() uint16 {
|
func (s *TCPNameServer) newReqID() uint16 {
|
||||||
return uint16(atomic.AddUint32(&s.reqID, 1))
|
return uint16(atomic.AddUint32(&s.reqID, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCacheController implements CachedNameserver.
|
func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||||
func (s *TCPNameServer) getCacheController() *CacheController {
|
errors.LogDebug(ctx, s.name, " querying DNS for: ", domain)
|
||||||
return s.cacheController
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendQuery implements CachedNameserver.
|
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||||
func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
|
||||||
errors.LogInfo(ctx, s.Name(), " querying DNS for: ", fqdn)
|
|
||||||
|
|
||||||
reqs := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
@@ -142,46 +221,23 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- er
|
|||||||
b, err := dns.PackMessage(r.msg)
|
b, err := dns.PackMessage(r.msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := s.dial(dnsCtx)
|
conn, err := s.dial(dnsCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to dial namesever")
|
errors.LogErrorInner(ctx, err, "failed to dial namesever")
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
dnsReqBuf := buf.New()
|
dnsReqBuf := buf.New()
|
||||||
err = binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
||||||
if err != nil {
|
dnsReqBuf.Write(b.Bytes())
|
||||||
errors.LogErrorInner(ctx, err, "binary write failed")
|
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = dnsReqBuf.Write(b.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "buffer write failed")
|
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b.Release()
|
b.Release()
|
||||||
|
|
||||||
_, err = conn.Write(dnsReqBuf.Bytes())
|
_, err = conn.Write(dnsReqBuf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to send query")
|
errors.LogErrorInner(ctx, err, "failed to send query")
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dnsReqBuf.Release()
|
dnsReqBuf.Release()
|
||||||
@@ -191,45 +247,129 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- er
|
|||||||
n, err := respBuf.ReadFullFrom(conn, 2)
|
n, err := respBuf.ReadFullFrom(conn, 2)
|
||||||
if err != nil && n == 0 {
|
if err != nil && n == 0 {
|
||||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var length uint16
|
var length int16
|
||||||
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
|
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
respBuf.Clear()
|
respBuf.Clear()
|
||||||
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
||||||
if err != nil && n == 0 {
|
if err != nil && n == 0 {
|
||||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rec, err := parseResponse(respBuf.Bytes())
|
rec, err := parseResponse(respBuf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to parse DNS over TCP response")
|
errors.LogErrorInner(ctx, err, "failed to parse DNS over TCP response")
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cacheController.updateRecord(r, rec)
|
s.updateIP(r, rec)
|
||||||
}(req)
|
}(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryIP implements Server.
|
func (s *TCPNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||||
func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
s.RLock()
|
||||||
return queryIP(ctx, s, domain, option)
|
record, found := s.ips[domain]
|
||||||
|
s.RUnlock()
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return nil, errRecordNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
var err4 error
|
||||||
|
var err6 error
|
||||||
|
var ips []net.Address
|
||||||
|
var ip6 []net.Address
|
||||||
|
|
||||||
|
if option.IPv4Enable {
|
||||||
|
ips, err4 = record.A.getIPs()
|
||||||
|
}
|
||||||
|
|
||||||
|
if option.IPv6Enable {
|
||||||
|
ip6, err6 = record.AAAA.getIPs()
|
||||||
|
ips = append(ips, ip6...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ips) > 0 {
|
||||||
|
return toNetIP(ips)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err4 != nil {
|
||||||
|
return nil, err4
|
||||||
|
}
|
||||||
|
|
||||||
|
if err6 != nil {
|
||||||
|
return nil, err6
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, dns_feature.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryIP implements Server.
|
||||||
|
func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
|
||||||
|
fqdn := Fqdn(domain)
|
||||||
|
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||||
|
if !option.IPv4Enable && !option.IPv6Enable {
|
||||||
|
return nil, dns_feature.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
if disableCache {
|
||||||
|
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
||||||
|
} else {
|
||||||
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
|
if err == nil || err == dns_feature.ErrEmptyResponse {
|
||||||
|
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
|
||||||
|
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||||
|
return ips, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ipv4 and ipv6 belong to different subscription groups
|
||||||
|
var sub4, sub6 *pubsub.Subscriber
|
||||||
|
if option.IPv4Enable {
|
||||||
|
sub4 = s.pub.Subscribe(fqdn + "4")
|
||||||
|
defer sub4.Close()
|
||||||
|
}
|
||||||
|
if option.IPv6Enable {
|
||||||
|
sub6 = s.pub.Subscribe(fqdn + "6")
|
||||||
|
defer sub6.Close()
|
||||||
|
}
|
||||||
|
done := make(chan interface{})
|
||||||
|
go func() {
|
||||||
|
if sub4 != nil {
|
||||||
|
select {
|
||||||
|
case <-sub4.Wait():
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sub6 != nil {
|
||||||
|
select {
|
||||||
|
case <-sub6.Wait():
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
s.sendQuery(ctx, fqdn, clientIP, option)
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
for {
|
||||||
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ 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, false, false, 0, net.IP(nil))
|
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP)
|
||||||
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", dns_feature.IPOption{
|
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
}, false)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
@@ -33,13 +33,13 @@ 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, false, false, 0, net.IP(nil))
|
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP)
|
||||||
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", dns_feature.IPOption{
|
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
}, false)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
@@ -47,10 +47,10 @@ func TestTCPLocalNameServerWithCache(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips2, _, err := s.QueryIP(ctx2, "google.com", dns_feature.IPOption{
|
ips2, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
}, true)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if r := cmp.Diff(ips2, ips); r != "" {
|
if r := cmp.Diff(ips2, ips); r != "" {
|
||||||
@@ -61,13 +61,13 @@ func TestTCPLocalNameServerWithCache(t *testing.T) {
|
|||||||
func TestTCPLocalNameServerWithIPv4Override(t *testing.T) {
|
func TestTCPLocalNameServerWithIPv4Override(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, false, false, 0, net.IP(nil))
|
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP4)
|
||||||
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", dns_feature.IPOption{
|
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: false,
|
IPv6Enable: true,
|
||||||
})
|
}, false)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
@@ -85,13 +85,13 @@ func TestTCPLocalNameServerWithIPv4Override(t *testing.T) {
|
|||||||
func TestTCPLocalNameServerWithIPv6Override(t *testing.T) {
|
func TestTCPLocalNameServerWithIPv6Override(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, false, false, 0, net.IP(nil))
|
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP6)
|
||||||
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", dns_feature.IPOption{
|
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||||
IPv4Enable: false,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
}, false)
|
||||||
cancel()
|
cancel()
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ import (
|
|||||||
|
|
||||||
"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/protocol/dns"
|
"github.com/xtls/xray-core/common/protocol/dns"
|
||||||
udp_proto "github.com/xtls/xray-core/common/protocol/udp"
|
udp_proto "github.com/xtls/xray-core/common/protocol/udp"
|
||||||
|
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||||
"github.com/xtls/xray-core/common/task"
|
"github.com/xtls/xray-core/common/task"
|
||||||
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"
|
||||||
@@ -22,61 +24,74 @@ import (
|
|||||||
// ClassicNameServer implemented traditional UDP DNS.
|
// ClassicNameServer implemented traditional UDP DNS.
|
||||||
type ClassicNameServer struct {
|
type ClassicNameServer struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
cacheController *CacheController
|
name string
|
||||||
address *net.Destination
|
address *net.Destination
|
||||||
requests map[uint16]*udpDnsRequest
|
ips map[string]*record
|
||||||
udpServer *udp.Dispatcher
|
requests map[uint16]*dnsRequest
|
||||||
requestsCleanup *task.Periodic
|
pub *pubsub.Service
|
||||||
reqID uint32
|
udpServer *udp.Dispatcher
|
||||||
clientIP net.IP
|
cleanup *task.Periodic
|
||||||
}
|
reqID uint32
|
||||||
|
queryStrategy QueryStrategy
|
||||||
type udpDnsRequest struct {
|
|
||||||
dnsRequest
|
|
||||||
ctx context.Context
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClassicNameServer creates udp server object for remote resolving.
|
// NewClassicNameServer creates udp server object for remote resolving.
|
||||||
func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher, disableCache bool, serveStale bool, serveExpiredTTL uint32, clientIP net.IP) *ClassicNameServer {
|
func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) *ClassicNameServer {
|
||||||
// default to 53 if unspecific
|
// default to 53 if unspecific
|
||||||
if address.Port == 0 {
|
if address.Port == 0 {
|
||||||
address.Port = net.Port(53)
|
address.Port = net.Port(53)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := &ClassicNameServer{
|
s := &ClassicNameServer{
|
||||||
cacheController: NewCacheController(strings.ToUpper(address.String()), disableCache, serveStale, serveExpiredTTL),
|
address: &address,
|
||||||
address: &address,
|
ips: make(map[string]*record),
|
||||||
requests: make(map[uint16]*udpDnsRequest),
|
requests: make(map[uint16]*dnsRequest),
|
||||||
clientIP: clientIP,
|
pub: pubsub.NewService(),
|
||||||
|
name: strings.ToUpper(address.String()),
|
||||||
|
queryStrategy: queryStrategy,
|
||||||
}
|
}
|
||||||
s.requestsCleanup = &task.Periodic{
|
s.cleanup = &task.Periodic{
|
||||||
Interval: time.Minute,
|
Interval: time.Minute,
|
||||||
Execute: s.RequestsCleanup,
|
Execute: s.Cleanup,
|
||||||
}
|
}
|
||||||
s.udpServer = udp.NewDispatcher(dispatcher, s.HandleResponse)
|
s.udpServer = udp.NewDispatcher(dispatcher, s.HandleResponse)
|
||||||
|
|
||||||
errors.LogInfo(context.Background(), "DNS: created UDP client initialized for ", address.NetAddr())
|
errors.LogInfo(context.Background(), "DNS: created UDP client initialized for ", address.NetAddr())
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name implements Server.
|
// Name implements Server.
|
||||||
func (s *ClassicNameServer) Name() string {
|
func (s *ClassicNameServer) Name() string {
|
||||||
return s.cacheController.name
|
return s.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDisableCache implements Server.
|
// Cleanup clears expired items from cache
|
||||||
func (s *ClassicNameServer) IsDisableCache() bool {
|
func (s *ClassicNameServer) Cleanup() error {
|
||||||
return s.cacheController.disableCache
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestsCleanup clears expired items from cache
|
|
||||||
func (s *ClassicNameServer) RequestsCleanup() error {
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
||||||
if len(s.requests) == 0 {
|
if len(s.ips) == 0 && len(s.requests) == 0 {
|
||||||
return errors.New(s.Name(), " nothing to do. stopping...")
|
return errors.New(s.name, " nothing to do. stopping...")
|
||||||
|
}
|
||||||
|
|
||||||
|
for domain, record := range s.ips {
|
||||||
|
if record.A != nil && record.A.Expire.Before(now) {
|
||||||
|
record.A = nil
|
||||||
|
}
|
||||||
|
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
||||||
|
record.AAAA = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if record.A == nil && record.AAAA == nil {
|
||||||
|
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||||
|
delete(s.ips, domain)
|
||||||
|
} else {
|
||||||
|
s.ips[domain] = record
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.ips) == 0 {
|
||||||
|
s.ips = make(map[string]*record)
|
||||||
}
|
}
|
||||||
|
|
||||||
for id, req := range s.requests {
|
for id, req := range s.requests {
|
||||||
@@ -86,7 +101,7 @@ func (s *ClassicNameServer) RequestsCleanup() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(s.requests) == 0 {
|
if len(s.requests) == 0 {
|
||||||
s.requests = make(map[uint16]*udpDnsRequest)
|
s.requests = make(map[uint16]*dnsRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -94,11 +109,9 @@ func (s *ClassicNameServer) RequestsCleanup() error {
|
|||||||
|
|
||||||
// HandleResponse handles udp response packet from remote DNS server.
|
// HandleResponse handles udp response packet from remote DNS server.
|
||||||
func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_proto.Packet) {
|
func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_proto.Packet) {
|
||||||
payload := packet.Payload
|
ipRec, err := parseResponse(packet.Payload.Bytes())
|
||||||
ipRec, err := parseResponse(payload.Bytes())
|
|
||||||
payload.Release()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, s.Name(), " fail to parse responded DNS udp")
|
errors.LogError(ctx, s.name, " fail to parse responded DNS udp")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,74 +124,179 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
|||||||
}
|
}
|
||||||
s.Unlock()
|
s.Unlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
errors.LogErrorInner(ctx, err, s.Name(), " cannot find the pending request")
|
errors.LogError(ctx, s.name, " cannot find the pending request")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// if truncated, retry with EDNS0 option(udp payload size: 1350)
|
var rec record
|
||||||
if ipRec.RawHeader.Truncated {
|
switch req.reqType {
|
||||||
// if already has EDNS0 option, no need to retry
|
case dnsmessage.TypeA:
|
||||||
if len(req.msg.Additionals) == 0 {
|
rec.A = ipRec
|
||||||
// copy necessary meta data from original request
|
case dnsmessage.TypeAAAA:
|
||||||
// and add EDNS0 option
|
rec.AAAA = ipRec
|
||||||
opt := new(dnsmessage.Resource)
|
|
||||||
common.Must(opt.Header.SetEDNS0(1350, 0xfe00, true))
|
|
||||||
opt.Body = &dnsmessage.OPTResource{}
|
|
||||||
newMsg := *req.msg
|
|
||||||
newReq := *req
|
|
||||||
newMsg.Additionals = append(newMsg.Additionals, *opt)
|
|
||||||
newMsg.ID = s.newReqID()
|
|
||||||
newReq.msg = &newMsg
|
|
||||||
s.addPendingRequest(&newReq)
|
|
||||||
b, _ := dns.PackMessage(newReq.msg)
|
|
||||||
copyDest := net.UDPDestination(s.address.Address, s.address.Port)
|
|
||||||
b.UDP = ©Dest
|
|
||||||
s.udpServer.Dispatch(toDnsContext(newReq.ctx, s.address.String()), *s.address, b)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cacheController.updateRecord(&req.dnsRequest, ipRec)
|
elapsed := time.Since(req.start)
|
||||||
|
errors.LogInfo(ctx, s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||||
|
if len(req.domain) > 0 && (rec.A != nil || rec.AAAA != nil) {
|
||||||
|
s.updateIP(req.domain, &rec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClassicNameServer) updateIP(domain string, newRec *record) {
|
||||||
|
s.Lock()
|
||||||
|
|
||||||
|
rec, found := s.ips[domain]
|
||||||
|
if !found {
|
||||||
|
rec = &record{}
|
||||||
|
}
|
||||||
|
|
||||||
|
updated := false
|
||||||
|
if isNewer(rec.A, newRec.A) {
|
||||||
|
rec.A = newRec.A
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
if isNewer(rec.AAAA, newRec.AAAA) {
|
||||||
|
rec.AAAA = newRec.AAAA
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if updated {
|
||||||
|
errors.LogDebug(context.Background(), s.name, " updating IP records for domain:", domain)
|
||||||
|
s.ips[domain] = rec
|
||||||
|
}
|
||||||
|
if newRec.A != nil {
|
||||||
|
s.pub.Publish(domain+"4", nil)
|
||||||
|
}
|
||||||
|
if newRec.AAAA != nil {
|
||||||
|
s.pub.Publish(domain+"6", nil)
|
||||||
|
}
|
||||||
|
s.Unlock()
|
||||||
|
common.Must(s.cleanup.Start())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ClassicNameServer) newReqID() uint16 {
|
func (s *ClassicNameServer) newReqID() uint16 {
|
||||||
return uint16(atomic.AddUint32(&s.reqID, 1))
|
return uint16(atomic.AddUint32(&s.reqID, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ClassicNameServer) addPendingRequest(req *udpDnsRequest) {
|
func (s *ClassicNameServer) addPendingRequest(req *dnsRequest) {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
id := req.msg.ID
|
id := req.msg.ID
|
||||||
req.expire = time.Now().Add(time.Second * 8)
|
req.expire = time.Now().Add(time.Second * 8)
|
||||||
s.requests[id] = req
|
s.requests[id] = req
|
||||||
s.Unlock()
|
|
||||||
common.Must(s.requestsCleanup.Start())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCacheController implements CachedNameserver.
|
func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||||
func (s *ClassicNameServer) getCacheController() *CacheController {
|
errors.LogDebug(ctx, s.name, " querying DNS for: ", domain)
|
||||||
return s.cacheController
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendQuery implements CachedNameserver.
|
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||||
func (s *ClassicNameServer) sendQuery(ctx context.Context, _ chan<- error, fqdn string, option dns_feature.IPOption) {
|
|
||||||
errors.LogInfo(ctx, s.Name(), " querying DNS for: ", fqdn)
|
|
||||||
|
|
||||||
reqs := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
|
||||||
|
|
||||||
for _, req := range reqs {
|
for _, req := range reqs {
|
||||||
udpReq := &udpDnsRequest{
|
s.addPendingRequest(req)
|
||||||
dnsRequest: *req,
|
|
||||||
ctx: ctx,
|
|
||||||
}
|
|
||||||
s.addPendingRequest(udpReq)
|
|
||||||
b, _ := dns.PackMessage(req.msg)
|
b, _ := dns.PackMessage(req.msg)
|
||||||
copyDest := net.UDPDestination(s.address.Address, s.address.Port)
|
|
||||||
b.UDP = ©Dest
|
|
||||||
s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b)
|
s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryIP implements Server.
|
func (s *ClassicNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||||
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
s.RLock()
|
||||||
return queryIP(ctx, s, domain, option)
|
record, found := s.ips[domain]
|
||||||
|
s.RUnlock()
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return nil, errRecordNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
var err4 error
|
||||||
|
var err6 error
|
||||||
|
var ips []net.Address
|
||||||
|
var ip6 []net.Address
|
||||||
|
|
||||||
|
if option.IPv4Enable {
|
||||||
|
ips, err4 = record.A.getIPs()
|
||||||
|
}
|
||||||
|
|
||||||
|
if option.IPv6Enable {
|
||||||
|
ip6, err6 = record.AAAA.getIPs()
|
||||||
|
ips = append(ips, ip6...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ips) > 0 {
|
||||||
|
return toNetIP(ips)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err4 != nil {
|
||||||
|
return nil, err4
|
||||||
|
}
|
||||||
|
|
||||||
|
if err6 != nil {
|
||||||
|
return nil, err6
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, dns_feature.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryIP implements Server.
|
||||||
|
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
|
||||||
|
fqdn := Fqdn(domain)
|
||||||
|
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||||
|
if !option.IPv4Enable && !option.IPv6Enable {
|
||||||
|
return nil, dns_feature.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
if disableCache {
|
||||||
|
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
||||||
|
} else {
|
||||||
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
|
if err == nil || err == dns_feature.ErrEmptyResponse {
|
||||||
|
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
|
||||||
|
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||||
|
return ips, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ipv4 and ipv6 belong to different subscription groups
|
||||||
|
var sub4, sub6 *pubsub.Subscriber
|
||||||
|
if option.IPv4Enable {
|
||||||
|
sub4 = s.pub.Subscribe(fqdn + "4")
|
||||||
|
defer sub4.Close()
|
||||||
|
}
|
||||||
|
if option.IPv6Enable {
|
||||||
|
sub6 = s.pub.Subscribe(fqdn + "6")
|
||||||
|
defer sub6.Close()
|
||||||
|
}
|
||||||
|
done := make(chan interface{})
|
||||||
|
go func() {
|
||||||
|
if sub4 != nil {
|
||||||
|
select {
|
||||||
|
case <-sub4.Wait():
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sub6 != nil {
|
||||||
|
select {
|
||||||
|
case <-sub6.Wait():
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
s.sendQuery(ctx, fqdn, clientIP, option)
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
for {
|
||||||
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/net/cnc"
|
"github.com/xtls/xray-core/common/net/cnc"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
|
||||||
"github.com/xtls/xray-core/common/signal/done"
|
"github.com/xtls/xray-core/common/signal/done"
|
||||||
"github.com/xtls/xray-core/transport"
|
"github.com/xtls/xray-core/transport"
|
||||||
)
|
)
|
||||||
@@ -109,13 +108,3 @@ func (co *Outbound) Close() error {
|
|||||||
co.closed = true
|
co.closed = true
|
||||||
return co.listener.Close()
|
return co.listener.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SenderSettings implements outbound.Handler.
|
|
||||||
func (co *Outbound) SenderSettings() *serial.TypedMessage {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProxySettings implements outbound.Handler.
|
|
||||||
func (co *Outbound) ProxySettings() *serial.TypedMessage {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -90,8 +90,6 @@ type HealthPingConfig struct {
|
|||||||
SamplingCount int32 `protobuf:"varint,4,opt,name=samplingCount,proto3" json:"samplingCount,omitempty"`
|
SamplingCount int32 `protobuf:"varint,4,opt,name=samplingCount,proto3" json:"samplingCount,omitempty"`
|
||||||
// ping timeout, int64 values of time.Duration
|
// ping timeout, int64 values of time.Duration
|
||||||
Timeout int64 `protobuf:"varint,5,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
Timeout int64 `protobuf:"varint,5,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
||||||
// http method to make request
|
|
||||||
HttpMethod string `protobuf:"bytes,6,opt,name=httpMethod,proto3" json:"httpMethod,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *HealthPingConfig) Reset() {
|
func (x *HealthPingConfig) Reset() {
|
||||||
@@ -159,13 +157,6 @@ func (x *HealthPingConfig) GetTimeout() int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *HealthPingConfig) GetHttpMethod() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.HttpMethod
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_app_observatory_burst_config_proto protoreflect.FileDescriptor
|
var File_app_observatory_burst_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
||||||
@@ -182,7 +173,7 @@ var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
|||||||
0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x62, 0x75, 0x72,
|
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,
|
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,
|
0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22,
|
||||||
0xd4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
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,
|
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,
|
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,
|
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||||
@@ -193,9 +184,7 @@ var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
|||||||
0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73,
|
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,
|
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,
|
0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74,
|
||||||
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x4d, 0x65,
|
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
|
||||||
0x74, 0x68, 0x6f, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x68, 0x74, 0x74, 0x70,
|
|
||||||
0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 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,
|
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,
|
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,
|
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
||||||
|
|||||||
@@ -26,7 +26,4 @@ message HealthPingConfig {
|
|||||||
int32 samplingCount = 4;
|
int32 samplingCount = 4;
|
||||||
// ping timeout, int64 values of time.Duration
|
// ping timeout, int64 values of time.Duration
|
||||||
int64 timeout = 5;
|
int64 timeout = 5;
|
||||||
// http method to make request
|
|
||||||
string httpMethod = 6;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ type HealthPingSettings struct {
|
|||||||
Interval time.Duration `json:"interval"`
|
Interval time.Duration `json:"interval"`
|
||||||
SamplingCount int `json:"sampling"`
|
SamplingCount int `json:"sampling"`
|
||||||
Timeout time.Duration `json:"timeout"`
|
Timeout time.Duration `json:"timeout"`
|
||||||
HttpMethod string `json:"httpMethod"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HealthPing is the health checker for balancers
|
// HealthPing is the health checker for balancers
|
||||||
@@ -38,21 +37,12 @@ type HealthPing struct {
|
|||||||
func NewHealthPing(ctx context.Context, dispatcher routing.Dispatcher, config *HealthPingConfig) *HealthPing {
|
func NewHealthPing(ctx context.Context, dispatcher routing.Dispatcher, config *HealthPingConfig) *HealthPing {
|
||||||
settings := &HealthPingSettings{}
|
settings := &HealthPingSettings{}
|
||||||
if config != nil {
|
if config != nil {
|
||||||
|
|
||||||
var httpMethod string
|
|
||||||
if config.HttpMethod == "" {
|
|
||||||
httpMethod = "HEAD"
|
|
||||||
} else {
|
|
||||||
httpMethod = strings.TrimSpace(config.HttpMethod)
|
|
||||||
}
|
|
||||||
|
|
||||||
settings = &HealthPingSettings{
|
settings = &HealthPingSettings{
|
||||||
Connectivity: strings.TrimSpace(config.Connectivity),
|
Connectivity: strings.TrimSpace(config.Connectivity),
|
||||||
Destination: strings.TrimSpace(config.Destination),
|
Destination: strings.TrimSpace(config.Destination),
|
||||||
Interval: time.Duration(config.Interval),
|
Interval: time.Duration(config.Interval),
|
||||||
SamplingCount: int(config.SamplingCount),
|
SamplingCount: int(config.SamplingCount),
|
||||||
Timeout: time.Duration(config.Timeout),
|
Timeout: time.Duration(config.Timeout),
|
||||||
HttpMethod: httpMethod,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if settings.Destination == "" {
|
if settings.Destination == "" {
|
||||||
@@ -174,7 +164,7 @@ func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int)
|
|||||||
}
|
}
|
||||||
time.AfterFunc(delay, func() {
|
time.AfterFunc(delay, func() {
|
||||||
errors.LogDebug(h.ctx, "checking ", handler)
|
errors.LogDebug(h.ctx, "checking ", handler)
|
||||||
delay, err := client.MeasureDelay(h.Settings.HttpMethod)
|
delay, err := client.MeasureDelay()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ch <- &rtt{
|
ch <- &rtt{
|
||||||
handler: handler,
|
handler: handler,
|
||||||
@@ -261,7 +251,7 @@ func (h *HealthPing) checkConnectivity() bool {
|
|||||||
h.Settings.Connectivity,
|
h.Settings.Connectivity,
|
||||||
h.Settings.Timeout,
|
h.Settings.Timeout,
|
||||||
)
|
)
|
||||||
if _, err := tester.MeasureDelay(h.Settings.HttpMethod); err != nil {
|
if _, err := tester.MeasureDelay(); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package burst
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -52,28 +51,20 @@ func newHTTPClient(ctxv context.Context, dispatcher routing.Dispatcher, handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MeasureDelay returns the delay time of the request to dest
|
// MeasureDelay returns the delay time of the request to dest
|
||||||
func (s *pingClient) MeasureDelay(httpMethod string) (time.Duration, error) {
|
func (s *pingClient) MeasureDelay() (time.Duration, error) {
|
||||||
if s.httpClient == nil {
|
if s.httpClient == nil {
|
||||||
panic("pingClient not initialized")
|
panic("pingClient not initialized")
|
||||||
}
|
}
|
||||||
|
req, err := http.NewRequest(http.MethodHead, s.destination, nil)
|
||||||
req, err := http.NewRequest(httpMethod, s.destination, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rttFailed, err
|
return rttFailed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
resp, err := s.httpClient.Do(req)
|
resp, err := s.httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rttFailed, err
|
return rttFailed, err
|
||||||
}
|
}
|
||||||
if httpMethod == http.MethodGet {
|
// don't wait for body
|
||||||
_, err = io.Copy(io.Discard, resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return rttFailed, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
|
|
||||||
return time.Since(start), nil
|
return time.Since(start), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package command
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/commander"
|
|
||||||
"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/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
@@ -100,28 +99,6 @@ func (s *handlerServer) AlterInbound(ctx context.Context, request *AlterInboundR
|
|||||||
return &AlterInboundResponse{}, operation.ApplyInbound(ctx, handler)
|
return &AlterInboundResponse{}, operation.ApplyInbound(ctx, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *handlerServer) ListInbounds(ctx context.Context, request *ListInboundsRequest) (*ListInboundsResponse, error) {
|
|
||||||
handlers := s.ihm.ListHandlers(ctx)
|
|
||||||
response := &ListInboundsResponse{}
|
|
||||||
if request.GetIsOnlyTags() {
|
|
||||||
for _, handler := range handlers {
|
|
||||||
response.Inbounds = append(response.Inbounds, &core.InboundHandlerConfig{
|
|
||||||
Tag: handler.Tag(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, handler := range handlers {
|
|
||||||
response.Inbounds = append(response.Inbounds, &core.InboundHandlerConfig{
|
|
||||||
Tag: handler.Tag(),
|
|
||||||
ReceiverSettings: handler.ReceiverSettings(),
|
|
||||||
ProxySettings: handler.ProxySettings(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *handlerServer) GetInboundUsers(ctx context.Context, request *GetInboundUserRequest) (*GetInboundUserResponse, error) {
|
func (s *handlerServer) GetInboundUsers(ctx context.Context, request *GetInboundUserRequest) (*GetInboundUserResponse, error) {
|
||||||
handler, err := s.ihm.GetHandler(ctx, request.Tag)
|
handler, err := s.ihm.GetHandler(ctx, request.Tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -187,23 +164,6 @@ func (s *handlerServer) AlterOutbound(ctx context.Context, request *AlterOutboun
|
|||||||
return &AlterOutboundResponse{}, operation.ApplyOutbound(ctx, handler)
|
return &AlterOutboundResponse{}, operation.ApplyOutbound(ctx, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *handlerServer) ListOutbounds(ctx context.Context, request *ListOutboundsRequest) (*ListOutboundsResponse, error) {
|
|
||||||
handlers := s.ohm.ListHandlers(ctx)
|
|
||||||
response := &ListOutboundsResponse{}
|
|
||||||
for _, handler := range handlers {
|
|
||||||
// Ignore gRPC outbound
|
|
||||||
if _, ok := handler.(*commander.Outbound); ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
response.Outbounds = append(response.Outbounds, &core.OutboundHandlerConfig{
|
|
||||||
Tag: handler.Tag(),
|
|
||||||
SenderSettings: handler.SenderSettings(),
|
|
||||||
ProxySettings: handler.ProxySettings(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return response, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *handlerServer) mustEmbedUnimplementedHandlerServiceServer() {}
|
func (s *handlerServer) mustEmbedUnimplementedHandlerServiceServer() {}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
|
|||||||
@@ -364,96 +364,6 @@ func (*AlterInboundResponse) Descriptor() ([]byte, []int) {
|
|||||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{7}
|
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{7}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListInboundsRequest struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
IsOnlyTags bool `protobuf:"varint,1,opt,name=isOnlyTags,proto3" json:"isOnlyTags,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListInboundsRequest) Reset() {
|
|
||||||
*x = ListInboundsRequest{}
|
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListInboundsRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*ListInboundsRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *ListInboundsRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use ListInboundsRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*ListInboundsRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{8}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListInboundsRequest) GetIsOnlyTags() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.IsOnlyTags
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListInboundsResponse struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Inbounds []*core.InboundHandlerConfig `protobuf:"bytes,1,rep,name=inbounds,proto3" json:"inbounds,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListInboundsResponse) Reset() {
|
|
||||||
*x = ListInboundsResponse{}
|
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListInboundsResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*ListInboundsResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *ListInboundsResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use ListInboundsResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*ListInboundsResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{9}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListInboundsResponse) GetInbounds() []*core.InboundHandlerConfig {
|
|
||||||
if x != nil {
|
|
||||||
return x.Inbounds
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetInboundUserRequest struct {
|
type GetInboundUserRequest struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -465,7 +375,7 @@ type GetInboundUserRequest struct {
|
|||||||
|
|
||||||
func (x *GetInboundUserRequest) Reset() {
|
func (x *GetInboundUserRequest) Reset() {
|
||||||
*x = GetInboundUserRequest{}
|
*x = GetInboundUserRequest{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -477,7 +387,7 @@ func (x *GetInboundUserRequest) String() string {
|
|||||||
func (*GetInboundUserRequest) ProtoMessage() {}
|
func (*GetInboundUserRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *GetInboundUserRequest) ProtoReflect() protoreflect.Message {
|
func (x *GetInboundUserRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -490,7 +400,7 @@ func (x *GetInboundUserRequest) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use GetInboundUserRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use GetInboundUserRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*GetInboundUserRequest) Descriptor() ([]byte, []int) {
|
func (*GetInboundUserRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{10}
|
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{8}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetInboundUserRequest) GetTag() string {
|
func (x *GetInboundUserRequest) GetTag() string {
|
||||||
@@ -517,7 +427,7 @@ type GetInboundUserResponse struct {
|
|||||||
|
|
||||||
func (x *GetInboundUserResponse) Reset() {
|
func (x *GetInboundUserResponse) Reset() {
|
||||||
*x = GetInboundUserResponse{}
|
*x = GetInboundUserResponse{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -529,7 +439,7 @@ func (x *GetInboundUserResponse) String() string {
|
|||||||
func (*GetInboundUserResponse) ProtoMessage() {}
|
func (*GetInboundUserResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *GetInboundUserResponse) ProtoReflect() protoreflect.Message {
|
func (x *GetInboundUserResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -542,7 +452,7 @@ func (x *GetInboundUserResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use GetInboundUserResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use GetInboundUserResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*GetInboundUserResponse) Descriptor() ([]byte, []int) {
|
func (*GetInboundUserResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{11}
|
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{9}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetInboundUserResponse) GetUsers() []*protocol.User {
|
func (x *GetInboundUserResponse) GetUsers() []*protocol.User {
|
||||||
@@ -562,7 +472,7 @@ type GetInboundUsersCountResponse struct {
|
|||||||
|
|
||||||
func (x *GetInboundUsersCountResponse) Reset() {
|
func (x *GetInboundUsersCountResponse) Reset() {
|
||||||
*x = GetInboundUsersCountResponse{}
|
*x = GetInboundUsersCountResponse{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -574,7 +484,7 @@ func (x *GetInboundUsersCountResponse) String() string {
|
|||||||
func (*GetInboundUsersCountResponse) ProtoMessage() {}
|
func (*GetInboundUsersCountResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *GetInboundUsersCountResponse) ProtoReflect() protoreflect.Message {
|
func (x *GetInboundUsersCountResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -587,7 +497,7 @@ func (x *GetInboundUsersCountResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use GetInboundUsersCountResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use GetInboundUsersCountResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*GetInboundUsersCountResponse) Descriptor() ([]byte, []int) {
|
func (*GetInboundUsersCountResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{12}
|
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{10}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetInboundUsersCountResponse) GetCount() int64 {
|
func (x *GetInboundUsersCountResponse) GetCount() int64 {
|
||||||
@@ -607,7 +517,7 @@ type AddOutboundRequest struct {
|
|||||||
|
|
||||||
func (x *AddOutboundRequest) Reset() {
|
func (x *AddOutboundRequest) Reset() {
|
||||||
*x = AddOutboundRequest{}
|
*x = AddOutboundRequest{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -619,7 +529,7 @@ func (x *AddOutboundRequest) String() string {
|
|||||||
func (*AddOutboundRequest) ProtoMessage() {}
|
func (*AddOutboundRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *AddOutboundRequest) ProtoReflect() protoreflect.Message {
|
func (x *AddOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -632,7 +542,7 @@ func (x *AddOutboundRequest) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use AddOutboundRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use AddOutboundRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*AddOutboundRequest) Descriptor() ([]byte, []int) {
|
func (*AddOutboundRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{13}
|
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{11}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddOutboundRequest) GetOutbound() *core.OutboundHandlerConfig {
|
func (x *AddOutboundRequest) GetOutbound() *core.OutboundHandlerConfig {
|
||||||
@@ -650,7 +560,7 @@ type AddOutboundResponse struct {
|
|||||||
|
|
||||||
func (x *AddOutboundResponse) Reset() {
|
func (x *AddOutboundResponse) Reset() {
|
||||||
*x = AddOutboundResponse{}
|
*x = AddOutboundResponse{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -662,7 +572,7 @@ func (x *AddOutboundResponse) String() string {
|
|||||||
func (*AddOutboundResponse) ProtoMessage() {}
|
func (*AddOutboundResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *AddOutboundResponse) ProtoReflect() protoreflect.Message {
|
func (x *AddOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -675,7 +585,7 @@ func (x *AddOutboundResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use AddOutboundResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use AddOutboundResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*AddOutboundResponse) Descriptor() ([]byte, []int) {
|
func (*AddOutboundResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{14}
|
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{12}
|
||||||
}
|
}
|
||||||
|
|
||||||
type RemoveOutboundRequest struct {
|
type RemoveOutboundRequest struct {
|
||||||
@@ -688,7 +598,7 @@ type RemoveOutboundRequest struct {
|
|||||||
|
|
||||||
func (x *RemoveOutboundRequest) Reset() {
|
func (x *RemoveOutboundRequest) Reset() {
|
||||||
*x = RemoveOutboundRequest{}
|
*x = RemoveOutboundRequest{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[15]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -700,7 +610,7 @@ func (x *RemoveOutboundRequest) String() string {
|
|||||||
func (*RemoveOutboundRequest) ProtoMessage() {}
|
func (*RemoveOutboundRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *RemoveOutboundRequest) ProtoReflect() protoreflect.Message {
|
func (x *RemoveOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[15]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -713,7 +623,7 @@ func (x *RemoveOutboundRequest) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use RemoveOutboundRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use RemoveOutboundRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*RemoveOutboundRequest) Descriptor() ([]byte, []int) {
|
func (*RemoveOutboundRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{15}
|
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{13}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveOutboundRequest) GetTag() string {
|
func (x *RemoveOutboundRequest) GetTag() string {
|
||||||
@@ -731,7 +641,7 @@ type RemoveOutboundResponse struct {
|
|||||||
|
|
||||||
func (x *RemoveOutboundResponse) Reset() {
|
func (x *RemoveOutboundResponse) Reset() {
|
||||||
*x = RemoveOutboundResponse{}
|
*x = RemoveOutboundResponse{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[16]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -743,7 +653,7 @@ func (x *RemoveOutboundResponse) String() string {
|
|||||||
func (*RemoveOutboundResponse) ProtoMessage() {}
|
func (*RemoveOutboundResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *RemoveOutboundResponse) ProtoReflect() protoreflect.Message {
|
func (x *RemoveOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[16]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -756,7 +666,7 @@ func (x *RemoveOutboundResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use RemoveOutboundResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use RemoveOutboundResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*RemoveOutboundResponse) Descriptor() ([]byte, []int) {
|
func (*RemoveOutboundResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{16}
|
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{14}
|
||||||
}
|
}
|
||||||
|
|
||||||
type AlterOutboundRequest struct {
|
type AlterOutboundRequest struct {
|
||||||
@@ -770,7 +680,7 @@ type AlterOutboundRequest struct {
|
|||||||
|
|
||||||
func (x *AlterOutboundRequest) Reset() {
|
func (x *AlterOutboundRequest) Reset() {
|
||||||
*x = AlterOutboundRequest{}
|
*x = AlterOutboundRequest{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[17]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[15]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -782,7 +692,7 @@ func (x *AlterOutboundRequest) String() string {
|
|||||||
func (*AlterOutboundRequest) ProtoMessage() {}
|
func (*AlterOutboundRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *AlterOutboundRequest) ProtoReflect() protoreflect.Message {
|
func (x *AlterOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[17]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[15]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -795,7 +705,7 @@ func (x *AlterOutboundRequest) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use AlterOutboundRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use AlterOutboundRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*AlterOutboundRequest) Descriptor() ([]byte, []int) {
|
func (*AlterOutboundRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{17}
|
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{15}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AlterOutboundRequest) GetTag() string {
|
func (x *AlterOutboundRequest) GetTag() string {
|
||||||
@@ -820,7 +730,7 @@ type AlterOutboundResponse struct {
|
|||||||
|
|
||||||
func (x *AlterOutboundResponse) Reset() {
|
func (x *AlterOutboundResponse) Reset() {
|
||||||
*x = AlterOutboundResponse{}
|
*x = AlterOutboundResponse{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[18]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[16]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -832,7 +742,7 @@ func (x *AlterOutboundResponse) String() string {
|
|||||||
func (*AlterOutboundResponse) ProtoMessage() {}
|
func (*AlterOutboundResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *AlterOutboundResponse) ProtoReflect() protoreflect.Message {
|
func (x *AlterOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[18]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[16]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -845,88 +755,7 @@ func (x *AlterOutboundResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use AlterOutboundResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use AlterOutboundResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*AlterOutboundResponse) Descriptor() ([]byte, []int) {
|
func (*AlterOutboundResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{18}
|
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{16}
|
||||||
}
|
|
||||||
|
|
||||||
type ListOutboundsRequest struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListOutboundsRequest) Reset() {
|
|
||||||
*x = ListOutboundsRequest{}
|
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[19]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListOutboundsRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*ListOutboundsRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *ListOutboundsRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[19]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use ListOutboundsRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*ListOutboundsRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{19}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListOutboundsResponse struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Outbounds []*core.OutboundHandlerConfig `protobuf:"bytes,1,rep,name=outbounds,proto3" json:"outbounds,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListOutboundsResponse) Reset() {
|
|
||||||
*x = ListOutboundsResponse{}
|
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[20]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListOutboundsResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*ListOutboundsResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *ListOutboundsResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[20]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use ListOutboundsResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*ListOutboundsResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{20}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListOutboundsResponse) GetOutbounds() []*core.OutboundHandlerConfig {
|
|
||||||
if x != nil {
|
|
||||||
return x.Outbounds
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -937,7 +766,7 @@ type Config struct {
|
|||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[21]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[17]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -949,7 +778,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_proxyman_command_command_proto_msgTypes[21]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[17]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -962,7 +791,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_proxyman_command_command_proto_rawDescGZIP(), []int{21}
|
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{17}
|
||||||
}
|
}
|
||||||
|
|
||||||
var File_app_proxyman_command_command_proto protoreflect.FileDescriptor
|
var File_app_proxyman_command_command_proto protoreflect.FileDescriptor
|
||||||
@@ -1002,84 +831,61 @@ var file_app_proxyman_command_command_proto_rawDesc = []byte{
|
|||||||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70,
|
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, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61,
|
0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61,
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x22, 0x16, 0x0a, 0x14, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62,
|
0x74, 0x69, 0x6f, 0x6e, 0x22, 0x16, 0x0a, 0x14, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62,
|
||||||
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x35, 0x0a, 0x13,
|
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3f, 0x0a, 0x15,
|
||||||
0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75,
|
0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65,
|
||||||
0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x54, 0x61, 0x67,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01,
|
||||||
0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x54,
|
0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c,
|
||||||
0x61, 0x67, 0x73, 0x22, 0x53, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x4a, 0x0a,
|
||||||
0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x69,
|
0x16, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52,
|
||||||
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e,
|
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73,
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
|
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||||
0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08,
|
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73,
|
||||||
0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x22, 0x3f, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x49,
|
0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x34, 0x0a, 0x1c, 0x47, 0x65, 0x74,
|
||||||
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x43, 0x6f, 0x75, 0x6e,
|
||||||
0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
|
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75,
|
||||||
0x74, 0x61, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01,
|
0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22,
|
||||||
0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x4a, 0x0a, 0x16, 0x47, 0x65, 0x74,
|
0x52, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65,
|
||||||
0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e,
|
||||||
0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03,
|
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
||||||
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64,
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05,
|
0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f,
|
||||||
0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x34, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f,
|
0x75, 0x6e, 0x64, 0x22, 0x15, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75,
|
||||||
0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73,
|
0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x0a, 0x15, 0x52, 0x65,
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01,
|
0x6d, 0x6f, 0x76, 0x65, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,
|
||||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x52, 0x0a, 0x12, 0x41,
|
|
||||||
0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
|
||||||
0x74, 0x12, 0x3c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20,
|
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
|
||||||
0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43,
|
|
||||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x22,
|
|
||||||
0x15, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65,
|
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
|
||||||
0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
|
||||||
0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61,
|
|
||||||
0x67, 0x22, 0x18, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4f, 0x75, 0x74, 0x62, 0x6f,
|
|
||||||
0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x68, 0x0a, 0x14, 0x41,
|
|
||||||
0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,
|
|
||||||
0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x3e, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
|
0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x18, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4f,
|
||||||
0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79,
|
0x68, 0x0a, 0x14, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,
|
||||||
0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72,
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01,
|
||||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x17, 0x0a, 0x15, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x3e, 0x0a, 0x09, 0x6f, 0x70, 0x65,
|
||||||
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16,
|
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78,
|
||||||
0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52,
|
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61,
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x57, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75,
|
0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09,
|
||||||
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x17, 0x0a, 0x15, 0x41, 0x6c, 0x74,
|
||||||
0x3e, 0x0a, 0x09, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03,
|
0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||||
0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x4f,
|
0x73, 0x65, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0xc5, 0x07, 0x0a,
|
||||||
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f,
|
0x0e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x22,
|
0x6b, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2c, 0x2e,
|
||||||
0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0xae, 0x09, 0x0a, 0x0e, 0x48, 0x61,
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
|
||||||
0x6e, 0x64, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6b, 0x0a, 0x0a,
|
0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62,
|
||||||
0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2c, 0x2e, 0x78, 0x72, 0x61,
|
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x78, 0x72,
|
||||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63,
|
|
||||||
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
|
|
||||||
0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
|
||||||
0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
|
|
||||||
0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52,
|
|
||||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x74, 0x0a, 0x0d, 0x52, 0x65, 0x6d,
|
|
||||||
0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2f, 0x2e, 0x78, 0x72, 0x61,
|
|
||||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63,
|
|
||||||
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62,
|
|
||||||
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x78, 0x72,
|
|
||||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e,
|
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e,
|
||||||
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e,
|
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75,
|
||||||
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
|
0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x74, 0x0a, 0x0d,
|
||||||
0x71, 0x0a, 0x0c, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12,
|
0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2f, 0x2e,
|
||||||
0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
|
||||||
0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x6c, 0x74, 0x65,
|
0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
||||||
0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30,
|
||||||
0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d,
|
||||||
0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x6c, 0x74, 0x65,
|
0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76,
|
||||||
0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||||
0x22, 0x00, 0x12, 0x71, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
|
0x22, 0x00, 0x12, 0x71, 0x0a, 0x0c, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75,
|
||||||
0x64, 0x73, 0x12, 0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
|
0x6e, 0x64, 0x12, 0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
|
||||||
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4c,
|
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41,
|
||||||
0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||||
0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
|
0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
|
||||||
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4c,
|
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41,
|
||||||
0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x78, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f,
|
0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x78, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f,
|
||||||
0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
|
0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
@@ -1118,22 +924,14 @@ var file_app_proxyman_command_command_proto_rawDesc = []byte{
|
|||||||
0x1a, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
0x1a, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
||||||
0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x6c, 0x74,
|
0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x6c, 0x74,
|
||||||
0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||||
0x73, 0x65, 0x22, 0x00, 0x12, 0x74, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x62,
|
0x73, 0x65, 0x22, 0x00, 0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
0x6f, 0x75, 0x6e, 0x64, 0x73, 0x12, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f,
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||||
0x64, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52,
|
0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f,
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f,
|
||||||
0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x19, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41,
|
||||||
0x6e, 0x64, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73,
|
0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,
|
||||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f,
|
0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
|
||||||
0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2e, 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, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x19,
|
|
||||||
0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
|
|
||||||
0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
|
||||||
0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -1148,7 +946,7 @@ func file_app_proxyman_command_command_proto_rawDescGZIP() []byte {
|
|||||||
return file_app_proxyman_command_command_proto_rawDescData
|
return file_app_proxyman_command_command_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_app_proxyman_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 22)
|
var file_app_proxyman_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 18)
|
||||||
var file_app_proxyman_command_command_proto_goTypes = []any{
|
var file_app_proxyman_command_command_proto_goTypes = []any{
|
||||||
(*AddUserOperation)(nil), // 0: xray.app.proxyman.command.AddUserOperation
|
(*AddUserOperation)(nil), // 0: xray.app.proxyman.command.AddUserOperation
|
||||||
(*RemoveUserOperation)(nil), // 1: xray.app.proxyman.command.RemoveUserOperation
|
(*RemoveUserOperation)(nil), // 1: xray.app.proxyman.command.RemoveUserOperation
|
||||||
@@ -1158,59 +956,49 @@ var file_app_proxyman_command_command_proto_goTypes = []any{
|
|||||||
(*RemoveInboundResponse)(nil), // 5: xray.app.proxyman.command.RemoveInboundResponse
|
(*RemoveInboundResponse)(nil), // 5: xray.app.proxyman.command.RemoveInboundResponse
|
||||||
(*AlterInboundRequest)(nil), // 6: xray.app.proxyman.command.AlterInboundRequest
|
(*AlterInboundRequest)(nil), // 6: xray.app.proxyman.command.AlterInboundRequest
|
||||||
(*AlterInboundResponse)(nil), // 7: xray.app.proxyman.command.AlterInboundResponse
|
(*AlterInboundResponse)(nil), // 7: xray.app.proxyman.command.AlterInboundResponse
|
||||||
(*ListInboundsRequest)(nil), // 8: xray.app.proxyman.command.ListInboundsRequest
|
(*GetInboundUserRequest)(nil), // 8: xray.app.proxyman.command.GetInboundUserRequest
|
||||||
(*ListInboundsResponse)(nil), // 9: xray.app.proxyman.command.ListInboundsResponse
|
(*GetInboundUserResponse)(nil), // 9: xray.app.proxyman.command.GetInboundUserResponse
|
||||||
(*GetInboundUserRequest)(nil), // 10: xray.app.proxyman.command.GetInboundUserRequest
|
(*GetInboundUsersCountResponse)(nil), // 10: xray.app.proxyman.command.GetInboundUsersCountResponse
|
||||||
(*GetInboundUserResponse)(nil), // 11: xray.app.proxyman.command.GetInboundUserResponse
|
(*AddOutboundRequest)(nil), // 11: xray.app.proxyman.command.AddOutboundRequest
|
||||||
(*GetInboundUsersCountResponse)(nil), // 12: xray.app.proxyman.command.GetInboundUsersCountResponse
|
(*AddOutboundResponse)(nil), // 12: xray.app.proxyman.command.AddOutboundResponse
|
||||||
(*AddOutboundRequest)(nil), // 13: xray.app.proxyman.command.AddOutboundRequest
|
(*RemoveOutboundRequest)(nil), // 13: xray.app.proxyman.command.RemoveOutboundRequest
|
||||||
(*AddOutboundResponse)(nil), // 14: xray.app.proxyman.command.AddOutboundResponse
|
(*RemoveOutboundResponse)(nil), // 14: xray.app.proxyman.command.RemoveOutboundResponse
|
||||||
(*RemoveOutboundRequest)(nil), // 15: xray.app.proxyman.command.RemoveOutboundRequest
|
(*AlterOutboundRequest)(nil), // 15: xray.app.proxyman.command.AlterOutboundRequest
|
||||||
(*RemoveOutboundResponse)(nil), // 16: xray.app.proxyman.command.RemoveOutboundResponse
|
(*AlterOutboundResponse)(nil), // 16: xray.app.proxyman.command.AlterOutboundResponse
|
||||||
(*AlterOutboundRequest)(nil), // 17: xray.app.proxyman.command.AlterOutboundRequest
|
(*Config)(nil), // 17: xray.app.proxyman.command.Config
|
||||||
(*AlterOutboundResponse)(nil), // 18: xray.app.proxyman.command.AlterOutboundResponse
|
(*protocol.User)(nil), // 18: xray.common.protocol.User
|
||||||
(*ListOutboundsRequest)(nil), // 19: xray.app.proxyman.command.ListOutboundsRequest
|
(*core.InboundHandlerConfig)(nil), // 19: xray.core.InboundHandlerConfig
|
||||||
(*ListOutboundsResponse)(nil), // 20: xray.app.proxyman.command.ListOutboundsResponse
|
(*serial.TypedMessage)(nil), // 20: xray.common.serial.TypedMessage
|
||||||
(*Config)(nil), // 21: xray.app.proxyman.command.Config
|
(*core.OutboundHandlerConfig)(nil), // 21: xray.core.OutboundHandlerConfig
|
||||||
(*protocol.User)(nil), // 22: xray.common.protocol.User
|
|
||||||
(*core.InboundHandlerConfig)(nil), // 23: xray.core.InboundHandlerConfig
|
|
||||||
(*serial.TypedMessage)(nil), // 24: xray.common.serial.TypedMessage
|
|
||||||
(*core.OutboundHandlerConfig)(nil), // 25: xray.core.OutboundHandlerConfig
|
|
||||||
}
|
}
|
||||||
var file_app_proxyman_command_command_proto_depIdxs = []int32{
|
var file_app_proxyman_command_command_proto_depIdxs = []int32{
|
||||||
22, // 0: xray.app.proxyman.command.AddUserOperation.user:type_name -> xray.common.protocol.User
|
18, // 0: xray.app.proxyman.command.AddUserOperation.user:type_name -> xray.common.protocol.User
|
||||||
23, // 1: xray.app.proxyman.command.AddInboundRequest.inbound:type_name -> xray.core.InboundHandlerConfig
|
19, // 1: xray.app.proxyman.command.AddInboundRequest.inbound:type_name -> xray.core.InboundHandlerConfig
|
||||||
24, // 2: xray.app.proxyman.command.AlterInboundRequest.operation:type_name -> xray.common.serial.TypedMessage
|
20, // 2: xray.app.proxyman.command.AlterInboundRequest.operation:type_name -> xray.common.serial.TypedMessage
|
||||||
23, // 3: xray.app.proxyman.command.ListInboundsResponse.inbounds:type_name -> xray.core.InboundHandlerConfig
|
18, // 3: xray.app.proxyman.command.GetInboundUserResponse.users:type_name -> xray.common.protocol.User
|
||||||
22, // 4: xray.app.proxyman.command.GetInboundUserResponse.users:type_name -> xray.common.protocol.User
|
21, // 4: xray.app.proxyman.command.AddOutboundRequest.outbound:type_name -> xray.core.OutboundHandlerConfig
|
||||||
25, // 5: xray.app.proxyman.command.AddOutboundRequest.outbound:type_name -> xray.core.OutboundHandlerConfig
|
20, // 5: xray.app.proxyman.command.AlterOutboundRequest.operation:type_name -> xray.common.serial.TypedMessage
|
||||||
24, // 6: xray.app.proxyman.command.AlterOutboundRequest.operation:type_name -> xray.common.serial.TypedMessage
|
2, // 6: xray.app.proxyman.command.HandlerService.AddInbound:input_type -> xray.app.proxyman.command.AddInboundRequest
|
||||||
25, // 7: xray.app.proxyman.command.ListOutboundsResponse.outbounds:type_name -> xray.core.OutboundHandlerConfig
|
4, // 7: xray.app.proxyman.command.HandlerService.RemoveInbound:input_type -> xray.app.proxyman.command.RemoveInboundRequest
|
||||||
2, // 8: xray.app.proxyman.command.HandlerService.AddInbound:input_type -> xray.app.proxyman.command.AddInboundRequest
|
6, // 8: xray.app.proxyman.command.HandlerService.AlterInbound:input_type -> xray.app.proxyman.command.AlterInboundRequest
|
||||||
4, // 9: xray.app.proxyman.command.HandlerService.RemoveInbound:input_type -> xray.app.proxyman.command.RemoveInboundRequest
|
8, // 9: xray.app.proxyman.command.HandlerService.GetInboundUsers:input_type -> xray.app.proxyman.command.GetInboundUserRequest
|
||||||
6, // 10: xray.app.proxyman.command.HandlerService.AlterInbound:input_type -> xray.app.proxyman.command.AlterInboundRequest
|
8, // 10: xray.app.proxyman.command.HandlerService.GetInboundUsersCount:input_type -> xray.app.proxyman.command.GetInboundUserRequest
|
||||||
8, // 11: xray.app.proxyman.command.HandlerService.ListInbounds:input_type -> xray.app.proxyman.command.ListInboundsRequest
|
11, // 11: xray.app.proxyman.command.HandlerService.AddOutbound:input_type -> xray.app.proxyman.command.AddOutboundRequest
|
||||||
10, // 12: xray.app.proxyman.command.HandlerService.GetInboundUsers:input_type -> xray.app.proxyman.command.GetInboundUserRequest
|
13, // 12: xray.app.proxyman.command.HandlerService.RemoveOutbound:input_type -> xray.app.proxyman.command.RemoveOutboundRequest
|
||||||
10, // 13: xray.app.proxyman.command.HandlerService.GetInboundUsersCount:input_type -> xray.app.proxyman.command.GetInboundUserRequest
|
15, // 13: xray.app.proxyman.command.HandlerService.AlterOutbound:input_type -> xray.app.proxyman.command.AlterOutboundRequest
|
||||||
13, // 14: xray.app.proxyman.command.HandlerService.AddOutbound:input_type -> xray.app.proxyman.command.AddOutboundRequest
|
3, // 14: xray.app.proxyman.command.HandlerService.AddInbound:output_type -> xray.app.proxyman.command.AddInboundResponse
|
||||||
15, // 15: xray.app.proxyman.command.HandlerService.RemoveOutbound:input_type -> xray.app.proxyman.command.RemoveOutboundRequest
|
5, // 15: xray.app.proxyman.command.HandlerService.RemoveInbound:output_type -> xray.app.proxyman.command.RemoveInboundResponse
|
||||||
17, // 16: xray.app.proxyman.command.HandlerService.AlterOutbound:input_type -> xray.app.proxyman.command.AlterOutboundRequest
|
7, // 16: xray.app.proxyman.command.HandlerService.AlterInbound:output_type -> xray.app.proxyman.command.AlterInboundResponse
|
||||||
19, // 17: xray.app.proxyman.command.HandlerService.ListOutbounds:input_type -> xray.app.proxyman.command.ListOutboundsRequest
|
9, // 17: xray.app.proxyman.command.HandlerService.GetInboundUsers:output_type -> xray.app.proxyman.command.GetInboundUserResponse
|
||||||
3, // 18: xray.app.proxyman.command.HandlerService.AddInbound:output_type -> xray.app.proxyman.command.AddInboundResponse
|
10, // 18: xray.app.proxyman.command.HandlerService.GetInboundUsersCount:output_type -> xray.app.proxyman.command.GetInboundUsersCountResponse
|
||||||
5, // 19: xray.app.proxyman.command.HandlerService.RemoveInbound:output_type -> xray.app.proxyman.command.RemoveInboundResponse
|
12, // 19: xray.app.proxyman.command.HandlerService.AddOutbound:output_type -> xray.app.proxyman.command.AddOutboundResponse
|
||||||
7, // 20: xray.app.proxyman.command.HandlerService.AlterInbound:output_type -> xray.app.proxyman.command.AlterInboundResponse
|
14, // 20: xray.app.proxyman.command.HandlerService.RemoveOutbound:output_type -> xray.app.proxyman.command.RemoveOutboundResponse
|
||||||
9, // 21: xray.app.proxyman.command.HandlerService.ListInbounds:output_type -> xray.app.proxyman.command.ListInboundsResponse
|
16, // 21: xray.app.proxyman.command.HandlerService.AlterOutbound:output_type -> xray.app.proxyman.command.AlterOutboundResponse
|
||||||
11, // 22: xray.app.proxyman.command.HandlerService.GetInboundUsers:output_type -> xray.app.proxyman.command.GetInboundUserResponse
|
14, // [14:22] is the sub-list for method output_type
|
||||||
12, // 23: xray.app.proxyman.command.HandlerService.GetInboundUsersCount:output_type -> xray.app.proxyman.command.GetInboundUsersCountResponse
|
6, // [6:14] is the sub-list for method input_type
|
||||||
14, // 24: xray.app.proxyman.command.HandlerService.AddOutbound:output_type -> xray.app.proxyman.command.AddOutboundResponse
|
6, // [6:6] is the sub-list for extension type_name
|
||||||
16, // 25: xray.app.proxyman.command.HandlerService.RemoveOutbound:output_type -> xray.app.proxyman.command.RemoveOutboundResponse
|
6, // [6:6] is the sub-list for extension extendee
|
||||||
18, // 26: xray.app.proxyman.command.HandlerService.AlterOutbound:output_type -> xray.app.proxyman.command.AlterOutboundResponse
|
0, // [0:6] is the sub-list for field type_name
|
||||||
20, // 27: xray.app.proxyman.command.HandlerService.ListOutbounds:output_type -> xray.app.proxyman.command.ListOutboundsResponse
|
|
||||||
18, // [18:28] is the sub-list for method output_type
|
|
||||||
8, // [8:18] is the sub-list for method input_type
|
|
||||||
8, // [8:8] is the sub-list for extension type_name
|
|
||||||
8, // [8:8] is the sub-list for extension extendee
|
|
||||||
0, // [0:8] is the sub-list for field type_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_proxyman_command_command_proto_init() }
|
func init() { file_app_proxyman_command_command_proto_init() }
|
||||||
@@ -1224,7 +1012,7 @@ func file_app_proxyman_command_command_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_app_proxyman_command_command_proto_rawDesc,
|
RawDescriptor: file_app_proxyman_command_command_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 22,
|
NumMessages: 18,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -37,14 +37,6 @@ message AlterInboundRequest {
|
|||||||
|
|
||||||
message AlterInboundResponse {}
|
message AlterInboundResponse {}
|
||||||
|
|
||||||
message ListInboundsRequest {
|
|
||||||
bool isOnlyTags = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ListInboundsResponse {
|
|
||||||
repeated core.InboundHandlerConfig inbounds = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message GetInboundUserRequest {
|
message GetInboundUserRequest {
|
||||||
string tag = 1;
|
string tag = 1;
|
||||||
string email = 2;
|
string email = 2;
|
||||||
@@ -77,12 +69,6 @@ message AlterOutboundRequest {
|
|||||||
|
|
||||||
message AlterOutboundResponse {}
|
message AlterOutboundResponse {}
|
||||||
|
|
||||||
message ListOutboundsRequest {}
|
|
||||||
|
|
||||||
message ListOutboundsResponse {
|
|
||||||
repeated core.OutboundHandlerConfig outbounds = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
service HandlerService {
|
service HandlerService {
|
||||||
rpc AddInbound(AddInboundRequest) returns (AddInboundResponse) {}
|
rpc AddInbound(AddInboundRequest) returns (AddInboundResponse) {}
|
||||||
|
|
||||||
@@ -90,8 +76,6 @@ service HandlerService {
|
|||||||
|
|
||||||
rpc AlterInbound(AlterInboundRequest) returns (AlterInboundResponse) {}
|
rpc AlterInbound(AlterInboundRequest) returns (AlterInboundResponse) {}
|
||||||
|
|
||||||
rpc ListInbounds(ListInboundsRequest) returns (ListInboundsResponse) {}
|
|
||||||
|
|
||||||
rpc GetInboundUsers(GetInboundUserRequest) returns (GetInboundUserResponse) {}
|
rpc GetInboundUsers(GetInboundUserRequest) returns (GetInboundUserResponse) {}
|
||||||
|
|
||||||
rpc GetInboundUsersCount(GetInboundUserRequest) returns (GetInboundUsersCountResponse) {}
|
rpc GetInboundUsersCount(GetInboundUserRequest) returns (GetInboundUsersCountResponse) {}
|
||||||
@@ -101,8 +85,6 @@ service HandlerService {
|
|||||||
rpc RemoveOutbound(RemoveOutboundRequest) returns (RemoveOutboundResponse) {}
|
rpc RemoveOutbound(RemoveOutboundRequest) returns (RemoveOutboundResponse) {}
|
||||||
|
|
||||||
rpc AlterOutbound(AlterOutboundRequest) returns (AlterOutboundResponse) {}
|
rpc AlterOutbound(AlterOutboundRequest) returns (AlterOutboundResponse) {}
|
||||||
|
|
||||||
rpc ListOutbounds(ListOutboundsRequest) returns (ListOutboundsResponse) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message Config {}
|
message Config {}
|
||||||
|
|||||||
@@ -22,13 +22,11 @@ const (
|
|||||||
HandlerService_AddInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AddInbound"
|
HandlerService_AddInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AddInbound"
|
||||||
HandlerService_RemoveInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/RemoveInbound"
|
HandlerService_RemoveInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/RemoveInbound"
|
||||||
HandlerService_AlterInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AlterInbound"
|
HandlerService_AlterInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AlterInbound"
|
||||||
HandlerService_ListInbounds_FullMethodName = "/xray.app.proxyman.command.HandlerService/ListInbounds"
|
|
||||||
HandlerService_GetInboundUsers_FullMethodName = "/xray.app.proxyman.command.HandlerService/GetInboundUsers"
|
HandlerService_GetInboundUsers_FullMethodName = "/xray.app.proxyman.command.HandlerService/GetInboundUsers"
|
||||||
HandlerService_GetInboundUsersCount_FullMethodName = "/xray.app.proxyman.command.HandlerService/GetInboundUsersCount"
|
HandlerService_GetInboundUsersCount_FullMethodName = "/xray.app.proxyman.command.HandlerService/GetInboundUsersCount"
|
||||||
HandlerService_AddOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AddOutbound"
|
HandlerService_AddOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AddOutbound"
|
||||||
HandlerService_RemoveOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/RemoveOutbound"
|
HandlerService_RemoveOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/RemoveOutbound"
|
||||||
HandlerService_AlterOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AlterOutbound"
|
HandlerService_AlterOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AlterOutbound"
|
||||||
HandlerService_ListOutbounds_FullMethodName = "/xray.app.proxyman.command.HandlerService/ListOutbounds"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandlerServiceClient is the client API for HandlerService service.
|
// HandlerServiceClient is the client API for HandlerService service.
|
||||||
@@ -38,13 +36,11 @@ type HandlerServiceClient interface {
|
|||||||
AddInbound(ctx context.Context, in *AddInboundRequest, opts ...grpc.CallOption) (*AddInboundResponse, error)
|
AddInbound(ctx context.Context, in *AddInboundRequest, opts ...grpc.CallOption) (*AddInboundResponse, error)
|
||||||
RemoveInbound(ctx context.Context, in *RemoveInboundRequest, opts ...grpc.CallOption) (*RemoveInboundResponse, error)
|
RemoveInbound(ctx context.Context, in *RemoveInboundRequest, opts ...grpc.CallOption) (*RemoveInboundResponse, error)
|
||||||
AlterInbound(ctx context.Context, in *AlterInboundRequest, opts ...grpc.CallOption) (*AlterInboundResponse, error)
|
AlterInbound(ctx context.Context, in *AlterInboundRequest, opts ...grpc.CallOption) (*AlterInboundResponse, error)
|
||||||
ListInbounds(ctx context.Context, in *ListInboundsRequest, opts ...grpc.CallOption) (*ListInboundsResponse, error)
|
|
||||||
GetInboundUsers(ctx context.Context, in *GetInboundUserRequest, opts ...grpc.CallOption) (*GetInboundUserResponse, error)
|
GetInboundUsers(ctx context.Context, in *GetInboundUserRequest, opts ...grpc.CallOption) (*GetInboundUserResponse, error)
|
||||||
GetInboundUsersCount(ctx context.Context, in *GetInboundUserRequest, opts ...grpc.CallOption) (*GetInboundUsersCountResponse, error)
|
GetInboundUsersCount(ctx context.Context, in *GetInboundUserRequest, opts ...grpc.CallOption) (*GetInboundUsersCountResponse, error)
|
||||||
AddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error)
|
AddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error)
|
||||||
RemoveOutbound(ctx context.Context, in *RemoveOutboundRequest, opts ...grpc.CallOption) (*RemoveOutboundResponse, error)
|
RemoveOutbound(ctx context.Context, in *RemoveOutboundRequest, opts ...grpc.CallOption) (*RemoveOutboundResponse, error)
|
||||||
AlterOutbound(ctx context.Context, in *AlterOutboundRequest, opts ...grpc.CallOption) (*AlterOutboundResponse, error)
|
AlterOutbound(ctx context.Context, in *AlterOutboundRequest, opts ...grpc.CallOption) (*AlterOutboundResponse, error)
|
||||||
ListOutbounds(ctx context.Context, in *ListOutboundsRequest, opts ...grpc.CallOption) (*ListOutboundsResponse, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type handlerServiceClient struct {
|
type handlerServiceClient struct {
|
||||||
@@ -85,16 +81,6 @@ func (c *handlerServiceClient) AlterInbound(ctx context.Context, in *AlterInboun
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *handlerServiceClient) ListInbounds(ctx context.Context, in *ListInboundsRequest, opts ...grpc.CallOption) (*ListInboundsResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(ListInboundsResponse)
|
|
||||||
err := c.cc.Invoke(ctx, HandlerService_ListInbounds_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *handlerServiceClient) GetInboundUsers(ctx context.Context, in *GetInboundUserRequest, opts ...grpc.CallOption) (*GetInboundUserResponse, error) {
|
func (c *handlerServiceClient) GetInboundUsers(ctx context.Context, in *GetInboundUserRequest, opts ...grpc.CallOption) (*GetInboundUserResponse, error) {
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
out := new(GetInboundUserResponse)
|
out := new(GetInboundUserResponse)
|
||||||
@@ -145,16 +131,6 @@ func (c *handlerServiceClient) AlterOutbound(ctx context.Context, in *AlterOutbo
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *handlerServiceClient) ListOutbounds(ctx context.Context, in *ListOutboundsRequest, opts ...grpc.CallOption) (*ListOutboundsResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(ListOutboundsResponse)
|
|
||||||
err := c.cc.Invoke(ctx, HandlerService_ListOutbounds_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlerServiceServer is the server API for HandlerService service.
|
// HandlerServiceServer is the server API for HandlerService service.
|
||||||
// All implementations must embed UnimplementedHandlerServiceServer
|
// All implementations must embed UnimplementedHandlerServiceServer
|
||||||
// for forward compatibility.
|
// for forward compatibility.
|
||||||
@@ -162,13 +138,11 @@ type HandlerServiceServer interface {
|
|||||||
AddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error)
|
AddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error)
|
||||||
RemoveInbound(context.Context, *RemoveInboundRequest) (*RemoveInboundResponse, error)
|
RemoveInbound(context.Context, *RemoveInboundRequest) (*RemoveInboundResponse, error)
|
||||||
AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error)
|
AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error)
|
||||||
ListInbounds(context.Context, *ListInboundsRequest) (*ListInboundsResponse, error)
|
|
||||||
GetInboundUsers(context.Context, *GetInboundUserRequest) (*GetInboundUserResponse, error)
|
GetInboundUsers(context.Context, *GetInboundUserRequest) (*GetInboundUserResponse, error)
|
||||||
GetInboundUsersCount(context.Context, *GetInboundUserRequest) (*GetInboundUsersCountResponse, error)
|
GetInboundUsersCount(context.Context, *GetInboundUserRequest) (*GetInboundUsersCountResponse, error)
|
||||||
AddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error)
|
AddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error)
|
||||||
RemoveOutbound(context.Context, *RemoveOutboundRequest) (*RemoveOutboundResponse, error)
|
RemoveOutbound(context.Context, *RemoveOutboundRequest) (*RemoveOutboundResponse, error)
|
||||||
AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error)
|
AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error)
|
||||||
ListOutbounds(context.Context, *ListOutboundsRequest) (*ListOutboundsResponse, error)
|
|
||||||
mustEmbedUnimplementedHandlerServiceServer()
|
mustEmbedUnimplementedHandlerServiceServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,9 +162,6 @@ func (UnimplementedHandlerServiceServer) RemoveInbound(context.Context, *RemoveI
|
|||||||
func (UnimplementedHandlerServiceServer) AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error) {
|
func (UnimplementedHandlerServiceServer) AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method AlterInbound not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method AlterInbound not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHandlerServiceServer) ListInbounds(context.Context, *ListInboundsRequest) (*ListInboundsResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method ListInbounds not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedHandlerServiceServer) GetInboundUsers(context.Context, *GetInboundUserRequest) (*GetInboundUserResponse, error) {
|
func (UnimplementedHandlerServiceServer) GetInboundUsers(context.Context, *GetInboundUserRequest) (*GetInboundUserResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetInboundUsers not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetInboundUsers not implemented")
|
||||||
}
|
}
|
||||||
@@ -206,9 +177,6 @@ func (UnimplementedHandlerServiceServer) RemoveOutbound(context.Context, *Remove
|
|||||||
func (UnimplementedHandlerServiceServer) AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error) {
|
func (UnimplementedHandlerServiceServer) AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method AlterOutbound not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method AlterOutbound not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHandlerServiceServer) ListOutbounds(context.Context, *ListOutboundsRequest) (*ListOutboundsResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method ListOutbounds not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedHandlerServiceServer) mustEmbedUnimplementedHandlerServiceServer() {}
|
func (UnimplementedHandlerServiceServer) mustEmbedUnimplementedHandlerServiceServer() {}
|
||||||
func (UnimplementedHandlerServiceServer) testEmbeddedByValue() {}
|
func (UnimplementedHandlerServiceServer) testEmbeddedByValue() {}
|
||||||
|
|
||||||
@@ -284,24 +252,6 @@ func _HandlerService_AlterInbound_Handler(srv interface{}, ctx context.Context,
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _HandlerService_ListInbounds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(ListInboundsRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(HandlerServiceServer).ListInbounds(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: HandlerService_ListInbounds_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(HandlerServiceServer).ListInbounds(ctx, req.(*ListInboundsRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _HandlerService_GetInboundUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _HandlerService_GetInboundUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(GetInboundUserRequest)
|
in := new(GetInboundUserRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
@@ -392,24 +342,6 @@ func _HandlerService_AlterOutbound_Handler(srv interface{}, ctx context.Context,
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _HandlerService_ListOutbounds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(ListOutboundsRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(HandlerServiceServer).ListOutbounds(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: HandlerService_ListOutbounds_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(HandlerServiceServer).ListOutbounds(ctx, req.(*ListOutboundsRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlerService_ServiceDesc is the grpc.ServiceDesc for HandlerService service.
|
// HandlerService_ServiceDesc is the grpc.ServiceDesc for HandlerService 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)
|
||||||
@@ -429,10 +361,6 @@ var HandlerService_ServiceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "AlterInbound",
|
MethodName: "AlterInbound",
|
||||||
Handler: _HandlerService_AlterInbound_Handler,
|
Handler: _HandlerService_AlterInbound_Handler,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
MethodName: "ListInbounds",
|
|
||||||
Handler: _HandlerService_ListInbounds_Handler,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
MethodName: "GetInboundUsers",
|
MethodName: "GetInboundUsers",
|
||||||
Handler: _HandlerService_GetInboundUsers_Handler,
|
Handler: _HandlerService_GetInboundUsers_Handler,
|
||||||
@@ -453,10 +381,6 @@ var HandlerService_ServiceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "AlterOutbound",
|
MethodName: "AlterOutbound",
|
||||||
Handler: _HandlerService_AlterOutbound_Handler,
|
Handler: _HandlerService_AlterOutbound_Handler,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
MethodName: "ListOutbounds",
|
|
||||||
Handler: _HandlerService_ListOutbounds_Handler,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{},
|
Streams: []grpc.StreamDesc{},
|
||||||
Metadata: "app/proxyman/command/command.proto",
|
Metadata: "app/proxyman/command/command.proto",
|
||||||
|
|||||||
@@ -1 +1,23 @@
|
|||||||
package proxyman
|
package proxyman
|
||||||
|
|
||||||
|
func (s *AllocationStrategy) GetConcurrencyValue() uint32 {
|
||||||
|
if s == nil || s.Concurrency == nil {
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
return s.Concurrency.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AllocationStrategy) GetRefreshValue() uint32 {
|
||||||
|
if s == nil || s.Refresh == nil {
|
||||||
|
return 5
|
||||||
|
}
|
||||||
|
return s.Refresh.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ReceiverConfig) GetEffectiveSniffingSettings() *SniffingConfig {
|
||||||
|
if c.SniffingSettings != nil {
|
||||||
|
return c.SniffingSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,58 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type AllocationStrategy_Type int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Always allocate all connection handlers.
|
||||||
|
AllocationStrategy_Always AllocationStrategy_Type = 0
|
||||||
|
// Randomly allocate specific range of handlers.
|
||||||
|
AllocationStrategy_Random AllocationStrategy_Type = 1
|
||||||
|
// External. Not supported yet.
|
||||||
|
AllocationStrategy_External AllocationStrategy_Type = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for AllocationStrategy_Type.
|
||||||
|
var (
|
||||||
|
AllocationStrategy_Type_name = map[int32]string{
|
||||||
|
0: "Always",
|
||||||
|
1: "Random",
|
||||||
|
2: "External",
|
||||||
|
}
|
||||||
|
AllocationStrategy_Type_value = map[string]int32{
|
||||||
|
"Always": 0,
|
||||||
|
"Random": 1,
|
||||||
|
"External": 2,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x AllocationStrategy_Type) Enum() *AllocationStrategy_Type {
|
||||||
|
p := new(AllocationStrategy_Type)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x AllocationStrategy_Type) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (AllocationStrategy_Type) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_app_proxyman_config_proto_enumTypes[0].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (AllocationStrategy_Type) Type() protoreflect.EnumType {
|
||||||
|
return &file_app_proxyman_config_proto_enumTypes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x AllocationStrategy_Type) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use AllocationStrategy_Type.Descriptor instead.
|
||||||
|
func (AllocationStrategy_Type) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 0}
|
||||||
|
}
|
||||||
|
|
||||||
type InboundConfig struct {
|
type InboundConfig struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -59,6 +111,71 @@ func (*InboundConfig) Descriptor() ([]byte, []int) {
|
|||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{0}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AllocationStrategy struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Type AllocationStrategy_Type `protobuf:"varint,1,opt,name=type,proto3,enum=xray.app.proxyman.AllocationStrategy_Type" json:"type,omitempty"`
|
||||||
|
// Number of handlers (ports) running in parallel.
|
||||||
|
// Default value is 3 if unset.
|
||||||
|
Concurrency *AllocationStrategy_AllocationStrategyConcurrency `protobuf:"bytes,2,opt,name=concurrency,proto3" json:"concurrency,omitempty"`
|
||||||
|
// Number of minutes before a handler is regenerated.
|
||||||
|
// Default value is 5 if unset.
|
||||||
|
Refresh *AllocationStrategy_AllocationStrategyRefresh `protobuf:"bytes,3,opt,name=refresh,proto3" json:"refresh,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) Reset() {
|
||||||
|
*x = AllocationStrategy{}
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*AllocationStrategy) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use AllocationStrategy.ProtoReflect.Descriptor instead.
|
||||||
|
func (*AllocationStrategy) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) GetType() AllocationStrategy_Type {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return AllocationStrategy_Always
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) GetConcurrency() *AllocationStrategy_AllocationStrategyConcurrency {
|
||||||
|
if x != nil {
|
||||||
|
return x.Concurrency
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) GetRefresh() *AllocationStrategy_AllocationStrategyRefresh {
|
||||||
|
if x != nil {
|
||||||
|
return x.Refresh
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type SniffingConfig struct {
|
type SniffingConfig struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -73,13 +190,14 @@ type SniffingConfig struct {
|
|||||||
// 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"`
|
||||||
|
Timeout int64 `protobuf:"varint,6,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SniffingConfig) Reset() {
|
func (x *SniffingConfig) Reset() {
|
||||||
*x = SniffingConfig{}
|
*x = SniffingConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -91,7 +209,7 @@ func (x *SniffingConfig) String() string {
|
|||||||
func (*SniffingConfig) ProtoMessage() {}
|
func (*SniffingConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *SniffingConfig) ProtoReflect() protoreflect.Message {
|
func (x *SniffingConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -104,7 +222,7 @@ func (x *SniffingConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use SniffingConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use SniffingConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*SniffingConfig) Descriptor() ([]byte, []int) {
|
func (*SniffingConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SniffingConfig) GetEnabled() bool {
|
func (x *SniffingConfig) GetEnabled() bool {
|
||||||
@@ -142,6 +260,13 @@ func (x *SniffingConfig) GetRouteOnly() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *SniffingConfig) GetTimeout() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Timeout
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
type ReceiverConfig struct {
|
type ReceiverConfig struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -151,14 +276,15 @@ type ReceiverConfig struct {
|
|||||||
PortList *net.PortList `protobuf:"bytes,1,opt,name=port_list,json=portList,proto3" json:"port_list,omitempty"`
|
PortList *net.PortList `protobuf:"bytes,1,opt,name=port_list,json=portList,proto3" json:"port_list,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"`
|
||||||
StreamSettings *internet.StreamConfig `protobuf:"bytes,3,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy,proto3" json:"allocation_strategy,omitempty"`
|
||||||
ReceiveOriginalDestination bool `protobuf:"varint,4,opt,name=receive_original_destination,json=receiveOriginalDestination,proto3" json:"receive_original_destination,omitempty"`
|
StreamSettings *internet.StreamConfig `protobuf:"bytes,4,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
||||||
SniffingSettings *SniffingConfig `protobuf:"bytes,6,opt,name=sniffing_settings,json=sniffingSettings,proto3" json:"sniffing_settings,omitempty"`
|
ReceiveOriginalDestination bool `protobuf:"varint,5,opt,name=receive_original_destination,json=receiveOriginalDestination,proto3" json:"receive_original_destination,omitempty"`
|
||||||
|
SniffingSettings *SniffingConfig `protobuf:"bytes,7,opt,name=sniffing_settings,json=sniffingSettings,proto3" json:"sniffing_settings,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReceiverConfig) Reset() {
|
func (x *ReceiverConfig) Reset() {
|
||||||
*x = ReceiverConfig{}
|
*x = ReceiverConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -170,7 +296,7 @@ func (x *ReceiverConfig) String() string {
|
|||||||
func (*ReceiverConfig) ProtoMessage() {}
|
func (*ReceiverConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *ReceiverConfig) ProtoReflect() protoreflect.Message {
|
func (x *ReceiverConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -183,7 +309,7 @@ func (x *ReceiverConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use ReceiverConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use ReceiverConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*ReceiverConfig) Descriptor() ([]byte, []int) {
|
func (*ReceiverConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{2}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{3}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReceiverConfig) GetPortList() *net.PortList {
|
func (x *ReceiverConfig) GetPortList() *net.PortList {
|
||||||
@@ -200,6 +326,13 @@ func (x *ReceiverConfig) GetListen() *net.IPOrDomain {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *ReceiverConfig) GetAllocationStrategy() *AllocationStrategy {
|
||||||
|
if x != nil {
|
||||||
|
return x.AllocationStrategy
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (x *ReceiverConfig) GetStreamSettings() *internet.StreamConfig {
|
func (x *ReceiverConfig) GetStreamSettings() *internet.StreamConfig {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.StreamSettings
|
return x.StreamSettings
|
||||||
@@ -233,7 +366,7 @@ type InboundHandlerConfig struct {
|
|||||||
|
|
||||||
func (x *InboundHandlerConfig) Reset() {
|
func (x *InboundHandlerConfig) Reset() {
|
||||||
*x = InboundHandlerConfig{}
|
*x = InboundHandlerConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -245,7 +378,7 @@ func (x *InboundHandlerConfig) String() string {
|
|||||||
func (*InboundHandlerConfig) ProtoMessage() {}
|
func (*InboundHandlerConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
|
func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -258,7 +391,7 @@ func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use InboundHandlerConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use InboundHandlerConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*InboundHandlerConfig) Descriptor() ([]byte, []int) {
|
func (*InboundHandlerConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{3}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{4}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *InboundHandlerConfig) GetTag() string {
|
func (x *InboundHandlerConfig) GetTag() string {
|
||||||
@@ -290,7 +423,7 @@ type OutboundConfig struct {
|
|||||||
|
|
||||||
func (x *OutboundConfig) Reset() {
|
func (x *OutboundConfig) Reset() {
|
||||||
*x = OutboundConfig{}
|
*x = OutboundConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -302,7 +435,7 @@ func (x *OutboundConfig) String() string {
|
|||||||
func (*OutboundConfig) ProtoMessage() {}
|
func (*OutboundConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *OutboundConfig) ProtoReflect() protoreflect.Message {
|
func (x *OutboundConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -315,7 +448,7 @@ func (x *OutboundConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use OutboundConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use OutboundConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*OutboundConfig) Descriptor() ([]byte, []int) {
|
func (*OutboundConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{4}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{5}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SenderConfig struct {
|
type SenderConfig struct {
|
||||||
@@ -324,17 +457,16 @@ type SenderConfig struct {
|
|||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// Send traffic through the given IP. Only IP is allowed.
|
// Send traffic through the given IP. Only IP is allowed.
|
||||||
Via *net.IPOrDomain `protobuf:"bytes,1,opt,name=via,proto3" json:"via,omitempty"`
|
Via *net.IPOrDomain `protobuf:"bytes,1,opt,name=via,proto3" json:"via,omitempty"`
|
||||||
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"`
|
ViaCidr string `protobuf:"bytes,5,opt,name=via_cidr,json=viaCidr,proto3" json:"via_cidr,omitempty"`
|
||||||
TargetStrategy internet.DomainStrategy `protobuf:"varint,6,opt,name=target_strategy,json=targetStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"target_strategy,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SenderConfig) Reset() {
|
func (x *SenderConfig) Reset() {
|
||||||
*x = SenderConfig{}
|
*x = SenderConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -346,7 +478,7 @@ func (x *SenderConfig) String() string {
|
|||||||
func (*SenderConfig) ProtoMessage() {}
|
func (*SenderConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *SenderConfig) ProtoReflect() protoreflect.Message {
|
func (x *SenderConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -359,7 +491,7 @@ func (x *SenderConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use SenderConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use SenderConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*SenderConfig) Descriptor() ([]byte, []int) {
|
func (*SenderConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{5}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{6}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SenderConfig) GetVia() *net.IPOrDomain {
|
func (x *SenderConfig) GetVia() *net.IPOrDomain {
|
||||||
@@ -397,13 +529,6 @@ func (x *SenderConfig) GetViaCidr() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SenderConfig) GetTargetStrategy() internet.DomainStrategy {
|
|
||||||
if x != nil {
|
|
||||||
return x.TargetStrategy
|
|
||||||
}
|
|
||||||
return internet.DomainStrategy(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
type MultiplexingConfig struct {
|
type MultiplexingConfig struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -421,7 +546,7 @@ type MultiplexingConfig struct {
|
|||||||
|
|
||||||
func (x *MultiplexingConfig) Reset() {
|
func (x *MultiplexingConfig) Reset() {
|
||||||
*x = MultiplexingConfig{}
|
*x = MultiplexingConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
mi := &file_app_proxyman_config_proto_msgTypes[7]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -433,7 +558,7 @@ func (x *MultiplexingConfig) String() string {
|
|||||||
func (*MultiplexingConfig) ProtoMessage() {}
|
func (*MultiplexingConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {
|
func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
mi := &file_app_proxyman_config_proto_msgTypes[7]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -446,7 +571,7 @@ func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use MultiplexingConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use MultiplexingConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*MultiplexingConfig) Descriptor() ([]byte, []int) {
|
func (*MultiplexingConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{6}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{7}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *MultiplexingConfig) GetEnabled() bool {
|
func (x *MultiplexingConfig) GetEnabled() bool {
|
||||||
@@ -477,6 +602,96 @@ func (x *MultiplexingConfig) GetXudpProxyUDP443() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AllocationStrategy_AllocationStrategyConcurrency struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) Reset() {
|
||||||
|
*x = AllocationStrategy_AllocationStrategyConcurrency{}
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[8]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*AllocationStrategy_AllocationStrategyConcurrency) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[8]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use AllocationStrategy_AllocationStrategyConcurrency.ProtoReflect.Descriptor instead.
|
||||||
|
func (*AllocationStrategy_AllocationStrategyConcurrency) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) GetValue() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type AllocationStrategy_AllocationStrategyRefresh struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyRefresh) Reset() {
|
||||||
|
*x = AllocationStrategy_AllocationStrategyRefresh{}
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[9]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyRefresh) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*AllocationStrategy_AllocationStrategyRefresh) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyRefresh) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[9]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use AllocationStrategy_AllocationStrategyRefresh.ProtoReflect.Descriptor instead.
|
||||||
|
func (*AllocationStrategy_AllocationStrategyRefresh) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyRefresh) GetValue() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
var File_app_proxyman_config_proto protoreflect.FileDescriptor
|
var File_app_proxyman_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_app_proxyman_config_proto_rawDesc = []byte{
|
var file_app_proxyman_config_proto_rawDesc = []byte{
|
||||||
@@ -491,98 +706,127 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
|
|||||||
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, 0x0f, 0x0a, 0x0d, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f,
|
0x6f, 0x74, 0x6f, 0x22, 0x0f, 0x0a, 0x0d, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f,
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x22, 0xcc, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e,
|
0x6e, 0x66, 0x69, 0x67, 0x22, 0xae, 0x03, 0x0a, 0x12, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74,
|
||||||
0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c,
|
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x3e, 0x0a, 0x04, 0x74,
|
||||||
0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
|
0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c,
|
||||||
0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
|
0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||||
0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72,
|
0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x65, 0x0a, 0x0b, 0x63,
|
||||||
0x72, 0x69, 0x64, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x5f,
|
0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
|
||||||
0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f,
|
0x32, 0x43, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
||||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x12,
|
0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
|
||||||
0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6f, 0x6e, 0x6c, 0x79,
|
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
||||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
|
0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72,
|
||||||
0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f, 0x6e,
|
0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
|
||||||
0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x4f,
|
0x63, 0x79, 0x12, 0x59, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x18, 0x03, 0x20,
|
||||||
0x6e, 0x6c, 0x79, 0x22, 0xe5, 0x02, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72,
|
0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
|
||||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c,
|
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
||||||
0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63,
|
||||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74,
|
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x65, 0x66,
|
||||||
0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x33,
|
0x72, 0x65, 0x73, 0x68, 0x52, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x1a, 0x35, 0x0a,
|
||||||
0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
|
0x1d, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74,
|
||||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,
|
0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x14,
|
||||||
0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, 0x73,
|
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76,
|
||||||
0x74, 0x65, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65,
|
0x61, 0x6c, 0x75, 0x65, 0x1a, 0x31, 0x0a, 0x19, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
||||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78,
|
0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73,
|
||||||
|
0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
|
||||||
|
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12,
|
||||||
|
0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52,
|
||||||
|
0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72,
|
||||||
|
0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0xe6, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 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, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
|
||||||
|
0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
|
||||||
|
0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65,
|
||||||
|
0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73,
|
||||||
|
0x5f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||||
|
0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64,
|
||||||
|
0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6f, 0x6e, 0x6c,
|
||||||
|
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,
|
||||||
|
0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||||
|
0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18,
|
||||||
|
0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0xbd,
|
||||||
|
0x03, 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, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01,
|
||||||
|
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, 0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73,
|
||||||
|
0x74, 0x65, 0x6e, 0x18, 0x02, 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, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x56,
|
||||||
|
0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72,
|
||||||
|
0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 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,
|
||||||
|
0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||||
|
0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 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, 0x11, 0x73, 0x6e, 0x69, 0x66,
|
||||||
|
0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x07, 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, 0xcb, 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, 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,
|
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,
|
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,
|
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,
|
0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74,
|
||||||
0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
|
0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72,
|
||||||
0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69,
|
0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,
|
||||||
0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e,
|
0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e,
|
0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
||||||
0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,
|
0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65,
|
||||||
0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 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, 0x05, 0x10, 0x06, 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, 0x9d, 0x03, 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, 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, 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, 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, 0x12, 0x50,
|
|
||||||
0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
|
|
||||||
0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 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, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
|
||||||
0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
|
||||||
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, 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,
|
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,
|
0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
|
||||||
0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
|
0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65,
|
||||||
0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61,
|
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x69, 0x61, 0x5f, 0x63, 0x69,
|
||||||
0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06,
|
0x64, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x69, 0x61, 0x43, 0x69, 0x64,
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
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, 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 (
|
||||||
@@ -597,39 +841,46 @@ 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_msgTypes = make([]protoimpl.MessageInfo, 7)
|
var file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
|
var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||||
var file_app_proxyman_config_proto_goTypes = []any{
|
var file_app_proxyman_config_proto_goTypes = []any{
|
||||||
(*InboundConfig)(nil), // 0: xray.app.proxyman.InboundConfig
|
(AllocationStrategy_Type)(0), // 0: xray.app.proxyman.AllocationStrategy.Type
|
||||||
(*SniffingConfig)(nil), // 1: xray.app.proxyman.SniffingConfig
|
(*InboundConfig)(nil), // 1: xray.app.proxyman.InboundConfig
|
||||||
(*ReceiverConfig)(nil), // 2: xray.app.proxyman.ReceiverConfig
|
(*AllocationStrategy)(nil), // 2: xray.app.proxyman.AllocationStrategy
|
||||||
(*InboundHandlerConfig)(nil), // 3: xray.app.proxyman.InboundHandlerConfig
|
(*SniffingConfig)(nil), // 3: xray.app.proxyman.SniffingConfig
|
||||||
(*OutboundConfig)(nil), // 4: xray.app.proxyman.OutboundConfig
|
(*ReceiverConfig)(nil), // 4: xray.app.proxyman.ReceiverConfig
|
||||||
(*SenderConfig)(nil), // 5: xray.app.proxyman.SenderConfig
|
(*InboundHandlerConfig)(nil), // 5: xray.app.proxyman.InboundHandlerConfig
|
||||||
(*MultiplexingConfig)(nil), // 6: xray.app.proxyman.MultiplexingConfig
|
(*OutboundConfig)(nil), // 6: xray.app.proxyman.OutboundConfig
|
||||||
(*net.PortList)(nil), // 7: xray.common.net.PortList
|
(*SenderConfig)(nil), // 7: xray.app.proxyman.SenderConfig
|
||||||
(*net.IPOrDomain)(nil), // 8: xray.common.net.IPOrDomain
|
(*MultiplexingConfig)(nil), // 8: xray.app.proxyman.MultiplexingConfig
|
||||||
(*internet.StreamConfig)(nil), // 9: xray.transport.internet.StreamConfig
|
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 9: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
|
||||||
(*serial.TypedMessage)(nil), // 10: xray.common.serial.TypedMessage
|
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
|
||||||
(*internet.ProxyConfig)(nil), // 11: xray.transport.internet.ProxyConfig
|
(*net.PortList)(nil), // 11: xray.common.net.PortList
|
||||||
(internet.DomainStrategy)(0), // 12: xray.transport.internet.DomainStrategy
|
(*net.IPOrDomain)(nil), // 12: xray.common.net.IPOrDomain
|
||||||
|
(*internet.StreamConfig)(nil), // 13: xray.transport.internet.StreamConfig
|
||||||
|
(*serial.TypedMessage)(nil), // 14: xray.common.serial.TypedMessage
|
||||||
|
(*internet.ProxyConfig)(nil), // 15: xray.transport.internet.ProxyConfig
|
||||||
}
|
}
|
||||||
var file_app_proxyman_config_proto_depIdxs = []int32{
|
var file_app_proxyman_config_proto_depIdxs = []int32{
|
||||||
7, // 0: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList
|
0, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type
|
||||||
8, // 1: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
|
9, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
|
||||||
9, // 2: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
10, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
|
||||||
1, // 3: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
|
11, // 3: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList
|
||||||
10, // 4: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
|
12, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
|
||||||
10, // 5: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
|
2, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy
|
||||||
8, // 6: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
|
13, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||||
9, // 7: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
3, // 7: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
|
||||||
11, // 8: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
|
14, // 8: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
|
||||||
6, // 9: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
14, // 9: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
|
||||||
12, // 10: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy
|
12, // 10: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
|
||||||
11, // [11:11] is the sub-list for method output_type
|
13, // 11: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||||
11, // [11:11] is the sub-list for method input_type
|
15, // 12: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
|
||||||
11, // [11:11] is the sub-list for extension type_name
|
8, // 13: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
||||||
11, // [11:11] is the sub-list for extension extendee
|
14, // [14:14] is the sub-list for method output_type
|
||||||
0, // [0:11] is the sub-list for field type_name
|
14, // [14:14] is the sub-list for method input_type
|
||||||
|
14, // [14:14] is the sub-list for extension type_name
|
||||||
|
14, // [14:14] is the sub-list for extension extendee
|
||||||
|
0, // [0:14] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_proxyman_config_proto_init() }
|
func init() { file_app_proxyman_config_proto_init() }
|
||||||
@@ -642,13 +893,14 @@ 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: 0,
|
NumEnums: 1,
|
||||||
NumMessages: 7,
|
NumMessages: 10,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
GoTypes: file_app_proxyman_config_proto_goTypes,
|
GoTypes: file_app_proxyman_config_proto_goTypes,
|
||||||
DependencyIndexes: file_app_proxyman_config_proto_depIdxs,
|
DependencyIndexes: file_app_proxyman_config_proto_depIdxs,
|
||||||
|
EnumInfos: file_app_proxyman_config_proto_enumTypes,
|
||||||
MessageInfos: file_app_proxyman_config_proto_msgTypes,
|
MessageInfos: file_app_proxyman_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_proxyman_config_proto = out.File
|
File_app_proxyman_config_proto = out.File
|
||||||
|
|||||||
@@ -13,6 +13,33 @@ import "common/serial/typed_message.proto";
|
|||||||
|
|
||||||
message InboundConfig {}
|
message InboundConfig {}
|
||||||
|
|
||||||
|
message AllocationStrategy {
|
||||||
|
enum Type {
|
||||||
|
// Always allocate all connection handlers.
|
||||||
|
Always = 0;
|
||||||
|
|
||||||
|
// Randomly allocate specific range of handlers.
|
||||||
|
Random = 1;
|
||||||
|
|
||||||
|
// External. Not supported yet.
|
||||||
|
External = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type type = 1;
|
||||||
|
|
||||||
|
message AllocationStrategyConcurrency { uint32 value = 1; }
|
||||||
|
|
||||||
|
// Number of handlers (ports) running in parallel.
|
||||||
|
// Default value is 3 if unset.
|
||||||
|
AllocationStrategyConcurrency concurrency = 2;
|
||||||
|
|
||||||
|
message AllocationStrategyRefresh { uint32 value = 1; }
|
||||||
|
|
||||||
|
// Number of minutes before a handler is regenerated.
|
||||||
|
// Default value is 5 if unset.
|
||||||
|
AllocationStrategyRefresh refresh = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message SniffingConfig {
|
message SniffingConfig {
|
||||||
// Whether or not to enable content sniffing on an inbound connection.
|
// Whether or not to enable content sniffing on an inbound connection.
|
||||||
bool enabled = 1;
|
bool enabled = 1;
|
||||||
@@ -28,6 +55,8 @@ message SniffingConfig {
|
|||||||
bool metadata_only = 4;
|
bool metadata_only = 4;
|
||||||
|
|
||||||
bool route_only = 5;
|
bool route_only = 5;
|
||||||
|
|
||||||
|
int64 timeout = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ReceiverConfig {
|
message ReceiverConfig {
|
||||||
@@ -35,10 +64,11 @@ message ReceiverConfig {
|
|||||||
xray.common.net.PortList port_list = 1;
|
xray.common.net.PortList port_list = 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;
|
||||||
xray.transport.internet.StreamConfig stream_settings = 3;
|
AllocationStrategy allocation_strategy = 3;
|
||||||
bool receive_original_destination = 4;
|
xray.transport.internet.StreamConfig stream_settings = 4;
|
||||||
reserved 5;
|
bool receive_original_destination = 5;
|
||||||
SniffingConfig sniffing_settings = 6;
|
reserved 6;
|
||||||
|
SniffingConfig sniffing_settings = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
message InboundHandlerConfig {
|
message InboundHandlerConfig {
|
||||||
@@ -56,7 +86,6 @@ message SenderConfig {
|
|||||||
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;
|
string via_cidr = 5;
|
||||||
xray.transport.internet.DomainStrategy target_strategy = 6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message MultiplexingConfig {
|
message MultiplexingConfig {
|
||||||
|
|||||||
@@ -5,16 +5,15 @@ import (
|
|||||||
|
|
||||||
"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/dice"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"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/serial"
|
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/policy"
|
"github.com/xtls/xray-core/features/policy"
|
||||||
"github.com/xtls/xray-core/features/stats"
|
"github.com/xtls/xray-core/features/stats"
|
||||||
"github.com/xtls/xray-core/proxy"
|
"github.com/xtls/xray-core/proxy"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"google.golang.org/protobuf/proto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {
|
func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {
|
||||||
@@ -43,12 +42,10 @@ func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter)
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AlwaysOnInboundHandler struct {
|
type AlwaysOnInboundHandler struct {
|
||||||
proxyConfig interface{}
|
proxy proxy.Inbound
|
||||||
receiverConfig *proxyman.ReceiverConfig
|
workers []worker
|
||||||
proxy proxy.Inbound
|
mux *mux.Server
|
||||||
workers []worker
|
tag string
|
||||||
mux *mux.Server
|
|
||||||
tag string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*AlwaysOnInboundHandler, error) {
|
func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*AlwaysOnInboundHandler, error) {
|
||||||
@@ -62,11 +59,9 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
}
|
}
|
||||||
|
|
||||||
h := &AlwaysOnInboundHandler{
|
h := &AlwaysOnInboundHandler{
|
||||||
receiverConfig: receiverConfig,
|
proxy: p,
|
||||||
proxyConfig: proxyConfig,
|
mux: mux.NewServer(ctx),
|
||||||
proxy: p,
|
tag: tag,
|
||||||
mux: mux.NewServer(ctx),
|
|
||||||
tag: tag,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uplinkCounter, downlinkCounter := getStatCounter(core.MustFromContext(ctx), tag)
|
uplinkCounter, downlinkCounter := getStatCounter(core.MustFromContext(ctx), tag)
|
||||||
@@ -102,7 +97,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
stream: mss,
|
stream: mss,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
dispatcher: h.mux,
|
dispatcher: h.mux,
|
||||||
sniffingConfig: receiverConfig.SniffingSettings,
|
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
uplinkCounter: uplinkCounter,
|
uplinkCounter: uplinkCounter,
|
||||||
downlinkCounter: downlinkCounter,
|
downlinkCounter: downlinkCounter,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
@@ -124,7 +119,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
recvOrigDest: receiverConfig.ReceiveOriginalDestination,
|
recvOrigDest: receiverConfig.ReceiveOriginalDestination,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
dispatcher: h.mux,
|
dispatcher: h.mux,
|
||||||
sniffingConfig: receiverConfig.SniffingSettings,
|
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
uplinkCounter: uplinkCounter,
|
uplinkCounter: uplinkCounter,
|
||||||
downlinkCounter: downlinkCounter,
|
downlinkCounter: downlinkCounter,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
@@ -139,7 +134,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
address: address,
|
address: address,
|
||||||
port: net.Port(port),
|
port: net.Port(port),
|
||||||
dispatcher: h.mux,
|
dispatcher: h.mux,
|
||||||
sniffingConfig: receiverConfig.SniffingSettings,
|
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
uplinkCounter: uplinkCounter,
|
uplinkCounter: uplinkCounter,
|
||||||
downlinkCounter: downlinkCounter,
|
downlinkCounter: downlinkCounter,
|
||||||
stream: mss,
|
stream: mss,
|
||||||
@@ -177,6 +172,14 @@ func (h *AlwaysOnInboundHandler) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *AlwaysOnInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {
|
||||||
|
if len(h.workers) == 0 {
|
||||||
|
return nil, 0, 0
|
||||||
|
}
|
||||||
|
w := h.workers[dice.Roll(len(h.workers))]
|
||||||
|
return w.Proxy(), w.Port(), 9999
|
||||||
|
}
|
||||||
|
|
||||||
func (h *AlwaysOnInboundHandler) Tag() string {
|
func (h *AlwaysOnInboundHandler) Tag() string {
|
||||||
return h.tag
|
return h.tag
|
||||||
}
|
}
|
||||||
@@ -184,16 +187,3 @@ func (h *AlwaysOnInboundHandler) Tag() string {
|
|||||||
func (h *AlwaysOnInboundHandler) GetInbound() proxy.Inbound {
|
func (h *AlwaysOnInboundHandler) GetInbound() proxy.Inbound {
|
||||||
return h.proxy
|
return h.proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReceiverSettings implements inbound.Handler.
|
|
||||||
func (h *AlwaysOnInboundHandler) ReceiverSettings() *serial.TypedMessage {
|
|
||||||
return serial.ToTypedMessage(h.receiverConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProxySettings implements inbound.Handler.
|
|
||||||
func (h *AlwaysOnInboundHandler) ProxySettings() *serial.TypedMessage {
|
|
||||||
if v, ok := h.proxyConfig.(proto.Message); ok {
|
|
||||||
return serial.ToTypedMessage(v)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
207
app/proxyman/inbound/dynamic.go
Normal file
207
app/proxyman/inbound/dynamic.go
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
package inbound
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/app/proxyman"
|
||||||
|
"github.com/xtls/xray-core/common/dice"
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/common/mux"
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/common/task"
|
||||||
|
"github.com/xtls/xray-core/core"
|
||||||
|
"github.com/xtls/xray-core/proxy"
|
||||||
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DynamicInboundHandler struct {
|
||||||
|
tag string
|
||||||
|
v *core.Instance
|
||||||
|
proxyConfig interface{}
|
||||||
|
receiverConfig *proxyman.ReceiverConfig
|
||||||
|
streamSettings *internet.MemoryStreamConfig
|
||||||
|
portMutex sync.Mutex
|
||||||
|
portsInUse map[net.Port]struct{}
|
||||||
|
workerMutex sync.RWMutex
|
||||||
|
worker []worker
|
||||||
|
lastRefresh time.Time
|
||||||
|
mux *mux.Server
|
||||||
|
task *task.Periodic
|
||||||
|
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*DynamicInboundHandler, error) {
|
||||||
|
v := core.MustFromContext(ctx)
|
||||||
|
h := &DynamicInboundHandler{
|
||||||
|
tag: tag,
|
||||||
|
proxyConfig: proxyConfig,
|
||||||
|
receiverConfig: receiverConfig,
|
||||||
|
portsInUse: make(map[net.Port]struct{}),
|
||||||
|
mux: mux.NewServer(ctx),
|
||||||
|
v: v,
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
|
||||||
|
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to parse stream settings").Base(err).AtWarning()
|
||||||
|
}
|
||||||
|
if receiverConfig.ReceiveOriginalDestination {
|
||||||
|
if mss.SocketSettings == nil {
|
||||||
|
mss.SocketSettings = &internet.SocketConfig{}
|
||||||
|
}
|
||||||
|
if mss.SocketSettings.Tproxy == internet.SocketConfig_Off {
|
||||||
|
mss.SocketSettings.Tproxy = internet.SocketConfig_Redirect
|
||||||
|
}
|
||||||
|
mss.SocketSettings.ReceiveOriginalDestAddress = true
|
||||||
|
}
|
||||||
|
|
||||||
|
h.streamSettings = mss
|
||||||
|
|
||||||
|
h.task = &task.Periodic{
|
||||||
|
Interval: time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()),
|
||||||
|
Execute: h.refresh,
|
||||||
|
}
|
||||||
|
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) allocatePort() net.Port {
|
||||||
|
allPorts := []int32{}
|
||||||
|
for _, pr := range h.receiverConfig.PortList.Range {
|
||||||
|
for i := pr.From; i <= pr.To; i++ {
|
||||||
|
allPorts = append(allPorts, int32(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h.portMutex.Lock()
|
||||||
|
defer h.portMutex.Unlock()
|
||||||
|
|
||||||
|
for {
|
||||||
|
r := dice.Roll(len(allPorts))
|
||||||
|
port := net.Port(allPorts[r])
|
||||||
|
_, used := h.portsInUse[port]
|
||||||
|
if !used {
|
||||||
|
h.portsInUse[port] = struct{}{}
|
||||||
|
return port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) closeWorkers(workers []worker) {
|
||||||
|
ports2Del := make([]net.Port, len(workers))
|
||||||
|
for idx, worker := range workers {
|
||||||
|
ports2Del[idx] = worker.Port()
|
||||||
|
if err := worker.Close(); err != nil {
|
||||||
|
errors.LogInfoInner(h.ctx, err, "failed to close worker")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.portMutex.Lock()
|
||||||
|
for _, port := range ports2Del {
|
||||||
|
delete(h.portsInUse, port)
|
||||||
|
}
|
||||||
|
h.portMutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) refresh() error {
|
||||||
|
h.lastRefresh = time.Now()
|
||||||
|
|
||||||
|
timeout := time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()) * 2
|
||||||
|
concurrency := h.receiverConfig.AllocationStrategy.GetConcurrencyValue()
|
||||||
|
workers := make([]worker, 0, concurrency)
|
||||||
|
|
||||||
|
address := h.receiverConfig.Listen.AsAddress()
|
||||||
|
if address == nil {
|
||||||
|
address = net.AnyIP
|
||||||
|
}
|
||||||
|
|
||||||
|
uplinkCounter, downlinkCounter := getStatCounter(h.v, h.tag)
|
||||||
|
|
||||||
|
for i := uint32(0); i < concurrency; i++ {
|
||||||
|
port := h.allocatePort()
|
||||||
|
rawProxy, err := core.CreateObject(h.v, h.proxyConfig)
|
||||||
|
if err != nil {
|
||||||
|
errors.LogWarningInner(h.ctx, err, "failed to create proxy instance")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p := rawProxy.(proxy.Inbound)
|
||||||
|
nl := p.Network()
|
||||||
|
if net.HasNetwork(nl, net.Network_TCP) {
|
||||||
|
worker := &tcpWorker{
|
||||||
|
tag: h.tag,
|
||||||
|
address: address,
|
||||||
|
port: port,
|
||||||
|
proxy: p,
|
||||||
|
stream: h.streamSettings,
|
||||||
|
recvOrigDest: h.receiverConfig.ReceiveOriginalDestination,
|
||||||
|
dispatcher: h.mux,
|
||||||
|
sniffingConfig: h.receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
|
uplinkCounter: uplinkCounter,
|
||||||
|
downlinkCounter: downlinkCounter,
|
||||||
|
ctx: h.ctx,
|
||||||
|
}
|
||||||
|
if err := worker.Start(); err != nil {
|
||||||
|
errors.LogWarningInner(h.ctx, err, "failed to create TCP worker")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
workers = append(workers, worker)
|
||||||
|
}
|
||||||
|
|
||||||
|
if net.HasNetwork(nl, net.Network_UDP) {
|
||||||
|
worker := &udpWorker{
|
||||||
|
tag: h.tag,
|
||||||
|
proxy: p,
|
||||||
|
address: address,
|
||||||
|
port: port,
|
||||||
|
dispatcher: h.mux,
|
||||||
|
sniffingConfig: h.receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
|
uplinkCounter: uplinkCounter,
|
||||||
|
downlinkCounter: downlinkCounter,
|
||||||
|
stream: h.streamSettings,
|
||||||
|
ctx: h.ctx,
|
||||||
|
}
|
||||||
|
if err := worker.Start(); err != nil {
|
||||||
|
errors.LogWarningInner(h.ctx, err, "failed to create UDP worker")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
workers = append(workers, worker)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.workerMutex.Lock()
|
||||||
|
h.worker = workers
|
||||||
|
h.workerMutex.Unlock()
|
||||||
|
|
||||||
|
time.AfterFunc(timeout, func() {
|
||||||
|
h.closeWorkers(workers)
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) Start() error {
|
||||||
|
return h.task.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) Close() error {
|
||||||
|
return h.task.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {
|
||||||
|
h.workerMutex.RLock()
|
||||||
|
defer h.workerMutex.RUnlock()
|
||||||
|
|
||||||
|
if len(h.worker) == 0 {
|
||||||
|
return nil, 0, 0
|
||||||
|
}
|
||||||
|
w := h.worker[dice.Roll(len(h.worker))]
|
||||||
|
expire := h.receiverConfig.AllocationStrategy.GetRefreshValue() - uint32(time.Since(h.lastRefresh)/time.Minute)
|
||||||
|
return w.Proxy(), w.Port(), int(expire)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) Tag() string {
|
||||||
|
return h.tag
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
// Manager manages all inbound handlers.
|
// Manager manages all inbound handlers.
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
access sync.RWMutex
|
access sync.RWMutex
|
||||||
untaggedHandlers []inbound.Handler
|
untaggedHandler []inbound.Handler
|
||||||
taggedHandlers map[string]inbound.Handler
|
taggedHandlers map[string]inbound.Handler
|
||||||
running bool
|
running bool
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ func (m *Manager) AddHandler(ctx context.Context, handler inbound.Handler) error
|
|||||||
}
|
}
|
||||||
m.taggedHandlers[tag] = handler
|
m.taggedHandlers[tag] = handler
|
||||||
} else {
|
} else {
|
||||||
m.untaggedHandlers = append(m.untaggedHandlers, handler)
|
m.untaggedHandler = append(m.untaggedHandler, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.running {
|
if m.running {
|
||||||
@@ -89,21 +89,6 @@ func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
|
|||||||
return common.ErrNoClue
|
return common.ErrNoClue
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListHandlers implements inbound.Manager.
|
|
||||||
func (m *Manager) ListHandlers(ctx context.Context) []inbound.Handler {
|
|
||||||
m.access.RLock()
|
|
||||||
defer m.access.RUnlock()
|
|
||||||
|
|
||||||
response := make([]inbound.Handler, len(m.untaggedHandlers))
|
|
||||||
copy(response, m.untaggedHandlers)
|
|
||||||
|
|
||||||
for _, v := range m.taggedHandlers {
|
|
||||||
response = append(response, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start implements common.Runnable.
|
// Start implements common.Runnable.
|
||||||
func (m *Manager) Start() error {
|
func (m *Manager) Start() error {
|
||||||
m.access.Lock()
|
m.access.Lock()
|
||||||
@@ -117,7 +102,7 @@ func (m *Manager) Start() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, handler := range m.untaggedHandlers {
|
for _, handler := range m.untaggedHandler {
|
||||||
if err := handler.Start(); err != nil {
|
if err := handler.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -138,7 +123,7 @@ func (m *Manager) Close() error {
|
|||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, handler := range m.untaggedHandlers {
|
for _, handler := range m.untaggedHandler {
|
||||||
if err := handler.Close(); err != nil {
|
if err := handler.Close(); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
@@ -178,7 +163,15 @@ func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound
|
|||||||
ctx = session.ContextWithAllowedNetwork(ctx, net.Network_UDP)
|
ctx = session.ContextWithAllowedNetwork(ctx, net.Network_UDP)
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewAlwaysOnInboundHandler(ctx, tag, receiverSettings, proxySettings)
|
allocStrategy := receiverSettings.AllocationStrategy
|
||||||
|
if allocStrategy == nil || allocStrategy.Type == proxyman.AllocationStrategy_Always {
|
||||||
|
return NewAlwaysOnInboundHandler(ctx, tag, receiverSettings, proxySettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
if allocStrategy.Type == proxyman.AllocationStrategy_Random {
|
||||||
|
return NewDynamicInboundHandler(ctx, tag, receiverSettings, proxySettings)
|
||||||
|
}
|
||||||
|
return nil, errors.New("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package inbound
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
gonet "net"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@@ -77,25 +76,7 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
|||||||
case internet.SocketConfig_TProxy:
|
case internet.SocketConfig_TProxy:
|
||||||
dest = net.DestinationFromAddr(conn.LocalAddr())
|
dest = net.DestinationFromAddr(conn.LocalAddr())
|
||||||
}
|
}
|
||||||
|
|
||||||
if dest.IsValid() {
|
if dest.IsValid() {
|
||||||
// Check if try to connect to this inbound itself (can cause loopback)
|
|
||||||
var isLoopBack bool
|
|
||||||
if w.address == net.AnyIP || w.address == net.AnyIPv6 {
|
|
||||||
if dest.Port.Value() == w.port.Value() && IsLocal(dest.Address.IP()) {
|
|
||||||
isLoopBack = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if w.hub.Addr().String() == dest.NetAddr() {
|
|
||||||
isLoopBack = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if isLoopBack {
|
|
||||||
cancel()
|
|
||||||
conn.Close()
|
|
||||||
errors.LogError(ctx, errors.New("loopback connection detected"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
outbounds[0].Target = dest
|
outbounds[0].Target = dest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,7 +91,6 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
|||||||
}
|
}
|
||||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||||
Source: net.DestinationFromAddr(conn.RemoteAddr()),
|
Source: net.DestinationFromAddr(conn.RemoteAddr()),
|
||||||
Local: net.DestinationFromAddr(conn.LocalAddr()),
|
|
||||||
Gateway: net.TCPDestination(w.address, w.port),
|
Gateway: net.TCPDestination(w.address, w.port),
|
||||||
Tag: w.tag,
|
Tag: w.tag,
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
@@ -123,6 +103,7 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
|||||||
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
||||||
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||||
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
||||||
|
content.SniffingRequest.Timeout = time.Duration(w.sniffingConfig.Timeout) * time.Millisecond
|
||||||
}
|
}
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
|
|
||||||
@@ -181,7 +162,6 @@ type udpConn struct {
|
|||||||
uplink stats.Counter
|
uplink stats.Counter
|
||||||
downlink stats.Counter
|
downlink stats.Counter
|
||||||
inactive bool
|
inactive bool
|
||||||
cancel context.CancelFunc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *udpConn) setInactive() {
|
func (c *udpConn) setInactive() {
|
||||||
@@ -224,9 +204,6 @@ func (c *udpConn) Write(buf []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *udpConn) Close() error {
|
func (c *udpConn) Close() error {
|
||||||
if c.cancel != nil {
|
|
||||||
c.cancel()
|
|
||||||
}
|
|
||||||
common.Must(c.done.Close())
|
common.Must(c.done.Close())
|
||||||
common.Must(common.Close(c.writer))
|
common.Must(common.Close(c.writer))
|
||||||
return nil
|
return nil
|
||||||
@@ -283,7 +260,6 @@ func (w *udpWorker) getConnection(id connID) (*udpConn, bool) {
|
|||||||
defer w.Unlock()
|
defer w.Unlock()
|
||||||
|
|
||||||
if conn, found := w.activeConn[id]; found && !conn.done.Done() {
|
if conn, found := w.activeConn[id]; found && !conn.done.Done() {
|
||||||
conn.updateActivity()
|
|
||||||
return conn, true
|
return conn, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,8 +307,7 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
|||||||
common.Must(w.checker.Start())
|
common.Must(w.checker.Start())
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
ctx, cancel := context.WithCancel(w.ctx)
|
ctx := w.ctx
|
||||||
conn.cancel = cancel
|
|
||||||
sid := session.NewID()
|
sid := session.NewID()
|
||||||
ctx = c.ContextWithID(ctx, sid)
|
ctx = c.ContextWithID(ctx, sid)
|
||||||
|
|
||||||
@@ -341,18 +316,8 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
|||||||
outbounds[0].Target = originalDest
|
outbounds[0].Target = originalDest
|
||||||
}
|
}
|
||||||
ctx = session.ContextWithOutbounds(ctx, outbounds)
|
ctx = session.ContextWithOutbounds(ctx, outbounds)
|
||||||
local := net.DestinationFromAddr(w.hub.Addr())
|
|
||||||
if local.Address == net.AnyIP || local.Address == net.AnyIPv6 {
|
|
||||||
if source.Address.Family().IsIPv4() {
|
|
||||||
local.Address = net.AnyIP
|
|
||||||
} else if source.Address.Family().IsIPv6() {
|
|
||||||
local.Address = net.AnyIPv6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||||
Source: source,
|
Source: source,
|
||||||
Local: local, // Due to some limitations, in UDP connections, localIP is always equal to listen interface IP
|
|
||||||
Gateway: net.UDPDestination(w.address, w.port),
|
Gateway: net.UDPDestination(w.address, w.port),
|
||||||
Tag: w.tag,
|
Tag: w.tag,
|
||||||
})
|
})
|
||||||
@@ -360,9 +325,9 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
|||||||
if w.sniffingConfig != nil {
|
if w.sniffingConfig != nil {
|
||||||
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
|
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
|
||||||
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
||||||
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
|
||||||
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||||
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
||||||
|
content.SniffingRequest.Timeout = time.Duration(w.sniffingConfig.Timeout) * time.Millisecond
|
||||||
}
|
}
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
|
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
|
||||||
@@ -502,7 +467,6 @@ func (w *dsWorker) callback(conn stat.Connection) {
|
|||||||
}
|
}
|
||||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||||
Source: net.DestinationFromAddr(conn.RemoteAddr()),
|
Source: net.DestinationFromAddr(conn.RemoteAddr()),
|
||||||
Local: net.DestinationFromAddr(conn.LocalAddr()),
|
|
||||||
Gateway: net.UnixDestination(w.address),
|
Gateway: net.UnixDestination(w.address),
|
||||||
Tag: w.tag,
|
Tag: w.tag,
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
@@ -515,6 +479,7 @@ func (w *dsWorker) callback(conn stat.Connection) {
|
|||||||
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
||||||
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||||
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
||||||
|
content.SniffingRequest.Timeout = time.Duration(w.sniffingConfig.Timeout) * time.Millisecond
|
||||||
}
|
}
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
|
|
||||||
@@ -563,18 +528,3 @@ func (w *dsWorker) Close() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsLocal(ip net.IP) bool {
|
|
||||||
addrs, err := gonet.InterfaceAddrs()
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, addr := range addrs {
|
|
||||||
if ipnet, ok := addr.(*gonet.IPNet); ok {
|
|
||||||
if ipnet.IP.Equal(ip) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import (
|
|||||||
gonet "net"
|
gonet "net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/dice"
|
|
||||||
|
|
||||||
"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 +16,6 @@ import (
|
|||||||
"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"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/outbound"
|
"github.com/xtls/xray-core/features/outbound"
|
||||||
@@ -30,7 +27,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
"github.com/xtls/xray-core/transport/internet/stat"
|
||||||
"github.com/xtls/xray-core/transport/internet/tls"
|
"github.com/xtls/xray-core/transport/internet/tls"
|
||||||
"github.com/xtls/xray-core/transport/pipe"
|
"github.com/xtls/xray-core/transport/pipe"
|
||||||
"google.golang.org/protobuf/proto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {
|
func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {
|
||||||
@@ -63,7 +59,6 @@ type Handler struct {
|
|||||||
tag string
|
tag string
|
||||||
senderSettings *proxyman.SenderConfig
|
senderSettings *proxyman.SenderConfig
|
||||||
streamSettings *internet.MemoryStreamConfig
|
streamSettings *internet.MemoryStreamConfig
|
||||||
proxyConfig proto.Message
|
|
||||||
proxy proxy.Outbound
|
proxy proxy.Outbound
|
||||||
outboundManager outbound.Manager
|
outboundManager outbound.Manager
|
||||||
mux *mux.ClientManager
|
mux *mux.ClientManager
|
||||||
@@ -106,9 +101,6 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
h.proxyConfig = proxyConfig
|
|
||||||
|
|
||||||
ctx = session.ContextWithFullHandler(ctx, h)
|
|
||||||
|
|
||||||
rawProxyHandler, err := common.CreateObject(ctx, proxyConfig)
|
rawProxyHandler, err := common.CreateObject(ctx, proxyConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -181,29 +173,6 @@ func (h *Handler) Tag() string {
|
|||||||
func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
ob := outbounds[len(outbounds)-1]
|
ob := outbounds[len(outbounds)-1]
|
||||||
content := session.ContentFromContext(ctx)
|
|
||||||
if h.senderSettings != nil && h.senderSettings.TargetStrategy.HasStrategy() && ob.Target.Address.Family().IsDomain() && (content == nil || !content.SkipDNSResolve) {
|
|
||||||
strategy := h.senderSettings.TargetStrategy
|
|
||||||
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil {
|
|
||||||
strategy = strategy.GetDynamicStrategy(ob.OriginalTarget.Address.Family())
|
|
||||||
}
|
|
||||||
ips, err := internet.LookupForIP(ob.Target.Address.Domain(), strategy, nil)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogInfoInner(ctx, err, "failed to resolve ip for target ", ob.Target.Address.Domain())
|
|
||||||
if h.senderSettings.TargetStrategy.ForceIP() {
|
|
||||||
err := errors.New("failed to resolve ip for target ", ob.Target.Address.Domain()).Base(err)
|
|
||||||
session.SubmitOutboundErrorToOriginator(ctx, err)
|
|
||||||
common.Interrupt(link.Writer)
|
|
||||||
common.Interrupt(link.Reader)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
unchangedDomain := ob.Target.Address.Domain()
|
|
||||||
ob.Target.Address = net.IPAddress(ips[dice.Roll(len(ips))])
|
|
||||||
errors.LogInfo(ctx, "target: ", unchangedDomain, " resolved to: ", ob.Target.Address.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil && ob.OriginalTarget.Address != ob.Target.Address {
|
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil && ob.OriginalTarget.Address != ob.Target.Address {
|
||||||
link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
||||||
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
||||||
@@ -215,7 +184,6 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
|||||||
session.SubmitOutboundErrorToOriginator(ctx, err)
|
session.SubmitOutboundErrorToOriginator(ctx, err)
|
||||||
errors.LogInfo(ctx, err.Error())
|
errors.LogInfo(ctx, err.Error())
|
||||||
common.Interrupt(link.Writer)
|
common.Interrupt(link.Writer)
|
||||||
common.Interrupt(link.Reader)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ob.Target.Network == net.Network_UDP && ob.Target.Port == 443 {
|
if ob.Target.Network == net.Network_UDP && ob.Target.Port == 443 {
|
||||||
@@ -241,10 +209,8 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
|||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
err := h.proxy.Process(ctx, link, h)
|
err := h.proxy.Process(ctx, link, h)
|
||||||
var errC error
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errC = errors.Cause(err)
|
if goerrors.Is(err, io.EOF) || goerrors.Is(err, io.ErrClosedPipe) || goerrors.Is(err, context.Canceled) {
|
||||||
if goerrors.Is(errC, io.EOF) || goerrors.Is(errC, io.ErrClosedPipe) || goerrors.Is(errC, context.Canceled) {
|
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,15 +221,19 @@ out:
|
|||||||
errors.LogInfo(ctx, err.Error())
|
errors.LogInfo(ctx, err.Error())
|
||||||
common.Interrupt(link.Writer)
|
common.Interrupt(link.Writer)
|
||||||
} else {
|
} else {
|
||||||
if errC != nil && goerrors.Is(errC, io.ErrClosedPipe) {
|
common.Close(link.Writer)
|
||||||
common.Interrupt(link.Writer)
|
|
||||||
} else {
|
|
||||||
common.Close(link.Writer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
common.Interrupt(link.Reader)
|
common.Interrupt(link.Reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Address implements internet.Dialer.
|
||||||
|
func (h *Handler) Address() net.Address {
|
||||||
|
if h.senderSettings == nil || h.senderSettings.Via == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return h.senderSettings.Via.AsAddress()
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handler) DestIpAddress() net.IP {
|
func (h *Handler) DestIpAddress() net.IP {
|
||||||
return internet.DestIpAddress()
|
return internet.DestIpAddress()
|
||||||
}
|
}
|
||||||
@@ -271,9 +241,7 @@ func (h *Handler) DestIpAddress() net.IP {
|
|||||||
// 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 {
|
||||||
|
|
||||||
if h.senderSettings.ProxySettings.HasTag() {
|
if h.senderSettings.ProxySettings.HasTag() {
|
||||||
|
|
||||||
tag := h.senderSettings.ProxySettings.Tag
|
tag := h.senderSettings.ProxySettings.Tag
|
||||||
handler := h.outboundManager.GetHandler(tag)
|
handler := h.outboundManager.GetHandler(tag)
|
||||||
if handler != nil {
|
if handler != nil {
|
||||||
@@ -298,16 +266,27 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
|||||||
return h.getStatCouterConnection(conn), nil
|
return h.getStatCouterConnection(conn), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogError(ctx, "failed to get outbound handler with tag: ", tag)
|
errors.LogWarning(ctx, "failed to get outbound handler with tag: ", tag)
|
||||||
return nil, errors.New("failed to get outbound handler with tag: " + tag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.senderSettings.Via != nil {
|
if h.senderSettings.Via != nil {
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
ob := outbounds[len(outbounds)-1]
|
ob := outbounds[len(outbounds)-1]
|
||||||
h.SetOutboundGateway(ctx, ob)
|
if h.senderSettings.ViaCidr == "" {
|
||||||
|
if h.senderSettings.Via.AsAddress().Family().IsDomain() && h.senderSettings.Via.AsAddress().Domain() == "origin" {
|
||||||
|
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||||
|
origin, _, err := net.SplitHostPort(inbound.Conn.LocalAddr().String())
|
||||||
|
if err == nil {
|
||||||
|
ob.Gateway = net.ParseAddress(origin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ob.Gateway = h.senderSettings.Via.AsAddress()
|
||||||
|
}
|
||||||
|
} else { //Get a random address.
|
||||||
|
ob.Gateway = ParseRandomIPv6(h.senderSettings.Via.AsAddress(), h.senderSettings.ViaCidr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if conn, err := h.getUoTConnection(ctx, dest); err != os.ErrInvalid {
|
if conn, err := h.getUoTConnection(ctx, dest); err != os.ErrInvalid {
|
||||||
@@ -317,47 +296,11 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
|||||||
conn, err := internet.Dial(ctx, dest, h.streamSettings)
|
conn, err := internet.Dial(ctx, dest, h.streamSettings)
|
||||||
conn = h.getStatCouterConnection(conn)
|
conn = h.getStatCouterConnection(conn)
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
if outbounds != nil {
|
ob := outbounds[len(outbounds)-1]
|
||||||
ob := outbounds[len(outbounds)-1]
|
ob.Conn = conn
|
||||||
ob.Conn = conn
|
|
||||||
} else {
|
|
||||||
// for Vision's pre-connect
|
|
||||||
}
|
|
||||||
return conn, err
|
return conn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) SetOutboundGateway(ctx context.Context, ob *session.Outbound) {
|
|
||||||
if ob.Gateway == nil && h.senderSettings != nil && h.senderSettings.Via != nil && !h.senderSettings.ProxySettings.HasTag() && (h.streamSettings.SocketSettings == nil || len(h.streamSettings.SocketSettings.DialerProxy) == 0) {
|
|
||||||
var domain string
|
|
||||||
addr := h.senderSettings.Via.AsAddress()
|
|
||||||
domain = h.senderSettings.Via.GetDomain()
|
|
||||||
switch {
|
|
||||||
case h.senderSettings.ViaCidr != "":
|
|
||||||
ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr)
|
|
||||||
|
|
||||||
case domain == "origin":
|
|
||||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
|
||||||
if inbound.Local.IsValid() && inbound.Local.Address.Family().IsIP() {
|
|
||||||
ob.Gateway = inbound.Local.Address
|
|
||||||
errors.LogDebug(ctx, "use inbound local ip as sendthrough: ", inbound.Local.Address.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case domain == "srcip":
|
|
||||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
|
||||||
if inbound.Source.IsValid() && inbound.Source.Address.Family().IsIP() {
|
|
||||||
ob.Gateway = inbound.Source.Address
|
|
||||||
errors.LogDebug(ctx, "use inbound source ip as sendthrough: ", inbound.Source.Address.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//case addr.Family().IsDomain():
|
|
||||||
default:
|
|
||||||
ob.Gateway = addr
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) getStatCouterConnection(conn stat.Connection) stat.Connection {
|
func (h *Handler) getStatCouterConnection(conn stat.Connection) stat.Connection {
|
||||||
if h.uplinkCounter != nil || h.downlinkCounter != nil {
|
if h.uplinkCounter != nil || h.downlinkCounter != nil {
|
||||||
return &stat.CounterConnection{
|
return &stat.CounterConnection{
|
||||||
@@ -382,35 +325,23 @@ func (h *Handler) Start() error {
|
|||||||
// Close implements common.Closable.
|
// Close implements common.Closable.
|
||||||
func (h *Handler) Close() error {
|
func (h *Handler) Close() error {
|
||||||
common.Close(h.mux)
|
common.Close(h.mux)
|
||||||
common.Close(h.proxy)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SenderSettings implements outbound.Handler.
|
func ParseRandomIPv6(address net.Address, prefix string) net.Address {
|
||||||
func (h *Handler) SenderSettings() *serial.TypedMessage {
|
_, network, _ := gonet.ParseCIDR(address.IP().String() + "/" + prefix)
|
||||||
return serial.ToTypedMessage(h.senderSettings)
|
|
||||||
}
|
maskSize, totalBits := network.Mask.Size()
|
||||||
|
subnetSize := big.NewInt(1).Lsh(big.NewInt(1), uint(totalBits-maskSize))
|
||||||
// ProxySettings implements outbound.Handler.
|
|
||||||
func (h *Handler) ProxySettings() *serial.TypedMessage {
|
// random
|
||||||
return serial.ToTypedMessage(h.proxyConfig)
|
randomBigInt, _ := rand.Int(rand.Reader, subnetSize)
|
||||||
}
|
|
||||||
|
startIPBigInt := big.NewInt(0).SetBytes(network.IP.To16())
|
||||||
func ParseRandomIP(addr net.Address, prefix string) net.Address {
|
randomIPBigInt := big.NewInt(0).Add(startIPBigInt, randomBigInt)
|
||||||
|
|
||||||
_, ipnet, _ := gonet.ParseCIDR(addr.IP().String() + "/" + prefix)
|
randomIPBytes := randomIPBigInt.Bytes()
|
||||||
|
randomIPBytes = append(make([]byte, 16-len(randomIPBytes)), randomIPBytes...)
|
||||||
ones, bits := ipnet.Mask.Size()
|
|
||||||
subnetSize := new(big.Int).Lsh(big.NewInt(1), uint(bits-ones))
|
return net.ParseAddress(gonet.IP(randomIPBytes).String())
|
||||||
|
|
||||||
rnd, _ := rand.Int(rand.Reader, subnetSize)
|
|
||||||
|
|
||||||
startInt := new(big.Int).SetBytes(ipnet.IP)
|
|
||||||
rndInt := new(big.Int).Add(startInt, rnd)
|
|
||||||
|
|
||||||
rndBytes := rndInt.Bytes()
|
|
||||||
padded := make([]byte, len(ipnet.IP))
|
|
||||||
copy(padded[len(padded)-len(rndBytes):], rndBytes)
|
|
||||||
|
|
||||||
return net.ParseAddress(gonet.IP(padded).String())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,21 +145,6 @@ func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListHandlers implements outbound.Manager.
|
|
||||||
func (m *Manager) ListHandlers(ctx context.Context) []outbound.Handler {
|
|
||||||
m.access.RLock()
|
|
||||||
defer m.access.RUnlock()
|
|
||||||
|
|
||||||
response := make([]outbound.Handler, len(m.untaggedHandlers))
|
|
||||||
copy(response, m.untaggedHandlers)
|
|
||||||
|
|
||||||
for _, v := range m.taggedHandler {
|
|
||||||
response = append(response, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select implements outbound.HandlerSelector.
|
// Select implements outbound.HandlerSelector.
|
||||||
func (m *Manager) Select(selectors []string) []string {
|
func (m *Manager) Select(selectors []string) []string {
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"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"
|
||||||
"github.com/xtls/xray-core/common/signal"
|
|
||||||
"github.com/xtls/xray-core/common/task"
|
"github.com/xtls/xray-core/common/task"
|
||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
"github.com/xtls/xray-core/transport"
|
"github.com/xtls/xray-core/transport"
|
||||||
@@ -53,11 +52,6 @@ func (b *Bridge) cleanup() {
|
|||||||
if w.IsActive() {
|
if w.IsActive() {
|
||||||
activeWorkers = append(activeWorkers, w)
|
activeWorkers = append(activeWorkers, w)
|
||||||
}
|
}
|
||||||
if w.Closed() {
|
|
||||||
if w.Timer != nil {
|
|
||||||
w.Timer.SetTimeout(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(activeWorkers) != len(b.workers) {
|
if len(activeWorkers) != len(b.workers) {
|
||||||
@@ -99,11 +93,10 @@ func (b *Bridge) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BridgeWorker struct {
|
type BridgeWorker struct {
|
||||||
Tag string
|
tag string
|
||||||
Worker *mux.ServerWorker
|
worker *mux.ServerWorker
|
||||||
Dispatcher routing.Dispatcher
|
dispatcher routing.Dispatcher
|
||||||
State Control_State
|
state Control_State
|
||||||
Timer *signal.ActivityTimer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBridgeWorker(domain string, tag string, d routing.Dispatcher) (*BridgeWorker, error) {
|
func NewBridgeWorker(domain string, tag string, d routing.Dispatcher) (*BridgeWorker, error) {
|
||||||
@@ -121,20 +114,16 @@ func NewBridgeWorker(domain string, tag string, d routing.Dispatcher) (*BridgeWo
|
|||||||
}
|
}
|
||||||
|
|
||||||
w := &BridgeWorker{
|
w := &BridgeWorker{
|
||||||
Dispatcher: d,
|
dispatcher: d,
|
||||||
Tag: tag,
|
tag: tag,
|
||||||
}
|
}
|
||||||
|
|
||||||
worker, err := mux.NewServerWorker(context.Background(), w, link)
|
worker, err := mux.NewServerWorker(context.Background(), w, link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
w.Worker = worker
|
w.worker = worker
|
||||||
|
|
||||||
terminate := func() {
|
|
||||||
worker.Close()
|
|
||||||
}
|
|
||||||
w.Timer = signal.CancelAfterInactivity(ctx, terminate, 60*time.Second)
|
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,65 +140,48 @@ func (w *BridgeWorker) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *BridgeWorker) IsActive() bool {
|
func (w *BridgeWorker) IsActive() bool {
|
||||||
return w.State == Control_ACTIVE && !w.Worker.Closed()
|
return w.state == Control_ACTIVE && !w.worker.Closed()
|
||||||
}
|
|
||||||
|
|
||||||
func (w *BridgeWorker) Closed() bool {
|
|
||||||
return w.Worker.Closed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *BridgeWorker) Connections() uint32 {
|
func (w *BridgeWorker) Connections() uint32 {
|
||||||
return w.Worker.ActiveConnections()
|
return w.worker.ActiveConnections()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *BridgeWorker) handleInternalConn(link *transport.Link) {
|
func (w *BridgeWorker) handleInternalConn(link *transport.Link) {
|
||||||
reader := link.Reader
|
go func() {
|
||||||
for {
|
reader := link.Reader
|
||||||
mb, err := reader.ReadMultiBuffer()
|
for {
|
||||||
if err != nil {
|
mb, err := reader.ReadMultiBuffer()
|
||||||
if w.Timer != nil {
|
if err != nil {
|
||||||
if w.Closed() {
|
break
|
||||||
w.Timer.SetTimeout(0)
|
}
|
||||||
} else {
|
for _, b := range mb {
|
||||||
w.Timer.SetTimeout(24 * time.Hour)
|
var ctl Control
|
||||||
|
if err := proto.Unmarshal(b.Bytes(), &ctl); err != nil {
|
||||||
|
errors.LogInfoInner(context.Background(), err, "failed to parse proto message")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if ctl.State != w.state {
|
||||||
|
w.state = ctl.State
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if w.Timer != nil {
|
}()
|
||||||
w.Timer.Update()
|
|
||||||
}
|
|
||||||
for _, b := range mb {
|
|
||||||
var ctl Control
|
|
||||||
if err := proto.Unmarshal(b.Bytes(), &ctl); err != nil {
|
|
||||||
errors.LogInfoInner(context.Background(), err, "failed to parse proto message")
|
|
||||||
if w.Timer != nil {
|
|
||||||
w.Timer.SetTimeout(0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if ctl.State != w.State {
|
|
||||||
w.State = ctl.State
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {
|
func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {
|
||||||
if !isInternalDomain(dest) {
|
if !isInternalDomain(dest) {
|
||||||
if session.InboundFromContext(ctx) == nil {
|
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
Tag: w.tag,
|
||||||
Tag: w.Tag,
|
})
|
||||||
})
|
return w.dispatcher.Dispatch(ctx, dest)
|
||||||
}
|
|
||||||
return w.Dispatcher.Dispatch(ctx, dest)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
opt := []pipe.Option{pipe.WithSizeLimit(16 * 1024)}
|
opt := []pipe.Option{pipe.WithSizeLimit(16 * 1024)}
|
||||||
uplinkReader, uplinkWriter := pipe.New(opt...)
|
uplinkReader, uplinkWriter := pipe.New(opt...)
|
||||||
downlinkReader, downlinkWriter := pipe.New(opt...)
|
downlinkReader, downlinkWriter := pipe.New(opt...)
|
||||||
|
|
||||||
go w.handleInternalConn(&transport.Link{
|
w.handleInternalConn(&transport.Link{
|
||||||
Reader: downlinkReader,
|
Reader: downlinkReader,
|
||||||
Writer: uplinkWriter,
|
Writer: uplinkWriter,
|
||||||
})
|
})
|
||||||
@@ -222,17 +194,12 @@ func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*tra
|
|||||||
|
|
||||||
func (w *BridgeWorker) DispatchLink(ctx context.Context, dest net.Destination, link *transport.Link) error {
|
func (w *BridgeWorker) DispatchLink(ctx context.Context, dest net.Destination, link *transport.Link) error {
|
||||||
if !isInternalDomain(dest) {
|
if !isInternalDomain(dest) {
|
||||||
if session.InboundFromContext(ctx) == nil {
|
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
Tag: w.tag,
|
||||||
Tag: w.Tag,
|
})
|
||||||
})
|
return w.dispatcher.DispatchLink(ctx, dest, link)
|
||||||
}
|
|
||||||
return w.Dispatcher.DispatchLink(ctx, dest, link)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if d, ok := w.Dispatcher.(routing.WrapLinkDispatcher); ok {
|
|
||||||
link = d.WrapLink(ctx, link)
|
|
||||||
}
|
|
||||||
w.handleInternalConn(link)
|
w.handleInternalConn(link)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
func (c *Control) FillInRandom() {
|
func (c *Control) FillInRandom() {
|
||||||
randomLength := dice.Roll(64)
|
randomLength := dice.Roll(64)
|
||||||
randomLength++
|
|
||||||
c.Random = make([]byte, randomLength)
|
c.Random = make([]byte, randomLength)
|
||||||
io.ReadFull(rand.Reader, c.Random)
|
io.ReadFull(rand.Reader, c.Random)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"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/serial"
|
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/common/signal"
|
|
||||||
"github.com/xtls/xray-core/common/task"
|
"github.com/xtls/xray-core/common/task"
|
||||||
"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"
|
||||||
@@ -83,21 +81,9 @@ func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.picker.AddWorker(worker)
|
p.picker.AddWorker(worker)
|
||||||
|
|
||||||
if _, ok := link.Reader.(*pipe.Reader); !ok {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
case <-muxClient.WaitClosed():
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil && ob.OriginalTarget.Address != ob.Target.Address {
|
|
||||||
link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
|
||||||
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.client.Dispatch(ctx, link)
|
return p.client.Dispatch(ctx, link)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +100,6 @@ func (o *Outbound) Dispatch(ctx context.Context, link *transport.Link) {
|
|||||||
if err := o.portal.HandleConnection(ctx, link); err != nil {
|
if err := o.portal.HandleConnection(ctx, link); err != nil {
|
||||||
errors.LogInfoInner(ctx, err, "failed to process reverse connection")
|
errors.LogInfoInner(ctx, err, "failed to process reverse connection")
|
||||||
common.Interrupt(link.Writer)
|
common.Interrupt(link.Writer)
|
||||||
common.Interrupt(link.Reader)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,16 +111,6 @@ func (o *Outbound) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SenderSettings implements outbound.Handler.
|
|
||||||
func (o *Outbound) SenderSettings() *serial.TypedMessage {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProxySettings implements outbound.Handler.
|
|
||||||
func (o *Outbound) ProxySettings() *serial.TypedMessage {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type StaticMuxPicker struct {
|
type StaticMuxPicker struct {
|
||||||
access sync.Mutex
|
access sync.Mutex
|
||||||
workers []*PortalWorker
|
workers []*PortalWorker
|
||||||
@@ -160,8 +135,6 @@ func (p *StaticMuxPicker) cleanup() error {
|
|||||||
for _, w := range p.workers {
|
for _, w := range p.workers {
|
||||||
if !w.Closed() {
|
if !w.Closed() {
|
||||||
activeWorkers = append(activeWorkers, w)
|
activeWorkers = append(activeWorkers, w)
|
||||||
} else {
|
|
||||||
w.timer.SetTimeout(0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +159,7 @@ func (p *StaticMuxPicker) PickAvailable() (*mux.ClientWorker, error) {
|
|||||||
if w.draining {
|
if w.draining {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if w.IsFull() {
|
if w.client.Closed() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if w.client.ActiveConnections() < minConn {
|
if w.client.ActiveConnections() < minConn {
|
||||||
@@ -227,8 +200,6 @@ type PortalWorker struct {
|
|||||||
writer buf.Writer
|
writer buf.Writer
|
||||||
reader buf.Reader
|
reader buf.Reader
|
||||||
draining bool
|
draining bool
|
||||||
counter uint32
|
|
||||||
timer *signal.ActivityTimer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
||||||
@@ -248,14 +219,10 @@ func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
|||||||
if !f {
|
if !f {
|
||||||
return nil, errors.New("unable to dispatch control connection")
|
return nil, errors.New("unable to dispatch control connection")
|
||||||
}
|
}
|
||||||
terminate := func() {
|
|
||||||
client.Close()
|
|
||||||
}
|
|
||||||
w := &PortalWorker{
|
w := &PortalWorker{
|
||||||
client: client,
|
client: client,
|
||||||
reader: downlinkReader,
|
reader: downlinkReader,
|
||||||
writer: uplinkWriter,
|
writer: uplinkWriter,
|
||||||
timer: signal.CancelAfterInactivity(ctx, terminate, 24*time.Hour), // // prevent leak
|
|
||||||
}
|
}
|
||||||
w.control = &task.Periodic{
|
w.control = &task.Periodic{
|
||||||
Execute: w.heartbeat,
|
Execute: w.heartbeat,
|
||||||
@@ -266,7 +233,7 @@ func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *PortalWorker) heartbeat() error {
|
func (w *PortalWorker) heartbeat() error {
|
||||||
if w.Closed() {
|
if w.client.Closed() {
|
||||||
return errors.New("client worker stopped")
|
return errors.New("client worker stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,15 +255,10 @@ func (w *PortalWorker) heartbeat() error {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
w.counter = (w.counter + 1) % 5
|
b, err := proto.Marshal(msg)
|
||||||
if w.draining || w.counter == 1 {
|
common.Must(err)
|
||||||
b, err := proto.Marshal(msg)
|
mb := buf.MergeBytes(nil, b)
|
||||||
common.Must(err)
|
return w.writer.WriteMultiBuffer(mb)
|
||||||
mb := buf.MergeBytes(nil, b)
|
|
||||||
w.timer.Update()
|
|
||||||
return w.writer.WriteMultiBuffer(mb)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *PortalWorker) IsFull() bool {
|
func (w *PortalWorker) IsFull() bool {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
internalDomain = "reverse"
|
internalDomain = "reverse.internal.v2fly.org" // make reverse proxy compatible with v2fly
|
||||||
)
|
)
|
||||||
|
|
||||||
func isDomain(dest net.Destination, domain string) bool {
|
func isDomain(dest net.Destination, domain string) bool {
|
||||||
|
|||||||
@@ -42,9 +42,6 @@ type RoutingContext struct {
|
|||||||
Attributes map[string]string `protobuf:"bytes,10,rep,name=Attributes,proto3" json:"Attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
Attributes map[string]string `protobuf:"bytes,10,rep,name=Attributes,proto3" json:"Attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
OutboundGroupTags []string `protobuf:"bytes,11,rep,name=OutboundGroupTags,proto3" json:"OutboundGroupTags,omitempty"`
|
OutboundGroupTags []string `protobuf:"bytes,11,rep,name=OutboundGroupTags,proto3" json:"OutboundGroupTags,omitempty"`
|
||||||
OutboundTag string `protobuf:"bytes,12,opt,name=OutboundTag,proto3" json:"OutboundTag,omitempty"`
|
OutboundTag string `protobuf:"bytes,12,opt,name=OutboundTag,proto3" json:"OutboundTag,omitempty"`
|
||||||
LocalIPs [][]byte `protobuf:"bytes,13,rep,name=LocalIPs,proto3" json:"LocalIPs,omitempty"`
|
|
||||||
LocalPort uint32 `protobuf:"varint,14,opt,name=LocalPort,proto3" json:"LocalPort,omitempty"`
|
|
||||||
VlessRoute uint32 `protobuf:"varint,15,opt,name=VlessRoute,proto3" json:"VlessRoute,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RoutingContext) Reset() {
|
func (x *RoutingContext) Reset() {
|
||||||
@@ -161,27 +158,6 @@ func (x *RoutingContext) GetOutboundTag() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RoutingContext) GetLocalIPs() [][]byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.LocalIPs
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RoutingContext) GetLocalPort() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.LocalPort
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RoutingContext) GetVlessRoute() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.VlessRoute
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// SubscribeRoutingStatsRequest subscribes to routing statistics channel if
|
// SubscribeRoutingStatsRequest subscribes to routing statistics channel if
|
||||||
// opened by xray-core.
|
// opened by xray-core.
|
||||||
// * FieldSelectors selects a subset of fields in routing statistics to return.
|
// * FieldSelectors selects a subset of fields in routing statistics to return.
|
||||||
@@ -851,7 +827,7 @@ var file_app_router_command_command_proto_rawDesc = []byte{
|
|||||||
0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e,
|
0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e,
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65,
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 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,
|
0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61,
|
||||||
0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf6, 0x04, 0x0a, 0x0e, 0x52, 0x6f, 0x75,
|
0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9c, 0x04, 0x0a, 0x0e, 0x52, 0x6f, 0x75,
|
||||||
0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x49,
|
0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x49,
|
||||||
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
0x0a, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x32, 0x0a, 0x07, 0x4e,
|
0x0a, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x32, 0x0a, 0x07, 0x4e,
|
||||||
@@ -881,129 +857,123 @@ var file_app_router_command_command_proto_rawDesc = []byte{
|
|||||||
0x03, 0x28, 0x09, 0x52, 0x11, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x47, 0x72, 0x6f,
|
0x03, 0x28, 0x09, 0x52, 0x11, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x47, 0x72, 0x6f,
|
||||||
0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75,
|
0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75,
|
||||||
0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x75, 0x74,
|
0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x75, 0x74,
|
||||||
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61,
|
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72,
|
||||||
0x6c, 0x49, 0x50, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x4c, 0x6f, 0x63, 0x61,
|
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
|
||||||
0x6c, 0x49, 0x50, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72,
|
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
|
||||||
0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f,
|
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
|
||||||
0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x46, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x73, 0x63,
|
||||||
0x18, 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x75,
|
0x72, 0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73,
|
||||||
0x74, 0x65, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64,
|
||||||
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||||
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22,
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
|
0xb1, 0x01, 0x0a, 0x10, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71,
|
||||||
0x01, 0x22, 0x46, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f,
|
0x75, 0x65, 0x73, 0x74, 0x12, 0x4f, 0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43,
|
||||||
0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78,
|
||||||
0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74,
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63,
|
||||||
0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64,
|
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
||||||
0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xb1, 0x01, 0x0a, 0x10, 0x54, 0x65,
|
0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
||||||
0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4f,
|
0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65,
|
||||||
0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
|
0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x24, 0x0a,
|
||||||
|
0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03,
|
||||||
|
0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73,
|
||||||
|
0x75, 0x6c, 0x74, 0x22, 0x27, 0x0a, 0x13, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65,
|
||||||
|
0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
|
||||||
|
0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x26, 0x0a, 0x0c,
|
||||||
|
0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06,
|
||||||
|
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61,
|
||||||
|
0x72, 0x67, 0x65, 0x74, 0x22, 0xa9, 0x01, 0x0a, 0x0b, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65,
|
||||||
|
0x72, 0x4d, 0x73, 0x67, 0x12, 0x41, 0x0a, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
|
||||||
|
0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||||
0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52,
|
0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6f,
|
||||||
0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12,
|
0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x57, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x6e, 0x63,
|
||||||
0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72,
|
0x69, 0x70, 0x6c, 0x65, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28,
|
||||||
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65,
|
0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
|
||||||
0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69,
|
0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x72, 0x69, 0x6e,
|
||||||
0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d,
|
0x63, 0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52,
|
||||||
0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x27, 0x0a,
|
0x0f, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||||
0x13, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
0x22, 0x2a, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49,
|
||||||
0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28,
|
0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
|
||||||
0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x26, 0x0a, 0x0c, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x5b, 0x0a, 0x17,
|
||||||
0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52,
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0xa9,
|
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e,
|
||||||
0x01, 0x0a, 0x0b, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x41,
|
0x63, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
0x0a, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
|
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||||
0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
0x61, 0x6e, 0x64, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x52,
|
||||||
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72,
|
0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x22, 0x59, 0x0a, 0x1d, 0x4f, 0x76, 0x65,
|
||||||
0x69, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
|
0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72,
|
||||||
0x65, 0x12, 0x57, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x74,
|
0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61,
|
||||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72,
|
0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
|
0x0b, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06,
|
||||||
|
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61,
|
||||||
|
0x72, 0x67, 0x65, 0x74, 0x22, 0x20, 0x0a, 0x1e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
|
||||||
|
0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65,
|
||||||
|
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6e, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c,
|
||||||
|
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66,
|
||||||
|
0x69, 0x67, 0x18, 0x01, 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, 0x06, 0x63, 0x6f, 0x6e, 0x66,
|
||||||
|
0x69, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x41, 0x70, 0x70, 0x65,
|
||||||
|
0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64,
|
||||||
|
0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x22, 0x11, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c,
|
||||||
|
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2d, 0x0a, 0x11, 0x52, 0x65, 0x6d,
|
||||||
|
0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18,
|
||||||
|
0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
|
0x07, 0x72, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x67, 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f,
|
||||||
|
0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08,
|
||||||
|
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0xbf, 0x05, 0x0a, 0x0e, 0x52, 0x6f, 0x75,
|
||||||
|
0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7b, 0x0a, 0x15, 0x53,
|
||||||
|
0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53,
|
||||||
|
0x74, 0x61, 0x74, 0x73, 0x12, 0x35, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||||
|
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53,
|
||||||
|
0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53,
|
||||||
|
0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x78, 0x72,
|
||||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f,
|
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f,
|
||||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x54,
|
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
|
||||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x70, 0x72, 0x69, 0x6e, 0x63,
|
0x74, 0x65, 0x78, 0x74, 0x22, 0x00, 0x30, 0x01, 0x12, 0x61, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74,
|
||||||
0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x2a, 0x0a, 0x16, 0x47, 0x65,
|
0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71,
|
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
||||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,
|
0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x5b, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c,
|
0x1a, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||||
0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69,
|
||||||
0x65, 0x12, 0x40, 0x0a, 0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x18, 0x01, 0x20,
|
0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00, 0x12, 0x76, 0x0a, 0x0f, 0x47,
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2f,
|
||||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x42, 0x61,
|
|
||||||
0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x52, 0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e,
|
|
||||||
0x63, 0x65, 0x72, 0x22, 0x59, 0x0a, 0x1d, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42,
|
|
||||||
0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71,
|
|
||||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72,
|
|
||||||
0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x61, 0x6c, 0x61, 0x6e,
|
|
||||||
0x63, 0x65, 0x72, 0x54, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x20,
|
|
||||||
0x0a, 0x1e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63,
|
|
||||||
0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
|
||||||
0x22, 0x6e, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
|
||||||
0x73, 0x74, 0x12, 0x38, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 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, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x22, 0x0a, 0x0c,
|
|
||||||
0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01,
|
|
||||||
0x28, 0x08, 0x52, 0x0c, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64,
|
|
||||||
0x22, 0x11, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
|
||||||
0x6e, 0x73, 0x65, 0x22, 0x2d, 0x0a, 0x11, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c,
|
|
||||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65,
|
|
||||||
0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x54,
|
|
||||||
0x61, 0x67, 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65,
|
|
||||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66,
|
|
||||||
0x69, 0x67, 0x32, 0xbf, 0x05, 0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65,
|
|
||||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7b, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
|
|
||||||
0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x35,
|
|
||||||
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, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
|
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61,
|
||||||
0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65,
|
0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c,
|
||||||
0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00,
|
0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
0x30, 0x01, 0x12, 0x61, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12,
|
0x65, 0x22, 0x00, 0x12, 0x8b, 0x01, 0x0a, 0x16, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
|
||||||
0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x36,
|
||||||
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f,
|
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
||||||
0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x78, 0x72, 0x61,
|
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
|
||||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d,
|
0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52,
|
||||||
0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74,
|
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||||
0x65, 0x78, 0x74, 0x22, 0x00, 0x12, 0x76, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61,
|
|
||||||
0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
|
||||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
|
||||||
0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e,
|
|
||||||
0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
|
||||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
|
||||||
0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49,
|
|
||||||
0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x8b, 0x01,
|
|
||||||
0x0a, 0x16, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63,
|
|
||||||
0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x36, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
|
||||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
|
||||||
0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e,
|
|
||||||
0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
|
||||||
0x1a, 0x37, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
|
||||||
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72,
|
|
||||||
0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65,
|
|
||||||
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x07, 0x41,
|
|
||||||
0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
|
||||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||||
0x2e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65,
|
||||||
0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||||
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c,
|
0x00, 0x12, 0x5e, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x27, 0x2e, 0x78,
|
||||||
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x67, 0x0a, 0x0a, 0x52,
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63,
|
||||||
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65,
|
||||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65,
|
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
|
||||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
||||||
0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||||
0x73, 0x65, 0x22, 0x00, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
0x00, 0x12, 0x67, 0x0a, 0x0a, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x12,
|
||||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||||
0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
||||||
0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65,
|
0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x78, 0x72,
|
||||||
0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
|
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f,
|
||||||
0x61, 0x6e, 0x64, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52,
|
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65,
|
||||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70,
|
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f,
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||||
|
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74,
|
||||||
|
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
|
||||||
|
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||||
|
0x72, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79,
|
||||||
|
0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,
|
||||||
|
0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -25,9 +25,6 @@ message RoutingContext {
|
|||||||
map<string, string> Attributes = 10;
|
map<string, string> Attributes = 10;
|
||||||
repeated string OutboundGroupTags = 11;
|
repeated string OutboundGroupTags = 11;
|
||||||
string OutboundTag = 12;
|
string OutboundTag = 12;
|
||||||
repeated bytes LocalIPs = 13;
|
|
||||||
uint32 LocalPort = 14;
|
|
||||||
uint32 VlessRoute = 15;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscribeRoutingStatsRequest subscribes to routing statistics channel if
|
// SubscribeRoutingStatsRequest subscribes to routing statistics channel if
|
||||||
|
|||||||
@@ -28,18 +28,6 @@ func (c routingContext) GetTargetPort() net.Port {
|
|||||||
return net.Port(c.RoutingContext.GetTargetPort())
|
return net.Port(c.RoutingContext.GetTargetPort())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c routingContext) GetLocalIPs() []net.IP {
|
|
||||||
return mapBytesToIPs(c.RoutingContext.GetLocalIPs())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c routingContext) GetLocalPort() net.Port {
|
|
||||||
return net.Port(c.RoutingContext.GetLocalPort())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c routingContext) GetVlessRoute() net.Port {
|
|
||||||
return net.Port(c.RoutingContext.GetVlessRoute())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c routingContext) GetRuleTag() string {
|
func (c routingContext) GetRuleTag() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -66,10 +54,8 @@ var fieldMap = map[string]func(*RoutingContext, routing.Route){
|
|||||||
"network": func(s *RoutingContext, r routing.Route) { s.Network = r.GetNetwork() },
|
"network": func(s *RoutingContext, r routing.Route) { s.Network = r.GetNetwork() },
|
||||||
"ip_source": func(s *RoutingContext, r routing.Route) { s.SourceIPs = mapIPsToBytes(r.GetSourceIPs()) },
|
"ip_source": func(s *RoutingContext, r routing.Route) { s.SourceIPs = mapIPsToBytes(r.GetSourceIPs()) },
|
||||||
"ip_target": func(s *RoutingContext, r routing.Route) { s.TargetIPs = mapIPsToBytes(r.GetTargetIPs()) },
|
"ip_target": func(s *RoutingContext, r routing.Route) { s.TargetIPs = mapIPsToBytes(r.GetTargetIPs()) },
|
||||||
"ip_local": func(s *RoutingContext, r routing.Route) { s.LocalIPs = mapIPsToBytes(r.GetLocalIPs()) },
|
|
||||||
"port_source": func(s *RoutingContext, r routing.Route) { s.SourcePort = uint32(r.GetSourcePort()) },
|
"port_source": func(s *RoutingContext, r routing.Route) { s.SourcePort = uint32(r.GetSourcePort()) },
|
||||||
"port_target": func(s *RoutingContext, r routing.Route) { s.TargetPort = uint32(r.GetTargetPort()) },
|
"port_target": func(s *RoutingContext, r routing.Route) { s.TargetPort = uint32(r.GetTargetPort()) },
|
||||||
"port_local": func(s *RoutingContext, r routing.Route) { s.LocalPort = uint32(r.GetLocalPort()) },
|
|
||||||
"domain": func(s *RoutingContext, r routing.Route) { s.TargetDomain = r.GetTargetDomain() },
|
"domain": func(s *RoutingContext, r routing.Route) { s.TargetDomain = r.GetTargetDomain() },
|
||||||
"protocol": func(s *RoutingContext, r routing.Route) { s.Protocol = r.GetProtocol() },
|
"protocol": func(s *RoutingContext, r routing.Route) { s.Protocol = r.GetProtocol() },
|
||||||
"user": func(s *RoutingContext, r routing.Route) { s.User = r.GetUser() },
|
"user": func(s *RoutingContext, r routing.Route) { s.User = r.GetUser() },
|
||||||
|
|||||||
@@ -47,6 +47,20 @@ var matcherTypeMap = map[Domain_Type]strmatcher.Type{
|
|||||||
Domain_Full: strmatcher.Full,
|
Domain_Full: strmatcher.Full,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func domainToMatcher(domain *Domain) (strmatcher.Matcher, error) {
|
||||||
|
matcherType, f := matcherTypeMap[domain.Type]
|
||||||
|
if !f {
|
||||||
|
return nil, errors.New("unsupported domain type", domain.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
matcher, err := matcherType.New(domain.Value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to create domain matcher").Base(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return matcher, nil
|
||||||
|
}
|
||||||
|
|
||||||
type DomainMatcher struct {
|
type DomainMatcher struct {
|
||||||
matchers strmatcher.IndexMatcher
|
matchers strmatcher.IndexMatcher
|
||||||
}
|
}
|
||||||
@@ -69,6 +83,21 @@ func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
|
||||||
|
g := new(strmatcher.MatcherGroup)
|
||||||
|
for _, d := range domains {
|
||||||
|
m, err := domainToMatcher(d)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
g.Add(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &DomainMatcher{
|
||||||
|
matchers: g,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *DomainMatcher) ApplyDomain(domain string) bool {
|
func (m *DomainMatcher) ApplyDomain(domain string) bool {
|
||||||
return len(m.matchers.Match(strings.ToLower(domain))) > 0
|
return len(m.matchers.Match(strings.ToLower(domain))) > 0
|
||||||
}
|
}
|
||||||
@@ -82,72 +111,66 @@ func (m *DomainMatcher) Apply(ctx routing.Context) bool {
|
|||||||
return m.ApplyDomain(domain)
|
return m.ApplyDomain(domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
type MatcherAsType byte
|
type MultiGeoIPMatcher struct {
|
||||||
|
matchers []*GeoIPMatcher
|
||||||
const (
|
onSource bool
|
||||||
MatcherAsType_Local MatcherAsType = iota
|
|
||||||
MatcherAsType_Source
|
|
||||||
MatcherAsType_Target
|
|
||||||
MatcherAsType_VlessRoute // for port
|
|
||||||
)
|
|
||||||
|
|
||||||
type IPMatcher struct {
|
|
||||||
matcher GeoIPMatcher
|
|
||||||
asType MatcherAsType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIPMatcher(geoips []*GeoIP, asType MatcherAsType) (*IPMatcher, error) {
|
func NewMultiGeoIPMatcher(geoips []*GeoIP, onSource bool) (*MultiGeoIPMatcher, error) {
|
||||||
matcher, err := BuildOptimizedGeoIPMatcher(geoips...)
|
var matchers []*GeoIPMatcher
|
||||||
if err != nil {
|
for _, geoip := range geoips {
|
||||||
return nil, err
|
matcher, err := globalGeoIPContainer.Add(geoip)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
matchers = append(matchers, matcher)
|
||||||
}
|
}
|
||||||
return &IPMatcher{matcher: matcher, asType: asType}, nil
|
|
||||||
|
matcher := &MultiGeoIPMatcher{
|
||||||
|
matchers: matchers,
|
||||||
|
onSource: onSource,
|
||||||
|
}
|
||||||
|
|
||||||
|
return matcher, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply implements Condition.
|
// Apply implements Condition.
|
||||||
func (m *IPMatcher) Apply(ctx routing.Context) bool {
|
func (m *MultiGeoIPMatcher) Apply(ctx routing.Context) bool {
|
||||||
var ips []net.IP
|
var ips []net.IP
|
||||||
|
if m.onSource {
|
||||||
switch m.asType {
|
|
||||||
case MatcherAsType_Local:
|
|
||||||
ips = ctx.GetLocalIPs()
|
|
||||||
case MatcherAsType_Source:
|
|
||||||
ips = ctx.GetSourceIPs()
|
ips = ctx.GetSourceIPs()
|
||||||
case MatcherAsType_Target:
|
} else {
|
||||||
ips = ctx.GetTargetIPs()
|
ips = ctx.GetTargetIPs()
|
||||||
default:
|
|
||||||
panic("unk asType")
|
|
||||||
}
|
}
|
||||||
|
for _, ip := range ips {
|
||||||
return m.matcher.AnyMatch(ips)
|
for _, matcher := range m.matchers {
|
||||||
|
if matcher.Match(ip) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type PortMatcher struct {
|
type PortMatcher struct {
|
||||||
port net.MemoryPortList
|
port net.MemoryPortList
|
||||||
asType MatcherAsType
|
onSource bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPortMatcher create a new port matcher that can match source or local or destination port
|
// NewPortMatcher create a new port matcher that can match source or destination port
|
||||||
func NewPortMatcher(list *net.PortList, asType MatcherAsType) *PortMatcher {
|
func NewPortMatcher(list *net.PortList, onSource bool) *PortMatcher {
|
||||||
return &PortMatcher{
|
return &PortMatcher{
|
||||||
port: net.PortListFromProto(list),
|
port: net.PortListFromProto(list),
|
||||||
asType: asType,
|
onSource: onSource,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply implements Condition.
|
// Apply implements Condition.
|
||||||
func (v *PortMatcher) Apply(ctx routing.Context) bool {
|
func (v *PortMatcher) Apply(ctx routing.Context) bool {
|
||||||
switch v.asType {
|
if v.onSource {
|
||||||
case MatcherAsType_Local:
|
|
||||||
return v.port.Contains(ctx.GetLocalPort())
|
|
||||||
case MatcherAsType_Source:
|
|
||||||
return v.port.Contains(ctx.GetSourcePort())
|
return v.port.Contains(ctx.GetSourcePort())
|
||||||
case MatcherAsType_Target:
|
} else {
|
||||||
return v.port.Contains(ctx.GetTargetPort())
|
return v.port.Contains(ctx.GetTargetPort())
|
||||||
case MatcherAsType_VlessRoute:
|
|
||||||
return v.port.Contains(ctx.GetVlessRoute())
|
|
||||||
default:
|
|
||||||
panic("unk asType")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,33 @@ func getAssetPath(file string) (string, error) {
|
|||||||
return path, nil
|
return path, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGeoIPMatcherContainer(t *testing.T) {
|
||||||
|
container := &router.GeoIPMatcherContainer{}
|
||||||
|
|
||||||
|
m1, err := container.Add(&router.GeoIP{
|
||||||
|
CountryCode: "CN",
|
||||||
|
})
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
m2, err := container.Add(&router.GeoIP{
|
||||||
|
CountryCode: "US",
|
||||||
|
})
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
m3, err := container.Add(&router.GeoIP{
|
||||||
|
CountryCode: "CN",
|
||||||
|
})
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
if m1 != m3 {
|
||||||
|
t.Error("expect same matcher for same geoip, but not")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m1 == m2 {
|
||||||
|
t.Error("expect different matcher for different geoip, but actually same")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGeoIPMatcher(t *testing.T) {
|
func TestGeoIPMatcher(t *testing.T) {
|
||||||
cidrList := []*router.CIDR{
|
cidrList := []*router.CIDR{
|
||||||
{Ip: []byte{0, 0, 0, 0}, Prefix: 8},
|
{Ip: []byte{0, 0, 0, 0}, Prefix: 8},
|
||||||
@@ -53,10 +80,8 @@ func TestGeoIPMatcher(t *testing.T) {
|
|||||||
{Ip: []byte{91, 108, 4, 0}, Prefix: 16},
|
{Ip: []byte{91, 108, 4, 0}, Prefix: 16},
|
||||||
}
|
}
|
||||||
|
|
||||||
matcher, err := router.BuildOptimizedGeoIPMatcher(&router.GeoIP{
|
matcher := &router.GeoIPMatcher{}
|
||||||
Cidr: cidrList,
|
common.Must(matcher.Init(cidrList))
|
||||||
})
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Input string
|
Input string
|
||||||
@@ -115,10 +140,8 @@ func TestGeoIPMatcherRegression(t *testing.T) {
|
|||||||
{Ip: []byte{98, 108, 20, 0}, Prefix: 23},
|
{Ip: []byte{98, 108, 20, 0}, Prefix: 23},
|
||||||
}
|
}
|
||||||
|
|
||||||
matcher, err := router.BuildOptimizedGeoIPMatcher(&router.GeoIP{
|
matcher := &router.GeoIPMatcher{}
|
||||||
Cidr: cidrList,
|
common.Must(matcher.Init(cidrList))
|
||||||
})
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Input string
|
Input string
|
||||||
@@ -148,11 +171,9 @@ func TestGeoIPReverseMatcher(t *testing.T) {
|
|||||||
{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},
|
||||||
}
|
}
|
||||||
matcher, err := router.BuildOptimizedGeoIPMatcher(&router.GeoIP{
|
matcher := &router.GeoIPMatcher{}
|
||||||
Cidr: cidrList,
|
matcher.SetReverseMatch(true) // Reverse match
|
||||||
})
|
common.Must(matcher.Init(cidrList))
|
||||||
common.Must(err)
|
|
||||||
matcher.SetReverse(true) // Reverse match
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Input string
|
Input string
|
||||||
@@ -185,10 +206,8 @@ func TestGeoIPMatcher4CN(t *testing.T) {
|
|||||||
ips, err := loadGeoIP("CN")
|
ips, err := loadGeoIP("CN")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
matcher, err := router.BuildOptimizedGeoIPMatcher(&router.GeoIP{
|
matcher := &router.GeoIPMatcher{}
|
||||||
Cidr: ips,
|
common.Must(matcher.Init(ips))
|
||||||
})
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
if matcher.Match([]byte{8, 8, 8, 8}) {
|
if matcher.Match([]byte{8, 8, 8, 8}) {
|
||||||
t.Error("expect CN geoip doesn't contain 8.8.8.8, but actually does")
|
t.Error("expect CN geoip doesn't contain 8.8.8.8, but actually does")
|
||||||
@@ -199,10 +218,8 @@ func TestGeoIPMatcher6US(t *testing.T) {
|
|||||||
ips, err := loadGeoIP("US")
|
ips, err := loadGeoIP("US")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
matcher, err := router.BuildOptimizedGeoIPMatcher(&router.GeoIP{
|
matcher := &router.GeoIPMatcher{}
|
||||||
Cidr: ips,
|
common.Must(matcher.Init(ips))
|
||||||
})
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
if !matcher.Match(net.ParseAddress("2001:4860:4860::8888").IP()) {
|
if !matcher.Match(net.ParseAddress("2001:4860:4860::8888").IP()) {
|
||||||
t.Error("expect US geoip contain 2001:4860:4860::8888, but actually not")
|
t.Error("expect US geoip contain 2001:4860:4860::8888, but actually not")
|
||||||
@@ -237,10 +254,8 @@ func BenchmarkGeoIPMatcher4CN(b *testing.B) {
|
|||||||
ips, err := loadGeoIP("CN")
|
ips, err := loadGeoIP("CN")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
matcher, err := router.BuildOptimizedGeoIPMatcher(&router.GeoIP{
|
matcher := &router.GeoIPMatcher{}
|
||||||
Cidr: ips,
|
common.Must(matcher.Init(ips))
|
||||||
})
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
||||||
@@ -253,10 +268,8 @@ func BenchmarkGeoIPMatcher6US(b *testing.B) {
|
|||||||
ips, err := loadGeoIP("US")
|
ips, err := loadGeoIP("US")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
matcher, err := router.BuildOptimizedGeoIPMatcher(&router.GeoIP{
|
matcher := &router.GeoIPMatcher{}
|
||||||
Cidr: ips,
|
common.Must(matcher.Init(ips))
|
||||||
})
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
||||||
|
|||||||
@@ -328,6 +328,9 @@ func TestChinaSites(t *testing.T) {
|
|||||||
domains, err := loadGeoSite("CN")
|
domains, err := loadGeoSite("CN")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
|
matcher, err := NewDomainMatcher(domains)
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
acMatcher, err := NewMphMatcherGroup(domains)
|
acMatcher, err := NewMphMatcherGroup(domains)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
@@ -359,9 +362,12 @@ func TestChinaSites(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
r := acMatcher.ApplyDomain(testCase.Domain)
|
r1 := matcher.ApplyDomain(testCase.Domain)
|
||||||
if r != testCase.Output {
|
r2 := acMatcher.ApplyDomain(testCase.Domain)
|
||||||
t.Error("ACDomainMatcher expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r)
|
if r1 != testCase.Output {
|
||||||
|
t.Error("DomainMatcher expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r1)
|
||||||
|
} else if r2 != testCase.Output {
|
||||||
|
t.Error("ACDomainMatcher expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -408,6 +414,48 @@ func BenchmarkMphDomainMatcher(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkDomainMatcher(b *testing.B) {
|
||||||
|
domains, err := loadGeoSite("CN")
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
matcher, err := NewDomainMatcher(domains)
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
type TestCase struct {
|
||||||
|
Domain string
|
||||||
|
Output bool
|
||||||
|
}
|
||||||
|
testCases := []TestCase{
|
||||||
|
{
|
||||||
|
Domain: "163.com",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Domain: "163.com",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Domain: "164.com",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Domain: "164.com",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 1024; i++ {
|
||||||
|
testCases = append(testCases, TestCase{Domain: strconv.Itoa(i) + ".not-exists.com", Output: false})
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
_ = matcher.ApplyDomain(testCase.Domain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkMultiGeoIPMatcher(b *testing.B) {
|
func BenchmarkMultiGeoIPMatcher(b *testing.B) {
|
||||||
var geoips []*GeoIP
|
var geoips []*GeoIP
|
||||||
|
|
||||||
@@ -447,7 +495,7 @@ func BenchmarkMultiGeoIPMatcher(b *testing.B) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
matcher, err := NewIPMatcher(geoips, MatcherAsType_Target)
|
matcher, err := NewMultiGeoIPMatcher(geoips, false)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)})
|
ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)})
|
||||||
|
|||||||
@@ -32,38 +32,66 @@ func (r *Rule) Apply(ctx routing.Context) bool {
|
|||||||
func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||||
conds := NewConditionChan()
|
conds := NewConditionChan()
|
||||||
|
|
||||||
|
if len(rr.Domain) > 0 {
|
||||||
|
switch rr.DomainMatcher {
|
||||||
|
case "linear":
|
||||||
|
matcher, err := NewDomainMatcher(rr.Domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to build domain condition").Base(err)
|
||||||
|
}
|
||||||
|
conds.Add(matcher)
|
||||||
|
case "mph", "hybrid":
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
matcher, err := NewMphMatcherGroup(rr.Domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to build domain condition with MphDomainMatcher").Base(err)
|
||||||
|
}
|
||||||
|
errors.LogDebug(context.Background(), "MphDomainMatcher is enabled for ", len(rr.Domain), " domain rule(s)")
|
||||||
|
conds.Add(matcher)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rr.UserEmail) > 0 {
|
||||||
|
conds.Add(NewUserMatcher(rr.UserEmail))
|
||||||
|
}
|
||||||
|
|
||||||
if len(rr.InboundTag) > 0 {
|
if len(rr.InboundTag) > 0 {
|
||||||
conds.Add(NewInboundTagMatcher(rr.InboundTag))
|
conds.Add(NewInboundTagMatcher(rr.InboundTag))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if rr.PortList != nil {
|
||||||
|
conds.Add(NewPortMatcher(rr.PortList, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
if rr.SourcePortList != nil {
|
||||||
|
conds.Add(NewPortMatcher(rr.SourcePortList, true))
|
||||||
|
}
|
||||||
|
|
||||||
if len(rr.Networks) > 0 {
|
if len(rr.Networks) > 0 {
|
||||||
conds.Add(NewNetworkMatcher(rr.Networks))
|
conds.Add(NewNetworkMatcher(rr.Networks))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(rr.Geoip) > 0 {
|
||||||
|
cond, err := NewMultiGeoIPMatcher(rr.Geoip, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conds.Add(cond)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rr.SourceGeoip) > 0 {
|
||||||
|
cond, err := NewMultiGeoIPMatcher(rr.SourceGeoip, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conds.Add(cond)
|
||||||
|
}
|
||||||
|
|
||||||
if len(rr.Protocol) > 0 {
|
if len(rr.Protocol) > 0 {
|
||||||
conds.Add(NewProtocolMatcher(rr.Protocol))
|
conds.Add(NewProtocolMatcher(rr.Protocol))
|
||||||
}
|
}
|
||||||
|
|
||||||
if rr.PortList != nil {
|
|
||||||
conds.Add(NewPortMatcher(rr.PortList, MatcherAsType_Target))
|
|
||||||
}
|
|
||||||
|
|
||||||
if rr.SourcePortList != nil {
|
|
||||||
conds.Add(NewPortMatcher(rr.SourcePortList, MatcherAsType_Source))
|
|
||||||
}
|
|
||||||
|
|
||||||
if rr.LocalPortList != nil {
|
|
||||||
conds.Add(NewPortMatcher(rr.LocalPortList, MatcherAsType_Local))
|
|
||||||
}
|
|
||||||
|
|
||||||
if rr.VlessRouteList != nil {
|
|
||||||
conds.Add(NewPortMatcher(rr.VlessRouteList, MatcherAsType_VlessRoute))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rr.UserEmail) > 0 {
|
|
||||||
conds.Add(NewUserMatcher(rr.UserEmail))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rr.Attributes) > 0 {
|
if len(rr.Attributes) > 0 {
|
||||||
configuredKeys := make(map[string]*regexp.Regexp)
|
configuredKeys := make(map[string]*regexp.Regexp)
|
||||||
for key, value := range rr.Attributes {
|
for key, value := range rr.Attributes {
|
||||||
@@ -72,40 +100,6 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
|||||||
conds.Add(&AttributeMatcher{configuredKeys})
|
conds.Add(&AttributeMatcher{configuredKeys})
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rr.Geoip) > 0 {
|
|
||||||
cond, err := NewIPMatcher(rr.Geoip, MatcherAsType_Target)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conds.Add(cond)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rr.SourceGeoip) > 0 {
|
|
||||||
cond, err := NewIPMatcher(rr.SourceGeoip, MatcherAsType_Source)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conds.Add(cond)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rr.LocalGeoip) > 0 {
|
|
||||||
cond, err := NewIPMatcher(rr.LocalGeoip, MatcherAsType_Local)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conds.Add(cond)
|
|
||||||
errors.LogWarning(context.Background(), "Due to some limitations, in UDP connections, localIP is always equal to listen interface IP, so \"localIP\" rule condition does not work properly on UDP inbound connections that listen on all interfaces")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rr.Domain) > 0 {
|
|
||||||
matcher, err := NewMphMatcherGroup(rr.Domain)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("failed to build domain condition with MphDomainMatcher").Base(err)
|
|
||||||
}
|
|
||||||
errors.LogDebug(context.Background(), "MphDomainMatcher is enabled for ", len(rr.Domain), " domain rule(s)")
|
|
||||||
conds.Add(matcher)
|
|
||||||
}
|
|
||||||
|
|
||||||
if conds.Len() == 0 {
|
if conds.Len() == 0 {
|
||||||
return nil, errors.New("this rule has no effective fields").AtWarning()
|
return nil, errors.New("this rule has no effective fields").AtWarning()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,8 @@ type Config_DomainStrategy int32
|
|||||||
const (
|
const (
|
||||||
// Use domain as is.
|
// Use domain as is.
|
||||||
Config_AsIs Config_DomainStrategy = 0
|
Config_AsIs Config_DomainStrategy = 0
|
||||||
|
// Always resolve IP for domains.
|
||||||
|
Config_UseIp Config_DomainStrategy = 1
|
||||||
// Resolve to IP if the domain doesn't match any rules.
|
// Resolve to IP if the domain doesn't match any rules.
|
||||||
Config_IpIfNonMatch Config_DomainStrategy = 2
|
Config_IpIfNonMatch Config_DomainStrategy = 2
|
||||||
// Resolve to IP if any rule requires IP matching.
|
// Resolve to IP if any rule requires IP matching.
|
||||||
@@ -94,11 +96,13 @@ const (
|
|||||||
var (
|
var (
|
||||||
Config_DomainStrategy_name = map[int32]string{
|
Config_DomainStrategy_name = map[int32]string{
|
||||||
0: "AsIs",
|
0: "AsIs",
|
||||||
|
1: "UseIp",
|
||||||
2: "IpIfNonMatch",
|
2: "IpIfNonMatch",
|
||||||
3: "IpOnDemand",
|
3: "IpOnDemand",
|
||||||
}
|
}
|
||||||
Config_DomainStrategy_value = map[string]int32{
|
Config_DomainStrategy_value = map[string]int32{
|
||||||
"AsIs": 0,
|
"AsIs": 0,
|
||||||
|
"UseIp": 1,
|
||||||
"IpIfNonMatch": 2,
|
"IpIfNonMatch": 2,
|
||||||
"IpOnDemand": 3,
|
"IpOnDemand": 3,
|
||||||
}
|
}
|
||||||
@@ -466,7 +470,7 @@ type RoutingRule struct {
|
|||||||
// *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,19,opt,name=rule_tag,json=ruleTag,proto3" json:"rule_tag,omitempty"`
|
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 GeoIPs for target IP address matching. If this entry exists, the
|
// List of GeoIPs for target IP address matching. If this entry exists, the
|
||||||
@@ -487,9 +491,7 @@ type RoutingRule struct {
|
|||||||
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 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"`
|
||||||
LocalGeoip []*GeoIP `protobuf:"bytes,17,rep,name=local_geoip,json=localGeoip,proto3" json:"local_geoip,omitempty"`
|
DomainMatcher string `protobuf:"bytes,17,opt,name=domain_matcher,json=domainMatcher,proto3" json:"domain_matcher,omitempty"`
|
||||||
LocalPortList *net.PortList `protobuf:"bytes,18,opt,name=local_port_list,json=localPortList,proto3" json:"local_port_list,omitempty"`
|
|
||||||
VlessRouteList *net.PortList `protobuf:"bytes,20,opt,name=vless_route_list,json=vlessRouteList,proto3" json:"vless_route_list,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RoutingRule) Reset() {
|
func (x *RoutingRule) Reset() {
|
||||||
@@ -620,25 +622,11 @@ func (x *RoutingRule) GetAttributes() map[string]string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RoutingRule) GetLocalGeoip() []*GeoIP {
|
func (x *RoutingRule) GetDomainMatcher() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.LocalGeoip
|
return x.DomainMatcher
|
||||||
}
|
}
|
||||||
return nil
|
return ""
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RoutingRule) GetLocalPortList() *net.PortList {
|
|
||||||
if x != nil {
|
|
||||||
return x.LocalPortList
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RoutingRule) GetVlessRouteList() *net.PortList {
|
|
||||||
if x != nil {
|
|
||||||
return x.VlessRouteList
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type isRoutingRule_TargetTag interface {
|
type isRoutingRule_TargetTag interface {
|
||||||
@@ -1081,13 +1069,13 @@ var file_app_router_config_proto_rawDesc = []byte{
|
|||||||
0x6f, 0x53, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x05, 0x65, 0x6e, 0x74,
|
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,
|
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,
|
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, 0xe8, 0x06, 0x0a, 0x0b, 0x52, 0x6f,
|
0x74, 0x65, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xce, 0x05, 0x0a, 0x0b, 0x52, 0x6f,
|
||||||
0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x03, 0x74, 0x61, 0x67,
|
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,
|
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,
|
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,
|
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,
|
0x67, 0x54, 0x61, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x61, 0x67,
|
||||||
0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x67, 0x12,
|
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,
|
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,
|
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,
|
0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||||
@@ -1119,78 +1107,69 @@ var file_app_router_config_proto_rawDesc = []byte{
|
|||||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52,
|
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,
|
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,
|
0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72,
|
||||||
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f,
|
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||||
0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x11, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72,
|
0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
|
||||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65,
|
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x1a, 0x3d, 0x0a,
|
||||||
0x6f, 0x49, 0x50, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12,
|
0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
|
||||||
0x41, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69,
|
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
|
||||||
0x73, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4c,
|
0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0c, 0x0a, 0x0a,
|
||||||
0x69, 0x73, 0x74, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69,
|
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x22, 0xdc, 0x01, 0x0a, 0x0d, 0x42,
|
||||||
0x73, 0x74, 0x12, 0x43, 0x0a, 0x10, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x5f, 0x72, 0x6f, 0x75, 0x74,
|
0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03,
|
||||||
0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78,
|
0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50,
|
0x0a, 0x11, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63,
|
||||||
0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x6f,
|
0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f,
|
||||||
0x75, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69,
|
0x75, 0x6e, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73,
|
||||||
0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
|
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73,
|
||||||
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
|
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4d, 0x0a, 0x11, 0x73, 0x74, 0x72, 0x61, 0x74,
|
||||||
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
|
0x65, 0x67, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01,
|
||||||
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||||
0x5f, 0x74, 0x61, 0x67, 0x22, 0xdc, 0x01, 0x0a, 0x0d, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69,
|
0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73,
|
||||||
0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20,
|
0x73, 0x61, 0x67, 0x65, 0x52, 0x10, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x53, 0x65,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x62,
|
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61,
|
||||||
0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20,
|
0x63, 0x6b, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x66, 0x61,
|
||||||
0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x65, 0x6c,
|
0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x54, 0x61, 0x67, 0x22, 0x54, 0x0a, 0x0e, 0x53, 0x74, 0x72,
|
||||||
0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
|
0x61, 0x74, 0x65, 0x67, 0x79, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72,
|
||||||
0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
|
0x65, 0x67, 0x65, 0x78, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x67,
|
||||||
0x79, 0x12, 0x4d, 0x0a, 0x11, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x5f, 0x73, 0x65,
|
0x65, 0x78, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01,
|
||||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78,
|
0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61,
|
0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,
|
||||||
0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x10,
|
0xc0, 0x01, 0x0a, 0x17, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x4c, 0x65, 0x61, 0x73,
|
||||||
0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
0x74, 0x4c, 0x6f, 0x61, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x05, 0x63,
|
||||||
0x12, 0x21, 0x0a, 0x0c, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x61, 0x67,
|
0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61,
|
||||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
|
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x72,
|
||||||
0x54, 0x61, 0x67, 0x22, 0x54, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x57,
|
0x61, 0x74, 0x65, 0x67, 0x79, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x05, 0x63, 0x6f, 0x73,
|
||||||
0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x18,
|
0x74, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x12, 0x14, 0x0a,
|
0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x09, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73,
|
||||||
0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61,
|
0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01,
|
||||||
0x74, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01,
|
0x28, 0x05, 0x52, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06,
|
||||||
0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xc0, 0x01, 0x0a, 0x17, 0x53, 0x74,
|
0x6d, 0x61, 0x78, 0x52, 0x54, 0x54, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6d, 0x61,
|
||||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x4c, 0x6f, 0x61, 0x64, 0x43,
|
0x78, 0x52, 0x54, 0x54, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63,
|
||||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x05, 0x63, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02,
|
0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e,
|
||||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
0x63, 0x65, 0x22, 0x9b, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4f, 0x0a,
|
||||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x57,
|
0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||||
0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x05, 0x63, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1c, 0x0a, 0x09,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||||
0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52,
|
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
|
||||||
0x09, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78,
|
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e,
|
||||||
0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x65, 0x78,
|
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x30,
|
||||||
0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x78, 0x52, 0x54, 0x54,
|
0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78,
|
||||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6d, 0x61, 0x78, 0x52, 0x54, 0x54, 0x12, 0x1c,
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52,
|
||||||
0x0a, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28,
|
0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65,
|
||||||
0x02, 0x52, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x90, 0x02, 0x0a,
|
0x12, 0x45, 0x0a, 0x0e, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75,
|
||||||
0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4f, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69,
|
0x6c, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
|
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e,
|
||||||
0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63,
|
||||||
0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x22, 0x47, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||||
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49,
|
||||||
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x30, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65,
|
0x73, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x49, 0x70, 0x10, 0x01, 0x12, 0x10,
|
||||||
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
0x0a, 0x0c, 0x49, 0x70, 0x49, 0x66, 0x4e, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x02,
|
||||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67,
|
0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x70, 0x4f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x10, 0x03,
|
||||||
0x52, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x45, 0x0a, 0x0e, 0x62, 0x61,
|
0x42, 0x4f, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x03,
|
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||||
0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
|
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d,
|
||||||
0x75, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75,
|
0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0xaa,
|
||||||
0x6c, 0x65, 0x52, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c,
|
0x02, 0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
||||||
0x65, 0x22, 0x3c, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74,
|
0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49, 0x73, 0x10, 0x00, 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 (
|
||||||
@@ -1241,19 +1220,16 @@ var file_app_router_config_proto_depIdxs = []int32{
|
|||||||
4, // 10: xray.app.router.RoutingRule.source_geoip:type_name -> xray.app.router.GeoIP
|
4, // 10: xray.app.router.RoutingRule.source_geoip:type_name -> xray.app.router.GeoIP
|
||||||
15, // 11: xray.app.router.RoutingRule.source_port_list:type_name -> xray.common.net.PortList
|
15, // 11: xray.app.router.RoutingRule.source_port_list:type_name -> xray.common.net.PortList
|
||||||
14, // 12: xray.app.router.RoutingRule.attributes:type_name -> xray.app.router.RoutingRule.AttributesEntry
|
14, // 12: xray.app.router.RoutingRule.attributes:type_name -> xray.app.router.RoutingRule.AttributesEntry
|
||||||
4, // 13: xray.app.router.RoutingRule.local_geoip:type_name -> xray.app.router.GeoIP
|
17, // 13: xray.app.router.BalancingRule.strategy_settings:type_name -> xray.common.serial.TypedMessage
|
||||||
15, // 14: xray.app.router.RoutingRule.local_port_list:type_name -> xray.common.net.PortList
|
10, // 14: xray.app.router.StrategyLeastLoadConfig.costs:type_name -> xray.app.router.StrategyWeight
|
||||||
15, // 15: xray.app.router.RoutingRule.vless_route_list:type_name -> xray.common.net.PortList
|
1, // 15: xray.app.router.Config.domain_strategy:type_name -> xray.app.router.Config.DomainStrategy
|
||||||
17, // 16: xray.app.router.BalancingRule.strategy_settings:type_name -> xray.common.serial.TypedMessage
|
8, // 16: xray.app.router.Config.rule:type_name -> xray.app.router.RoutingRule
|
||||||
10, // 17: xray.app.router.StrategyLeastLoadConfig.costs:type_name -> xray.app.router.StrategyWeight
|
9, // 17: xray.app.router.Config.balancing_rule:type_name -> xray.app.router.BalancingRule
|
||||||
1, // 18: xray.app.router.Config.domain_strategy:type_name -> xray.app.router.Config.DomainStrategy
|
18, // [18:18] is the sub-list for method output_type
|
||||||
8, // 19: xray.app.router.Config.rule:type_name -> xray.app.router.RoutingRule
|
18, // [18:18] is the sub-list for method input_type
|
||||||
9, // 20: xray.app.router.Config.balancing_rule:type_name -> xray.app.router.BalancingRule
|
18, // [18:18] is the sub-list for extension type_name
|
||||||
21, // [21:21] is the sub-list for method output_type
|
18, // [18:18] is the sub-list for extension extendee
|
||||||
21, // [21:21] is the sub-list for method input_type
|
0, // [0:18] is the sub-list for field type_name
|
||||||
21, // [21:21] is the sub-list for extension type_name
|
|
||||||
21, // [21:21] is the sub-list for extension extendee
|
|
||||||
0, // [0:21] is the sub-list for field type_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_router_config_proto_init() }
|
func init() { file_app_router_config_proto_init() }
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ message RoutingRule {
|
|||||||
// Tag of routing balancer.
|
// Tag of routing balancer.
|
||||||
string balancing_tag = 12;
|
string balancing_tag = 12;
|
||||||
}
|
}
|
||||||
string rule_tag = 19;
|
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;
|
||||||
@@ -109,10 +109,7 @@ message RoutingRule {
|
|||||||
|
|
||||||
map<string, string> attributes = 15;
|
map<string, string> attributes = 15;
|
||||||
|
|
||||||
repeated GeoIP local_geoip = 17;
|
string domain_matcher = 17;
|
||||||
xray.common.net.PortList local_port_list = 18;
|
|
||||||
|
|
||||||
xray.common.net.PortList vless_route_list = 20;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message BalancingRule {
|
message BalancingRule {
|
||||||
@@ -147,8 +144,8 @@ message Config {
|
|||||||
// Use domain as is.
|
// Use domain as is.
|
||||||
AsIs = 0;
|
AsIs = 0;
|
||||||
|
|
||||||
// [Deprecated] Always resolve IP for domains.
|
// Always resolve IP for domains.
|
||||||
// UseIp = 1;
|
UseIp = 1;
|
||||||
|
|
||||||
// Resolve to IP if the domain doesn't match any rules.
|
// Resolve to IP if the domain doesn't match any rules.
|
||||||
IpIfNonMatch = 2;
|
IpIfNonMatch = 2;
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ func TestIPOnDemand(t *testing.T) {
|
|||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
}).Return([]net.IP{{192, 168, 0, 1}}, uint32(600), nil).AnyTimes()
|
}).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
|
||||||
|
|
||||||
r := new(Router)
|
r := new(Router)
|
||||||
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
|
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
|
||||||
@@ -222,7 +222,7 @@ func TestIPIfNonMatchDomain(t *testing.T) {
|
|||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
}).Return([]net.IP{{192, 168, 0, 1}}, uint32(600), nil).AnyTimes()
|
}).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
|
||||||
|
|
||||||
r := new(Router)
|
r := new(Router)
|
||||||
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
|
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
feature_stats "github.com/xtls/xray-core/features/stats"
|
feature_stats "github.com/xtls/xray-core/features/stats"
|
||||||
grpc "google.golang.org/grpc"
|
grpc "google.golang.org/grpc"
|
||||||
codes "google.golang.org/grpc/codes"
|
|
||||||
status "google.golang.org/grpc/status"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// statsServer is an implementation of StatsService.
|
// statsServer is an implementation of StatsService.
|
||||||
@@ -32,7 +30,7 @@ func NewStatsServer(manager feature_stats.Manager) StatsServiceServer {
|
|||||||
func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {
|
func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {
|
||||||
c := s.stats.GetCounter(request.Name)
|
c := s.stats.GetCounter(request.Name)
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil, status.Error(codes.NotFound, request.Name+" not found.")
|
return nil, errors.New(request.Name, " not found.")
|
||||||
}
|
}
|
||||||
var value int64
|
var value int64
|
||||||
if request.Reset_ {
|
if request.Reset_ {
|
||||||
@@ -51,7 +49,7 @@ func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*
|
|||||||
func (s *statsServer) GetStatsOnline(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {
|
func (s *statsServer) GetStatsOnline(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {
|
||||||
c := s.stats.GetOnlineMap(request.Name)
|
c := s.stats.GetOnlineMap(request.Name)
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil, status.Error(codes.NotFound, request.Name+" not found.")
|
return nil, errors.New(request.Name, " not found.")
|
||||||
}
|
}
|
||||||
value := int64(c.Count())
|
value := int64(c.Count())
|
||||||
return &GetStatsResponse{
|
return &GetStatsResponse{
|
||||||
@@ -66,7 +64,7 @@ func (s *statsServer) GetStatsOnlineIpList(ctx context.Context, request *GetStat
|
|||||||
c := s.stats.GetOnlineMap(request.Name)
|
c := s.stats.GetOnlineMap(request.Name)
|
||||||
|
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil, status.Error(codes.NotFound, request.Name+" not found.")
|
return nil, errors.New(request.Name, " not found.")
|
||||||
}
|
}
|
||||||
|
|
||||||
ips := make(map[string]int64)
|
ips := make(map[string]int64)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
// OnlineMap is an implementation of stats.OnlineMap.
|
// OnlineMap is an implementation of stats.OnlineMap.
|
||||||
type OnlineMap struct {
|
type OnlineMap struct {
|
||||||
|
value int
|
||||||
ipList map[string]time.Time
|
ipList map[string]time.Time
|
||||||
access sync.RWMutex
|
access sync.RWMutex
|
||||||
lastCleanup time.Time
|
lastCleanup time.Time
|
||||||
@@ -24,10 +25,7 @@ func NewOnlineMap() *OnlineMap {
|
|||||||
|
|
||||||
// Count implements stats.OnlineMap.
|
// Count implements stats.OnlineMap.
|
||||||
func (c *OnlineMap) Count() int {
|
func (c *OnlineMap) Count() int {
|
||||||
c.access.RLock()
|
return c.value
|
||||||
defer c.access.RUnlock()
|
|
||||||
|
|
||||||
return len(c.ipList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// List implements stats.OnlineMap.
|
// List implements stats.OnlineMap.
|
||||||
@@ -37,18 +35,23 @@ func (c *OnlineMap) List() []string {
|
|||||||
|
|
||||||
// AddIP implements stats.OnlineMap.
|
// AddIP implements stats.OnlineMap.
|
||||||
func (c *OnlineMap) AddIP(ip string) {
|
func (c *OnlineMap) AddIP(ip string) {
|
||||||
|
list := c.ipList
|
||||||
|
|
||||||
if ip == "127.0.0.1" {
|
if ip == "127.0.0.1" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if _, ok := list[ip]; !ok {
|
||||||
c.access.Lock()
|
c.access.Lock()
|
||||||
c.ipList[ip] = time.Now()
|
list[ip] = time.Now()
|
||||||
c.access.Unlock()
|
c.access.Unlock()
|
||||||
|
}
|
||||||
if time.Since(c.lastCleanup) > c.cleanupPeriod {
|
if time.Since(c.lastCleanup) > c.cleanupPeriod {
|
||||||
c.RemoveExpiredIPs()
|
list = c.RemoveExpiredIPs(list)
|
||||||
c.lastCleanup = time.Now()
|
c.lastCleanup = time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.value = len(list)
|
||||||
|
c.ipList = list
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *OnlineMap) GetKeys() []string {
|
func (c *OnlineMap) GetKeys() []string {
|
||||||
@@ -62,22 +65,24 @@ func (c *OnlineMap) GetKeys() []string {
|
|||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *OnlineMap) RemoveExpiredIPs() {
|
func (c *OnlineMap) RemoveExpiredIPs(list map[string]time.Time) map[string]time.Time {
|
||||||
c.access.Lock()
|
c.access.Lock()
|
||||||
defer c.access.Unlock()
|
defer c.access.Unlock()
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
for k, t := range c.ipList {
|
for k, t := range list {
|
||||||
diff := now.Sub(t)
|
diff := now.Sub(t)
|
||||||
if diff.Seconds() > 20 {
|
if diff.Seconds() > 20 {
|
||||||
delete(c.ipList, k)
|
delete(list, k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *OnlineMap) IpTimeMap() map[string]time.Time {
|
func (c *OnlineMap) IpTimeMap() map[string]time.Time {
|
||||||
|
list := c.ipList
|
||||||
if time.Since(c.lastCleanup) > c.cleanupPeriod {
|
if time.Since(c.lastCleanup) > c.cleanupPeriod {
|
||||||
c.RemoveExpiredIPs()
|
list = c.RemoveExpiredIPs(list)
|
||||||
c.lastCleanup = time.Now()
|
c.lastCleanup = time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,152 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.35.1
|
|
||||||
// protoc v5.28.2
|
|
||||||
// source: app/version/config.proto
|
|
||||||
|
|
||||||
package version
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
CoreVersion string `protobuf:"bytes,1,opt,name=core_version,json=coreVersion,proto3" json:"core_version,omitempty"`
|
|
||||||
MinVersion string `protobuf:"bytes,2,opt,name=min_version,json=minVersion,proto3" json:"min_version,omitempty"`
|
|
||||||
MaxVersion string `protobuf:"bytes,3,opt,name=max_version,json=maxVersion,proto3" json:"max_version,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
|
||||||
*x = Config{}
|
|
||||||
mi := &file_app_version_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_version_config_proto_msgTypes[0]
|
|
||||||
if 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_version_config_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetCoreVersion() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.CoreVersion
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetMinVersion() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.MinVersion
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetMaxVersion() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.MaxVersion
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_app_version_config_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_app_version_config_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x18, 0x61, 0x70, 0x70, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x6f,
|
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61, 0x79,
|
|
||||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x6d, 0x0a, 0x06,
|
|
||||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x72, 0x65, 0x5f, 0x76,
|
|
||||||
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f,
|
|
||||||
0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x69, 0x6e,
|
|
||||||
0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
|
|
||||||
0x6d, 0x69, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x61,
|
|
||||||
0x78, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
|
|
||||||
0x0a, 0x6d, 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x52, 0x0a, 0x14, 0x63,
|
|
||||||
0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x73,
|
|
||||||
0x69, 0x6f, 0x6e, 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, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0xaa, 0x02, 0x10, 0x58,
|
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x62,
|
|
||||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_app_version_config_proto_rawDescOnce sync.Once
|
|
||||||
file_app_version_config_proto_rawDescData = file_app_version_config_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_app_version_config_proto_rawDescGZIP() []byte {
|
|
||||||
file_app_version_config_proto_rawDescOnce.Do(func() {
|
|
||||||
file_app_version_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_version_config_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_app_version_config_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_app_version_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
|
||||||
var file_app_version_config_proto_goTypes = []any{
|
|
||||||
(*Config)(nil), // 0: xray.app.version.Config
|
|
||||||
}
|
|
||||||
var file_app_version_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_version_config_proto_init() }
|
|
||||||
func file_app_version_config_proto_init() {
|
|
||||||
if File_app_version_config_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_app_version_config_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 1,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_app_version_config_proto_goTypes,
|
|
||||||
DependencyIndexes: file_app_version_config_proto_depIdxs,
|
|
||||||
MessageInfos: file_app_version_config_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_app_version_config_proto = out.File
|
|
||||||
file_app_version_config_proto_rawDesc = nil
|
|
||||||
file_app_version_config_proto_goTypes = nil
|
|
||||||
file_app_version_config_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package xray.app.version;
|
|
||||||
option csharp_namespace = "Xray.App.Version";
|
|
||||||
option go_package = "github.com/xtls/xray-core/app/version";
|
|
||||||
option java_package = "com.xray.app.version";
|
|
||||||
option java_multiple_files = true;
|
|
||||||
|
|
||||||
|
|
||||||
message Config {
|
|
||||||
string core_version = 1;
|
|
||||||
string min_version = 2;
|
|
||||||
string max_version = 3;
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
package version
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Version struct {
|
|
||||||
config *Config
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(ctx context.Context, config *Config) (*Version, error) {
|
|
||||||
if config.MinVersion != "" {
|
|
||||||
result, err := compareVersions(config.MinVersion, config.CoreVersion)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if result > 0 {
|
|
||||||
return nil, errors.New("this config must be run on version ", config.MinVersion, " or higher")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if config.MaxVersion != "" {
|
|
||||||
result, err := compareVersions(config.MaxVersion, config.CoreVersion)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if result < 0 {
|
|
||||||
return nil, errors.New("this config should be run on version ", config.MaxVersion, " or lower")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &Version{config: config, ctx: ctx}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func compareVersions(v1, v2 string) (int, error) {
|
|
||||||
// Split version strings into components
|
|
||||||
v1Parts := strings.Split(v1, ".")
|
|
||||||
v2Parts := strings.Split(v2, ".")
|
|
||||||
|
|
||||||
// Pad shorter versions with zeros
|
|
||||||
for len(v1Parts) < len(v2Parts) {
|
|
||||||
v1Parts = append(v1Parts, "0")
|
|
||||||
}
|
|
||||||
for len(v2Parts) < len(v1Parts) {
|
|
||||||
v2Parts = append(v2Parts, "0")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare each part
|
|
||||||
for i := 0; i < len(v1Parts); i++ {
|
|
||||||
// Convert parts to integers
|
|
||||||
n1, err := strconv.Atoi(v1Parts[i])
|
|
||||||
if err != nil {
|
|
||||||
return 0, errors.New("invalid version component ", v1Parts[i], " in ", v1)
|
|
||||||
}
|
|
||||||
n2, err := strconv.Atoi(v2Parts[i])
|
|
||||||
if err != nil {
|
|
||||||
return 0, errors.New("invalid version component ", v2Parts[i], " in ", v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
if n1 < n2 {
|
|
||||||
return -1, nil // v1 < v2
|
|
||||||
}
|
|
||||||
if n1 > n2 {
|
|
||||||
return 1, nil // v1 > v2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0, nil // v1 == v2
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
|
||||||
return New(ctx, config.(*Config))
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
@@ -13,19 +13,8 @@ const (
|
|||||||
Size = 8192
|
Size = 8192
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrBufferFull = errors.New("buffer is full")
|
|
||||||
|
|
||||||
var pool = bytespool.GetPool(Size)
|
var pool = bytespool.GetPool(Size)
|
||||||
|
|
||||||
// ownership represents the data owner of the buffer.
|
|
||||||
type ownership uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
managed ownership = iota
|
|
||||||
unmanaged
|
|
||||||
bytespools
|
|
||||||
)
|
|
||||||
|
|
||||||
// Buffer is a recyclable allocation of a byte array. Buffer.Release() recycles
|
// Buffer is a recyclable allocation of a byte array. Buffer.Release() recycles
|
||||||
// the buffer into an internal buffer pool, in order to recreate a buffer more
|
// the buffer into an internal buffer pool, in order to recreate a buffer more
|
||||||
// quickly.
|
// quickly.
|
||||||
@@ -33,11 +22,11 @@ type Buffer struct {
|
|||||||
v []byte
|
v []byte
|
||||||
start int32
|
start int32
|
||||||
end int32
|
end int32
|
||||||
ownership ownership
|
unmanaged bool
|
||||||
UDP *net.Destination
|
UDP *net.Destination
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a Buffer with 0 length and 8K capacity, managed.
|
// New creates a Buffer with 0 length and 8K capacity.
|
||||||
func New() *Buffer {
|
func New() *Buffer {
|
||||||
buf := pool.Get().([]byte)
|
buf := pool.Get().([]byte)
|
||||||
if cap(buf) >= Size {
|
if cap(buf) >= Size {
|
||||||
@@ -51,7 +40,7 @@ func New() *Buffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewExisted creates a standard size Buffer with an existed bytearray, managed.
|
// NewExisted creates a managed, standard size Buffer with an existed bytearray
|
||||||
func NewExisted(b []byte) *Buffer {
|
func NewExisted(b []byte) *Buffer {
|
||||||
if cap(b) < Size {
|
if cap(b) < Size {
|
||||||
panic("Invalid buffer")
|
panic("Invalid buffer")
|
||||||
@@ -68,16 +57,16 @@ func NewExisted(b []byte) *Buffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromBytes creates a Buffer with an existed bytearray, unmanaged.
|
// FromBytes creates a Buffer with an existed bytearray
|
||||||
func FromBytes(b []byte) *Buffer {
|
func FromBytes(b []byte) *Buffer {
|
||||||
return &Buffer{
|
return &Buffer{
|
||||||
v: b,
|
v: b,
|
||||||
end: int32(len(b)),
|
end: int32(len(b)),
|
||||||
ownership: unmanaged,
|
unmanaged: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// StackNew creates a new Buffer object on stack, managed.
|
// StackNew creates a new Buffer object on stack.
|
||||||
// This method is for buffers that is released in the same function.
|
// This method is for buffers that is released in the same function.
|
||||||
func StackNew() Buffer {
|
func StackNew() Buffer {
|
||||||
buf := pool.Get().([]byte)
|
buf := pool.Get().([]byte)
|
||||||
@@ -92,17 +81,9 @@ func StackNew() Buffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWithSize creates a Buffer with 0 length and capacity with at least the given size, bytespool's.
|
|
||||||
func NewWithSize(size int32) *Buffer {
|
|
||||||
return &Buffer{
|
|
||||||
v: bytespool.Alloc(size),
|
|
||||||
ownership: bytespools,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release recycles the buffer into an internal buffer pool.
|
// Release recycles the buffer into an internal buffer pool.
|
||||||
func (b *Buffer) Release() {
|
func (b *Buffer) Release() {
|
||||||
if b == nil || b.v == nil || b.ownership == unmanaged {
|
if b == nil || b.v == nil || b.unmanaged {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,13 +91,8 @@ func (b *Buffer) Release() {
|
|||||||
b.v = nil
|
b.v = nil
|
||||||
b.Clear()
|
b.Clear()
|
||||||
|
|
||||||
switch b.ownership {
|
if cap(p) == Size {
|
||||||
case managed:
|
pool.Put(p)
|
||||||
if cap(p) == Size {
|
|
||||||
pool.Put(p)
|
|
||||||
}
|
|
||||||
case bytespools:
|
|
||||||
bytespool.Free(p)
|
|
||||||
}
|
}
|
||||||
b.UDP = nil
|
b.UDP = nil
|
||||||
}
|
}
|
||||||
@@ -144,7 +120,7 @@ func (b *Buffer) Bytes() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extend increases the buffer size by n bytes, and returns the extended part.
|
// Extend increases the buffer size by n bytes, and returns the extended part.
|
||||||
// It panics if result size is larger than size of this buffer.
|
// It panics if result size is larger than buf.Size.
|
||||||
func (b *Buffer) Extend(n int32) []byte {
|
func (b *Buffer) Extend(n int32) []byte {
|
||||||
end := b.end + n
|
end := b.end + n
|
||||||
if end > int32(len(b.v)) {
|
if end > int32(len(b.v)) {
|
||||||
@@ -152,7 +128,6 @@ func (b *Buffer) Extend(n int32) []byte {
|
|||||||
}
|
}
|
||||||
ext := b.v[b.end:end]
|
ext := b.v[b.end:end]
|
||||||
b.end = end
|
b.end = end
|
||||||
clear(ext)
|
|
||||||
return ext
|
return ext
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +176,6 @@ func (b *Buffer) Check() {
|
|||||||
|
|
||||||
// Resize cuts the buffer at the given position.
|
// Resize cuts the buffer at the given position.
|
||||||
func (b *Buffer) Resize(from, to int32) {
|
func (b *Buffer) Resize(from, to int32) {
|
||||||
oldEnd := b.end
|
|
||||||
if from < 0 {
|
if from < 0 {
|
||||||
from += b.Len()
|
from += b.Len()
|
||||||
}
|
}
|
||||||
@@ -214,9 +188,6 @@ func (b *Buffer) Resize(from, to int32) {
|
|||||||
b.end = b.start + to
|
b.end = b.start + to
|
||||||
b.start += from
|
b.start += from
|
||||||
b.Check()
|
b.Check()
|
||||||
if b.end > oldEnd {
|
|
||||||
clear(b.v[oldEnd:b.end])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advance cuts the buffer at the given position.
|
// Advance cuts the buffer at the given position.
|
||||||
@@ -244,12 +215,11 @@ func (b *Buffer) Cap() int32 {
|
|||||||
return int32(len(b.v))
|
return int32(len(b.v))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Available returns the available capacity of the buffer content.
|
// NewWithSize creates a Buffer with 0 length and capacity with at least the given size.
|
||||||
func (b *Buffer) Available() int32 {
|
func NewWithSize(size int32) *Buffer {
|
||||||
if b == nil {
|
return &Buffer{
|
||||||
return 0
|
v: bytespool.Alloc(size),
|
||||||
}
|
}
|
||||||
return int32(len(b.v)) - b.end
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEmpty returns true if the buffer is empty.
|
// IsEmpty returns true if the buffer is empty.
|
||||||
@@ -266,16 +236,13 @@ func (b *Buffer) IsFull() bool {
|
|||||||
func (b *Buffer) Write(data []byte) (int, error) {
|
func (b *Buffer) Write(data []byte) (int, error) {
|
||||||
nBytes := copy(b.v[b.end:], data)
|
nBytes := copy(b.v[b.end:], data)
|
||||||
b.end += int32(nBytes)
|
b.end += int32(nBytes)
|
||||||
if nBytes < len(data) {
|
|
||||||
return nBytes, ErrBufferFull
|
|
||||||
}
|
|
||||||
return nBytes, nil
|
return nBytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteByte writes a single byte into the buffer.
|
// WriteByte writes a single byte into the buffer.
|
||||||
func (b *Buffer) WriteByte(v byte) error {
|
func (b *Buffer) WriteByte(v byte) error {
|
||||||
if b.IsFull() {
|
if b.IsFull() {
|
||||||
return ErrBufferFull
|
return errors.New("buffer full")
|
||||||
}
|
}
|
||||||
b.v[b.end] = v
|
b.v[b.end] = v
|
||||||
b.end++
|
b.end++
|
||||||
|
|||||||
@@ -24,59 +24,9 @@ var ErrReadTimeout = errors.New("IO timeout")
|
|||||||
|
|
||||||
// TimeoutReader is a reader that returns error if Read() operation takes longer than the given timeout.
|
// TimeoutReader is a reader that returns error if Read() operation takes longer than the given timeout.
|
||||||
type TimeoutReader interface {
|
type TimeoutReader interface {
|
||||||
Reader
|
|
||||||
ReadMultiBufferTimeout(time.Duration) (MultiBuffer, error)
|
ReadMultiBufferTimeout(time.Duration) (MultiBuffer, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type TimeoutWrapperReader struct {
|
|
||||||
Reader
|
|
||||||
stats.Counter
|
|
||||||
mb MultiBuffer
|
|
||||||
err error
|
|
||||||
done chan struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *TimeoutWrapperReader) ReadMultiBuffer() (MultiBuffer, error) {
|
|
||||||
if r.done != nil {
|
|
||||||
<-r.done
|
|
||||||
r.done = nil
|
|
||||||
if r.Counter != nil {
|
|
||||||
r.Counter.Add(int64(r.mb.Len()))
|
|
||||||
}
|
|
||||||
return r.mb, r.err
|
|
||||||
}
|
|
||||||
r.mb, r.err = r.Reader.ReadMultiBuffer()
|
|
||||||
if r.Counter != nil {
|
|
||||||
r.Counter.Add(int64(r.mb.Len()))
|
|
||||||
}
|
|
||||||
return r.mb, r.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *TimeoutWrapperReader) ReadMultiBufferTimeout(duration time.Duration) (MultiBuffer, error) {
|
|
||||||
if r.done == nil {
|
|
||||||
r.done = make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
r.mb, r.err = r.Reader.ReadMultiBuffer()
|
|
||||||
close(r.done)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
timeout := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
time.Sleep(duration)
|
|
||||||
close(timeout)
|
|
||||||
}()
|
|
||||||
select {
|
|
||||||
case <-r.done:
|
|
||||||
r.done = nil
|
|
||||||
if r.Counter != nil {
|
|
||||||
r.Counter.Add(int64(r.mb.Len()))
|
|
||||||
}
|
|
||||||
return r.mb, r.err
|
|
||||||
case <-timeout:
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writer extends io.Writer with MultiBuffer.
|
// Writer extends io.Writer with MultiBuffer.
|
||||||
type Writer interface {
|
type Writer interface {
|
||||||
// WriteMultiBuffer writes a MultiBuffer into underlying writer.
|
// WriteMultiBuffer writes a MultiBuffer into underlying writer.
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ func Compact(mb MultiBuffer) MultiBuffer {
|
|||||||
|
|
||||||
for i := 1; i < len(mb); i++ {
|
for i := 1; i < len(mb); i++ {
|
||||||
curr := mb[i]
|
curr := mb[i]
|
||||||
if curr.Len() > last.Available() {
|
if last.Len()+curr.Len() > Size {
|
||||||
mb2 = append(mb2, last)
|
mb2 = append(mb2, last)
|
||||||
last = curr
|
last = curr
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -175,29 +175,6 @@ func TestCompact(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompactWithConsumed(t *testing.T) {
|
|
||||||
// make a consumed buffer (a.Start != 0)
|
|
||||||
a := New()
|
|
||||||
for range 8192 {
|
|
||||||
common.Must2(a.WriteString("a"))
|
|
||||||
}
|
|
||||||
a.Read(make([]byte, 2))
|
|
||||||
|
|
||||||
b := New()
|
|
||||||
for range 2 {
|
|
||||||
common.Must2(b.WriteString("b"))
|
|
||||||
}
|
|
||||||
|
|
||||||
mb := MultiBuffer{a, b}
|
|
||||||
cmb := Compact(mb)
|
|
||||||
mbc := &MultiBufferContainer{mb}
|
|
||||||
mbc.Read(make([]byte, 8190))
|
|
||||||
|
|
||||||
if w := cmb.String(); w != "bb" {
|
|
||||||
t.Error("unexpected Compact result ", w)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSplitBytes(b *testing.B) {
|
func BenchmarkSplitBytes(b *testing.B) {
|
||||||
var mb MultiBuffer
|
var mb MultiBuffer
|
||||||
raw := make([]byte, Size)
|
raw := make([]byte, Size)
|
||||||
|
|||||||
@@ -75,10 +75,9 @@ func (w *BufferToBytesWriter) ReadFrom(reader io.Reader) (int64, error) {
|
|||||||
// BufferedWriter is a Writer with internal buffer.
|
// BufferedWriter is a Writer with internal buffer.
|
||||||
type BufferedWriter struct {
|
type BufferedWriter struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
writer Writer
|
writer Writer
|
||||||
buffer *Buffer
|
buffer *Buffer
|
||||||
buffered bool
|
buffered bool
|
||||||
flushNext bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBufferedWriter creates a new BufferedWriter.
|
// NewBufferedWriter creates a new BufferedWriter.
|
||||||
@@ -162,12 +161,6 @@ func (w *BufferedWriter) WriteMultiBuffer(b MultiBuffer) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.flushNext {
|
|
||||||
w.buffered = false
|
|
||||||
w.flushNext = false
|
|
||||||
return w.flushInternal()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,13 +201,6 @@ func (w *BufferedWriter) SetBuffered(f bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFlushNext will wait the next WriteMultiBuffer to flush and set buffered = false
|
|
||||||
func (w *BufferedWriter) SetFlushNext() {
|
|
||||||
w.Lock()
|
|
||||||
defer w.Unlock()
|
|
||||||
w.flushNext = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadFrom implements io.ReaderFrom.
|
// ReadFrom implements io.ReaderFrom.
|
||||||
func (w *BufferedWriter) ReadFrom(reader io.Reader) (int64, error) {
|
func (w *BufferedWriter) ReadFrom(reader io.Reader) (int64, error) {
|
||||||
if err := w.SetBuffered(false); err != nil {
|
if err := w.SetBuffered(false); err != nil {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"go/build"
|
"go/build"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
@@ -24,9 +23,7 @@ func Must(err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Must2 panics if the second parameter is not nil, otherwise returns the first parameter.
|
// Must2 panics if the second parameter is not nil, otherwise returns the first parameter.
|
||||||
// This is useful when function returned "sth, err" and avoid many "if err != nil"
|
func Must2(v interface{}, err error) interface{} {
|
||||||
// Internal usage only, if user input can cause err, it must be handled
|
|
||||||
func Must2[T any](v T, err error) T {
|
|
||||||
Must(err)
|
Must(err)
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
@@ -154,14 +151,3 @@ func GetModuleName(pathToProjectRoot string) (string, error) {
|
|||||||
}
|
}
|
||||||
return moduleName, fmt.Errorf("no `go.mod` file in every parent directory of `%s`", pathToProjectRoot)
|
return moduleName, fmt.Errorf("no `go.mod` file in every parent directory of `%s`", pathToProjectRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloseIfExists call obj.Close() if obj is not nil.
|
|
||||||
func CloseIfExists(obj any) error {
|
|
||||||
if obj != nil {
|
|
||||||
v := reflect.ValueOf(obj)
|
|
||||||
if !v.IsNil() {
|
|
||||||
return Close(obj)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ func NewAesCTRStream(key []byte, iv []byte) cipher.Stream {
|
|||||||
|
|
||||||
// NewAesGcm creates a AEAD cipher based on AES-GCM.
|
// NewAesGcm creates a AEAD cipher based on AES-GCM.
|
||||||
func NewAesGcm(key []byte) cipher.AEAD {
|
func NewAesGcm(key []byte) cipher.AEAD {
|
||||||
block := common.Must2(aes.NewCipher(key))
|
block, err := aes.NewCipher(key)
|
||||||
aead := common.Must2(cipher.NewGCM(block))
|
common.Must(err)
|
||||||
|
aead, err := cipher.NewGCM(block)
|
||||||
|
common.Must(err)
|
||||||
return aead
|
return aead
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package crypto_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -16,8 +18,11 @@ import (
|
|||||||
func TestAuthenticationReaderWriter(t *testing.T) {
|
func TestAuthenticationReaderWriter(t *testing.T) {
|
||||||
key := make([]byte, 16)
|
key := make([]byte, 16)
|
||||||
rand.Read(key)
|
rand.Read(key)
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
aead := NewAesGcm(key)
|
aead, err := cipher.NewGCM(block)
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
const payloadSize = 1024 * 80
|
const payloadSize = 1024 * 80
|
||||||
rawPayload := make([]byte, payloadSize)
|
rawPayload := make([]byte, payloadSize)
|
||||||
@@ -66,7 +71,7 @@ func TestAuthenticationReaderWriter(t *testing.T) {
|
|||||||
t.Error(r)
|
t.Error(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := reader.ReadMultiBuffer()
|
_, err = reader.ReadMultiBuffer()
|
||||||
if err != io.EOF {
|
if err != io.EOF {
|
||||||
t.Error("error: ", err)
|
t.Error("error: ", err)
|
||||||
}
|
}
|
||||||
@@ -75,8 +80,11 @@ func TestAuthenticationReaderWriter(t *testing.T) {
|
|||||||
func TestAuthenticationReaderWriterPacket(t *testing.T) {
|
func TestAuthenticationReaderWriterPacket(t *testing.T) {
|
||||||
key := make([]byte, 16)
|
key := make([]byte, 16)
|
||||||
common.Must2(rand.Read(key))
|
common.Must2(rand.Read(key))
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
aead := NewAesGcm(key)
|
aead, err := cipher.NewGCM(block)
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
cache := buf.New()
|
cache := buf.New()
|
||||||
iv := make([]byte, 12)
|
iv := make([]byte, 12)
|
||||||
|
|||||||
@@ -1,18 +1,2 @@
|
|||||||
// Package crypto provides common crypto libraries for Xray.
|
// Package crypto provides common crypto libraries for Xray.
|
||||||
package crypto // import "github.com/xtls/xray-core/common/crypto"
|
package crypto // import "github.com/xtls/xray-core/common/crypto"
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"math/big"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RandBetween(from int64, to int64) int64 {
|
|
||||||
if from == to {
|
|
||||||
return from
|
|
||||||
}
|
|
||||||
if from > to {
|
|
||||||
from, to = to, from
|
|
||||||
}
|
|
||||||
bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from))
|
|
||||||
return from + bigInt.Int64()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package errors
|
package errors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -37,12 +36,12 @@ func AllEqual(expected error, actual error) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for _, err := range errs {
|
for _, err := range errs {
|
||||||
if !errors.Is(err, expected) {
|
if err != expected {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return errors.Is(errs, expected)
|
return errs == expected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,8 @@ func (l *DNSLog) String() string {
|
|||||||
type dnsStatus string
|
type dnsStatus string
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DNSQueried = dnsStatus("got answer:")
|
DNSQueried = dnsStatus("got answer:")
|
||||||
DNSCacheHit = dnsStatus("cache HIT:")
|
DNSCacheHit = dnsStatus("cache HIT:")
|
||||||
DNSCacheOptimiste = dnsStatus("cache OPTIMISTE:")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func joinNetIP(ips []net.IP) string {
|
func joinNetIP(ips []net.IP) string {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package mux
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
goerrors "errors"
|
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -155,11 +154,8 @@ func (f *DialingWorkerFactory) Create() (*ClientWorker, error) {
|
|||||||
ctx := session.ContextWithOutbounds(context.Background(), outbounds)
|
ctx := session.ContextWithOutbounds(context.Background(), outbounds)
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
if errP := p.Process(ctx, &transport.Link{Reader: uplinkReader, Writer: downlinkWriter}, d); errP != nil {
|
if err := p.Process(ctx, &transport.Link{Reader: uplinkReader, Writer: downlinkWriter}, d); err != nil {
|
||||||
errC := errors.Cause(errP)
|
errors.LogInfoInner(ctx, err, "failed to handler mux client connection")
|
||||||
if !(goerrors.Is(errC, io.EOF) || goerrors.Is(errC, io.ErrClosedPipe) || goerrors.Is(errC, context.Canceled)) {
|
|
||||||
errors.LogInfoInner(ctx, errP, "failed to handler mux client connection")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
common.Must(c.Close())
|
common.Must(c.Close())
|
||||||
cancel()
|
cancel()
|
||||||
@@ -177,7 +173,6 @@ type ClientWorker struct {
|
|||||||
sessionManager *SessionManager
|
sessionManager *SessionManager
|
||||||
link transport.Link
|
link transport.Link
|
||||||
done *done.Instance
|
done *done.Instance
|
||||||
timer *time.Ticker
|
|
||||||
strategy ClientStrategy
|
strategy ClientStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +187,6 @@ func NewClientWorker(stream transport.Link, s ClientStrategy) (*ClientWorker, er
|
|||||||
sessionManager: NewSessionManager(),
|
sessionManager: NewSessionManager(),
|
||||||
link: stream,
|
link: stream,
|
||||||
done: done.New(),
|
done: done.New(),
|
||||||
timer: time.NewTicker(time.Second * 16),
|
|
||||||
strategy: s,
|
strategy: s,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,28 +209,20 @@ func (m *ClientWorker) Closed() bool {
|
|||||||
return m.done.Done()
|
return m.done.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ClientWorker) WaitClosed() <-chan struct{} {
|
|
||||||
return m.done.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *ClientWorker) Close() error {
|
|
||||||
return m.done.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *ClientWorker) monitor() {
|
func (m *ClientWorker) monitor() {
|
||||||
defer m.timer.Stop()
|
timer := time.NewTicker(time.Second * 16)
|
||||||
|
defer timer.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
checkSize := m.sessionManager.Size()
|
|
||||||
checkCount := m.sessionManager.Count()
|
|
||||||
select {
|
select {
|
||||||
case <-m.done.Wait():
|
case <-m.done.Wait():
|
||||||
m.sessionManager.Close()
|
m.sessionManager.Close()
|
||||||
common.Interrupt(m.link.Writer)
|
common.Close(m.link.Writer)
|
||||||
common.Interrupt(m.link.Reader)
|
common.Interrupt(m.link.Reader)
|
||||||
return
|
return
|
||||||
case <-m.timer.C:
|
case <-timer.C:
|
||||||
if m.sessionManager.CloseIfNoSessionAndIdle(checkSize, checkCount) {
|
size := m.sessionManager.Size()
|
||||||
|
if size == 0 && m.sessionManager.CloseIfNoSession() {
|
||||||
common.Must(m.done.Close())
|
common.Must(m.done.Close())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,11 +250,7 @@ func fetchInput(ctx context.Context, s *Session, output buf.Writer) {
|
|||||||
transferType = protocol.TransferTypePacket
|
transferType = protocol.TransferTypePacket
|
||||||
}
|
}
|
||||||
s.transferType = transferType
|
s.transferType = transferType
|
||||||
var inbound *session.Inbound
|
writer := NewWriter(s.ID, ob.Target, output, transferType, xudp.GetGlobalID(ctx))
|
||||||
if session.IsReverseMuxFromContext(ctx) {
|
|
||||||
inbound = session.InboundFromContext(ctx)
|
|
||||||
}
|
|
||||||
writer := NewWriter(s.ID, ob.Target, output, transferType, xudp.GetGlobalID(ctx), inbound)
|
|
||||||
defer s.Close(false)
|
defer s.Close(false)
|
||||||
defer writer.Close()
|
defer writer.Close()
|
||||||
|
|
||||||
@@ -294,8 +276,6 @@ func (m *ClientWorker) IsClosing() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsFull returns true if this ClientWorker is unable to accept more connections.
|
|
||||||
// it might be because it is closing, or the number of connections has reached the limit.
|
|
||||||
func (m *ClientWorker) IsFull() bool {
|
func (m *ClientWorker) IsFull() bool {
|
||||||
if m.IsClosing() || m.Closed() {
|
if m.IsClosing() || m.Closed() {
|
||||||
return true
|
return true
|
||||||
@@ -309,24 +289,18 @@ func (m *ClientWorker) IsFull() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *ClientWorker) Dispatch(ctx context.Context, link *transport.Link) bool {
|
func (m *ClientWorker) Dispatch(ctx context.Context, link *transport.Link) bool {
|
||||||
if m.IsFull() {
|
if m.IsFull() || m.Closed() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
sm := m.sessionManager
|
sm := m.sessionManager
|
||||||
s := sm.Allocate(&m.strategy)
|
s := sm.Allocate()
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
s.input = link.Reader
|
s.input = link.Reader
|
||||||
s.output = link.Writer
|
s.output = link.Writer
|
||||||
go fetchInput(ctx, s, m.link.Writer)
|
go fetchInput(ctx, s, m.link.Writer)
|
||||||
if _, ok := link.Reader.(*pipe.Reader); !ok {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
case <-s.done.Wait():
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,7 +362,7 @@ func (m *ClientWorker) fetchOutput() {
|
|||||||
|
|
||||||
var meta FrameMetadata
|
var meta FrameMetadata
|
||||||
for {
|
for {
|
||||||
err := meta.Unmarshal(reader, false)
|
err := meta.Unmarshal(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Cause(err) != io.EOF {
|
if errors.Cause(err) != io.EOF {
|
||||||
errors.LogInfoInner(context.Background(), err, "failed to read metadata")
|
errors.LogInfoInner(context.Background(), err, "failed to read metadata")
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
"github.com/xtls/xray-core/common/session"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type SessionStatus byte
|
type SessionStatus byte
|
||||||
@@ -61,7 +60,6 @@ type FrameMetadata struct {
|
|||||||
Option bitmask.Byte
|
Option bitmask.Byte
|
||||||
SessionStatus SessionStatus
|
SessionStatus SessionStatus
|
||||||
GlobalID [8]byte
|
GlobalID [8]byte
|
||||||
Inbound *session.Inbound
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FrameMetadata) WriteTo(b *buf.Buffer) error {
|
func (f FrameMetadata) WriteTo(b *buf.Buffer) error {
|
||||||
@@ -81,23 +79,11 @@ func (f FrameMetadata) WriteTo(b *buf.Buffer) error {
|
|||||||
case net.Network_UDP:
|
case net.Network_UDP:
|
||||||
common.Must(b.WriteByte(byte(TargetNetworkUDP)))
|
common.Must(b.WriteByte(byte(TargetNetworkUDP)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := addrParser.WriteAddressPort(b, f.Target.Address, f.Target.Port); err != nil {
|
if err := addrParser.WriteAddressPort(b, f.Target.Address, f.Target.Port); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if f.Inbound != nil {
|
if b.UDP != nil { // make sure it's user's proxy request
|
||||||
if f.Inbound.Source.Network == net.Network_TCP || f.Inbound.Source.Network == net.Network_UDP {
|
|
||||||
common.Must(b.WriteByte(byte(f.Inbound.Source.Network - 1)))
|
|
||||||
if err := addrParser.WriteAddressPort(b, f.Inbound.Source.Address, f.Inbound.Source.Port); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if f.Inbound.Local.Network == net.Network_TCP || f.Inbound.Local.Network == net.Network_UDP {
|
|
||||||
common.Must(b.WriteByte(byte(f.Inbound.Local.Network - 1)))
|
|
||||||
if err := addrParser.WriteAddressPort(b, f.Inbound.Local.Address, f.Inbound.Local.Port); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if b.UDP != nil { // make sure it's user's proxy request
|
|
||||||
b.Write(f.GlobalID[:]) // no need to check whether it's empty
|
b.Write(f.GlobalID[:]) // no need to check whether it's empty
|
||||||
}
|
}
|
||||||
} else if b.UDP != nil {
|
} else if b.UDP != nil {
|
||||||
@@ -111,7 +97,7 @@ func (f FrameMetadata) WriteTo(b *buf.Buffer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshal reads FrameMetadata from the given reader.
|
// Unmarshal reads FrameMetadata from the given reader.
|
||||||
func (f *FrameMetadata) Unmarshal(reader io.Reader, readSourceAndLocal bool) error {
|
func (f *FrameMetadata) Unmarshal(reader io.Reader) error {
|
||||||
metaLen, err := serial.ReadUint16(reader)
|
metaLen, err := serial.ReadUint16(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -126,12 +112,12 @@ func (f *FrameMetadata) Unmarshal(reader io.Reader, readSourceAndLocal bool) err
|
|||||||
if _, err := b.ReadFullFrom(reader, int32(metaLen)); err != nil {
|
if _, err := b.ReadFullFrom(reader, int32(metaLen)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return f.UnmarshalFromBuffer(b, readSourceAndLocal)
|
return f.UnmarshalFromBuffer(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalFromBuffer reads a FrameMetadata from the given buffer.
|
// UnmarshalFromBuffer reads a FrameMetadata from the given buffer.
|
||||||
// Visible for testing only.
|
// Visible for testing only.
|
||||||
func (f *FrameMetadata) UnmarshalFromBuffer(b *buf.Buffer, readSourceAndLocal bool) error {
|
func (f *FrameMetadata) UnmarshalFromBuffer(b *buf.Buffer) error {
|
||||||
if b.Len() < 4 {
|
if b.Len() < 4 {
|
||||||
return errors.New("insufficient buffer: ", b.Len())
|
return errors.New("insufficient buffer: ", b.Len())
|
||||||
}
|
}
|
||||||
@@ -164,54 +150,6 @@ func (f *FrameMetadata) UnmarshalFromBuffer(b *buf.Buffer, readSourceAndLocal bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.SessionStatus == SessionStatusNew && readSourceAndLocal {
|
|
||||||
f.Inbound = &session.Inbound{}
|
|
||||||
|
|
||||||
if b.Len() == 0 {
|
|
||||||
return nil // for heartbeat, etc.
|
|
||||||
}
|
|
||||||
network := TargetNetwork(b.Byte(0))
|
|
||||||
if network == 0 {
|
|
||||||
return nil // may be padding
|
|
||||||
}
|
|
||||||
b.Advance(1)
|
|
||||||
addr, port, err := addrParser.ReadAddressPort(nil, b)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("reading source: failed to parse address and port").Base(err)
|
|
||||||
}
|
|
||||||
switch network {
|
|
||||||
case TargetNetworkTCP:
|
|
||||||
f.Inbound.Source = net.TCPDestination(addr, port)
|
|
||||||
case TargetNetworkUDP:
|
|
||||||
f.Inbound.Source = net.UDPDestination(addr, port)
|
|
||||||
default:
|
|
||||||
return errors.New("reading source: unknown network type: ", network)
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.Len() == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
network = TargetNetwork(b.Byte(0))
|
|
||||||
if network == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
b.Advance(1)
|
|
||||||
addr, port, err = addrParser.ReadAddressPort(nil, b)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("reading local: failed to parse address and port").Base(err)
|
|
||||||
}
|
|
||||||
switch network {
|
|
||||||
case TargetNetworkTCP:
|
|
||||||
f.Inbound.Local = net.TCPDestination(addr, port)
|
|
||||||
case TargetNetworkUDP:
|
|
||||||
f.Inbound.Local = net.UDPDestination(addr, port)
|
|
||||||
default:
|
|
||||||
return errors.New("reading local: unknown network type: ", network)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Application data is essential, to test whether the pipe is closed.
|
// Application data is essential, to test whether the pipe is closed.
|
||||||
if f.SessionStatus == SessionStatusNew && f.Option.Has(OptionData) &&
|
if f.SessionStatus == SessionStatusNew && f.Option.Has(OptionData) &&
|
||||||
f.Target.Network == net.Network_UDP && b.Len() >= 8 {
|
f.Target.Network == net.Network_UDP && b.Len() >= 8 {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
. "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/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/session"
|
|
||||||
"github.com/xtls/xray-core/transport/pipe"
|
"github.com/xtls/xray-core/transport/pipe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,13 +32,13 @@ func TestReaderWriter(t *testing.T) {
|
|||||||
pReader, pWriter := pipe.New(pipe.WithSizeLimit(1024))
|
pReader, pWriter := pipe.New(pipe.WithSizeLimit(1024))
|
||||||
|
|
||||||
dest := net.TCPDestination(net.DomainAddress("example.com"), 80)
|
dest := net.TCPDestination(net.DomainAddress("example.com"), 80)
|
||||||
writer := NewWriter(1, dest, pWriter, protocol.TransferTypeStream, [8]byte{}, &session.Inbound{})
|
writer := NewWriter(1, dest, pWriter, protocol.TransferTypeStream, [8]byte{})
|
||||||
|
|
||||||
dest2 := net.TCPDestination(net.LocalHostIP, 443)
|
dest2 := net.TCPDestination(net.LocalHostIP, 443)
|
||||||
writer2 := NewWriter(2, dest2, pWriter, protocol.TransferTypeStream, [8]byte{}, &session.Inbound{})
|
writer2 := NewWriter(2, dest2, pWriter, protocol.TransferTypeStream, [8]byte{})
|
||||||
|
|
||||||
dest3 := net.TCPDestination(net.LocalHostIPv6, 18374)
|
dest3 := net.TCPDestination(net.LocalHostIPv6, 18374)
|
||||||
writer3 := NewWriter(3, dest3, pWriter, protocol.TransferTypeStream, [8]byte{}, &session.Inbound{})
|
writer3 := NewWriter(3, dest3, pWriter, protocol.TransferTypeStream, [8]byte{})
|
||||||
|
|
||||||
writePayload := func(writer *Writer, payload ...byte) error {
|
writePayload := func(writer *Writer, payload ...byte) error {
|
||||||
b := buf.New()
|
b := buf.New()
|
||||||
@@ -63,7 +62,7 @@ func TestReaderWriter(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
var meta FrameMetadata
|
var meta FrameMetadata
|
||||||
common.Must(meta.Unmarshal(bytesReader, false))
|
common.Must(meta.Unmarshal(bytesReader))
|
||||||
if r := cmp.Diff(meta, FrameMetadata{
|
if r := cmp.Diff(meta, FrameMetadata{
|
||||||
SessionID: 1,
|
SessionID: 1,
|
||||||
SessionStatus: SessionStatusNew,
|
SessionStatus: SessionStatusNew,
|
||||||
@@ -82,7 +81,7 @@ func TestReaderWriter(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
var meta FrameMetadata
|
var meta FrameMetadata
|
||||||
common.Must(meta.Unmarshal(bytesReader, false))
|
common.Must(meta.Unmarshal(bytesReader))
|
||||||
if r := cmp.Diff(meta, FrameMetadata{
|
if r := cmp.Diff(meta, FrameMetadata{
|
||||||
SessionStatus: SessionStatusNew,
|
SessionStatus: SessionStatusNew,
|
||||||
SessionID: 2,
|
SessionID: 2,
|
||||||
@@ -95,7 +94,7 @@ func TestReaderWriter(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
var meta FrameMetadata
|
var meta FrameMetadata
|
||||||
common.Must(meta.Unmarshal(bytesReader, false))
|
common.Must(meta.Unmarshal(bytesReader))
|
||||||
if r := cmp.Diff(meta, FrameMetadata{
|
if r := cmp.Diff(meta, FrameMetadata{
|
||||||
SessionID: 1,
|
SessionID: 1,
|
||||||
SessionStatus: SessionStatusKeep,
|
SessionStatus: SessionStatusKeep,
|
||||||
@@ -113,7 +112,7 @@ func TestReaderWriter(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
var meta FrameMetadata
|
var meta FrameMetadata
|
||||||
common.Must(meta.Unmarshal(bytesReader, false))
|
common.Must(meta.Unmarshal(bytesReader))
|
||||||
if r := cmp.Diff(meta, FrameMetadata{
|
if r := cmp.Diff(meta, FrameMetadata{
|
||||||
SessionID: 3,
|
SessionID: 3,
|
||||||
SessionStatus: SessionStatusNew,
|
SessionStatus: SessionStatusNew,
|
||||||
@@ -132,7 +131,7 @@ func TestReaderWriter(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
var meta FrameMetadata
|
var meta FrameMetadata
|
||||||
common.Must(meta.Unmarshal(bytesReader, false))
|
common.Must(meta.Unmarshal(bytesReader))
|
||||||
if r := cmp.Diff(meta, FrameMetadata{
|
if r := cmp.Diff(meta, FrameMetadata{
|
||||||
SessionID: 1,
|
SessionID: 1,
|
||||||
SessionStatus: SessionStatusEnd,
|
SessionStatus: SessionStatusEnd,
|
||||||
@@ -144,7 +143,7 @@ func TestReaderWriter(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
var meta FrameMetadata
|
var meta FrameMetadata
|
||||||
common.Must(meta.Unmarshal(bytesReader, false))
|
common.Must(meta.Unmarshal(bytesReader))
|
||||||
if r := cmp.Diff(meta, FrameMetadata{
|
if r := cmp.Diff(meta, FrameMetadata{
|
||||||
SessionID: 3,
|
SessionID: 3,
|
||||||
SessionStatus: SessionStatusEnd,
|
SessionStatus: SessionStatusEnd,
|
||||||
@@ -156,7 +155,7 @@ func TestReaderWriter(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
var meta FrameMetadata
|
var meta FrameMetadata
|
||||||
common.Must(meta.Unmarshal(bytesReader, false))
|
common.Must(meta.Unmarshal(bytesReader))
|
||||||
if r := cmp.Diff(meta, FrameMetadata{
|
if r := cmp.Diff(meta, FrameMetadata{
|
||||||
SessionID: 2,
|
SessionID: 2,
|
||||||
SessionStatus: SessionStatusKeep,
|
SessionStatus: SessionStatusKeep,
|
||||||
@@ -174,7 +173,7 @@ func TestReaderWriter(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
var meta FrameMetadata
|
var meta FrameMetadata
|
||||||
common.Must(meta.Unmarshal(bytesReader, false))
|
common.Must(meta.Unmarshal(bytesReader))
|
||||||
if r := cmp.Diff(meta, FrameMetadata{
|
if r := cmp.Diff(meta, FrameMetadata{
|
||||||
SessionID: 2,
|
SessionID: 2,
|
||||||
SessionStatus: SessionStatusEnd,
|
SessionStatus: SessionStatusEnd,
|
||||||
@@ -188,7 +187,7 @@ func TestReaderWriter(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
var meta FrameMetadata
|
var meta FrameMetadata
|
||||||
err := meta.Unmarshal(bytesReader, false)
|
err := meta.Unmarshal(bytesReader)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("nil error")
|
t.Error("nil error")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package mux
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
@@ -12,7 +11,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/common/signal/done"
|
|
||||||
"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/transport"
|
"github.com/xtls/xray-core/transport"
|
||||||
@@ -63,18 +61,8 @@ func (s *Server) DispatchLink(ctx context.Context, dest net.Destination, link *t
|
|||||||
if dest.Address != muxCoolAddress {
|
if dest.Address != muxCoolAddress {
|
||||||
return s.dispatcher.DispatchLink(ctx, dest, link)
|
return s.dispatcher.DispatchLink(ctx, dest, link)
|
||||||
}
|
}
|
||||||
if d, ok := s.dispatcher.(routing.WrapLinkDispatcher); ok {
|
_, err := NewServerWorker(ctx, s.dispatcher, link)
|
||||||
link = d.WrapLink(ctx, link)
|
return err
|
||||||
}
|
|
||||||
worker, err := NewServerWorker(ctx, s.dispatcher, link)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
case <-worker.done.Wait():
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start implements common.Runnable.
|
// Start implements common.Runnable.
|
||||||
@@ -91,8 +79,6 @@ type ServerWorker struct {
|
|||||||
dispatcher routing.Dispatcher
|
dispatcher routing.Dispatcher
|
||||||
link *transport.Link
|
link *transport.Link
|
||||||
sessionManager *SessionManager
|
sessionManager *SessionManager
|
||||||
done *done.Instance
|
|
||||||
timer *time.Ticker
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServerWorker(ctx context.Context, d routing.Dispatcher, link *transport.Link) (*ServerWorker, error) {
|
func NewServerWorker(ctx context.Context, d routing.Dispatcher, link *transport.Link) (*ServerWorker, error) {
|
||||||
@@ -100,14 +86,8 @@ func NewServerWorker(ctx context.Context, d routing.Dispatcher, link *transport.
|
|||||||
dispatcher: d,
|
dispatcher: d,
|
||||||
link: link,
|
link: link,
|
||||||
sessionManager: NewSessionManager(),
|
sessionManager: NewSessionManager(),
|
||||||
done: done.New(),
|
|
||||||
timer: time.NewTicker(60 * time.Second),
|
|
||||||
}
|
|
||||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
|
||||||
inbound.CanSpliceCopy = 3
|
|
||||||
}
|
}
|
||||||
go worker.run(ctx)
|
go worker.run(ctx)
|
||||||
go worker.monitor()
|
|
||||||
return worker, nil
|
return worker, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,40 +102,12 @@ func handle(ctx context.Context, s *Session, output buf.Writer) {
|
|||||||
s.Close(false)
|
s.Close(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *ServerWorker) monitor() {
|
|
||||||
defer w.timer.Stop()
|
|
||||||
|
|
||||||
for {
|
|
||||||
checkSize := w.sessionManager.Size()
|
|
||||||
checkCount := w.sessionManager.Count()
|
|
||||||
select {
|
|
||||||
case <-w.done.Wait():
|
|
||||||
w.sessionManager.Close()
|
|
||||||
common.Interrupt(w.link.Writer)
|
|
||||||
common.Interrupt(w.link.Reader)
|
|
||||||
return
|
|
||||||
case <-w.timer.C:
|
|
||||||
if w.sessionManager.CloseIfNoSessionAndIdle(checkSize, checkCount) {
|
|
||||||
common.Must(w.done.Close())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ServerWorker) ActiveConnections() uint32 {
|
func (w *ServerWorker) ActiveConnections() uint32 {
|
||||||
return uint32(w.sessionManager.Size())
|
return uint32(w.sessionManager.Size())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *ServerWorker) Closed() bool {
|
func (w *ServerWorker) Closed() bool {
|
||||||
return w.done.Done()
|
return w.sessionManager.Closed()
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ServerWorker) WaitClosed() <-chan struct{} {
|
|
||||||
return w.done.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ServerWorker) Close() error {
|
|
||||||
return w.done.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||||
@@ -166,15 +118,9 @@ func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.Bu
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata, reader *buf.BufferedReader) error {
|
func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||||
ctx = session.SubContextFromMuxInbound(ctx)
|
// deep-clone outbounds because it is going to be mutated concurrently
|
||||||
if meta.Inbound != nil && meta.Inbound.Source.IsValid() && meta.Inbound.Local.IsValid() {
|
// (Target and OriginalTarget)
|
||||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
ctx = session.ContextCloneOutbounds(ctx)
|
||||||
newInbound := *inbound
|
|
||||||
newInbound.Source = meta.Inbound.Source
|
|
||||||
newInbound.Local = meta.Inbound.Local
|
|
||||||
ctx = session.ContextWithInbound(ctx, &newInbound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
errors.LogInfo(ctx, "received request for ", meta.Target)
|
errors.LogInfo(ctx, "received request for ", meta.Target)
|
||||||
{
|
{
|
||||||
msg := &log.AccessMessage{
|
msg := &log.AccessMessage{
|
||||||
@@ -255,12 +201,11 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
|
|||||||
transferType: protocol.TransferTypePacket,
|
transferType: protocol.TransferTypePacket,
|
||||||
XUDP: x,
|
XUDP: x,
|
||||||
}
|
}
|
||||||
|
go handle(ctx, x.Mux, w.link.Writer)
|
||||||
x.Status = Active
|
x.Status = Active
|
||||||
if !w.sessionManager.Add(x.Mux) {
|
if !w.sessionManager.Add(x.Mux) {
|
||||||
x.Mux.Close(false)
|
x.Mux.Close(false)
|
||||||
return errors.New("failed to add new session")
|
|
||||||
}
|
}
|
||||||
go handle(ctx, x.Mux, w.link.Writer)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,23 +226,18 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
|
|||||||
if meta.Target.Network == net.Network_UDP {
|
if meta.Target.Network == net.Network_UDP {
|
||||||
s.transferType = protocol.TransferTypePacket
|
s.transferType = protocol.TransferTypePacket
|
||||||
}
|
}
|
||||||
if !w.sessionManager.Add(s) {
|
w.sessionManager.Add(s)
|
||||||
s.Close(false)
|
|
||||||
return errors.New("failed to add new session")
|
|
||||||
}
|
|
||||||
go handle(ctx, s, w.link.Writer)
|
go handle(ctx, s, w.link.Writer)
|
||||||
if !meta.Option.Has(OptionData) {
|
if !meta.Option.Has(OptionData) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rr := s.NewReader(reader, &meta.Target)
|
rr := s.NewReader(reader, &meta.Target)
|
||||||
err = buf.Copy(rr, s.output)
|
if err := buf.Copy(rr, s.output); err != nil {
|
||||||
|
buf.Copy(rr, buf.Discard)
|
||||||
if err != nil && buf.IsWriteError(err) {
|
return s.Close(false)
|
||||||
s.Close(false)
|
|
||||||
return buf.Copy(rr, buf.Discard)
|
|
||||||
}
|
}
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||||
@@ -338,7 +278,7 @@ func (w *ServerWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.Buffered
|
|||||||
|
|
||||||
func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedReader) error {
|
func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedReader) error {
|
||||||
var meta FrameMetadata
|
var meta FrameMetadata
|
||||||
err := meta.Unmarshal(reader, session.IsReverseMuxFromContext(ctx))
|
err := meta.Unmarshal(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to read metadata").Base(err)
|
return errors.New("failed to read metadata").Base(err)
|
||||||
}
|
}
|
||||||
@@ -349,7 +289,7 @@ func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedRead
|
|||||||
case SessionStatusEnd:
|
case SessionStatusEnd:
|
||||||
err = w.handleStatusEnd(&meta, reader)
|
err = w.handleStatusEnd(&meta, reader)
|
||||||
case SessionStatusNew:
|
case SessionStatusNew:
|
||||||
err = w.handleStatusNew(session.ContextWithIsReverseMux(ctx, false), &meta, reader)
|
err = w.handleStatusNew(ctx, &meta, reader)
|
||||||
case SessionStatusKeep:
|
case SessionStatusKeep:
|
||||||
err = w.handleStatusKeep(&meta, reader)
|
err = w.handleStatusKeep(&meta, reader)
|
||||||
default:
|
default:
|
||||||
@@ -364,11 +304,10 @@ func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedRead
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *ServerWorker) run(ctx context.Context) {
|
func (w *ServerWorker) run(ctx context.Context) {
|
||||||
defer func() {
|
input := w.link.Reader
|
||||||
common.Must(w.done.Close())
|
reader := &buf.BufferedReader{Reader: input}
|
||||||
}()
|
|
||||||
|
|
||||||
reader := &buf.BufferedReader{Reader: w.link.Reader}
|
defer w.sessionManager.Close()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@@ -379,6 +318,7 @@ func (w *ServerWorker) run(ctx context.Context) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Cause(err) != io.EOF {
|
if errors.Cause(err) != io.EOF {
|
||||||
errors.LogInfoInner(ctx, err, "unexpected EOF")
|
errors.LogInfoInner(ctx, err, "unexpected EOF")
|
||||||
|
common.Interrupt(input)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/signal/done"
|
|
||||||
"github.com/xtls/xray-core/transport/pipe"
|
"github.com/xtls/xray-core/transport/pipe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -51,14 +50,11 @@ func (m *SessionManager) Count() int {
|
|||||||
return int(m.count)
|
return int(m.count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *SessionManager) Allocate(Strategy *ClientStrategy) *Session {
|
func (m *SessionManager) Allocate() *Session {
|
||||||
m.Lock()
|
m.Lock()
|
||||||
defer m.Unlock()
|
defer m.Unlock()
|
||||||
|
|
||||||
MaxConcurrency := int(Strategy.MaxConcurrency)
|
if m.closed {
|
||||||
MaxConnection := uint16(Strategy.MaxConnection)
|
|
||||||
|
|
||||||
if m.closed || (MaxConcurrency > 0 && len(m.sessions) >= MaxConcurrency) || (MaxConnection > 0 && m.count >= MaxConnection) {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +62,6 @@ func (m *SessionManager) Allocate(Strategy *ClientStrategy) *Session {
|
|||||||
s := &Session{
|
s := &Session{
|
||||||
ID: m.count,
|
ID: m.count,
|
||||||
parent: m,
|
parent: m,
|
||||||
done: done.New(),
|
|
||||||
}
|
}
|
||||||
m.sessions[s.ID] = s
|
m.sessions[s.ID] = s
|
||||||
return s
|
return s
|
||||||
@@ -117,7 +112,7 @@ func (m *SessionManager) Get(id uint16) (*Session, bool) {
|
|||||||
return s, found
|
return s, found
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *SessionManager) CloseIfNoSessionAndIdle(checkSize int, checkCount int) bool {
|
func (m *SessionManager) CloseIfNoSession() bool {
|
||||||
m.Lock()
|
m.Lock()
|
||||||
defer m.Unlock()
|
defer m.Unlock()
|
||||||
|
|
||||||
@@ -125,13 +120,11 @@ func (m *SessionManager) CloseIfNoSessionAndIdle(checkSize int, checkCount int)
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(m.sessions) != 0 || checkSize != 0 || checkCount != int(m.count) {
|
if len(m.sessions) != 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
m.closed = true
|
m.closed = true
|
||||||
|
|
||||||
m.sessions = nil
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +154,6 @@ type Session struct {
|
|||||||
ID uint16
|
ID uint16
|
||||||
transferType protocol.TransferType
|
transferType protocol.TransferType
|
||||||
closed bool
|
closed bool
|
||||||
done *done.Instance
|
|
||||||
XUDP *XUDP
|
XUDP *XUDP
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,9 +168,6 @@ func (s *Session) Close(locked bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
s.closed = true
|
s.closed = true
|
||||||
if s.done != nil {
|
|
||||||
s.done.Close()
|
|
||||||
}
|
|
||||||
if s.XUDP == nil {
|
if s.XUDP == nil {
|
||||||
common.Interrupt(s.input)
|
common.Interrupt(s.input)
|
||||||
common.Close(s.output)
|
common.Close(s.output)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
func TestSessionManagerAdd(t *testing.T) {
|
func TestSessionManagerAdd(t *testing.T) {
|
||||||
m := NewSessionManager()
|
m := NewSessionManager()
|
||||||
|
|
||||||
s := m.Allocate(&ClientStrategy{})
|
s := m.Allocate()
|
||||||
if s.ID != 1 {
|
if s.ID != 1 {
|
||||||
t.Error("id: ", s.ID)
|
t.Error("id: ", s.ID)
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ func TestSessionManagerAdd(t *testing.T) {
|
|||||||
t.Error("size: ", m.Size())
|
t.Error("size: ", m.Size())
|
||||||
}
|
}
|
||||||
|
|
||||||
s = m.Allocate(&ClientStrategy{})
|
s = m.Allocate()
|
||||||
if s.ID != 2 {
|
if s.ID != 2 {
|
||||||
t.Error("id: ", s.ID)
|
t.Error("id: ", s.ID)
|
||||||
}
|
}
|
||||||
@@ -39,13 +39,13 @@ func TestSessionManagerAdd(t *testing.T) {
|
|||||||
|
|
||||||
func TestSessionManagerClose(t *testing.T) {
|
func TestSessionManagerClose(t *testing.T) {
|
||||||
m := NewSessionManager()
|
m := NewSessionManager()
|
||||||
s := m.Allocate(&ClientStrategy{})
|
s := m.Allocate()
|
||||||
|
|
||||||
if m.CloseIfNoSessionAndIdle(m.Size(), m.Count()) {
|
if m.CloseIfNoSession() {
|
||||||
t.Error("able to close")
|
t.Error("able to close")
|
||||||
}
|
}
|
||||||
m.Remove(false, s.ID)
|
m.Remove(false, s.ID)
|
||||||
if !m.CloseIfNoSessionAndIdle(m.Size(), m.Count()) {
|
if !m.CloseIfNoSession() {
|
||||||
t.Error("not able to close")
|
t.Error("not able to close")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
"github.com/xtls/xray-core/common/session"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Writer struct {
|
type Writer struct {
|
||||||
@@ -17,10 +16,9 @@ type Writer struct {
|
|||||||
hasError bool
|
hasError bool
|
||||||
transferType protocol.TransferType
|
transferType protocol.TransferType
|
||||||
globalID [8]byte
|
globalID [8]byte
|
||||||
inbound *session.Inbound
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWriter(id uint16, dest net.Destination, writer buf.Writer, transferType protocol.TransferType, globalID [8]byte, inbound *session.Inbound) *Writer {
|
func NewWriter(id uint16, dest net.Destination, writer buf.Writer, transferType protocol.TransferType, globalID [8]byte) *Writer {
|
||||||
return &Writer{
|
return &Writer{
|
||||||
id: id,
|
id: id,
|
||||||
dest: dest,
|
dest: dest,
|
||||||
@@ -28,7 +26,6 @@ func NewWriter(id uint16, dest net.Destination, writer buf.Writer, transferType
|
|||||||
followup: false,
|
followup: false,
|
||||||
transferType: transferType,
|
transferType: transferType,
|
||||||
globalID: globalID,
|
globalID: globalID,
|
||||||
inbound: inbound,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +43,6 @@ func (w *Writer) getNextFrameMeta() FrameMetadata {
|
|||||||
SessionID: w.id,
|
SessionID: w.id,
|
||||||
Target: w.dest,
|
Target: w.dest,
|
||||||
GlobalID: w.globalID,
|
GlobalID: w.globalID,
|
||||||
Inbound: w.inbound,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.followup {
|
if w.followup {
|
||||||
|
|||||||
@@ -1,14 +1,2 @@
|
|||||||
// Package net is a drop-in replacement to Golang's net package, with some more functionalities.
|
// Package net is a drop-in replacement to Golang's net package, with some more functionalities.
|
||||||
package net // import "github.com/xtls/xray-core/common/net"
|
package net // import "github.com/xtls/xray-core/common/net"
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
// defines the maximum time an idle TCP session can survive in the tunnel, so
|
|
||||||
// it should be consistent across HTTP versions and with other transports.
|
|
||||||
const ConnIdleTimeout = 300 * time.Second
|
|
||||||
|
|
||||||
// consistent with quic-go
|
|
||||||
const QuicgoH3KeepAlivePeriod = 10 * time.Second
|
|
||||||
|
|
||||||
// consistent with chrome
|
|
||||||
const ChromeH2KeepAlivePeriod = 45 * time.Second
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package filesystem
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/platform"
|
"github.com/xtls/xray-core/common/platform"
|
||||||
@@ -29,13 +28,6 @@ func ReadAsset(file string) ([]byte, error) {
|
|||||||
return ReadFile(platform.GetAssetLocation(file))
|
return ReadFile(platform.GetAssetLocation(file))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadCert(file string) ([]byte, error) {
|
|
||||||
if filepath.IsAbs(file) {
|
|
||||||
return ReadFile(file)
|
|
||||||
}
|
|
||||||
return ReadFile(platform.GetCertLocation(file))
|
|
||||||
}
|
|
||||||
|
|
||||||
func CopyFile(dst string, src string) error {
|
func CopyFile(dst string, src string) error {
|
||||||
bytes, err := ReadFile(src)
|
bytes, err := ReadFile(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func GetToolLocation(file string) string {
|
|||||||
return filepath.Join(toolPath, file)
|
return filepath.Join(toolPath, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAssetLocation searches for `file` in the env dir, the executable dir, and certain locations
|
// GetAssetLocation searches for `file` in certain locations
|
||||||
func GetAssetLocation(file string) string {
|
func GetAssetLocation(file string) string {
|
||||||
assetPath := NewEnvFlag(AssetLocation).GetValue(getExecutableDir)
|
assetPath := NewEnvFlag(AssetLocation).GetValue(getExecutableDir)
|
||||||
defPath := filepath.Join(assetPath, file)
|
defPath := filepath.Join(assetPath, file)
|
||||||
@@ -42,9 +42,3 @@ func GetAssetLocation(file string) string {
|
|||||||
// asset not found, let the caller throw out the error
|
// asset not found, let the caller throw out the error
|
||||||
return defPath
|
return defPath
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCertLocation searches for `file` in the env dir and the executable dir
|
|
||||||
func GetCertLocation(file string) string {
|
|
||||||
certPath := NewEnvFlag(CertLocation).GetValue(getExecutableDir)
|
|
||||||
return filepath.Join(certPath, file)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ const (
|
|||||||
ConfdirLocation = "xray.location.confdir"
|
ConfdirLocation = "xray.location.confdir"
|
||||||
ToolLocation = "xray.location.tool"
|
ToolLocation = "xray.location.tool"
|
||||||
AssetLocation = "xray.location.asset"
|
AssetLocation = "xray.location.asset"
|
||||||
CertLocation = "xray.location.cert"
|
|
||||||
|
|
||||||
UseReadV = "xray.buf.readv"
|
UseReadV = "xray.buf.readv"
|
||||||
UseFreedomSplice = "xray.buf.splice"
|
UseFreedomSplice = "xray.buf.splice"
|
||||||
|
|||||||
@@ -19,14 +19,8 @@ func GetToolLocation(file string) string {
|
|||||||
return filepath.Join(toolPath, file+".exe")
|
return filepath.Join(toolPath, file+".exe")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAssetLocation searches for `file` in the env dir and the executable dir
|
// GetAssetLocation searches for `file` in the executable dir
|
||||||
func GetAssetLocation(file string) string {
|
func GetAssetLocation(file string) string {
|
||||||
assetPath := NewEnvFlag(AssetLocation).GetValue(getExecutableDir)
|
assetPath := NewEnvFlag(AssetLocation).GetValue(getExecutableDir)
|
||||||
return filepath.Join(assetPath, file)
|
return filepath.Join(assetPath, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCertLocation searches for `file` in the env dir and the executable dir
|
|
||||||
func GetCertLocation(file string) string {
|
|
||||||
certPath := NewEnvFlag(CertLocation).GetValue(getExecutableDir)
|
|
||||||
return filepath.Join(certPath, file)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/xtls/xray-core/common/bitmask"
|
"github.com/xtls/xray-core/common/bitmask"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/common/uuid"
|
||||||
"golang.org/x/sys/cpu"
|
"golang.org/x/sys/cpu"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,12 +16,11 @@ const (
|
|||||||
RequestCommandTCP = RequestCommand(0x01)
|
RequestCommandTCP = RequestCommand(0x01)
|
||||||
RequestCommandUDP = RequestCommand(0x02)
|
RequestCommandUDP = RequestCommand(0x02)
|
||||||
RequestCommandMux = RequestCommand(0x03)
|
RequestCommandMux = RequestCommand(0x03)
|
||||||
RequestCommandRvs = RequestCommand(0x04)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c RequestCommand) TransferType() TransferType {
|
func (c RequestCommand) TransferType() TransferType {
|
||||||
switch c {
|
switch c {
|
||||||
case RequestCommandTCP, RequestCommandMux, RequestCommandRvs:
|
case RequestCommandTCP, RequestCommandMux:
|
||||||
return TransferTypeStream
|
return TransferTypeStream
|
||||||
case RequestCommandUDP:
|
case RequestCommandUDP:
|
||||||
return TransferTypePacket
|
return TransferTypePacket
|
||||||
@@ -70,19 +70,29 @@ type ResponseHeader struct {
|
|||||||
Command ResponseCommand
|
Command ResponseCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
type CommandSwitchAccount struct {
|
||||||
// Keep in sync with crypto/tls/cipher_suites.go.
|
Host net.Address
|
||||||
hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ && cpu.X86.HasSSE41 && cpu.X86.HasSSSE3
|
Port net.Port
|
||||||
hasGCMAsmARM64 = (cpu.ARM64.HasAES && cpu.ARM64.HasPMULL) || (runtime.GOOS == "darwin" && runtime.GOARCH == "arm64")
|
ID uuid.UUID
|
||||||
hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCTR && cpu.S390X.HasGHASH
|
Level uint32
|
||||||
hasGCMAsmPPC64 = runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le"
|
ValidMin byte
|
||||||
|
}
|
||||||
|
|
||||||
HasAESGCMHardwareSupport = hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X || hasGCMAsmPPC64
|
var (
|
||||||
|
hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ
|
||||||
|
hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL
|
||||||
|
// Keep in sync with crypto/aes/cipher_s390x.go.
|
||||||
|
hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR &&
|
||||||
|
(cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)
|
||||||
|
|
||||||
|
hasAESGCMHardwareSupport = runtime.GOARCH == "amd64" && hasGCMAsmAMD64 ||
|
||||||
|
runtime.GOARCH == "arm64" && hasGCMAsmARM64 ||
|
||||||
|
runtime.GOARCH == "s390x" && hasGCMAsmS390X
|
||||||
)
|
)
|
||||||
|
|
||||||
func (sc *SecurityConfig) GetSecurityType() SecurityType {
|
func (sc *SecurityConfig) GetSecurityType() SecurityType {
|
||||||
if sc == nil || sc.Type == SecurityType_AUTO {
|
if sc == nil || sc.Type == SecurityType_AUTO {
|
||||||
if HasAESGCMHardwareSupport {
|
if hasAESGCMHardwareSupport {
|
||||||
return SecurityType_AES128_GCM
|
return SecurityType_AES128_GCM
|
||||||
}
|
}
|
||||||
return SecurityType_CHACHA20_POLY1305
|
return SecurityType_CHACHA20_POLY1305
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ func SniffHTTP(b []byte, c context.Context) (*SniffHeader, error) {
|
|||||||
ShouldSniffAttr := true
|
ShouldSniffAttr := true
|
||||||
// If content.Attributes have information, that means it comes from HTTP inbound PlainHTTP mode.
|
// If content.Attributes have information, that means it comes from HTTP inbound PlainHTTP mode.
|
||||||
// It will set attributes, so skip it.
|
// It will set attributes, so skip it.
|
||||||
if content == nil || len(content.Attributes) != 0 {
|
if content == nil || content.AttributeLen() != 0 {
|
||||||
ShouldSniffAttr = false
|
ShouldSniffAttr = false
|
||||||
}
|
}
|
||||||
if err := beginWithHTTPMethod(b); err != nil {
|
if err := beginWithHTTPMethod(b); err != nil {
|
||||||
|
|||||||
@@ -1,7 +1 @@
|
|||||||
package protocol // import "github.com/xtls/xray-core/common/protocol"
|
package protocol // import "github.com/xtls/xray-core/common/protocol"
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ErrProtoNeedMoreData = errors.New("protocol matches, but need more data to complete sniffing")
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user