mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-12-19 05:34:36 +03:00
Compare commits
12 Commits
remove-udp
...
ax
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64c2986853 | ||
|
|
778876df9e | ||
|
|
5bf2b31883 | ||
|
|
390a76ff61 | ||
|
|
486f96838d | ||
|
|
710b283204 | ||
|
|
073ba6f1c5 | ||
|
|
a4f657f787 | ||
|
|
ea94d07f65 | ||
|
|
14aa152a8a | ||
|
|
e316cd4c66 | ||
|
|
16d96aa54d |
78
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
78
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,78 +0,0 @@
|
|||||||
name: Bug report
|
|
||||||
description: "Submit Xray-core bug"
|
|
||||||
body:
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Integrity requirements
|
|
||||||
description: |-
|
|
||||||
Please check all of the following options to prove that you have read and understood the requirements, otherwise this issue will be closed.
|
|
||||||
options:
|
|
||||||
- label: I 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.
|
|
||||||
required: true
|
|
||||||
- label: I provided the complete config and logs, rather than just providing the truncated parts based on my own judgment.
|
|
||||||
required: true
|
|
||||||
- label: I searched issues and did not find any similar issues.
|
|
||||||
required: true
|
|
||||||
- label: The problem can be successfully reproduced in the latest Release
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Description
|
|
||||||
description: |-
|
|
||||||
Please provide a detailed description of the error. And the information you think valuable.
|
|
||||||
If the problem occurs after the update, please provide the **specific** version
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Reproduction Method
|
|
||||||
description: |-
|
|
||||||
Based on the configuration you provided below, provide the method to reproduce the bug.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |-
|
|
||||||
## Configuration and Log Section
|
|
||||||
|
|
||||||
### For config
|
|
||||||
Please provide the configuration files that can reproduce the problem, including the server and client.
|
|
||||||
Don't just paste a big exported config file here. Eliminate useless inbound/outbound, rules, options, this can help determine the problem, if you really want to get help.
|
|
||||||
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
|
|
||||||
Please set the log level to debug and dnsLog to true first.
|
|
||||||
Restart Xray-core, then operate according to the reproduction method, try to reduce the irrelevant part in the log.
|
|
||||||
Remember to delete parts with personal information (such as UUID and IP).
|
|
||||||
Provide the log of Xray-core, not the log output by the panel or other things.
|
|
||||||
|
|
||||||
### Finally
|
|
||||||
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
|
|
||||||
```
|
|
||||||
<details><pre><code>
|
|
||||||
(config)
|
|
||||||
</code></pre></details>
|
|
||||||
```
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Client config
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Server config
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Client log
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Server log
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
78
.github/ISSUE_TEMPLATE/bug_report_zh.yml
vendored
78
.github/ISSUE_TEMPLATE/bug_report_zh.yml
vendored
@@ -1,78 +0,0 @@
|
|||||||
name: bug反馈
|
|
||||||
description: "提交 Xray-core bug"
|
|
||||||
body:
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: 完整性要求
|
|
||||||
description: |-
|
|
||||||
请勾选以下所有选项以证明您已经阅读并理解了以下要求,否则该 issue 将被关闭。
|
|
||||||
options:
|
|
||||||
- label: 我读完了 issue 模板中的所有注释,确保填写符合要求。
|
|
||||||
required: true
|
|
||||||
- label: 我保证阅读了文档,了解所有我编写的配置文件项的含义,而不是大量堆砌看似有用的选项或默认值。
|
|
||||||
required: true
|
|
||||||
- label: 我提供了完整的配置文件和日志,而不是出于自己的判断只给出截取的部分。
|
|
||||||
required: true
|
|
||||||
- label: 我搜索了 issues, 没有发现已提出的类似问题。
|
|
||||||
required: true
|
|
||||||
- label: 问题在 Release 最新的版本上可以成功复现
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 描述
|
|
||||||
description: |-
|
|
||||||
请提供错误的详细描述。以及你认为有价值的信息。
|
|
||||||
如果问题在更新后出现,请提供**具体**出现问题的版本号。
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 重现方式
|
|
||||||
description: |-
|
|
||||||
基于你下面提供的配置,提供重现BUG方法。
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |-
|
|
||||||
## 配置与日志部分
|
|
||||||
|
|
||||||
### 对于配置文件
|
|
||||||
请提供可以重现问题的配置文件,包括服务端和客户端。
|
|
||||||
不要直接在这里黏贴一大段导出的 config 文件。去掉无用的出入站、规则、选项,这可以帮助确定问题,如果你真的想得到帮助。
|
|
||||||
在去掉不影响复现的部分后,提供实际运行的**完整**文件。
|
|
||||||
完整的含义:可以直接使用这个配置启动核心,**不是截取的部分配置**。对于密钥等参数使用重新生成未实际使用的有效参数填充。
|
|
||||||
|
|
||||||
### 对于日志
|
|
||||||
请先将日志等级设置为 debug, dnsLog 设置为true.
|
|
||||||
重启 Xray-core ,再按复现方式操作,尽量减少日志中的无关部分。
|
|
||||||
记得删除有关个人信息(如UUID与IP)的部分。
|
|
||||||
提供 Xray-core 的日志,而不是面板或者别的东西输出的日志。
|
|
||||||
|
|
||||||
### 最后
|
|
||||||
把下面的每格具体内容需要放在 ```<details><pre><code>``` 和 ```</code></pre></details>``` 中间,如
|
|
||||||
```
|
|
||||||
<details><pre><code>
|
|
||||||
(config)
|
|
||||||
</code></pre></details>
|
|
||||||
```
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 客户端配置
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 服务端配置
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 客户端日志
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 服务端日志
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,4 +0,0 @@
|
|||||||
contact_links:
|
|
||||||
- name: Community Support and Questions
|
|
||||||
url: https://github.com/XTLS/Xray-core/discussions
|
|
||||||
about: Please ask and answer questions there. The issue tracker is for issues with core.
|
|
||||||
4
.github/build/friendly-filenames.json
vendored
4
.github/build/friendly-filenames.json
vendored
@@ -2,6 +2,7 @@
|
|||||||
"android-arm64": { "friendlyName": "android-arm64-v8a" },
|
"android-arm64": { "friendlyName": "android-arm64-v8a" },
|
||||||
"darwin-amd64": { "friendlyName": "macos-64" },
|
"darwin-amd64": { "friendlyName": "macos-64" },
|
||||||
"darwin-arm64": { "friendlyName": "macos-arm64-v8a" },
|
"darwin-arm64": { "friendlyName": "macos-arm64-v8a" },
|
||||||
|
"dragonfly-amd64": { "friendlyName": "dragonfly-64" },
|
||||||
"freebsd-386": { "friendlyName": "freebsd-32" },
|
"freebsd-386": { "friendlyName": "freebsd-32" },
|
||||||
"freebsd-amd64": { "friendlyName": "freebsd-64" },
|
"freebsd-amd64": { "friendlyName": "freebsd-64" },
|
||||||
"freebsd-arm64": { "friendlyName": "freebsd-arm64-v8a" },
|
"freebsd-arm64": { "friendlyName": "freebsd-arm64-v8a" },
|
||||||
@@ -21,7 +22,6 @@
|
|||||||
"linux-ppc64le": { "friendlyName": "linux-ppc64le" },
|
"linux-ppc64le": { "friendlyName": "linux-ppc64le" },
|
||||||
"linux-ppc64": { "friendlyName": "linux-ppc64" },
|
"linux-ppc64": { "friendlyName": "linux-ppc64" },
|
||||||
"linux-riscv64": { "friendlyName": "linux-riscv64" },
|
"linux-riscv64": { "friendlyName": "linux-riscv64" },
|
||||||
"linux-loong64": { "friendlyName": "linux-loong64" },
|
|
||||||
"linux-s390x": { "friendlyName": "linux-s390x" },
|
"linux-s390x": { "friendlyName": "linux-s390x" },
|
||||||
"openbsd-386": { "friendlyName": "openbsd-32" },
|
"openbsd-386": { "friendlyName": "openbsd-32" },
|
||||||
"openbsd-amd64": { "friendlyName": "openbsd-64" },
|
"openbsd-amd64": { "friendlyName": "openbsd-64" },
|
||||||
@@ -31,4 +31,4 @@
|
|||||||
"windows-amd64": { "friendlyName": "windows-64" },
|
"windows-amd64": { "friendlyName": "windows-64" },
|
||||||
"windows-arm64": { "friendlyName": "windows-arm64-v8a" },
|
"windows-arm64": { "friendlyName": "windows-arm64-v8a" },
|
||||||
"windows-arm7": { "friendlyName": "windows-arm32-v7a" }
|
"windows-arm7": { "friendlyName": "windows-arm32-v7a" }
|
||||||
}
|
}
|
||||||
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
@@ -9,7 +9,3 @@ updates:
|
|||||||
directory: "/" # Location of package manifests
|
directory: "/" # Location of package manifests
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
|
|||||||
62
.github/docker/Dockerfile
vendored
62
.github/docker/Dockerfile
vendored
@@ -1,62 +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 -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
|
|
||||||
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
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/usr/local/bin/xray" ]
|
|
||||||
CMD [ "-confdir", "/usr/local/etc/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 -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/" ]
|
|
||||||
133
.github/workflows/docker.yml
vendored
133
.github/workflows/docker.yml
vendored
@@ -1,133 +0,0 @@
|
|||||||
name: Build and Push Docker Image
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types:
|
|
||||||
- published
|
|
||||||
- released
|
|
||||||
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
tag:
|
|
||||||
description: "Docker image tag:"
|
|
||||||
required: true
|
|
||||||
latest:
|
|
||||||
description: "Set to latest"
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-and-push:
|
|
||||||
if: (github.event.action != 'published') || (github.event.action == 'published' && github.event.release.prerelease == true)
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Set repository and image name to lowercase
|
|
||||||
env:
|
|
||||||
IMAGE_NAME: "${{ github.repository }}"
|
|
||||||
run: |
|
|
||||||
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
|
|
||||||
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
|
|
||||||
|
|
||||||
- name: Validate and extract tag
|
|
||||||
run: |
|
|
||||||
SOURCE_TAG="${{ github.event.inputs.tag }}"
|
|
||||||
if [[ -z "$SOURCE_TAG" ]]; then
|
|
||||||
SOURCE_TAG="${{ github.ref_name }}"
|
|
||||||
fi
|
|
||||||
if [[ -z "$SOURCE_TAG" ]]; then
|
|
||||||
SOURCE_TAG="${{ github.event.release.tag_name }}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "$SOURCE_TAG" ]]; then
|
|
||||||
echo "Error: Could not determine a valid tag source. Input tag and context tag (github.ref_name) are both empty."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$SOURCE_TAG" =~ ^v[0-9]+\.[0-9] ]]; then
|
|
||||||
IMAGE_TAG="${SOURCE_TAG#v}"
|
|
||||||
else
|
|
||||||
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@v5
|
|
||||||
|
|
||||||
- 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
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build Docker image (main architectures)
|
|
||||||
id: build_main_arches
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: .github/docker/Dockerfile
|
|
||||||
platforms: |
|
|
||||||
linux/amd64
|
|
||||||
linux/arm/v7
|
|
||||||
linux/arm64/v8
|
|
||||||
linux/ppc64le
|
|
||||||
linux/s390x
|
|
||||||
provenance: false
|
|
||||||
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
|
||||||
|
|
||||||
- name: Build Docker image (additional architectures)
|
|
||||||
id: build_additional_arches
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: .github/docker/Dockerfile.usa
|
|
||||||
platforms: |
|
|
||||||
linux/386
|
|
||||||
linux/arm/v6
|
|
||||||
linux/riscv64
|
|
||||||
linux/loong64
|
|
||||||
provenance: false
|
|
||||||
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
|
||||||
|
|
||||||
- name: Create manifest list and push
|
|
||||||
run: |
|
|
||||||
echo "Creating multi-arch manifest with tag: '${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}'."
|
|
||||||
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
|
|
||||||
148
.github/workflows/release-win7.yml
vendored
148
.github/workflows/release-win7.yml
vendored
@@ -1,148 +0,0 @@
|
|||||||
name: Build and Release for Windows 7
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, synchronize, reopened]
|
|
||||||
|
|
||||||
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:
|
|
||||||
needs: check-assets
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
# BEGIN Windows 7
|
|
||||||
- goos: windows
|
|
||||||
goarch: amd64
|
|
||||||
assetname: win7-64
|
|
||||||
- goos: windows
|
|
||||||
goarch: 386
|
|
||||||
assetname: win7-32
|
|
||||||
# END Windows 7
|
|
||||||
fail-fast: false
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
GOOS: ${{ matrix.goos}}
|
|
||||||
GOARCH: ${{ matrix.goarch }}
|
|
||||||
CGO_ENABLED: 0
|
|
||||||
steps:
|
|
||||||
- name: Checkout codebase
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Show workflow information
|
|
||||||
run: |
|
|
||||||
_NAME=${{ matrix.assetname }}
|
|
||||||
echo "GOOS: ${{ matrix.goos }}, GOARCH: ${{ matrix.goarch }}, RELEASE_NAME: $_NAME"
|
|
||||||
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set up Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version-file: go.mod
|
|
||||||
check-latest: true
|
|
||||||
|
|
||||||
- name: Setup patched builder
|
|
||||||
run: |
|
|
||||||
GOSDK=$(go env GOROOT)
|
|
||||||
rm -r $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
|
|
||||||
unzip ./go-for-win7-linux-amd64.zip -d $GOSDK
|
|
||||||
rm ./go-for-win7-linux-amd64.zip
|
|
||||||
|
|
||||||
- name: Get project dependencies
|
|
||||||
run: go mod download
|
|
||||||
|
|
||||||
- name: Build Xray
|
|
||||||
run: |
|
|
||||||
mkdir -p build_assets
|
|
||||||
COMMID=$(git describe --always --dirty)
|
|
||||||
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
|
|
||||||
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
|
|
||||||
# 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
|
|
||||||
|
|
||||||
- name: Restore Geodat Cache
|
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-geodat-
|
|
||||||
|
|
||||||
- name: Copy README.md & LICENSE
|
|
||||||
run: |
|
|
||||||
mv -f resources/* build_assets
|
|
||||||
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
|
|
||||||
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
|
|
||||||
|
|
||||||
- name: Create ZIP archive
|
|
||||||
if: github.event_name == 'release'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
pushd build_assets || exit 1
|
|
||||||
touch -mt $(date +%Y01010000) *
|
|
||||||
zip -9vr ../Xray-${{ env.ASSET_NAME }}.zip .
|
|
||||||
popd || exit 1
|
|
||||||
FILE=./Xray-${{ env.ASSET_NAME }}.zip
|
|
||||||
DGST=$FILE.dgst
|
|
||||||
for METHOD in {"md5","sha1","sha256","sha512"}
|
|
||||||
do
|
|
||||||
openssl dgst -$METHOD $FILE | sed 's/([^)]*)//g' >>$DGST
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Change the name
|
|
||||||
run: |
|
|
||||||
mv build_assets Xray-${{ env.ASSET_NAME }}
|
|
||||||
|
|
||||||
- name: Upload files to Artifacts
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: Xray-${{ env.ASSET_NAME }}
|
|
||||||
path: |
|
|
||||||
./Xray-${{ env.ASSET_NAME }}/*
|
|
||||||
|
|
||||||
- name: Upload binaries to release
|
|
||||||
uses: svenstaro/upload-release-action@v2
|
|
||||||
if: github.event_name == 'release'
|
|
||||||
with:
|
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
file: ./Xray-${{ env.ASSET_NAME }}.zip*
|
|
||||||
tag: ${{ github.ref }}
|
|
||||||
file_glob: true
|
|
||||||
188
.github/workflows/release.yml
vendored
188
.github/workflows/release.yml
vendored
@@ -5,71 +5,35 @@ on:
|
|||||||
release:
|
release:
|
||||||
types: [published]
|
types: [published]
|
||||||
push:
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "**/*.go"
|
||||||
|
- "go.mod"
|
||||||
|
- "go.sum"
|
||||||
|
- ".github/workflows/*.yml"
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, synchronize, reopened]
|
types: [opened, synchronize, reopened]
|
||||||
|
paths:
|
||||||
|
- "**/*.go"
|
||||||
|
- "go.mod"
|
||||||
|
- "go.sum"
|
||||||
|
- ".github/workflows/*.yml"
|
||||||
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@v7
|
|
||||||
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:
|
|
||||||
contents: write
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
# Include amd64 on all platforms.
|
# Include amd64 on all platforms.
|
||||||
goos: [windows, freebsd, openbsd, linux, darwin]
|
goos: [windows, freebsd, openbsd, linux, dragonfly, darwin]
|
||||||
goarch: [amd64, 386]
|
goarch: [amd64, 386]
|
||||||
patch-assetname: [""]
|
|
||||||
exclude:
|
exclude:
|
||||||
# Exclude i386 on darwin
|
# Exclude i386 on darwin and dragonfly.
|
||||||
|
- goarch: 386
|
||||||
|
goos: dragonfly
|
||||||
- goarch: 386
|
- goarch: 386
|
||||||
goos: darwin
|
goos: darwin
|
||||||
include:
|
include:
|
||||||
# BEGIN MacOS ARM64
|
# BEIGIN MacOS ARM64
|
||||||
- goos: darwin
|
- goos: darwin
|
||||||
goarch: arm64
|
goarch: arm64
|
||||||
# END MacOS ARM64
|
# END MacOS ARM64
|
||||||
@@ -88,11 +52,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
|
||||||
@@ -100,14 +59,12 @@ jobs:
|
|||||||
goarch: arm
|
goarch: arm
|
||||||
goarm: 7
|
goarm: 7
|
||||||
# BEGIN Other architectures
|
# BEGIN Other architectures
|
||||||
# BEGIN riscv64 & ARM64 & LOONG64
|
# BEGIN riscv64 & ARM64
|
||||||
- goos: linux
|
- goos: linux
|
||||||
goarch: arm64
|
goarch: arm64
|
||||||
- goos: linux
|
- goos: linux
|
||||||
goarch: riscv64
|
goarch: riscv64
|
||||||
- goos: linux
|
# END riscv64 & ARM64
|
||||||
goarch: loong64
|
|
||||||
# END riscv64 & ARM64 & LOONG64
|
|
||||||
# BEGIN MIPS
|
# BEGIN MIPS
|
||||||
- goos: linux
|
- goos: linux
|
||||||
goarch: mips64
|
goarch: mips64
|
||||||
@@ -153,80 +110,75 @@ jobs:
|
|||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codebase
|
- name: Checkout codebase
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set up NDK
|
- name: Show workflow information
|
||||||
if: matrix.goos == 'android'
|
id: get_filename
|
||||||
run: |
|
run: |
|
||||||
wget -qO android-ndk.zip https://dl.google.com/android/repository/android-ndk-r28b-linux.zip
|
export _NAME=$(jq ".[\"$GOOS-$GOARCH$GOARM$GOMIPS\"].friendlyName" -r < .github/build/friendly-filenames.json)
|
||||||
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
|
|
||||||
run: |
|
|
||||||
_NAME=${{ matrix.patch-assetname }}
|
|
||||||
[ -n "$_NAME" ] || _NAME=$(jq ".[\"$GOOS-$GOARCH$GOARM$GOMIPS\"].friendlyName" -r < .github/build/friendly-filenames.json)
|
|
||||||
echo "GOOS: $GOOS, GOARCH: $GOARCH, GOARM: $GOARM, GOMIPS: $GOMIPS, RELEASE_NAME: $_NAME"
|
echo "GOOS: $GOOS, GOARCH: $GOARCH, GOARM: $GOARM, GOMIPS: $GOMIPS, RELEASE_NAME: $_NAME"
|
||||||
|
echo "::set-output name=ASSET_NAME::$_NAME"
|
||||||
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version: ^1.17.2
|
||||||
check-latest: true
|
|
||||||
|
|
||||||
- name: Get project dependencies
|
- name: Get project dependencies
|
||||||
run: go mod download
|
run: go mod download
|
||||||
|
|
||||||
|
- name: Replace Custom to Commit ID
|
||||||
|
if: github.event_name != 'release'
|
||||||
|
run: |
|
||||||
|
ID=$(git rev-parse --short ${{ github.sha }})
|
||||||
|
if [ "${{ github.event_name }}" == 'pull_request' ]
|
||||||
|
then
|
||||||
|
ID=$(git rev-parse --short ${{ github.event.pull_request.head.sha }})
|
||||||
|
fi
|
||||||
|
sed -i '/build/ s/Custom/'$ID'/' ./core/core.go
|
||||||
|
|
||||||
- name: Build Xray
|
- name: Build Xray
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build_assets
|
mkdir -p build_assets
|
||||||
COMMID=$(git describe --always --dirty)
|
go build -v -o build_assets/xray -trimpath -ldflags "-s -w -buildid=" ./main
|
||||||
if [[ ${GOOS} == 'windows' ]]; then
|
|
||||||
echo 'Building Xray for Windows...'
|
- name: Build Mips softfloat Xray
|
||||||
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
|
if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle'
|
||||||
echo 'CreateObject("Wscript.Shell").Run "xray.exe -config config.json",0' > build_assets/xray_no_window.vbs
|
run: |
|
||||||
echo 'Start-Process -FilePath ".\xray.exe" -ArgumentList "-config .\config.json" -WindowStyle Hidden' > build_assets/xray_no_window.ps1
|
GOMIPS=softfloat go build -v -o build_assets/xray_softfloat -trimpath -ldflags "-s -w -buildid=" ./main
|
||||||
# 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
|
- name: Rename Windows Xray
|
||||||
else
|
if: matrix.goos == 'windows'
|
||||||
echo 'Building Xray...'
|
run: |
|
||||||
if [[ ${GOARCH} == 'mips' || ${GOARCH} == 'mipsle' ]]; then
|
cd ./build_assets || exit 1
|
||||||
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
|
mv xray xray.exe
|
||||||
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
|
- name: Prepare to release
|
||||||
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
|
|
||||||
|
|
||||||
- name: Restore Geodat Cache
|
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-geodat-
|
|
||||||
|
|
||||||
- name: Copy README.md & LICENSE
|
|
||||||
run: |
|
run: |
|
||||||
mv -f resources/* build_assets
|
|
||||||
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
|
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
|
||||||
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
|
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
|
||||||
|
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite')
|
||||||
|
for i in "${LIST[@]}"
|
||||||
|
do
|
||||||
|
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3}'))
|
||||||
|
LASTEST_TAG="$(curl -sL "https://api.github.com/repos/v2fly/${INFO[0]}/releases" | jq -r ".[0].tag_name" || echo "latest")"
|
||||||
|
FILE_NAME="${INFO[2]}.dat"
|
||||||
|
echo -e "Downloading ${FILE_NAME}..."
|
||||||
|
curl -L "https://github.com/v2fly/${INFO[0]}/releases/download/${LASTEST_TAG}/${INFO[1]}.dat" -o ./build_assets/${FILE_NAME}
|
||||||
|
echo -e "Verifying HASH key..."
|
||||||
|
HASH="$(curl -sL "https://github.com/v2fly/${INFO[0]}/releases/download/${LASTEST_TAG}/${INFO[1]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
|
||||||
|
[ "$(sha256sum "./build_assets/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ] || { echo -e "The HASH key of ${FILE_NAME} does not match cloud one."; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
- name: Create ZIP archive
|
- name: Create ZIP archive
|
||||||
if: github.event_name == 'release'
|
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
pushd build_assets || exit 1
|
pushd build_assets || exit 1
|
||||||
touch -mt $(date +%Y01010000) *
|
touch -mt $(date +%Y01010000) *
|
||||||
zip -9vr ../Xray-${{ env.ASSET_NAME }}.zip .
|
zip -9vr ../Xray-$ASSET_NAME.zip .
|
||||||
popd || exit 1
|
popd || exit 1
|
||||||
FILE=./Xray-${{ env.ASSET_NAME }}.zip
|
FILE=./Xray-$ASSET_NAME.zip
|
||||||
DGST=$FILE.dgst
|
DGST=$FILE.dgst
|
||||||
for METHOD in {"md5","sha1","sha256","sha512"}
|
for METHOD in {"md5","sha1","sha256","sha512"}
|
||||||
do
|
do
|
||||||
@@ -235,20 +187,20 @@ jobs:
|
|||||||
|
|
||||||
- name: Change the name
|
- name: Change the name
|
||||||
run: |
|
run: |
|
||||||
mv build_assets Xray-${{ env.ASSET_NAME }}
|
mv build_assets Xray-$ASSET_NAME
|
||||||
|
|
||||||
- name: Upload files to Artifacts
|
- name: Upload files to Artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: Xray-${{ env.ASSET_NAME }}
|
name: Xray-${{ steps.get_filename.outputs.ASSET_NAME }}
|
||||||
path: |
|
path: |
|
||||||
./Xray-${{ env.ASSET_NAME }}/*
|
./Xray-${{ steps.get_filename.outputs.ASSET_NAME }}/*
|
||||||
|
|
||||||
- name: Upload binaries to release
|
- name: Upload binaries to release
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: svenstaro/upload-release-action@v2
|
||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
file: ./Xray-${{ env.ASSET_NAME }}.zip*
|
file: ./Xray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip*
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
file_glob: true
|
file_glob: true
|
||||||
|
|||||||
65
.github/workflows/scheduled-assets-update.yml
vendored
65
.github/workflows/scheduled-assets-update.yml
vendored
@@ -1,65 +0,0 @@
|
|||||||
name: Scheduled assets update
|
|
||||||
|
|
||||||
# NOTE: This Github Actions is required by other actions, for preparing other packaging assets in a
|
|
||||||
# routine manner, for example: GeoIP/GeoSite.
|
|
||||||
# Currently updating:
|
|
||||||
# - Geodat (GeoIP/Geosite)
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
# Update GeoData on every day (22:30 UTC)
|
|
||||||
- cron: "30 22 * * *"
|
|
||||||
push:
|
|
||||||
# Prevent triggering update request storm
|
|
||||||
paths:
|
|
||||||
- ".github/workflows/scheduled-assets-update.yml"
|
|
||||||
pull_request:
|
|
||||||
# Prevent triggering update request storm
|
|
||||||
paths:
|
|
||||||
- ".github/workflows/scheduled-assets-update.yml"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
geodat:
|
|
||||||
if: github.event.schedule == '30 22 * * *' || github.event_name == 'push'|| github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Restore Geodat Cache
|
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-geodat-
|
|
||||||
|
|
||||||
- name: Update Geodat
|
|
||||||
id: update
|
|
||||||
uses: nick-fields/retry@v3
|
|
||||||
with:
|
|
||||||
timeout_minutes: 60
|
|
||||||
retry_wait_seconds: 60
|
|
||||||
max_attempts: 60
|
|
||||||
command: |
|
|
||||||
[ -d 'resources' ] || mkdir resources
|
|
||||||
LIST=('Loyalsoldier v2ray-rules-dat geoip geoip' 'Loyalsoldier v2ray-rules-dat geosite geosite')
|
|
||||||
for i in "${LIST[@]}"
|
|
||||||
do
|
|
||||||
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3,$4}'))
|
|
||||||
FILE_NAME="${INFO[3]}.dat"
|
|
||||||
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}')"
|
|
||||||
if [ -s "./resources/${FILE_NAME}" ] && [ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ]; then
|
|
||||||
continue
|
|
||||||
else
|
|
||||||
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}
|
|
||||||
echo -e "Verifying HASH key..."
|
|
||||||
[ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ] || { echo -e "The HASH key of ${FILE_NAME} does not match cloud one."; exit 1; }
|
|
||||||
echo "unhit=true" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Save Geodat Cache
|
|
||||||
uses: actions/cache/save@v4
|
|
||||||
if: ${{ steps.update.outputs.unhit }}
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-geodat-${{ github.sha }}-${{ github.run_number }}
|
|
||||||
71
.github/workflows/test.yml
vendored
71
.github/workflows/test.yml
vendored
@@ -2,60 +2,47 @@ name: Test
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "**/*.go"
|
||||||
|
- "go.mod"
|
||||||
|
- "go.sum"
|
||||||
|
- ".github/workflows/*.yml"
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, synchronize, reopened]
|
types: [opened, synchronize, reopened]
|
||||||
|
paths:
|
||||||
|
- "**/*.go"
|
||||||
|
- "go.mod"
|
||||||
|
- "go.sum"
|
||||||
|
- ".github/workflows/*.yml"
|
||||||
|
|
||||||
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:
|
|
||||||
contents: read
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [windows-latest, ubuntu-latest, macos-latest]
|
os: [windows-latest, ubuntu-latest, macos-latest]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codebase
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version: ^1.17.2
|
||||||
check-latest: true
|
- name: Checkout codebase
|
||||||
- name: Restore Geodat Cache
|
uses: actions/checkout@v2
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
- name: Prepare geo*dat
|
||||||
path: resources
|
if: ${{ matrix.os != 'windows-latest' }}
|
||||||
key: xray-geodat-
|
run: |
|
||||||
enableCrossOsArchive: true
|
mkdir resources
|
||||||
|
wget -O ./resources/geoip.dat https://github.com/v2fly/geoip/releases/latest/download/geoip.dat
|
||||||
|
wget -O ./resources/geosite.dat https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat
|
||||||
|
- name: Prepare geo*dat for Windows
|
||||||
|
if: ${{ matrix.os == 'windows-latest' }}
|
||||||
|
run: |
|
||||||
|
mkdir resources
|
||||||
|
Invoke-WebRequest -Uri "https://github.com/v2fly/geoip/releases/latest/download/geoip.dat" -OutFile "./resources/geoip.dat"
|
||||||
|
Invoke-WebRequest -Uri "https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat" -OutFile "./resources/geosite.dat"
|
||||||
- name: Test
|
- name: Test
|
||||||
run: go test -timeout 1h -v ./...
|
run: go test -timeout 1h -v ./...
|
||||||
|
|||||||
52
.gitignore
vendored
52
.gitignore
vendored
@@ -11,58 +11,18 @@
|
|||||||
# 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
|
v2ray
|
||||||
*.gz
|
v2ctl
|
||||||
*.bz2
|
|
||||||
|
|
||||||
# Go build binaries
|
|
||||||
xray
|
|
||||||
xray_softfloat
|
|
||||||
mockgen
|
mockgen
|
||||||
vprotogen
|
vprotogen
|
||||||
!infra/vprotogen/
|
!infra/vprotogen/
|
||||||
errorgen
|
errorgen
|
||||||
!common/errors/errorgen/
|
!common/errors/errorgen/
|
||||||
*.dat
|
*.dat
|
||||||
|
|
||||||
# Build assets
|
|
||||||
/build_assets/
|
|
||||||
|
|
||||||
# Output from dlv test
|
|
||||||
**/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
|
|
||||||
|
|||||||
235
README.md
235
README.md
@@ -1,26 +1,85 @@
|
|||||||
# Project X
|
# Project X
|
||||||
|
|
||||||
[Project X](https://github.com/XTLS) originates from XTLS protocol, providing a set of network tools such as [Xray-core](https://github.com/XTLS/Xray-core) and [REALITY](https://github.com/XTLS/REALITY).
|
[Project X](https://github.com/XTLS) originates from XTLS protocol, provides a set of network tools such as [Xray-core](https://github.com/XTLS/Xray-core) and [Xray-flutter](https://github.com/XTLS/Xray-flutter).
|
||||||
|
|
||||||
[README](https://github.com/XTLS/Xray-core#readme) is open, so feel free to submit your project [here](https://github.com/XTLS/Xray-core/pulls).
|
|
||||||
|
|
||||||
## 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)
|
|
||||||
|
|
||||||
- **ETH/USDT/USDC: `0xDc3Fe44F0f25D13CACb1C4896CD0D321df3146Ee`**
|
|
||||||
- **REALITY NFT: https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/2**
|
|
||||||
- **Related links: https://opensea.io/collection/xtls, [Announcement of NFTs by Project X](https://github.com/XTLS/Xray-core/discussions/3633), [XHTTP: Beyond REALITY](https://github.com/XTLS/Xray-core/discussions/4113)**
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[Mozilla Public License Version 2.0](https://github.com/XTLS/Xray-core/blob/main/LICENSE)
|
[Mozilla Public License Version 2.0](https://github.com/XTLS/Xray-core/blob/main/LICENSE)
|
||||||
|
|
||||||
## Documentation
|
## Installation
|
||||||
|
|
||||||
[Project X Official Website](https://xtls.github.io)
|
- Linux Script
|
||||||
|
- [Xray-install](https://github.com/XTLS/Xray-install)
|
||||||
|
- [Xray-script](https://github.com/kirin10000/Xray-script)
|
||||||
|
- Docker
|
||||||
|
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
|
||||||
|
- Xray-docker
|
||||||
|
- One Click
|
||||||
|
- [ProxySU](https://github.com/proxysu/ProxySU)
|
||||||
|
- [v2ray-agent](https://github.com/mack-a/v2ray-agent)
|
||||||
|
- [Xray-yes](https://github.com/jiuqi9997/Xray-yes)
|
||||||
|
- [Xray_onekey](https://github.com/wulabing/Xray_onekey)
|
||||||
|
- Magisk
|
||||||
|
- [Xray4Magisk](https://github.com/CerteKim/Xray4Magisk)
|
||||||
|
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
|
||||||
|
- Homebrew
|
||||||
|
- `brew install xray`
|
||||||
|
- [(Tap) Repository 0](https://github.com/N4FA/homebrew-xray)
|
||||||
|
- [(Tap) Repository 1](https://github.com/xiruizhao/homebrew-xray)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
[Xray-examples](https://github.com/XTLS/Xray-examples) / [VLESS-TCP-XTLS-WHATEVER](https://github.com/XTLS/Xray-examples/tree/main/VLESS-TCP-XTLS-WHATEVER)
|
||||||
|
|
||||||
|
## GUI Clients
|
||||||
|
|
||||||
|
- OpenWrt
|
||||||
|
- [PassWall](https://github.com/xiaorouji/openwrt-passwall)
|
||||||
|
- [Hello World](https://github.com/jerrykuku/luci-app-vssr)
|
||||||
|
- [ShadowSocksR Plus+](https://github.com/fw876/helloworld)
|
||||||
|
- [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray))
|
||||||
|
- Windows
|
||||||
|
- [v2rayN](https://github.com/2dust/v2rayN)
|
||||||
|
- [Qv2ray](https://github.com/Qv2ray/Qv2ray) (This project had been archived and currently inactive)
|
||||||
|
- [Netch (NetFilter & TUN/TAP)](https://github.com/NetchX/Netch)
|
||||||
|
- Android
|
||||||
|
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
||||||
|
- [AnXray](https://github.com/XTLS/AnXray)
|
||||||
|
- [Kitsunebi](https://github.com/rurirei/Kitsunebi/tree/release_xtls)
|
||||||
|
- iOS & macOS (with M1 chip)
|
||||||
|
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
||||||
|
- macOS (Intel chip & M1 chip)
|
||||||
|
- [Qv2ray](https://github.com/Qv2ray/Qv2ray) (This project had been archived and currently inactive)
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
This repo relies on the following third-party projects:
|
||||||
|
|
||||||
|
- Special thanks:
|
||||||
|
- [v2fly/v2ray-core](https://github.com/v2fly/v2ray-core)
|
||||||
|
- In production:
|
||||||
|
- [gorilla/websocket](https://github.com/gorilla/websocket)
|
||||||
|
- [lucas-clemente/quic-go](https://github.com/lucas-clemente/quic-go)
|
||||||
|
- [pires/go-proxyproto](https://github.com/pires/go-proxyproto)
|
||||||
|
- [seiflotfy/cuckoofilter](https://github.com/seiflotfy/cuckoofilter)
|
||||||
|
- [google/starlark-go](https://github.com/google/starlark-go)
|
||||||
|
- For testing only:
|
||||||
|
- [miekg/dns](https://github.com/miekg/dns)
|
||||||
|
- [h12w/socks](https://github.com/h12w/socks)
|
||||||
|
|
||||||
|
## Compilation
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
```
|
||||||
|
go build -o xray.exe -trimpath -ldflags "-s -w -buildid=" ./main
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linux / macOS
|
||||||
|
|
||||||
|
```
|
||||||
|
go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
|
||||||
|
```
|
||||||
|
|
||||||
## Telegram
|
## Telegram
|
||||||
|
|
||||||
@@ -28,152 +87,6 @@
|
|||||||
|
|
||||||
[Project X Channel](https://t.me/projectXtls)
|
[Project X Channel](https://t.me/projectXtls)
|
||||||
|
|
||||||
[Project VLESS](https://t.me/projectVless) (Русский)
|
|
||||||
|
|
||||||
[Project XHTTP](https://t.me/projectXhttp) (Persian)
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
- Linux Script
|
|
||||||
- [XTLS/Xray-install](https://github.com/XTLS/Xray-install) (**Official**)
|
|
||||||
- [tempest](https://github.com/team-cloudchaser/tempest) (supports [`systemd`](https://systemd.io) and [OpenRC](https://github.com/OpenRC/openrc); Linux-only)
|
|
||||||
- Docker
|
|
||||||
- [ghcr.io/xtls/xray-core](https://ghcr.io/xtls/xray-core) (**Official**)
|
|
||||||
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
|
|
||||||
- [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:**
|
|
||||||
- [Remnawave](https://github.com/remnawave/panel)
|
|
||||||
- [Marzban](https://github.com/Gozargah/Marzban)
|
|
||||||
- [Xray-UI](https://github.com/qist/xray-ui)
|
|
||||||
- [Hiddify](https://github.com/hiddify/Hiddify-Manager)
|
|
||||||
- One Click
|
|
||||||
- [Xray-REALITY](https://github.com/zxcvos/Xray-script), [xray-reality](https://github.com/sajjaddg/xray-reality), [reality-ezpz](https://github.com/aleskxyz/reality-ezpz)
|
|
||||||
- [Xray_bash_onekey](https://github.com/hello-yunshu/Xray_bash_onekey), [XTool](https://github.com/LordPenguin666/XTool), [VPainLess](https://github.com/vpainless/vpainless)
|
|
||||||
- [v2ray-agent](https://github.com/mack-a/v2ray-agent), [Xray_onekey](https://github.com/wulabing/Xray_onekey), [ProxySU](https://github.com/proxysu/ProxySU)
|
|
||||||
- Magisk
|
|
||||||
- [Xray4Magisk](https://github.com/Asterisk4Magisk/Xray4Magisk)
|
|
||||||
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
|
|
||||||
- Homebrew
|
|
||||||
- `brew install xray`
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
- Example
|
|
||||||
- [VLESS-XTLS-uTLS-REALITY](https://github.com/XTLS/REALITY#readme)
|
|
||||||
- [VLESS-TCP-XTLS-Vision](https://github.com/XTLS/Xray-examples/tree/main/VLESS-TCP-XTLS-Vision)
|
|
||||||
- [All-in-One-fallbacks-Nginx](https://github.com/XTLS/Xray-examples/tree/main/All-in-One-fallbacks-Nginx)
|
|
||||||
- Xray-examples
|
|
||||||
- [XTLS/Xray-examples](https://github.com/XTLS/Xray-examples)
|
|
||||||
- [chika0801/Xray-examples](https://github.com/chika0801/Xray-examples)
|
|
||||||
- [lxhao61/integrated-examples](https://github.com/lxhao61/integrated-examples)
|
|
||||||
- Tutorial
|
|
||||||
- [XTLS Vision](https://github.com/chika0801/Xray-install)
|
|
||||||
- [REALITY (English)](https://cscot.pages.dev/2023/03/02/Xray-REALITY-tutorial/)
|
|
||||||
- [XTLS-Iran-Reality (English)](https://github.com/SasukeFreestyle/XTLS-Iran-Reality)
|
|
||||||
- [Xray REALITY with 'steal oneself' (English)](https://computerscot.github.io/vless-xtls-utls-reality-steal-oneself.html)
|
|
||||||
- [Xray with WireGuard inbound (English)](https://g800.pages.dev/wireguard)
|
|
||||||
|
|
||||||
## GUI Clients
|
|
||||||
|
|
||||||
- OpenWrt
|
|
||||||
- [PassWall](https://github.com/xiaorouji/openwrt-passwall), [PassWall 2](https://github.com/xiaorouji/openwrt-passwall2)
|
|
||||||
- [ShadowSocksR Plus+](https://github.com/fw876/helloworld)
|
|
||||||
- [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray))
|
|
||||||
- Asuswrt-Merlin
|
|
||||||
- [XRAYUI](https://github.com/DanielLavrushin/asuswrt-merlin-xrayui)
|
|
||||||
- Windows
|
|
||||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
|
||||||
- [Furious](https://github.com/LorenEteval/Furious)
|
|
||||||
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
|
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
|
||||||
- Android
|
|
||||||
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
|
||||||
- [X-flutter](https://github.com/XTLS/X-flutter)
|
|
||||||
- [SaeedDev94/Xray](https://github.com/SaeedDev94/Xray)
|
|
||||||
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
|
||||||
- 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)
|
|
||||||
- [OneXray](https://github.com/OneXray/OneXray)
|
|
||||||
- macOS arm64 & x64
|
|
||||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215)
|
|
||||||
- [V2rayU](https://github.com/yanue/V2rayU)
|
|
||||||
- [V2RayXS](https://github.com/tzmax/V2RayXS)
|
|
||||||
- [Furious](https://github.com/LorenEteval/Furious)
|
|
||||||
- [OneXray](https://github.com/OneXray/OneXray)
|
|
||||||
- [GoXRay](https://github.com/goxray/desktop)
|
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
|
||||||
- Linux
|
|
||||||
- [v2rayA](https://github.com/v2rayA/v2rayA)
|
|
||||||
- [Furious](https://github.com/LorenEteval/Furious)
|
|
||||||
- [GorzRay](https://github.com/ketetefid/GorzRay)
|
|
||||||
- [GoXRay](https://github.com/goxray/desktop)
|
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
|
||||||
|
|
||||||
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
|
||||||
|
|
||||||
- iOS & macOS arm64 & tvOS
|
|
||||||
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
|
||||||
- [Loon](https://apps.apple.com/us/app/loon/id1373567447)
|
|
||||||
- Xray Tools
|
|
||||||
- [xray-knife](https://github.com/lilendian0x00/xray-knife)
|
|
||||||
- [xray-checker](https://github.com/kutovoys/xray-checker)
|
|
||||||
- Xray Wrapper
|
|
||||||
- [XTLS/libXray](https://github.com/XTLS/libXray)
|
|
||||||
- [xtls-sdk](https://github.com/remnawave/xtls-sdk)
|
|
||||||
- [xtlsapi](https://github.com/hiddify/xtlsapi)
|
|
||||||
- [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite)
|
|
||||||
- [Xray-core-python](https://github.com/LorenEteval/Xray-core-python)
|
|
||||||
- [xray-api](https://github.com/XVGuardian/xray-api)
|
|
||||||
- [XrayR](https://github.com/XrayR-project/XrayR)
|
|
||||||
- [XrayR-release](https://github.com/XrayR-project/XrayR-release)
|
|
||||||
- [XrayR-V2Board](https://github.com/missuo/XrayR-V2Board)
|
|
||||||
- Cores
|
|
||||||
- [Amnezia VPN](https://github.com/amnezia-vpn)
|
|
||||||
- [mihomo](https://github.com/MetaCubeX/mihomo)
|
|
||||||
- [sing-box](https://github.com/SagerNet/sing-box)
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
[Code of Conduct](https://github.com/XTLS/Xray-core/blob/main/CODE_OF_CONDUCT.md)
|
|
||||||
|
|
||||||
[](https://deepwiki.com/XTLS/Xray-core)
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
- [Xray-core v1.0.0](https://github.com/XTLS/Xray-core/releases/tag/v1.0.0) was forked from [v2fly-core 9a03cc5](https://github.com/v2fly/v2ray-core/commit/9a03cc5c98d04cc28320fcee26dbc236b3291256), and we have made & accumulated a huge number of enhancements over time, check [the release notes for each version](https://github.com/XTLS/Xray-core/releases).
|
|
||||||
- For third-party projects used in [Xray-core](https://github.com/XTLS/Xray-core), check your local or [the latest go.mod](https://github.com/XTLS/Xray-core/blob/main/go.mod).
|
|
||||||
|
|
||||||
## One-line Compilation
|
|
||||||
|
|
||||||
### Windows (PowerShell)
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
$env:CGO_ENABLED=0
|
|
||||||
go build -o xray.exe -trimpath -buildvcs=false -ldflags="-s -w -buildid=" -v ./main
|
|
||||||
```
|
|
||||||
|
|
||||||
### Linux / macOS
|
|
||||||
|
|
||||||
```bash
|
|
||||||
CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -ldflags="-s -w -buildid=" -v ./main
|
|
||||||
```
|
|
||||||
|
|
||||||
### Reproducible Releases
|
|
||||||
|
|
||||||
Make sure that you are using the same Go version, and remember to set the git commit id (7 bytes):
|
|
||||||
|
|
||||||
```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
|
|
||||||
```
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
[](https://starchart.cc/XTLS/Xray-core)
|
[](https://starchart.cc/XTLS/Xray-core)
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
package commander
|
package commander
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/signal/done"
|
"github.com/xtls/xray-core/common/signal/done"
|
||||||
core "github.com/xtls/xray-core/core"
|
core "github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/outbound"
|
"github.com/xtls/xray-core/features/outbound"
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Commander is a Xray feature that provides gRPC methods to external clients.
|
// Commander is a Xray feature that provides gRPC methods to external clients.
|
||||||
@@ -20,14 +22,12 @@ type Commander struct {
|
|||||||
services []Service
|
services []Service
|
||||||
ohm outbound.Manager
|
ohm outbound.Manager
|
||||||
tag string
|
tag string
|
||||||
listen string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCommander creates a new Commander based on the given config.
|
// NewCommander creates a new Commander based on the given config.
|
||||||
func NewCommander(ctx context.Context, config *Config) (*Commander, error) {
|
func NewCommander(ctx context.Context, config *Config) (*Commander, error) {
|
||||||
c := &Commander{
|
c := &Commander{
|
||||||
tag: config.Tag,
|
tag: config.Tag,
|
||||||
listen: config.Listen,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
common.Must(core.RequireFeatures(ctx, func(om outbound.Manager) {
|
common.Must(core.RequireFeatures(ctx, func(om outbound.Manager) {
|
||||||
@@ -45,7 +45,7 @@ func NewCommander(ctx context.Context, config *Config) (*Commander, error) {
|
|||||||
}
|
}
|
||||||
service, ok := rawService.(Service)
|
service, ok := rawService.(Service)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not a Service.")
|
return nil, newError("not a Service.")
|
||||||
}
|
}
|
||||||
c.services = append(c.services, service)
|
c.services = append(c.services, service)
|
||||||
}
|
}
|
||||||
@@ -67,32 +67,19 @@ func (c *Commander) Start() error {
|
|||||||
}
|
}
|
||||||
c.Unlock()
|
c.Unlock()
|
||||||
|
|
||||||
var listen = func(listener net.Listener) {
|
|
||||||
if err := c.server.Serve(listener); err != nil {
|
|
||||||
errors.LogErrorInner(context.Background(), err, "failed to start grpc server")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.listen) > 0 {
|
|
||||||
if l, err := net.Listen("tcp", c.listen); err != nil {
|
|
||||||
errors.LogErrorInner(context.Background(), err, "API server failed to listen on ", c.listen)
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
errors.LogInfo(context.Background(), "API server listening on ", l.Addr())
|
|
||||||
go listen(l)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
listener := &OutboundListener{
|
listener := &OutboundListener{
|
||||||
buffer: make(chan net.Conn, 4),
|
buffer: make(chan net.Conn, 4),
|
||||||
done: done.New(),
|
done: done.New(),
|
||||||
}
|
}
|
||||||
|
|
||||||
go listen(listener)
|
go func() {
|
||||||
|
if err := c.server.Serve(listener); err != nil {
|
||||||
|
newError("failed to start grpc server").Base(err).AtError().WriteToLog()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if err := c.ohm.RemoveHandler(context.Background(), c.tag); err != nil {
|
if err := c.ohm.RemoveHandler(context.Background(), c.tag); err != nil {
|
||||||
errors.LogInfoInner(context.Background(), err, "failed to remove existing handler")
|
newError("failed to remove existing handler").WriteToLog()
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.ohm.AddHandler(context.Background(), &Outbound{
|
return c.ohm.AddHandler(context.Background(), &Outbound{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.27.1
|
||||||
// protoc v5.28.2
|
// protoc v3.18.0
|
||||||
// source: app/commander/config.proto
|
// source: app/commander/config.proto
|
||||||
|
|
||||||
package commander
|
package commander
|
||||||
@@ -29,8 +29,6 @@ type Config struct {
|
|||||||
|
|
||||||
// Tag of the outbound handler that handles grpc connections.
|
// Tag of the outbound handler that handles grpc connections.
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
// Network address of commander grpc service.
|
|
||||||
Listen string `protobuf:"bytes,3,opt,name=listen,proto3" json:"listen,omitempty"`
|
|
||||||
// Services that supported by this server. All services must implement Service
|
// Services that supported by this server. All services must implement Service
|
||||||
// interface.
|
// interface.
|
||||||
Service []*serial.TypedMessage `protobuf:"bytes,2,rep,name=service,proto3" json:"service,omitempty"`
|
Service []*serial.TypedMessage `protobuf:"bytes,2,rep,name=service,proto3" json:"service,omitempty"`
|
||||||
@@ -38,9 +36,11 @@ type Config struct {
|
|||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
mi := &file_app_commander_config_proto_msgTypes[0]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_commander_config_proto_msgTypes[0]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) String() string {
|
func (x *Config) String() string {
|
||||||
@@ -51,7 +51,7 @@ func (*Config) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_commander_config_proto_msgTypes[0]
|
mi := &file_app_commander_config_proto_msgTypes[0]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -73,13 +73,6 @@ func (x *Config) GetTag() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetListen() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Listen
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetService() []*serial.TypedMessage {
|
func (x *Config) GetService() []*serial.TypedMessage {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Service
|
return x.Service
|
||||||
@@ -96,9 +89,11 @@ type ReflectionConfig struct {
|
|||||||
|
|
||||||
func (x *ReflectionConfig) Reset() {
|
func (x *ReflectionConfig) Reset() {
|
||||||
*x = ReflectionConfig{}
|
*x = ReflectionConfig{}
|
||||||
mi := &file_app_commander_config_proto_msgTypes[1]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_commander_config_proto_msgTypes[1]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReflectionConfig) String() string {
|
func (x *ReflectionConfig) String() string {
|
||||||
@@ -109,7 +104,7 @@ func (*ReflectionConfig) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *ReflectionConfig) ProtoReflect() protoreflect.Message {
|
func (x *ReflectionConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_commander_config_proto_msgTypes[1]
|
mi := &file_app_commander_config_proto_msgTypes[1]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -132,21 +127,20 @@ var file_app_commander_config_proto_rawDesc = []byte{
|
|||||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72,
|
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72,
|
||||||
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,
|
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,
|
||||||
0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
|
0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
|
||||||
0x6f, 0x74, 0x6f, 0x22, 0x6e, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a,
|
0x6f, 0x74, 0x6f, 0x22, 0x56, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a,
|
||||||
0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12,
|
0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12,
|
||||||
0x16, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x3a, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
|
||||||
0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x3a, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69,
|
0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73,
|
||||||
0x63, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79,
|
0x67, 0x65, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52,
|
||||||
0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76,
|
0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42,
|
||||||
0x69, 0x63, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||||
0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
|
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65,
|
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
|
||||||
0x72, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
||||||
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61,
|
0x6e, 0x64, 0x65, 0x72, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e,
|
||||||
0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0xaa, 0x02, 0x12, 0x58,
|
0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65,
|
0x33,
|
||||||
0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -162,7 +156,7 @@ func file_app_commander_config_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_app_commander_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
var file_app_commander_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||||
var file_app_commander_config_proto_goTypes = []any{
|
var file_app_commander_config_proto_goTypes = []interface{}{
|
||||||
(*Config)(nil), // 0: xray.app.commander.Config
|
(*Config)(nil), // 0: xray.app.commander.Config
|
||||||
(*ReflectionConfig)(nil), // 1: xray.app.commander.ReflectionConfig
|
(*ReflectionConfig)(nil), // 1: xray.app.commander.ReflectionConfig
|
||||||
(*serial.TypedMessage)(nil), // 2: xray.common.serial.TypedMessage
|
(*serial.TypedMessage)(nil), // 2: xray.common.serial.TypedMessage
|
||||||
@@ -181,6 +175,32 @@ func file_app_commander_config_proto_init() {
|
|||||||
if File_app_commander_config_proto != nil {
|
if File_app_commander_config_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_app_commander_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Config); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_commander_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ReflectionConfig); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
|
|||||||
@@ -12,10 +12,6 @@ import "common/serial/typed_message.proto";
|
|||||||
message Config {
|
message Config {
|
||||||
// Tag of the outbound handler that handles grpc connections.
|
// Tag of the outbound handler that handles grpc connections.
|
||||||
string tag = 1;
|
string tag = 1;
|
||||||
|
|
||||||
// Network address of commander grpc service.
|
|
||||||
string listen = 3;
|
|
||||||
|
|
||||||
// Services that supported by this server. All services must implement Service
|
// Services that supported by this server. All services must implement Service
|
||||||
// interface.
|
// interface.
|
||||||
repeated xray.common.serial.TypedMessage service = 2;
|
repeated xray.common.serial.TypedMessage service = 2;
|
||||||
|
|||||||
9
app/commander/errors.generated.go
Normal file
9
app/commander/errors.generated.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package commander
|
||||||
|
|
||||||
|
import "github.com/xtls/xray-core/common/errors"
|
||||||
|
|
||||||
|
type errPathObjHolder struct{}
|
||||||
|
|
||||||
|
func newError(values ...interface{}) *errors.Error {
|
||||||
|
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||||
|
}
|
||||||
@@ -5,10 +5,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/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"
|
||||||
)
|
)
|
||||||
@@ -33,13 +31,13 @@ func (l *OutboundListener) add(conn net.Conn) {
|
|||||||
func (l *OutboundListener) Accept() (net.Conn, error) {
|
func (l *OutboundListener) Accept() (net.Conn, error) {
|
||||||
select {
|
select {
|
||||||
case <-l.done.Wait():
|
case <-l.done.Wait():
|
||||||
return nil, errors.New("listen closed")
|
return nil, newError("listen closed")
|
||||||
case c := <-l.buffer:
|
case c := <-l.buffer:
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close implements net.Listener.
|
// Close implement net.Listener.
|
||||||
func (l *OutboundListener) Close() error {
|
func (l *OutboundListener) Close() error {
|
||||||
common.Must(l.done.Close())
|
common.Must(l.done.Close())
|
||||||
L:
|
L:
|
||||||
@@ -109,13 +107,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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ package commander
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/reflection"
|
"google.golang.org/grpc/reflection"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Service is a Commander service.
|
// Service is a Commander service.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.27.1
|
||||||
// protoc v5.28.2
|
// protoc v3.18.0
|
||||||
// source: app/dispatcher/config.proto
|
// source: app/dispatcher/config.proto
|
||||||
|
|
||||||
package dispatcher
|
package dispatcher
|
||||||
@@ -28,9 +28,11 @@ type SessionConfig struct {
|
|||||||
|
|
||||||
func (x *SessionConfig) Reset() {
|
func (x *SessionConfig) Reset() {
|
||||||
*x = SessionConfig{}
|
*x = SessionConfig{}
|
||||||
mi := &file_app_dispatcher_config_proto_msgTypes[0]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_dispatcher_config_proto_msgTypes[0]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SessionConfig) String() string {
|
func (x *SessionConfig) String() string {
|
||||||
@@ -41,7 +43,7 @@ func (*SessionConfig) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *SessionConfig) ProtoReflect() protoreflect.Message {
|
func (x *SessionConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_dispatcher_config_proto_msgTypes[0]
|
mi := &file_app_dispatcher_config_proto_msgTypes[0]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -66,9 +68,11 @@ type Config struct {
|
|||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
mi := &file_app_dispatcher_config_proto_msgTypes[1]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_dispatcher_config_proto_msgTypes[1]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) String() string {
|
func (x *Config) String() string {
|
||||||
@@ -79,7 +83,7 @@ func (*Config) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_dispatcher_config_proto_msgTypes[1]
|
mi := &file_app_dispatcher_config_proto_msgTypes[1]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -135,7 +139,7 @@ func file_app_dispatcher_config_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_app_dispatcher_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
var file_app_dispatcher_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||||
var file_app_dispatcher_config_proto_goTypes = []any{
|
var file_app_dispatcher_config_proto_goTypes = []interface{}{
|
||||||
(*SessionConfig)(nil), // 0: xray.app.dispatcher.SessionConfig
|
(*SessionConfig)(nil), // 0: xray.app.dispatcher.SessionConfig
|
||||||
(*Config)(nil), // 1: xray.app.dispatcher.Config
|
(*Config)(nil), // 1: xray.app.dispatcher.Config
|
||||||
}
|
}
|
||||||
@@ -153,6 +157,32 @@ func file_app_dispatcher_config_proto_init() {
|
|||||||
if File_app_dispatcher_config_proto != nil {
|
if File_app_dispatcher_config_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_app_dispatcher_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*SessionConfig); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_dispatcher_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Config); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
package dispatcher
|
package dispatcher
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"regexp"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/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"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
|
||||||
"github.com/xtls/xray-core/features/outbound"
|
"github.com/xtls/xray-core/features/outbound"
|
||||||
"github.com/xtls/xray-core/features/policy"
|
"github.com/xtls/xray-core/features/policy"
|
||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
@@ -25,7 +25,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/transport/pipe"
|
"github.com/xtls/xray-core/transport/pipe"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errSniffingTimeout = errors.New("timeout on sniffing")
|
var errSniffingTimeout = newError("timeout on sniffing")
|
||||||
|
|
||||||
type cachedReader struct {
|
type cachedReader struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
@@ -33,21 +33,17 @@ type cachedReader struct {
|
|||||||
cache buf.MultiBuffer
|
cache buf.MultiBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *cachedReader) Cache(b *buf.Buffer, deadline time.Duration) error {
|
func (r *cachedReader) Cache(b *buf.Buffer) {
|
||||||
mb, err := r.reader.ReadMultiBufferTimeout(deadline)
|
mb, _ := r.reader.ReadMultiBufferTimeout(time.Millisecond * 100)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
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()
|
b.Clear()
|
||||||
rawBytes := b.Extend(min(r.cache.Len(), b.Cap()))
|
rawBytes := b.Extend(buf.Size)
|
||||||
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 {
|
||||||
@@ -96,17 +92,14 @@ type DefaultDispatcher struct {
|
|||||||
router routing.Router
|
router routing.Router
|
||||||
policy policy.Manager
|
policy policy.Manager
|
||||||
stats stats.Manager
|
stats stats.Manager
|
||||||
fdns dns.FakeDNSEngine
|
hosts dns.HostsLookup
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||||
d := new(DefaultDispatcher)
|
d := new(DefaultDispatcher)
|
||||||
if err := core.RequireFeatures(ctx, func(om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dc dns.Client) error {
|
if err := core.RequireFeatures(ctx, func(om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dc dns.Client) error {
|
||||||
core.OptionalFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
return d.Init(config.(*Config), om, router, pm, sm, dc)
|
||||||
d.fdns = fdns
|
|
||||||
})
|
|
||||||
return d.Init(config.(*Config), om, router, pm, sm)
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -115,11 +108,14 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init initializes DefaultDispatcher.
|
// Init initializes DefaultDispatcher.
|
||||||
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager) error {
|
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dc dns.Client) error {
|
||||||
d.ohm = om
|
d.ohm = om
|
||||||
d.router = router
|
d.router = router
|
||||||
d.policy = pm
|
d.policy = pm
|
||||||
d.stats = sm
|
d.stats = sm
|
||||||
|
if hosts, ok := dc.(dns.HostsLookup); ok {
|
||||||
|
d.hosts = hosts
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,56 +173,33 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 inboundLink, outboundLink
|
return inboundLink, outboundLink
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
func shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
||||||
domain := result.Domain()
|
domain := result.Domain()
|
||||||
if domain == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, d := range request.ExcludeForDomain {
|
for _, d := range request.ExcludeForDomain {
|
||||||
if strings.HasPrefix(d, "regexp:") {
|
if strings.ToLower(domain) == d {
|
||||||
pattern := d[7:]
|
return false
|
||||||
re, err := regexp.Compile(pattern)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogInfo(ctx, "Unable to compile regex")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if re.MatchString(domain) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if strings.ToLower(domain) == d {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var fakeDNSEngine dns.FakeDNSEngine
|
||||||
|
core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||||
|
fakeDNSEngine = fdns
|
||||||
|
})
|
||||||
protocolString := result.Protocol()
|
protocolString := result.Protocol()
|
||||||
if resComp, ok := result.(SnifferResultComposite); ok {
|
if resComp, ok := result.(SnifferResultComposite); ok {
|
||||||
protocolString = resComp.ProtocolForDomainResult()
|
protocolString = resComp.ProtocolForDomainResult()
|
||||||
}
|
}
|
||||||
for _, p := range request.OverrideDestinationForProtocol {
|
for _, p := range request.OverrideDestinationForProtocol {
|
||||||
if strings.HasPrefix(protocolString, p) || strings.HasPrefix(p, protocolString) {
|
if strings.HasPrefix(protocolString, p) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && protocolString != "bittorrent" && p == "fakedns" &&
|
if fkr0, ok := fakeDNSEngine.(dns.FakeDNSEngineRev0); ok && protocolString != "bittorrent" && p == "fakedns" &&
|
||||||
fkr0.IsIPInIPPool(destination.Address) {
|
destination.Address.Family().IsIP() && fkr0.IsIPInIPPool(destination.Address) {
|
||||||
errors.LogInfo(ctx, "Using sniffer ", protocolString, " since the fake DNS missed")
|
newError("Using sniffer ", protocolString, " since the fake DNS missed").WriteToLog(session.ExportIDToError(ctx))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if resultSubset, ok := result.(SnifferIsProtoSubsetOf); ok {
|
if resultSubset, ok := result.(SnifferIsProtoSubsetOf); ok {
|
||||||
@@ -244,47 +217,53 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
|||||||
if !destination.IsValid() {
|
if !destination.IsValid() {
|
||||||
panic("Dispatcher: Invalid destination.")
|
panic("Dispatcher: Invalid destination.")
|
||||||
}
|
}
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
ob := &session.Outbound{
|
||||||
if len(outbounds) == 0 {
|
Target: destination,
|
||||||
outbounds = []*session.Outbound{{}}
|
|
||||||
ctx = session.ContextWithOutbounds(ctx, outbounds)
|
|
||||||
}
|
}
|
||||||
ob := outbounds[len(outbounds)-1]
|
ctx = session.ContextWithOutbound(ctx, ob)
|
||||||
ob.OriginalTarget = destination
|
|
||||||
ob.Target = destination
|
inbound, outbound := d.getLink(ctx)
|
||||||
content := session.ContentFromContext(ctx)
|
content := session.ContentFromContext(ctx)
|
||||||
if content == nil {
|
if content == nil {
|
||||||
content = new(session.Content)
|
content = new(session.Content)
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
sniffingRequest := content.SniffingRequest
|
sniffingRequest := content.SniffingRequest
|
||||||
inbound, outbound := d.getLink(ctx)
|
switch {
|
||||||
if !sniffingRequest.Enabled {
|
case !sniffingRequest.Enabled:
|
||||||
go d.routedDispatch(ctx, outbound, destination)
|
go d.routedDispatch(ctx, outbound, destination)
|
||||||
} else {
|
case destination.Network != net.Network_TCP:
|
||||||
|
// Only metadata sniff will be used for non tcp connection
|
||||||
|
result, err := sniffer(ctx, nil, true)
|
||||||
|
if err == nil {
|
||||||
|
content.Protocol = result.Protocol()
|
||||||
|
if shouldOverride(ctx, result, sniffingRequest, destination) {
|
||||||
|
domain := result.Domain()
|
||||||
|
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
destination.Address = net.ParseAddress(domain)
|
||||||
|
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
|
||||||
|
ob.RouteTarget = destination
|
||||||
|
} else {
|
||||||
|
ob.Target = destination
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
go d.routedDispatch(ctx, outbound, destination)
|
||||||
|
default:
|
||||||
go func() {
|
go func() {
|
||||||
cReader := &cachedReader{
|
cReader := &cachedReader{
|
||||||
reader: outbound.Reader.(*pipe.Reader),
|
reader: outbound.Reader.(*pipe.Reader),
|
||||||
}
|
}
|
||||||
outbound.Reader = cReader
|
outbound.Reader = cReader
|
||||||
result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly, destination.Network)
|
result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
content.Protocol = result.Protocol()
|
content.Protocol = result.Protocol()
|
||||||
}
|
}
|
||||||
if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) {
|
if err == nil && shouldOverride(ctx, result, sniffingRequest, destination) {
|
||||||
domain := result.Domain()
|
domain := result.Domain()
|
||||||
errors.LogInfo(ctx, "sniffed domain: ", domain)
|
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||||
destination.Address = net.ParseAddress(domain)
|
destination.Address = net.ParseAddress(domain)
|
||||||
protocol := result.Protocol()
|
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
|
||||||
if resComp, ok := result.(SnifferResultComposite); ok {
|
|
||||||
protocol = resComp.ProtocolForDomainResult()
|
|
||||||
}
|
|
||||||
isFakeIP := false
|
|
||||||
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && fkr0.IsIPInIPPool(ob.Target.Address) {
|
|
||||||
isFakeIP = true
|
|
||||||
}
|
|
||||||
if sniffingRequest.RouteOnly && protocol != "fakedns" && protocol != "fakedns+others" && !isFakeIP {
|
|
||||||
ob.RouteTarget = destination
|
ob.RouteTarget = destination
|
||||||
} else {
|
} else {
|
||||||
ob.Target = destination
|
ob.Target = destination
|
||||||
@@ -299,59 +278,66 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
|||||||
// DispatchLink implements routing.Dispatcher.
|
// DispatchLink implements routing.Dispatcher.
|
||||||
func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.Destination, outbound *transport.Link) error {
|
func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.Destination, outbound *transport.Link) error {
|
||||||
if !destination.IsValid() {
|
if !destination.IsValid() {
|
||||||
return errors.New("Dispatcher: Invalid destination.")
|
return newError("Dispatcher: Invalid destination.")
|
||||||
}
|
}
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
ob := &session.Outbound{
|
||||||
if len(outbounds) == 0 {
|
Target: destination,
|
||||||
outbounds = []*session.Outbound{{}}
|
|
||||||
ctx = session.ContextWithOutbounds(ctx, outbounds)
|
|
||||||
}
|
}
|
||||||
ob := outbounds[len(outbounds)-1]
|
ctx = session.ContextWithOutbound(ctx, ob)
|
||||||
ob.OriginalTarget = destination
|
|
||||||
ob.Target = destination
|
|
||||||
content := session.ContentFromContext(ctx)
|
content := session.ContentFromContext(ctx)
|
||||||
if content == nil {
|
if content == nil {
|
||||||
content = new(session.Content)
|
content = new(session.Content)
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
}
|
}
|
||||||
sniffingRequest := content.SniffingRequest
|
sniffingRequest := content.SniffingRequest
|
||||||
if !sniffingRequest.Enabled {
|
switch {
|
||||||
d.routedDispatch(ctx, outbound, destination)
|
case !sniffingRequest.Enabled:
|
||||||
} else {
|
go d.routedDispatch(ctx, outbound, destination)
|
||||||
cReader := &cachedReader{
|
case destination.Network != net.Network_TCP:
|
||||||
reader: outbound.Reader.(*pipe.Reader),
|
// Only metadata sniff will be used for non tcp connection
|
||||||
}
|
result, err := sniffer(ctx, nil, true)
|
||||||
outbound.Reader = cReader
|
|
||||||
result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly, destination.Network)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
content.Protocol = result.Protocol()
|
content.Protocol = result.Protocol()
|
||||||
}
|
if shouldOverride(ctx, result, sniffingRequest, destination) {
|
||||||
if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) {
|
domain := result.Domain()
|
||||||
domain := result.Domain()
|
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||||
errors.LogInfo(ctx, "sniffed domain: ", domain)
|
destination.Address = net.ParseAddress(domain)
|
||||||
destination.Address = net.ParseAddress(domain)
|
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
|
||||||
protocol := result.Protocol()
|
ob.RouteTarget = destination
|
||||||
if resComp, ok := result.(SnifferResultComposite); ok {
|
} else {
|
||||||
protocol = resComp.ProtocolForDomainResult()
|
ob.Target = destination
|
||||||
}
|
}
|
||||||
isFakeIP := false
|
|
||||||
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && fkr0.IsIPInIPPool(ob.Target.Address) {
|
|
||||||
isFakeIP = true
|
|
||||||
}
|
|
||||||
if sniffingRequest.RouteOnly && protocol != "fakedns" && protocol != "fakedns+others" && !isFakeIP {
|
|
||||||
ob.RouteTarget = destination
|
|
||||||
} else {
|
|
||||||
ob.Target = destination
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d.routedDispatch(ctx, outbound, destination)
|
go d.routedDispatch(ctx, outbound, destination)
|
||||||
|
default:
|
||||||
|
go func() {
|
||||||
|
cReader := &cachedReader{
|
||||||
|
reader: outbound.Reader.(*pipe.Reader),
|
||||||
|
}
|
||||||
|
outbound.Reader = cReader
|
||||||
|
result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly)
|
||||||
|
if err == nil {
|
||||||
|
content.Protocol = result.Protocol()
|
||||||
|
}
|
||||||
|
if err == nil && shouldOverride(ctx, result, sniffingRequest, destination) {
|
||||||
|
domain := result.Domain()
|
||||||
|
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
destination.Address = net.ParseAddress(domain)
|
||||||
|
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
|
||||||
|
ob.RouteTarget = destination
|
||||||
|
} else {
|
||||||
|
ob.Target = destination
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.routedDispatch(ctx, outbound, destination)
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, network net.Network) (SniffResult, error) {
|
func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool) (SniffResult, error) {
|
||||||
payload := buf.NewWithSize(32767)
|
payload := buf.New()
|
||||||
defer payload.Release()
|
defer payload.Release()
|
||||||
|
|
||||||
sniffer := NewSniffer(ctx)
|
sniffer := NewSniffer(ctx)
|
||||||
@@ -363,36 +349,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())
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -405,43 +381,46 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
|
|||||||
}
|
}
|
||||||
return contentResult, contentErr
|
return contentResult, contentErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
ob := session.OutboundFromContext(ctx)
|
||||||
ob := outbounds[len(outbounds)-1]
|
if d.hosts != nil && destination.Address.Family().IsDomain() {
|
||||||
|
proxied := d.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
|
||||||
|
|
||||||
routingLink := routing_session.AsRoutingContext(ctx)
|
|
||||||
inTag := routingLink.GetInboundTag()
|
|
||||||
isPickRoute := 0
|
|
||||||
if forcedOutboundTag := session.GetForcedOutboundTagFromContext(ctx); forcedOutboundTag != "" {
|
if forcedOutboundTag := session.GetForcedOutboundTagFromContext(ctx); forcedOutboundTag != "" {
|
||||||
ctx = session.SetForcedOutboundTagToContext(ctx, "")
|
ctx = session.SetForcedOutboundTagToContext(ctx, "")
|
||||||
if h := d.ohm.GetHandler(forcedOutboundTag); h != nil {
|
if h := d.ohm.GetHandler(forcedOutboundTag); h != nil {
|
||||||
isPickRoute = 1
|
newError("taking platform initialized detour [", forcedOutboundTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
|
||||||
errors.LogInfo(ctx, "taking platform initialized detour [", forcedOutboundTag, "] for [", destination, "]")
|
|
||||||
handler = h
|
handler = h
|
||||||
} else {
|
} else {
|
||||||
errors.LogError(ctx, "non existing tag for platform initialized detour: ", forcedOutboundTag)
|
newError("non existing tag for platform initialized detour: ", forcedOutboundTag).AtError().WriteToLog(session.ExportIDToError(ctx))
|
||||||
common.Close(link.Writer)
|
common.Close(link.Writer)
|
||||||
common.Interrupt(link.Reader)
|
common.Interrupt(link.Reader)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if d.router != nil {
|
} else if d.router != nil {
|
||||||
if route, err := d.router.PickRoute(routingLink); err == nil {
|
if route, err := d.router.PickRoute(routing_session.AsRoutingContext(ctx)); err == nil {
|
||||||
outTag := route.GetOutboundTag()
|
tag := route.GetOutboundTag()
|
||||||
if h := d.ohm.GetHandler(outTag); h != nil {
|
if h := d.ohm.GetHandler(tag); h != nil {
|
||||||
isPickRoute = 2
|
newError("taking detour [", tag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
|
||||||
if route.GetRuleTag() == "" {
|
|
||||||
errors.LogInfo(ctx, "taking detour [", outTag, "] for [", destination, "]")
|
|
||||||
} else {
|
|
||||||
errors.LogInfo(ctx, "Hit route rule: [", route.GetRuleTag(), "] so taking detour [", outTag, "] for [", destination, "]")
|
|
||||||
}
|
|
||||||
handler = h
|
handler = h
|
||||||
} else {
|
} else {
|
||||||
errors.LogWarning(ctx, "non existing outTag: ", outTag)
|
newError("non existing outTag: ", tag).AtWarning().WriteToLog(session.ExportIDToError(ctx))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errors.LogInfo(ctx, "default route for ", destination)
|
newError("default route for ", destination).WriteToLog(session.ExportIDToError(ctx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,24 +429,15 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
|||||||
}
|
}
|
||||||
|
|
||||||
if handler == nil {
|
if handler == nil {
|
||||||
errors.LogInfo(ctx, "default outbound handler not exist")
|
newError("default outbound handler not exist").WriteToLog(session.ExportIDToError(ctx))
|
||||||
common.Close(link.Writer)
|
common.Close(link.Writer)
|
||||||
common.Interrupt(link.Reader)
|
common.Interrupt(link.Reader)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ob.Tag = handler.Tag()
|
|
||||||
if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil {
|
if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil {
|
||||||
if tag := handler.Tag(); tag != "" {
|
if tag := handler.Tag(); tag != "" {
|
||||||
if inTag == "" {
|
accessMessage.Detour = tag
|
||||||
accessMessage.Detour = tag
|
|
||||||
} else if isPickRoute == 1 {
|
|
||||||
accessMessage.Detour = inTag + " ==> " + tag
|
|
||||||
} else if isPickRoute == 2 {
|
|
||||||
accessMessage.Detour = inTag + " -> " + tag
|
|
||||||
} else {
|
|
||||||
accessMessage.Detour = inTag + " >> " + tag
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
log.Record(accessMessage)
|
log.Record(accessMessage)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
package dispatcher
|
package dispatcher
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|||||||
9
app/dispatcher/errors.generated.go
Normal file
9
app/dispatcher/errors.generated.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package dispatcher
|
||||||
|
|
||||||
|
import "github.com/xtls/xray-core/common/errors"
|
||||||
|
|
||||||
|
type errPathObjHolder struct{}
|
||||||
|
|
||||||
|
func newError(values ...interface{}) *errors.Error {
|
||||||
|
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||||
|
}
|
||||||
@@ -5,34 +5,31 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
// newFakeDNSSniffer Creates a Fake DNS metadata sniffer
|
// newFakeDNSSniffer Create a Fake DNS metadata sniffer
|
||||||
func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error) {
|
func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error) {
|
||||||
var fakeDNSEngine dns.FakeDNSEngine
|
var fakeDNSEngine dns.FakeDNSEngine
|
||||||
{
|
err := core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||||
fakeDNSEngineFeat := core.MustFromContext(ctx).GetFeature((*dns.FakeDNSEngine)(nil))
|
fakeDNSEngine = fdns
|
||||||
if fakeDNSEngineFeat != nil {
|
})
|
||||||
fakeDNSEngine = fakeDNSEngineFeat.(dns.FakeDNSEngine)
|
if err != nil {
|
||||||
}
|
return protocolSnifferWithMetadata{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if fakeDNSEngine == nil {
|
if fakeDNSEngine == nil {
|
||||||
errNotInit := errors.New("FakeDNSEngine is not initialized, but such a sniffer is used").AtError()
|
errNotInit := newError("FakeDNSEngine is not initialized, but such a sniffer is used").AtError()
|
||||||
return protocolSnifferWithMetadata{}, errNotInit
|
return protocolSnifferWithMetadata{}, errNotInit
|
||||||
}
|
}
|
||||||
return protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) {
|
return protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) {
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
Target := session.OutboundFromContext(ctx).Target
|
||||||
ob := outbounds[len(outbounds)-1]
|
if Target.Network == net.Network_TCP || Target.Network == net.Network_UDP {
|
||||||
if ob.Target.Network == net.Network_TCP || ob.Target.Network == net.Network_UDP {
|
domainFromFakeDNS := fakeDNSEngine.GetDomainFromFakeDNS(Target.Address)
|
||||||
domainFromFakeDNS := fakeDNSEngine.GetDomainFromFakeDNS(ob.Target.Address)
|
|
||||||
if domainFromFakeDNS != "" {
|
if domainFromFakeDNS != "" {
|
||||||
errors.LogInfo(ctx, "fake dns got domain: ", domainFromFakeDNS, " for ip: ", ob.Target.Address.String())
|
newError("fake dns got domain: ", domainFromFakeDNS, " for ip: ", Target.Address.String()).WriteToLog(session.ExportIDToError(ctx))
|
||||||
return &fakeDNSSniffResult{domainName: domainFromFakeDNS}, nil
|
return &fakeDNSSniffResult{domainName: domainFromFakeDNS}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,7 +37,7 @@ func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error)
|
|||||||
if ipAddressInRangeValueI := ctx.Value(ipAddressInRange); ipAddressInRangeValueI != nil {
|
if ipAddressInRangeValueI := ctx.Value(ipAddressInRange); ipAddressInRangeValueI != nil {
|
||||||
ipAddressInRangeValue := ipAddressInRangeValueI.(*ipAddressInRangeOpt)
|
ipAddressInRangeValue := ipAddressInRangeValueI.(*ipAddressInRangeOpt)
|
||||||
if fkr0, ok := fakeDNSEngine.(dns.FakeDNSEngineRev0); ok {
|
if fkr0, ok := fakeDNSEngine.(dns.FakeDNSEngineRev0); ok {
|
||||||
inPool := fkr0.IsIPInIPPool(ob.Target.Address)
|
inPool := fkr0.IsIPInIPPool(Target.Address)
|
||||||
ipAddressInRangeValue.addressInRange = &inPool
|
ipAddressInRangeValue.addressInRange = &inPool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,8 +84,7 @@ func (f DNSThenOthersSniffResult) Domain() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newFakeDNSThenOthers(ctx context.Context, fakeDNSSniffer protocolSnifferWithMetadata, others []protocolSnifferWithMetadata) (
|
func newFakeDNSThenOthers(ctx context.Context, fakeDNSSniffer protocolSnifferWithMetadata, others []protocolSnifferWithMetadata) (
|
||||||
protocolSnifferWithMetadata, error,
|
protocolSnifferWithMetadata, error) { // nolint: unparam
|
||||||
) { // nolint: unparam
|
|
||||||
// ctx may be used in the future
|
// ctx may be used in the future
|
||||||
_ = ctx
|
_ = ctx
|
||||||
return protocolSnifferWithMetadata{
|
return protocolSnifferWithMetadata{
|
||||||
@@ -110,10 +106,10 @@ func newFakeDNSThenOthers(ctx context.Context, fakeDNSSniffer protocolSnifferWit
|
|||||||
}
|
}
|
||||||
return nil, common.ErrNoClue
|
return nil, common.ErrNoClue
|
||||||
}
|
}
|
||||||
errors.LogDebug(ctx, "ip address not in fake dns range, return as is")
|
newError("ip address not in fake dns range, return as is").AtDebug().WriteToLog()
|
||||||
return nil, common.ErrNoClue
|
return nil, common.ErrNoClue
|
||||||
}
|
}
|
||||||
errors.LogWarning(ctx, "fake dns sniffer did not set address in range option, assume false.")
|
newError("fake dns sniffer did not set address in range option, assume false.").AtWarning().WriteToLog()
|
||||||
return nil, common.ErrNoClue
|
return nil, common.ErrNoClue
|
||||||
},
|
},
|
||||||
metadataSniffer: false,
|
metadataSniffer: false,
|
||||||
|
|||||||
@@ -4,12 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/common/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/tls"
|
"github.com/xtls/xray-core/common/protocol/tls"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,7 +22,6 @@ type protocolSnifferWithMetadata struct {
|
|||||||
// for both TCP and UDP connections
|
// for both TCP and UDP connections
|
||||||
// It will not be shown as a traffic type for routing unless there is no other successful sniffing.
|
// It will not be shown as a traffic type for routing unless there is no other successful sniffing.
|
||||||
metadataSniffer bool
|
metadataSniffer bool
|
||||||
network net.Network
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Sniffer struct {
|
type Sniffer struct {
|
||||||
@@ -36,11 +31,9 @@ type Sniffer struct {
|
|||||||
func NewSniffer(ctx context.Context) *Sniffer {
|
func NewSniffer(ctx context.Context) *Sniffer {
|
||||||
ret := &Sniffer{
|
ret := &Sniffer{
|
||||||
sniffer: []protocolSnifferWithMetadata{
|
sniffer: []protocolSnifferWithMetadata{
|
||||||
{func(c context.Context, b []byte) (SniffResult, error) { return http.SniffHTTP(b, c) }, false, net.Network_TCP},
|
{func(c context.Context, b []byte) (SniffResult, error) { return http.SniffHTTP(b) }, false},
|
||||||
{func(c context.Context, b []byte) (SniffResult, error) { return tls.SniffTLS(b) }, false, net.Network_TCP},
|
{func(c context.Context, b []byte) (SniffResult, error) { return tls.SniffTLS(b) }, false},
|
||||||
{func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffBittorrent(b) }, false, net.Network_TCP},
|
{func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffBittorrent(b) }, false},
|
||||||
{func(c context.Context, b []byte) (SniffResult, error) { return quic.SniffQUIC(b) }, false, net.Network_UDP},
|
|
||||||
{func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffUTP(b) }, false, net.Network_UDP},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if sniffer, err := newFakeDNSSniffer(ctx); err == nil {
|
if sniffer, err := newFakeDNSSniffer(ctx); err == nil {
|
||||||
@@ -54,22 +47,19 @@ func NewSniffer(ctx context.Context) *Sniffer {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
var errUnknownContent = errors.New("unknown content")
|
var errUnknownContent = newError("unknown content")
|
||||||
|
|
||||||
func (s *Sniffer) Sniff(c context.Context, payload []byte, network net.Network) (SniffResult, error) {
|
func (s *Sniffer) Sniff(c context.Context, payload []byte) (SniffResult, error) {
|
||||||
var pendingSniffer []protocolSnifferWithMetadata
|
var pendingSniffer []protocolSnifferWithMetadata
|
||||||
for _, si := range s.sniffer {
|
for _, si := range s.sniffer {
|
||||||
protocolSniffer := si.protocolSniffer
|
s := si.protocolSniffer
|
||||||
if si.metadataSniffer || si.network != network {
|
if si.metadataSniffer {
|
||||||
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,188 +0,0 @@
|
|||||||
package dns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
go_errors "errors"
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
|
||||||
"github.com/xtls/xray-core/common/task"
|
|
||||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
|
||||||
"golang.org/x/net/dns/dnsmessage"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CacheController struct {
|
|
||||||
sync.RWMutex
|
|
||||||
ips map[string]*record
|
|
||||||
pub *pubsub.Service
|
|
||||||
cacheCleanup *task.Periodic
|
|
||||||
name string
|
|
||||||
disableCache bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCacheController(name string, disableCache bool) *CacheController {
|
|
||||||
c := &CacheController{
|
|
||||||
name: name,
|
|
||||||
disableCache: disableCache,
|
|
||||||
ips: make(map[string]*record),
|
|
||||||
pub: pubsub.NewService(),
|
|
||||||
}
|
|
||||||
|
|
||||||
c.cacheCleanup = &task.Periodic{
|
|
||||||
Interval: time.Minute,
|
|
||||||
Execute: c.CacheCleanup,
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// CacheCleanup clears expired items from cache
|
|
||||||
func (c *CacheController) CacheCleanup() error {
|
|
||||||
now := time.Now()
|
|
||||||
c.Lock()
|
|
||||||
defer c.Unlock()
|
|
||||||
|
|
||||||
if len(c.ips) == 0 {
|
|
||||||
return errors.New("nothing to do. stopping...")
|
|
||||||
}
|
|
||||||
|
|
||||||
for domain, record := range c.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(), c.name, "cache cleanup ", domain)
|
|
||||||
delete(c.ips, domain)
|
|
||||||
} else {
|
|
||||||
c.ips[domain] = record
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.ips) == 0 {
|
|
||||||
c.ips = make(map[string]*record)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheController) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
|
||||||
elapsed := time.Since(req.start)
|
|
||||||
|
|
||||||
c.Lock()
|
|
||||||
rec, found := c.ips[req.domain]
|
|
||||||
if !found {
|
|
||||||
rec = &record{}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch req.reqType {
|
|
||||||
case dnsmessage.TypeA:
|
|
||||||
rec.A = ipRec
|
|
||||||
case dnsmessage.TypeAAAA:
|
|
||||||
rec.AAAA = ipRec
|
|
||||||
}
|
|
||||||
|
|
||||||
errors.LogInfo(context.Background(), c.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
|
||||||
c.ips[req.domain] = rec
|
|
||||||
|
|
||||||
switch req.reqType {
|
|
||||||
case dnsmessage.TypeA:
|
|
||||||
c.pub.Publish(req.domain+"4", nil)
|
|
||||||
if !c.disableCache {
|
|
||||||
_, _, err := rec.AAAA.getIPs()
|
|
||||||
if !go_errors.Is(err, errRecordNotFound) {
|
|
||||||
c.pub.Publish(req.domain+"6", nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case dnsmessage.TypeAAAA:
|
|
||||||
c.pub.Publish(req.domain+"6", nil)
|
|
||||||
if !c.disableCache {
|
|
||||||
_, _, err := rec.A.getIPs()
|
|
||||||
if !go_errors.Is(err, errRecordNotFound) {
|
|
||||||
c.pub.Publish(req.domain+"4", nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Unlock()
|
|
||||||
common.Must(c.cacheCleanup.Start())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheController) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
|
||||||
c.RLock()
|
|
||||||
record, found := c.ips[domain]
|
|
||||||
c.RUnlock()
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
return nil, 0, errRecordNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
var errs []error
|
|
||||||
var allIPs []net.IP
|
|
||||||
var rTTL uint32 = dns_feature.DefaultTTL
|
|
||||||
|
|
||||||
mergeReq := option.IPv4Enable && option.IPv6Enable
|
|
||||||
|
|
||||||
if option.IPv4Enable {
|
|
||||||
ips, ttl, err := record.A.getIPs()
|
|
||||||
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 := record.AAAA.getIPs()
|
|
||||||
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 go_errors.Is(errs[0], errs[1]) {
|
|
||||||
return nil, rTTL, errs[0]
|
|
||||||
}
|
|
||||||
return nil, rTTL, errors.Combine(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"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/strmatcher"
|
"github.com/xtls/xray-core/common/strmatcher"
|
||||||
"github.com/xtls/xray-core/common/uuid"
|
"github.com/xtls/xray-core/common/uuid"
|
||||||
@@ -37,11 +36,11 @@ var localTLDsAndDotlessDomainsRule = &NameServer_OriginalRule{
|
|||||||
func toStrMatcher(t DomainMatchingType, domain string) (strmatcher.Matcher, error) {
|
func toStrMatcher(t DomainMatchingType, domain string) (strmatcher.Matcher, error) {
|
||||||
strMType, f := typeMap[t]
|
strMType, f := typeMap[t]
|
||||||
if !f {
|
if !f {
|
||||||
return nil, errors.New("unknown mapping type", t).AtWarning()
|
return nil, newError("unknown mapping type", t).AtWarning()
|
||||||
}
|
}
|
||||||
matcher, err := strMType.New(domain)
|
matcher, err := strMType.New(domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to create str matcher").Base(err)
|
return nil, newError("failed to create str matcher").Base(err)
|
||||||
}
|
}
|
||||||
return matcher, nil
|
return matcher, nil
|
||||||
}
|
}
|
||||||
@@ -52,7 +51,7 @@ func toNetIP(addrs []net.Address) ([]net.IP, error) {
|
|||||||
if addr.Family().IsIP() {
|
if addr.Family().IsIP() {
|
||||||
ips = append(ips, addr.IP())
|
ips = append(ips, addr.IP())
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("Failed to convert address", addr, "to Net IP.").AtWarning()
|
return nil, newError("Failed to convert address", addr, "to Net IP.").AtWarning()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ips, nil
|
return ips, nil
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.27.1
|
||||||
// protoc v5.28.2
|
// protoc v3.18.0
|
||||||
// source: app/dns/config.proto
|
// source: app/dns/config.proto
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
@@ -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,23 +132,17 @@ 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"`
|
|
||||||
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" json:"disableCache,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"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) Reset() {
|
func (x *NameServer) Reset() {
|
||||||
*x = NameServer{}
|
*x = NameServer{}
|
||||||
mi := &file_app_dns_config_proto_msgTypes[0]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_dns_config_proto_msgTypes[0]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) String() string {
|
func (x *NameServer) String() string {
|
||||||
@@ -162,7 +153,7 @@ func (*NameServer) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *NameServer) ProtoReflect() protoreflect.Message {
|
func (x *NameServer) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_dns_config_proto_msgTypes[0]
|
mi := &file_app_dns_config_proto_msgTypes[0]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -205,9 +196,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
|
||||||
}
|
}
|
||||||
@@ -219,70 +210,24 @@ func (x *NameServer) GetOriginalRules() []*NameServer_OriginalRule {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) GetQueryStrategy() QueryStrategy {
|
|
||||||
if x != nil {
|
|
||||||
return x.QueryStrategy
|
|
||||||
}
|
|
||||||
return QueryStrategy_USE_IP
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
return x.DisableCache
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
// Nameservers used by this DNS. Only traditional UDP servers are support at
|
||||||
|
// the moment. A special value 'localhost' as a domain address can be set to
|
||||||
|
// use DNS on local system.
|
||||||
|
//
|
||||||
|
// Deprecated: Do not use.
|
||||||
|
NameServers []*net.Endpoint `protobuf:"bytes,1,rep,name=NameServers,proto3" json:"NameServers,omitempty"`
|
||||||
// NameServer list used by this DNS client.
|
// NameServer list used by this DNS client.
|
||||||
// A special value 'localhost' as a domain address can be set to use DNS on local system.
|
|
||||||
NameServer []*NameServer `protobuf:"bytes,5,rep,name=name_server,json=nameServer,proto3" json:"name_server,omitempty"`
|
NameServer []*NameServer `protobuf:"bytes,5,rep,name=name_server,json=nameServer,proto3" json:"name_server,omitempty"`
|
||||||
|
// Static hosts. Domain to IP.
|
||||||
|
// Deprecated. Use static_hosts.
|
||||||
|
//
|
||||||
|
// Deprecated: Do not use.
|
||||||
|
Hosts map[string]*net.IPOrDomain `protobuf:"bytes,2,rep,name=Hosts,proto3" json:"Hosts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes
|
// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes
|
||||||
// (IPv6).
|
// (IPv6).
|
||||||
ClientIp []byte `protobuf:"bytes,3,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
|
ClientIp []byte `protobuf:"bytes,3,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
|
||||||
@@ -298,9 +243,11 @@ type Config struct {
|
|||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
mi := &file_app_dns_config_proto_msgTypes[1]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_dns_config_proto_msgTypes[1]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) String() string {
|
func (x *Config) String() string {
|
||||||
@@ -311,7 +258,7 @@ func (*Config) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_dns_config_proto_msgTypes[1]
|
mi := &file_app_dns_config_proto_msgTypes[1]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -326,6 +273,14 @@ func (*Config) Descriptor() ([]byte, []int) {
|
|||||||
return file_app_dns_config_proto_rawDescGZIP(), []int{1}
|
return file_app_dns_config_proto_rawDescGZIP(), []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: Do not use.
|
||||||
|
func (x *Config) GetNameServers() []*net.Endpoint {
|
||||||
|
if x != nil {
|
||||||
|
return x.NameServers
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (x *Config) GetNameServer() []*NameServer {
|
func (x *Config) GetNameServer() []*NameServer {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.NameServer
|
return x.NameServer
|
||||||
@@ -333,6 +288,14 @@ func (x *Config) GetNameServer() []*NameServer {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: Do not use.
|
||||||
|
func (x *Config) GetHosts() map[string]*net.IPOrDomain {
|
||||||
|
if x != nil {
|
||||||
|
return x.Hosts
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (x *Config) GetClientIp() []byte {
|
func (x *Config) GetClientIp() []byte {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.ClientIp
|
return x.ClientIp
|
||||||
@@ -393,9 +356,11 @@ type NameServer_PriorityDomain struct {
|
|||||||
|
|
||||||
func (x *NameServer_PriorityDomain) Reset() {
|
func (x *NameServer_PriorityDomain) Reset() {
|
||||||
*x = NameServer_PriorityDomain{}
|
*x = NameServer_PriorityDomain{}
|
||||||
mi := &file_app_dns_config_proto_msgTypes[2]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_dns_config_proto_msgTypes[2]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer_PriorityDomain) String() string {
|
func (x *NameServer_PriorityDomain) String() string {
|
||||||
@@ -406,7 +371,7 @@ func (*NameServer_PriorityDomain) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *NameServer_PriorityDomain) ProtoReflect() protoreflect.Message {
|
func (x *NameServer_PriorityDomain) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_dns_config_proto_msgTypes[2]
|
mi := &file_app_dns_config_proto_msgTypes[2]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -446,9 +411,11 @@ type NameServer_OriginalRule struct {
|
|||||||
|
|
||||||
func (x *NameServer_OriginalRule) Reset() {
|
func (x *NameServer_OriginalRule) Reset() {
|
||||||
*x = NameServer_OriginalRule{}
|
*x = NameServer_OriginalRule{}
|
||||||
mi := &file_app_dns_config_proto_msgTypes[3]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_dns_config_proto_msgTypes[3]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer_OriginalRule) String() string {
|
func (x *NameServer_OriginalRule) String() string {
|
||||||
@@ -459,7 +426,7 @@ func (*NameServer_OriginalRule) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *NameServer_OriginalRule) ProtoReflect() protoreflect.Message {
|
func (x *NameServer_OriginalRule) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_dns_config_proto_msgTypes[3]
|
mi := &file_app_dns_config_proto_msgTypes[3]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -503,9 +470,11 @@ type Config_HostMapping struct {
|
|||||||
|
|
||||||
func (x *Config_HostMapping) Reset() {
|
func (x *Config_HostMapping) Reset() {
|
||||||
*x = Config_HostMapping{}
|
*x = Config_HostMapping{}
|
||||||
mi := &file_app_dns_config_proto_msgTypes[4]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_dns_config_proto_msgTypes[5]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config_HostMapping) String() string {
|
func (x *Config_HostMapping) String() string {
|
||||||
@@ -515,8 +484,8 @@ func (x *Config_HostMapping) String() string {
|
|||||||
func (*Config_HostMapping) ProtoMessage() {}
|
func (*Config_HostMapping) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Config_HostMapping) ProtoReflect() protoreflect.Message {
|
func (x *Config_HostMapping) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_dns_config_proto_msgTypes[4]
|
mi := &file_app_dns_config_proto_msgTypes[5]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -528,7 +497,7 @@ func (x *Config_HostMapping) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Config_HostMapping.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Config_HostMapping.ProtoReflect.Descriptor instead.
|
||||||
func (*Config_HostMapping) Descriptor() ([]byte, []int) {
|
func (*Config_HostMapping) Descriptor() ([]byte, []int) {
|
||||||
return file_app_dns_config_proto_rawDescGZIP(), []int{1, 0}
|
return file_app_dns_config_proto_rawDescGZIP(), []int{1, 1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config_HostMapping) GetType() DomainMatchingType {
|
func (x *Config_HostMapping) GetType() DomainMatchingType {
|
||||||
@@ -564,109 +533,103 @@ var File_app_dns_config_proto protoreflect.FileDescriptor
|
|||||||
var file_app_dns_config_proto_rawDesc = []byte{
|
var file_app_dns_config_proto_rawDesc = []byte{
|
||||||
0x0a, 0x14, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
0x0a, 0x14, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74,
|
0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x18, 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, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c,
|
||||||
0x74, 0x6f, 0x1a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63,
|
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x65, 0x73, 0x74, 0x69,
|
||||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb6, 0x06, 0x0a, 0x0a,
|
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x61, 0x70,
|
||||||
0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64,
|
0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
|
||||||
0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72,
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xee, 0x03, 0x0a, 0x0a, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65,
|
||||||
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e,
|
0x72, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18,
|
||||||
0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12,
|
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x05, 0x20, 0x01,
|
0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
||||||
0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x22, 0x0a, 0x0c,
|
0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69,
|
||||||
0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01,
|
0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c,
|
||||||
0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
|
0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61,
|
||||||
0x12, 0x56, 0x0a, 0x12, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x5f,
|
0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b,
|
||||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78,
|
0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x56, 0x0a, 0x12, 0x70, 0x72,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65,
|
0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||||
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44,
|
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x11, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a,
|
0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||||
0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3d, 0x0a, 0x0e, 0x65, 0x78, 0x70, 0x65,
|
0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52,
|
||||||
0x63, 0x74, 0x65, 0x64, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
|
0x11, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61,
|
||||||
0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28,
|
||||||
0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0d, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74,
|
0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
|
||||||
0x65, 0x64, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69,
|
0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70,
|
||||||
0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
0x12, 0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c,
|
||||||
0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e,
|
0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e,
|
0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76,
|
||||||
0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
|
0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52,
|
||||||
0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73,
|
0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x1a, 0x5e,
|
||||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e,
|
0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65,
|
0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20,
|
||||||
0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72,
|
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f,
|
||||||
0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x74,
|
0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65,
|
||||||
0x50, 0x72, 0x69, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x63, 0x74,
|
0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||||
0x50, 0x72, 0x69, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x09, 0x20, 0x01,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36,
|
||||||
0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x6f,
|
0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12,
|
||||||
0x75, 0x74, 0x4d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
|
0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75,
|
||||||
0x6f, 0x75, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
|
0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
|
||||||
0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73,
|
0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0xef, 0x05, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||||
0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6e,
|
0x67, 0x12, 0x3f, 0x0a, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73,
|
||||||
0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66,
|
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||||
0x69, 0x6e, 0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x41, 0x0a, 0x10, 0x75, 0x6e, 0x65,
|
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
|
||||||
0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0d, 0x20,
|
0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65,
|
||||||
0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
0x72, 0x73, 0x12, 0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0f, 0x75, 0x6e, 0x65,
|
0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
|
||||||
0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a,
|
0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65,
|
||||||
0x61, 0x63, 0x74, 0x55, 0x6e, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08,
|
0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x39, 0x0a,
|
||||||
0x52, 0x0a, 0x61, 0x63, 0x74, 0x55, 0x6e, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x1a, 0x5e, 0x0a, 0x0e,
|
0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78,
|
||||||
0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34,
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66,
|
||||||
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78,
|
0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x02, 0x18,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61,
|
0x01, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65,
|
||||||
0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04,
|
0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69,
|
||||||
0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02,
|
0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c,
|
0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72,
|
||||||
0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04,
|
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||||
0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65,
|
0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73,
|
||||||
0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04,
|
0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
|
||||||
0x73, 0x69, 0x7a, 0x65, 0x22, 0x9c, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x22, 0x0a, 0x0c,
|
||||||
0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05,
|
0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08, 0x20, 0x01,
|
||||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65,
|
||||||
0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a,
|
0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||||
0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c,
|
0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63,
|
0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72,
|
||||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69,
|
0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61,
|
||||||
0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e,
|
0x74, 0x65, 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46,
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e,
|
0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64,
|
||||||
0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52,
|
0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x36,
|
||||||
0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03,
|
0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
|
||||||
0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x22,
|
0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16,
|
||||||
0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08,
|
0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49,
|
||||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63,
|
0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x1a, 0x55, 0x0a, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45,
|
||||||
0x68, 0x65, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61,
|
0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x74, 0x65, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61,
|
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
|
||||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53,
|
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74,
|
0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61,
|
||||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c,
|
0x69, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x92, 0x01,
|
||||||
0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52,
|
0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a,
|
||||||
0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
|
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72,
|
||||||
0x12, 0x36, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62,
|
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||||
0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08,
|
0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74,
|
||||||
0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
|
0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20,
|
||||||
0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x1a, 0x92, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73,
|
0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
||||||
0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
|
0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20,
|
||||||
0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63,
|
0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61,
|
||||||
0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16,
|
0x69, 0x6e, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x2a, 0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61,
|
||||||
0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08,
|
||||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03,
|
0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64,
|
||||||
0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65,
|
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f,
|
||||||
0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
|
0x72, 0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x2a,
|
||||||
0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x04, 0x08,
|
0x35, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||||
0x07, 0x10, 0x08, 0x2a, 0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74,
|
0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07,
|
||||||
0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c,
|
0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45,
|
||||||
0x6c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
0x5f, 0x49, 0x50, 0x36, 0x10, 0x02, 0x42, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
|
||||||
0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x10, 0x02, 0x12,
|
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69,
|
||||||
0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x2a, 0x42, 0x0a, 0x0d, 0x51, 0x75,
|
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72,
|
||||||
0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55,
|
0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa,
|
||||||
0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49,
|
0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06,
|
||||||
0x50, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10,
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
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 (
|
||||||
@@ -682,35 +645,38 @@ func file_app_dns_config_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_app_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
var file_app_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||||
var file_app_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
var file_app_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||||
var file_app_dns_config_proto_goTypes = []any{
|
var file_app_dns_config_proto_goTypes = []interface{}{
|
||||||
(DomainMatchingType)(0), // 0: xray.app.dns.DomainMatchingType
|
(DomainMatchingType)(0), // 0: xray.app.dns.DomainMatchingType
|
||||||
(QueryStrategy)(0), // 1: xray.app.dns.QueryStrategy
|
(QueryStrategy)(0), // 1: xray.app.dns.QueryStrategy
|
||||||
(*NameServer)(nil), // 2: xray.app.dns.NameServer
|
(*NameServer)(nil), // 2: xray.app.dns.NameServer
|
||||||
(*Config)(nil), // 3: xray.app.dns.Config
|
(*Config)(nil), // 3: xray.app.dns.Config
|
||||||
(*NameServer_PriorityDomain)(nil), // 4: xray.app.dns.NameServer.PriorityDomain
|
(*NameServer_PriorityDomain)(nil), // 4: xray.app.dns.NameServer.PriorityDomain
|
||||||
(*NameServer_OriginalRule)(nil), // 5: xray.app.dns.NameServer.OriginalRule
|
(*NameServer_OriginalRule)(nil), // 5: xray.app.dns.NameServer.OriginalRule
|
||||||
(*Config_HostMapping)(nil), // 6: xray.app.dns.Config.HostMapping
|
nil, // 6: xray.app.dns.Config.HostsEntry
|
||||||
(*net.Endpoint)(nil), // 7: xray.common.net.Endpoint
|
(*Config_HostMapping)(nil), // 7: xray.app.dns.Config.HostMapping
|
||||||
(*router.GeoIP)(nil), // 8: xray.app.router.GeoIP
|
(*net.Endpoint)(nil), // 8: xray.common.net.Endpoint
|
||||||
|
(*router.GeoIP)(nil), // 9: xray.app.router.GeoIP
|
||||||
|
(*net.IPOrDomain)(nil), // 10: xray.common.net.IPOrDomain
|
||||||
}
|
}
|
||||||
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
|
8, // 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
|
9, // 2: xray.app.dns.NameServer.geoip:type_name -> xray.app.router.GeoIP
|
||||||
5, // 3: xray.app.dns.NameServer.original_rules:type_name -> xray.app.dns.NameServer.OriginalRule
|
5, // 3: xray.app.dns.NameServer.original_rules:type_name -> xray.app.dns.NameServer.OriginalRule
|
||||||
1, // 4: xray.app.dns.NameServer.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
8, // 4: xray.app.dns.Config.NameServers:type_name -> xray.common.net.Endpoint
|
||||||
8, // 5: xray.app.dns.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.Hosts:type_name -> xray.app.dns.Config.HostsEntry
|
||||||
6, // 7: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
7, // 7: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
||||||
1, // 8: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
1, // 8: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
||||||
0, // 9: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
|
0, // 9: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
|
||||||
0, // 10: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType
|
10, // 10: xray.app.dns.Config.HostsEntry.value:type_name -> xray.common.net.IPOrDomain
|
||||||
11, // [11:11] is the sub-list for method output_type
|
0, // 11: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType
|
||||||
11, // [11:11] is the sub-list for method input_type
|
12, // [12:12] is the sub-list for method output_type
|
||||||
11, // [11:11] is the sub-list for extension type_name
|
12, // [12:12] is the sub-list for method input_type
|
||||||
11, // [11:11] is the sub-list for extension extendee
|
12, // [12:12] is the sub-list for extension type_name
|
||||||
0, // [0:11] is the sub-list for field type_name
|
12, // [12:12] is the sub-list for extension extendee
|
||||||
|
0, // [0:12] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_dns_config_proto_init() }
|
func init() { file_app_dns_config_proto_init() }
|
||||||
@@ -718,13 +684,75 @@ func file_app_dns_config_proto_init() {
|
|||||||
if File_app_dns_config_proto != nil {
|
if File_app_dns_config_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_app_dns_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*NameServer); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_dns_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Config); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_dns_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*NameServer_PriorityDomain); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_dns_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*NameServer_OriginalRule); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_dns_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Config_HostMapping); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_app_dns_config_proto_rawDesc,
|
RawDescriptor: file_app_dns_config_proto_rawDesc,
|
||||||
NumEnums: 2,
|
NumEnums: 2,
|
||||||
NumMessages: 5,
|
NumMessages: 6,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ option go_package = "github.com/xtls/xray-core/app/dns";
|
|||||||
option java_package = "com.xray.app.dns";
|
option java_package = "com.xray.app.dns";
|
||||||
option java_multiple_files = true;
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
import "common/net/address.proto";
|
||||||
import "common/net/destination.proto";
|
import "common/net/destination.proto";
|
||||||
import "app/router/config.proto";
|
import "app/router/config.proto";
|
||||||
|
|
||||||
@@ -25,16 +26,8 @@ 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;
|
|
||||||
bool actPrior = 8;
|
|
||||||
string tag = 9;
|
|
||||||
uint64 timeoutMs = 10;
|
|
||||||
bool disableCache = 11;
|
|
||||||
bool finalQuery = 12;
|
|
||||||
repeated xray.app.router.GeoIP unexpected_geoip = 13;
|
|
||||||
bool actUnprior = 14;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DomainMatchingType {
|
enum DomainMatchingType {
|
||||||
@@ -48,14 +41,21 @@ 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 {
|
||||||
|
// Nameservers used by this DNS. Only traditional UDP servers are support at
|
||||||
|
// the moment. A special value 'localhost' as a domain address can be set to
|
||||||
|
// use DNS on local system.
|
||||||
|
repeated xray.common.net.Endpoint NameServers = 1 [deprecated = true];
|
||||||
|
|
||||||
// NameServer list used by this DNS client.
|
// NameServer list used by this DNS client.
|
||||||
// A special value 'localhost' as a domain address can be set to use DNS on local system.
|
|
||||||
repeated NameServer name_server = 5;
|
repeated NameServer name_server = 5;
|
||||||
|
|
||||||
|
// Static hosts. Domain to IP.
|
||||||
|
// Deprecated. Use static_hosts.
|
||||||
|
map<string, xray.common.net.IPOrDomain> Hosts = 2 [deprecated = true];
|
||||||
|
|
||||||
// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes
|
// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes
|
||||||
// (IPv6).
|
// (IPv6).
|
||||||
bytes client_ip = 3;
|
bytes client_ip = 3;
|
||||||
|
|||||||
234
app/dns/dns.go
234
app/dns/dns.go
@@ -1,25 +1,29 @@
|
|||||||
// Package dns is an implementation of core.DNS feature.
|
// Package dns is an implementation of core.DNS feature.
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
go_errors "errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"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"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"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/features"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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
|
||||||
ipOption *dns.IPOption
|
ipOption *dns.IPOption
|
||||||
@@ -28,7 +32,6 @@ type DNS struct {
|
|||||||
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
|
||||||
@@ -39,59 +42,50 @@ 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:
|
||||||
clientIP = net.IP(config.ClientIp)
|
clientIP = net.IP(config.ClientIp)
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("unexpected client IP length ", len(config.ClientIp))
|
return nil, newError("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, config.Hosts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to create hosts").Base(err)
|
return nil, newError("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)
|
||||||
}
|
}
|
||||||
@@ -99,6 +93,16 @@ 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 _, endpoint := range config.NameServers {
|
||||||
|
features.PrintDeprecatedFeatureWarning("simple DNS server")
|
||||||
|
client, err := NewSimpleClient(ctx, endpoint, clientIP)
|
||||||
|
if err != nil {
|
||||||
|
return nil, newError("failed to create client").Base(err)
|
||||||
|
}
|
||||||
|
clients = append(clients, client)
|
||||||
|
}
|
||||||
|
|
||||||
for _, ns := range config.NameServer {
|
for _, ns := range config.NameServer {
|
||||||
clientIdx := len(clients)
|
clientIdx := len(clients)
|
||||||
@@ -116,40 +120,29 @@ 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 || ns.DisableCache
|
|
||||||
|
|
||||||
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, tag, clientIPOption, &matcherInfos, updateDomain)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to create client").Base(err)
|
return nil, newError("failed to create client").Base(err)
|
||||||
}
|
}
|
||||||
clients = append(clients, client)
|
clients = append(clients, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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,
|
||||||
checkSystem: checkSystem,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,101 +164,95 @@ 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, newError("empty domain name")
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.checkSystem {
|
option.IPv4Enable = option.IPv4Enable && s.ipOption.IPv4Enable
|
||||||
supportIPv4, supportIPv6 := checkSystemNetwork()
|
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
|
||||||
|
if strings.HasSuffix(domain, ".") {
|
||||||
|
domain = domain[:len(domain)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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())
|
newError("domain replaced: ", domain, " -> ", addrs[0].Domain()).WriteToLog()
|
||||||
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)
|
newError("returning ", len(addrs), " IP(s) for domain ", domain, " -> ", addrs).WriteToLog()
|
||||||
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
|
||||||
var errs []error
|
errs := []error{}
|
||||||
|
ctx := session.ContextWithInbound(s.ctx, &session.Inbound{Tag: s.tag})
|
||||||
for _, client := range s.sortClients(domain) {
|
for _, client := range s.sortClients(domain) {
|
||||||
if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
|
if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
|
||||||
errors.LogDebug(s.ctx, "skip DNS resolution for domain ", domain, " at server ", client.Name())
|
newError("skip DNS resolution for domain ", domain, " at server ", client.Name()).AtDebug().WriteToLog()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
ips, err := client.QueryIP(ctx, domain, option, s.disableCache)
|
||||||
ips, ttl, err := client.QueryIP(s.ctx, domain, option)
|
|
||||||
|
|
||||||
if len(ips) > 0 {
|
if len(ips) > 0 {
|
||||||
if ttl == 0 {
|
return ips, nil
|
||||||
ttl = 1
|
|
||||||
}
|
|
||||||
return ips, ttl, nil
|
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
errors.LogInfoInner(s.ctx, err, "failed to lookup ip for domain ", domain, " at server ", client.Name())
|
newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog()
|
||||||
if err == nil {
|
errs = append(errs, err)
|
||||||
err = dns.ErrEmptyResponse
|
|
||||||
}
|
}
|
||||||
errs = append(errs, err)
|
if err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch {
|
||||||
|
return nil, err
|
||||||
if client.IsFinalQuery() {
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(errs) > 0 {
|
return nil, newError("returning nil for domain ", domain).Base(errors.Combine(errs...))
|
||||||
allErrs := errors.Combine(errs...)
|
}
|
||||||
err0 := errs[0]
|
|
||||||
if errors.AllEqual(err0, allErrs) {
|
// LookupHosts implements dns.HostsLookup.
|
||||||
if go_errors.Is(err0, dns.ErrEmptyResponse) {
|
func (s *DNS) LookupHosts(domain string) *net.Address {
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
domain = strings.TrimSuffix(domain, ".")
|
||||||
}
|
if domain == "" {
|
||||||
return nil, 0, errors.New("returning nil for domain ", domain).Base(err0)
|
return nil
|
||||||
}
|
|
||||||
return nil, 0, errors.New("returning nil for domain ", domain).Base(allErrs)
|
|
||||||
}
|
}
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
// Normalize the FQDN form query
|
||||||
|
addrs := s.hosts.Lookup(domain, *s.ipOption)
|
||||||
|
if len(addrs) > 0 {
|
||||||
|
newError("domain replaced: ", domain, " -> ", addrs[0].String()).AtInfo().WriteToLog()
|
||||||
|
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 {
|
||||||
@@ -276,11 +263,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]
|
||||||
@@ -307,16 +290,16 @@ func (s *DNS) sortClients(domain string) []*Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(domainRules) > 0 {
|
if len(domainRules) > 0 {
|
||||||
errors.LogDebug(s.ctx, "domain ", domain, " matches following rules: ", domainRules)
|
newError("domain ", domain, " matches following rules: ", domainRules).AtDebug().WriteToLog()
|
||||||
}
|
}
|
||||||
if len(clientNames) > 0 {
|
if len(clientNames) > 0 {
|
||||||
errors.LogDebug(s.ctx, "domain ", domain, " will use DNS in order: ", clientNames)
|
newError("domain ", domain, " will use DNS in order: ", clientNames).AtDebug().WriteToLog()
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(clients) == 0 {
|
if len(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)
|
newError("domain ", domain, " will use the first DNS: ", clientNames).AtDebug().WriteToLog()
|
||||||
}
|
}
|
||||||
|
|
||||||
return clients
|
return clients
|
||||||
@@ -327,22 +310,3 @@ func init() {
|
|||||||
return New(ctx, config.(*Config))
|
return New(ctx, config.(*Config))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkSystemNetwork() (supportIPv4 bool, supportIPv6 bool) {
|
|
||||||
conn4, err4 := net.Dial("udp4", "8.8.8.8:53")
|
|
||||||
if err4 != nil {
|
|
||||||
supportIPv4 = false
|
|
||||||
} else {
|
|
||||||
supportIPv4 = true
|
|
||||||
conn4.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
conn6, err6 := net.Dial("udp6", "[2001:4860:4860::8888]:53")
|
|
||||||
if err6 != nil {
|
|
||||||
supportIPv6 = false
|
|
||||||
} else {
|
|
||||||
supportIPv6 = true
|
|
||||||
conn6.Close()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
_ "github.com/xtls/xray-core/app/proxyman/outbound"
|
_ "github.com/xtls/xray-core/app/proxyman/outbound"
|
||||||
"github.com/xtls/xray-core/app/router"
|
"github.com/xtls/xray-core/app/router"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
@@ -76,9 +75,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,23 +116,22 @@ 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)
|
||||||
|
|
||||||
config := &core.Config{
|
config := &core.Config{
|
||||||
App: []*serial.TypedMessage{
|
App: []*serial.TypedMessage{
|
||||||
serial.ToTypedMessage(&Config{
|
serial.ToTypedMessage(&Config{
|
||||||
NameServer: []*NameServer{
|
NameServers: []*net.Endpoint{
|
||||||
{
|
{
|
||||||
Address: &net.Endpoint{
|
Network: net.Network_UDP,
|
||||||
Network: net.Network_UDP,
|
Address: &net.IPOrDomain{
|
||||||
Address: &net.IPOrDomain{
|
Address: &net.IPOrDomain_Ip{
|
||||||
Address: &net.IPOrDomain_Ip{
|
Ip: []byte{127, 0, 0, 1},
|
||||||
Ip: []byte{127, 0, 0, 1},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Port: uint32(port),
|
|
||||||
},
|
},
|
||||||
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ClientIp: []byte{7, 8, 9, 10},
|
ClientIp: []byte{7, 8, 9, 10},
|
||||||
@@ -157,7 +152,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,
|
||||||
@@ -187,17 +182,15 @@ func TestUDPServer(t *testing.T) {
|
|||||||
config := &core.Config{
|
config := &core.Config{
|
||||||
App: []*serial.TypedMessage{
|
App: []*serial.TypedMessage{
|
||||||
serial.ToTypedMessage(&Config{
|
serial.ToTypedMessage(&Config{
|
||||||
NameServer: []*NameServer{
|
NameServers: []*net.Endpoint{
|
||||||
{
|
{
|
||||||
Address: &net.Endpoint{
|
Network: net.Network_UDP,
|
||||||
Network: net.Network_UDP,
|
Address: &net.IPOrDomain{
|
||||||
Address: &net.IPOrDomain{
|
Address: &net.IPOrDomain_Ip{
|
||||||
Address: &net.IPOrDomain_Ip{
|
Ip: []byte{127, 0, 0, 1},
|
||||||
Ip: []byte{127, 0, 0, 1},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Port: uint32(port),
|
|
||||||
},
|
},
|
||||||
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -218,7 +211,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 +226,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 +241,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,12 +255,12 @@ 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,
|
||||||
})
|
})
|
||||||
if !errors.AllEqual(feature_dns.ErrEmptyResponse, errors.Cause(err)) {
|
if err != feature_dns.ErrEmptyResponse {
|
||||||
t.Fatal("error: ", err)
|
t.Fatal("error: ", err)
|
||||||
}
|
}
|
||||||
if len(ips) != 0 {
|
if len(ips) != 0 {
|
||||||
@@ -278,7 +271,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,
|
||||||
@@ -309,18 +302,18 @@ func TestPrioritizedDomain(t *testing.T) {
|
|||||||
config := &core.Config{
|
config := &core.Config{
|
||||||
App: []*serial.TypedMessage{
|
App: []*serial.TypedMessage{
|
||||||
serial.ToTypedMessage(&Config{
|
serial.ToTypedMessage(&Config{
|
||||||
NameServer: []*NameServer{
|
NameServers: []*net.Endpoint{
|
||||||
{
|
{
|
||||||
Address: &net.Endpoint{
|
Network: net.Network_UDP,
|
||||||
Network: net.Network_UDP,
|
Address: &net.IPOrDomain{
|
||||||
Address: &net.IPOrDomain{
|
Address: &net.IPOrDomain_Ip{
|
||||||
Address: &net.IPOrDomain_Ip{
|
Ip: []byte{127, 0, 0, 1},
|
||||||
Ip: []byte{127, 0, 0, 1},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Port: 9999, /* unreachable */
|
|
||||||
},
|
},
|
||||||
|
Port: 9999, /* unreachable */
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
NameServer: []*NameServer{
|
||||||
{
|
{
|
||||||
Address: &net.Endpoint{
|
Address: &net.Endpoint{
|
||||||
Network: net.Network_UDP,
|
Network: net.Network_UDP,
|
||||||
@@ -359,7 +352,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,
|
||||||
@@ -395,17 +388,15 @@ func TestUDPServerIPv6(t *testing.T) {
|
|||||||
config := &core.Config{
|
config := &core.Config{
|
||||||
App: []*serial.TypedMessage{
|
App: []*serial.TypedMessage{
|
||||||
serial.ToTypedMessage(&Config{
|
serial.ToTypedMessage(&Config{
|
||||||
NameServer: []*NameServer{
|
NameServers: []*net.Endpoint{
|
||||||
{
|
{
|
||||||
Address: &net.Endpoint{
|
Network: net.Network_UDP,
|
||||||
Network: net.Network_UDP,
|
Address: &net.IPOrDomain{
|
||||||
Address: &net.IPOrDomain{
|
Address: &net.IPOrDomain_Ip{
|
||||||
Address: &net.IPOrDomain_Ip{
|
Ip: []byte{127, 0, 0, 1},
|
||||||
Ip: []byte{127, 0, 0, 1},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Port: uint32(port),
|
|
||||||
},
|
},
|
||||||
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -425,7 +416,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,
|
||||||
@@ -456,17 +447,15 @@ func TestStaticHostDomain(t *testing.T) {
|
|||||||
config := &core.Config{
|
config := &core.Config{
|
||||||
App: []*serial.TypedMessage{
|
App: []*serial.TypedMessage{
|
||||||
serial.ToTypedMessage(&Config{
|
serial.ToTypedMessage(&Config{
|
||||||
NameServer: []*NameServer{
|
NameServers: []*net.Endpoint{
|
||||||
{
|
{
|
||||||
Address: &net.Endpoint{
|
Network: net.Network_UDP,
|
||||||
Network: net.Network_UDP,
|
Address: &net.IPOrDomain{
|
||||||
Address: &net.IPOrDomain{
|
Address: &net.IPOrDomain_Ip{
|
||||||
Address: &net.IPOrDomain_Ip{
|
Ip: []byte{127, 0, 0, 1},
|
||||||
Ip: []byte{127, 0, 0, 1},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Port: uint32(port),
|
|
||||||
},
|
},
|
||||||
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
StaticHosts: []*Config_HostMapping{
|
StaticHosts: []*Config_HostMapping{
|
||||||
@@ -494,7 +483,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 +528,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 +552,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 +594,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,
|
||||||
@@ -641,18 +630,18 @@ func TestLocalDomain(t *testing.T) {
|
|||||||
config := &core.Config{
|
config := &core.Config{
|
||||||
App: []*serial.TypedMessage{
|
App: []*serial.TypedMessage{
|
||||||
serial.ToTypedMessage(&Config{
|
serial.ToTypedMessage(&Config{
|
||||||
NameServer: []*NameServer{
|
NameServers: []*net.Endpoint{
|
||||||
{
|
{
|
||||||
Address: &net.Endpoint{
|
Network: net.Network_UDP,
|
||||||
Network: net.Network_UDP,
|
Address: &net.IPOrDomain{
|
||||||
Address: &net.IPOrDomain{
|
Address: &net.IPOrDomain_Ip{
|
||||||
Address: &net.IPOrDomain_Ip{
|
Ip: []byte{127, 0, 0, 1},
|
||||||
Ip: []byte{127, 0, 0, 1},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Port: 9999, /* unreachable */
|
|
||||||
},
|
},
|
||||||
|
Port: 9999, /* unreachable */
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
NameServer: []*NameServer{
|
||||||
{
|
{
|
||||||
Address: &net.Endpoint{
|
Address: &net.Endpoint{
|
||||||
Network: net.Network_UDP,
|
Network: net.Network_UDP,
|
||||||
@@ -667,7 +656,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 +717,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 +732,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 +747,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 +762,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 +776,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 +791,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 +806,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 +822,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,
|
||||||
@@ -869,18 +858,18 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
config := &core.Config{
|
config := &core.Config{
|
||||||
App: []*serial.TypedMessage{
|
App: []*serial.TypedMessage{
|
||||||
serial.ToTypedMessage(&Config{
|
serial.ToTypedMessage(&Config{
|
||||||
NameServer: []*NameServer{
|
NameServers: []*net.Endpoint{
|
||||||
{
|
{
|
||||||
Address: &net.Endpoint{
|
Network: net.Network_UDP,
|
||||||
Network: net.Network_UDP,
|
Address: &net.IPOrDomain{
|
||||||
Address: &net.IPOrDomain{
|
Address: &net.IPOrDomain_Ip{
|
||||||
Address: &net.IPOrDomain_Ip{
|
Ip: []byte{127, 0, 0, 1},
|
||||||
Ip: []byte{127, 0, 0, 1},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Port: 9999, /* unreachable */
|
|
||||||
},
|
},
|
||||||
|
Port: 9999, /* unreachable */
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
NameServer: []*NameServer{
|
||||||
{
|
{
|
||||||
Address: &net.Endpoint{
|
Address: &net.Endpoint{
|
||||||
Network: net.Network_UDP,
|
Network: net.Network_UDP,
|
||||||
@@ -897,7 +886,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 +911,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 +935,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 +959,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 +988,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 +1003,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 +1018,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 +1033,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,
|
||||||
|
|||||||
@@ -1,22 +1,19 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/log"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/session"
|
|
||||||
"github.com/xtls/xray-core/core"
|
|
||||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||||
"golang.org/x/net/dns/dnsmessage"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fqdn normalizes domain make sure it ends with '.'
|
// Fqdn normalize domain make sure it ends with '.'
|
||||||
func Fqdn(domain string) string {
|
func Fqdn(domain string) string {
|
||||||
if len(domain) > 0 && strings.HasSuffix(domain, ".") {
|
if len(domain) > 0 && strings.HasSuffix(domain, ".") {
|
||||||
return domain
|
return domain
|
||||||
@@ -31,34 +28,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, uint32, 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()
|
|
||||||
if untilExpire <= 0 {
|
|
||||||
return nil, 0, errRecordNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
ttl := uint32(untilExpire) + 1
|
|
||||||
if ttl == 1 {
|
|
||||||
r.Expire = time.Now().Add(time.Second) // To ensure that two consecutive requests get the same result
|
|
||||||
}
|
}
|
||||||
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")
|
||||||
@@ -71,59 +64,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
|
||||||
@@ -180,23 +163,22 @@ func buildReqMsgs(domain string, option dns_feature.IPOption, reqIDGen func() ui
|
|||||||
return reqs
|
return reqs
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseResponse parses DNS answers from the returned payload
|
// parseResponse parse DNS answers from the returned payload
|
||||||
func parseResponse(payload []byte) (*IPRecord, error) {
|
func parseResponse(payload []byte) (*IPRecord, error) {
|
||||||
var parser dnsmessage.Parser
|
var parser dnsmessage.Parser
|
||||||
h, err := parser.Start(payload)
|
h, err := parser.Start(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to parse DNS response").Base(err).AtWarning()
|
return nil, newError("failed to parse DNS response").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
if err := parser.SkipAllQuestions(); err != nil {
|
if err := parser.SkipAllQuestions(); err != nil {
|
||||||
return nil, errors.New("failed to skip questions in DNS response").Base(err).AtWarning()
|
return nil, newError("failed to skip questions in DNS response").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
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.Minute * 30),
|
||||||
RawHeader: &h,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
L:
|
L:
|
||||||
@@ -204,14 +186,14 @@ L:
|
|||||||
ah, err := parser.AnswerHeader()
|
ah, err := parser.AnswerHeader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != dnsmessage.ErrSectionDone {
|
if err != dnsmessage.ErrSectionDone {
|
||||||
errors.LogInfoInner(context.Background(), err, "failed to parse answer section for domain: ", ah.Name.String())
|
newError("failed to parse answer section for domain: ", ah.Name.String()).Base(err).WriteToLog()
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
@@ -222,23 +204,20 @@ L:
|
|||||||
case dnsmessage.TypeA:
|
case dnsmessage.TypeA:
|
||||||
ans, err := parser.AResource()
|
ans, err := parser.AResource()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogInfoInner(context.Background(), err, "failed to parse A record for domain: ", ah.Name)
|
newError("failed to parse A record for domain: ", ah.Name).Base(err).WriteToLog()
|
||||||
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)
|
newError("failed to parse AAAA record for domain: ", ah.Name).Base(err).WriteToLog()
|
||||||
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")
|
newError("failed to skip answer").Base(err).WriteToLog()
|
||||||
break L
|
break L
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
@@ -247,19 +226,3 @@ L:
|
|||||||
|
|
||||||
return ipRecord, nil
|
return ipRecord, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// toDnsContext create a new background context with parent inbound, session and dns log
|
|
||||||
func toDnsContext(ctx context.Context, addr string) context.Context {
|
|
||||||
dnsCtx := core.ToBackgroundDetachedContext(ctx)
|
|
||||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
|
||||||
dnsCtx = session.ContextWithInbound(dnsCtx, inbound)
|
|
||||||
}
|
|
||||||
dnsCtx = session.ContextWithContent(dnsCtx, session.ContentFromContext(ctx))
|
|
||||||
dnsCtx = log.ContextWithAccessMessage(dnsCtx, &log.AccessMessage{
|
|
||||||
From: "DNS",
|
|
||||||
To: addr,
|
|
||||||
Status: log.AccessAccepted,
|
|
||||||
Reason: "",
|
|
||||||
})
|
|
||||||
return dnsCtx
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import (
|
|||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||||
"golang.org/x/net/dns/dnsmessage"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_parseResponse(t *testing.T) {
|
func Test_parseResponse(t *testing.T) {
|
||||||
@@ -18,31 +19,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::123:8888")),
|
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8888")).(dns.RR),
|
||||||
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123: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 +52,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 +64,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::123:8888"), net.ParseIP("2001::123: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,12 +85,11 @@ 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.Errorf(cmp.Diff(got, tt.want))
|
||||||
// t.Errorf("handleResponse() = %#v, want %#v", got, tt.want)
|
// t.Errorf("handleResponse() = %#v, want %#v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -156,7 +155,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)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
9
app/dns/errors.generated.go
Normal file
9
app/dns/errors.generated.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
import "github.com/xtls/xray-core/common/errors"
|
||||||
|
|
||||||
|
type errPathObjHolder struct{}
|
||||||
|
|
||||||
|
func newError(values ...interface{}) *errors.Error {
|
||||||
|
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||||
|
}
|
||||||
9
app/dns/fakedns/errors.generated.go
Normal file
9
app/dns/fakedns/errors.generated.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package fakedns
|
||||||
|
|
||||||
|
import "github.com/xtls/xray-core/common/errors"
|
||||||
|
|
||||||
|
type errPathObjHolder struct{}
|
||||||
|
|
||||||
|
func newError(values ...interface{}) *errors.Error {
|
||||||
|
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||||
|
}
|
||||||
@@ -5,12 +5,10 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
gonet "net"
|
gonet "net"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/cache"
|
"github.com/xtls/xray-core/common/cache"
|
||||||
"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/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
)
|
)
|
||||||
@@ -18,7 +16,6 @@ import (
|
|||||||
type Holder struct {
|
type Holder struct {
|
||||||
domainToIP cache.Lru
|
domainToIP cache.Lru
|
||||||
ipRange *gonet.IPNet
|
ipRange *gonet.IPNet
|
||||||
mu *sync.Mutex
|
|
||||||
|
|
||||||
config *FakeDnsPool
|
config *FakeDnsPool
|
||||||
}
|
}
|
||||||
@@ -46,13 +43,12 @@ func (fkdns *Holder) Start() error {
|
|||||||
if fkdns.config != nil && fkdns.config.IpPool != "" && fkdns.config.LruSize != 0 {
|
if fkdns.config != nil && fkdns.config.IpPool != "" && fkdns.config.LruSize != 0 {
|
||||||
return fkdns.initializeFromConfig()
|
return fkdns.initializeFromConfig()
|
||||||
}
|
}
|
||||||
return errors.New("invalid fakeDNS setting")
|
return newError("invalid fakeDNS setting")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fkdns *Holder) Close() error {
|
func (fkdns *Holder) Close() error {
|
||||||
fkdns.domainToIP = nil
|
fkdns.domainToIP = nil
|
||||||
fkdns.ipRange = nil
|
fkdns.ipRange = nil
|
||||||
fkdns.mu = nil
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +57,7 @@ func NewFakeDNSHolder() (*Holder, error) {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
if fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil {
|
if fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil {
|
||||||
return nil, errors.New("Unable to create Fake Dns Engine").Base(err).AtError()
|
return nil, newError("Unable to create Fake Dns Engine").Base(err).AtError()
|
||||||
}
|
}
|
||||||
err = fkdns.initialize(dns.FakeIPv4Pool, 65535)
|
err = fkdns.initialize(dns.FakeIPv4Pool, 65535)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -71,7 +67,7 @@ func NewFakeDNSHolder() (*Holder, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewFakeDNSHolderConfigOnly(conf *FakeDnsPool) (*Holder, error) {
|
func NewFakeDNSHolderConfigOnly(conf *FakeDnsPool) (*Holder, error) {
|
||||||
return &Holder{nil, nil, nil, conf}, nil
|
return &Holder{nil, nil, conf}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fkdns *Holder) initializeFromConfig() error {
|
func (fkdns *Holder) initializeFromConfig() error {
|
||||||
@@ -83,24 +79,21 @@ func (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
if _, ipRange, err = gonet.ParseCIDR(ipPoolCidr); err != nil {
|
if _, ipRange, err = gonet.ParseCIDR(ipPoolCidr); err != nil {
|
||||||
return errors.New("Unable to parse CIDR for Fake DNS IP assignment").Base(err).AtError()
|
return newError("Unable to parse CIDR for Fake DNS IP assignment").Base(err).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
ones, bits := ipRange.Mask.Size()
|
ones, bits := ipRange.Mask.Size()
|
||||||
rooms := bits - ones
|
rooms := bits - ones
|
||||||
if math.Log2(float64(lruSize)) >= float64(rooms) {
|
if math.Log2(float64(lruSize)) >= float64(rooms) {
|
||||||
return errors.New("LRU size is bigger than subnet size").AtError()
|
return newError("LRU size is bigger than subnet size").AtError()
|
||||||
}
|
}
|
||||||
fkdns.domainToIP = cache.NewLru(lruSize)
|
fkdns.domainToIP = cache.NewLru(lruSize)
|
||||||
fkdns.ipRange = ipRange
|
fkdns.ipRange = ipRange
|
||||||
fkdns.mu = new(sync.Mutex)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFakeIPForDomain checks and generates a fake IP for a domain name
|
// GetFakeIPForDomain check and generate a fake IP for a domain name
|
||||||
func (fkdns *Holder) GetFakeIPForDomain(domain string) []net.Address {
|
func (fkdns *Holder) GetFakeIPForDomain(domain string) []net.Address {
|
||||||
fkdns.mu.Lock()
|
|
||||||
defer fkdns.mu.Unlock()
|
|
||||||
if v, ok := fkdns.domainToIP.Get(domain); ok {
|
if v, ok := fkdns.domainToIP.Get(domain); ok {
|
||||||
return []net.Address{v.(net.Address)}
|
return []net.Address{v.(net.Address)}
|
||||||
}
|
}
|
||||||
@@ -130,7 +123,7 @@ func (fkdns *Holder) GetFakeIPForDomain(domain string) []net.Address {
|
|||||||
return []net.Address{ip}
|
return []net.Address{ip}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDomainFromFakeDNS checks if an IP is a fake IP and have corresponding domain name
|
// GetDomainFromFakeDNS check if an IP is a fake IP and have corresponding domain name
|
||||||
func (fkdns *Holder) GetDomainFromFakeDNS(ip net.Address) string {
|
func (fkdns *Holder) GetDomainFromFakeDNS(ip net.Address) string {
|
||||||
if !ip.Family().IsIP() || !fkdns.ipRange.Contains(ip.IP()) {
|
if !ip.Family().IsIP() || !fkdns.ipRange.Contains(ip.IP()) {
|
||||||
return ""
|
return ""
|
||||||
@@ -138,7 +131,7 @@ func (fkdns *Holder) GetDomainFromFakeDNS(ip net.Address) string {
|
|||||||
if k, ok := fkdns.domainToIP.GetKeyFromValue(ip); ok {
|
if k, ok := fkdns.domainToIP.GetKeyFromValue(ip); ok {
|
||||||
return k.(string)
|
return k.(string)
|
||||||
}
|
}
|
||||||
errors.LogInfo(context.Background(), "A fake ip request to ", ip, ", however there is no matching domain name in fake DNS")
|
newError("A fake ip request to ", ip, ", however there is no matching domain name in fake DNS").AtInfo().WriteToLog()
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,10 +186,10 @@ func (h *HolderMulti) Start() error {
|
|||||||
for _, v := range h.holders {
|
for _, v := range h.holders {
|
||||||
if v.config != nil && v.config.IpPool != "" && v.config.LruSize != 0 {
|
if v.config != nil && v.config.IpPool != "" && v.config.LruSize != 0 {
|
||||||
if err := v.Start(); err != nil {
|
if err := v.Start(); err != nil {
|
||||||
return errors.New("Cannot start all fake dns pools").Base(err)
|
return newError("Cannot start all fake dns pools").Base(err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return errors.New("invalid fakeDNS setting")
|
return newError("invalid fakeDNS setting")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -205,7 +198,7 @@ func (h *HolderMulti) Start() error {
|
|||||||
func (h *HolderMulti) Close() error {
|
func (h *HolderMulti) Close() error {
|
||||||
for _, v := range h.holders {
|
for _, v := range h.holders {
|
||||||
if err := v.Close(); err != nil {
|
if err := v.Close(); err != nil {
|
||||||
return errors.New("Cannot close all fake dns pools").Base(err)
|
return newError("Cannot close all fake dns pools").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
package fakedns
|
package fakedns
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.27.1
|
||||||
// protoc v5.28.2
|
// protoc v3.18.0
|
||||||
// source: app/dns/fakedns/fakedns.proto
|
// source: app/dns/fakedns/fakedns.proto
|
||||||
|
|
||||||
package fakedns
|
package fakedns
|
||||||
@@ -31,9 +31,11 @@ type FakeDnsPool struct {
|
|||||||
|
|
||||||
func (x *FakeDnsPool) Reset() {
|
func (x *FakeDnsPool) Reset() {
|
||||||
*x = FakeDnsPool{}
|
*x = FakeDnsPool{}
|
||||||
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[0]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[0]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *FakeDnsPool) String() string {
|
func (x *FakeDnsPool) String() string {
|
||||||
@@ -44,7 +46,7 @@ func (*FakeDnsPool) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *FakeDnsPool) ProtoReflect() protoreflect.Message {
|
func (x *FakeDnsPool) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[0]
|
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[0]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -83,9 +85,11 @@ type FakeDnsPoolMulti struct {
|
|||||||
|
|
||||||
func (x *FakeDnsPoolMulti) Reset() {
|
func (x *FakeDnsPoolMulti) Reset() {
|
||||||
*x = FakeDnsPoolMulti{}
|
*x = FakeDnsPoolMulti{}
|
||||||
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[1]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[1]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *FakeDnsPoolMulti) String() string {
|
func (x *FakeDnsPoolMulti) String() string {
|
||||||
@@ -96,7 +100,7 @@ func (*FakeDnsPoolMulti) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *FakeDnsPoolMulti) ProtoReflect() protoreflect.Message {
|
func (x *FakeDnsPoolMulti) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[1]
|
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[1]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -155,7 +159,7 @@ func file_app_dns_fakedns_fakedns_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_app_dns_fakedns_fakedns_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
var file_app_dns_fakedns_fakedns_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||||
var file_app_dns_fakedns_fakedns_proto_goTypes = []any{
|
var file_app_dns_fakedns_fakedns_proto_goTypes = []interface{}{
|
||||||
(*FakeDnsPool)(nil), // 0: xray.app.dns.fakedns.FakeDnsPool
|
(*FakeDnsPool)(nil), // 0: xray.app.dns.fakedns.FakeDnsPool
|
||||||
(*FakeDnsPoolMulti)(nil), // 1: xray.app.dns.fakedns.FakeDnsPoolMulti
|
(*FakeDnsPoolMulti)(nil), // 1: xray.app.dns.fakedns.FakeDnsPoolMulti
|
||||||
}
|
}
|
||||||
@@ -173,6 +177,32 @@ func file_app_dns_fakedns_fakedns_proto_init() {
|
|||||||
if File_app_dns_fakedns_fakedns_proto != nil {
|
if File_app_dns_fakedns_fakedns_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_app_dns_fakedns_fakedns_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*FakeDnsPool); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_dns_fakedns_fakedns_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*FakeDnsPoolMulti); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
package fakedns
|
package fakedns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gonet "net"
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
gonet "net"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/uuid"
|
"github.com/xtls/xray-core/common/uuid"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
"golang.org/x/sync/errgroup"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var ipPrefix = "198.1"
|
var ipPrefix = "198.1"
|
||||||
@@ -67,31 +67,6 @@ func TestFakeDnsHolderCreateMappingManySingleDomain(t *testing.T) {
|
|||||||
assert.Equal(t, addr[0].IP().String(), addr2[0].IP().String())
|
assert.Equal(t, addr[0].IP().String(), addr2[0].IP().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetFakeIPForDomainConcurrently(t *testing.T) {
|
|
||||||
fkdns, err := NewFakeDNSHolder()
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
total := 200
|
|
||||||
addr := make([][]net.Address, total)
|
|
||||||
var errg errgroup.Group
|
|
||||||
for i := 0; i < total; i++ {
|
|
||||||
errg.Go(testGetFakeIP(i, addr, fkdns))
|
|
||||||
}
|
|
||||||
errg.Wait()
|
|
||||||
for i := 0; i < total; i++ {
|
|
||||||
for j := i + 1; j < total; j++ {
|
|
||||||
assert.NotEqual(t, addr[i][0].IP().String(), addr[j][0].IP().String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testGetFakeIP(index int, addr [][]net.Address, fkdns *Holder) func() error {
|
|
||||||
return func() error {
|
|
||||||
addr[index] = fkdns.GetFakeIPForDomain("fakednstest" + strconv.Itoa(index) + ".example.com")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFakeDnsHolderCreateMappingAndRollOver(t *testing.T) {
|
func TestFakeDnsHolderCreateMappingAndRollOver(t *testing.T) {
|
||||||
fkdns, err := NewFakeDNSHolderConfigOnly(&FakeDnsPool{
|
fkdns, err := NewFakeDNSHolderConfigOnly(&FakeDnsPool{
|
||||||
IpPool: dns.FakeIPv4Pool,
|
IpPool: dns.FakeIPv4Pool,
|
||||||
@@ -173,31 +148,31 @@ func TestFakeDNSMulti(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("allocateTwoAddressForTwoPool", func(t *testing.T) {
|
t.Run("allocateTwoAddressForTwoPool", func(t *testing.T) {
|
||||||
address := fakeMulti.GetFakeIPForDomain("fakednstest.example.com")
|
address := fakeMulti.GetFakeIPForDomain("fakednstest.v2fly.org")
|
||||||
assert.Len(t, address, 2, "should be 2 address one for each pool")
|
assert.Len(t, address, 2, "should be 2 address one for each pool")
|
||||||
t.Run("eachOfThemShouldResolve:0", func(t *testing.T) {
|
t.Run("eachOfThemShouldResolve:0", func(t *testing.T) {
|
||||||
domain := fakeMulti.GetDomainFromFakeDNS(address[0])
|
domain := fakeMulti.GetDomainFromFakeDNS(address[0])
|
||||||
assert.Equal(t, "fakednstest.example.com", domain)
|
assert.Equal(t, "fakednstest.v2fly.org", domain)
|
||||||
})
|
})
|
||||||
t.Run("eachOfThemShouldResolve:1", func(t *testing.T) {
|
t.Run("eachOfThemShouldResolve:1", func(t *testing.T) {
|
||||||
domain := fakeMulti.GetDomainFromFakeDNS(address[1])
|
domain := fakeMulti.GetDomainFromFakeDNS(address[1])
|
||||||
assert.Equal(t, "fakednstest.example.com", domain)
|
assert.Equal(t, "fakednstest.v2fly.org", domain)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("understandIPTypeSelector", func(t *testing.T) {
|
t.Run("understandIPTypeSelector", func(t *testing.T) {
|
||||||
t.Run("ipv4", func(t *testing.T) {
|
t.Run("ipv4", func(t *testing.T) {
|
||||||
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv4.example.com", true, false)
|
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv4.v2fly.org", true, false)
|
||||||
assert.Len(t, address, 1, "should be 1 address")
|
assert.Len(t, address, 1, "should be 1 address")
|
||||||
assert.True(t, address[0].Family().IsIPv4())
|
assert.True(t, address[0].Family().IsIPv4())
|
||||||
})
|
})
|
||||||
t.Run("ipv6", func(t *testing.T) {
|
t.Run("ipv6", func(t *testing.T) {
|
||||||
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv6.example.com", false, true)
|
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv6.v2fly.org", false, true)
|
||||||
assert.Len(t, address, 1, "should be 1 address")
|
assert.Len(t, address, 1, "should be 1 address")
|
||||||
assert.True(t, address[0].Family().IsIPv6())
|
assert.True(t, address[0].Family().IsIPv6())
|
||||||
})
|
})
|
||||||
t.Run("ipv46", func(t *testing.T) {
|
t.Run("ipv46", func(t *testing.T) {
|
||||||
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv46.example.com", true, true)
|
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv46.v2fly.org", true, true)
|
||||||
assert.Len(t, address, 2, "should be 2 address")
|
assert.Len(t, address, 2, "should be 2 address")
|
||||||
assert.True(t, address[0].Family().IsIPv4())
|
assert.True(t, address[0].Family().IsIPv4())
|
||||||
assert.True(t, address[1].Family().IsIPv6())
|
assert.True(t, address[1].Family().IsIPv6())
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"github.com/xtls/xray-core/common"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"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/strmatcher"
|
"github.com/xtls/xray-core/common/strmatcher"
|
||||||
|
"github.com/xtls/xray-core/features"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,39 +15,50 @@ type StaticHosts struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewStaticHosts creates a new StaticHosts instance.
|
// NewStaticHosts creates a new StaticHosts instance.
|
||||||
func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
|
func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDomain) (*StaticHosts, error) {
|
||||||
g := new(strmatcher.MatcherGroup)
|
g := new(strmatcher.MatcherGroup)
|
||||||
sh := &StaticHosts{
|
sh := &StaticHosts{
|
||||||
ips: make([][]net.Address, len(hosts)+16),
|
ips: make([][]net.Address, len(hosts)+len(legacy)+16),
|
||||||
matchers: g,
|
matchers: g,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if legacy != nil {
|
||||||
|
features.PrintDeprecatedFeatureWarning("simple host mapping")
|
||||||
|
|
||||||
|
for domain, ip := range legacy {
|
||||||
|
matcher, err := strmatcher.Full.New(domain)
|
||||||
|
common.Must(err)
|
||||||
|
id := g.Add(matcher)
|
||||||
|
|
||||||
|
address := ip.AsAddress()
|
||||||
|
if address.Family().IsDomain() {
|
||||||
|
return nil, newError("invalid domain address in static hosts: ", address.Domain()).AtWarning()
|
||||||
|
}
|
||||||
|
|
||||||
|
sh.ips[id] = []net.Address{address}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, mapping := range hosts {
|
for _, mapping := range hosts {
|
||||||
matcher, err := toStrMatcher(mapping.Type, mapping.Domain)
|
matcher, err := toStrMatcher(mapping.Type, mapping.Domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to create domain matcher").Base(err)
|
return nil, newError("failed to create domain matcher").Base(err)
|
||||||
}
|
}
|
||||||
id := g.Add(matcher)
|
id := g.Add(matcher)
|
||||||
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)
|
||||||
if addr == nil {
|
if addr == nil {
|
||||||
return nil, errors.New("invalid IP address in static hosts: ", ip).AtWarning()
|
return nil, newError("invalid IP address in static hosts: ", ip).AtWarning()
|
||||||
}
|
}
|
||||||
ips = append(ips, addr)
|
ips = append(ips, addr)
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
return nil, newError("neither IP address nor proxied domain specified for domain: ", mapping.Domain).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
sh.ips[id] = ips
|
sh.ips[id] = ips
|
||||||
@@ -68,51 +77,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")
|
newError("found replaced domain: ", domain, " -> ", addrs[0].Domain(), ". Try to unwrap it").AtDebug().WriteToLog()
|
||||||
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",
|
||||||
@@ -55,18 +50,11 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
hosts, err := NewStaticHosts(pb)
|
hosts, err := NewStaticHosts(pb, nil)
|
||||||
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"
|
||||||
@@ -21,27 +20,22 @@ type Server interface {
|
|||||||
// Name of the Client.
|
// Name of the Client.
|
||||||
Name() string
|
Name() string
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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, clientIP net.IP) (Server, error) {
|
func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, error) {
|
||||||
if address := dest.Address; address.Family().IsDomain() {
|
if address := dest.Address; address.Family().IsDomain() {
|
||||||
u, err := url.Parse(address.Domain())
|
u, err := url.Parse(address.Domain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -50,66 +44,46 @@ 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(), nil
|
||||||
case strings.EqualFold(u.Scheme, "https"): // DNS-over-HTTPS Remote mode
|
case strings.EqualFold(u.Scheme, "https"): // DOH Remote mode
|
||||||
return NewDoHNameServer(u, dispatcher, false, disableCache, clientIP), nil
|
return NewDoHNameServer(u, dispatcher)
|
||||||
case strings.EqualFold(u.Scheme, "h2c"): // DNS-over-HTTPS h2c Remote mode
|
case strings.EqualFold(u.Scheme, "https+local"): // DOH Local mode
|
||||||
return NewDoHNameServer(u, dispatcher, true, disableCache, clientIP), nil
|
return NewDoHLocalNameServer(u), nil
|
||||||
case strings.EqualFold(u.Scheme, "https+local"): // DNS-over-HTTPS Local mode
|
|
||||||
return NewDoHNameServer(u, nil, false, disableCache, clientIP), nil
|
|
||||||
case strings.EqualFold(u.Scheme, "h2c+local"): // DNS-over-HTTPS h2c Local mode
|
|
||||||
return NewDoHNameServer(u, nil, true, disableCache, 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, clientIP)
|
return NewQUICNameServer(u)
|
||||||
case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode
|
case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode
|
||||||
return NewTCPNameServer(u, dispatcher, disableCache, clientIP)
|
return NewTCPNameServer(u, dispatcher)
|
||||||
case strings.EqualFold(u.Scheme, "tcp+local"): // DNS-over-TCP Local mode
|
case strings.EqualFold(u.Scheme, "tcp+local"): // DNS-over-TCP Local mode
|
||||||
return NewTCPLocalNameServer(u, disableCache, clientIP)
|
return NewTCPLocalNameServer(u)
|
||||||
case strings.EqualFold(u.String(), "fakedns"):
|
case strings.EqualFold(u.String(), "fakedns"):
|
||||||
var fd dns.FakeDNSEngine
|
return NewFakeDNSServer(), nil
|
||||||
err = core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
|
||||||
fd = fdns
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return NewFakeDNSServer(fd), nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dest.Network == net.Network_Unknown {
|
if dest.Network == net.Network_Unknown {
|
||||||
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, clientIP), nil
|
return NewClassicNameServer(dest, dispatcher), nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("No available name server could be created from ", dest).AtWarning()
|
return nil, newError("No available name server could be created from ", dest).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
|
// NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
|
||||||
func NewClient(
|
func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container router.GeoIPMatcherContainer, matcherInfos *[]*DomainMatcherInfo, updateDomainRule func(strmatcher.Matcher, int, []*DomainMatcherInfo) error) (*Client, error) {
|
||||||
ctx context.Context,
|
|
||||||
ns *NameServer,
|
|
||||||
clientIP net.IP,
|
|
||||||
disableCache bool,
|
|
||||||
tag string,
|
|
||||||
ipOption dns.IPOption,
|
|
||||||
matcherInfos *[]*DomainMatcherInfo,
|
|
||||||
updateDomainRule func(strmatcher.Matcher, int, []*DomainMatcherInfo) error,
|
|
||||||
) (*Client, error) {
|
|
||||||
client := &Client{}
|
client := &Client{}
|
||||||
|
|
||||||
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
|
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
|
||||||
// Create a new server for each client for now
|
// Create a new server for each client for now
|
||||||
server, err := NewServer(ctx, ns.Address.AsDestination(), dispatcher, disableCache, clientIP)
|
server, err := NewServer(ns.Address.AsDestination(), dispatcher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create nameserver").Base(err).AtWarning()
|
return newError("failed to create nameserver").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prioritize local domains with specific TLDs or those without any dot for the local DNS
|
// Priotize local domains with specific TLDs or without any dot to local DNS
|
||||||
if _, isLocalDNS := server.(*LocalNameServer); isLocalDNS {
|
if _, isLocalDNS := server.(*LocalNameServer); isLocalDNS {
|
||||||
ns.PrioritizedDomain = append(ns.PrioritizedDomain, localTLDsAndDotlessDomains...)
|
ns.PrioritizedDomain = append(ns.PrioritizedDomain, localTLDsAndDotlessDomains...)
|
||||||
ns.OriginalRules = append(ns.OriginalRules, localTLDsAndDotlessDomainsRule)
|
ns.OriginalRules = append(ns.OriginalRules, localTLDsAndDotlessDomainsRule)
|
||||||
// The following lines is a solution to avoid core panics(rule index out of range) when setting `localhost` DNS client in config.
|
// The following lines is a solution to avoid core panics(rule index out of range) when setting `localhost` DNS client in config.
|
||||||
// Because the `localhost` DNS client will append len(localTLDsAndDotlessDomains) rules into matcherInfos to match `geosite:private` default rule.
|
// Because the `localhost` DNS client will apend len(localTLDsAndDotlessDomains) rules into matcherInfos to match `geosite:private` default rule.
|
||||||
// But `matcherInfos` has no enough length to add rules, which leads to core panics (rule index out of range).
|
// But `matcherInfos` has no enough length to add rules, which leads to core panics (rule index out of range).
|
||||||
// To avoid this, the length of `matcherInfos` must be equal to the expected, so manually append it with Golang default zero value first for later modification.
|
// To avoid this, the length of `matcherInfos` must be equal to the expected, so manually append it with Golang default zero value first for later modification.
|
||||||
// Related issues:
|
// Related issues:
|
||||||
@@ -130,7 +104,7 @@ func NewClient(
|
|||||||
for _, domain := range ns.PrioritizedDomain {
|
for _, domain := range ns.PrioritizedDomain {
|
||||||
domainRule, err := toStrMatcher(domain.Type, domain.Domain)
|
domainRule, err := toStrMatcher(domain.Type, domain.Domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create prioritized domain").Base(err).AtWarning()
|
return newError("failed to create prioritized domain").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
originalRuleIdx := ruleCurr
|
originalRuleIdx := ruleCurr
|
||||||
if ruleCurr < len(ns.OriginalRules) {
|
if ruleCurr < len(ns.OriginalRules) {
|
||||||
@@ -149,154 +123,98 @@ func NewClient(
|
|||||||
}
|
}
|
||||||
err = updateDomainRule(domainRule, originalRuleIdx, *matcherInfos)
|
err = updateDomainRule(domainRule, originalRuleIdx, *matcherInfos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create prioritized domain").Base(err).AtWarning()
|
return newError("failed to create prioritized domain").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Establish expected IPs
|
// Establish expected IPs
|
||||||
var expectedMatchers []*router.GeoIPMatcher
|
var matchers []*router.GeoIPMatcher
|
||||||
for _, geoip := range ns.ExpectedGeoip {
|
for _, geoip := range ns.Geoip {
|
||||||
matcher, err := router.GlobalGeoIPContainer.Add(geoip)
|
matcher, err := container.Add(geoip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create expected ip matcher").Base(err).AtWarning()
|
return newError("failed to create ip matcher").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
expectedMatchers = append(expectedMatchers, matcher)
|
matchers = append(matchers, matcher)
|
||||||
}
|
|
||||||
|
|
||||||
// Establish unexpected IPs
|
|
||||||
var unexpectedMatchers []*router.GeoIPMatcher
|
|
||||||
for _, geoip := range ns.UnexpectedGeoip {
|
|
||||||
matcher, err := router.GlobalGeoIPContainer.Add(geoip)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("failed to create unexpected ip matcher").Base(err).AtWarning()
|
|
||||||
}
|
|
||||||
unexpectedMatchers = append(unexpectedMatchers, matcher)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(clientIP) > 0 {
|
if len(clientIP) > 0 {
|
||||||
switch ns.Address.Address.GetAddress().(type) {
|
switch ns.Address.Address.GetAddress().(type) {
|
||||||
case *net.IPOrDomain_Domain:
|
case *net.IPOrDomain_Domain:
|
||||||
errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetDomain(), " uses clientIP ", clientIP.String())
|
newError("DNS: client ", ns.Address.Address.GetDomain(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
|
||||||
case *net.IPOrDomain_Ip:
|
case *net.IPOrDomain_Ip:
|
||||||
errors.LogInfo(ctx, "DNS: client ", net.IP(ns.Address.Address.GetIp()), " uses clientIP ", clientIP.String())
|
newError("DNS: client ", ns.Address.Address.GetIp(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = expectedMatchers
|
client.expectIPs = matchers
|
||||||
client.unexpectedIPs = unexpectedMatchers
|
|
||||||
client.actPrior = ns.ActPrior
|
|
||||||
client.actUnprior = ns.ActUnprior
|
|
||||||
client.tag = tag
|
|
||||||
client.timeoutMs = timeoutMs
|
|
||||||
client.finalQuery = ns.FinalQuery
|
|
||||||
client.ipOption = &ipOption
|
|
||||||
client.checkSystem = checkSystem
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
return client, err
|
return client, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewSimpleClient creates a DNS client with a simple destination.
|
||||||
|
func NewSimpleClient(ctx context.Context, endpoint *net.Endpoint, clientIP net.IP) (*Client, error) {
|
||||||
|
client := &Client{}
|
||||||
|
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
|
||||||
|
server, err := NewServer(endpoint.AsDestination(), dispatcher)
|
||||||
|
if err != nil {
|
||||||
|
return newError("failed to create nameserver").Base(err).AtWarning()
|
||||||
|
}
|
||||||
|
client.server = server
|
||||||
|
client.clientIP = clientIP
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if len(clientIP) > 0 {
|
||||||
|
switch endpoint.Address.GetAddress().(type) {
|
||||||
|
case *net.IPOrDomain_Domain:
|
||||||
|
newError("DNS: client ", endpoint.Address.GetDomain(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
|
||||||
|
case *net.IPOrDomain_Ip:
|
||||||
|
newError("DNS: client ", endpoint.Address.GetIp(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return client, err
|
||||||
|
}
|
||||||
|
|
||||||
// Name returns the server name the client manages.
|
// Name returns the server name the client manages.
|
||||||
func (c *Client) Name() string {
|
func (c *Client) Name() string {
|
||||||
return c.server.Name()
|
return c.server.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) IsFinalQuery() bool {
|
// QueryIP send DNS query to the name server with the client's IP.
|
||||||
return c.finalQuery
|
func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption, disableCache bool) ([]net.IP, error) {
|
||||||
}
|
ctx, cancel := context.WithTimeout(ctx, 4*time.Second)
|
||||||
|
ips, err := c.server.QueryIP(ctx, domain, c.clientIP, option, disableCache)
|
||||||
// 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) {
|
|
||||||
if c.checkSystem {
|
|
||||||
supportIPv4, supportIPv6 := checkSystemNetwork()
|
|
||||||
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 {
|
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.expectedIPs) > 0 && !c.actPrior {
|
|
||||||
ips = router.MatchIPs(c.expectedIPs, ips, false)
|
|
||||||
errors.LogDebug(context.Background(), "domain ", domain, " expectedIPs ", ips, " matched at server ", c.Name())
|
|
||||||
if len(ips) == 0 {
|
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.unexpectedIPs) > 0 && !c.actUnprior {
|
|
||||||
ips = router.MatchIPs(c.unexpectedIPs, ips, true)
|
|
||||||
errors.LogDebug(context.Background(), "domain ", domain, " unexpectedIPs ", ips, " matched at server ", c.Name())
|
|
||||||
if len(ips) == 0 {
|
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.expectedIPs) > 0 && c.actPrior {
|
|
||||||
ipsNew := router.MatchIPs(c.expectedIPs, ips, false)
|
|
||||||
if len(ipsNew) > 0 {
|
|
||||||
ips = ipsNew
|
|
||||||
errors.LogDebug(context.Background(), "domain ", domain, " priorIPs ", ips, " matched at server ", c.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.unexpectedIPs) > 0 && c.actUnprior {
|
|
||||||
ipsNew := router.MatchIPs(c.unexpectedIPs, ips, true)
|
|
||||||
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 {
|
// MatchExpectedIPs matches queried domain IPs with expected IPs and returns matched ones.
|
||||||
switch queryStrategy {
|
func (c *Client) MatchExpectedIPs(domain string, ips []net.IP) ([]net.IP, error) {
|
||||||
case QueryStrategy_USE_IP:
|
if len(c.expectIPs) == 0 {
|
||||||
return ipOption
|
return ips, nil
|
||||||
case QueryStrategy_USE_SYS:
|
|
||||||
return ipOption
|
|
||||||
case QueryStrategy_USE_IP4:
|
|
||||||
return dns.IPOption{
|
|
||||||
IPv4Enable: ipOption.IPv4Enable,
|
|
||||||
IPv6Enable: false,
|
|
||||||
FakeEnable: false,
|
|
||||||
}
|
|
||||||
case QueryStrategy_USE_IP6:
|
|
||||||
return dns.IPOption{
|
|
||||||
IPv4Enable: false,
|
|
||||||
IPv6Enable: ipOption.IPv6Enable,
|
|
||||||
FakeEnable: false,
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return ipOption
|
|
||||||
}
|
}
|
||||||
|
newIps := []net.IP{}
|
||||||
|
for _, ip := range ips {
|
||||||
|
for _, matcher := range c.expectIPs {
|
||||||
|
if matcher.Match(ip) {
|
||||||
|
newIps = append(newIps, ip)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(newIps) == 0 {
|
||||||
|
return nil, errExpectedIPNonMatch
|
||||||
|
}
|
||||||
|
newError("domain ", domain, " expectIPs ", newIps, " matched at server ", c.Name()).AtDebug().WriteToLog()
|
||||||
|
return newIps, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,136 +3,247 @@ package dns
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
go_errors "errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
utls "github.com/refraction-networking/utls"
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
|
|
||||||
"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/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/http2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DoHNameServer implemented DNS over HTTPS (RFC8484) Wire Format,
|
// DoHNameServer implemented DNS over HTTPS (RFC8484) Wire Format,
|
||||||
// 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
|
||||||
|
reqID uint32
|
||||||
|
httpClient *http.Client
|
||||||
|
dohURL string
|
||||||
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, clientIP net.IP) *DoHNameServer {
|
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher) (*DoHNameServer, error) {
|
||||||
url.Scheme = "https"
|
newError("DNS: created Remote DOH client for ", url.String()).AtInfo().WriteToLog()
|
||||||
mode := "DOH"
|
s := baseDOHNameServer(url, "DOH")
|
||||||
if dispatcher == nil {
|
|
||||||
mode = "DOHL"
|
s.dispatcher = dispatcher
|
||||||
}
|
tr := &http.Transport{
|
||||||
errors.LogInfo(context.Background(), "DNS: created ", mode, " client for ", url.String(), ", with h2c ", h2c)
|
MaxIdleConns: 30,
|
||||||
s := &DoHNameServer{
|
IdleConnTimeout: 90 * time.Second,
|
||||||
cacheController: NewCacheController(mode+"//"+url.Host, disableCache),
|
TLSHandshakeTimeout: 30 * time.Second,
|
||||||
dohURL: url.String(),
|
ForceAttemptHTTP2: true,
|
||||||
clientIP: clientIP,
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
dispatcherCtx := context.Background()
|
||||||
|
|
||||||
|
dest, err := net.ParseDestination(network + ":" + addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatcherCtx = session.ContextWithContent(dispatcherCtx, session.ContentFromContext(ctx))
|
||||||
|
dispatcherCtx = session.ContextWithInbound(dispatcherCtx, session.InboundFromContext(ctx))
|
||||||
|
dispatcherCtx = log.ContextWithAccessMessage(dispatcherCtx, &log.AccessMessage{
|
||||||
|
From: "DoH",
|
||||||
|
To: s.dohURL,
|
||||||
|
Status: log.AccessAccepted,
|
||||||
|
Reason: "",
|
||||||
|
})
|
||||||
|
|
||||||
|
link, err := s.dispatcher.Dispatch(dispatcherCtx, dest)
|
||||||
|
select {
|
||||||
|
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
|
||||||
|
},
|
||||||
}
|
}
|
||||||
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) {
|
|
||||||
dest, err := net.ParseDestination(network + ":" + addr)
|
return s, nil
|
||||||
if err != nil {
|
}
|
||||||
return nil, err
|
|
||||||
}
|
// NewDoHLocalNameServer creates DOH client object for local resolving
|
||||||
var conn net.Conn
|
func NewDoHLocalNameServer(url *url.URL) *DoHNameServer {
|
||||||
if dispatcher != nil {
|
url.Scheme = "https"
|
||||||
dnsCtx := toDnsContext(ctx, s.dohURL)
|
s := baseDOHNameServer(url, "DOHL")
|
||||||
if h2c {
|
tr := &http.Transport{
|
||||||
dnsCtx = session.ContextWithMitmAlpn11(dnsCtx, false) // for insurance
|
IdleConnTimeout: 90 * time.Second,
|
||||||
dnsCtx = session.ContextWithMitmServerName(dnsCtx, url.Hostname())
|
ForceAttemptHTTP2: true,
|
||||||
}
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
link, err := dispatcher.Dispatch(dnsCtx, dest)
|
dest, err := net.ParseDestination(network + ":" + addr)
|
||||||
select {
|
if err != nil {
|
||||||
case <-ctx.Done():
|
return nil, err
|
||||||
return nil, ctx.Err()
|
}
|
||||||
default:
|
conn, err := internet.DialSystemDNS(ctx, dest, nil)
|
||||||
}
|
log.Record(&log.AccessMessage{
|
||||||
if err != nil {
|
From: "DoH",
|
||||||
return nil, err
|
To: s.dohURL,
|
||||||
}
|
Status: log.AccessAccepted,
|
||||||
cc := common.ChainedClosable{}
|
Detour: "local",
|
||||||
if cw, ok := link.Writer.(common.Closable); ok {
|
})
|
||||||
cc = append(cc, cw)
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
if cr, ok := link.Reader.(common.Closable); ok {
|
}
|
||||||
cc = append(cc, cr)
|
return conn, nil
|
||||||
}
|
|
||||||
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
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
s.httpClient = &http.Client{
|
||||||
|
Timeout: time.Second * 180,
|
||||||
|
Transport: tr,
|
||||||
|
}
|
||||||
|
newError("DNS: created Local DOH client for ", url.String()).AtInfo().WriteToLog()
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func baseDOHNameServer(url *url.URL, prefix string) *DoHNameServer {
|
||||||
|
s := &DoHNameServer{
|
||||||
|
ips: make(map[string]*record),
|
||||||
|
pub: pubsub.NewService(),
|
||||||
|
name: prefix + "//" + url.Host,
|
||||||
|
dohURL: url.String(),
|
||||||
|
}
|
||||||
|
s.cleanup = &task.Periodic{
|
||||||
|
Interval: time.Minute,
|
||||||
|
Execute: s.Cleanup,
|
||||||
|
}
|
||||||
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup clears expired items from cache
|
||||||
|
func (s *DoHNameServer) Cleanup() error {
|
||||||
|
now := time.Now()
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
|
if len(s.ips) == 0 {
|
||||||
|
return newError("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 {
|
||||||
|
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog()
|
||||||
|
|
||||||
|
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 uint16(atomic.AddUint32(&s.reqID, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DoHNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||||
errors.LogInfo(ctx, s.Name(), " querying: ", domain)
|
newError(s.name, " querying: ", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
|
||||||
if s.Name()+"." == "DOH//"+domain {
|
if s.name+"." == "DOH//"+domain {
|
||||||
errors.LogError(ctx, s.Name(), " tries to resolve itself! Use IP or set \"hosts\" instead.")
|
newError(s.name, " tries to resolve itself! Use IP or set \"hosts\" instead.").AtError().WriteToLog(session.ExportIDToError(ctx))
|
||||||
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(domain, 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 {
|
||||||
@@ -158,7 +269,7 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- er
|
|||||||
})
|
})
|
||||||
|
|
||||||
// forced to use mux for DOH
|
// forced to use mux for DOH
|
||||||
// dnsCtx = session.ContextWithMuxPreferred(dnsCtx, true)
|
// dnsCtx = session.ContextWithMuxPrefered(dnsCtx, true)
|
||||||
|
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline)
|
dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline)
|
||||||
@@ -166,23 +277,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 ", domain)
|
newError("failed to pack dns query for ", domain).Base(err).AtError().WriteToLog()
|
||||||
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 ", domain)
|
newError("failed to retrieve response for ", domain).Base(err).AtError().WriteToLog()
|
||||||
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 ", domain)
|
newError("failed to handle DOH response for ", domain).Base(err).AtError().WriteToLog()
|
||||||
noResponseErrCh <- err
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.cacheController.updateIP(r, rec)
|
s.updateIP(r, rec)
|
||||||
}(req)
|
}(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,8 +305,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))
|
||||||
@@ -215,50 +321,103 @@ 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) { // nolint: dupl
|
s.RLock()
|
||||||
fqdn := Fqdn(domain)
|
record, found := s.ips[domain]
|
||||||
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
s.RUnlock()
|
||||||
defer closeSubscribers(sub4, sub6)
|
|
||||||
|
|
||||||
if s.cacheController.disableCache {
|
if !found {
|
||||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
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)
|
||||||
|
|
||||||
|
if disableCache {
|
||||||
|
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||||
} else {
|
} else {
|
||||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
if !go_errors.Is(err, errRecordNotFound) {
|
if err != errRecordNotFound {
|
||||||
errors.LogDebugInner(ctx, err, s.Name(), " cache HIT ", domain, " -> ", ips)
|
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||||
return ips, ttl, err
|
return ips, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
noResponseErrCh := make(chan error, 2)
|
// ipv4 and ipv6 belong to different subscription groups
|
||||||
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
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()
|
start := time.Now()
|
||||||
|
|
||||||
if sub4 != nil {
|
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 {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil, 0, ctx.Err()
|
return nil, ctx.Err()
|
||||||
case err := <-noResponseErrCh:
|
case <-done:
|
||||||
return nil, 0, err
|
|
||||||
case <-sub4.Wait():
|
|
||||||
sub4.Close()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if sub6 != nil {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, 0, ctx.Err()
|
|
||||||
case err := <-noResponseErrCh:
|
|
||||||
return nil, 0, err
|
|
||||||
case <-sub6.Wait():
|
|
||||||
sub6.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
|
||||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
|
||||||
return ips, ttl, err
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
. "github.com/xtls/xray-core/app/dns"
|
. "github.com/xtls/xray-core/app/dns"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
@@ -17,12 +18,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, net.IP(nil))
|
s := NewDoHLocalNameServer(url)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", 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 +35,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, net.IP(nil))
|
s := NewDoHLocalNameServer(url)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", 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,59 +48,13 @@ 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 != "" {
|
||||||
t.Fatal(r)
|
t.Fatal(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDOHNameServerWithIPv4Override(t *testing.T) {
|
|
||||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
s := NewDoHNameServer(url, nil, false, false, net.IP(nil))
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: false,
|
|
||||||
})
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ip := range ips {
|
|
||||||
if len(ip) != net.IPv4len {
|
|
||||||
t.Error("expect only IPv4 response from DNS query")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDOHNameServerWithIPv6Override(t *testing.T) {
|
|
||||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
s := NewDoHNameServer(url, nil, false, false, net.IP(nil))
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
|
||||||
IPv4Enable: false,
|
|
||||||
IPv6Enable: true,
|
|
||||||
})
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ip := range ips {
|
|
||||||
if len(ip) != net.IPv6len {
|
|
||||||
t.Error("expect only IPv6 response from DNS query")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package dns
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"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/core"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -12,19 +12,22 @@ type FakeDNSServer struct {
|
|||||||
fakeDNSEngine dns.FakeDNSEngine
|
fakeDNSEngine dns.FakeDNSEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFakeDNSServer(fd dns.FakeDNSEngine) *FakeDNSServer {
|
func NewFakeDNSServer() *FakeDNSServer {
|
||||||
return &FakeDNSServer{fakeDNSEngine: fd}
|
return &FakeDNSServer{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (FakeDNSServer) Name() string {
|
func (FakeDNSServer) Name() string {
|
||||||
return "FakeDNS"
|
return "FakeDNS"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, opt dns.IPOption) ([]net.IP, uint32, error) {
|
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, opt dns.IPOption, _ bool) ([]net.IP, error) {
|
||||||
if f.fakeDNSEngine == nil {
|
if f.fakeDNSEngine == nil {
|
||||||
return nil, 0, errors.New("Unable to locate a fake DNS Engine").AtError()
|
if err := core.RequireFeatures(ctx, func(fd dns.FakeDNSEngine) {
|
||||||
|
f.fakeDNSEngine = fd
|
||||||
|
}); err != nil {
|
||||||
|
return nil, newError("Unable to locate a fake DNS Engine").Base(err).AtError()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ips []net.Address
|
var ips []net.Address
|
||||||
if fkr0, ok := f.fakeDNSEngine.(dns.FakeDNSEngineRev0); ok {
|
if fkr0, ok := f.fakeDNSEngine.(dns.FakeDNSEngineRev0); ok {
|
||||||
ips = fkr0.GetFakeIPForDomain3(domain, opt.IPv4Enable, opt.IPv6Enable)
|
ips = fkr0.GetFakeIPForDomain3(domain, opt.IPv4Enable, opt.IPv6Enable)
|
||||||
@@ -34,13 +37,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, newError("Unable to convert IP to net ip").Base(err).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogInfo(ctx, f.Name(), " got answer: ", domain, " -> ", ips)
|
newError(f.Name(), " got answer: ", domain, " -> ", ips).AtInfo().WriteToLog()
|
||||||
|
|
||||||
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,12 +2,11 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"strings"
|
||||||
|
|
||||||
"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/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/features/dns/localdns"
|
"github.com/xtls/xray-core/features/dns/localdns"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,15 +15,18 @@ type LocalNameServer struct {
|
|||||||
client *localdns.Client
|
client *localdns.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryIP implements Server.
|
const errEmptyResponse = "No address associated with hostname"
|
||||||
func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, option dns.IPOption) (ips []net.IP, ttl uint32, err error) {
|
|
||||||
|
|
||||||
start := time.Now()
|
// QueryIP implements Server.
|
||||||
ips, ttl, err = s.client.LookupIP(domain, option)
|
func (s *LocalNameServer) QueryIP(_ context.Context, domain string, _ net.IP, option dns.IPOption, _ bool) (ips []net.IP, err error) {
|
||||||
|
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)
|
newError("Localhost got answer: ", domain, " -> ", ips).AtInfo().WriteToLog()
|
||||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -37,13 +39,13 @@ func (s *LocalNameServer) Name() string {
|
|||||||
|
|
||||||
// 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() *LocalNameServer {
|
||||||
errors.LogInfo(context.Background(), "DNS: created localhost client")
|
newError("DNS: created localhost client").AtInfo().WriteToLog()
|
||||||
return &LocalNameServer{
|
return &LocalNameServer{
|
||||||
client: localdns.New(),
|
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()}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
|
||||||
. "github.com/xtls/xray-core/app/dns"
|
. "github.com/xtls/xray-core/app/dns"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
@@ -13,11 +15,11 @@ import (
|
|||||||
func TestLocalNameServer(t *testing.T) {
|
func TestLocalNameServer(t *testing.T) {
|
||||||
s := NewLocalNameServer()
|
s := NewLocalNameServer()
|
||||||
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 {
|
||||||
|
|||||||
@@ -1,47 +1,50 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
|
||||||
go_errors "errors"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/quic-go/quic-go"
|
"github.com/lucas-clemente/quic-go"
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"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"
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NextProtoDQ - During connection establishment, DNS/QUIC support is indicated
|
// NextProtoDQ - During connection establishment, DNS/QUIC support is indicated
|
||||||
// by selecting the ALPN token "dq" in the crypto handshake.
|
// by selecting the ALPN token "dq" in the crypto handshake.
|
||||||
const NextProtoDQ = "doq"
|
const NextProtoDQ = "doq-i00"
|
||||||
|
|
||||||
const handshakeTimeout = time.Second * 8
|
const handshakeTimeout = time.Second * 8
|
||||||
|
|
||||||
// QUICNameServer implemented DNS over QUIC
|
// QUICNameServer implemented DNS over QUIC
|
||||||
type QUICNameServer struct {
|
type QUICNameServer struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
cacheController *CacheController
|
ips map[string]*record
|
||||||
destination *net.Destination
|
pub *pubsub.Service
|
||||||
connection *quic.Conn
|
cleanup *task.Periodic
|
||||||
clientIP net.IP
|
reqID uint32
|
||||||
|
name string
|
||||||
|
destination *net.Destination
|
||||||
|
session quic.Session
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, clientIP net.IP) (*QUICNameServer, error) {
|
func NewQUICNameServer(url *url.URL) (*QUICNameServer, error) {
|
||||||
errors.LogInfo(context.Background(), "DNS: created Local DNS-over-QUIC client for ", url.String())
|
newError("DNS: created Local DNS-over-QUIC client for ", url.String()).AtInfo().WriteToLog()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
port := net.Port(853)
|
port := net.Port(784)
|
||||||
if url.Port() != "" {
|
if url.Port() != "" {
|
||||||
port, err = net.PortFromString(url.Port())
|
port, err = net.PortFromString(url.Port())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -51,9 +54,14 @@ func NewQUICNameServer(url *url.URL, disableCache bool, clientIP net.IP) (*QUICN
|
|||||||
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),
|
ips: make(map[string]*record),
|
||||||
destination: &dest,
|
pub: pubsub.NewService(),
|
||||||
clientIP: clientIP,
|
name: url.String(),
|
||||||
|
destination: &dest,
|
||||||
|
}
|
||||||
|
s.cleanup = &task.Periodic{
|
||||||
|
Interval: time.Minute,
|
||||||
|
Execute: s.Cleanup,
|
||||||
}
|
}
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
@@ -61,17 +69,94 @@ func NewQUICNameServer(url *url.URL, disableCache bool, clientIP net.IP) (*QUICN
|
|||||||
|
|
||||||
// Name returns client name
|
// Name returns client name
|
||||||
func (s *QUICNameServer) Name() string {
|
func (s *QUICNameServer) Name() string {
|
||||||
return s.cacheController.name
|
return s.name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup clears expired items from cache
|
||||||
|
func (s *QUICNameServer) Cleanup() error {
|
||||||
|
now := time.Now()
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
|
if len(s.ips) == 0 {
|
||||||
|
return newError("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 {
|
||||||
|
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog()
|
||||||
|
|
||||||
|
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 uint16(atomic.AddUint32(&s.reqID, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||||
errors.LogInfo(ctx, s.Name(), " querying: ", domain)
|
newError(s.name, " querying: ", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
|
||||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
@@ -102,37 +187,19 @@ 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")
|
newError("failed to pack dns query").Base(err).AtError().WriteToLog()
|
||||||
noResponseErrCh <- err
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dnsReqBuf := buf.New()
|
|
||||||
err = binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "binary write failed")
|
|
||||||
noResponseErrCh <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = dnsReqBuf.Write(b.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "buffer write failed")
|
|
||||||
noResponseErrCh <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
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")
|
newError("failed to open quic session").Base(err).AtError().WriteToLog()
|
||||||
noResponseErrCh <- err
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = conn.Write(dnsReqBuf.Bytes())
|
_, err = conn.Write(b.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to send query")
|
newError("failed to send query").Base(err).AtError().WriteToLog()
|
||||||
noResponseErrCh <- err
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,87 +207,121 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- e
|
|||||||
|
|
||||||
respBuf := buf.New()
|
respBuf := buf.New()
|
||||||
defer respBuf.Release()
|
defer respBuf.Release()
|
||||||
n, err := respBuf.ReadFullFrom(conn, 2)
|
n, err := respBuf.ReadFrom(conn)
|
||||||
if err != nil && n == 0 {
|
if err != nil && n == 0 {
|
||||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
newError("failed to read response").Base(err).AtError().WriteToLog()
|
||||||
noResponseErrCh <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var length int16
|
|
||||||
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
|
||||||
noResponseErrCh <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
respBuf.Clear()
|
|
||||||
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
|
||||||
if err != nil && n == 0 {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
|
||||||
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")
|
newError("failed to handle response").Base(err).AtError().WriteToLog()
|
||||||
noResponseErrCh <- err
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.cacheController.updateIP(r, rec)
|
s.updateIP(r, rec)
|
||||||
}(req)
|
}(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryIP is called from dns.Server->queryIPTimeout
|
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()
|
||||||
fqdn := Fqdn(domain)
|
record, found := s.ips[domain]
|
||||||
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
s.RUnlock()
|
||||||
defer closeSubscribers(sub4, sub6)
|
|
||||||
|
|
||||||
if s.cacheController.disableCache {
|
if !found {
|
||||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
return nil, errRecordNotFound
|
||||||
} else {
|
|
||||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
|
||||||
if !go_errors.Is(err, errRecordNotFound) {
|
|
||||||
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, ttl, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
noResponseErrCh := make(chan error, 2)
|
var err4 error
|
||||||
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
var err6 error
|
||||||
start := time.Now()
|
var ips []net.Address
|
||||||
|
var ip6 []net.Address
|
||||||
|
|
||||||
if sub4 != nil {
|
if option.IPv4Enable {
|
||||||
select {
|
ips, err4 = record.A.getIPs()
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, 0, ctx.Err()
|
|
||||||
case err := <-noResponseErrCh:
|
|
||||||
return nil, 0, err
|
|
||||||
case <-sub4.Wait():
|
|
||||||
sub4.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sub6 != nil {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, 0, ctx.Err()
|
|
||||||
case err := <-noResponseErrCh:
|
|
||||||
return nil, 0, err
|
|
||||||
case <-sub6.Wait():
|
|
||||||
sub6.Close()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
if option.IPv6Enable {
|
||||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
ip6, err6 = record.AAAA.getIPs()
|
||||||
return ips, ttl, err
|
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)
|
||||||
|
|
||||||
|
if disableCache {
|
||||||
|
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||||
|
} else {
|
||||||
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
|
if err != errRecordNotFound {
|
||||||
|
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||||
|
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)
|
||||||
|
|
||||||
|
for {
|
||||||
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
|
if err != errRecordNotFound {
|
||||||
|
return ips, err
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isActive(s quic.Session) bool {
|
||||||
select {
|
select {
|
||||||
case <-s.Context().Done():
|
case <-s.Context().Done():
|
||||||
return false
|
return false
|
||||||
@@ -229,17 +330,17 @@ func isActive(s *quic.Conn) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QUICNameServer) getConnection() (*quic.Conn, error) {
|
func (s *QUICNameServer) getSession() (quic.Session, error) {
|
||||||
var conn *quic.Conn
|
var session quic.Session
|
||||||
s.RLock()
|
s.RLock()
|
||||||
conn = s.connection
|
session = s.session
|
||||||
if conn != nil && isActive(conn) {
|
if session != nil && isActive(session) {
|
||||||
s.RUnlock()
|
s.RUnlock()
|
||||||
return conn, nil
|
return session, nil
|
||||||
}
|
}
|
||||||
if conn != nil {
|
if session != nil {
|
||||||
// we're recreating the connection, let's create a new one
|
// we're recreating the session, let's create a new one
|
||||||
_ = conn.CloseWithError(0, "")
|
_ = session.CloseWithError(0, "")
|
||||||
}
|
}
|
||||||
s.RUnlock()
|
s.RUnlock()
|
||||||
|
|
||||||
@@ -247,48 +348,42 @@ func (s *QUICNameServer) getConnection() (*quic.Conn, error) {
|
|||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
conn, err = s.openConnection()
|
session, err = s.openSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// This does not look too nice, but QUIC (or maybe quic-go)
|
// This does not look too nice, but QUIC (or maybe quic-go)
|
||||||
// doesn't seem stable enough.
|
// doesn't seem stable enough.
|
||||||
// Maybe retransmissions aren't fully implemented in quic-go?
|
// Maybe retransmissions aren't fully implemented in quic-go?
|
||||||
// Anyways, the simple solution is to make a second try when
|
// Anyways, the simple solution is to make a second try when
|
||||||
// it fails to open the QUIC connection.
|
// it fails to open the QUIC session.
|
||||||
conn, err = s.openConnection()
|
session, err = s.openSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.connection = conn
|
s.session = session
|
||||||
return conn, nil
|
return session, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QUICNameServer) openConnection() (*quic.Conn, error) {
|
func (s *QUICNameServer) openSession() (quic.Session, error) {
|
||||||
tlsConfig := tls.Config{}
|
tlsConfig := tls.Config{}
|
||||||
quicConfig := &quic.Config{
|
quicConfig := &quic.Config{
|
||||||
HandshakeIdleTimeout: handshakeTimeout,
|
HandshakeIdleTimeout: handshakeTimeout,
|
||||||
}
|
}
|
||||||
tlsConfig.ServerName = s.destination.Address.String()
|
|
||||||
conn, err := quic.DialAddr(context.Background(), s.destination.NetAddr(), tlsConfig.GetTLSConfig(tls.WithNextProto("http/1.1", http2.NextProtoTLS, NextProtoDQ)), quicConfig)
|
session, err := quic.DialAddrContext(context.Background(), s.destination.NetAddr(), tlsConfig.GetTLSConfig(tls.WithNextProto("http/1.1", http2.NextProtoTLS, NextProtoDQ)), quicConfig)
|
||||||
log.Record(&log.AccessMessage{
|
|
||||||
From: "DNS",
|
|
||||||
To: s.destination,
|
|
||||||
Status: log.AccessAccepted,
|
|
||||||
Detour: "local",
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return conn, nil
|
return session, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QUICNameServer) openStream(ctx context.Context) (*quic.Stream, error) {
|
func (s *QUICNameServer) openStream(ctx context.Context) (quic.Stream, error) {
|
||||||
conn, err := s.getConnection()
|
session, err := s.getSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// open a new stream
|
// open a new stream
|
||||||
return conn.OpenStreamSync(ctx)
|
return session.OpenStreamSync(ctx)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,82 +6,39 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/features/dns"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
. "github.com/xtls/xray-core/app/dns"
|
. "github.com/xtls/xray-core/app/dns"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestQUICNameServer(t *testing.T) {
|
func TestQUICNameServer(t *testing.T) {
|
||||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
url, err := url.Parse("quic://dns.adguard.com")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
s, err := NewQUICNameServer(url, false, net.IP(nil))
|
s, err := NewQUICNameServer(url)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", 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 != "" {
|
||||||
t.Fatal(r)
|
t.Fatal(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQUICNameServerWithIPv4Override(t *testing.T) {
|
|
||||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
|
||||||
common.Must(err)
|
|
||||||
s, err := NewQUICNameServer(url, false, net.IP(nil))
|
|
||||||
common.Must(err)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: false,
|
|
||||||
})
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ip := range ips {
|
|
||||||
if len(ip) != net.IPv4len {
|
|
||||||
t.Error("expect only IPv4 response from DNS query")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestQUICNameServerWithIPv6Override(t *testing.T) {
|
|
||||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
|
||||||
common.Must(err)
|
|
||||||
s, err := NewQUICNameServer(url, false, net.IP(nil))
|
|
||||||
common.Must(err)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns.IPOption{
|
|
||||||
IPv4Enable: false,
|
|
||||||
IPv6Enable: true,
|
|
||||||
})
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ip := range ips {
|
|
||||||
if len(ip) != net.IPv6len {
|
|
||||||
t.Error("expect only IPv6 response from DNS query")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,18 +4,21 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
go_errors "errors"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
|
|
||||||
|
"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/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"
|
||||||
@@ -23,27 +26,25 @@ import (
|
|||||||
|
|
||||||
// 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTCPNameServer creates DNS over TCP server object for remote resolving.
|
// NewTCPNameServer creates DNS over TCP server object for remote resolving.
|
||||||
func NewTCPNameServer(
|
func NewTCPNameServer(url *url.URL, dispatcher routing.Dispatcher) (*TCPNameServer, error) {
|
||||||
url *url.URL,
|
s, err := baseTCPNameServer(url, "TCP")
|
||||||
dispatcher routing.Dispatcher,
|
|
||||||
disableCache bool,
|
|
||||||
clientIP net.IP,
|
|
||||||
) (*TCPNameServer, error) {
|
|
||||||
s, err := baseTCPNameServer(url, "TCP", disableCache, clientIP)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.dial = func(ctx context.Context) (net.Conn, error) {
|
s.dial = func(ctx context.Context) (net.Conn, error) {
|
||||||
link, err := dispatcher.Dispatch(toDnsContext(ctx, s.destination.String()), *s.destination)
|
link, err := dispatcher.Dispatch(ctx, *s.destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -58,8 +59,8 @@ func NewTCPNameServer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewTCPLocalNameServer creates DNS over TCP client object for local resolving
|
// NewTCPLocalNameServer creates DNS over TCP client object for local resolving
|
||||||
func NewTCPLocalNameServer(url *url.URL, disableCache bool, clientIP net.IP) (*TCPNameServer, error) {
|
func NewTCPLocalNameServer(url *url.URL) (*TCPNameServer, error) {
|
||||||
s, err := baseTCPNameServer(url, "TCPL", disableCache, clientIP)
|
s, err := baseTCPNameServer(url, "TCPL")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -71,20 +72,26 @@ func NewTCPLocalNameServer(url *url.URL, disableCache bool, clientIP net.IP) (*T
|
|||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func baseTCPNameServer(url *url.URL, prefix string, disableCache bool, clientIP net.IP) (*TCPNameServer, error) {
|
func baseTCPNameServer(url *url.URL, prefix string) (*TCPNameServer, error) {
|
||||||
|
var err error
|
||||||
port := net.Port(53)
|
port := net.Port(53)
|
||||||
if url.Port() != "" {
|
if url.Port() != "" {
|
||||||
var err error
|
port, err = net.PortFromString(url.Port())
|
||||||
if port, err = net.PortFromString(url.Port()); err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dest := net.TCPDestination(net.ParseAddress(url.Hostname()), port)
|
dest := net.TCPDestination(net.ParseAddress(url.Hostname()), port)
|
||||||
|
|
||||||
s := &TCPNameServer{
|
s := &TCPNameServer{
|
||||||
cacheController: NewCacheController(prefix+"//"+dest.NetAddr(), disableCache),
|
destination: &dest,
|
||||||
destination: &dest,
|
ips: make(map[string]*record),
|
||||||
clientIP: clientIP,
|
pub: pubsub.NewService(),
|
||||||
|
name: prefix + "//" + dest.NetAddr(),
|
||||||
|
}
|
||||||
|
s.cleanup = &task.Periodic{
|
||||||
|
Interval: time.Minute,
|
||||||
|
Execute: s.Cleanup,
|
||||||
}
|
}
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
@@ -92,17 +99,94 @@ func baseTCPNameServer(url *url.URL, prefix string, disableCache bool, clientIP
|
|||||||
|
|
||||||
// Name implements Server.
|
// Name implements Server.
|
||||||
func (s *TCPNameServer) Name() string {
|
func (s *TCPNameServer) Name() string {
|
||||||
return s.cacheController.name
|
return s.name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup clears expired items from cache
|
||||||
|
func (s *TCPNameServer) Cleanup() error {
|
||||||
|
now := time.Now()
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
|
if len(s.ips) == 0 {
|
||||||
|
return newError("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 {
|
||||||
|
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog()
|
||||||
|
|
||||||
|
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))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||||
errors.LogDebug(ctx, s.Name(), " querying DNS for: ", domain)
|
newError(s.name, " querying DNS for: ", domain).AtDebug().WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
|
||||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
@@ -130,37 +214,24 @@ 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")
|
newError("failed to pack dns query").Base(err).AtError().WriteToLog()
|
||||||
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")
|
newError("failed to dial namesever").Base(err).AtError().WriteToLog()
|
||||||
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")
|
|
||||||
noResponseErrCh <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = dnsReqBuf.Write(b.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "buffer write failed")
|
|
||||||
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")
|
newError("failed to send query").Base(err).AtError().WriteToLog()
|
||||||
noResponseErrCh <- err
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dnsReqBuf.Release()
|
dnsReqBuf.Release()
|
||||||
@@ -169,81 +240,123 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- er
|
|||||||
defer respBuf.Release()
|
defer respBuf.Release()
|
||||||
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")
|
newError("failed to read response length").Base(err).AtError().WriteToLog()
|
||||||
noResponseErrCh <- err
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var length int16
|
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")
|
newError("failed to parse response length").Base(err).AtError().WriteToLog()
|
||||||
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")
|
newError("failed to read response length").Base(err).AtError().WriteToLog()
|
||||||
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")
|
newError("failed to parse DNS over TCP response").Base(err).AtError().WriteToLog()
|
||||||
noResponseErrCh <- err
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cacheController.updateIP(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()
|
||||||
fqdn := Fqdn(domain)
|
record, found := s.ips[domain]
|
||||||
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
s.RUnlock()
|
||||||
defer closeSubscribers(sub4, sub6)
|
|
||||||
|
|
||||||
if s.cacheController.disableCache {
|
if !found {
|
||||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
return nil, errRecordNotFound
|
||||||
} else {
|
|
||||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
|
||||||
if !go_errors.Is(err, errRecordNotFound) {
|
|
||||||
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, ttl, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
noResponseErrCh := make(chan error, 2)
|
var err4 error
|
||||||
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
var err6 error
|
||||||
start := time.Now()
|
var ips []net.Address
|
||||||
|
var ip6 []net.Address
|
||||||
|
|
||||||
if sub4 != nil {
|
if option.IPv4Enable {
|
||||||
select {
|
ips, err4 = record.A.getIPs()
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, 0, ctx.Err()
|
|
||||||
case err := <-noResponseErrCh:
|
|
||||||
return nil, 0, err
|
|
||||||
case <-sub4.Wait():
|
|
||||||
sub4.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sub6 != nil {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, 0, ctx.Err()
|
|
||||||
case err := <-noResponseErrCh:
|
|
||||||
return nil, 0, err
|
|
||||||
case <-sub6.Wait():
|
|
||||||
sub6.Close()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
if option.IPv6Enable {
|
||||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
ip6, err6 = record.AAAA.getIPs()
|
||||||
return ips, ttl, err
|
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)
|
||||||
|
|
||||||
|
if disableCache {
|
||||||
|
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||||
|
} else {
|
||||||
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
|
if err != errRecordNotFound {
|
||||||
|
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||||
|
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)
|
||||||
|
|
||||||
|
for {
|
||||||
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
|
if err != errRecordNotFound {
|
||||||
|
return ips, err
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
. "github.com/xtls/xray-core/app/dns"
|
. "github.com/xtls/xray-core/app/dns"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
@@ -16,13 +17,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, net.IP(nil))
|
s, err := NewTCPLocalNameServer(url)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", 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 +34,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, net.IP(nil))
|
s, err := NewTCPLocalNameServer(url)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", 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,61 +48,13 @@ 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 != "" {
|
||||||
t.Fatal(r)
|
t.Fatal(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTCPLocalNameServerWithIPv4Override(t *testing.T) {
|
|
||||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
|
||||||
common.Must(err)
|
|
||||||
s, err := NewTCPLocalNameServer(url, false, net.IP(nil))
|
|
||||||
common.Must(err)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: false,
|
|
||||||
})
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ip := range ips {
|
|
||||||
if len(ip) != net.IPv4len {
|
|
||||||
t.Error("expect only IPv4 response from DNS query")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTCPLocalNameServerWithIPv6Override(t *testing.T) {
|
|
||||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
|
||||||
common.Must(err)
|
|
||||||
s, err := NewTCPLocalNameServer(url, false, net.IP(nil))
|
|
||||||
common.Must(err)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
|
||||||
IPv4Enable: false,
|
|
||||||
IPv6Enable: true,
|
|
||||||
})
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ip := range ips {
|
|
||||||
if len(ip) != net.IPv6len {
|
|
||||||
t.Error("expect only IPv6 response from DNS query")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,77 +2,95 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
go_errors "errors"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/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"
|
||||||
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/session"
|
||||||
|
"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"
|
||||||
"github.com/xtls/xray-core/transport/internet/udp"
|
"github.com/xtls/xray-core/transport/internet/udp"
|
||||||
"golang.org/x/net/dns/dnsmessage"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ClassicNameServer implemented traditional UDP DNS.
|
// ClassicNameServer implemented traditional UDP DNS.
|
||||||
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
|
||||||
|
|
||||||
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, clientIP net.IP) *ClassicNameServer {
|
func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher) *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),
|
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()),
|
||||||
}
|
}
|
||||||
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())
|
newError("DNS: created UDP client initialized for ", address.NetAddr()).AtInfo().WriteToLog()
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestsCleanup clears expired items from cache
|
// Cleanup clears expired items from cache
|
||||||
func (s *ClassicNameServer) RequestsCleanup() error {
|
func (s *ClassicNameServer) Cleanup() 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 newError(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 {
|
||||||
|
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog()
|
||||||
|
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 {
|
||||||
@@ -82,7 +100,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
|
||||||
@@ -92,7 +110,7 @@ func (s *ClassicNameServer) RequestsCleanup() error {
|
|||||||
func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_proto.Packet) {
|
func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_proto.Packet) {
|
||||||
ipRec, err := parseResponse(packet.Payload.Bytes())
|
ipRec, err := parseResponse(packet.Payload.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogError(ctx, s.Name(), " fail to parse responded DNS udp")
|
newError(s.name, " fail to parse responded DNS udp").AtError().WriteToLog()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,107 +123,189 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
|||||||
}
|
}
|
||||||
s.Unlock()
|
s.Unlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
errors.LogError(ctx, s.Name(), " cannot find the pending request")
|
newError(s.name, " cannot find the pending request").AtError().WriteToLog()
|
||||||
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)
|
|
||||||
s.udpServer.Dispatch(toDnsContext(newReq.ctx, s.address.String()), *s.address, b)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cacheController.updateIP(&req.dnsRequest, ipRec)
|
elapsed := time.Since(req.start)
|
||||||
|
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog()
|
||||||
|
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 {
|
||||||
|
newError(s.name, " updating IP records for domain:", domain).AtDebug().WriteToLog()
|
||||||
|
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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ClassicNameServer) sendQuery(ctx context.Context, _ chan<- error, domain string, option dns_feature.IPOption) {
|
func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||||
errors.LogDebug(ctx, s.Name(), " querying DNS for: ", domain)
|
newError(s.name, " querying DNS for: ", domain).AtDebug().WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
|
||||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||||
|
|
||||||
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)
|
||||||
s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b)
|
udpCtx := context.Background()
|
||||||
|
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||||
|
udpCtx = session.ContextWithInbound(udpCtx, inbound)
|
||||||
|
}
|
||||||
|
|
||||||
|
udpCtx = session.ContextWithContent(udpCtx, &session.Content{
|
||||||
|
Protocol: "dns",
|
||||||
|
})
|
||||||
|
udpCtx = log.ContextWithAccessMessage(udpCtx, &log.AccessMessage{
|
||||||
|
From: "DNS",
|
||||||
|
To: s.address,
|
||||||
|
Status: log.AccessAccepted,
|
||||||
|
Reason: "",
|
||||||
|
})
|
||||||
|
s.udpServer.Dispatch(udpCtx, *s.address, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ClassicNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||||
|
s.RLock()
|
||||||
|
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.
|
// QueryIP implements Server.
|
||||||
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
|
||||||
fqdn := Fqdn(domain)
|
fqdn := Fqdn(domain)
|
||||||
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
|
||||||
defer closeSubscribers(sub4, sub6)
|
|
||||||
|
|
||||||
if s.cacheController.disableCache {
|
if disableCache {
|
||||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||||
} else {
|
} else {
|
||||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
if !go_errors.Is(err, errRecordNotFound) {
|
if err != errRecordNotFound {
|
||||||
errors.LogDebugInner(ctx, err, s.Name(), " cache HIT ", domain, " -> ", ips)
|
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||||
return ips, ttl, err
|
return ips, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
noResponseErrCh := make(chan error, 2)
|
// ipv4 and ipv6 belong to different subscription groups
|
||||||
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
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()
|
start := time.Now()
|
||||||
|
|
||||||
if sub4 != nil {
|
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 {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil, 0, ctx.Err()
|
return nil, ctx.Err()
|
||||||
case err := <-noResponseErrCh:
|
case <-done:
|
||||||
return nil, 0, err
|
|
||||||
case <-sub4.Wait():
|
|
||||||
sub4.Close()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if sub6 != nil {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, 0, ctx.Err()
|
|
||||||
case err := <-noResponseErrCh:
|
|
||||||
return nil, 0, err
|
|
||||||
case <-sub6.Wait():
|
|
||||||
sub6.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
|
||||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
|
||||||
return ips, ttl, err
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/log"
|
"github.com/xtls/xray-core/app/log"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
grpc "google.golang.org/grpc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type LoggerServer struct {
|
type LoggerServer struct {
|
||||||
@@ -18,13 +20,13 @@ type LoggerServer struct {
|
|||||||
func (s *LoggerServer) RestartLogger(ctx context.Context, request *RestartLoggerRequest) (*RestartLoggerResponse, error) {
|
func (s *LoggerServer) RestartLogger(ctx context.Context, request *RestartLoggerRequest) (*RestartLoggerResponse, error) {
|
||||||
logger := s.V.GetFeature((*log.Instance)(nil))
|
logger := s.V.GetFeature((*log.Instance)(nil))
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
return nil, errors.New("unable to get logger instance")
|
return nil, newError("unable to get logger instance")
|
||||||
}
|
}
|
||||||
if err := logger.Close(); err != nil {
|
if err := logger.Close(); err != nil {
|
||||||
return nil, errors.New("failed to close logger").Base(err)
|
return nil, newError("failed to close logger").Base(err)
|
||||||
}
|
}
|
||||||
if err := logger.Start(); err != nil {
|
if err := logger.Start(); err != nil {
|
||||||
return nil, errors.New("failed to start logger").Base(err)
|
return nil, newError("failed to start logger").Base(err)
|
||||||
}
|
}
|
||||||
return &RestartLoggerResponse{}, nil
|
return &RestartLoggerResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.27.1
|
||||||
// protoc v5.28.2
|
// protoc v3.18.0
|
||||||
// source: app/log/command/config.proto
|
// source: app/log/command/config.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
@@ -28,9 +28,11 @@ type Config struct {
|
|||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
mi := &file_app_log_command_config_proto_msgTypes[0]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_log_command_config_proto_msgTypes[0]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) String() string {
|
func (x *Config) String() string {
|
||||||
@@ -41,7 +43,7 @@ func (*Config) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_log_command_config_proto_msgTypes[0]
|
mi := &file_app_log_command_config_proto_msgTypes[0]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -64,9 +66,11 @@ type RestartLoggerRequest struct {
|
|||||||
|
|
||||||
func (x *RestartLoggerRequest) Reset() {
|
func (x *RestartLoggerRequest) Reset() {
|
||||||
*x = RestartLoggerRequest{}
|
*x = RestartLoggerRequest{}
|
||||||
mi := &file_app_log_command_config_proto_msgTypes[1]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_log_command_config_proto_msgTypes[1]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RestartLoggerRequest) String() string {
|
func (x *RestartLoggerRequest) String() string {
|
||||||
@@ -77,7 +81,7 @@ func (*RestartLoggerRequest) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *RestartLoggerRequest) ProtoReflect() protoreflect.Message {
|
func (x *RestartLoggerRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_log_command_config_proto_msgTypes[1]
|
mi := &file_app_log_command_config_proto_msgTypes[1]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -100,9 +104,11 @@ type RestartLoggerResponse struct {
|
|||||||
|
|
||||||
func (x *RestartLoggerResponse) Reset() {
|
func (x *RestartLoggerResponse) Reset() {
|
||||||
*x = RestartLoggerResponse{}
|
*x = RestartLoggerResponse{}
|
||||||
mi := &file_app_log_command_config_proto_msgTypes[2]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_log_command_config_proto_msgTypes[2]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RestartLoggerResponse) String() string {
|
func (x *RestartLoggerResponse) String() string {
|
||||||
@@ -113,7 +119,7 @@ func (*RestartLoggerResponse) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *RestartLoggerResponse) ProtoReflect() protoreflect.Message {
|
func (x *RestartLoggerResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_log_command_config_proto_msgTypes[2]
|
mi := &file_app_log_command_config_proto_msgTypes[2]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -168,7 +174,7 @@ func file_app_log_command_config_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_app_log_command_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
var file_app_log_command_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||||
var file_app_log_command_config_proto_goTypes = []any{
|
var file_app_log_command_config_proto_goTypes = []interface{}{
|
||||||
(*Config)(nil), // 0: xray.app.log.command.Config
|
(*Config)(nil), // 0: xray.app.log.command.Config
|
||||||
(*RestartLoggerRequest)(nil), // 1: xray.app.log.command.RestartLoggerRequest
|
(*RestartLoggerRequest)(nil), // 1: xray.app.log.command.RestartLoggerRequest
|
||||||
(*RestartLoggerResponse)(nil), // 2: xray.app.log.command.RestartLoggerResponse
|
(*RestartLoggerResponse)(nil), // 2: xray.app.log.command.RestartLoggerResponse
|
||||||
@@ -188,6 +194,44 @@ func file_app_log_command_config_proto_init() {
|
|||||||
if File_app_log_command_config_proto != nil {
|
if File_app_log_command_config_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_app_log_command_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Config); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_log_command_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*RestartLoggerRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_log_command_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*RestartLoggerResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
// versions:
|
|
||||||
// - protoc-gen-go-grpc v1.5.1
|
|
||||||
// - protoc v5.28.2
|
|
||||||
// source: app/log/command/config.proto
|
|
||||||
|
|
||||||
package command
|
package command
|
||||||
|
|
||||||
@@ -15,12 +11,8 @@ import (
|
|||||||
|
|
||||||
// This is a compile-time assertion to ensure that this generated file
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
// is compatible with the grpc package it is being compiled against.
|
// is compatible with the grpc package it is being compiled against.
|
||||||
// Requires gRPC-Go v1.64.0 or later.
|
// Requires gRPC-Go v1.32.0 or later.
|
||||||
const _ = grpc.SupportPackageIsVersion9
|
const _ = grpc.SupportPackageIsVersion7
|
||||||
|
|
||||||
const (
|
|
||||||
LoggerService_RestartLogger_FullMethodName = "/xray.app.log.command.LoggerService/RestartLogger"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LoggerServiceClient is the client API for LoggerService service.
|
// LoggerServiceClient is the client API for LoggerService service.
|
||||||
//
|
//
|
||||||
@@ -38,9 +30,8 @@ func NewLoggerServiceClient(cc grpc.ClientConnInterface) LoggerServiceClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *loggerServiceClient) RestartLogger(ctx context.Context, in *RestartLoggerRequest, opts ...grpc.CallOption) (*RestartLoggerResponse, error) {
|
func (c *loggerServiceClient) RestartLogger(ctx context.Context, in *RestartLoggerRequest, opts ...grpc.CallOption) (*RestartLoggerResponse, error) {
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(RestartLoggerResponse)
|
out := new(RestartLoggerResponse)
|
||||||
err := c.cc.Invoke(ctx, LoggerService_RestartLogger_FullMethodName, in, out, cOpts...)
|
err := c.cc.Invoke(ctx, "/xray.app.log.command.LoggerService/RestartLogger", in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -49,24 +40,20 @@ func (c *loggerServiceClient) RestartLogger(ctx context.Context, in *RestartLogg
|
|||||||
|
|
||||||
// LoggerServiceServer is the server API for LoggerService service.
|
// LoggerServiceServer is the server API for LoggerService service.
|
||||||
// All implementations must embed UnimplementedLoggerServiceServer
|
// All implementations must embed UnimplementedLoggerServiceServer
|
||||||
// for forward compatibility.
|
// for forward compatibility
|
||||||
type LoggerServiceServer interface {
|
type LoggerServiceServer interface {
|
||||||
RestartLogger(context.Context, *RestartLoggerRequest) (*RestartLoggerResponse, error)
|
RestartLogger(context.Context, *RestartLoggerRequest) (*RestartLoggerResponse, error)
|
||||||
mustEmbedUnimplementedLoggerServiceServer()
|
mustEmbedUnimplementedLoggerServiceServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnimplementedLoggerServiceServer must be embedded to have
|
// UnimplementedLoggerServiceServer must be embedded to have forward compatible implementations.
|
||||||
// forward compatible implementations.
|
type UnimplementedLoggerServiceServer struct {
|
||||||
//
|
}
|
||||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
|
||||||
// pointer dereference when methods are called.
|
|
||||||
type UnimplementedLoggerServiceServer struct{}
|
|
||||||
|
|
||||||
func (UnimplementedLoggerServiceServer) RestartLogger(context.Context, *RestartLoggerRequest) (*RestartLoggerResponse, error) {
|
func (UnimplementedLoggerServiceServer) RestartLogger(context.Context, *RestartLoggerRequest) (*RestartLoggerResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method RestartLogger not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method RestartLogger not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedLoggerServiceServer) mustEmbedUnimplementedLoggerServiceServer() {}
|
func (UnimplementedLoggerServiceServer) mustEmbedUnimplementedLoggerServiceServer() {}
|
||||||
func (UnimplementedLoggerServiceServer) testEmbeddedByValue() {}
|
|
||||||
|
|
||||||
// UnsafeLoggerServiceServer may be embedded to opt out of forward compatibility for this service.
|
// UnsafeLoggerServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
// Use of this interface is not recommended, as added methods to LoggerServiceServer will
|
// Use of this interface is not recommended, as added methods to LoggerServiceServer will
|
||||||
@@ -76,13 +63,6 @@ type UnsafeLoggerServiceServer interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RegisterLoggerServiceServer(s grpc.ServiceRegistrar, srv LoggerServiceServer) {
|
func RegisterLoggerServiceServer(s grpc.ServiceRegistrar, srv LoggerServiceServer) {
|
||||||
// If the following call pancis, it indicates UnimplementedLoggerServiceServer was
|
|
||||||
// embedded by pointer and is nil. This will cause panics if an
|
|
||||||
// unimplemented method is ever invoked, so we test this at initialization
|
|
||||||
// time to prevent it from happening at runtime later due to I/O.
|
|
||||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
|
||||||
t.testEmbeddedByValue()
|
|
||||||
}
|
|
||||||
s.RegisterService(&LoggerService_ServiceDesc, srv)
|
s.RegisterService(&LoggerService_ServiceDesc, srv)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +76,7 @@ func _LoggerService_RestartLogger_Handler(srv interface{}, ctx context.Context,
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: LoggerService_RestartLogger_FullMethodName,
|
FullMethod: "/xray.app.log.command.LoggerService/RestartLogger",
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(LoggerServiceServer).RestartLogger(ctx, req.(*RestartLoggerRequest))
|
return srv.(LoggerServiceServer).RestartLogger(ctx, req.(*RestartLoggerRequest))
|
||||||
|
|||||||
9
app/log/command/errors.generated.go
Normal file
9
app/log/command/errors.generated.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import "github.com/xtls/xray-core/common/errors"
|
||||||
|
|
||||||
|
type errPathObjHolder struct{}
|
||||||
|
|
||||||
|
func newError(values ...interface{}) *errors.Error {
|
||||||
|
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.27.1
|
||||||
// protoc v5.28.2
|
// protoc v3.18.0
|
||||||
// source: app/log/config.proto
|
// source: app/log/config.proto
|
||||||
|
|
||||||
package log
|
package log
|
||||||
@@ -84,14 +84,15 @@ type Config struct {
|
|||||||
AccessLogType LogType `protobuf:"varint,4,opt,name=access_log_type,json=accessLogType,proto3,enum=xray.app.log.LogType" json:"access_log_type,omitempty"`
|
AccessLogType LogType `protobuf:"varint,4,opt,name=access_log_type,json=accessLogType,proto3,enum=xray.app.log.LogType" json:"access_log_type,omitempty"`
|
||||||
AccessLogPath string `protobuf:"bytes,5,opt,name=access_log_path,json=accessLogPath,proto3" json:"access_log_path,omitempty"`
|
AccessLogPath string `protobuf:"bytes,5,opt,name=access_log_path,json=accessLogPath,proto3" json:"access_log_path,omitempty"`
|
||||||
EnableDnsLog bool `protobuf:"varint,6,opt,name=enable_dns_log,json=enableDnsLog,proto3" json:"enable_dns_log,omitempty"`
|
EnableDnsLog bool `protobuf:"varint,6,opt,name=enable_dns_log,json=enableDnsLog,proto3" json:"enable_dns_log,omitempty"`
|
||||||
MaskAddress string `protobuf:"bytes,7,opt,name=mask_address,json=maskAddress,proto3" json:"mask_address,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
mi := &file_app_log_config_proto_msgTypes[0]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_log_config_proto_msgTypes[0]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) String() string {
|
func (x *Config) String() string {
|
||||||
@@ -102,7 +103,7 @@ func (*Config) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_log_config_proto_msgTypes[0]
|
mi := &file_app_log_config_proto_msgTypes[0]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -159,20 +160,13 @@ func (x *Config) GetEnableDnsLog() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetMaskAddress() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.MaskAddress
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_app_log_config_proto protoreflect.FileDescriptor
|
var File_app_log_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_app_log_config_proto_rawDesc = []byte{
|
var file_app_log_config_proto_rawDesc = []byte{
|
||||||
0x0a, 0x14, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
0x0a, 0x14, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
0x2e, 0x6c, 0x6f, 0x67, 0x1a, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6c, 0x6f, 0x67,
|
0x2e, 0x6c, 0x6f, 0x67, 0x1a, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6c, 0x6f, 0x67,
|
||||||
0x2f, 0x6c, 0x6f, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xde, 0x02, 0x0a, 0x06, 0x43,
|
0x2f, 0x6c, 0x6f, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xbb, 0x02, 0x0a, 0x06, 0x43,
|
||||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3b, 0x0a, 0x0e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6c,
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3b, 0x0a, 0x0e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6c,
|
||||||
0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e,
|
0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e,
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x4c, 0x6f, 0x67,
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x4c, 0x6f, 0x67,
|
||||||
@@ -192,18 +186,15 @@ var file_app_log_config_proto_rawDesc = []byte{
|
|||||||
0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x50, 0x61,
|
0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x50, 0x61,
|
||||||
0x74, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x6e, 0x73,
|
0x74, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x6e, 0x73,
|
||||||
0x5f, 0x6c, 0x6f, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x65, 0x6e, 0x61, 0x62,
|
0x5f, 0x6c, 0x6f, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x65, 0x6e, 0x61, 0x62,
|
||||||
0x6c, 0x65, 0x44, 0x6e, 0x73, 0x4c, 0x6f, 0x67, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x73, 0x6b,
|
0x6c, 0x65, 0x44, 0x6e, 0x73, 0x4c, 0x6f, 0x67, 0x2a, 0x35, 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x54,
|
||||||
0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
|
0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00, 0x12, 0x0b, 0x0a,
|
||||||
0x6d, 0x61, 0x73, 0x6b, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2a, 0x35, 0x0a, 0x07, 0x4c,
|
0x07, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x69,
|
||||||
0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00,
|
0x6c, 0x65, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x10, 0x03, 0x42,
|
||||||
0x12, 0x0b, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x10, 0x01, 0x12, 0x08, 0x0a,
|
0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||||
0x04, 0x46, 0x69, 0x6c, 0x65, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74,
|
0x6c, 0x6f, 0x67, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||||
0x10, 0x03, 0x42, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
|
0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65,
|
||||||
0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0xaa, 0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63,
|
0x41, 0x70, 0x70, 0x2e, 0x4c, 0x6f, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0xaa, 0x02, 0x0c, 0x58, 0x72,
|
|
||||||
0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4c, 0x6f, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
|
||||||
0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -220,7 +211,7 @@ func file_app_log_config_proto_rawDescGZIP() []byte {
|
|||||||
|
|
||||||
var file_app_log_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
var file_app_log_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
var file_app_log_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
var file_app_log_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||||
var file_app_log_config_proto_goTypes = []any{
|
var file_app_log_config_proto_goTypes = []interface{}{
|
||||||
(LogType)(0), // 0: xray.app.log.LogType
|
(LogType)(0), // 0: xray.app.log.LogType
|
||||||
(*Config)(nil), // 1: xray.app.log.Config
|
(*Config)(nil), // 1: xray.app.log.Config
|
||||||
(log.Severity)(0), // 2: xray.common.log.Severity
|
(log.Severity)(0), // 2: xray.common.log.Severity
|
||||||
@@ -241,6 +232,20 @@ func file_app_log_config_proto_init() {
|
|||||||
if File_app_log_config_proto != nil {
|
if File_app_log_config_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_app_log_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Config); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
|
|||||||
@@ -23,5 +23,4 @@ message Config {
|
|||||||
LogType access_log_type = 4;
|
LogType access_log_type = 4;
|
||||||
string access_log_path = 5;
|
string access_log_path = 5;
|
||||||
bool enable_dns_log = 6;
|
bool enable_dns_log = 6;
|
||||||
string mask_address= 7;
|
|
||||||
}
|
}
|
||||||
|
|||||||
9
app/log/errors.generated.go
Normal file
9
app/log/errors.generated.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import "github.com/xtls/xray-core/common/errors"
|
||||||
|
|
||||||
|
type errPathObjHolder struct{}
|
||||||
|
|
||||||
|
func newError(values ...interface{}) *errors.Error {
|
||||||
|
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||||
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
package log
|
package log
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"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/log"
|
"github.com/xtls/xray-core/common/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,13 +29,13 @@ func New(ctx context.Context, config *Config) (*Instance, error) {
|
|||||||
}
|
}
|
||||||
log.RegisterHandler(g)
|
log.RegisterHandler(g)
|
||||||
|
|
||||||
// start logger now,
|
// start logger instantly on inited
|
||||||
// then other modules will be able to log during initialization
|
// other modules would log during init
|
||||||
if err := g.startInternal(); err != nil {
|
if err := g.startInternal(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogDebug(ctx, "Logger started")
|
newError("Logger started").AtDebug().WriteToLog()
|
||||||
return g, nil
|
return g, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,10 +77,10 @@ func (g *Instance) startInternal() error {
|
|||||||
g.active = true
|
g.active = true
|
||||||
|
|
||||||
if err := g.initAccessLogger(); err != nil {
|
if err := g.initAccessLogger(); err != nil {
|
||||||
return errors.New("failed to initialize access logger").Base(err).AtWarning()
|
return newError("failed to initialize access logger").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
if err := g.initErrorLogger(); err != nil {
|
if err := g.initErrorLogger(); err != nil {
|
||||||
return errors.New("failed to initialize error logger").Base(err).AtWarning()
|
return newError("failed to initialize error logger").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -102,25 +100,18 @@ func (g *Instance) Handle(msg log.Message) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var Msg log.Message
|
|
||||||
if g.config.MaskAddress != "" {
|
|
||||||
Msg = &MaskedMsgWrapper{Message: msg, config: g.config}
|
|
||||||
} else {
|
|
||||||
Msg = msg
|
|
||||||
}
|
|
||||||
|
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case *log.AccessMessage:
|
case *log.AccessMessage:
|
||||||
if g.accessLogger != nil {
|
if g.accessLogger != nil {
|
||||||
g.accessLogger.Handle(Msg)
|
g.accessLogger.Handle(msg)
|
||||||
}
|
}
|
||||||
case *log.DNSLog:
|
case *log.DNSLog:
|
||||||
if g.dns && g.accessLogger != nil {
|
if g.dns && g.accessLogger != nil {
|
||||||
g.accessLogger.Handle(Msg)
|
g.accessLogger.Handle(msg)
|
||||||
}
|
}
|
||||||
case *log.GeneralMessage:
|
case *log.GeneralMessage:
|
||||||
if g.errorLogger != nil && msg.Severity <= g.config.ErrorLogLevel {
|
if g.errorLogger != nil && msg.Severity <= g.config.ErrorLogLevel {
|
||||||
g.errorLogger.Handle(Msg)
|
g.errorLogger.Handle(msg)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// Swallow
|
// Swallow
|
||||||
@@ -129,7 +120,7 @@ func (g *Instance) Handle(msg log.Message) {
|
|||||||
|
|
||||||
// Close implements common.Closable.Close().
|
// Close implements common.Closable.Close().
|
||||||
func (g *Instance) Close() error {
|
func (g *Instance) Close() error {
|
||||||
errors.LogDebug(context.Background(), "Logger closing")
|
newError("Logger closing").AtDebug().WriteToLog()
|
||||||
|
|
||||||
g.Lock()
|
g.Lock()
|
||||||
defer g.Unlock()
|
defer g.Unlock()
|
||||||
@@ -149,56 +140,6 @@ func (g *Instance) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MaskedMsgWrapper is to wrap the string() method to mask IP addresses in the log.
|
|
||||||
type MaskedMsgWrapper struct {
|
|
||||||
log.Message
|
|
||||||
config *Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MaskedMsgWrapper) String() string {
|
|
||||||
str := m.Message.String()
|
|
||||||
|
|
||||||
ipv4Regex := regexp.MustCompile(`(\d{1,3}\.){3}\d{1,3}`)
|
|
||||||
ipv6Regex := regexp.MustCompile(`((?:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}){2,7})(?:[\/\\%](\d{1,3}))?`)
|
|
||||||
|
|
||||||
// Process ipv4
|
|
||||||
maskedMsg := ipv4Regex.ReplaceAllStringFunc(str, func(ip string) string {
|
|
||||||
parts := strings.Split(ip, ".")
|
|
||||||
switch m.config.MaskAddress {
|
|
||||||
case "half":
|
|
||||||
return fmt.Sprintf("%s.%s.*.*", parts[0], parts[1])
|
|
||||||
case "quarter":
|
|
||||||
return fmt.Sprintf("%s.*.*.*", parts[0])
|
|
||||||
case "full":
|
|
||||||
return "[Masked IPv4]"
|
|
||||||
default:
|
|
||||||
return ip
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// process ipv6
|
|
||||||
maskedMsg = ipv6Regex.ReplaceAllStringFunc(maskedMsg, func(ip string) string {
|
|
||||||
parts := strings.Split(ip, ":")
|
|
||||||
switch m.config.MaskAddress {
|
|
||||||
case "half":
|
|
||||||
if len(parts) >= 2 {
|
|
||||||
return fmt.Sprintf("%s:%s::/32", parts[0], parts[1])
|
|
||||||
}
|
|
||||||
case "quarter":
|
|
||||||
if len(parts) >= 1 {
|
|
||||||
return fmt.Sprintf("%s::/16", parts[0])
|
|
||||||
}
|
|
||||||
case "full":
|
|
||||||
return "Masked IPv6" // Do not use [Masked IPv6] like ipv4, or you will get "[[Masked IPv6]]" (v6 address already has [])
|
|
||||||
default:
|
|
||||||
return ip
|
|
||||||
}
|
|
||||||
return ip
|
|
||||||
})
|
|
||||||
|
|
||||||
return maskedMsg
|
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ package log
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"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/log"
|
"github.com/xtls/xray-core/common/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,7 +19,7 @@ var handlerCreatorMapLock = &sync.RWMutex{}
|
|||||||
|
|
||||||
func RegisterHandlerCreator(logType LogType, f HandlerCreator) error {
|
func RegisterHandlerCreator(logType LogType, f HandlerCreator) error {
|
||||||
if f == nil {
|
if f == nil {
|
||||||
return errors.New("nil HandlerCreator")
|
return newError("nil HandlerCreator")
|
||||||
}
|
}
|
||||||
|
|
||||||
handlerCreatorMapLock.Lock()
|
handlerCreatorMapLock.Lock()
|
||||||
@@ -36,7 +35,7 @@ func createHandler(logType LogType, options HandlerCreatorOptions) (log.Handler,
|
|||||||
|
|
||||||
creator, found := handlerCreatorMap[logType]
|
creator, found := handlerCreatorMap[logType]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, errors.New("unable to create log handler for ", logType)
|
return nil, newError("unable to create log handler for ", logType)
|
||||||
}
|
}
|
||||||
return creator(logType, options)
|
return creator(logType, options)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/log"
|
"github.com/xtls/xray-core/app/log"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
clog "github.com/xtls/xray-core/common/log"
|
clog "github.com/xtls/xray-core/common/log"
|
||||||
|
|||||||
@@ -1,142 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.35.1
|
|
||||||
// protoc v5.28.2
|
|
||||||
// source: app/metrics/config.proto
|
|
||||||
|
|
||||||
package metrics
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Config is the settings for metrics.
|
|
||||||
type Config struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
// Tag of the outbound handler that handles metrics http connections.
|
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
Listen string `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
|
||||||
*x = Config{}
|
|
||||||
mi := &file_app_metrics_config_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Config) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_metrics_config_proto_msgTypes[0]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Config) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_metrics_config_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetTag() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Tag
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetListen() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Listen
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_app_metrics_config_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_app_metrics_config_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x18, 0x61, 0x70, 0x70, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x63, 0x6f,
|
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61, 0x79,
|
|
||||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x32, 0x0a, 0x06,
|
|
||||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20,
|
|
||||||
0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74,
|
|
||||||
0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e,
|
|
||||||
0x42, 0x52, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
|
||||||
0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68,
|
|
||||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
|
||||||
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
|
|
||||||
0x73, 0xaa, 0x02, 0x10, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4d, 0x65, 0x74,
|
|
||||||
0x72, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_app_metrics_config_proto_rawDescOnce sync.Once
|
|
||||||
file_app_metrics_config_proto_rawDescData = file_app_metrics_config_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_app_metrics_config_proto_rawDescGZIP() []byte {
|
|
||||||
file_app_metrics_config_proto_rawDescOnce.Do(func() {
|
|
||||||
file_app_metrics_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_metrics_config_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_app_metrics_config_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_app_metrics_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
|
||||||
var file_app_metrics_config_proto_goTypes = []any{
|
|
||||||
(*Config)(nil), // 0: xray.app.metrics.Config
|
|
||||||
}
|
|
||||||
var file_app_metrics_config_proto_depIdxs = []int32{
|
|
||||||
0, // [0:0] is the sub-list for method output_type
|
|
||||||
0, // [0:0] is the sub-list for method input_type
|
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
|
||||||
0, // [0:0] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_app_metrics_config_proto_init() }
|
|
||||||
func file_app_metrics_config_proto_init() {
|
|
||||||
if File_app_metrics_config_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_app_metrics_config_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 1,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_app_metrics_config_proto_goTypes,
|
|
||||||
DependencyIndexes: file_app_metrics_config_proto_depIdxs,
|
|
||||||
MessageInfos: file_app_metrics_config_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_app_metrics_config_proto = out.File
|
|
||||||
file_app_metrics_config_proto_rawDesc = nil
|
|
||||||
file_app_metrics_config_proto_goTypes = nil
|
|
||||||
file_app_metrics_config_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package xray.app.metrics;
|
|
||||||
option csharp_namespace = "Xray.App.Metrics";
|
|
||||||
option go_package = "github.com/xtls/xray-core/app/metrics";
|
|
||||||
option java_package = "com.xray.app.metrics";
|
|
||||||
option java_multiple_files = true;
|
|
||||||
|
|
||||||
// Config is the settings for metrics.
|
|
||||||
message Config {
|
|
||||||
// Tag of the outbound handler that handles metrics http connections.
|
|
||||||
string tag = 1;
|
|
||||||
string listen = 2;
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
package metrics
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"expvar"
|
|
||||||
"net/http"
|
|
||||||
_ "net/http/pprof"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/observatory"
|
|
||||||
"github.com/xtls/xray-core/app/stats"
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/common/signal/done"
|
|
||||||
"github.com/xtls/xray-core/core"
|
|
||||||
"github.com/xtls/xray-core/features/extension"
|
|
||||||
"github.com/xtls/xray-core/features/outbound"
|
|
||||||
feature_stats "github.com/xtls/xray-core/features/stats"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MetricsHandler struct {
|
|
||||||
ohm outbound.Manager
|
|
||||||
statsManager feature_stats.Manager
|
|
||||||
observatory extension.Observatory
|
|
||||||
tag string
|
|
||||||
listen string
|
|
||||||
tcpListener net.Listener
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMetricsHandler creates a new MetricsHandler based on the given config.
|
|
||||||
func NewMetricsHandler(ctx context.Context, config *Config) (*MetricsHandler, error) {
|
|
||||||
c := &MetricsHandler{
|
|
||||||
tag: config.Tag,
|
|
||||||
listen: config.Listen,
|
|
||||||
}
|
|
||||||
common.Must(core.RequireFeatures(ctx, func(om outbound.Manager, sm feature_stats.Manager) {
|
|
||||||
c.statsManager = sm
|
|
||||||
c.ohm = om
|
|
||||||
}))
|
|
||||||
expvar.Publish("stats", expvar.Func(func() interface{} {
|
|
||||||
manager, ok := c.statsManager.(*stats.Manager)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
resp := map[string]map[string]map[string]int64{
|
|
||||||
"inbound": {},
|
|
||||||
"outbound": {},
|
|
||||||
"user": {},
|
|
||||||
}
|
|
||||||
manager.VisitCounters(func(name string, counter feature_stats.Counter) bool {
|
|
||||||
nameSplit := strings.Split(name, ">>>")
|
|
||||||
typeName, tagOrUser, direction := nameSplit[0], nameSplit[1], nameSplit[3]
|
|
||||||
if item, found := resp[typeName][tagOrUser]; found {
|
|
||||||
item[direction] = counter.Value()
|
|
||||||
} else {
|
|
||||||
resp[typeName][tagOrUser] = map[string]int64{
|
|
||||||
direction: counter.Value(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return resp
|
|
||||||
}))
|
|
||||||
expvar.Publish("observatory", expvar.Func(func() interface{} {
|
|
||||||
if c.observatory == nil {
|
|
||||||
common.Must(core.RequireFeatures(ctx, func(observatory extension.Observatory) error {
|
|
||||||
c.observatory = observatory
|
|
||||||
return nil
|
|
||||||
}))
|
|
||||||
if c.observatory == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resp := map[string]*observatory.OutboundStatus{}
|
|
||||||
if o, err := c.observatory.GetObservation(context.Background()); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
for _, x := range o.(*observatory.ObservationResult).GetStatus() {
|
|
||||||
resp[x.OutboundTag] = x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resp
|
|
||||||
}))
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MetricsHandler) Type() interface{} {
|
|
||||||
return (*MetricsHandler)(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MetricsHandler) Start() error {
|
|
||||||
|
|
||||||
// direct listen a port if listen is set
|
|
||||||
if p.listen != "" {
|
|
||||||
TCPlistener, err := net.Listen("tcp", p.listen)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
p.tcpListener = TCPlistener
|
|
||||||
errors.LogInfo(context.Background(), "Metrics server listening on ", p.listen)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if err := http.Serve(TCPlistener, http.DefaultServeMux); err != nil {
|
|
||||||
errors.LogErrorInner(context.Background(), err, "failed to start metrics server")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
listener := &OutboundListener{
|
|
||||||
buffer: make(chan net.Conn, 4),
|
|
||||||
done: done.New(),
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if err := http.Serve(listener, http.DefaultServeMux); err != nil {
|
|
||||||
errors.LogErrorInner(context.Background(), err, "failed to start metrics server")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := p.ohm.RemoveHandler(context.Background(), p.tag); err != nil {
|
|
||||||
errors.LogInfo(context.Background(), "failed to remove existing handler")
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.ohm.AddHandler(context.Background(), &Outbound{
|
|
||||||
tag: p.tag,
|
|
||||||
listener: listener,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MetricsHandler) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
|
|
||||||
return NewMetricsHandler(ctx, cfg.(*Config))
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
package metrics
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/common/net/cnc"
|
|
||||||
"github.com/xtls/xray-core/common/serial"
|
|
||||||
"github.com/xtls/xray-core/common/signal/done"
|
|
||||||
"github.com/xtls/xray-core/transport"
|
|
||||||
)
|
|
||||||
|
|
||||||
// OutboundListener is a net.Listener for listening metrics http connections.
|
|
||||||
type OutboundListener struct {
|
|
||||||
buffer chan net.Conn
|
|
||||||
done *done.Instance
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *OutboundListener) add(conn net.Conn) {
|
|
||||||
select {
|
|
||||||
case l.buffer <- conn:
|
|
||||||
case <-l.done.Wait():
|
|
||||||
conn.Close()
|
|
||||||
default:
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept implements net.Listener.
|
|
||||||
func (l *OutboundListener) Accept() (net.Conn, error) {
|
|
||||||
select {
|
|
||||||
case <-l.done.Wait():
|
|
||||||
return nil, errors.New("listen closed")
|
|
||||||
case c := <-l.buffer:
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close implement net.Listener.
|
|
||||||
func (l *OutboundListener) Close() error {
|
|
||||||
common.Must(l.done.Close())
|
|
||||||
L:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case c := <-l.buffer:
|
|
||||||
c.Close()
|
|
||||||
default:
|
|
||||||
break L
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Addr implements net.Listener.
|
|
||||||
func (l *OutboundListener) Addr() net.Addr {
|
|
||||||
return &net.TCPAddr{
|
|
||||||
IP: net.IP{0, 0, 0, 0},
|
|
||||||
Port: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Outbound is an outbound.Handler that handles metrics http connections.
|
|
||||||
type Outbound struct {
|
|
||||||
tag string
|
|
||||||
listener *OutboundListener
|
|
||||||
access sync.RWMutex
|
|
||||||
closed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispatch implements outbound.Handler.
|
|
||||||
func (co *Outbound) Dispatch(ctx context.Context, link *transport.Link) {
|
|
||||||
co.access.RLock()
|
|
||||||
|
|
||||||
if co.closed {
|
|
||||||
common.Interrupt(link.Reader)
|
|
||||||
common.Interrupt(link.Writer)
|
|
||||||
co.access.RUnlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
closeSignal := done.New()
|
|
||||||
c := cnc.NewConnection(cnc.ConnectionInputMulti(link.Writer), cnc.ConnectionOutputMulti(link.Reader), cnc.ConnectionOnClose(closeSignal))
|
|
||||||
co.listener.add(c)
|
|
||||||
co.access.RUnlock()
|
|
||||||
<-closeSignal.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tag implements outbound.Handler.
|
|
||||||
func (co *Outbound) Tag() string {
|
|
||||||
return co.tag
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start implements common.Runnable.
|
|
||||||
func (co *Outbound) Start() error {
|
|
||||||
co.access.Lock()
|
|
||||||
co.closed = false
|
|
||||||
co.access.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close implements common.Closable.
|
|
||||||
func (co *Outbound) Close() error {
|
|
||||||
co.access.Lock()
|
|
||||||
defer co.access.Unlock()
|
|
||||||
|
|
||||||
co.closed = true
|
|
||||||
return co.listener.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SenderSettings implements outbound.Handler.
|
|
||||||
func (co *Outbound) SenderSettings() *serial.TypedMessage {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProxySettings implements outbound.Handler.
|
|
||||||
func (co *Outbound) ProxySettings() *serial.TypedMessage {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package burst
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
rttFailed = time.Duration(math.MaxInt64 - iota)
|
|
||||||
rttUntested
|
|
||||||
rttUnqualified
|
|
||||||
)
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
package burst
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/observatory"
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/signal/done"
|
|
||||||
"github.com/xtls/xray-core/core"
|
|
||||||
"github.com/xtls/xray-core/features/extension"
|
|
||||||
"github.com/xtls/xray-core/features/outbound"
|
|
||||||
"github.com/xtls/xray-core/features/routing"
|
|
||||||
"google.golang.org/protobuf/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Observer struct {
|
|
||||||
config *Config
|
|
||||||
ctx context.Context
|
|
||||||
|
|
||||||
statusLock sync.Mutex
|
|
||||||
hp *HealthPing
|
|
||||||
|
|
||||||
finished *done.Instance
|
|
||||||
|
|
||||||
ohm outbound.Manager
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Observer) GetObservation(ctx context.Context) (proto.Message, error) {
|
|
||||||
return &observatory.ObservationResult{Status: o.createResult()}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Observer) createResult() []*observatory.OutboundStatus {
|
|
||||||
var result []*observatory.OutboundStatus
|
|
||||||
o.hp.access.Lock()
|
|
||||||
defer o.hp.access.Unlock()
|
|
||||||
for name, value := range o.hp.Results {
|
|
||||||
status := observatory.OutboundStatus{
|
|
||||||
Alive: value.getStatistics().All != value.getStatistics().Fail,
|
|
||||||
Delay: value.getStatistics().Average.Milliseconds(),
|
|
||||||
LastErrorReason: "",
|
|
||||||
OutboundTag: name,
|
|
||||||
LastSeenTime: 0,
|
|
||||||
LastTryTime: 0,
|
|
||||||
HealthPing: &observatory.HealthPingMeasurementResult{
|
|
||||||
All: int64(value.getStatistics().All),
|
|
||||||
Fail: int64(value.getStatistics().Fail),
|
|
||||||
Deviation: int64(value.getStatistics().Deviation),
|
|
||||||
Average: int64(value.getStatistics().Average),
|
|
||||||
Max: int64(value.getStatistics().Max),
|
|
||||||
Min: int64(value.getStatistics().Min),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
result = append(result, &status)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Observer) Type() interface{} {
|
|
||||||
return extension.ObservatoryType()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Observer) Start() error {
|
|
||||||
if o.config != nil && len(o.config.SubjectSelector) != 0 {
|
|
||||||
o.finished = done.New()
|
|
||||||
o.hp.StartScheduler(func() ([]string, error) {
|
|
||||||
hs, ok := o.ohm.(outbound.HandlerSelector)
|
|
||||||
if !ok {
|
|
||||||
|
|
||||||
return nil, errors.New("outbound.Manager is not a HandlerSelector")
|
|
||||||
}
|
|
||||||
|
|
||||||
outbounds := hs.Select(o.config.SubjectSelector)
|
|
||||||
return outbounds, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Observer) Close() error {
|
|
||||||
if o.finished != nil {
|
|
||||||
o.hp.StopScheduler()
|
|
||||||
return o.finished.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(ctx context.Context, config *Config) (*Observer, error) {
|
|
||||||
var outboundManager outbound.Manager
|
|
||||||
var dispatcher routing.Dispatcher
|
|
||||||
err := core.RequireFeatures(ctx, func(om outbound.Manager, rd routing.Dispatcher) {
|
|
||||||
outboundManager = om
|
|
||||||
dispatcher = rd
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("Cannot get depended features").Base(err)
|
|
||||||
}
|
|
||||||
hp := NewHealthPing(ctx, dispatcher, config.PingConfig)
|
|
||||||
return &Observer{
|
|
||||||
config: config,
|
|
||||||
ctx: ctx,
|
|
||||||
ohm: outboundManager,
|
|
||||||
hp: hp,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
|
||||||
return New(ctx, config.(*Config))
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
@@ -1,257 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.35.1
|
|
||||||
// protoc v5.28.2
|
|
||||||
// source: app/observatory/burst/config.proto
|
|
||||||
|
|
||||||
package burst
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
// @Document The selectors for outbound under observation
|
|
||||||
SubjectSelector []string `protobuf:"bytes,2,rep,name=subject_selector,json=subjectSelector,proto3" json:"subject_selector,omitempty"`
|
|
||||||
PingConfig *HealthPingConfig `protobuf:"bytes,3,opt,name=ping_config,json=pingConfig,proto3" json:"ping_config,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
|
||||||
*x = Config{}
|
|
||||||
mi := &file_app_observatory_burst_config_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Config) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_observatory_burst_config_proto_msgTypes[0]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Config) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_observatory_burst_config_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetSubjectSelector() []string {
|
|
||||||
if x != nil {
|
|
||||||
return x.SubjectSelector
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetPingConfig() *HealthPingConfig {
|
|
||||||
if x != nil {
|
|
||||||
return x.PingConfig
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type HealthPingConfig struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
// destination url, need 204 for success return
|
|
||||||
// default https://connectivitycheck.gstatic.com/generate_204
|
|
||||||
Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"`
|
|
||||||
// connectivity check url
|
|
||||||
Connectivity string `protobuf:"bytes,2,opt,name=connectivity,proto3" json:"connectivity,omitempty"`
|
|
||||||
// health check interval, int64 values of time.Duration
|
|
||||||
Interval int64 `protobuf:"varint,3,opt,name=interval,proto3" json:"interval,omitempty"`
|
|
||||||
// sampling count is the amount of recent ping results which are kept for calculation
|
|
||||||
SamplingCount int32 `protobuf:"varint,4,opt,name=samplingCount,proto3" json:"samplingCount,omitempty"`
|
|
||||||
// ping timeout, int64 values of time.Duration
|
|
||||||
Timeout int64 `protobuf:"varint,5,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
|
||||||
// http method to make request
|
|
||||||
HttpMethod string `protobuf:"bytes,6,opt,name=httpMethod,proto3" json:"httpMethod,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingConfig) Reset() {
|
|
||||||
*x = HealthPingConfig{}
|
|
||||||
mi := &file_app_observatory_burst_config_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingConfig) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*HealthPingConfig) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *HealthPingConfig) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_observatory_burst_config_proto_msgTypes[1]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use HealthPingConfig.ProtoReflect.Descriptor instead.
|
|
||||||
func (*HealthPingConfig) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_observatory_burst_config_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingConfig) GetDestination() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Destination
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingConfig) GetConnectivity() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Connectivity
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingConfig) GetInterval() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Interval
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingConfig) GetSamplingCount() int32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.SamplingCount
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingConfig) GetTimeout() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Timeout
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
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_rawDesc = []byte{
|
|
||||||
0x0a, 0x22, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
|
|
||||||
0x79, 0x2f, 0x62, 0x75, 0x72, 0x73, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70,
|
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1f, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
|
||||||
0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e,
|
|
||||||
0x62, 0x75, 0x72, 0x73, 0x74, 0x22, 0x87, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
|
||||||
0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65,
|
|
||||||
0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a,
|
|
||||||
0x65, 0x63, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x52, 0x0a, 0x0b, 0x70,
|
|
||||||
0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
|
|
||||||
0x32, 0x31, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
|
|
||||||
0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x62, 0x75, 0x72,
|
|
||||||
0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
|
|
||||||
0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22,
|
|
||||||
0xd4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
|
|
||||||
0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69,
|
|
||||||
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
|
||||||
0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f,
|
|
||||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e,
|
|
||||||
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x6e,
|
|
||||||
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x69,
|
|
||||||
0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73,
|
|
||||||
0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07,
|
|
||||||
0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74,
|
|
||||||
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x4d, 0x65,
|
|
||||||
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,
|
|
||||||
0x72, 0x79, 0x2e, 0x62, 0x75, 0x72, 0x73, 0x74, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68,
|
|
||||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
|
||||||
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76,
|
|
||||||
0x61, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x62, 0x75, 0x72, 0x73, 0x74, 0xaa, 0x02, 0x1a, 0x58, 0x72,
|
|
||||||
0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
|
|
||||||
0x72, 0x79, 0x2e, 0x42, 0x75, 0x72, 0x73, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_app_observatory_burst_config_proto_rawDescOnce sync.Once
|
|
||||||
file_app_observatory_burst_config_proto_rawDescData = file_app_observatory_burst_config_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_app_observatory_burst_config_proto_rawDescGZIP() []byte {
|
|
||||||
file_app_observatory_burst_config_proto_rawDescOnce.Do(func() {
|
|
||||||
file_app_observatory_burst_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_observatory_burst_config_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_app_observatory_burst_config_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_app_observatory_burst_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
|
||||||
var file_app_observatory_burst_config_proto_goTypes = []any{
|
|
||||||
(*Config)(nil), // 0: xray.core.app.observatory.burst.Config
|
|
||||||
(*HealthPingConfig)(nil), // 1: xray.core.app.observatory.burst.HealthPingConfig
|
|
||||||
}
|
|
||||||
var file_app_observatory_burst_config_proto_depIdxs = []int32{
|
|
||||||
1, // 0: xray.core.app.observatory.burst.Config.ping_config:type_name -> xray.core.app.observatory.burst.HealthPingConfig
|
|
||||||
1, // [1:1] is the sub-list for method output_type
|
|
||||||
1, // [1:1] is the sub-list for method input_type
|
|
||||||
1, // [1:1] is the sub-list for extension type_name
|
|
||||||
1, // [1:1] is the sub-list for extension extendee
|
|
||||||
0, // [0:1] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_app_observatory_burst_config_proto_init() }
|
|
||||||
func file_app_observatory_burst_config_proto_init() {
|
|
||||||
if File_app_observatory_burst_config_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_app_observatory_burst_config_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 2,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_app_observatory_burst_config_proto_goTypes,
|
|
||||||
DependencyIndexes: file_app_observatory_burst_config_proto_depIdxs,
|
|
||||||
MessageInfos: file_app_observatory_burst_config_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_app_observatory_burst_config_proto = out.File
|
|
||||||
file_app_observatory_burst_config_proto_rawDesc = nil
|
|
||||||
file_app_observatory_burst_config_proto_goTypes = nil
|
|
||||||
file_app_observatory_burst_config_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package xray.core.app.observatory.burst;
|
|
||||||
option csharp_namespace = "Xray.App.Observatory.Burst";
|
|
||||||
option go_package = "github.com/xtls/xray-core/app/observatory/burst";
|
|
||||||
option java_package = "com.xray.app.observatory.burst";
|
|
||||||
option java_multiple_files = true;
|
|
||||||
|
|
||||||
message Config {
|
|
||||||
/* @Document The selectors for outbound under observation
|
|
||||||
*/
|
|
||||||
repeated string subject_selector = 2;
|
|
||||||
|
|
||||||
HealthPingConfig ping_config = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message HealthPingConfig {
|
|
||||||
// destination url, need 204 for success return
|
|
||||||
// default https://connectivitycheck.gstatic.com/generate_204
|
|
||||||
string destination = 1;
|
|
||||||
// connectivity check url
|
|
||||||
string connectivity = 2;
|
|
||||||
// health check interval, int64 values of time.Duration
|
|
||||||
int64 interval = 3;
|
|
||||||
// sampling count is the amount of recent ping results which are kept for calculation
|
|
||||||
int32 samplingCount = 4;
|
|
||||||
// ping timeout, int64 values of time.Duration
|
|
||||||
int64 timeout = 5;
|
|
||||||
// http method to make request
|
|
||||||
string httpMethod = 6;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,268 +0,0 @@
|
|||||||
package burst
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/dice"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/features/routing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HealthPingSettings holds settings for health Checker
|
|
||||||
type HealthPingSettings struct {
|
|
||||||
Destination string `json:"destination"`
|
|
||||||
Connectivity string `json:"connectivity"`
|
|
||||||
Interval time.Duration `json:"interval"`
|
|
||||||
SamplingCount int `json:"sampling"`
|
|
||||||
Timeout time.Duration `json:"timeout"`
|
|
||||||
HttpMethod string `json:"httpMethod"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// HealthPing is the health checker for balancers
|
|
||||||
type HealthPing struct {
|
|
||||||
ctx context.Context
|
|
||||||
dispatcher routing.Dispatcher
|
|
||||||
access sync.Mutex
|
|
||||||
ticker *time.Ticker
|
|
||||||
tickerClose chan struct{}
|
|
||||||
|
|
||||||
Settings *HealthPingSettings
|
|
||||||
Results map[string]*HealthPingRTTS
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHealthPing creates a new HealthPing with settings
|
|
||||||
func NewHealthPing(ctx context.Context, dispatcher routing.Dispatcher, config *HealthPingConfig) *HealthPing {
|
|
||||||
settings := &HealthPingSettings{}
|
|
||||||
if config != nil {
|
|
||||||
|
|
||||||
var httpMethod string
|
|
||||||
if config.HttpMethod == "" {
|
|
||||||
httpMethod = "HEAD"
|
|
||||||
} else {
|
|
||||||
httpMethod = strings.TrimSpace(config.HttpMethod)
|
|
||||||
}
|
|
||||||
|
|
||||||
settings = &HealthPingSettings{
|
|
||||||
Connectivity: strings.TrimSpace(config.Connectivity),
|
|
||||||
Destination: strings.TrimSpace(config.Destination),
|
|
||||||
Interval: time.Duration(config.Interval),
|
|
||||||
SamplingCount: int(config.SamplingCount),
|
|
||||||
Timeout: time.Duration(config.Timeout),
|
|
||||||
HttpMethod: httpMethod,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if settings.Destination == "" {
|
|
||||||
// Destination URL, need 204 for success return default to chromium
|
|
||||||
// https://github.com/chromium/chromium/blob/main/components/safety_check/url_constants.cc#L10
|
|
||||||
// https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/safety_check/url_constants.cc#10
|
|
||||||
settings.Destination = "https://connectivitycheck.gstatic.com/generate_204"
|
|
||||||
}
|
|
||||||
if settings.Interval == 0 {
|
|
||||||
settings.Interval = time.Duration(1) * time.Minute
|
|
||||||
} else if settings.Interval < 10 {
|
|
||||||
errors.LogWarning(ctx, "health check interval is too small, 10s is applied")
|
|
||||||
settings.Interval = time.Duration(10) * time.Second
|
|
||||||
}
|
|
||||||
if settings.SamplingCount <= 0 {
|
|
||||||
settings.SamplingCount = 10
|
|
||||||
}
|
|
||||||
if settings.Timeout <= 0 {
|
|
||||||
// results are saved after all health pings finish,
|
|
||||||
// a larger timeout could possibly makes checks run longer
|
|
||||||
settings.Timeout = time.Duration(5) * time.Second
|
|
||||||
}
|
|
||||||
return &HealthPing{
|
|
||||||
ctx: ctx,
|
|
||||||
dispatcher: dispatcher,
|
|
||||||
Settings: settings,
|
|
||||||
Results: nil,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartScheduler implements the HealthChecker
|
|
||||||
func (h *HealthPing) StartScheduler(selector func() ([]string, error)) {
|
|
||||||
if h.ticker != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
interval := h.Settings.Interval * time.Duration(h.Settings.SamplingCount)
|
|
||||||
ticker := time.NewTicker(interval)
|
|
||||||
tickerClose := make(chan struct{})
|
|
||||||
h.ticker = ticker
|
|
||||||
h.tickerClose = tickerClose
|
|
||||||
go func() {
|
|
||||||
tags, err := selector()
|
|
||||||
if err != nil {
|
|
||||||
errors.LogWarning(h.ctx, "error select outbounds for initial health check: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
h.Check(tags)
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
go func() {
|
|
||||||
tags, err := selector()
|
|
||||||
if err != nil {
|
|
||||||
errors.LogWarning(h.ctx, "error select outbounds for scheduled health check: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
h.doCheck(tags, interval, h.Settings.SamplingCount)
|
|
||||||
h.Cleanup(tags)
|
|
||||||
}()
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
continue
|
|
||||||
case <-tickerClose:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// StopScheduler implements the HealthChecker
|
|
||||||
func (h *HealthPing) StopScheduler() {
|
|
||||||
if h.ticker == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
h.ticker.Stop()
|
|
||||||
h.ticker = nil
|
|
||||||
close(h.tickerClose)
|
|
||||||
h.tickerClose = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check implements the HealthChecker
|
|
||||||
func (h *HealthPing) Check(tags []string) error {
|
|
||||||
if len(tags) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
errors.LogInfo(h.ctx, "perform one-time health check for tags ", tags)
|
|
||||||
h.doCheck(tags, 0, 1)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type rtt struct {
|
|
||||||
handler string
|
|
||||||
value time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
// doCheck performs the 'rounds' amount checks in given 'duration'. You should make
|
|
||||||
// sure all tags are valid for current balancer
|
|
||||||
func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int) {
|
|
||||||
count := len(tags) * rounds
|
|
||||||
if count == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ch := make(chan *rtt, count)
|
|
||||||
|
|
||||||
for _, tag := range tags {
|
|
||||||
handler := tag
|
|
||||||
client := newPingClient(
|
|
||||||
h.ctx,
|
|
||||||
h.dispatcher,
|
|
||||||
h.Settings.Destination,
|
|
||||||
h.Settings.Timeout,
|
|
||||||
handler,
|
|
||||||
)
|
|
||||||
for i := 0; i < rounds; i++ {
|
|
||||||
delay := time.Duration(0)
|
|
||||||
if duration > 0 {
|
|
||||||
delay = time.Duration(dice.RollInt63n(int64(duration)))
|
|
||||||
}
|
|
||||||
time.AfterFunc(delay, func() {
|
|
||||||
errors.LogDebug(h.ctx, "checking ", handler)
|
|
||||||
delay, err := client.MeasureDelay(h.Settings.HttpMethod)
|
|
||||||
if err == nil {
|
|
||||||
ch <- &rtt{
|
|
||||||
handler: handler,
|
|
||||||
value: delay,
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !h.checkConnectivity() {
|
|
||||||
errors.LogWarning(h.ctx, "network is down")
|
|
||||||
ch <- &rtt{
|
|
||||||
handler: handler,
|
|
||||||
value: 0,
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
errors.LogWarning(h.ctx, fmt.Sprintf(
|
|
||||||
"error ping %s with %s: %s",
|
|
||||||
h.Settings.Destination,
|
|
||||||
handler,
|
|
||||||
err,
|
|
||||||
))
|
|
||||||
ch <- &rtt{
|
|
||||||
handler: handler,
|
|
||||||
value: rttFailed,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
rtt := <-ch
|
|
||||||
if rtt.value > 0 {
|
|
||||||
// should not put results when network is down
|
|
||||||
h.PutResult(rtt.handler, rtt.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PutResult put a ping rtt to results
|
|
||||||
func (h *HealthPing) PutResult(tag string, rtt time.Duration) {
|
|
||||||
h.access.Lock()
|
|
||||||
defer h.access.Unlock()
|
|
||||||
if h.Results == nil {
|
|
||||||
h.Results = make(map[string]*HealthPingRTTS)
|
|
||||||
}
|
|
||||||
r, ok := h.Results[tag]
|
|
||||||
if !ok {
|
|
||||||
// validity is 2 times to sampling period, since the check are
|
|
||||||
// distributed in the time line randomly, in extreme cases,
|
|
||||||
// Previous checks are distributed on the left, and later ones
|
|
||||||
// on the right
|
|
||||||
validity := h.Settings.Interval * time.Duration(h.Settings.SamplingCount) * 2
|
|
||||||
r = NewHealthPingResult(h.Settings.SamplingCount, validity)
|
|
||||||
h.Results[tag] = r
|
|
||||||
}
|
|
||||||
r.Put(rtt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup removes results of removed handlers,
|
|
||||||
// tags should be all valid tags of the Balancer now
|
|
||||||
func (h *HealthPing) Cleanup(tags []string) {
|
|
||||||
h.access.Lock()
|
|
||||||
defer h.access.Unlock()
|
|
||||||
for tag := range h.Results {
|
|
||||||
found := false
|
|
||||||
for _, v := range tags {
|
|
||||||
if tag == v {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
delete(h.Results, tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkConnectivity checks the network connectivity, it returns
|
|
||||||
// true if network is good or "connectivity check url" not set
|
|
||||||
func (h *HealthPing) checkConnectivity() bool {
|
|
||||||
if h.Settings.Connectivity == "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
tester := newDirectPingClient(
|
|
||||||
h.Settings.Connectivity,
|
|
||||||
h.Settings.Timeout,
|
|
||||||
)
|
|
||||||
if _, err := tester.MeasureDelay(h.Settings.HttpMethod); err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
package burst
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HealthPingStats is the statistics of HealthPingRTTS
|
|
||||||
type HealthPingStats struct {
|
|
||||||
All int
|
|
||||||
Fail int
|
|
||||||
Deviation time.Duration
|
|
||||||
Average time.Duration
|
|
||||||
Max time.Duration
|
|
||||||
Min time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
// HealthPingRTTS holds ping rtts for health Checker
|
|
||||||
type HealthPingRTTS struct {
|
|
||||||
idx int
|
|
||||||
cap int
|
|
||||||
validity time.Duration
|
|
||||||
rtts []*pingRTT
|
|
||||||
|
|
||||||
lastUpdateAt time.Time
|
|
||||||
stats *HealthPingStats
|
|
||||||
}
|
|
||||||
|
|
||||||
type pingRTT struct {
|
|
||||||
time time.Time
|
|
||||||
value time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHealthPingResult returns a *HealthPingResult with specified capacity
|
|
||||||
func NewHealthPingResult(cap int, validity time.Duration) *HealthPingRTTS {
|
|
||||||
return &HealthPingRTTS{cap: cap, validity: validity}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get gets statistics of the HealthPingRTTS
|
|
||||||
func (h *HealthPingRTTS) Get() *HealthPingStats {
|
|
||||||
return h.getStatistics()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWithCache get statistics and write cache for next call
|
|
||||||
// Make sure use Mutex.Lock() before calling it, RWMutex.RLock()
|
|
||||||
// is not an option since it writes cache
|
|
||||||
func (h *HealthPingRTTS) GetWithCache() *HealthPingStats {
|
|
||||||
lastPutAt := h.rtts[h.idx].time
|
|
||||||
now := time.Now()
|
|
||||||
if h.stats == nil || h.lastUpdateAt.Before(lastPutAt) || h.findOutdated(now) >= 0 {
|
|
||||||
h.stats = h.getStatistics()
|
|
||||||
h.lastUpdateAt = now
|
|
||||||
}
|
|
||||||
return h.stats
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put puts a new rtt to the HealthPingResult
|
|
||||||
func (h *HealthPingRTTS) Put(d time.Duration) {
|
|
||||||
if h.rtts == nil {
|
|
||||||
h.rtts = make([]*pingRTT, h.cap)
|
|
||||||
for i := 0; i < h.cap; i++ {
|
|
||||||
h.rtts[i] = &pingRTT{}
|
|
||||||
}
|
|
||||||
h.idx = -1
|
|
||||||
}
|
|
||||||
h.idx = h.calcIndex(1)
|
|
||||||
now := time.Now()
|
|
||||||
h.rtts[h.idx].time = now
|
|
||||||
h.rtts[h.idx].value = d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HealthPingRTTS) calcIndex(step int) int {
|
|
||||||
idx := h.idx
|
|
||||||
idx += step
|
|
||||||
if idx >= h.cap {
|
|
||||||
idx %= h.cap
|
|
||||||
}
|
|
||||||
return idx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HealthPingRTTS) getStatistics() *HealthPingStats {
|
|
||||||
stats := &HealthPingStats{}
|
|
||||||
stats.Fail = 0
|
|
||||||
stats.Max = 0
|
|
||||||
stats.Min = rttFailed
|
|
||||||
sum := time.Duration(0)
|
|
||||||
cnt := 0
|
|
||||||
validRTTs := make([]time.Duration, 0)
|
|
||||||
for _, rtt := range h.rtts {
|
|
||||||
switch {
|
|
||||||
case rtt.value == 0 || time.Since(rtt.time) > h.validity:
|
|
||||||
continue
|
|
||||||
case rtt.value == rttFailed:
|
|
||||||
stats.Fail++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
cnt++
|
|
||||||
sum += rtt.value
|
|
||||||
validRTTs = append(validRTTs, rtt.value)
|
|
||||||
if stats.Max < rtt.value {
|
|
||||||
stats.Max = rtt.value
|
|
||||||
}
|
|
||||||
if stats.Min > rtt.value {
|
|
||||||
stats.Min = rtt.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stats.All = cnt + stats.Fail
|
|
||||||
if cnt == 0 {
|
|
||||||
stats.Min = 0
|
|
||||||
return stats
|
|
||||||
}
|
|
||||||
stats.Average = time.Duration(int(sum) / cnt)
|
|
||||||
var std float64
|
|
||||||
if cnt < 2 {
|
|
||||||
// no enough data for standard deviation, we assume it's half of the average rtt
|
|
||||||
// if we don't do this, standard deviation of 1 round tested nodes is 0, will always
|
|
||||||
// selected before 2 or more rounds tested nodes
|
|
||||||
std = float64(stats.Average / 2)
|
|
||||||
} else {
|
|
||||||
variance := float64(0)
|
|
||||||
for _, rtt := range validRTTs {
|
|
||||||
variance += math.Pow(float64(rtt-stats.Average), 2)
|
|
||||||
}
|
|
||||||
std = math.Sqrt(variance / float64(cnt))
|
|
||||||
}
|
|
||||||
stats.Deviation = time.Duration(std)
|
|
||||||
return stats
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HealthPingRTTS) findOutdated(now time.Time) int {
|
|
||||||
for i := h.cap - 1; i < 2*h.cap; i++ {
|
|
||||||
// from oldest to latest
|
|
||||||
idx := h.calcIndex(i)
|
|
||||||
validity := h.rtts[idx].time.Add(h.validity)
|
|
||||||
if h.lastUpdateAt.After(validity) {
|
|
||||||
return idx
|
|
||||||
}
|
|
||||||
if validity.Before(now) {
|
|
||||||
return idx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
package burst_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
reflect "reflect"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/observatory/burst"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHealthPingResults(t *testing.T) {
|
|
||||||
rtts := []int64{60, 140, 60, 140, 60, 60, 140, 60, 140}
|
|
||||||
hr := burst.NewHealthPingResult(4, time.Hour)
|
|
||||||
for _, rtt := range rtts {
|
|
||||||
hr.Put(time.Duration(rtt))
|
|
||||||
}
|
|
||||||
rttFailed := time.Duration(math.MaxInt64)
|
|
||||||
expected := &burst.HealthPingStats{
|
|
||||||
All: 4,
|
|
||||||
Fail: 0,
|
|
||||||
Deviation: 40,
|
|
||||||
Average: 100,
|
|
||||||
Max: 140,
|
|
||||||
Min: 60,
|
|
||||||
}
|
|
||||||
actual := hr.Get()
|
|
||||||
if !reflect.DeepEqual(expected, actual) {
|
|
||||||
t.Errorf("expected: %v, actual: %v", expected, actual)
|
|
||||||
}
|
|
||||||
hr.Put(rttFailed)
|
|
||||||
hr.Put(rttFailed)
|
|
||||||
expected.Fail = 2
|
|
||||||
actual = hr.Get()
|
|
||||||
if !reflect.DeepEqual(expected, actual) {
|
|
||||||
t.Errorf("failed half-failures test, expected: %v, actual: %v", expected, actual)
|
|
||||||
}
|
|
||||||
hr.Put(rttFailed)
|
|
||||||
hr.Put(rttFailed)
|
|
||||||
expected = &burst.HealthPingStats{
|
|
||||||
All: 4,
|
|
||||||
Fail: 4,
|
|
||||||
Deviation: 0,
|
|
||||||
Average: 0,
|
|
||||||
Max: 0,
|
|
||||||
Min: 0,
|
|
||||||
}
|
|
||||||
actual = hr.Get()
|
|
||||||
if !reflect.DeepEqual(expected, actual) {
|
|
||||||
t.Errorf("failed all-failures test, expected: %v, actual: %v", expected, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHealthPingResultsIgnoreOutdated(t *testing.T) {
|
|
||||||
rtts := []int64{60, 140, 60, 140}
|
|
||||||
hr := burst.NewHealthPingResult(4, time.Duration(10)*time.Millisecond)
|
|
||||||
for i, rtt := range rtts {
|
|
||||||
if i == 2 {
|
|
||||||
// wait for previous 2 outdated
|
|
||||||
time.Sleep(time.Duration(10) * time.Millisecond)
|
|
||||||
}
|
|
||||||
hr.Put(time.Duration(rtt))
|
|
||||||
}
|
|
||||||
hr.Get()
|
|
||||||
expected := &burst.HealthPingStats{
|
|
||||||
All: 2,
|
|
||||||
Fail: 0,
|
|
||||||
Deviation: 40,
|
|
||||||
Average: 100,
|
|
||||||
Max: 140,
|
|
||||||
Min: 60,
|
|
||||||
}
|
|
||||||
actual := hr.Get()
|
|
||||||
if !reflect.DeepEqual(expected, actual) {
|
|
||||||
t.Errorf("failed 'half-outdated' test, expected: %v, actual: %v", expected, actual)
|
|
||||||
}
|
|
||||||
// wait for all outdated
|
|
||||||
time.Sleep(time.Duration(10) * time.Millisecond)
|
|
||||||
expected = &burst.HealthPingStats{
|
|
||||||
All: 0,
|
|
||||||
Fail: 0,
|
|
||||||
Deviation: 0,
|
|
||||||
Average: 0,
|
|
||||||
Max: 0,
|
|
||||||
Min: 0,
|
|
||||||
}
|
|
||||||
actual = hr.Get()
|
|
||||||
if !reflect.DeepEqual(expected, actual) {
|
|
||||||
t.Errorf("failed 'outdated / not-tested' test, expected: %v, actual: %v", expected, actual)
|
|
||||||
}
|
|
||||||
|
|
||||||
hr.Put(time.Duration(60))
|
|
||||||
expected = &burst.HealthPingStats{
|
|
||||||
All: 1,
|
|
||||||
Fail: 0,
|
|
||||||
// 1 sample, std=0.5rtt
|
|
||||||
Deviation: 30,
|
|
||||||
Average: 60,
|
|
||||||
Max: 60,
|
|
||||||
Min: 60,
|
|
||||||
}
|
|
||||||
actual = hr.Get()
|
|
||||||
if !reflect.DeepEqual(expected, actual) {
|
|
||||||
t.Errorf("expected: %v, actual: %v", expected, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
package burst
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/features/routing"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/tagged"
|
|
||||||
)
|
|
||||||
|
|
||||||
type pingClient struct {
|
|
||||||
destination string
|
|
||||||
httpClient *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPingClient(ctx context.Context, dispatcher routing.Dispatcher, destination string, timeout time.Duration, handler string) *pingClient {
|
|
||||||
return &pingClient{
|
|
||||||
destination: destination,
|
|
||||||
httpClient: newHTTPClient(ctx, dispatcher, handler, timeout),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newDirectPingClient(destination string, timeout time.Duration) *pingClient {
|
|
||||||
return &pingClient{
|
|
||||||
destination: destination,
|
|
||||||
httpClient: &http.Client{Timeout: timeout},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newHTTPClient(ctxv context.Context, dispatcher routing.Dispatcher, handler string, timeout time.Duration) *http.Client {
|
|
||||||
tr := &http.Transport{
|
|
||||||
DisableKeepAlives: true,
|
|
||||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
||||||
dest, err := net.ParseDestination(network + ":" + addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return tagged.Dialer(ctxv, dispatcher, dest, handler)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return &http.Client{
|
|
||||||
Transport: tr,
|
|
||||||
Timeout: timeout,
|
|
||||||
// don't follow redirect
|
|
||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
||||||
return http.ErrUseLastResponse
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MeasureDelay returns the delay time of the request to dest
|
|
||||||
func (s *pingClient) MeasureDelay(httpMethod string) (time.Duration, error) {
|
|
||||||
if s.httpClient == nil {
|
|
||||||
panic("pingClient not initialized")
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequest(httpMethod, s.destination, nil)
|
|
||||||
if err != nil {
|
|
||||||
return rttFailed, err
|
|
||||||
}
|
|
||||||
|
|
||||||
start := time.Now()
|
|
||||||
resp, err := s.httpClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return rttFailed, err
|
|
||||||
}
|
|
||||||
if httpMethod == http.MethodGet {
|
|
||||||
_, err = io.Copy(io.Discard, resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return rttFailed, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resp.Body.Close()
|
|
||||||
|
|
||||||
return time.Since(start), nil
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/observatory"
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
core "github.com/xtls/xray-core/core"
|
|
||||||
"github.com/xtls/xray-core/features/extension"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
type service struct {
|
|
||||||
UnimplementedObservatoryServiceServer
|
|
||||||
v *core.Instance
|
|
||||||
|
|
||||||
observatory extension.Observatory
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) GetOutboundStatus(ctx context.Context, request *GetOutboundStatusRequest) (*GetOutboundStatusResponse, error) {
|
|
||||||
resp, err := s.observatory.GetObservation(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
retdata := resp.(*observatory.ObservationResult)
|
|
||||||
return &GetOutboundStatusResponse{
|
|
||||||
Status: retdata,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) Register(server *grpc.Server) {
|
|
||||||
RegisterObservatoryServiceServer(server, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
|
|
||||||
s := core.MustFromContext(ctx)
|
|
||||||
sv := &service{v: s}
|
|
||||||
err := s.RequireFeatures(func(Observatory extension.Observatory) {
|
|
||||||
sv.observatory = Observatory
|
|
||||||
}, false)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return sv, nil
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.35.1
|
|
||||||
// protoc v5.28.2
|
|
||||||
// source: app/observatory/command/command.proto
|
|
||||||
|
|
||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
observatory "github.com/xtls/xray-core/app/observatory"
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type GetOutboundStatusRequest struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetOutboundStatusRequest) Reset() {
|
|
||||||
*x = GetOutboundStatusRequest{}
|
|
||||||
mi := &file_app_observatory_command_command_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetOutboundStatusRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*GetOutboundStatusRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *GetOutboundStatusRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_observatory_command_command_proto_msgTypes[0]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use GetOutboundStatusRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*GetOutboundStatusRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_observatory_command_command_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetOutboundStatusResponse struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Status *observatory.ObservationResult `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetOutboundStatusResponse) Reset() {
|
|
||||||
*x = GetOutboundStatusResponse{}
|
|
||||||
mi := &file_app_observatory_command_command_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetOutboundStatusResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*GetOutboundStatusResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *GetOutboundStatusResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_observatory_command_command_proto_msgTypes[1]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use GetOutboundStatusResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*GetOutboundStatusResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_observatory_command_command_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetOutboundStatusResponse) GetStatus() *observatory.ObservationResult {
|
|
||||||
if x != nil {
|
|
||||||
return x.Status
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
|
||||||
*x = Config{}
|
|
||||||
mi := &file_app_observatory_command_command_proto_msgTypes[2]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Config) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_observatory_command_command_proto_msgTypes[2]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Config) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_observatory_command_command_proto_rawDescGZIP(), []int{2}
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_app_observatory_command_command_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_app_observatory_command_command_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x25, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
|
|
||||||
0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
|
||||||
0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x21, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
|
||||||
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
|
|
||||||
0x72, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x1c, 0x61, 0x70, 0x70, 0x2f,
|
|
||||||
0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x63, 0x6f, 0x6e, 0x66,
|
|
||||||
0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1a, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x4f,
|
|
||||||
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71,
|
|
||||||
0x75, 0x65, 0x73, 0x74, 0x22, 0x61, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f,
|
|
||||||
0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
|
||||||
0x65, 0x12, 0x44, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
|
|
||||||
0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
|
|
||||||
0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x4f, 0x62,
|
|
||||||
0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52,
|
|
||||||
0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
|
||||||
0x67, 0x32, 0xa7, 0x01, 0x0a, 0x12, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
|
|
||||||
0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x90, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74,
|
|
||||||
0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3b,
|
|
||||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f,
|
|
||||||
0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
|
||||||
0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74,
|
|
||||||
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3c, 0x2e, 0x78, 0x72,
|
|
||||||
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65,
|
|
||||||
0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
|
||||||
0x47, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75,
|
|
||||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x80, 0x01, 0x0a, 0x25,
|
|
||||||
0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
|
|
||||||
0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x6f,
|
|
||||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
|
||||||
0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f,
|
|
||||||
0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
|
|
||||||
0x72, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x21, 0x58, 0x72, 0x61,
|
|
||||||
0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72,
|
|
||||||
0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06,
|
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_app_observatory_command_command_proto_rawDescOnce sync.Once
|
|
||||||
file_app_observatory_command_command_proto_rawDescData = file_app_observatory_command_command_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_app_observatory_command_command_proto_rawDescGZIP() []byte {
|
|
||||||
file_app_observatory_command_command_proto_rawDescOnce.Do(func() {
|
|
||||||
file_app_observatory_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_observatory_command_command_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_app_observatory_command_command_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_app_observatory_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
|
||||||
var file_app_observatory_command_command_proto_goTypes = []any{
|
|
||||||
(*GetOutboundStatusRequest)(nil), // 0: xray.core.app.observatory.command.GetOutboundStatusRequest
|
|
||||||
(*GetOutboundStatusResponse)(nil), // 1: xray.core.app.observatory.command.GetOutboundStatusResponse
|
|
||||||
(*Config)(nil), // 2: xray.core.app.observatory.command.Config
|
|
||||||
(*observatory.ObservationResult)(nil), // 3: xray.core.app.observatory.ObservationResult
|
|
||||||
}
|
|
||||||
var file_app_observatory_command_command_proto_depIdxs = []int32{
|
|
||||||
3, // 0: xray.core.app.observatory.command.GetOutboundStatusResponse.status:type_name -> xray.core.app.observatory.ObservationResult
|
|
||||||
0, // 1: xray.core.app.observatory.command.ObservatoryService.GetOutboundStatus:input_type -> xray.core.app.observatory.command.GetOutboundStatusRequest
|
|
||||||
1, // 2: xray.core.app.observatory.command.ObservatoryService.GetOutboundStatus:output_type -> xray.core.app.observatory.command.GetOutboundStatusResponse
|
|
||||||
2, // [2:3] is the sub-list for method output_type
|
|
||||||
1, // [1:2] is the sub-list for method input_type
|
|
||||||
1, // [1:1] is the sub-list for extension type_name
|
|
||||||
1, // [1:1] is the sub-list for extension extendee
|
|
||||||
0, // [0:1] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_app_observatory_command_command_proto_init() }
|
|
||||||
func file_app_observatory_command_command_proto_init() {
|
|
||||||
if File_app_observatory_command_command_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_app_observatory_command_command_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 3,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 1,
|
|
||||||
},
|
|
||||||
GoTypes: file_app_observatory_command_command_proto_goTypes,
|
|
||||||
DependencyIndexes: file_app_observatory_command_command_proto_depIdxs,
|
|
||||||
MessageInfos: file_app_observatory_command_command_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_app_observatory_command_command_proto = out.File
|
|
||||||
file_app_observatory_command_command_proto_rawDesc = nil
|
|
||||||
file_app_observatory_command_command_proto_goTypes = nil
|
|
||||||
file_app_observatory_command_command_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package xray.core.app.observatory.command;
|
|
||||||
option csharp_namespace = "Xray.Core.App.Observatory.Command";
|
|
||||||
option go_package = "github.com/xtls/xray-core/app/observatory/command";
|
|
||||||
option java_package = "com.xray.core.app.observatory.command";
|
|
||||||
option java_multiple_files = true;
|
|
||||||
|
|
||||||
import "app/observatory/config.proto";
|
|
||||||
|
|
||||||
message GetOutboundStatusRequest {
|
|
||||||
}
|
|
||||||
|
|
||||||
message GetOutboundStatusResponse {
|
|
||||||
xray.core.app.observatory.ObservationResult status = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
service ObservatoryService {
|
|
||||||
rpc GetOutboundStatus(GetOutboundStatusRequest)
|
|
||||||
returns (GetOutboundStatusResponse) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
message Config {}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// - protoc-gen-go-grpc v1.5.1
|
|
||||||
// - protoc v5.28.2
|
|
||||||
// source: app/observatory/command/command.proto
|
|
||||||
|
|
||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
context "context"
|
|
||||||
grpc "google.golang.org/grpc"
|
|
||||||
codes "google.golang.org/grpc/codes"
|
|
||||||
status "google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This is a compile-time assertion to ensure that this generated file
|
|
||||||
// is compatible with the grpc package it is being compiled against.
|
|
||||||
// Requires gRPC-Go v1.64.0 or later.
|
|
||||||
const _ = grpc.SupportPackageIsVersion9
|
|
||||||
|
|
||||||
const (
|
|
||||||
ObservatoryService_GetOutboundStatus_FullMethodName = "/xray.core.app.observatory.command.ObservatoryService/GetOutboundStatus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ObservatoryServiceClient is the client API for ObservatoryService service.
|
|
||||||
//
|
|
||||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
|
||||||
type ObservatoryServiceClient interface {
|
|
||||||
GetOutboundStatus(ctx context.Context, in *GetOutboundStatusRequest, opts ...grpc.CallOption) (*GetOutboundStatusResponse, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type observatoryServiceClient struct {
|
|
||||||
cc grpc.ClientConnInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewObservatoryServiceClient(cc grpc.ClientConnInterface) ObservatoryServiceClient {
|
|
||||||
return &observatoryServiceClient{cc}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *observatoryServiceClient) GetOutboundStatus(ctx context.Context, in *GetOutboundStatusRequest, opts ...grpc.CallOption) (*GetOutboundStatusResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(GetOutboundStatusResponse)
|
|
||||||
err := c.cc.Invoke(ctx, ObservatoryService_GetOutboundStatus_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ObservatoryServiceServer is the server API for ObservatoryService service.
|
|
||||||
// All implementations must embed UnimplementedObservatoryServiceServer
|
|
||||||
// for forward compatibility.
|
|
||||||
type ObservatoryServiceServer interface {
|
|
||||||
GetOutboundStatus(context.Context, *GetOutboundStatusRequest) (*GetOutboundStatusResponse, error)
|
|
||||||
mustEmbedUnimplementedObservatoryServiceServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnimplementedObservatoryServiceServer must be embedded to have
|
|
||||||
// forward compatible implementations.
|
|
||||||
//
|
|
||||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
|
||||||
// pointer dereference when methods are called.
|
|
||||||
type UnimplementedObservatoryServiceServer struct{}
|
|
||||||
|
|
||||||
func (UnimplementedObservatoryServiceServer) GetOutboundStatus(context.Context, *GetOutboundStatusRequest) (*GetOutboundStatusResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetOutboundStatus not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedObservatoryServiceServer) mustEmbedUnimplementedObservatoryServiceServer() {}
|
|
||||||
func (UnimplementedObservatoryServiceServer) testEmbeddedByValue() {}
|
|
||||||
|
|
||||||
// UnsafeObservatoryServiceServer may be embedded to opt out of forward compatibility for this service.
|
|
||||||
// Use of this interface is not recommended, as added methods to ObservatoryServiceServer will
|
|
||||||
// result in compilation errors.
|
|
||||||
type UnsafeObservatoryServiceServer interface {
|
|
||||||
mustEmbedUnimplementedObservatoryServiceServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterObservatoryServiceServer(s grpc.ServiceRegistrar, srv ObservatoryServiceServer) {
|
|
||||||
// If the following call pancis, it indicates UnimplementedObservatoryServiceServer was
|
|
||||||
// embedded by pointer and is nil. This will cause panics if an
|
|
||||||
// unimplemented method is ever invoked, so we test this at initialization
|
|
||||||
// time to prevent it from happening at runtime later due to I/O.
|
|
||||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
|
||||||
t.testEmbeddedByValue()
|
|
||||||
}
|
|
||||||
s.RegisterService(&ObservatoryService_ServiceDesc, srv)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _ObservatoryService_GetOutboundStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(GetOutboundStatusRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(ObservatoryServiceServer).GetOutboundStatus(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: ObservatoryService_GetOutboundStatus_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(ObservatoryServiceServer).GetOutboundStatus(ctx, req.(*GetOutboundStatusRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ObservatoryService_ServiceDesc is the grpc.ServiceDesc for ObservatoryService service.
|
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
|
||||||
// and not to be introspected or modified (even as a copy)
|
|
||||||
var ObservatoryService_ServiceDesc = grpc.ServiceDesc{
|
|
||||||
ServiceName: "xray.core.app.observatory.command.ObservatoryService",
|
|
||||||
HandlerType: (*ObservatoryServiceServer)(nil),
|
|
||||||
Methods: []grpc.MethodDesc{
|
|
||||||
{
|
|
||||||
MethodName: "GetOutboundStatus",
|
|
||||||
Handler: _ObservatoryService_GetOutboundStatus_Handler,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Streams: []grpc.StreamDesc{},
|
|
||||||
Metadata: "app/observatory/command/command.proto",
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.27.1
|
||||||
// protoc v5.28.2
|
// protoc v3.18.0
|
||||||
// source: app/observatory/config.proto
|
// source: app/observatory/config.proto
|
||||||
|
|
||||||
package observatory
|
package observatory
|
||||||
@@ -30,9 +30,11 @@ type ObservationResult struct {
|
|||||||
|
|
||||||
func (x *ObservationResult) Reset() {
|
func (x *ObservationResult) Reset() {
|
||||||
*x = ObservationResult{}
|
*x = ObservationResult{}
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[0]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_observatory_config_proto_msgTypes[0]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ObservationResult) String() string {
|
func (x *ObservationResult) String() string {
|
||||||
@@ -43,7 +45,7 @@ func (*ObservationResult) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *ObservationResult) ProtoReflect() protoreflect.Message {
|
func (x *ObservationResult) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[0]
|
mi := &file_app_observatory_config_proto_msgTypes[0]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -65,123 +67,39 @@ func (x *ObservationResult) GetStatus() []*OutboundStatus {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type HealthPingMeasurementResult struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
All int64 `protobuf:"varint,1,opt,name=all,proto3" json:"all,omitempty"`
|
|
||||||
Fail int64 `protobuf:"varint,2,opt,name=fail,proto3" json:"fail,omitempty"`
|
|
||||||
Deviation int64 `protobuf:"varint,3,opt,name=deviation,proto3" json:"deviation,omitempty"`
|
|
||||||
Average int64 `protobuf:"varint,4,opt,name=average,proto3" json:"average,omitempty"`
|
|
||||||
Max int64 `protobuf:"varint,5,opt,name=max,proto3" json:"max,omitempty"`
|
|
||||||
Min int64 `protobuf:"varint,6,opt,name=min,proto3" json:"min,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingMeasurementResult) Reset() {
|
|
||||||
*x = HealthPingMeasurementResult{}
|
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingMeasurementResult) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*HealthPingMeasurementResult) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *HealthPingMeasurementResult) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[1]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use HealthPingMeasurementResult.ProtoReflect.Descriptor instead.
|
|
||||||
func (*HealthPingMeasurementResult) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_observatory_config_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingMeasurementResult) GetAll() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.All
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingMeasurementResult) GetFail() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Fail
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingMeasurementResult) GetDeviation() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Deviation
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingMeasurementResult) GetAverage() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Average
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingMeasurementResult) GetMax() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Max
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HealthPingMeasurementResult) GetMin() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Min
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type OutboundStatus struct {
|
type OutboundStatus struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// @Document Whether this outbound is usable
|
// @Document Whether this outbound is usable
|
||||||
// @Restriction ReadOnlyForUser
|
//@Restriction ReadOnlyForUser
|
||||||
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
|
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
|
||||||
// @Document The time for probe request to finish.
|
// @Document The time for probe request to finish.
|
||||||
// @Type time.ms
|
//@Type time.ms
|
||||||
// @Restriction ReadOnlyForUser
|
//@Restriction ReadOnlyForUser
|
||||||
Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"`
|
Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"`
|
||||||
// @Document The last error caused this outbound failed to relay probe request
|
// @Document The last error caused this outbound failed to relay probe request
|
||||||
// @Restriction NotMachineReadable
|
//@Restriction NotMachineReadable
|
||||||
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
|
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
|
||||||
// @Document The outbound tag for this Server
|
// @Document The outbound tag for this Server
|
||||||
// @Type id.outboundTag
|
//@Type id.outboundTag
|
||||||
OutboundTag string `protobuf:"bytes,4,opt,name=outbound_tag,json=outboundTag,proto3" json:"outbound_tag,omitempty"`
|
OutboundTag string `protobuf:"bytes,4,opt,name=outbound_tag,json=outboundTag,proto3" json:"outbound_tag,omitempty"`
|
||||||
// @Document The time this outbound is known to be alive
|
// @Document The time this outbound is known to be alive
|
||||||
// @Type id.outboundTag
|
//@Type id.outboundTag
|
||||||
LastSeenTime int64 `protobuf:"varint,5,opt,name=last_seen_time,json=lastSeenTime,proto3" json:"last_seen_time,omitempty"`
|
LastSeenTime int64 `protobuf:"varint,5,opt,name=last_seen_time,json=lastSeenTime,proto3" json:"last_seen_time,omitempty"`
|
||||||
// @Document The time this outbound is tried
|
// @Document The time this outbound is tried
|
||||||
// @Type id.outboundTag
|
//@Type id.outboundTag
|
||||||
LastTryTime int64 `protobuf:"varint,6,opt,name=last_try_time,json=lastTryTime,proto3" json:"last_try_time,omitempty"`
|
LastTryTime int64 `protobuf:"varint,6,opt,name=last_try_time,json=lastTryTime,proto3" json:"last_try_time,omitempty"`
|
||||||
HealthPing *HealthPingMeasurementResult `protobuf:"bytes,7,opt,name=health_ping,json=healthPing,proto3" json:"health_ping,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OutboundStatus) Reset() {
|
func (x *OutboundStatus) Reset() {
|
||||||
*x = OutboundStatus{}
|
*x = OutboundStatus{}
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[2]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_observatory_config_proto_msgTypes[1]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OutboundStatus) String() string {
|
func (x *OutboundStatus) String() string {
|
||||||
@@ -191,8 +109,8 @@ func (x *OutboundStatus) String() string {
|
|||||||
func (*OutboundStatus) ProtoMessage() {}
|
func (*OutboundStatus) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *OutboundStatus) ProtoReflect() protoreflect.Message {
|
func (x *OutboundStatus) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[2]
|
mi := &file_app_observatory_config_proto_msgTypes[1]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -204,7 +122,7 @@ func (x *OutboundStatus) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use OutboundStatus.ProtoReflect.Descriptor instead.
|
// Deprecated: Use OutboundStatus.ProtoReflect.Descriptor instead.
|
||||||
func (*OutboundStatus) Descriptor() ([]byte, []int) {
|
func (*OutboundStatus) Descriptor() ([]byte, []int) {
|
||||||
return file_app_observatory_config_proto_rawDescGZIP(), []int{2}
|
return file_app_observatory_config_proto_rawDescGZIP(), []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OutboundStatus) GetAlive() bool {
|
func (x *OutboundStatus) GetAlive() bool {
|
||||||
@@ -249,35 +167,30 @@ func (x *OutboundStatus) GetLastTryTime() int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OutboundStatus) GetHealthPing() *HealthPingMeasurementResult {
|
|
||||||
if x != nil {
|
|
||||||
return x.HealthPing
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProbeResult struct {
|
type ProbeResult struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// @Document Whether this outbound is usable
|
// @Document Whether this outbound is usable
|
||||||
// @Restriction ReadOnlyForUser
|
//@Restriction ReadOnlyForUser
|
||||||
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
|
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
|
||||||
// @Document The time for probe request to finish.
|
// @Document The time for probe request to finish.
|
||||||
// @Type time.ms
|
//@Type time.ms
|
||||||
// @Restriction ReadOnlyForUser
|
//@Restriction ReadOnlyForUser
|
||||||
Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"`
|
Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"`
|
||||||
// @Document The error caused this outbound failed to relay probe request
|
// @Document The error caused this outbound failed to relay probe request
|
||||||
// @Restriction NotMachineReadable
|
//@Restriction NotMachineReadable
|
||||||
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
|
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ProbeResult) Reset() {
|
func (x *ProbeResult) Reset() {
|
||||||
*x = ProbeResult{}
|
*x = ProbeResult{}
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[3]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_observatory_config_proto_msgTypes[2]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ProbeResult) String() string {
|
func (x *ProbeResult) String() string {
|
||||||
@@ -287,8 +200,8 @@ func (x *ProbeResult) String() string {
|
|||||||
func (*ProbeResult) ProtoMessage() {}
|
func (*ProbeResult) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *ProbeResult) ProtoReflect() protoreflect.Message {
|
func (x *ProbeResult) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[3]
|
mi := &file_app_observatory_config_proto_msgTypes[2]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -300,7 +213,7 @@ func (x *ProbeResult) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use ProbeResult.ProtoReflect.Descriptor instead.
|
// Deprecated: Use ProbeResult.ProtoReflect.Descriptor instead.
|
||||||
func (*ProbeResult) Descriptor() ([]byte, []int) {
|
func (*ProbeResult) Descriptor() ([]byte, []int) {
|
||||||
return file_app_observatory_config_proto_rawDescGZIP(), []int{3}
|
return file_app_observatory_config_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ProbeResult) GetAlive() bool {
|
func (x *ProbeResult) GetAlive() bool {
|
||||||
@@ -330,15 +243,17 @@ type Intensity struct {
|
|||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// @Document The time interval for a probe request in ms.
|
// @Document The time interval for a probe request in ms.
|
||||||
// @Type time.ms
|
//@Type time.ms
|
||||||
ProbeInterval uint32 `protobuf:"varint,1,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
|
ProbeInterval uint32 `protobuf:"varint,1,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Intensity) Reset() {
|
func (x *Intensity) Reset() {
|
||||||
*x = Intensity{}
|
*x = Intensity{}
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[4]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_observatory_config_proto_msgTypes[3]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Intensity) String() string {
|
func (x *Intensity) String() string {
|
||||||
@@ -348,8 +263,8 @@ func (x *Intensity) String() string {
|
|||||||
func (*Intensity) ProtoMessage() {}
|
func (*Intensity) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Intensity) ProtoReflect() protoreflect.Message {
|
func (x *Intensity) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[4]
|
mi := &file_app_observatory_config_proto_msgTypes[3]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -361,7 +276,7 @@ func (x *Intensity) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Intensity.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Intensity.ProtoReflect.Descriptor instead.
|
||||||
func (*Intensity) Descriptor() ([]byte, []int) {
|
func (*Intensity) Descriptor() ([]byte, []int) {
|
||||||
return file_app_observatory_config_proto_rawDescGZIP(), []int{4}
|
return file_app_observatory_config_proto_rawDescGZIP(), []int{3}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Intensity) GetProbeInterval() uint32 {
|
func (x *Intensity) GetProbeInterval() uint32 {
|
||||||
@@ -385,9 +300,11 @@ type Config struct {
|
|||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[5]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_observatory_config_proto_msgTypes[4]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) String() string {
|
func (x *Config) String() string {
|
||||||
@@ -397,8 +314,8 @@ func (x *Config) String() string {
|
|||||||
func (*Config) ProtoMessage() {}
|
func (*Config) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[5]
|
mi := &file_app_observatory_config_proto_msgTypes[4]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -410,7 +327,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||||
func (*Config) Descriptor() ([]byte, []int) {
|
func (*Config) Descriptor() ([]byte, []int) {
|
||||||
return file_app_observatory_config_proto_rawDescGZIP(), []int{5}
|
return file_app_observatory_config_proto_rawDescGZIP(), []int{4}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetSubjectSelector() []string {
|
func (x *Config) GetSubjectSelector() []string {
|
||||||
@@ -453,62 +370,47 @@ var file_app_observatory_config_proto_rawDesc = []byte{
|
|||||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f,
|
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f,
|
||||||
0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f,
|
0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f,
|
||||||
0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
|
0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
|
||||||
0x73, 0x22, 0x9f, 0x01, 0x0a, 0x1b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67,
|
0x73, 0x22, 0xd5, 0x01, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74,
|
||||||
0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c,
|
0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20,
|
||||||
0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03,
|
0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65,
|
||||||
0x61, 0x6c, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28,
|
0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79,
|
||||||
0x03, 0x52, 0x04, 0x66, 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x61,
|
0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x72,
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69,
|
0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c, 0x61, 0x73,
|
||||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65,
|
0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c,
|
||||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65, 0x12,
|
0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x04, 0x20, 0x01,
|
||||||
0x10, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6d, 0x61,
|
0x28, 0x09, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12,
|
||||||
0x78, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03,
|
0x24, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x74, 0x69, 0x6d,
|
||||||
0x6d, 0x69, 0x6e, 0x22, 0xae, 0x02, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,
|
0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65,
|
||||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18,
|
0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x74, 0x72,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05,
|
0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6c, 0x61,
|
||||||
0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c,
|
0x73, 0x74, 0x54, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x65, 0x0a, 0x0b, 0x50, 0x72, 0x6f,
|
||||||
0x61, 0x79, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
0x62, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76,
|
||||||
0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c,
|
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x14,
|
||||||
0x61, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21,
|
0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64,
|
||||||
0x0a, 0x0c, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x04,
|
0x65, 0x6c, 0x61, 0x79, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61,
|
0x6f, 0x72, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
0x67, 0x12, 0x24, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x74,
|
0x0f, 0x6c, 0x61, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e,
|
||||||
0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53,
|
0x22, 0x32, 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a,
|
||||||
0x65, 0x65, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x5f,
|
0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18,
|
||||||
0x74, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b,
|
0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65,
|
||||||
0x6c, 0x61, 0x73, 0x74, 0x54, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x57, 0x0a, 0x0b, 0x68,
|
0x72, 0x76, 0x61, 0x6c, 0x22, 0xa6, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
||||||
0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
|
0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63,
|
||||||
0x32, 0x36, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
|
0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65,
|
||||||
0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x48, 0x65, 0x61,
|
0x63, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x72,
|
||||||
0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65,
|
0x6f, 0x62, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70,
|
||||||
0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0a, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68,
|
0x72, 0x6f, 0x62, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65,
|
||||||
0x50, 0x69, 0x6e, 0x67, 0x22, 0x65, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x73,
|
0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||||
0x75, 0x6c, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01,
|
0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x2d,
|
||||||
0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c,
|
0x0a, 0x12, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72,
|
||||||
0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12,
|
0x65, 0x6e, 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x65, 0x6e, 0x61, 0x62,
|
||||||
0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x72, 0x65,
|
0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x42, 0x5e, 0x0a,
|
||||||
0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c, 0x61, 0x73, 0x74,
|
0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62,
|
||||||
0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x32, 0x0a, 0x09, 0x49,
|
0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74,
|
||||||
0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x62,
|
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
|
||||||
0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
|
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72,
|
||||||
0x52, 0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22,
|
0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0xaa, 0x02, 0x14, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70,
|
||||||
0xa6, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75,
|
0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70,
|
||||||
0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02,
|
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, 0x6c,
|
|
||||||
0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x75,
|
|
||||||
0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x55,
|
|
||||||
0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65,
|
|
||||||
0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x62,
|
|
||||||
0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x2d, 0x0a, 0x12, 0x65, 0x6e, 0x61,
|
|
||||||
0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18,
|
|
||||||
0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6e,
|
|
||||||
0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x42, 0x5e, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e,
|
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61,
|
|
||||||
0x74, 0x6f, 0x72, 0x79, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
|
||||||
0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72,
|
|
||||||
0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
|
|
||||||
0x79, 0xaa, 0x02, 0x14, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4f, 0x62, 0x73,
|
|
||||||
0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -523,23 +425,21 @@ func file_app_observatory_config_proto_rawDescGZIP() []byte {
|
|||||||
return file_app_observatory_config_proto_rawDescData
|
return file_app_observatory_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_app_observatory_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
var file_app_observatory_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||||
var file_app_observatory_config_proto_goTypes = []any{
|
var file_app_observatory_config_proto_goTypes = []interface{}{
|
||||||
(*ObservationResult)(nil), // 0: xray.core.app.observatory.ObservationResult
|
(*ObservationResult)(nil), // 0: xray.core.app.observatory.ObservationResult
|
||||||
(*HealthPingMeasurementResult)(nil), // 1: xray.core.app.observatory.HealthPingMeasurementResult
|
(*OutboundStatus)(nil), // 1: xray.core.app.observatory.OutboundStatus
|
||||||
(*OutboundStatus)(nil), // 2: xray.core.app.observatory.OutboundStatus
|
(*ProbeResult)(nil), // 2: xray.core.app.observatory.ProbeResult
|
||||||
(*ProbeResult)(nil), // 3: xray.core.app.observatory.ProbeResult
|
(*Intensity)(nil), // 3: xray.core.app.observatory.Intensity
|
||||||
(*Intensity)(nil), // 4: xray.core.app.observatory.Intensity
|
(*Config)(nil), // 4: xray.core.app.observatory.Config
|
||||||
(*Config)(nil), // 5: xray.core.app.observatory.Config
|
|
||||||
}
|
}
|
||||||
var file_app_observatory_config_proto_depIdxs = []int32{
|
var file_app_observatory_config_proto_depIdxs = []int32{
|
||||||
2, // 0: xray.core.app.observatory.ObservationResult.status:type_name -> xray.core.app.observatory.OutboundStatus
|
1, // 0: xray.core.app.observatory.ObservationResult.status:type_name -> xray.core.app.observatory.OutboundStatus
|
||||||
1, // 1: xray.core.app.observatory.OutboundStatus.health_ping:type_name -> xray.core.app.observatory.HealthPingMeasurementResult
|
1, // [1:1] is the sub-list for method output_type
|
||||||
2, // [2:2] is the sub-list for method output_type
|
1, // [1:1] is the sub-list for method input_type
|
||||||
2, // [2:2] is the sub-list for method input_type
|
1, // [1:1] is the sub-list for extension type_name
|
||||||
2, // [2:2] is the sub-list for extension type_name
|
1, // [1:1] is the sub-list for extension extendee
|
||||||
2, // [2:2] is the sub-list for extension extendee
|
0, // [0:1] is the sub-list for field type_name
|
||||||
0, // [0:2] is the sub-list for field type_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_observatory_config_proto_init() }
|
func init() { file_app_observatory_config_proto_init() }
|
||||||
@@ -547,13 +447,75 @@ func file_app_observatory_config_proto_init() {
|
|||||||
if File_app_observatory_config_proto != nil {
|
if File_app_observatory_config_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_app_observatory_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ObservationResult); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_observatory_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*OutboundStatus); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_observatory_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ProbeResult); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_observatory_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Intensity); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_observatory_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Config); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_app_observatory_config_proto_rawDesc,
|
RawDescriptor: file_app_observatory_config_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 6,
|
NumMessages: 5,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,15 +10,6 @@ message ObservationResult {
|
|||||||
repeated OutboundStatus status = 1;
|
repeated OutboundStatus status = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message HealthPingMeasurementResult {
|
|
||||||
int64 all = 1;
|
|
||||||
int64 fail = 2;
|
|
||||||
int64 deviation = 3;
|
|
||||||
int64 average = 4;
|
|
||||||
int64 max = 5;
|
|
||||||
int64 min = 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
message OutboundStatus{
|
message OutboundStatus{
|
||||||
/* @Document Whether this outbound is usable
|
/* @Document Whether this outbound is usable
|
||||||
@Restriction ReadOnlyForUser
|
@Restriction ReadOnlyForUser
|
||||||
@@ -45,8 +36,6 @@ message OutboundStatus{
|
|||||||
@Type id.outboundTag
|
@Type id.outboundTag
|
||||||
*/
|
*/
|
||||||
int64 last_try_time = 6;
|
int64 last_try_time = 6;
|
||||||
|
|
||||||
HealthPingMeasurementResult health_ping = 7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message ProbeResult{
|
message ProbeResult{
|
||||||
|
|||||||
9
app/observatory/errors.generated.go
Normal file
9
app/observatory/errors.generated.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package observatory
|
||||||
|
|
||||||
|
import "github.com/xtls/xray-core/common/errors"
|
||||||
|
|
||||||
|
type errPathObjHolder struct{}
|
||||||
|
|
||||||
|
func newError(values ...interface{}) *errors.Error {
|
||||||
|
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||||
|
}
|
||||||
@@ -8,10 +8,10 @@ type errorCollector struct {
|
|||||||
|
|
||||||
func (e *errorCollector) SubmitError(err error) {
|
func (e *errorCollector) SubmitError(err error) {
|
||||||
if e.errors == nil {
|
if e.errors == nil {
|
||||||
e.errors = errors.New("underlying connection error").Base(err)
|
e.errors = newError("underlying connection error").Base(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
e.errors = e.errors.Base(errors.New("underlying connection error").Base(err))
|
e.errors = e.errors.Base(newError("underlying connection error").Base(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func newErrorCollector() *errorCollector {
|
func newErrorCollector() *errorCollector {
|
||||||
@@ -20,7 +20,7 @@ func newErrorCollector() *errorCollector {
|
|||||||
|
|
||||||
func (e *errorCollector) UnderlyingError() error {
|
func (e *errorCollector) UnderlyingError() error {
|
||||||
if e.errors == nil {
|
if e.errors == nil {
|
||||||
return errors.New("failed to produce report")
|
return newError("failed to produce report")
|
||||||
}
|
}
|
||||||
return e.errors
|
return e.errors
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
package observatory
|
package observatory
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package observatory
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/xtls/xray-core/core"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -9,18 +10,16 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
v2net "github.com/xtls/xray-core/common/net"
|
v2net "github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/common/signal/done"
|
"github.com/xtls/xray-core/common/signal/done"
|
||||||
"github.com/xtls/xray-core/common/task"
|
"github.com/xtls/xray-core/common/task"
|
||||||
"github.com/xtls/xray-core/core"
|
|
||||||
"github.com/xtls/xray-core/features/extension"
|
"github.com/xtls/xray-core/features/extension"
|
||||||
"github.com/xtls/xray-core/features/outbound"
|
"github.com/xtls/xray-core/features/outbound"
|
||||||
"github.com/xtls/xray-core/features/routing"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/tagged"
|
"github.com/xtls/xray-core/transport/internet/tagged"
|
||||||
"google.golang.org/protobuf/proto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Observer struct {
|
type Observer struct {
|
||||||
@@ -32,8 +31,9 @@ type Observer struct {
|
|||||||
|
|
||||||
finished *done.Instance
|
finished *done.Instance
|
||||||
|
|
||||||
ohm outbound.Manager
|
ohm outbound.Manager
|
||||||
dispatcher routing.Dispatcher
|
|
||||||
|
StatusUpdate func(result *OutboundStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Observer) GetObservation(ctx context.Context) (proto.Message, error) {
|
func (o *Observer) GetObservation(ctx context.Context) (proto.Message, error) {
|
||||||
@@ -63,50 +63,27 @@ func (o *Observer) background() {
|
|||||||
for !o.finished.Done() {
|
for !o.finished.Done() {
|
||||||
hs, ok := o.ohm.(outbound.HandlerSelector)
|
hs, ok := o.ohm.(outbound.HandlerSelector)
|
||||||
if !ok {
|
if !ok {
|
||||||
errors.LogInfo(o.ctx, "outbound.Manager is not a HandlerSelector")
|
newError("outbound.Manager is not a HandlerSelector").WriteToLog()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
outbounds := hs.Select(o.config.SubjectSelector)
|
outbounds := hs.Select(o.config.SubjectSelector)
|
||||||
|
sort.Strings(outbounds)
|
||||||
|
|
||||||
o.updateStatus(outbounds)
|
o.updateStatus(outbounds)
|
||||||
|
|
||||||
sleepTime := time.Second * 10
|
|
||||||
if o.config.ProbeInterval != 0 {
|
|
||||||
sleepTime = time.Duration(o.config.ProbeInterval)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !o.config.EnableConcurrency {
|
|
||||||
sort.Strings(outbounds)
|
|
||||||
for _, v := range outbounds {
|
|
||||||
result := o.probe(v)
|
|
||||||
o.updateStatusForResult(v, &result)
|
|
||||||
if o.finished.Done() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
time.Sleep(sleepTime)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ch := make(chan struct{}, len(outbounds))
|
|
||||||
|
|
||||||
for _, v := range outbounds {
|
for _, v := range outbounds {
|
||||||
go func(v string) {
|
result := o.probe(v)
|
||||||
result := o.probe(v)
|
o.updateStatusForResult(v, &result)
|
||||||
o.updateStatusForResult(v, &result)
|
if o.finished.Done() {
|
||||||
ch <- struct{}{}
|
|
||||||
}(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
for range outbounds {
|
|
||||||
select {
|
|
||||||
case <-ch:
|
|
||||||
case <-o.finished.Wait():
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
sleepTime := time.Second * 10
|
||||||
|
if o.config.ProbeInterval != 0 {
|
||||||
|
sleepTime = time.Duration(o.config.ProbeInterval)
|
||||||
|
}
|
||||||
|
time.Sleep(sleepTime)
|
||||||
}
|
}
|
||||||
time.Sleep(sleepTime)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,21 +104,21 @@ func (o *Observer) probe(outbound string) ProbeResult {
|
|||||||
DialContext: func(ctx context.Context, network string, addr string) (net.Conn, error) {
|
DialContext: func(ctx context.Context, network string, addr string) (net.Conn, error) {
|
||||||
var connection net.Conn
|
var connection net.Conn
|
||||||
taskErr := task.Run(ctx, func() error {
|
taskErr := task.Run(ctx, func() error {
|
||||||
// MUST use Xray's built in context system
|
// MUST use V2Fly's built in context system
|
||||||
dest, err := v2net.ParseDestination(network + ":" + addr)
|
dest, err := v2net.ParseDestination(network + ":" + addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("cannot understand address").Base(err)
|
return newError("cannot understand address").Base(err)
|
||||||
}
|
}
|
||||||
trackedCtx := session.TrackedConnectionError(o.ctx, errorCollectorForRequest)
|
trackedCtx := session.TrackedConnectionError(o.ctx, errorCollectorForRequest)
|
||||||
conn, err := tagged.Dialer(trackedCtx, o.dispatcher, dest, outbound)
|
conn, err := tagged.Dialer(trackedCtx, dest, outbound)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("cannot dial remote address ", dest).Base(err)
|
return newError("cannot dial remote address ", dest).Base(err)
|
||||||
}
|
}
|
||||||
connection = conn
|
connection = conn
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if taskErr != nil {
|
if taskErr != nil {
|
||||||
return nil, errors.New("cannot finish connection").Base(taskErr)
|
return nil, newError("cannot finish connection").Base(taskErr)
|
||||||
}
|
}
|
||||||
return connection, nil
|
return connection, nil
|
||||||
},
|
},
|
||||||
@@ -158,13 +135,13 @@ func (o *Observer) probe(outbound string) ProbeResult {
|
|||||||
var GETTime time.Duration
|
var GETTime time.Duration
|
||||||
err := task.Run(o.ctx, func() error {
|
err := task.Run(o.ctx, func() error {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
probeURL := "https://www.google.com/generate_204"
|
probeURL := "https://api.v2fly.org/checkConnection.svgz"
|
||||||
if o.config.ProbeUrl != "" {
|
if o.config.ProbeUrl != "" {
|
||||||
probeURL = o.config.ProbeUrl
|
probeURL = o.config.ProbeUrl
|
||||||
}
|
}
|
||||||
response, err := httpClient.Get(probeURL)
|
response, err := httpClient.Get(probeURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("outbound failed to relay connection").Base(err)
|
return newError("outbound failed to relay connection").Base(err)
|
||||||
}
|
}
|
||||||
if response.Body != nil {
|
if response.Body != nil {
|
||||||
response.Body.Close()
|
response.Body.Close()
|
||||||
@@ -174,11 +151,15 @@ func (o *Observer) probe(outbound string) ProbeResult {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var errorMessage = "the outbound " + outbound + " is dead: GET request failed:" + err.Error() + "with outbound handler report underlying connection failed"
|
fullerr := newError("underlying connection failed").Base(errorCollectorForRequest.UnderlyingError())
|
||||||
errors.LogInfoInner(o.ctx, errorCollectorForRequest.UnderlyingError(), errorMessage)
|
fullerr = newError("with outbound handler report").Base(fullerr)
|
||||||
return ProbeResult{Alive: false, LastErrorReason: errorMessage}
|
fullerr = newError("GET request failed:", err).Base(fullerr)
|
||||||
|
fullerr = newError("the outbound ", outbound, " is dead:").Base(fullerr)
|
||||||
|
fullerr = fullerr.AtInfo()
|
||||||
|
fullerr.WriteToLog()
|
||||||
|
return ProbeResult{Alive: false, LastErrorReason: fullerr.Error()}
|
||||||
}
|
}
|
||||||
errors.LogInfo(o.ctx, "the outbound ", outbound, " is alive:", GETTime.Seconds())
|
newError("the outbound ", outbound, " is alive:", GETTime.Seconds()).AtInfo().WriteToLog()
|
||||||
return ProbeResult{Alive: true, Delay: GETTime.Milliseconds()}
|
return ProbeResult{Alive: true, Delay: GETTime.Milliseconds()}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,6 +185,10 @@ func (o *Observer) updateStatusForResult(outbound string, result *ProbeResult) {
|
|||||||
status.LastErrorReason = result.LastErrorReason
|
status.LastErrorReason = result.LastErrorReason
|
||||||
status.Delay = 99999999
|
status.Delay = 99999999
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.StatusUpdate != nil {
|
||||||
|
o.StatusUpdate(status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Observer) findStatusLocationLockHolderOnly(outbound string) int {
|
func (o *Observer) findStatusLocationLockHolderOnly(outbound string) int {
|
||||||
@@ -217,19 +202,16 @@ func (o *Observer) findStatusLocationLockHolderOnly(outbound string) int {
|
|||||||
|
|
||||||
func New(ctx context.Context, config *Config) (*Observer, error) {
|
func New(ctx context.Context, config *Config) (*Observer, error) {
|
||||||
var outboundManager outbound.Manager
|
var outboundManager outbound.Manager
|
||||||
var dispatcher routing.Dispatcher
|
err := core.RequireFeatures(ctx, func(om outbound.Manager) {
|
||||||
err := core.RequireFeatures(ctx, func(om outbound.Manager, rd routing.Dispatcher) {
|
|
||||||
outboundManager = om
|
outboundManager = om
|
||||||
dispatcher = rd
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("Cannot get depended features").Base(err)
|
return nil, newError("Cannot get depended features").Base(err)
|
||||||
}
|
}
|
||||||
return &Observer{
|
return &Observer{
|
||||||
config: config,
|
config: config,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
ohm: outboundManager,
|
ohm: outboundManager,
|
||||||
dispatcher: dispatcher,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
app/observatory/persist.go
Normal file
12
app/observatory/persist.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package observatory
|
||||||
|
|
||||||
|
func (o *Observer) UpdateStatus(result *OutboundStatus) {
|
||||||
|
o.statusLock.Lock()
|
||||||
|
defer o.statusLock.Unlock()
|
||||||
|
|
||||||
|
if location := o.findStatusLocationLockHolderOnly(result.OutboundTag); location != -1 {
|
||||||
|
o.status[location] = result
|
||||||
|
} else {
|
||||||
|
o.status = append(o.status, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -73,7 +73,6 @@ func (p *Policy) ToCorePolicy() policy.Session {
|
|||||||
if p.Stats != nil {
|
if p.Stats != nil {
|
||||||
cp.Stats.UserUplink = p.Stats.UserUplink
|
cp.Stats.UserUplink = p.Stats.UserUplink
|
||||||
cp.Stats.UserDownlink = p.Stats.UserDownlink
|
cp.Stats.UserDownlink = p.Stats.UserDownlink
|
||||||
cp.Stats.UserOnline = p.Stats.UserOnline
|
|
||||||
}
|
}
|
||||||
if p.Buffer != nil {
|
if p.Buffer != nil {
|
||||||
cp.Buffer.PerConnection = p.Buffer.Connection
|
cp.Buffer.PerConnection = p.Buffer.Connection
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.27.1
|
||||||
// protoc v5.28.2
|
// protoc v3.18.0
|
||||||
// source: app/policy/config.proto
|
// source: app/policy/config.proto
|
||||||
|
|
||||||
package policy
|
package policy
|
||||||
@@ -30,9 +30,11 @@ type Second struct {
|
|||||||
|
|
||||||
func (x *Second) Reset() {
|
func (x *Second) Reset() {
|
||||||
*x = Second{}
|
*x = Second{}
|
||||||
mi := &file_app_policy_config_proto_msgTypes[0]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_policy_config_proto_msgTypes[0]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Second) String() string {
|
func (x *Second) String() string {
|
||||||
@@ -43,7 +45,7 @@ func (*Second) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *Second) ProtoReflect() protoreflect.Message {
|
func (x *Second) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_policy_config_proto_msgTypes[0]
|
mi := &file_app_policy_config_proto_msgTypes[0]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -77,9 +79,11 @@ type Policy struct {
|
|||||||
|
|
||||||
func (x *Policy) Reset() {
|
func (x *Policy) Reset() {
|
||||||
*x = Policy{}
|
*x = Policy{}
|
||||||
mi := &file_app_policy_config_proto_msgTypes[1]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_policy_config_proto_msgTypes[1]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Policy) String() string {
|
func (x *Policy) String() string {
|
||||||
@@ -90,7 +94,7 @@ func (*Policy) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *Policy) ProtoReflect() protoreflect.Message {
|
func (x *Policy) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_policy_config_proto_msgTypes[1]
|
mi := &file_app_policy_config_proto_msgTypes[1]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -136,9 +140,11 @@ type SystemPolicy struct {
|
|||||||
|
|
||||||
func (x *SystemPolicy) Reset() {
|
func (x *SystemPolicy) Reset() {
|
||||||
*x = SystemPolicy{}
|
*x = SystemPolicy{}
|
||||||
mi := &file_app_policy_config_proto_msgTypes[2]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_policy_config_proto_msgTypes[2]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SystemPolicy) String() string {
|
func (x *SystemPolicy) String() string {
|
||||||
@@ -149,7 +155,7 @@ func (*SystemPolicy) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *SystemPolicy) ProtoReflect() protoreflect.Message {
|
func (x *SystemPolicy) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_policy_config_proto_msgTypes[2]
|
mi := &file_app_policy_config_proto_msgTypes[2]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -182,9 +188,11 @@ type Config struct {
|
|||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
mi := &file_app_policy_config_proto_msgTypes[3]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_policy_config_proto_msgTypes[3]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) String() string {
|
func (x *Config) String() string {
|
||||||
@@ -195,7 +203,7 @@ func (*Config) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_policy_config_proto_msgTypes[3]
|
mi := &file_app_policy_config_proto_msgTypes[3]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -238,9 +246,11 @@ type Policy_Timeout struct {
|
|||||||
|
|
||||||
func (x *Policy_Timeout) Reset() {
|
func (x *Policy_Timeout) Reset() {
|
||||||
*x = Policy_Timeout{}
|
*x = Policy_Timeout{}
|
||||||
mi := &file_app_policy_config_proto_msgTypes[4]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_policy_config_proto_msgTypes[4]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Policy_Timeout) String() string {
|
func (x *Policy_Timeout) String() string {
|
||||||
@@ -251,7 +261,7 @@ func (*Policy_Timeout) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *Policy_Timeout) ProtoReflect() protoreflect.Message {
|
func (x *Policy_Timeout) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_policy_config_proto_msgTypes[4]
|
mi := &file_app_policy_config_proto_msgTypes[4]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -301,14 +311,15 @@ type Policy_Stats struct {
|
|||||||
|
|
||||||
UserUplink bool `protobuf:"varint,1,opt,name=user_uplink,json=userUplink,proto3" json:"user_uplink,omitempty"`
|
UserUplink bool `protobuf:"varint,1,opt,name=user_uplink,json=userUplink,proto3" json:"user_uplink,omitempty"`
|
||||||
UserDownlink bool `protobuf:"varint,2,opt,name=user_downlink,json=userDownlink,proto3" json:"user_downlink,omitempty"`
|
UserDownlink bool `protobuf:"varint,2,opt,name=user_downlink,json=userDownlink,proto3" json:"user_downlink,omitempty"`
|
||||||
UserOnline bool `protobuf:"varint,3,opt,name=user_online,json=userOnline,proto3" json:"user_online,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Policy_Stats) Reset() {
|
func (x *Policy_Stats) Reset() {
|
||||||
*x = Policy_Stats{}
|
*x = Policy_Stats{}
|
||||||
mi := &file_app_policy_config_proto_msgTypes[5]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_policy_config_proto_msgTypes[5]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Policy_Stats) String() string {
|
func (x *Policy_Stats) String() string {
|
||||||
@@ -319,7 +330,7 @@ func (*Policy_Stats) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *Policy_Stats) ProtoReflect() protoreflect.Message {
|
func (x *Policy_Stats) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_policy_config_proto_msgTypes[5]
|
mi := &file_app_policy_config_proto_msgTypes[5]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -348,13 +359,6 @@ func (x *Policy_Stats) GetUserDownlink() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Policy_Stats) GetUserOnline() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.UserOnline
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type Policy_Buffer struct {
|
type Policy_Buffer struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -366,9 +370,11 @@ type Policy_Buffer struct {
|
|||||||
|
|
||||||
func (x *Policy_Buffer) Reset() {
|
func (x *Policy_Buffer) Reset() {
|
||||||
*x = Policy_Buffer{}
|
*x = Policy_Buffer{}
|
||||||
mi := &file_app_policy_config_proto_msgTypes[6]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_policy_config_proto_msgTypes[6]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Policy_Buffer) String() string {
|
func (x *Policy_Buffer) String() string {
|
||||||
@@ -379,7 +385,7 @@ func (*Policy_Buffer) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *Policy_Buffer) ProtoReflect() protoreflect.Message {
|
func (x *Policy_Buffer) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_policy_config_proto_msgTypes[6]
|
mi := &file_app_policy_config_proto_msgTypes[6]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -414,9 +420,11 @@ type SystemPolicy_Stats struct {
|
|||||||
|
|
||||||
func (x *SystemPolicy_Stats) Reset() {
|
func (x *SystemPolicy_Stats) Reset() {
|
||||||
*x = SystemPolicy_Stats{}
|
*x = SystemPolicy_Stats{}
|
||||||
mi := &file_app_policy_config_proto_msgTypes[7]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_policy_config_proto_msgTypes[7]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SystemPolicy_Stats) String() string {
|
func (x *SystemPolicy_Stats) String() string {
|
||||||
@@ -427,7 +435,7 @@ func (*SystemPolicy_Stats) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *SystemPolicy_Stats) ProtoReflect() protoreflect.Message {
|
func (x *SystemPolicy_Stats) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_policy_config_proto_msgTypes[7]
|
mi := &file_app_policy_config_proto_msgTypes[7]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -477,7 +485,7 @@ var file_app_policy_config_proto_rawDesc = []byte{
|
|||||||
0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x1e, 0x0a, 0x06, 0x53, 0x65,
|
0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x1e, 0x0a, 0x06, 0x53, 0x65,
|
||||||
0x63, 0x6f, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20,
|
0x63, 0x6f, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20,
|
||||||
0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xc7, 0x04, 0x0a, 0x06, 0x50,
|
0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xa6, 0x04, 0x0a, 0x06, 0x50,
|
||||||
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x39, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
|
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x39, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||||
0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
|
0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
|
||||||
@@ -504,51 +512,49 @@ var file_app_policy_config_proto_rawDesc = []byte{
|
|||||||
0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x04, 0x20,
|
0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x04, 0x20,
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
|
0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
|
||||||
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x52, 0x0c, 0x64, 0x6f,
|
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x52, 0x0c, 0x64, 0x6f,
|
||||||
0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4f, 0x6e, 0x6c, 0x79, 0x1a, 0x6e, 0x0a, 0x05, 0x53, 0x74,
|
0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4f, 0x6e, 0x6c, 0x79, 0x1a, 0x4d, 0x0a, 0x05, 0x53, 0x74,
|
||||||
0x61, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x75, 0x70, 0x6c, 0x69,
|
0x61, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x75, 0x70, 0x6c, 0x69,
|
||||||
0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x55, 0x70,
|
0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x55, 0x70,
|
||||||
0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x77,
|
0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x77,
|
||||||
0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x73, 0x65,
|
0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x73, 0x65,
|
||||||
0x72, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65,
|
0x72, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x1a, 0x28, 0x0a, 0x06, 0x42, 0x75, 0x66,
|
||||||
0x72, 0x5f, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a,
|
0x66, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||||
0x75, 0x73, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x1a, 0x28, 0x0a, 0x06, 0x42, 0x75,
|
0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
|
||||||
0x66, 0x66, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
|
0x69, 0x6f, 0x6e, 0x22, 0xfb, 0x01, 0x0a, 0x0c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x50, 0x6f,
|
||||||
0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
0x6c, 0x69, 0x63, 0x79, 0x12, 0x39, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20,
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x22, 0xfb, 0x01, 0x0a, 0x0c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x50,
|
0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
|
||||||
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x39, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01,
|
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x50, 0x6f, 0x6c, 0x69,
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
0x63, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x1a,
|
||||||
0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x50, 0x6f, 0x6c,
|
0xaf, 0x01, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x62,
|
||||||
0x69, 0x63, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73,
|
0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x1a, 0xaf, 0x01, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e,
|
0x08, 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b,
|
||||||
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01,
|
0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e,
|
||||||
0x28, 0x08, 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x70, 0x6c, 0x69, 0x6e,
|
0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x6e, 0x62, 0x6f,
|
||||||
0x6b, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x64, 0x6f, 0x77,
|
0x75, 0x6e, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x27, 0x0a, 0x0f, 0x6f,
|
||||||
0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x6e, 0x62,
|
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x03,
|
||||||
0x6f, 0x75, 0x6e, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x27, 0x0a, 0x0f,
|
0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x70,
|
||||||
0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x18,
|
0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,
|
||||||
0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55,
|
0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||||
0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e,
|
0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e,
|
||||||
0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08,
|
0x6b, 0x22, 0xcc, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x38, 0x0a, 0x05,
|
||||||
0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69,
|
0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x72,
|
||||||
0x6e, 0x6b, 0x22, 0xcc, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x38, 0x0a,
|
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x43, 0x6f,
|
||||||
0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78,
|
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x43,
|
0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x35, 0x0a, 0x06, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d,
|
||||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||||
0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x35, 0x0a, 0x06, 0x73, 0x79, 0x73, 0x74, 0x65,
|
0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x50,
|
||||||
0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
|
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x06, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x1a, 0x51, 0x0a,
|
||||||
0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d,
|
0x0a, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
|
||||||
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x06, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x1a, 0x51,
|
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a,
|
||||||
0x0a, 0x0a, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
|
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x78,
|
||||||
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d,
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50,
|
||||||
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
|
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
|
0x42, 0x4f, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
|
0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x50, 0x01, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||||
0x01, 0x42, 0x4f, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d,
|
||||||
0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x50, 0x01, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68,
|
0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0xaa,
|
||||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
0x02, 0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63,
|
||||||
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
|
0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0xaa, 0x02, 0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x6f, 0x6c, 0x69,
|
|
||||||
0x63, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -564,7 +570,7 @@ func file_app_policy_config_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_app_policy_config_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
|
var file_app_policy_config_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
|
||||||
var file_app_policy_config_proto_goTypes = []any{
|
var file_app_policy_config_proto_goTypes = []interface{}{
|
||||||
(*Second)(nil), // 0: xray.app.policy.Second
|
(*Second)(nil), // 0: xray.app.policy.Second
|
||||||
(*Policy)(nil), // 1: xray.app.policy.Policy
|
(*Policy)(nil), // 1: xray.app.policy.Policy
|
||||||
(*SystemPolicy)(nil), // 2: xray.app.policy.SystemPolicy
|
(*SystemPolicy)(nil), // 2: xray.app.policy.SystemPolicy
|
||||||
@@ -599,6 +605,104 @@ func file_app_policy_config_proto_init() {
|
|||||||
if File_app_policy_config_proto != nil {
|
if File_app_policy_config_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_app_policy_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Second); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_policy_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Policy); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_policy_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*SystemPolicy); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_policy_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Config); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_policy_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Policy_Timeout); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_policy_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Policy_Stats); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_policy_config_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Policy_Buffer); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_policy_config_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*SystemPolicy_Stats); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ message Policy {
|
|||||||
message Stats {
|
message Stats {
|
||||||
bool user_uplink = 1;
|
bool user_uplink = 1;
|
||||||
bool user_downlink = 2;
|
bool user_downlink = 2;
|
||||||
bool user_online = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message Buffer {
|
message Buffer {
|
||||||
|
|||||||
9
app/policy/errors.generated.go
Normal file
9
app/policy/errors.generated.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package policy
|
||||||
|
|
||||||
|
import "github.com/xtls/xray-core/common/errors"
|
||||||
|
|
||||||
|
type errPathObjHolder struct{}
|
||||||
|
|
||||||
|
func newError(values ...interface{}) *errors.Error {
|
||||||
|
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||||
|
}
|
||||||
@@ -1,2 +1,4 @@
|
|||||||
// Package policy is an implementation of policy.Manager feature.
|
// Package policy is an implementation of policy.Manager feature.
|
||||||
package policy
|
package policy
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ package command
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/commander"
|
grpc "google.golang.org/grpc"
|
||||||
|
|
||||||
"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/protocol"
|
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/inbound"
|
"github.com/xtls/xray-core/features/inbound"
|
||||||
"github.com/xtls/xray-core/features/outbound"
|
"github.com/xtls/xray-core/features/outbound"
|
||||||
"github.com/xtls/xray-core/proxy"
|
"github.com/xtls/xray-core/proxy"
|
||||||
grpc "google.golang.org/grpc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// InboundOperation is the interface for operations that applies to inbound handlers.
|
// InboundOperation is the interface for operations that applies to inbound handlers.
|
||||||
@@ -29,7 +27,7 @@ type OutboundOperation interface {
|
|||||||
func getInbound(handler inbound.Handler) (proxy.Inbound, error) {
|
func getInbound(handler inbound.Handler) (proxy.Inbound, error) {
|
||||||
gi, ok := handler.(proxy.GetInbound)
|
gi, ok := handler.(proxy.GetInbound)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("can't get inbound proxy from handler.")
|
return nil, newError("can't get inbound proxy from handler.")
|
||||||
}
|
}
|
||||||
return gi.GetInbound(), nil
|
return gi.GetInbound(), nil
|
||||||
}
|
}
|
||||||
@@ -42,11 +40,11 @@ func (op *AddUserOperation) ApplyInbound(ctx context.Context, handler inbound.Ha
|
|||||||
}
|
}
|
||||||
um, ok := p.(proxy.UserManager)
|
um, ok := p.(proxy.UserManager)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("proxy is not a UserManager")
|
return newError("proxy is not a UserManager")
|
||||||
}
|
}
|
||||||
mUser, err := op.User.ToMemoryUser()
|
mUser, err := op.User.ToMemoryUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to parse user").Base(err)
|
return newError("failed to parse user").Base(err)
|
||||||
}
|
}
|
||||||
return um.AddUser(ctx, mUser)
|
return um.AddUser(ctx, mUser)
|
||||||
}
|
}
|
||||||
@@ -59,7 +57,7 @@ func (op *RemoveUserOperation) ApplyInbound(ctx context.Context, handler inbound
|
|||||||
}
|
}
|
||||||
um, ok := p.(proxy.UserManager)
|
um, ok := p.(proxy.UserManager)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("proxy is not a UserManager")
|
return newError("proxy is not a UserManager")
|
||||||
}
|
}
|
||||||
return um.RemoveUser(ctx, op.Email)
|
return um.RemoveUser(ctx, op.Email)
|
||||||
}
|
}
|
||||||
@@ -85,83 +83,21 @@ func (s *handlerServer) RemoveInbound(ctx context.Context, request *RemoveInboun
|
|||||||
func (s *handlerServer) AlterInbound(ctx context.Context, request *AlterInboundRequest) (*AlterInboundResponse, error) {
|
func (s *handlerServer) AlterInbound(ctx context.Context, request *AlterInboundRequest) (*AlterInboundResponse, error) {
|
||||||
rawOperation, err := request.Operation.GetInstance()
|
rawOperation, err := request.Operation.GetInstance()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("unknown operation").Base(err)
|
return nil, newError("unknown operation").Base(err)
|
||||||
}
|
}
|
||||||
operation, ok := rawOperation.(InboundOperation)
|
operation, ok := rawOperation.(InboundOperation)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an inbound operation")
|
return nil, newError("not an inbound operation")
|
||||||
}
|
}
|
||||||
|
|
||||||
handler, err := s.ihm.GetHandler(ctx, request.Tag)
|
handler, err := s.ihm.GetHandler(ctx, request.Tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to get handler: ", request.Tag).Base(err)
|
return nil, newError("failed to get handler: ", request.Tag).Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|
||||||
handler, err := s.ihm.GetHandler(ctx, request.Tag)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("failed to get handler: ", request.Tag).Base(err)
|
|
||||||
}
|
|
||||||
p, err := getInbound(handler)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
um, ok := p.(proxy.UserManager)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("proxy is not a UserManager")
|
|
||||||
}
|
|
||||||
if len(request.Email) > 0 {
|
|
||||||
return &GetInboundUserResponse{Users: []*protocol.User{protocol.ToProtoUser(um.GetUser(ctx, request.Email))}}, nil
|
|
||||||
}
|
|
||||||
var result = make([]*protocol.User, 0, 100)
|
|
||||||
users := um.GetUsers(ctx)
|
|
||||||
for _, u := range users {
|
|
||||||
result = append(result, protocol.ToProtoUser(u))
|
|
||||||
}
|
|
||||||
return &GetInboundUserResponse{Users: result}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *handlerServer) GetInboundUsersCount(ctx context.Context, request *GetInboundUserRequest) (*GetInboundUsersCountResponse, error) {
|
|
||||||
handler, err := s.ihm.GetHandler(ctx, request.Tag)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("failed to get handler: ", request.Tag).Base(err)
|
|
||||||
}
|
|
||||||
p, err := getInbound(handler)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
um, ok := p.(proxy.UserManager)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("proxy is not a UserManager")
|
|
||||||
}
|
|
||||||
return &GetInboundUsersCountResponse{Count: um.GetUsersCount(ctx)}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *handlerServer) AddOutbound(ctx context.Context, request *AddOutboundRequest) (*AddOutboundResponse, error) {
|
func (s *handlerServer) AddOutbound(ctx context.Context, request *AddOutboundRequest) (*AddOutboundResponse, error) {
|
||||||
if err := core.AddOutboundHandler(s.s, request.Outbound); err != nil {
|
if err := core.AddOutboundHandler(s.s, request.Outbound); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -176,34 +112,17 @@ func (s *handlerServer) RemoveOutbound(ctx context.Context, request *RemoveOutbo
|
|||||||
func (s *handlerServer) AlterOutbound(ctx context.Context, request *AlterOutboundRequest) (*AlterOutboundResponse, error) {
|
func (s *handlerServer) AlterOutbound(ctx context.Context, request *AlterOutboundRequest) (*AlterOutboundResponse, error) {
|
||||||
rawOperation, err := request.Operation.GetInstance()
|
rawOperation, err := request.Operation.GetInstance()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("unknown operation").Base(err)
|
return nil, newError("unknown operation").Base(err)
|
||||||
}
|
}
|
||||||
operation, ok := rawOperation.(OutboundOperation)
|
operation, ok := rawOperation.(OutboundOperation)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an outbound operation")
|
return nil, newError("not an outbound operation")
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := s.ohm.GetHandler(request.Tag)
|
handler := s.ohm.GetHandler(request.Tag)
|
||||||
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 {
|
||||||
@@ -217,7 +136,7 @@ func (s *service) Register(server *grpc.Server) {
|
|||||||
common.Must(s.v.RequireFeatures(func(im inbound.Manager, om outbound.Manager) {
|
common.Must(s.v.RequireFeatures(func(im inbound.Manager, om outbound.Manager) {
|
||||||
hs.ihm = im
|
hs.ihm = im
|
||||||
hs.ohm = om
|
hs.ohm = om
|
||||||
}, false))
|
}))
|
||||||
RegisterHandlerServiceServer(server, hs)
|
RegisterHandlerServiceServer(server, hs)
|
||||||
|
|
||||||
// For compatibility purposes
|
// For compatibility purposes
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -37,27 +37,6 @@ message AlterInboundRequest {
|
|||||||
|
|
||||||
message AlterInboundResponse {}
|
message AlterInboundResponse {}
|
||||||
|
|
||||||
message ListInboundsRequest {
|
|
||||||
bool isOnlyTags = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ListInboundsResponse {
|
|
||||||
repeated core.InboundHandlerConfig inbounds = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message GetInboundUserRequest {
|
|
||||||
string tag = 1;
|
|
||||||
string email = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message GetInboundUserResponse {
|
|
||||||
repeated xray.common.protocol.User users = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message GetInboundUsersCountResponse {
|
|
||||||
int64 count = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message AddOutboundRequest {
|
message AddOutboundRequest {
|
||||||
core.OutboundHandlerConfig outbound = 1;
|
core.OutboundHandlerConfig outbound = 1;
|
||||||
}
|
}
|
||||||
@@ -77,12 +56,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,19 +63,11 @@ service HandlerService {
|
|||||||
|
|
||||||
rpc AlterInbound(AlterInboundRequest) returns (AlterInboundResponse) {}
|
rpc AlterInbound(AlterInboundRequest) returns (AlterInboundResponse) {}
|
||||||
|
|
||||||
rpc ListInbounds(ListInboundsRequest) returns (ListInboundsResponse) {}
|
|
||||||
|
|
||||||
rpc GetInboundUsers(GetInboundUserRequest) returns (GetInboundUserResponse) {}
|
|
||||||
|
|
||||||
rpc GetInboundUsersCount(GetInboundUserRequest) returns (GetInboundUsersCountResponse) {}
|
|
||||||
|
|
||||||
rpc AddOutbound(AddOutboundRequest) returns (AddOutboundResponse) {}
|
rpc AddOutbound(AddOutboundRequest) returns (AddOutboundResponse) {}
|
||||||
|
|
||||||
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 {}
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
// versions:
|
|
||||||
// - protoc-gen-go-grpc v1.5.1
|
|
||||||
// - protoc v5.28.2
|
|
||||||
// source: app/proxyman/command/command.proto
|
|
||||||
|
|
||||||
package command
|
package command
|
||||||
|
|
||||||
@@ -15,21 +11,8 @@ import (
|
|||||||
|
|
||||||
// This is a compile-time assertion to ensure that this generated file
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
// is compatible with the grpc package it is being compiled against.
|
// is compatible with the grpc package it is being compiled against.
|
||||||
// Requires gRPC-Go v1.64.0 or later.
|
// Requires gRPC-Go v1.32.0 or later.
|
||||||
const _ = grpc.SupportPackageIsVersion9
|
const _ = grpc.SupportPackageIsVersion7
|
||||||
|
|
||||||
const (
|
|
||||||
HandlerService_AddInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AddInbound"
|
|
||||||
HandlerService_RemoveInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/RemoveInbound"
|
|
||||||
HandlerService_AlterInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AlterInbound"
|
|
||||||
HandlerService_ListInbounds_FullMethodName = "/xray.app.proxyman.command.HandlerService/ListInbounds"
|
|
||||||
HandlerService_GetInboundUsers_FullMethodName = "/xray.app.proxyman.command.HandlerService/GetInboundUsers"
|
|
||||||
HandlerService_GetInboundUsersCount_FullMethodName = "/xray.app.proxyman.command.HandlerService/GetInboundUsersCount"
|
|
||||||
HandlerService_AddOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AddOutbound"
|
|
||||||
HandlerService_RemoveOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/RemoveOutbound"
|
|
||||||
HandlerService_AlterOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AlterOutbound"
|
|
||||||
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 +21,9 @@ 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)
|
|
||||||
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 {
|
||||||
@@ -56,9 +35,8 @@ func NewHandlerServiceClient(cc grpc.ClientConnInterface) HandlerServiceClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *handlerServiceClient) AddInbound(ctx context.Context, in *AddInboundRequest, opts ...grpc.CallOption) (*AddInboundResponse, error) {
|
func (c *handlerServiceClient) AddInbound(ctx context.Context, in *AddInboundRequest, opts ...grpc.CallOption) (*AddInboundResponse, error) {
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(AddInboundResponse)
|
out := new(AddInboundResponse)
|
||||||
err := c.cc.Invoke(ctx, HandlerService_AddInbound_FullMethodName, in, out, cOpts...)
|
err := c.cc.Invoke(ctx, "/xray.app.proxyman.command.HandlerService/AddInbound", in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -66,9 +44,8 @@ func (c *handlerServiceClient) AddInbound(ctx context.Context, in *AddInboundReq
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *handlerServiceClient) RemoveInbound(ctx context.Context, in *RemoveInboundRequest, opts ...grpc.CallOption) (*RemoveInboundResponse, error) {
|
func (c *handlerServiceClient) RemoveInbound(ctx context.Context, in *RemoveInboundRequest, opts ...grpc.CallOption) (*RemoveInboundResponse, error) {
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(RemoveInboundResponse)
|
out := new(RemoveInboundResponse)
|
||||||
err := c.cc.Invoke(ctx, HandlerService_RemoveInbound_FullMethodName, in, out, cOpts...)
|
err := c.cc.Invoke(ctx, "/xray.app.proxyman.command.HandlerService/RemoveInbound", in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -76,39 +53,8 @@ func (c *handlerServiceClient) RemoveInbound(ctx context.Context, in *RemoveInbo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *handlerServiceClient) AlterInbound(ctx context.Context, in *AlterInboundRequest, opts ...grpc.CallOption) (*AlterInboundResponse, error) {
|
func (c *handlerServiceClient) AlterInbound(ctx context.Context, in *AlterInboundRequest, opts ...grpc.CallOption) (*AlterInboundResponse, error) {
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(AlterInboundResponse)
|
out := new(AlterInboundResponse)
|
||||||
err := c.cc.Invoke(ctx, HandlerService_AlterInbound_FullMethodName, in, out, cOpts...)
|
err := c.cc.Invoke(ctx, "/xray.app.proxyman.command.HandlerService/AlterInbound", in, out, opts...)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(GetInboundUserResponse)
|
|
||||||
err := c.cc.Invoke(ctx, HandlerService_GetInboundUsers_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *handlerServiceClient) GetInboundUsersCount(ctx context.Context, in *GetInboundUserRequest, opts ...grpc.CallOption) (*GetInboundUsersCountResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(GetInboundUsersCountResponse)
|
|
||||||
err := c.cc.Invoke(ctx, HandlerService_GetInboundUsersCount_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -116,9 +62,8 @@ func (c *handlerServiceClient) GetInboundUsersCount(ctx context.Context, in *Get
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *handlerServiceClient) AddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error) {
|
func (c *handlerServiceClient) AddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error) {
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(AddOutboundResponse)
|
out := new(AddOutboundResponse)
|
||||||
err := c.cc.Invoke(ctx, HandlerService_AddOutbound_FullMethodName, in, out, cOpts...)
|
err := c.cc.Invoke(ctx, "/xray.app.proxyman.command.HandlerService/AddOutbound", in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -126,9 +71,8 @@ func (c *handlerServiceClient) AddOutbound(ctx context.Context, in *AddOutboundR
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *handlerServiceClient) RemoveOutbound(ctx context.Context, in *RemoveOutboundRequest, opts ...grpc.CallOption) (*RemoveOutboundResponse, error) {
|
func (c *handlerServiceClient) RemoveOutbound(ctx context.Context, in *RemoveOutboundRequest, opts ...grpc.CallOption) (*RemoveOutboundResponse, error) {
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(RemoveOutboundResponse)
|
out := new(RemoveOutboundResponse)
|
||||||
err := c.cc.Invoke(ctx, HandlerService_RemoveOutbound_FullMethodName, in, out, cOpts...)
|
err := c.cc.Invoke(ctx, "/xray.app.proxyman.command.HandlerService/RemoveOutbound", in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -136,19 +80,8 @@ func (c *handlerServiceClient) RemoveOutbound(ctx context.Context, in *RemoveOut
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *handlerServiceClient) AlterOutbound(ctx context.Context, in *AlterOutboundRequest, opts ...grpc.CallOption) (*AlterOutboundResponse, error) {
|
func (c *handlerServiceClient) AlterOutbound(ctx context.Context, in *AlterOutboundRequest, opts ...grpc.CallOption) (*AlterOutboundResponse, error) {
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(AlterOutboundResponse)
|
out := new(AlterOutboundResponse)
|
||||||
err := c.cc.Invoke(ctx, HandlerService_AlterOutbound_FullMethodName, in, out, cOpts...)
|
err := c.cc.Invoke(ctx, "/xray.app.proxyman.command.HandlerService/AlterOutbound", in, out, opts...)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -157,27 +90,20 @@ func (c *handlerServiceClient) ListOutbounds(ctx context.Context, in *ListOutbou
|
|||||||
|
|
||||||
// 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
|
||||||
type HandlerServiceServer interface {
|
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)
|
|
||||||
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()
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnimplementedHandlerServiceServer must be embedded to have
|
// UnimplementedHandlerServiceServer must be embedded to have forward compatible implementations.
|
||||||
// forward compatible implementations.
|
type UnimplementedHandlerServiceServer struct {
|
||||||
//
|
}
|
||||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
|
||||||
// pointer dereference when methods are called.
|
|
||||||
type UnimplementedHandlerServiceServer struct{}
|
|
||||||
|
|
||||||
func (UnimplementedHandlerServiceServer) AddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error) {
|
func (UnimplementedHandlerServiceServer) AddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method AddInbound not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method AddInbound not implemented")
|
||||||
@@ -188,15 +114,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) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetInboundUsers not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedHandlerServiceServer) GetInboundUsersCount(context.Context, *GetInboundUserRequest) (*GetInboundUsersCountResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetInboundUsersCount not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedHandlerServiceServer) AddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error) {
|
func (UnimplementedHandlerServiceServer) AddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method AddOutbound not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method AddOutbound not implemented")
|
||||||
}
|
}
|
||||||
@@ -206,11 +123,7 @@ 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() {}
|
|
||||||
|
|
||||||
// UnsafeHandlerServiceServer may be embedded to opt out of forward compatibility for this service.
|
// UnsafeHandlerServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
// Use of this interface is not recommended, as added methods to HandlerServiceServer will
|
// Use of this interface is not recommended, as added methods to HandlerServiceServer will
|
||||||
@@ -220,13 +133,6 @@ type UnsafeHandlerServiceServer interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RegisterHandlerServiceServer(s grpc.ServiceRegistrar, srv HandlerServiceServer) {
|
func RegisterHandlerServiceServer(s grpc.ServiceRegistrar, srv HandlerServiceServer) {
|
||||||
// If the following call pancis, it indicates UnimplementedHandlerServiceServer was
|
|
||||||
// embedded by pointer and is nil. This will cause panics if an
|
|
||||||
// unimplemented method is ever invoked, so we test this at initialization
|
|
||||||
// time to prevent it from happening at runtime later due to I/O.
|
|
||||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
|
||||||
t.testEmbeddedByValue()
|
|
||||||
}
|
|
||||||
s.RegisterService(&HandlerService_ServiceDesc, srv)
|
s.RegisterService(&HandlerService_ServiceDesc, srv)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +146,7 @@ func _HandlerService_AddInbound_Handler(srv interface{}, ctx context.Context, de
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HandlerService_AddInbound_FullMethodName,
|
FullMethod: "/xray.app.proxyman.command.HandlerService/AddInbound",
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HandlerServiceServer).AddInbound(ctx, req.(*AddInboundRequest))
|
return srv.(HandlerServiceServer).AddInbound(ctx, req.(*AddInboundRequest))
|
||||||
@@ -258,7 +164,7 @@ func _HandlerService_RemoveInbound_Handler(srv interface{}, ctx context.Context,
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HandlerService_RemoveInbound_FullMethodName,
|
FullMethod: "/xray.app.proxyman.command.HandlerService/RemoveInbound",
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HandlerServiceServer).RemoveInbound(ctx, req.(*RemoveInboundRequest))
|
return srv.(HandlerServiceServer).RemoveInbound(ctx, req.(*RemoveInboundRequest))
|
||||||
@@ -276,7 +182,7 @@ func _HandlerService_AlterInbound_Handler(srv interface{}, ctx context.Context,
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HandlerService_AlterInbound_FullMethodName,
|
FullMethod: "/xray.app.proxyman.command.HandlerService/AlterInbound",
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HandlerServiceServer).AlterInbound(ctx, req.(*AlterInboundRequest))
|
return srv.(HandlerServiceServer).AlterInbound(ctx, req.(*AlterInboundRequest))
|
||||||
@@ -284,60 +190,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) {
|
|
||||||
in := new(GetInboundUserRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(HandlerServiceServer).GetInboundUsers(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: HandlerService_GetInboundUsers_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(HandlerServiceServer).GetInboundUsers(ctx, req.(*GetInboundUserRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _HandlerService_GetInboundUsersCount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(GetInboundUserRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(HandlerServiceServer).GetInboundUsersCount(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: HandlerService_GetInboundUsersCount_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(HandlerServiceServer).GetInboundUsersCount(ctx, req.(*GetInboundUserRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _HandlerService_AddOutbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _HandlerService_AddOutbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(AddOutboundRequest)
|
in := new(AddOutboundRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
@@ -348,7 +200,7 @@ func _HandlerService_AddOutbound_Handler(srv interface{}, ctx context.Context, d
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HandlerService_AddOutbound_FullMethodName,
|
FullMethod: "/xray.app.proxyman.command.HandlerService/AddOutbound",
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HandlerServiceServer).AddOutbound(ctx, req.(*AddOutboundRequest))
|
return srv.(HandlerServiceServer).AddOutbound(ctx, req.(*AddOutboundRequest))
|
||||||
@@ -366,7 +218,7 @@ func _HandlerService_RemoveOutbound_Handler(srv interface{}, ctx context.Context
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HandlerService_RemoveOutbound_FullMethodName,
|
FullMethod: "/xray.app.proxyman.command.HandlerService/RemoveOutbound",
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HandlerServiceServer).RemoveOutbound(ctx, req.(*RemoveOutboundRequest))
|
return srv.(HandlerServiceServer).RemoveOutbound(ctx, req.(*RemoveOutboundRequest))
|
||||||
@@ -384,7 +236,7 @@ func _HandlerService_AlterOutbound_Handler(srv interface{}, ctx context.Context,
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: HandlerService_AlterOutbound_FullMethodName,
|
FullMethod: "/xray.app.proxyman.command.HandlerService/AlterOutbound",
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(HandlerServiceServer).AlterOutbound(ctx, req.(*AlterOutboundRequest))
|
return srv.(HandlerServiceServer).AlterOutbound(ctx, req.(*AlterOutboundRequest))
|
||||||
@@ -392,24 +244,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,18 +263,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",
|
|
||||||
Handler: _HandlerService_GetInboundUsers_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "GetInboundUsersCount",
|
|
||||||
Handler: _HandlerService_GetInboundUsersCount_Handler,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
MethodName: "AddOutbound",
|
MethodName: "AddOutbound",
|
||||||
Handler: _HandlerService_AddOutbound_Handler,
|
Handler: _HandlerService_AddOutbound_Handler,
|
||||||
@@ -453,10 +275,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,3 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|||||||
9
app/proxyman/command/errors.generated.go
Normal file
9
app/proxyman/command/errors.generated.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import "github.com/xtls/xray-core/common/errors"
|
||||||
|
|
||||||
|
type errPathObjHolder struct{}
|
||||||
|
|
||||||
|
func newError(values ...interface{}) *errors.Error {
|
||||||
|
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||||
|
}
|
||||||
@@ -19,5 +19,21 @@ func (c *ReceiverConfig) GetEffectiveSniffingSettings() *SniffingConfig {
|
|||||||
return c.SniffingSettings
|
return c.SniffingSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(c.DomainOverride) > 0 {
|
||||||
|
var p []string
|
||||||
|
for _, kd := range c.DomainOverride {
|
||||||
|
switch kd {
|
||||||
|
case KnownProtocols_HTTP:
|
||||||
|
p = append(p, "http")
|
||||||
|
case KnownProtocols_TLS:
|
||||||
|
p = append(p, "tls")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &SniffingConfig{
|
||||||
|
Enabled: true,
|
||||||
|
DestinationOverride: p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.27.1
|
||||||
// protoc v5.28.2
|
// protoc v3.18.0
|
||||||
// source: app/proxyman/config.proto
|
// source: app/proxyman/config.proto
|
||||||
|
|
||||||
package proxyman
|
package proxyman
|
||||||
@@ -23,6 +23,110 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type KnownProtocols int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
KnownProtocols_HTTP KnownProtocols = 0
|
||||||
|
KnownProtocols_TLS KnownProtocols = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for KnownProtocols.
|
||||||
|
var (
|
||||||
|
KnownProtocols_name = map[int32]string{
|
||||||
|
0: "HTTP",
|
||||||
|
1: "TLS",
|
||||||
|
}
|
||||||
|
KnownProtocols_value = map[string]int32{
|
||||||
|
"HTTP": 0,
|
||||||
|
"TLS": 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x KnownProtocols) Enum() *KnownProtocols {
|
||||||
|
p := new(KnownProtocols)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x KnownProtocols) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (KnownProtocols) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_app_proxyman_config_proto_enumTypes[0].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (KnownProtocols) Type() protoreflect.EnumType {
|
||||||
|
return &file_app_proxyman_config_proto_enumTypes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x KnownProtocols) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use KnownProtocols.Descriptor instead.
|
||||||
|
func (KnownProtocols) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
type DomainStrategy int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
DomainStrategy_AS_IS DomainStrategy = 0
|
||||||
|
DomainStrategy_USE_IP DomainStrategy = 1
|
||||||
|
DomainStrategy_USE_IP4 DomainStrategy = 2
|
||||||
|
DomainStrategy_USE_IP6 DomainStrategy = 3
|
||||||
|
DomainStrategy_PREFER_IP4 DomainStrategy = 4
|
||||||
|
DomainStrategy_PREFER_IP6 DomainStrategy = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for DomainStrategy.
|
||||||
|
var (
|
||||||
|
DomainStrategy_name = map[int32]string{
|
||||||
|
0: "AS_IS",
|
||||||
|
1: "USE_IP",
|
||||||
|
2: "USE_IP4",
|
||||||
|
3: "USE_IP6",
|
||||||
|
4: "PREFER_IP4",
|
||||||
|
5: "PREFER_IP6",
|
||||||
|
}
|
||||||
|
DomainStrategy_value = map[string]int32{
|
||||||
|
"AS_IS": 0,
|
||||||
|
"USE_IP": 1,
|
||||||
|
"USE_IP4": 2,
|
||||||
|
"USE_IP6": 3,
|
||||||
|
"PREFER_IP4": 4,
|
||||||
|
"PREFER_IP6": 5,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x DomainStrategy) Enum() *DomainStrategy {
|
||||||
|
p := new(DomainStrategy)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x DomainStrategy) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (DomainStrategy) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_app_proxyman_config_proto_enumTypes[1].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (DomainStrategy) Type() protoreflect.EnumType {
|
||||||
|
return &file_app_proxyman_config_proto_enumTypes[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x DomainStrategy) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use DomainStrategy.Descriptor instead.
|
||||||
|
func (DomainStrategy) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
type AllocationStrategy_Type int32
|
type AllocationStrategy_Type int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -59,11 +163,11 @@ func (x AllocationStrategy_Type) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (AllocationStrategy_Type) Descriptor() protoreflect.EnumDescriptor {
|
func (AllocationStrategy_Type) Descriptor() protoreflect.EnumDescriptor {
|
||||||
return file_app_proxyman_config_proto_enumTypes[0].Descriptor()
|
return file_app_proxyman_config_proto_enumTypes[2].Descriptor()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (AllocationStrategy_Type) Type() protoreflect.EnumType {
|
func (AllocationStrategy_Type) Type() protoreflect.EnumType {
|
||||||
return &file_app_proxyman_config_proto_enumTypes[0]
|
return &file_app_proxyman_config_proto_enumTypes[2]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x AllocationStrategy_Type) Number() protoreflect.EnumNumber {
|
func (x AllocationStrategy_Type) Number() protoreflect.EnumNumber {
|
||||||
@@ -83,9 +187,11 @@ type InboundConfig struct {
|
|||||||
|
|
||||||
func (x *InboundConfig) Reset() {
|
func (x *InboundConfig) Reset() {
|
||||||
*x = InboundConfig{}
|
*x = InboundConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[0]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_config_proto_msgTypes[0]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *InboundConfig) String() string {
|
func (x *InboundConfig) String() string {
|
||||||
@@ -96,7 +202,7 @@ func (*InboundConfig) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *InboundConfig) ProtoReflect() protoreflect.Message {
|
func (x *InboundConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[0]
|
mi := &file_app_proxyman_config_proto_msgTypes[0]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -127,9 +233,11 @@ type AllocationStrategy struct {
|
|||||||
|
|
||||||
func (x *AllocationStrategy) Reset() {
|
func (x *AllocationStrategy) Reset() {
|
||||||
*x = AllocationStrategy{}
|
*x = AllocationStrategy{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AllocationStrategy) String() string {
|
func (x *AllocationStrategy) String() string {
|
||||||
@@ -140,7 +248,7 @@ func (*AllocationStrategy) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *AllocationStrategy) ProtoReflect() protoreflect.Message {
|
func (x *AllocationStrategy) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -188,17 +296,18 @@ type SniffingConfig struct {
|
|||||||
DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
|
DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
|
||||||
DomainsExcluded []string `protobuf:"bytes,3,rep,name=domains_excluded,json=domainsExcluded,proto3" json:"domains_excluded,omitempty"`
|
DomainsExcluded []string `protobuf:"bytes,3,rep,name=domains_excluded,json=domainsExcluded,proto3" json:"domains_excluded,omitempty"`
|
||||||
// Whether should only try to sniff metadata without waiting for client input.
|
// Whether should only try to sniff metadata without waiting for client input.
|
||||||
// Can be used to support SMTP like protocol where server send the first
|
// Can be used to support SMTP like protocol where server send the first message.
|
||||||
// message.
|
|
||||||
MetadataOnly bool `protobuf:"varint,4,opt,name=metadata_only,json=metadataOnly,proto3" json:"metadata_only,omitempty"`
|
MetadataOnly bool `protobuf:"varint,4,opt,name=metadata_only,json=metadataOnly,proto3" json:"metadata_only,omitempty"`
|
||||||
RouteOnly bool `protobuf:"varint,5,opt,name=route_only,json=routeOnly,proto3" json:"route_only,omitempty"`
|
RouteOnly bool `protobuf:"varint,5,opt,name=route_only,json=routeOnly,proto3" json:"route_only,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SniffingConfig) Reset() {
|
func (x *SniffingConfig) Reset() {
|
||||||
*x = SniffingConfig{}
|
*x = SniffingConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SniffingConfig) String() string {
|
func (x *SniffingConfig) String() string {
|
||||||
@@ -209,7 +318,7 @@ func (*SniffingConfig) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *SniffingConfig) ProtoReflect() protoreflect.Message {
|
func (x *SniffingConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -264,21 +373,28 @@ type ReceiverConfig struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// PortList specifies the ports which the Receiver should listen on.
|
// PortRange specifies the ports which the Receiver should listen on.
|
||||||
PortList *net.PortList `protobuf:"bytes,1,opt,name=port_list,json=portList,proto3" json:"port_list,omitempty"`
|
PortRange *net.PortRange `protobuf:"bytes,1,opt,name=port_range,json=portRange,proto3" json:"port_range,omitempty"`
|
||||||
// Listen specifies the IP address that the Receiver should listen on.
|
// Listen specifies the IP address that the Receiver should listen on.
|
||||||
Listen *net.IPOrDomain `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"`
|
Listen *net.IPOrDomain `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"`
|
||||||
AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy,proto3" json:"allocation_strategy,omitempty"`
|
AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy,proto3" json:"allocation_strategy,omitempty"`
|
||||||
StreamSettings *internet.StreamConfig `protobuf:"bytes,4,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
StreamSettings *internet.StreamConfig `protobuf:"bytes,4,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
||||||
ReceiveOriginalDestination bool `protobuf:"varint,5,opt,name=receive_original_destination,json=receiveOriginalDestination,proto3" json:"receive_original_destination,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"`
|
// Override domains for the given protocol.
|
||||||
|
// Deprecated. Use sniffing_settings.
|
||||||
|
//
|
||||||
|
// Deprecated: Do not use.
|
||||||
|
DomainOverride []KnownProtocols `protobuf:"varint,7,rep,packed,name=domain_override,json=domainOverride,proto3,enum=xray.app.proxyman.KnownProtocols" json:"domain_override,omitempty"`
|
||||||
|
SniffingSettings *SniffingConfig `protobuf:"bytes,8,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[3]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReceiverConfig) String() string {
|
func (x *ReceiverConfig) String() string {
|
||||||
@@ -289,7 +405,7 @@ func (*ReceiverConfig) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *ReceiverConfig) ProtoReflect() protoreflect.Message {
|
func (x *ReceiverConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -304,9 +420,9 @@ func (*ReceiverConfig) Descriptor() ([]byte, []int) {
|
|||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{3}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{3}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReceiverConfig) GetPortList() *net.PortList {
|
func (x *ReceiverConfig) GetPortRange() *net.PortRange {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.PortList
|
return x.PortRange
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -339,6 +455,14 @@ func (x *ReceiverConfig) GetReceiveOriginalDestination() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: Do not use.
|
||||||
|
func (x *ReceiverConfig) GetDomainOverride() []KnownProtocols {
|
||||||
|
if x != nil {
|
||||||
|
return x.DomainOverride
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (x *ReceiverConfig) GetSniffingSettings() *SniffingConfig {
|
func (x *ReceiverConfig) GetSniffingSettings() *SniffingConfig {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.SniffingSettings
|
return x.SniffingSettings
|
||||||
@@ -358,9 +482,11 @@ type InboundHandlerConfig struct {
|
|||||||
|
|
||||||
func (x *InboundHandlerConfig) Reset() {
|
func (x *InboundHandlerConfig) Reset() {
|
||||||
*x = InboundHandlerConfig{}
|
*x = InboundHandlerConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *InboundHandlerConfig) String() string {
|
func (x *InboundHandlerConfig) String() string {
|
||||||
@@ -371,7 +497,7 @@ func (*InboundHandlerConfig) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
|
func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -415,9 +541,11 @@ type OutboundConfig struct {
|
|||||||
|
|
||||||
func (x *OutboundConfig) Reset() {
|
func (x *OutboundConfig) Reset() {
|
||||||
*x = OutboundConfig{}
|
*x = OutboundConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OutboundConfig) String() string {
|
func (x *OutboundConfig) String() string {
|
||||||
@@ -428,7 +556,7 @@ func (*OutboundConfig) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *OutboundConfig) ProtoReflect() protoreflect.Message {
|
func (x *OutboundConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -449,19 +577,20 @@ 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"`
|
DomainStrategy DomainStrategy `protobuf:"varint,5,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.app.proxyman.DomainStrategy" json:"domain_strategy,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[6]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SenderConfig) String() string {
|
func (x *SenderConfig) String() string {
|
||||||
@@ -472,7 +601,7 @@ func (*SenderConfig) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *SenderConfig) ProtoReflect() protoreflect.Message {
|
func (x *SenderConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -515,18 +644,11 @@ func (x *SenderConfig) GetMultiplexSettings() *MultiplexingConfig {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SenderConfig) GetViaCidr() string {
|
func (x *SenderConfig) GetDomainStrategy() DomainStrategy {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.ViaCidr
|
return x.DomainStrategy
|
||||||
}
|
}
|
||||||
return ""
|
return DomainStrategy_AS_IS
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SenderConfig) GetTargetStrategy() internet.DomainStrategy {
|
|
||||||
if x != nil {
|
|
||||||
return x.TargetStrategy
|
|
||||||
}
|
|
||||||
return internet.DomainStrategy(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type MultiplexingConfig struct {
|
type MultiplexingConfig struct {
|
||||||
@@ -537,18 +659,16 @@ type MultiplexingConfig struct {
|
|||||||
// Whether or not Mux is enabled.
|
// Whether or not Mux is enabled.
|
||||||
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
||||||
// Max number of concurrent connections that one Mux connection can handle.
|
// Max number of concurrent connections that one Mux connection can handle.
|
||||||
Concurrency int32 `protobuf:"varint,2,opt,name=concurrency,proto3" json:"concurrency,omitempty"`
|
Concurrency uint32 `protobuf:"varint,2,opt,name=concurrency,proto3" json:"concurrency,omitempty"`
|
||||||
// Transport XUDP in another Mux.
|
|
||||||
XudpConcurrency int32 `protobuf:"varint,3,opt,name=xudpConcurrency,proto3" json:"xudpConcurrency,omitempty"`
|
|
||||||
// "reject" (default), "allow" or "skip".
|
|
||||||
XudpProxyUDP443 string `protobuf:"bytes,4,opt,name=xudpProxyUDP443,proto3" json:"xudpProxyUDP443,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *MultiplexingConfig) Reset() {
|
func (x *MultiplexingConfig) Reset() {
|
||||||
*x = MultiplexingConfig{}
|
*x = MultiplexingConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[7]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_config_proto_msgTypes[7]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *MultiplexingConfig) String() string {
|
func (x *MultiplexingConfig) String() string {
|
||||||
@@ -559,7 +679,7 @@ func (*MultiplexingConfig) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {
|
func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[7]
|
mi := &file_app_proxyman_config_proto_msgTypes[7]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -581,27 +701,13 @@ func (x *MultiplexingConfig) GetEnabled() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *MultiplexingConfig) GetConcurrency() int32 {
|
func (x *MultiplexingConfig) GetConcurrency() uint32 {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Concurrency
|
return x.Concurrency
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *MultiplexingConfig) GetXudpConcurrency() int32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.XudpConcurrency
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *MultiplexingConfig) GetXudpProxyUDP443() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.XudpProxyUDP443
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type AllocationStrategy_AllocationStrategyConcurrency struct {
|
type AllocationStrategy_AllocationStrategyConcurrency struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -612,9 +718,11 @@ type AllocationStrategy_AllocationStrategyConcurrency struct {
|
|||||||
|
|
||||||
func (x *AllocationStrategy_AllocationStrategyConcurrency) Reset() {
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) Reset() {
|
||||||
*x = AllocationStrategy_AllocationStrategyConcurrency{}
|
*x = AllocationStrategy_AllocationStrategyConcurrency{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[8]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_config_proto_msgTypes[8]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AllocationStrategy_AllocationStrategyConcurrency) String() string {
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) String() string {
|
||||||
@@ -625,7 +733,7 @@ func (*AllocationStrategy_AllocationStrategyConcurrency) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *AllocationStrategy_AllocationStrategyConcurrency) ProtoReflect() protoreflect.Message {
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[8]
|
mi := &file_app_proxyman_config_proto_msgTypes[8]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -657,9 +765,11 @@ type AllocationStrategy_AllocationStrategyRefresh struct {
|
|||||||
|
|
||||||
func (x *AllocationStrategy_AllocationStrategyRefresh) Reset() {
|
func (x *AllocationStrategy_AllocationStrategyRefresh) Reset() {
|
||||||
*x = AllocationStrategy_AllocationStrategyRefresh{}
|
*x = AllocationStrategy_AllocationStrategyRefresh{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[9]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_config_proto_msgTypes[9]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AllocationStrategy_AllocationStrategyRefresh) String() string {
|
func (x *AllocationStrategy_AllocationStrategyRefresh) String() string {
|
||||||
@@ -670,7 +780,7 @@ func (*AllocationStrategy_AllocationStrategyRefresh) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *AllocationStrategy_AllocationStrategyRefresh) ProtoReflect() protoreflect.Message {
|
func (x *AllocationStrategy_AllocationStrategyRefresh) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[9]
|
mi := &file_app_proxyman_config_proto_msgTypes[9]
|
||||||
if x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -746,90 +856,97 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
|
|||||||
0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
|
0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
|
||||||
0x61, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f,
|
0x61, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f,
|
||||||
0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||||
0x4f, 0x6e, 0x6c, 0x79, 0x22, 0xbd, 0x03, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
|
0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x90, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
|
||||||
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f,
|
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f,
|
||||||
0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61,
|
0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72,
|
||||||
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72,
|
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f,
|
||||||
0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12,
|
0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e,
|
||||||
0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
0x67, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01,
|
||||||
0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
|
0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||||
0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69,
|
0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52,
|
||||||
0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63,
|
||||||
0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28,
|
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03,
|
||||||
0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f,
|
0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||||
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74,
|
||||||
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61,
|
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c,
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4e, 0x0a, 0x0f,
|
0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12,
|
||||||
|
0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
||||||
|
0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
|
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
||||||
|
0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
|
||||||
|
0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,
|
||||||
|
0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69,
|
||||||
|
0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
|
||||||
|
0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72,
|
||||||
|
0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
|
||||||
|
0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72,
|
||||||
|
0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61,
|
||||||
|
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4b,
|
||||||
|
0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x42, 0x02, 0x18,
|
||||||
|
0x01, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
|
||||||
|
0x65, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65,
|
||||||
|
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78,
|
||||||
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e,
|
||||||
|
0x2e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
|
||||||
|
0x10, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
|
||||||
|
0x73, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f,
|
||||||
|
0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
|
0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74,
|
||||||
|
0x61, 0x67, 0x12, 0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73,
|
||||||
|
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e,
|
||||||
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69,
|
||||||
|
0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
|
||||||
|
0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
|
||||||
|
0x73, 0x12, 0x47, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
|
||||||
|
0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
|
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54,
|
||||||
|
0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f,
|
||||||
|
0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75,
|
||||||
|
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xfc, 0x02, 0x0a,
|
||||||
|
0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a,
|
||||||
|
0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61,
|
||||||
|
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f,
|
||||||
|
0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f,
|
||||||
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
|
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
|
||||||
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
|
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
|
||||||
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
|
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
|
||||||
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74,
|
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74,
|
||||||
0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x1c,
|
0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e,
|
||||||
0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
|
0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03,
|
||||||
0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01,
|
0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
|
||||||
0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69,
|
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50,
|
||||||
0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e,
|
0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78,
|
||||||
0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
|
0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c,
|
||||||
0x6e, 0x67, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
|
||||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e,
|
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e,
|
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70,
|
||||||
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04,
|
0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75,
|
||||||
0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
|
0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,
|
||||||
0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a,
|
0x4a, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||||
0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12,
|
0x67, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74,
|
0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x6f, 0x6d,
|
||||||
0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61,
|
0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d,
|
||||||
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e,
|
0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, 0x50, 0x0a, 0x12, 0x4d,
|
||||||
0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x10, 0x72, 0x65,
|
0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||||
0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47,
|
0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||||
0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63,
|
||||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
|
||||||
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65,
|
0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2a, 0x23, 0x0a,
|
||||||
0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53,
|
0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12,
|
||||||
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f,
|
0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x4c, 0x53,
|
||||||
0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x9d, 0x03, 0x0a, 0x0c, 0x53, 0x65,
|
0x10, 0x01, 0x2a, 0x61, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61,
|
||||||
0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x03, 0x76, 0x69,
|
0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x49, 0x53, 0x10, 0x00, 0x12,
|
||||||
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55,
|
||||||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f,
|
0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f,
|
||||||
0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72,
|
0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x52, 0x45, 0x46, 0x45, 0x52, 0x5f,
|
||||||
0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01,
|
0x49, 0x50, 0x34, 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x52, 0x45, 0x46, 0x45, 0x52, 0x5f,
|
||||||
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
|
0x49, 0x50, 0x36, 0x10, 0x05, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61,
|
||||||
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72,
|
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01,
|
||||||
0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61,
|
0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c,
|
||||||
0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e, 0x70, 0x72, 0x6f,
|
0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f,
|
||||||
0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
|
0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
|
0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72,
|
||||||
0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78,
|
0x6f, 0x74, 0x6f, 0x33,
|
||||||
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, 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 (
|
||||||
@@ -844,48 +961,50 @@ func file_app_proxyman_config_proto_rawDescGZIP() []byte {
|
|||||||
return file_app_proxyman_config_proto_rawDescData
|
return file_app_proxyman_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
var file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
|
||||||
var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||||
var file_app_proxyman_config_proto_goTypes = []any{
|
var file_app_proxyman_config_proto_goTypes = []interface{}{
|
||||||
(AllocationStrategy_Type)(0), // 0: xray.app.proxyman.AllocationStrategy.Type
|
(KnownProtocols)(0), // 0: xray.app.proxyman.KnownProtocols
|
||||||
(*InboundConfig)(nil), // 1: xray.app.proxyman.InboundConfig
|
(DomainStrategy)(0), // 1: xray.app.proxyman.DomainStrategy
|
||||||
(*AllocationStrategy)(nil), // 2: xray.app.proxyman.AllocationStrategy
|
(AllocationStrategy_Type)(0), // 2: xray.app.proxyman.AllocationStrategy.Type
|
||||||
(*SniffingConfig)(nil), // 3: xray.app.proxyman.SniffingConfig
|
(*InboundConfig)(nil), // 3: xray.app.proxyman.InboundConfig
|
||||||
(*ReceiverConfig)(nil), // 4: xray.app.proxyman.ReceiverConfig
|
(*AllocationStrategy)(nil), // 4: xray.app.proxyman.AllocationStrategy
|
||||||
(*InboundHandlerConfig)(nil), // 5: xray.app.proxyman.InboundHandlerConfig
|
(*SniffingConfig)(nil), // 5: xray.app.proxyman.SniffingConfig
|
||||||
(*OutboundConfig)(nil), // 6: xray.app.proxyman.OutboundConfig
|
(*ReceiverConfig)(nil), // 6: xray.app.proxyman.ReceiverConfig
|
||||||
(*SenderConfig)(nil), // 7: xray.app.proxyman.SenderConfig
|
(*InboundHandlerConfig)(nil), // 7: xray.app.proxyman.InboundHandlerConfig
|
||||||
(*MultiplexingConfig)(nil), // 8: xray.app.proxyman.MultiplexingConfig
|
(*OutboundConfig)(nil), // 8: xray.app.proxyman.OutboundConfig
|
||||||
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 9: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
|
(*SenderConfig)(nil), // 9: xray.app.proxyman.SenderConfig
|
||||||
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
|
(*MultiplexingConfig)(nil), // 10: xray.app.proxyman.MultiplexingConfig
|
||||||
(*net.PortList)(nil), // 11: xray.common.net.PortList
|
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 11: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
|
||||||
(*net.IPOrDomain)(nil), // 12: xray.common.net.IPOrDomain
|
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 12: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
|
||||||
(*internet.StreamConfig)(nil), // 13: xray.transport.internet.StreamConfig
|
(*net.PortRange)(nil), // 13: xray.common.net.PortRange
|
||||||
(*serial.TypedMessage)(nil), // 14: xray.common.serial.TypedMessage
|
(*net.IPOrDomain)(nil), // 14: xray.common.net.IPOrDomain
|
||||||
(*internet.ProxyConfig)(nil), // 15: xray.transport.internet.ProxyConfig
|
(*internet.StreamConfig)(nil), // 15: xray.transport.internet.StreamConfig
|
||||||
(internet.DomainStrategy)(0), // 16: xray.transport.internet.DomainStrategy
|
(*serial.TypedMessage)(nil), // 16: xray.common.serial.TypedMessage
|
||||||
|
(*internet.ProxyConfig)(nil), // 17: xray.transport.internet.ProxyConfig
|
||||||
}
|
}
|
||||||
var file_app_proxyman_config_proto_depIdxs = []int32{
|
var file_app_proxyman_config_proto_depIdxs = []int32{
|
||||||
0, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type
|
2, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type
|
||||||
9, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
|
11, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
|
||||||
10, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
|
12, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
|
||||||
11, // 3: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList
|
13, // 3: xray.app.proxyman.ReceiverConfig.port_range:type_name -> xray.common.net.PortRange
|
||||||
12, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
|
14, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
|
||||||
2, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy
|
4, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy
|
||||||
13, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
15, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||||
3, // 7: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
|
0, // 7: xray.app.proxyman.ReceiverConfig.domain_override:type_name -> xray.app.proxyman.KnownProtocols
|
||||||
14, // 8: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
|
5, // 8: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
|
||||||
14, // 9: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
|
16, // 9: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
|
||||||
12, // 10: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
|
16, // 10: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
|
||||||
13, // 11: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
14, // 11: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
|
||||||
15, // 12: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
|
15, // 12: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||||
8, // 13: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
17, // 13: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
|
||||||
16, // 14: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy
|
10, // 14: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
||||||
15, // [15:15] is the sub-list for method output_type
|
1, // 15: xray.app.proxyman.SenderConfig.domain_strategy:type_name -> xray.app.proxyman.DomainStrategy
|
||||||
15, // [15:15] is the sub-list for method input_type
|
16, // [16:16] is the sub-list for method output_type
|
||||||
15, // [15:15] is the sub-list for extension type_name
|
16, // [16:16] is the sub-list for method input_type
|
||||||
15, // [15:15] is the sub-list for extension extendee
|
16, // [16:16] is the sub-list for extension type_name
|
||||||
0, // [0:15] is the sub-list for field type_name
|
16, // [16:16] is the sub-list for extension extendee
|
||||||
|
0, // [0:16] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_proxyman_config_proto_init() }
|
func init() { file_app_proxyman_config_proto_init() }
|
||||||
@@ -893,12 +1012,134 @@ func file_app_proxyman_config_proto_init() {
|
|||||||
if File_app_proxyman_config_proto != nil {
|
if File_app_proxyman_config_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_app_proxyman_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*InboundConfig); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*AllocationStrategy); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*SniffingConfig); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ReceiverConfig); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*InboundHandlerConfig); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*OutboundConfig); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_config_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*SenderConfig); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_config_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*MultiplexingConfig); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_config_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*AllocationStrategy_AllocationStrategyConcurrency); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_config_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*AllocationStrategy_AllocationStrategyRefresh); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
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: 1,
|
NumEnums: 3,
|
||||||
NumMessages: 10,
|
NumMessages: 10,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
|
|||||||
@@ -27,19 +27,28 @@ message AllocationStrategy {
|
|||||||
|
|
||||||
Type type = 1;
|
Type type = 1;
|
||||||
|
|
||||||
message AllocationStrategyConcurrency { uint32 value = 1; }
|
message AllocationStrategyConcurrency {
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Number of handlers (ports) running in parallel.
|
// Number of handlers (ports) running in parallel.
|
||||||
// Default value is 3 if unset.
|
// Default value is 3 if unset.
|
||||||
AllocationStrategyConcurrency concurrency = 2;
|
AllocationStrategyConcurrency concurrency = 2;
|
||||||
|
|
||||||
message AllocationStrategyRefresh { uint32 value = 1; }
|
message AllocationStrategyRefresh {
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Number of minutes before a handler is regenerated.
|
// Number of minutes before a handler is regenerated.
|
||||||
// Default value is 5 if unset.
|
// Default value is 5 if unset.
|
||||||
AllocationStrategyRefresh refresh = 3;
|
AllocationStrategyRefresh refresh = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum KnownProtocols {
|
||||||
|
HTTP = 0;
|
||||||
|
TLS = 1;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -50,23 +59,25 @@ message SniffingConfig {
|
|||||||
repeated string domains_excluded = 3;
|
repeated string domains_excluded = 3;
|
||||||
|
|
||||||
// Whether should only try to sniff metadata without waiting for client input.
|
// Whether should only try to sniff metadata without waiting for client input.
|
||||||
// Can be used to support SMTP like protocol where server send the first
|
// Can be used to support SMTP like protocol where server send the first message.
|
||||||
// message.
|
|
||||||
bool metadata_only = 4;
|
bool metadata_only = 4;
|
||||||
|
|
||||||
bool route_only = 5;
|
bool route_only = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ReceiverConfig {
|
message ReceiverConfig {
|
||||||
// PortList specifies the ports which the Receiver should listen on.
|
// PortRange specifies the ports which the Receiver should listen on.
|
||||||
xray.common.net.PortList port_list = 1;
|
xray.common.net.PortRange port_range = 1;
|
||||||
// Listen specifies the IP address that the Receiver should listen on.
|
// Listen specifies the IP address that the Receiver should listen on.
|
||||||
xray.common.net.IPOrDomain listen = 2;
|
xray.common.net.IPOrDomain listen = 2;
|
||||||
AllocationStrategy allocation_strategy = 3;
|
AllocationStrategy allocation_strategy = 3;
|
||||||
xray.transport.internet.StreamConfig stream_settings = 4;
|
xray.transport.internet.StreamConfig stream_settings = 4;
|
||||||
bool receive_original_destination = 5;
|
bool receive_original_destination = 5;
|
||||||
reserved 6;
|
reserved 6;
|
||||||
SniffingConfig sniffing_settings = 7;
|
// Override domains for the given protocol.
|
||||||
|
// Deprecated. Use sniffing_settings.
|
||||||
|
repeated KnownProtocols domain_override = 7 [deprecated = true];
|
||||||
|
SniffingConfig sniffing_settings = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
message InboundHandlerConfig {
|
message InboundHandlerConfig {
|
||||||
@@ -77,23 +88,27 @@ message InboundHandlerConfig {
|
|||||||
|
|
||||||
message OutboundConfig {}
|
message OutboundConfig {}
|
||||||
|
|
||||||
|
enum DomainStrategy {
|
||||||
|
AS_IS = 0;
|
||||||
|
USE_IP = 1;
|
||||||
|
USE_IP4 = 2;
|
||||||
|
USE_IP6 = 3;
|
||||||
|
PREFER_IP4 = 4;
|
||||||
|
PREFER_IP6 = 5;
|
||||||
|
}
|
||||||
|
|
||||||
message SenderConfig {
|
message SenderConfig {
|
||||||
// Send traffic through the given IP. Only IP is allowed.
|
// Send traffic through the given IP. Only IP is allowed.
|
||||||
xray.common.net.IPOrDomain via = 1;
|
xray.common.net.IPOrDomain via = 1;
|
||||||
xray.transport.internet.StreamConfig stream_settings = 2;
|
xray.transport.internet.StreamConfig stream_settings = 2;
|
||||||
xray.transport.internet.ProxyConfig proxy_settings = 3;
|
xray.transport.internet.ProxyConfig proxy_settings = 3;
|
||||||
MultiplexingConfig multiplex_settings = 4;
|
MultiplexingConfig multiplex_settings = 4;
|
||||||
string via_cidr = 5;
|
DomainStrategy domain_strategy = 5;
|
||||||
xray.transport.internet.DomainStrategy target_strategy = 6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message MultiplexingConfig {
|
message MultiplexingConfig {
|
||||||
// Whether or not Mux is enabled.
|
// Whether or not Mux is enabled.
|
||||||
bool enabled = 1;
|
bool enabled = 1;
|
||||||
// Max number of concurrent connections that one Mux connection can handle.
|
// Max number of concurrent connections that one Mux connection can handle.
|
||||||
int32 concurrency = 2;
|
uint32 concurrency = 2;
|
||||||
// Transport XUDP in another Mux.
|
|
||||||
int32 xudpConcurrency = 3;
|
|
||||||
// "reject" (default), "allow" or "skip".
|
|
||||||
string xudpProxyUDP443 = 4;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user