mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-12-19 05:34:36 +03:00
Compare commits
1 Commits
v24.10.16
...
dev/codeql
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bdfeeed225 |
87
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
87
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,87 +0,0 @@
|
|||||||
name: Bug report
|
|
||||||
description: "Submit Xray-core bug"
|
|
||||||
body:
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Integrity requirements
|
|
||||||
description: |-
|
|
||||||
Please check all of the following options to prove that you have read and understood the requirements, otherwise this issue will be closed.
|
|
||||||
options:
|
|
||||||
- label: I confirm that I have read the documentation, understand the meaning of all the configuration items I wrote, and did not pile up seemingly useful options or default values.
|
|
||||||
required: true
|
|
||||||
- label: I 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.
|
|
||||||
|
|
||||||
### 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
|
|
||||||
After removing parts that do not affect reproduction, provide the actual running **complete** file, do not only provide inbound or outbound or a few lines of logs based on your own judgment.
|
|
||||||
Put the content between the preset ```<details><pre><code>``` ```</code></pre></details>``` in the text box.
|
|
||||||
If the problem is very clear that only related to one end (such as core startup failure/crash after correctly writing the config according to the documents), N/A can be filled in for unnecessary areas below.
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Client config
|
|
||||||
value: |-
|
|
||||||
<details><pre><code>
|
|
||||||
|
|
||||||
</code></pre></details>
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Server config
|
|
||||||
value: |-
|
|
||||||
<details><pre><code>
|
|
||||||
|
|
||||||
</code></pre></details>
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Client log
|
|
||||||
value: |-
|
|
||||||
<details><pre><code>
|
|
||||||
|
|
||||||
</code></pre></details>
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Server log
|
|
||||||
value: |-
|
|
||||||
<details><pre><code>
|
|
||||||
|
|
||||||
</code></pre></details>
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
87
.github/ISSUE_TEMPLATE/bug_report_zh.yml
vendored
87
.github/ISSUE_TEMPLATE/bug_report_zh.yml
vendored
@@ -1,87 +0,0 @@
|
|||||||
name: bug反馈
|
|
||||||
description: "提交 Xray-core bug"
|
|
||||||
body:
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: 完整性要求
|
|
||||||
description: |-
|
|
||||||
请勾选以下所有选项以证明您已经阅读并理解了以下要求,否则该 issue 将被关闭。
|
|
||||||
options:
|
|
||||||
- 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>``` 中间。
|
|
||||||
如果问题十分明确只出现在某一端(如按文档正确编写配置后核心启动失败/崩溃),可以在下面不需要的项目填入N/A.
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 客户端配置
|
|
||||||
value: |-
|
|
||||||
<details><pre><code>
|
|
||||||
|
|
||||||
</code></pre></details>
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 服务端配置
|
|
||||||
value: |-
|
|
||||||
<details><pre><code>
|
|
||||||
|
|
||||||
</code></pre></details>
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 客户端日志
|
|
||||||
value: |-
|
|
||||||
<details><pre><code>
|
|
||||||
|
|
||||||
</code></pre></details>
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 服务端日志
|
|
||||||
value: |-
|
|
||||||
<details><pre><code>
|
|
||||||
|
|
||||||
</code></pre></details>
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
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.
|
|
||||||
3
.github/build/friendly-filenames.json
vendored
3
.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" },
|
||||||
@@ -29,6 +29,5 @@
|
|||||||
"openbsd-arm7": { "friendlyName": "openbsd-arm32-v7a" },
|
"openbsd-arm7": { "friendlyName": "openbsd-arm32-v7a" },
|
||||||
"windows-386": { "friendlyName": "windows-32" },
|
"windows-386": { "friendlyName": "windows-32" },
|
||||||
"windows-amd64": { "friendlyName": "windows-64" },
|
"windows-amd64": { "friendlyName": "windows-64" },
|
||||||
"windows-arm64": { "friendlyName": "windows-arm64-v8a" },
|
|
||||||
"windows-arm7": { "friendlyName": "windows-arm32-v7a" }
|
"windows-arm7": { "friendlyName": "windows-arm32-v7a" }
|
||||||
}
|
}
|
||||||
|
|||||||
15
.github/dependabot.yml
vendored
15
.github/dependabot.yml
vendored
@@ -1,15 +0,0 @@
|
|||||||
# To get started with Dependabot version updates, you'll need to specify which
|
|
||||||
# package ecosystems to update and where the package manifests are located.
|
|
||||||
# Please see the documentation for all configuration options:
|
|
||||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
||||||
|
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "gomod"
|
|
||||||
directory: "/" # Location of package manifests
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
28
.github/docker/Dockerfile
vendored
28
.github/docker/Dockerfile
vendored
@@ -1,28 +0,0 @@
|
|||||||
# syntax=docker/dockerfile:1
|
|
||||||
FROM --platform=$BUILDPLATFORM golang:alpine AS build
|
|
||||||
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
|
|
||||||
ADD https://github.com/v2fly/geoip/releases/latest/download/geoip.dat /v2fly/geoip.dat
|
|
||||||
ADD https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat /v2fly/geosite.dat
|
|
||||||
ADD https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat /loyalsoldier/geoip.dat
|
|
||||||
ADD https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat /loyalsoldier/geosite.dat
|
|
||||||
|
|
||||||
# chainguard/static contains only tzdata and ca-certificates, can be built with multiarch static binaries.
|
|
||||||
FROM --platform=linux/amd64 chainguard/static:latest
|
|
||||||
WORKDIR /var/log/xray
|
|
||||||
COPY .github/docker/files/config.json /etc/xray/config.json
|
|
||||||
COPY --from=build --chmod=755 /src/xray /usr/bin/xray
|
|
||||||
|
|
||||||
USER root
|
|
||||||
WORKDIR /root
|
|
||||||
VOLUME /etc/xray
|
|
||||||
ARG TZ=Asia/Shanghai
|
|
||||||
ENV TZ=$TZ
|
|
||||||
ENTRYPOINT [ "/usr/bin/xray" ]
|
|
||||||
CMD [ "-config", "/etc/xray/config.json" ]
|
|
||||||
|
|
||||||
ARG flavor=v2fly
|
|
||||||
COPY --from=build --chmod=644 /$flavor /usr/share/xray
|
|
||||||
18
.github/docker/files/config.json
vendored
18
.github/docker/files/config.json
vendored
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"inbounds": [{
|
|
||||||
"port": 9000,
|
|
||||||
"protocol": "vmess",
|
|
||||||
"settings": {
|
|
||||||
"clients": [
|
|
||||||
{
|
|
||||||
"id": "1eb6e917-774b-4a84-aff6-b058577c60a5",
|
|
||||||
"level": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"outbounds": [{
|
|
||||||
"protocol": "freedom",
|
|
||||||
"settings": {}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
51
.github/workflows/codeql-analysis.yml
vendored
Normal file
51
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main, dev/codeql ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'go' ]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v1
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 https://git.io/JvXDl
|
||||||
|
|
||||||
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
|
# and modify them (or add more) to build your code if your project
|
||||||
|
# uses a compiled language
|
||||||
|
|
||||||
|
#- run: |
|
||||||
|
# make bootstrap
|
||||||
|
# make release
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
||||||
76
.github/workflows/docker.yml
vendored
76
.github/workflows/docker.yml
vendored
@@ -1,76 +0,0 @@
|
|||||||
name: Build docker image
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-image:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Docker metadata
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ghcr.io/${{ github.repository_owner }}/xray-core
|
|
||||||
flavor: latest=auto
|
|
||||||
tags: |
|
|
||||||
type=sha
|
|
||||||
type=ref,event=branch
|
|
||||||
type=ref,event=pr
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
- name: Docker metadata Loyalsoldier flavor
|
|
||||||
id: loyalsoldier
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ghcr.io/${{ github.repository_owner }}/xray-core
|
|
||||||
flavor: |
|
|
||||||
latest=auto
|
|
||||||
suffix=-ls,onlatest=true
|
|
||||||
tags: |
|
|
||||||
type=sha
|
|
||||||
type=ref,event=branch
|
|
||||||
type=ref,event=pr
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: |
|
|
||||||
linux/amd64
|
|
||||||
linux/arm64
|
|
||||||
linux/loong64
|
|
||||||
linux/riscv64
|
|
||||||
provenance: false
|
|
||||||
file: .github/docker/Dockerfile
|
|
||||||
push: true
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
- name: Build and push Loyalsoldier flavor
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: |
|
|
||||||
linux/amd64
|
|
||||||
linux/arm64
|
|
||||||
linux/loong64
|
|
||||||
linux/riscv64
|
|
||||||
provenance: false
|
|
||||||
file: .github/docker/Dockerfile
|
|
||||||
build-args: flavor=loyalsoldier
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
${{ steps.loyalsoldier.outputs.tags }}
|
|
||||||
163
.github/workflows/release.yml
vendored
163
.github/workflows/release.yml
vendored
@@ -1,11 +1,5 @@
|
|||||||
name: Build and Release
|
name: Build and Release
|
||||||
|
|
||||||
# NOTE: This Github Actions file depends on the Makefile.
|
|
||||||
# Building the correct package requires the correct binaries generated by the Makefile. To
|
|
||||||
# ensure the correct output, the Makefile must accept the appropriate input and compile the
|
|
||||||
# correct file with the correct name. If you need to modify this file, please ensure it won't
|
|
||||||
# disrupt the Makefile.
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
release:
|
release:
|
||||||
@@ -17,76 +11,29 @@ on:
|
|||||||
- "**/*.go"
|
- "**/*.go"
|
||||||
- "go.mod"
|
- "go.mod"
|
||||||
- "go.sum"
|
- "go.sum"
|
||||||
- ".github/workflows/release.yml"
|
- ".github/workflows/*.yml"
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, synchronize, reopened]
|
types: [opened, synchronize, reopened]
|
||||||
paths:
|
paths:
|
||||||
- "**/*.go"
|
- "**/*.go"
|
||||||
- "go.mod"
|
- "go.mod"
|
||||||
- "go.sum"
|
- "go.sum"
|
||||||
- ".github/workflows/release.yml"
|
- ".github/workflows/*.yml"
|
||||||
jobs:
|
jobs:
|
||||||
prepare:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Restore Cache
|
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-geodat-
|
|
||||||
|
|
||||||
- name: Update Geodat
|
|
||||||
id: update
|
|
||||||
uses: nick-fields/retry@v3
|
|
||||||
with:
|
|
||||||
timeout_minutes: 60
|
|
||||||
retry_wait_seconds: 60
|
|
||||||
max_attempts: 60
|
|
||||||
command: |
|
|
||||||
[ -d 'resources' ] || mkdir resources
|
|
||||||
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite')
|
|
||||||
for i in "${LIST[@]}"
|
|
||||||
do
|
|
||||||
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3}'))
|
|
||||||
FILE_NAME="${INFO[2]}.dat"
|
|
||||||
echo -e "Verifying HASH key..."
|
|
||||||
HASH="$(curl -sL "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
|
|
||||||
if [ -s "./resources/${FILE_NAME}" ] && [ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ]; then
|
|
||||||
continue
|
|
||||||
else
|
|
||||||
echo -e "Downloading https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat..."
|
|
||||||
curl -L "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.dat" -o ./resources/${FILE_NAME}
|
|
||||||
echo -e "Verifying HASH key..."
|
|
||||||
[ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ] || { echo -e "The HASH key of ${FILE_NAME} does not match cloud one."; exit 1; }
|
|
||||||
echo "unhit=true" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Save Cache
|
|
||||||
uses: actions/cache/save@v4
|
|
||||||
if: ${{ steps.update.outputs.unhit }}
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-geodat-${{ github.sha }}-${{ github.run_number }}
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
needs: prepare
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
# Include amd64 on all platforms.
|
# Include amd64 on all platforms.
|
||||||
goos: [windows, freebsd, openbsd, linux, darwin]
|
goos: [windows, freebsd, openbsd, linux, dragonfly, darwin]
|
||||||
goarch: [amd64, 386]
|
goarch: [amd64, 386]
|
||||||
gotoolchain: [""]
|
|
||||||
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
|
||||||
@@ -105,21 +52,17 @@ jobs:
|
|||||||
- goos: android
|
- goos: android
|
||||||
goarch: arm64
|
goarch: arm64
|
||||||
# END Android ARM 8
|
# END Android ARM 8
|
||||||
# Windows ARM
|
# Windows ARM 7
|
||||||
- goos: windows
|
|
||||||
goarch: arm64
|
|
||||||
- goos: windows
|
- goos: windows
|
||||||
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
|
||||||
@@ -155,16 +98,6 @@ jobs:
|
|||||||
goarch: arm
|
goarch: arm
|
||||||
goarm: 7
|
goarm: 7
|
||||||
# END OPENBSD ARM
|
# END OPENBSD ARM
|
||||||
# BEGIN Windows 7
|
|
||||||
- goos: windows
|
|
||||||
goarch: amd64
|
|
||||||
gotoolchain: 1.21.4
|
|
||||||
patch-assetname: win7-64
|
|
||||||
- goos: windows
|
|
||||||
goarch: 386
|
|
||||||
gotoolchain: 1.21.4
|
|
||||||
patch-assetname: win7-32
|
|
||||||
# END Windows 7
|
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -175,51 +108,75 @@ jobs:
|
|||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codebase
|
- name: Checkout codebase
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Show workflow information
|
- name: Show workflow information
|
||||||
|
id: get_filename
|
||||||
run: |
|
run: |
|
||||||
_NAME=${{ matrix.patch-assetname }}
|
export _NAME=$(jq ".[\"$GOOS-$GOARCH$GOARM$GOMIPS\"].friendlyName" -r < .github/build/friendly-filenames.json)
|
||||||
[ -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: ${{ matrix.gotoolchain || '1.23' }}
|
go-version: ^1.16
|
||||||
check-latest: true
|
|
||||||
|
|
||||||
- name: Get project dependencies
|
- name: Get project dependencies
|
||||||
run: go mod download
|
run: go mod download
|
||||||
|
|
||||||
|
- name: Replace Custom to Commit ID
|
||||||
|
if: github.event_name != 'release'
|
||||||
|
run: |
|
||||||
|
ID=$(git rev-parse --short ${{ github.sha }})
|
||||||
|
if [ "${{ github.event_name }}" == 'pull_request' ]
|
||||||
|
then
|
||||||
|
ID=$(git rev-parse --short ${{ github.event.pull_request.head.sha }})
|
||||||
|
fi
|
||||||
|
sed -i '/build/ s/Custom/'$ID'/' ./core/core.go
|
||||||
|
|
||||||
- name: Build Xray
|
- name: Build Xray
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build_assets
|
mkdir -p build_assets
|
||||||
make
|
go build -v -o build_assets/xray -trimpath -ldflags "-s -w -buildid=" ./main
|
||||||
find . -maxdepth 1 -type f -regex './\(wxray\|xray\|xray_softfloat\)\(\|.exe\)' -exec mv {} ./build_assets/ \;
|
|
||||||
|
- name: Build Mips softfloat Xray
|
||||||
- name: Restore Cache
|
if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle'
|
||||||
uses: actions/cache/restore@v4
|
run: |
|
||||||
with:
|
GOMIPS=softfloat go build -v -o build_assets/xray_softfloat -trimpath -ldflags "-s -w -buildid=" ./main
|
||||||
path: resources
|
|
||||||
key: xray-geodat-
|
- name: Rename Windows Xray
|
||||||
|
if: matrix.goos == 'windows'
|
||||||
- name: Copy README.md & LICENSE
|
run: |
|
||||||
|
cd ./build_assets || exit 1
|
||||||
|
mv xray xray.exe
|
||||||
|
|
||||||
|
- name: Prepare to release
|
||||||
run: |
|
run: |
|
||||||
mv -f resources/* build_assets
|
|
||||||
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
|
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
|
||||||
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
|
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
|
||||||
|
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite')
|
||||||
|
for i in "${LIST[@]}"
|
||||||
|
do
|
||||||
|
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3}'))
|
||||||
|
LASTEST_TAG="$(curl -sL "https://api.github.com/repos/v2fly/${INFO[0]}/releases" | jq -r ".[0].tag_name" || echo "latest")"
|
||||||
|
FILE_NAME="${INFO[2]}.dat"
|
||||||
|
echo -e "Downloading ${FILE_NAME}..."
|
||||||
|
curl -L "https://github.com/v2fly/${INFO[0]}/releases/download/${LASTEST_TAG}/${INFO[1]}.dat" -o ./build_assets/${FILE_NAME}
|
||||||
|
echo -e "Verifying HASH key..."
|
||||||
|
HASH="$(curl -sL "https://github.com/v2fly/${INFO[0]}/releases/download/${LASTEST_TAG}/${INFO[1]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
|
||||||
|
[ "$(sha256sum "./build_assets/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ] || { echo -e "The HASH key of ${FILE_NAME} does not match cloud one."; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
- name: Create ZIP archive
|
- name: Create ZIP archive
|
||||||
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
|
||||||
@@ -228,20 +185,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
|
||||||
|
|||||||
30
.github/workflows/test.yml
vendored
30
.github/workflows/test.yml
vendored
@@ -19,26 +19,30 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [windows-latest, ubuntu-latest, macos-latest]
|
os: [windows-latest, ubuntu-latest, macos-latest]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codebase
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: ^1.16
|
||||||
check-latest: true
|
- name: Checkout codebase
|
||||||
- name: Restore Cache
|
uses: actions/checkout@v2
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
- name: Prepare geo*dat
|
||||||
path: resources
|
if: ${{ matrix.os != 'windows-latest' }}
|
||||||
key: xray-geodat-
|
run: |
|
||||||
enableCrossOsArchive: true
|
mkdir resources
|
||||||
|
wget -O ./resources/geoip.dat https://github.com/v2fly/geoip/releases/latest/download/geoip.dat
|
||||||
|
wget -O ./resources/geosite.dat https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat
|
||||||
|
- name: Prepare geo*dat for Windows
|
||||||
|
if: ${{ matrix.os == 'windows-latest' }}
|
||||||
|
run: |
|
||||||
|
mkdir resources
|
||||||
|
Invoke-WebRequest -Uri "https://github.com/v2fly/geoip/releases/latest/download/geoip.dat" -OutFile "./resources/geoip.dat"
|
||||||
|
Invoke-WebRequest -Uri "https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat" -OutFile "./resources/geosite.dat"
|
||||||
- name: Test
|
- name: Test
|
||||||
run: go test -timeout 1h -v ./...
|
run: go test -timeout 1h -v ./...
|
||||||
|
|||||||
33
.gitignore
vendored
33
.gitignore
vendored
@@ -1,33 +0,0 @@
|
|||||||
# Binaries for programs and plugins
|
|
||||||
*.exe
|
|
||||||
*.exe~
|
|
||||||
*.dll
|
|
||||||
*.so
|
|
||||||
*.dylib
|
|
||||||
|
|
||||||
# Test binary, built with `go test -c`
|
|
||||||
*.test
|
|
||||||
|
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
|
||||||
*.out
|
|
||||||
|
|
||||||
# Dependency directories (remove the comment below to include it)
|
|
||||||
# vendor/
|
|
||||||
|
|
||||||
*.DS_Store
|
|
||||||
.idea
|
|
||||||
*.zip
|
|
||||||
*.tar.gz
|
|
||||||
xray
|
|
||||||
xray_softfloat
|
|
||||||
mockgen
|
|
||||||
vprotogen
|
|
||||||
!infra/vprotogen/
|
|
||||||
errorgen
|
|
||||||
!common/errors/errorgen/
|
|
||||||
*.dat
|
|
||||||
.vscode
|
|
||||||
/build_assets
|
|
||||||
|
|
||||||
# Output from dlv test
|
|
||||||
**/debug.*
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
# Contributor Covenant Code of Conduct
|
|
||||||
|
|
||||||
## Our Pledge
|
|
||||||
|
|
||||||
We as members, contributors, and leaders pledge to make participation in our
|
|
||||||
community a harassment-free experience for everyone, regardless of age, body
|
|
||||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
||||||
identity and expression, level of experience, education, socio-economic status,
|
|
||||||
nationality, personal appearance, race, religion, or sexual identity
|
|
||||||
and orientation.
|
|
||||||
|
|
||||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
|
||||||
diverse, inclusive, and healthy community.
|
|
||||||
|
|
||||||
## Our Standards
|
|
||||||
|
|
||||||
Examples of behavior that contributes to a positive environment for our
|
|
||||||
community include:
|
|
||||||
|
|
||||||
* Demonstrating empathy and kindness toward other people
|
|
||||||
* Being respectful of differing opinions, viewpoints, and experiences
|
|
||||||
* Giving and gracefully accepting constructive feedback
|
|
||||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
|
||||||
and learning from the experience
|
|
||||||
* Focusing on what is best not just for us as individuals, but for the
|
|
||||||
overall community
|
|
||||||
|
|
||||||
Examples of unacceptable behavior include:
|
|
||||||
|
|
||||||
* The use of sexualized language or imagery, and sexual attention or
|
|
||||||
advances of any kind
|
|
||||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
||||||
* Public or private harassment
|
|
||||||
* Publishing others' private information, such as a physical or email
|
|
||||||
address, without their explicit permission
|
|
||||||
* Other conduct which could reasonably be considered inappropriate in a
|
|
||||||
professional setting
|
|
||||||
|
|
||||||
## Enforcement Responsibilities
|
|
||||||
|
|
||||||
Community leaders are responsible for clarifying and enforcing our standards of
|
|
||||||
acceptable behavior and will take appropriate and fair corrective action in
|
|
||||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
|
||||||
or harmful.
|
|
||||||
|
|
||||||
Community leaders have the right and responsibility to remove, edit, or reject
|
|
||||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
|
||||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
|
||||||
decisions when appropriate.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
This Code of Conduct applies within all community spaces, and also applies when
|
|
||||||
an individual is officially representing the community in public spaces.
|
|
||||||
Examples of representing our community include using an official e-mail address,
|
|
||||||
posting via an official social media account, or acting as an appointed
|
|
||||||
representative at an online or offline event.
|
|
||||||
|
|
||||||
## Enforcement
|
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
||||||
reported to the community leaders responsible for enforcement at
|
|
||||||
https://t.me/projectXtls.
|
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
|
||||||
|
|
||||||
All community leaders are obligated to respect the privacy and security of the
|
|
||||||
reporter of any incident.
|
|
||||||
|
|
||||||
## Enforcement Guidelines
|
|
||||||
|
|
||||||
Community leaders will follow these Community Impact Guidelines in determining
|
|
||||||
the consequences for any action they deem in violation of this Code of Conduct:
|
|
||||||
|
|
||||||
### 1. Correction
|
|
||||||
|
|
||||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
|
||||||
unprofessional or unwelcome in the community.
|
|
||||||
|
|
||||||
**Consequence**: A private, written warning from community leaders, providing
|
|
||||||
clarity around the nature of the violation and an explanation of why the
|
|
||||||
behavior was inappropriate. A public apology may be requested.
|
|
||||||
|
|
||||||
### 2. Warning
|
|
||||||
|
|
||||||
**Community Impact**: A violation through a single incident or series
|
|
||||||
of actions.
|
|
||||||
|
|
||||||
**Consequence**: A warning with consequences for continued behavior. No
|
|
||||||
interaction with the people involved, including unsolicited interaction with
|
|
||||||
those enforcing the Code of Conduct, for a specified period of time. This
|
|
||||||
includes avoiding interactions in community spaces as well as external channels
|
|
||||||
like social media. Violating these terms may lead to a temporary or
|
|
||||||
permanent ban.
|
|
||||||
|
|
||||||
### 3. Temporary Ban
|
|
||||||
|
|
||||||
**Community Impact**: A serious violation of community standards, including
|
|
||||||
sustained inappropriate behavior.
|
|
||||||
|
|
||||||
**Consequence**: A temporary ban from any sort of interaction or public
|
|
||||||
communication with the community for a specified period of time. No public or
|
|
||||||
private interaction with the people involved, including unsolicited interaction
|
|
||||||
with those enforcing the Code of Conduct, is allowed during this period.
|
|
||||||
Violating these terms may lead to a permanent ban.
|
|
||||||
|
|
||||||
### 4. Permanent Ban
|
|
||||||
|
|
||||||
**Community Impact**: Demonstrating a pattern of violation of community
|
|
||||||
standards, including sustained inappropriate behavior, harassment of an
|
|
||||||
individual, or aggression toward or disparagement of classes of individuals.
|
|
||||||
|
|
||||||
**Consequence**: A permanent ban from any sort of public interaction within
|
|
||||||
the community.
|
|
||||||
|
|
||||||
## Attribution
|
|
||||||
|
|
||||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
||||||
version 2.0, available at
|
|
||||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
|
||||||
|
|
||||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
|
||||||
enforcement ladder](https://github.com/mozilla/diversity).
|
|
||||||
|
|
||||||
[homepage]: https://www.contributor-covenant.org
|
|
||||||
|
|
||||||
For answers to common questions about this code of conduct, see the FAQ at
|
|
||||||
https://www.contributor-covenant.org/faq. Translations are available at
|
|
||||||
https://www.contributor-covenant.org/translations.
|
|
||||||
37
Makefile
37
Makefile
@@ -1,37 +0,0 @@
|
|||||||
NAME = xray
|
|
||||||
|
|
||||||
VERSION=$(shell git describe --always --dirty)
|
|
||||||
|
|
||||||
# NOTE: This MAKEFILE can be used to build Xray-core locally and in Automatic workflows. It is \
|
|
||||||
provided for convenience in automatic building and functions as a part of it.
|
|
||||||
# NOTE: If you need to modify this file, please be aware that:\
|
|
||||||
- This file is not the main Makefile; it only accepts environment variables and builds the \
|
|
||||||
binary.\
|
|
||||||
- Automatic building expects the correct binaries to be built by this Makefile. If you \
|
|
||||||
intend to propose a change to this Makefile, carefully review the file below and ensure \
|
|
||||||
that the change will not accidentally break the automatic building:\
|
|
||||||
.github/workflows/release.yml \
|
|
||||||
Otherwise it is recommended to contact the project maintainers.
|
|
||||||
|
|
||||||
LDFLAGS = -X github.com/xtls/xray-core/core.build=$(VERSION) -s -w -buildid=
|
|
||||||
PARAMS = -trimpath -ldflags "$(LDFLAGS)" -v
|
|
||||||
MAIN = ./main
|
|
||||||
PREFIX ?= $(shell go env GOPATH)
|
|
||||||
ifeq ($(GOOS),windows)
|
|
||||||
OUTPUT = $(NAME).exe
|
|
||||||
ADDITION = go build -o w$(NAME).exe -trimpath -ldflags "-H windowsgui $(LDFLAGS)" -v $(MAIN)
|
|
||||||
else
|
|
||||||
OUTPUT = $(NAME)
|
|
||||||
endif
|
|
||||||
ifeq ($(shell echo "$(GOARCH)" | grep -Eq "(mips|mipsle)" && echo true),true) #
|
|
||||||
ADDITION = GOMIPS=softfloat go build -o $(NAME)_softfloat -trimpath -ldflags "$(LDFLAGS)" -v $(MAIN)
|
|
||||||
endif
|
|
||||||
.PHONY: clean build
|
|
||||||
|
|
||||||
build:
|
|
||||||
go build -o $(OUTPUT) $(PARAMS) $(MAIN)
|
|
||||||
$(ADDITION)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
go clean -v -i $(PWD)
|
|
||||||
rm -f xray xray.exe wxray.exe xray_softfloat
|
|
||||||
199
README.md
199
README.md
@@ -1,20 +1,82 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
[Announcement of NFTs by Project X](https://github.com/XTLS/Xray-core/discussions/3633)
|
|
||||||
|
|
||||||
## 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)
|
||||||
|
- [Netch (NetFilter & TUN/TAP)](https://github.com/NetchX/Netch)
|
||||||
|
- Android
|
||||||
|
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
||||||
|
- [Kitsunebi](https://github.com/rurirei/Kitsunebi/tree/release_xtls)
|
||||||
|
- iOS / Mac
|
||||||
|
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
@@ -22,125 +84,6 @@
|
|||||||
|
|
||||||
[Project X Channel](https://t.me/projectXtls)
|
[Project X Channel](https://t.me/projectXtls)
|
||||||
|
|
||||||
[Project VLESS](https://t.me/projectVless) (non-Chinese)
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
- Linux Script
|
|
||||||
- [XTLS/Xray-install](https://github.com/XTLS/Xray-install) (**Official**)
|
|
||||||
- [tempest](https://github.com/team-cloudchaser/tempest) (supports [`systemd`](https://systemd.io) and [OpenRC](https://github.com/OpenRC/openrc); Linux-only)
|
|
||||||
- Docker
|
|
||||||
- [ghcr.io/xtls/xray-core](https://ghcr.io/xtls/xray-core) (**Official**)
|
|
||||||
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
|
|
||||||
- Web Panel
|
|
||||||
- [3X-UI](https://github.com/MHSanaei/3x-ui), [X-UI](https://github.com/alireza0/x-ui), [Xray-UI](https://github.com/qist/xray-ui)
|
|
||||||
- [Hiddify](https://github.com/hiddify/hiddify-config)
|
|
||||||
- [Marzneshin](https://github.com/marzneshin/marzneshin)
|
|
||||||
- [Marzban](https://github.com/Gozargah/Marzban)
|
|
||||||
- [Libertea](https://github.com/VZiChoushaDui/Libertea)
|
|
||||||
- One Click
|
|
||||||
- [Xray-REALITY](https://github.com/zxcvos/Xray-script), [xray-reality](https://github.com/sajjaddg/xray-reality), [reality-ezpz](https://github.com/aleskxyz/reality-ezpz)
|
|
||||||
- [Xray_bash_onekey](https://github.com/hello-yunshu/Xray_bash_onekey), [XTool](https://github.com/LordPenguin666/XTool)
|
|
||||||
- [v2ray-agent](https://github.com/mack-a/v2ray-agent), [Xray_onekey](https://github.com/wulabing/Xray_onekey), [ProxySU](https://github.com/proxysu/ProxySU)
|
|
||||||
- Magisk
|
|
||||||
- [Xray4Magisk](https://github.com/Asterisk4Magisk/Xray4Magisk)
|
|
||||||
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
|
|
||||||
- Homebrew
|
|
||||||
- `brew install xray`
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
- Example
|
|
||||||
- [VLESS-XTLS-uTLS-REALITY](https://github.com/XTLS/REALITY#readme)
|
|
||||||
- [VLESS-TCP-XTLS-Vision](https://github.com/XTLS/Xray-examples/tree/main/VLESS-TCP-XTLS-Vision)
|
|
||||||
- [All-in-One-fallbacks-Nginx](https://github.com/XTLS/Xray-examples/tree/main/All-in-One-fallbacks-Nginx)
|
|
||||||
- Xray-examples
|
|
||||||
- [XTLS/Xray-examples](https://github.com/XTLS/Xray-examples)
|
|
||||||
- [chika0801/Xray-examples](https://github.com/chika0801/Xray-examples)
|
|
||||||
- [lxhao61/integrated-examples](https://github.com/lxhao61/integrated-examples)
|
|
||||||
- Tutorial
|
|
||||||
- [XTLS Vision](https://github.com/chika0801/Xray-install)
|
|
||||||
- [REALITY (English)](https://cscot.pages.dev/2023/03/02/Xray-REALITY-tutorial/)
|
|
||||||
- [XTLS-Iran-Reality (English)](https://github.com/SasukeFreestyle/XTLS-Iran-Reality)
|
|
||||||
- [Xray REALITY with 'steal oneself' (English)](https://computerscot.github.io/vless-xtls-utls-reality-steal-oneself.html)
|
|
||||||
- [Xray with WireGuard inbound (English)](https://g800.pages.dev/wireguard)
|
|
||||||
|
|
||||||
## GUI Clients
|
|
||||||
|
|
||||||
- OpenWrt
|
|
||||||
- [PassWall](https://github.com/xiaorouji/openwrt-passwall), [PassWall 2](https://github.com/xiaorouji/openwrt-passwall2)
|
|
||||||
- [ShadowSocksR Plus+](https://github.com/fw876/helloworld)
|
|
||||||
- [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray))
|
|
||||||
- Windows
|
|
||||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
|
||||||
- [Furious](https://github.com/LorenEteval/Furious)
|
|
||||||
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
|
|
||||||
- Android
|
|
||||||
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
|
||||||
- [X-flutter](https://github.com/XTLS/X-flutter)
|
|
||||||
- [SaeedDev94/Xray](https://github.com/SaeedDev94/Xray)
|
|
||||||
- iOS & macOS arm64
|
|
||||||
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
|
|
||||||
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)
|
|
||||||
- macOS arm64 & x64
|
|
||||||
- [V2rayU](https://github.com/yanue/V2rayU)
|
|
||||||
- [V2RayXS](https://github.com/tzmax/V2RayXS)
|
|
||||||
- [Furious](https://github.com/LorenEteval/Furious)
|
|
||||||
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
|
|
||||||
- Linux
|
|
||||||
- [v2rayA](https://github.com/v2rayA/v2rayA)
|
|
||||||
- [Furious](https://github.com/LorenEteval/Furious)
|
|
||||||
|
|
||||||
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
|
||||||
|
|
||||||
- iOS & macOS arm64
|
|
||||||
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
|
||||||
- Xray Tools
|
|
||||||
- [xray-knife](https://github.com/lilendian0x00/xray-knife)
|
|
||||||
- Xray Wrapper
|
|
||||||
- [XTLS/libXray](https://github.com/XTLS/libXray)
|
|
||||||
- [xtlsapi](https://github.com/hiddify/xtlsapi)
|
|
||||||
- [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite)
|
|
||||||
- [Xray-core-python](https://github.com/LorenEteval/Xray-core-python)
|
|
||||||
- [xray-api](https://github.com/XVGuardian/xray-api)
|
|
||||||
- [XrayR](https://github.com/XrayR-project/XrayR)
|
|
||||||
- [XrayR-release](https://github.com/XrayR-project/XrayR-release)
|
|
||||||
- [XrayR-V2Board](https://github.com/missuo/XrayR-V2Board)
|
|
||||||
- [Clash.Meta](https://github.com/MetaCubeX/Clash.Meta)
|
|
||||||
- [clashN](https://github.com/2dust/clashN)
|
|
||||||
- [Clash Meta for Android](https://github.com/MetaCubeX/ClashMetaForAndroid)
|
|
||||||
- [sing-box](https://github.com/SagerNet/sing-box)
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
[Code of Conduct](https://github.com/XTLS/Xray-core/blob/main/CODE_OF_CONDUCT.md)
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
- [Xray-core v1.0.0](https://github.com/XTLS/Xray-core/releases/tag/v1.0.0) was forked from [v2fly-core 9a03cc5](https://github.com/v2fly/v2ray-core/commit/9a03cc5c98d04cc28320fcee26dbc236b3291256), and we have made & accumulated a huge number of enhancements over time, check [the release notes for each version](https://github.com/XTLS/Xray-core/releases).
|
|
||||||
- For third-party projects used in [Xray-core](https://github.com/XTLS/Xray-core), check your local or [the latest go.mod](https://github.com/XTLS/Xray-core/blob/main/go.mod).
|
|
||||||
|
|
||||||
## Compilation
|
|
||||||
|
|
||||||
### Windows (PowerShell)
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
$env:CGO_ENABLED=0
|
|
||||||
go build -o xray.exe -trimpath -ldflags "-s -w -buildid=" ./main
|
|
||||||
```
|
|
||||||
|
|
||||||
### Linux / macOS
|
|
||||||
|
|
||||||
```bash
|
|
||||||
CGO_ENABLED=0 go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
|
|
||||||
```
|
|
||||||
|
|
||||||
### Reproducible Releases
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make
|
|
||||||
```
|
|
||||||
|
|
||||||
## Stargazers over time
|
## Stargazers over time
|
||||||
|
|
||||||
[](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,12 +1,13 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.25.0
|
||||||
// protoc v5.28.2
|
// protoc v3.14.0
|
||||||
// source: app/commander/config.proto
|
// source: app/commander/config.proto
|
||||||
|
|
||||||
package commander
|
package commander
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
serial "github.com/xtls/xray-core/common/serial"
|
serial "github.com/xtls/xray-core/common/serial"
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
@@ -21,6 +22,10 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||||
|
// of the legacy proto package is being used.
|
||||||
|
const _ = proto.ProtoPackageIsVersion4
|
||||||
|
|
||||||
// Config is the settings for Commander.
|
// Config is the settings for Commander.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
@@ -29,8 +34,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 +41,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 +56,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 +78,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 +94,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 +109,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 +132,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 +161,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 +180,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,7 +5,6 @@ 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/signal/done"
|
"github.com/xtls/xray-core/common/signal/done"
|
||||||
@@ -32,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:
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.25.0
|
||||||
// protoc v5.28.2
|
// protoc v3.14.0
|
||||||
// source: app/dispatcher/config.proto
|
// source: app/dispatcher/config.proto
|
||||||
|
|
||||||
package dispatcher
|
package dispatcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
@@ -20,6 +21,10 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||||
|
// of the legacy proto package is being used.
|
||||||
|
const _ = proto.ProtoPackageIsVersion4
|
||||||
|
|
||||||
type SessionConfig struct {
|
type SessionConfig struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -28,9 +33,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 +48,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 +73,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 +88,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 +144,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 +162,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,15 +1,15 @@
|
|||||||
package dispatcher
|
package dispatcher
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"regexp"
|
|
||||||
"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"
|
||||||
@@ -25,7 +25,9 @@ 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
|
||||||
@@ -39,14 +41,8 @@ func (r *cachedReader) Cache(b *buf.Buffer) {
|
|||||||
if !mb.IsEmpty() {
|
if !mb.IsEmpty() {
|
||||||
r.cache, _ = buf.MergeMulti(r.cache, mb)
|
r.cache, _ = buf.MergeMulti(r.cache, mb)
|
||||||
}
|
}
|
||||||
cacheLen := r.cache.Len()
|
b.Clear()
|
||||||
if cacheLen <= b.Cap() {
|
rawBytes := b.Extend(buf.Size)
|
||||||
b.Clear()
|
|
||||||
} else {
|
|
||||||
b.Release()
|
|
||||||
*b = *buf.NewWithSize(cacheLen)
|
|
||||||
}
|
|
||||||
rawBytes := b.Extend(cacheLen)
|
|
||||||
n := r.cache.Copy(rawBytes)
|
n := r.cache.Copy(rawBytes)
|
||||||
b.Resize(0, int32(n))
|
b.Resize(0, int32(n))
|
||||||
r.Unlock()
|
r.Unlock()
|
||||||
@@ -98,18 +94,13 @@ type DefaultDispatcher struct {
|
|||||||
router routing.Router
|
router routing.Router
|
||||||
policy policy.Manager
|
policy policy.Manager
|
||||||
stats stats.Manager
|
stats stats.Manager
|
||||||
dns dns.Client
|
|
||||||
fdns dns.FakeDNSEngine
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||||
d := new(DefaultDispatcher)
|
d := new(DefaultDispatcher)
|
||||||
if err := core.RequireFeatures(ctx, func(om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dc dns.Client) error {
|
if err := core.RequireFeatures(ctx, func(om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager) error {
|
||||||
core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
return d.Init(config.(*Config), om, router, pm, sm)
|
||||||
d.fdns = fdns
|
|
||||||
})
|
|
||||||
return d.Init(config.(*Config), om, router, pm, sm, dc)
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -118,12 +109,11 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init initializes DefaultDispatcher.
|
// Init initializes DefaultDispatcher.
|
||||||
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dns dns.Client) error {
|
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager) error {
|
||||||
d.ohm = om
|
d.ohm = om
|
||||||
d.router = router
|
d.router = router
|
||||||
d.policy = pm
|
d.policy = pm
|
||||||
d.stats = sm
|
d.stats = sm
|
||||||
d.dns = dns
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,46 +176,30 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
|
|||||||
return inboundLink, outboundLink
|
return inboundLink, outboundLink
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
func shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
||||||
domain := result.Domain()
|
domain := result.Domain()
|
||||||
if domain == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, d := range request.ExcludeForDomain {
|
for _, d := range request.ExcludeForDomain {
|
||||||
if strings.HasPrefix(d, "regexp:") {
|
if 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 fakeDNSEngine != nil && protocolString != "bittorrent" && p == "fakedns" &&
|
||||||
fkr0.IsIPInIPPool(destination.Address) {
|
destination.Address.Family().IsIP() && fakeDNSEngine.GetFakeIPRange().Contains(destination.Address.IP()) {
|
||||||
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.IsProtoSubsetOf(p) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
@@ -236,51 +210,49 @@ 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)
|
||||||
|
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()
|
ob.Target = destination
|
||||||
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
|
|
||||||
} else {
|
|
||||||
ob.Target = destination
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
d.routedDispatch(ctx, outbound, destination)
|
d.routedDispatch(ctx, outbound, destination)
|
||||||
}()
|
}()
|
||||||
@@ -288,61 +260,7 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
|||||||
return inbound, nil
|
return inbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DispatchLink implements routing.Dispatcher.
|
func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool) (SniffResult, error) {
|
||||||
func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.Destination, outbound *transport.Link) error {
|
|
||||||
if !destination.IsValid() {
|
|
||||||
return errors.New("Dispatcher: Invalid destination.")
|
|
||||||
}
|
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
|
||||||
if len(outbounds) == 0 {
|
|
||||||
outbounds = []*session.Outbound{{}}
|
|
||||||
ctx = session.ContextWithOutbounds(ctx, outbounds)
|
|
||||||
}
|
|
||||||
ob := outbounds[len(outbounds)-1]
|
|
||||||
ob.OriginalTarget = destination
|
|
||||||
ob.Target = destination
|
|
||||||
content := session.ContentFromContext(ctx)
|
|
||||||
if content == nil {
|
|
||||||
content = new(session.Content)
|
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
|
||||||
}
|
|
||||||
sniffingRequest := content.SniffingRequest
|
|
||||||
if !sniffingRequest.Enabled {
|
|
||||||
d.routedDispatch(ctx, outbound, destination)
|
|
||||||
} else {
|
|
||||||
cReader := &cachedReader{
|
|
||||||
reader: outbound.Reader.(*pipe.Reader),
|
|
||||||
}
|
|
||||||
outbound.Reader = cReader
|
|
||||||
result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly, destination.Network)
|
|
||||||
if err == nil {
|
|
||||||
content.Protocol = result.Protocol()
|
|
||||||
}
|
|
||||||
if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) {
|
|
||||||
domain := result.Domain()
|
|
||||||
errors.LogInfo(ctx, "sniffed domain: ", domain)
|
|
||||||
destination.Address = net.ParseAddress(domain)
|
|
||||||
protocol := result.Protocol()
|
|
||||||
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
|
|
||||||
} else {
|
|
||||||
ob.Target = destination
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.routedDispatch(ctx, outbound, destination)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, network net.Network) (SniffResult, error) {
|
|
||||||
payload := buf.New()
|
payload := buf.New()
|
||||||
defer payload.Release()
|
defer payload.Release()
|
||||||
|
|
||||||
@@ -368,7 +286,7 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
|
|||||||
|
|
||||||
cReader.Cache(payload)
|
cReader.Cache(payload)
|
||||||
if !payload.IsEmpty() {
|
if !payload.IsEmpty() {
|
||||||
result, err := sniffer.Sniff(ctx, payload.Bytes(), network)
|
result, err := sniffer.Sniff(ctx, payload.Bytes())
|
||||||
if err != common.ErrNoClue {
|
if err != common.ErrNoClue {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
@@ -387,55 +305,30 @@ 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) {
|
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
|
||||||
ob := outbounds[len(outbounds)-1]
|
|
||||||
if hosts, ok := d.dns.(dns.HostsLookup); ok && destination.Address.Family().IsDomain() {
|
|
||||||
proxied := hosts.LookupHosts(ob.Target.String())
|
|
||||||
if proxied != nil {
|
|
||||||
ro := ob.RouteTarget == destination
|
|
||||||
destination.Address = *proxied
|
|
||||||
if ro {
|
|
||||||
ob.RouteTarget = destination
|
|
||||||
} else {
|
|
||||||
ob.Target = destination
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
||||||
var handler outbound.Handler
|
var handler outbound.Handler
|
||||||
|
|
||||||
|
skipRoutePick := false
|
||||||
|
if content := session.ContentFromContext(ctx); content != nil {
|
||||||
|
skipRoutePick = content.SkipRoutePick
|
||||||
|
}
|
||||||
|
|
||||||
routingLink := routing_session.AsRoutingContext(ctx)
|
routingLink := routing_session.AsRoutingContext(ctx)
|
||||||
inTag := routingLink.GetInboundTag()
|
inTag := routingLink.GetInboundTag()
|
||||||
isPickRoute := 0
|
isPickRoute := false
|
||||||
if forcedOutboundTag := session.GetForcedOutboundTagFromContext(ctx); forcedOutboundTag != "" {
|
if d.router != nil && !skipRoutePick {
|
||||||
ctx = session.SetForcedOutboundTagToContext(ctx, "")
|
|
||||||
if h := d.ohm.GetHandler(forcedOutboundTag); h != nil {
|
|
||||||
isPickRoute = 1
|
|
||||||
errors.LogInfo(ctx, "taking platform initialized detour [", forcedOutboundTag, "] for [", destination, "]")
|
|
||||||
handler = h
|
|
||||||
} else {
|
|
||||||
errors.LogError(ctx, "non existing tag for platform initialized detour: ", forcedOutboundTag)
|
|
||||||
common.Close(link.Writer)
|
|
||||||
common.Interrupt(link.Reader)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else if d.router != nil {
|
|
||||||
if route, err := d.router.PickRoute(routingLink); err == nil {
|
if route, err := d.router.PickRoute(routingLink); err == nil {
|
||||||
outTag := route.GetOutboundTag()
|
outTag := route.GetOutboundTag()
|
||||||
|
isPickRoute = true
|
||||||
if h := d.ohm.GetHandler(outTag); h != nil {
|
if h := d.ohm.GetHandler(outTag); h != nil {
|
||||||
isPickRoute = 2
|
newError("taking detour [", outTag, "] 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: ", outTag).AtWarning().WriteToLog(session.ExportIDToError(ctx))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errors.LogInfo(ctx, "default route for ", destination)
|
newError("default route for ", destination).WriteToLog(session.ExportIDToError(ctx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,23 +337,26 @@ 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 == "" {
|
if isPickRoute {
|
||||||
accessMessage.Detour = tag
|
if inTag != "" {
|
||||||
} else if isPickRoute == 1 {
|
accessMessage.Detour = inTag + " -> " + tag
|
||||||
accessMessage.Detour = inTag + " ==> " + tag
|
} else {
|
||||||
} else if isPickRoute == 2 {
|
accessMessage.Detour = tag
|
||||||
accessMessage.Detour = inTag + " -> " + tag
|
}
|
||||||
} else {
|
} else {
|
||||||
accessMessage.Detour = inTag + " >> " + tag
|
if inTag != "" {
|
||||||
|
accessMessage.Detour = inTag + " >> " + tag
|
||||||
|
} else {
|
||||||
|
accessMessage.Detour = 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{})
|
||||||
|
}
|
||||||
@@ -2,49 +2,36 @@ package dispatcher
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ipAddressInRangeValueI := ctx.Value(ipAddressInRange); ipAddressInRangeValueI != nil {
|
|
||||||
ipAddressInRangeValue := ipAddressInRangeValueI.(*ipAddressInRangeOpt)
|
|
||||||
if fkr0, ok := fakeDNSEngine.(dns.FakeDNSEngineRev0); ok {
|
|
||||||
inPool := fkr0.IsIPInIPPool(ob.Target.Address)
|
|
||||||
ipAddressInRangeValue.addressInRange = &inPool
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, common.ErrNoClue
|
return nil, common.ErrNoClue
|
||||||
}, metadataSniffer: true}, nil
|
}, metadataSniffer: true}, nil
|
||||||
}
|
}
|
||||||
@@ -60,62 +47,3 @@ func (fakeDNSSniffResult) Protocol() string {
|
|||||||
func (f fakeDNSSniffResult) Domain() string {
|
func (f fakeDNSSniffResult) Domain() string {
|
||||||
return f.domainName
|
return f.domainName
|
||||||
}
|
}
|
||||||
|
|
||||||
type fakeDNSExtraOpts int
|
|
||||||
|
|
||||||
const ipAddressInRange fakeDNSExtraOpts = 1
|
|
||||||
|
|
||||||
type ipAddressInRangeOpt struct {
|
|
||||||
addressInRange *bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type DNSThenOthersSniffResult struct {
|
|
||||||
domainName string
|
|
||||||
protocolOriginalName string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f DNSThenOthersSniffResult) IsProtoSubsetOf(protocolName string) bool {
|
|
||||||
return strings.HasPrefix(protocolName, f.protocolOriginalName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (DNSThenOthersSniffResult) Protocol() string {
|
|
||||||
return "fakedns+others"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f DNSThenOthersSniffResult) Domain() string {
|
|
||||||
return f.domainName
|
|
||||||
}
|
|
||||||
|
|
||||||
func newFakeDNSThenOthers(ctx context.Context, fakeDNSSniffer protocolSnifferWithMetadata, others []protocolSnifferWithMetadata) (
|
|
||||||
protocolSnifferWithMetadata, error,
|
|
||||||
) { // nolint: unparam
|
|
||||||
// ctx may be used in the future
|
|
||||||
_ = ctx
|
|
||||||
return protocolSnifferWithMetadata{
|
|
||||||
protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) {
|
|
||||||
ipAddressInRangeValue := &ipAddressInRangeOpt{}
|
|
||||||
ctx = context.WithValue(ctx, ipAddressInRange, ipAddressInRangeValue)
|
|
||||||
result, err := fakeDNSSniffer.protocolSniffer(ctx, bytes)
|
|
||||||
if err == nil {
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
if ipAddressInRangeValue.addressInRange != nil {
|
|
||||||
if *ipAddressInRangeValue.addressInRange {
|
|
||||||
for _, v := range others {
|
|
||||||
if v.metadataSniffer || bytes != nil {
|
|
||||||
if result, err := v.protocolSniffer(ctx, bytes); err == nil {
|
|
||||||
return DNSThenOthersSniffResult{domainName: result.Domain(), protocolOriginalName: result.Protocol()}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, common.ErrNoClue
|
|
||||||
}
|
|
||||||
errors.LogDebug(ctx, "ip address not in fake dns range, return as is")
|
|
||||||
return nil, common.ErrNoClue
|
|
||||||
}
|
|
||||||
errors.LogWarning(ctx, "fake dns sniffer did not set address in range option, assume false.")
|
|
||||||
return nil, common.ErrNoClue
|
|
||||||
},
|
|
||||||
metadataSniffer: false,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,11 +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/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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,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 {
|
||||||
@@ -35,31 +31,24 @@ 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 {
|
||||||
others := ret.sniffer
|
|
||||||
ret.sniffer = append(ret.sniffer, sniffer)
|
ret.sniffer = append(ret.sniffer, sniffer)
|
||||||
fakeDNSThenOthers, err := newFakeDNSThenOthers(ctx, sniffer, others)
|
|
||||||
if err == nil {
|
|
||||||
ret.sniffer = append([]protocolSnifferWithMetadata{fakeDNSThenOthers}, ret.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 {
|
||||||
s := si.protocolSniffer
|
s := si.protocolSniffer
|
||||||
if si.metadataSniffer || si.network != network {
|
if si.metadataSniffer {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
result, err := s(c, payload)
|
result, err := s(c, payload)
|
||||||
@@ -132,7 +121,3 @@ func (c compositeResult) ProtocolForDomainResult() string {
|
|||||||
type SnifferResultComposite interface {
|
type SnifferResultComposite interface {
|
||||||
ProtocolForDomainResult() string
|
ProtocolForDomainResult() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type SnifferIsProtoSubsetOf interface {
|
|
||||||
IsProtoSubsetOf(protocolName string) bool
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
package dns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/common/strmatcher"
|
|
||||||
"github.com/xtls/xray-core/common/uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
var typeMap = map[DomainMatchingType]strmatcher.Type{
|
|
||||||
DomainMatchingType_Full: strmatcher.Full,
|
|
||||||
DomainMatchingType_Subdomain: strmatcher.Domain,
|
|
||||||
DomainMatchingType_Keyword: strmatcher.Substr,
|
|
||||||
DomainMatchingType_Regex: strmatcher.Regex,
|
|
||||||
}
|
|
||||||
|
|
||||||
// References:
|
|
||||||
// https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml
|
|
||||||
// https://unix.stackexchange.com/questions/92441/whats-the-difference-between-local-home-and-lan
|
|
||||||
var localTLDsAndDotlessDomains = []*NameServer_PriorityDomain{
|
|
||||||
{Type: DomainMatchingType_Regex, Domain: "^[^.]+$"}, // This will only match domains without any dot
|
|
||||||
{Type: DomainMatchingType_Subdomain, Domain: "local"},
|
|
||||||
{Type: DomainMatchingType_Subdomain, Domain: "localdomain"},
|
|
||||||
{Type: DomainMatchingType_Subdomain, Domain: "localhost"},
|
|
||||||
{Type: DomainMatchingType_Subdomain, Domain: "lan"},
|
|
||||||
{Type: DomainMatchingType_Subdomain, Domain: "home.arpa"},
|
|
||||||
{Type: DomainMatchingType_Subdomain, Domain: "example"},
|
|
||||||
{Type: DomainMatchingType_Subdomain, Domain: "invalid"},
|
|
||||||
{Type: DomainMatchingType_Subdomain, Domain: "test"},
|
|
||||||
}
|
|
||||||
|
|
||||||
var localTLDsAndDotlessDomainsRule = &NameServer_OriginalRule{
|
|
||||||
Rule: "geosite:private",
|
|
||||||
Size: uint32(len(localTLDsAndDotlessDomains)),
|
|
||||||
}
|
|
||||||
|
|
||||||
func toStrMatcher(t DomainMatchingType, domain string) (strmatcher.Matcher, error) {
|
|
||||||
strMType, f := typeMap[t]
|
|
||||||
if !f {
|
|
||||||
return nil, errors.New("unknown mapping type", t).AtWarning()
|
|
||||||
}
|
|
||||||
matcher, err := strMType.New(domain)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("failed to create str matcher").Base(err)
|
|
||||||
}
|
|
||||||
return matcher, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func toNetIP(addrs []net.Address) ([]net.IP, error) {
|
|
||||||
ips := make([]net.IP, 0, len(addrs))
|
|
||||||
for _, addr := range addrs {
|
|
||||||
if addr.Family().IsIP() {
|
|
||||||
ips = append(ips, addr.IP())
|
|
||||||
} else {
|
|
||||||
return nil, errors.New("Failed to convert address", addr, "to Net IP.").AtWarning()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ips, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateRandomTag() string {
|
|
||||||
id := uuid.New()
|
|
||||||
return "xray.system." + id.String()
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.25.0
|
||||||
// protoc v5.28.2
|
// protoc v3.14.0
|
||||||
// source: app/dns/config.proto
|
// source: app/dns/config.proto
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
router "github.com/xtls/xray-core/app/router"
|
router "github.com/xtls/xray-core/app/router"
|
||||||
net "github.com/xtls/xray-core/common/net"
|
net "github.com/xtls/xray-core/common/net"
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
@@ -22,6 +23,10 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||||
|
// of the legacy proto package is being used.
|
||||||
|
const _ = proto.ProtoPackageIsVersion4
|
||||||
|
|
||||||
type DomainMatchingType int32
|
type DomainMatchingType int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -74,74 +79,24 @@ func (DomainMatchingType) EnumDescriptor() ([]byte, []int) {
|
|||||||
return file_app_dns_config_proto_rawDescGZIP(), []int{0}
|
return file_app_dns_config_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
type QueryStrategy int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
QueryStrategy_USE_IP QueryStrategy = 0
|
|
||||||
QueryStrategy_USE_IP4 QueryStrategy = 1
|
|
||||||
QueryStrategy_USE_IP6 QueryStrategy = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
// Enum value maps for QueryStrategy.
|
|
||||||
var (
|
|
||||||
QueryStrategy_name = map[int32]string{
|
|
||||||
0: "USE_IP",
|
|
||||||
1: "USE_IP4",
|
|
||||||
2: "USE_IP6",
|
|
||||||
}
|
|
||||||
QueryStrategy_value = map[string]int32{
|
|
||||||
"USE_IP": 0,
|
|
||||||
"USE_IP4": 1,
|
|
||||||
"USE_IP6": 2,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (x QueryStrategy) Enum() *QueryStrategy {
|
|
||||||
p := new(QueryStrategy)
|
|
||||||
*p = x
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x QueryStrategy) String() string {
|
|
||||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (QueryStrategy) Descriptor() protoreflect.EnumDescriptor {
|
|
||||||
return file_app_dns_config_proto_enumTypes[1].Descriptor()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (QueryStrategy) Type() protoreflect.EnumType {
|
|
||||||
return &file_app_dns_config_proto_enumTypes[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x QueryStrategy) Number() protoreflect.EnumNumber {
|
|
||||||
return protoreflect.EnumNumber(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use QueryStrategy.Descriptor instead.
|
|
||||||
func (QueryStrategy) EnumDescriptor() ([]byte, []int) {
|
|
||||||
return file_app_dns_config_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
type NameServer struct {
|
type NameServer struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Address *net.Endpoint `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
|
Address *net.Endpoint `protobuf:"bytes,1,opt,name=address,proto3" json:"address,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"`
|
|
||||||
PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
|
PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
|
||||||
Geoip []*router.GeoIP `protobuf:"bytes,3,rep,name=geoip,proto3" json:"geoip,omitempty"`
|
Geoip []*router.GeoIP `protobuf:"bytes,3,rep,name=geoip,proto3" json:"geoip,omitempty"`
|
||||||
OriginalRules []*NameServer_OriginalRule `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
|
OriginalRules []*NameServer_OriginalRule `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
|
||||||
QueryStrategy QueryStrategy `protobuf:"varint,7,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) Reset() {
|
func (x *NameServer) Reset() {
|
||||||
*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 {
|
||||||
@@ -152,7 +107,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)
|
||||||
@@ -174,20 +129,6 @@ func (x *NameServer) GetAddress() *net.Endpoint {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) GetClientIp() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.ClientIp
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *NameServer) GetSkipFallback() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.SkipFallback
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *NameServer) GetPrioritizedDomain() []*NameServer_PriorityDomain {
|
func (x *NameServer) GetPrioritizedDomain() []*NameServer_PriorityDomain {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.PrioritizedDomain
|
return x.PrioritizedDomain
|
||||||
@@ -209,39 +150,39 @@ func (x *NameServer) GetOriginalRules() []*NameServer_OriginalRule {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) GetQueryStrategy() QueryStrategy {
|
|
||||||
if x != nil {
|
|
||||||
return x.QueryStrategy
|
|
||||||
}
|
|
||||||
return QueryStrategy_USE_IP
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
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"`
|
||||||
StaticHosts []*Config_HostMapping `protobuf:"bytes,4,rep,name=static_hosts,json=staticHosts,proto3" json:"static_hosts,omitempty"`
|
StaticHosts []*Config_HostMapping `protobuf:"bytes,4,rep,name=static_hosts,json=staticHosts,proto3" json:"static_hosts,omitempty"`
|
||||||
// Tag is the inbound tag of DNS client.
|
// Tag is the inbound tag of DNS client.
|
||||||
Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
|
Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
// DisableCache disables DNS cache
|
|
||||||
DisableCache bool `protobuf:"varint,8,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
|
|
||||||
QueryStrategy QueryStrategy `protobuf:"varint,9,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
|
||||||
DisableFallback bool `protobuf:"varint,10,opt,name=disableFallback,proto3" json:"disableFallback,omitempty"`
|
|
||||||
DisableFallbackIfMatch bool `protobuf:"varint,11,opt,name=disableFallbackIfMatch,proto3" json:"disableFallbackIfMatch,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
@@ -252,7 +193,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)
|
||||||
@@ -267,6 +208,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
|
||||||
@@ -274,6 +223,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
|
||||||
@@ -295,34 +252,6 @@ func (x *Config) GetTag() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetDisableCache() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.DisableCache
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetQueryStrategy() QueryStrategy {
|
|
||||||
if x != nil {
|
|
||||||
return x.QueryStrategy
|
|
||||||
}
|
|
||||||
return QueryStrategy_USE_IP
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetDisableFallback() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.DisableFallback
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetDisableFallbackIfMatch() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.DisableFallbackIfMatch
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type NameServer_PriorityDomain struct {
|
type NameServer_PriorityDomain struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -334,9 +263,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 {
|
||||||
@@ -347,7 +278,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)
|
||||||
@@ -387,9 +318,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 {
|
||||||
@@ -400,7 +333,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)
|
||||||
@@ -438,15 +371,18 @@ type Config_HostMapping struct {
|
|||||||
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
|
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
|
||||||
Ip [][]byte `protobuf:"bytes,3,rep,name=ip,proto3" json:"ip,omitempty"`
|
Ip [][]byte `protobuf:"bytes,3,rep,name=ip,proto3" json:"ip,omitempty"`
|
||||||
// ProxiedDomain indicates the mapped domain has the same IP address on this
|
// ProxiedDomain indicates the mapped domain has the same IP address on this
|
||||||
// domain. Xray will use this domain for IP queries.
|
// domain. Xray will use this domain for IP queries. This field is only
|
||||||
|
// effective if ip is empty.
|
||||||
ProxiedDomain string `protobuf:"bytes,4,opt,name=proxied_domain,json=proxiedDomain,proto3" json:"proxied_domain,omitempty"`
|
ProxiedDomain string `protobuf:"bytes,4,opt,name=proxied_domain,json=proxiedDomain,proto3" json:"proxied_domain,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
@@ -456,8 +392,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)
|
||||||
@@ -469,7 +405,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 {
|
||||||
@@ -505,92 +441,82 @@ 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, 0xb2, 0x04, 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, 0xad, 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, 0x56, 0x0a, 0x12, 0x70, 0x72, 0x69,
|
||||||
0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01,
|
0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18,
|
||||||
0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
|
0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
0x12, 0x56, 0x0a, 0x12, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x5f,
|
0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e,
|
||||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78,
|
0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x11,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65,
|
0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||||
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44,
|
0x6e, 0x12, 0x2c, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
|
||||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x11, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a,
|
0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||||
0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69,
|
0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x12,
|
||||||
0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
|
0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65,
|
||||||
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52,
|
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
|
||||||
0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e,
|
0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65,
|
||||||
0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25,
|
0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d,
|
||||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61,
|
0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x1a, 0x5e, 0x0a,
|
||||||
0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61,
|
0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12,
|
||||||
0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52,
|
0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e,
|
||||||
0x75, 0x6c, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74,
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d,
|
||||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78,
|
0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72,
|
0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18,
|
||||||
0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79,
|
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36, 0x0a,
|
||||||
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x1a, 0x5e, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f,
|
0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a,
|
||||||
0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79,
|
0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75, 0x6c,
|
||||||
0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
||||||
0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61,
|
0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x9f, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
|
0x12, 0x3f, 0x0a, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x18,
|
||||||
0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67,
|
0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
||||||
0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65,
|
0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04,
|
0x73, 0x12, 0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||||
0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65,
|
0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||||
0x22, 0x9c, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0b, 0x6e,
|
0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||||
0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b,
|
0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x05,
|
||||||
0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e,
|
0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72,
|
||||||
0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65,
|
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||||
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
|
0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x02, 0x18, 0x01,
|
||||||
0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||||
0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x68, 0x6f,
|
0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65,
|
||||||
0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
0x6e, 0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x68,
|
||||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
|
0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61,
|
||||||
0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73, 0x74, 0x61,
|
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18,
|
0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73, 0x74,
|
||||||
0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69,
|
0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67,
|
||||||
0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08,
|
0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x1a, 0x55, 0x0a, 0x0a, 0x48,
|
||||||
0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x42,
|
0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
|
||||||
0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x05, 0x76,
|
||||||
0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61,
|
||||||
0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74,
|
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f,
|
||||||
0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
|
0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
|
||||||
0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c,
|
0x38, 0x01, 0x1a, 0x92, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69,
|
||||||
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x69, 0x73,
|
0x6e, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
|
||||||
0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x36, 0x0a, 0x16,
|
0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e,
|
||||||
0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49,
|
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79,
|
||||||
0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x64, 0x69,
|
0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61,
|
||||||
0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d,
|
0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||||
0x61, 0x74, 0x63, 0x68, 0x1a, 0x92, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70,
|
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70,
|
||||||
0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,
|
0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61,
|
||||||
0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e,
|
0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65,
|
||||||
0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67,
|
0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2a, 0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||||
0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f,
|
0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a,
|
||||||
0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61,
|
0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64, 0x6f,
|
||||||
0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x02,
|
0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72,
|
||||||
0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f,
|
0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x42, 0x46,
|
||||||
0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78,
|
0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64,
|
||||||
0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x2a,
|
0x6e, 0x73, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e,
|
0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f,
|
||||||
0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12,
|
0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41,
|
||||||
0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b,
|
0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52,
|
|
||||||
0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x2a, 0x35, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53,
|
|
||||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49,
|
|
||||||
0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x01,
|
|
||||||
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x02, 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 (
|
||||||
@@ -605,35 +531,37 @@ func file_app_dns_config_proto_rawDescGZIP() []byte {
|
|||||||
return file_app_dns_config_proto_rawDescData
|
return file_app_dns_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_app_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
var file_app_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
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
|
(*NameServer)(nil), // 1: xray.app.dns.NameServer
|
||||||
(*NameServer)(nil), // 2: xray.app.dns.NameServer
|
(*Config)(nil), // 2: xray.app.dns.Config
|
||||||
(*Config)(nil), // 3: xray.app.dns.Config
|
(*NameServer_PriorityDomain)(nil), // 3: xray.app.dns.NameServer.PriorityDomain
|
||||||
(*NameServer_PriorityDomain)(nil), // 4: xray.app.dns.NameServer.PriorityDomain
|
(*NameServer_OriginalRule)(nil), // 4: xray.app.dns.NameServer.OriginalRule
|
||||||
(*NameServer_OriginalRule)(nil), // 5: xray.app.dns.NameServer.OriginalRule
|
nil, // 5: xray.app.dns.Config.HostsEntry
|
||||||
(*Config_HostMapping)(nil), // 6: xray.app.dns.Config.HostMapping
|
(*Config_HostMapping)(nil), // 6: xray.app.dns.Config.HostMapping
|
||||||
(*net.Endpoint)(nil), // 7: xray.common.net.Endpoint
|
(*net.Endpoint)(nil), // 7: xray.common.net.Endpoint
|
||||||
(*router.GeoIP)(nil), // 8: xray.app.router.GeoIP
|
(*router.GeoIP)(nil), // 8: xray.app.router.GeoIP
|
||||||
|
(*net.IPOrDomain)(nil), // 9: 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
|
7, // 0: xray.app.dns.NameServer.address:type_name -> xray.common.net.Endpoint
|
||||||
4, // 1: xray.app.dns.NameServer.prioritized_domain:type_name -> xray.app.dns.NameServer.PriorityDomain
|
3, // 1: xray.app.dns.NameServer.prioritized_domain:type_name -> xray.app.dns.NameServer.PriorityDomain
|
||||||
8, // 2: xray.app.dns.NameServer.geoip:type_name -> xray.app.router.GeoIP
|
8, // 2: xray.app.dns.NameServer.geoip:type_name -> xray.app.router.GeoIP
|
||||||
5, // 3: xray.app.dns.NameServer.original_rules:type_name -> xray.app.dns.NameServer.OriginalRule
|
4, // 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
|
7, // 4: xray.app.dns.Config.NameServers:type_name -> xray.common.net.Endpoint
|
||||||
2, // 5: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer
|
1, // 5: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer
|
||||||
6, // 6: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
5, // 6: xray.app.dns.Config.Hosts:type_name -> xray.app.dns.Config.HostsEntry
|
||||||
1, // 7: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
6, // 7: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
||||||
0, // 8: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
|
0, // 8: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
|
||||||
0, // 9: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType
|
9, // 9: xray.app.dns.Config.HostsEntry.value:type_name -> xray.common.net.IPOrDomain
|
||||||
10, // [10:10] is the sub-list for method output_type
|
0, // 10: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType
|
||||||
10, // [10:10] is the sub-list for method input_type
|
11, // [11:11] is the sub-list for method output_type
|
||||||
10, // [10:10] is the sub-list for extension type_name
|
11, // [11:11] is the sub-list for method input_type
|
||||||
10, // [10:10] is the sub-list for extension extendee
|
11, // [11:11] is the sub-list for extension type_name
|
||||||
0, // [0:10] is the sub-list for field type_name
|
11, // [11:11] is the sub-list for extension extendee
|
||||||
|
0, // [0:11] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_dns_config_proto_init() }
|
func init() { file_app_dns_config_proto_init() }
|
||||||
@@ -641,13 +569,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: 1,
|
||||||
NumMessages: 5,
|
NumMessages: 6,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,13 +6,12 @@ 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";
|
||||||
|
|
||||||
message NameServer {
|
message NameServer {
|
||||||
xray.common.net.Endpoint address = 1;
|
xray.common.net.Endpoint address = 1;
|
||||||
bytes client_ip = 5;
|
|
||||||
bool skipFallback = 6;
|
|
||||||
|
|
||||||
message PriorityDomain {
|
message PriorityDomain {
|
||||||
DomainMatchingType type = 1;
|
DomainMatchingType type = 1;
|
||||||
@@ -27,7 +26,6 @@ message NameServer {
|
|||||||
repeated PriorityDomain prioritized_domain = 2;
|
repeated PriorityDomain prioritized_domain = 2;
|
||||||
repeated xray.app.router.GeoIP geoip = 3;
|
repeated xray.app.router.GeoIP geoip = 3;
|
||||||
repeated OriginalRule original_rules = 4;
|
repeated OriginalRule original_rules = 4;
|
||||||
QueryStrategy query_strategy = 7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DomainMatchingType {
|
enum DomainMatchingType {
|
||||||
@@ -37,17 +35,19 @@ enum DomainMatchingType {
|
|||||||
Regex = 3;
|
Regex = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum QueryStrategy {
|
|
||||||
USE_IP = 0;
|
|
||||||
USE_IP4 = 1;
|
|
||||||
USE_IP6 = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
@@ -59,7 +59,8 @@ message Config {
|
|||||||
repeated bytes ip = 3;
|
repeated bytes ip = 3;
|
||||||
|
|
||||||
// ProxiedDomain indicates the mapped domain has the same IP address on this
|
// ProxiedDomain indicates the mapped domain has the same IP address on this
|
||||||
// domain. Xray will use this domain for IP queries.
|
// domain. Xray will use this domain for IP queries. This field is only
|
||||||
|
// effective if ip is empty.
|
||||||
string proxied_domain = 4;
|
string proxied_domain = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,12 +70,4 @@ message Config {
|
|||||||
string tag = 6;
|
string tag = 6;
|
||||||
|
|
||||||
reserved 7;
|
reserved 7;
|
||||||
|
|
||||||
// DisableCache disables DNS cache
|
|
||||||
bool disableCache = 8;
|
|
||||||
|
|
||||||
QueryStrategy query_strategy = 9;
|
|
||||||
|
|
||||||
bool disableFallback = 10;
|
|
||||||
bool disableFallbackIfMatch = 11;
|
|
||||||
}
|
}
|
||||||
|
|||||||
297
app/dns/dns.go
297
app/dns/dns.go
@@ -1,299 +1,4 @@
|
|||||||
// Package dns is an implementation of core.DNS feature.
|
// Package dns is an implementation of core.DNS feature.
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/router"
|
|
||||||
"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/session"
|
|
||||||
"github.com/xtls/xray-core/common/strmatcher"
|
|
||||||
"github.com/xtls/xray-core/features/dns"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DNS is a DNS rely server.
|
|
||||||
type DNS struct {
|
|
||||||
sync.Mutex
|
|
||||||
tag string
|
|
||||||
disableCache bool
|
|
||||||
disableFallback bool
|
|
||||||
disableFallbackIfMatch bool
|
|
||||||
ipOption *dns.IPOption
|
|
||||||
hosts *StaticHosts
|
|
||||||
clients []*Client
|
|
||||||
ctx context.Context
|
|
||||||
domainMatcher strmatcher.IndexMatcher
|
|
||||||
matcherInfos []*DomainMatcherInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// DomainMatcherInfo contains information attached to index returned by Server.domainMatcher
|
|
||||||
type DomainMatcherInfo struct {
|
|
||||||
clientIdx uint16
|
|
||||||
domainRuleIdx uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new DNS server with given configuration.
|
|
||||||
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
|
|
||||||
switch len(config.ClientIp) {
|
|
||||||
case 0, net.IPv4len, net.IPv6len:
|
|
||||||
clientIP = net.IP(config.ClientIp)
|
|
||||||
default:
|
|
||||||
return nil, errors.New("unexpected client IP length ", len(config.ClientIp))
|
|
||||||
}
|
|
||||||
|
|
||||||
var ipOption *dns.IPOption
|
|
||||||
switch config.QueryStrategy {
|
|
||||||
case QueryStrategy_USE_IP:
|
|
||||||
ipOption = &dns.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
FakeEnable: false,
|
|
||||||
}
|
|
||||||
case QueryStrategy_USE_IP4:
|
|
||||||
ipOption = &dns.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: false,
|
|
||||||
FakeEnable: false,
|
|
||||||
}
|
|
||||||
case QueryStrategy_USE_IP6:
|
|
||||||
ipOption = &dns.IPOption{
|
|
||||||
IPv4Enable: false,
|
|
||||||
IPv6Enable: true,
|
|
||||||
FakeEnable: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hosts, err := NewStaticHosts(config.StaticHosts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("failed to create hosts").Base(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
clients := []*Client{}
|
|
||||||
domainRuleCount := 0
|
|
||||||
for _, ns := range config.NameServer {
|
|
||||||
domainRuleCount += len(ns.PrioritizedDomain)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatcherInfos is ensured to cover the maximum index domainMatcher could return, where matcher's index starts from 1
|
|
||||||
matcherInfos := make([]*DomainMatcherInfo, domainRuleCount+1)
|
|
||||||
domainMatcher := &strmatcher.MatcherGroup{}
|
|
||||||
geoipContainer := router.GeoIPMatcherContainer{}
|
|
||||||
|
|
||||||
for _, ns := range config.NameServer {
|
|
||||||
clientIdx := len(clients)
|
|
||||||
updateDomain := func(domainRule strmatcher.Matcher, originalRuleIdx int, matcherInfos []*DomainMatcherInfo) error {
|
|
||||||
midx := domainMatcher.Add(domainRule)
|
|
||||||
matcherInfos[midx] = &DomainMatcherInfo{
|
|
||||||
clientIdx: uint16(clientIdx),
|
|
||||||
domainRuleIdx: uint16(originalRuleIdx),
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
myClientIP := clientIP
|
|
||||||
switch len(ns.ClientIp) {
|
|
||||||
case net.IPv4len, net.IPv6len:
|
|
||||||
myClientIP = net.IP(ns.ClientIp)
|
|
||||||
}
|
|
||||||
client, err := NewClient(ctx, ns, myClientIP, geoipContainer, &matcherInfos, updateDomain)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("failed to create client").Base(err)
|
|
||||||
}
|
|
||||||
clients = append(clients, client)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is no DNS client in config, add a `localhost` DNS client
|
|
||||||
if len(clients) == 0 {
|
|
||||||
clients = append(clients, NewLocalDNSClient())
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DNS{
|
|
||||||
tag: tag,
|
|
||||||
hosts: hosts,
|
|
||||||
ipOption: ipOption,
|
|
||||||
clients: clients,
|
|
||||||
ctx: ctx,
|
|
||||||
domainMatcher: domainMatcher,
|
|
||||||
matcherInfos: matcherInfos,
|
|
||||||
disableCache: config.DisableCache,
|
|
||||||
disableFallback: config.DisableFallback,
|
|
||||||
disableFallbackIfMatch: config.DisableFallbackIfMatch,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type implements common.HasType.
|
|
||||||
func (*DNS) Type() interface{} {
|
|
||||||
return dns.ClientType()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start implements common.Runnable.
|
|
||||||
func (s *DNS) Start() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close implements common.Closable.
|
|
||||||
func (s *DNS) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsOwnLink implements proxy.dns.ownLinkVerifier
|
|
||||||
func (s *DNS) IsOwnLink(ctx context.Context) bool {
|
|
||||||
inbound := session.InboundFromContext(ctx)
|
|
||||||
return inbound != nil && inbound.Tag == s.tag
|
|
||||||
}
|
|
||||||
|
|
||||||
// LookupIP implements dns.Client.
|
|
||||||
func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
|
|
||||||
if domain == "" {
|
|
||||||
return nil, errors.New("empty domain name")
|
|
||||||
}
|
|
||||||
|
|
||||||
option.IPv4Enable = option.IPv4Enable && s.ipOption.IPv4Enable
|
|
||||||
option.IPv6Enable = option.IPv6Enable && s.ipOption.IPv6Enable
|
|
||||||
|
|
||||||
if !option.IPv4Enable && !option.IPv6Enable {
|
|
||||||
return nil, dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normalize the FQDN form query
|
|
||||||
domain = strings.TrimSuffix(domain, ".")
|
|
||||||
|
|
||||||
// Static host lookup
|
|
||||||
switch addrs := s.hosts.Lookup(domain, option); {
|
|
||||||
case addrs == nil: // Domain not recorded in static host
|
|
||||||
break
|
|
||||||
case len(addrs) == 0: // Domain recorded, but no valid IP returned (e.g. IPv4 address with only IPv6 enabled)
|
|
||||||
return nil, dns.ErrEmptyResponse
|
|
||||||
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Domain replacement
|
|
||||||
errors.LogInfo(s.ctx, "domain replaced: ", domain, " -> ", addrs[0].Domain())
|
|
||||||
domain = addrs[0].Domain()
|
|
||||||
default: // Successfully found ip records in static host
|
|
||||||
errors.LogInfo(s.ctx, "returning ", len(addrs), " IP(s) for domain ", domain, " -> ", addrs)
|
|
||||||
return toNetIP(addrs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name servers lookup
|
|
||||||
errs := []error{}
|
|
||||||
ctx := session.ContextWithInbound(s.ctx, &session.Inbound{Tag: s.tag})
|
|
||||||
for _, client := range s.sortClients(domain) {
|
|
||||||
if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
|
|
||||||
errors.LogDebug(s.ctx, "skip DNS resolution for domain ", domain, " at server ", client.Name())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ips, err := client.QueryIP(ctx, domain, option, s.disableCache)
|
|
||||||
if len(ips) > 0 {
|
|
||||||
return ips, nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
errors.LogInfoInner(s.ctx, err, "failed to lookup ip for domain ", domain, " at server ", client.Name())
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
// 5 for RcodeRefused in miekg/dns, hardcode to reduce binary size
|
|
||||||
if err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch && err != dns.ErrEmptyResponse && dns.RCodeFromError(err) != 5 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("returning nil for domain ", domain).Base(errors.Combine(errs...))
|
|
||||||
}
|
|
||||||
|
|
||||||
// LookupHosts implements dns.HostsLookup.
|
|
||||||
func (s *DNS) LookupHosts(domain string) *net.Address {
|
|
||||||
domain = strings.TrimSuffix(domain, ".")
|
|
||||||
if domain == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// Normalize the FQDN form query
|
|
||||||
addrs := s.hosts.Lookup(domain, *s.ipOption)
|
|
||||||
if len(addrs) > 0 {
|
|
||||||
errors.LogInfo(s.ctx, "domain replaced: ", domain, " -> ", addrs[0].String())
|
|
||||||
return &addrs[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetIPOption implements ClientWithIPOption.
|
|
||||||
func (s *DNS) GetIPOption() *dns.IPOption {
|
|
||||||
return s.ipOption
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetQueryOption implements ClientWithIPOption.
|
|
||||||
func (s *DNS) SetQueryOption(isIPv4Enable, isIPv6Enable bool) {
|
|
||||||
s.ipOption.IPv4Enable = isIPv4Enable
|
|
||||||
s.ipOption.IPv6Enable = isIPv6Enable
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetFakeDNSOption implements ClientWithIPOption.
|
|
||||||
func (s *DNS) SetFakeDNSOption(isFakeEnable bool) {
|
|
||||||
s.ipOption.FakeEnable = isFakeEnable
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DNS) sortClients(domain string) []*Client {
|
|
||||||
clients := make([]*Client, 0, len(s.clients))
|
|
||||||
clientUsed := make([]bool, len(s.clients))
|
|
||||||
clientNames := make([]string, 0, len(s.clients))
|
|
||||||
domainRules := []string{}
|
|
||||||
|
|
||||||
// Priority domain matching
|
|
||||||
hasMatch := false
|
|
||||||
for _, match := range s.domainMatcher.Match(domain) {
|
|
||||||
info := s.matcherInfos[match]
|
|
||||||
client := s.clients[info.clientIdx]
|
|
||||||
domainRule := client.domains[info.domainRuleIdx]
|
|
||||||
domainRules = append(domainRules, fmt.Sprintf("%s(DNS idx:%d)", domainRule, info.clientIdx))
|
|
||||||
if clientUsed[info.clientIdx] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
clientUsed[info.clientIdx] = true
|
|
||||||
clients = append(clients, client)
|
|
||||||
clientNames = append(clientNames, client.Name())
|
|
||||||
hasMatch = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !(s.disableFallback || s.disableFallbackIfMatch && hasMatch) {
|
|
||||||
// Default round-robin query
|
|
||||||
for idx, client := range s.clients {
|
|
||||||
if clientUsed[idx] || client.skipFallback {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
clientUsed[idx] = true
|
|
||||||
clients = append(clients, client)
|
|
||||||
clientNames = append(clientNames, client.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(domainRules) > 0 {
|
|
||||||
errors.LogDebug(s.ctx, "domain ", domain, " matches following rules: ", domainRules)
|
|
||||||
}
|
|
||||||
if len(clientNames) > 0 {
|
|
||||||
errors.LogDebug(s.ctx, "domain ", domain, " will use DNS in order: ", clientNames)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(clients) == 0 {
|
|
||||||
clients = append(clients, s.clients[0])
|
|
||||||
clientNames = append(clientNames, s.clients[0].Name())
|
|
||||||
errors.LogDebug(s.ctx, "domain ", domain, " will use the first DNS: ", clientNames)
|
|
||||||
}
|
|
||||||
|
|
||||||
return clients
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
|
||||||
return New(ctx, config.(*Config))
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,22 +1,18 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/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"
|
"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
|
||||||
@@ -57,7 +53,9 @@ func isNewer(baseRec *IPRecord, newRec *IPRecord) bool {
|
|||||||
return baseRec.Expire.Before(newRec.Expire)
|
return baseRec.Expire.Before(newRec.Expire)
|
||||||
}
|
}
|
||||||
|
|
||||||
var errRecordNotFound = errors.New("record not found")
|
var (
|
||||||
|
errRecordNotFound = errors.New("record not found")
|
||||||
|
)
|
||||||
|
|
||||||
type dnsRequest struct {
|
type dnsRequest struct {
|
||||||
reqType dnsmessage.Type
|
reqType dnsmessage.Type
|
||||||
@@ -166,15 +164,15 @@ 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()
|
||||||
@@ -189,7 +187,7 @@ 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
|
||||||
}
|
}
|
||||||
@@ -207,20 +205,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[:]))
|
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 A record for domain: ", ah.Name).Base(err).WriteToLog()
|
||||||
break L
|
break L
|
||||||
}
|
}
|
||||||
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.AAAA[:]))
|
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.AAAA[:]))
|
||||||
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
|
||||||
@@ -229,19 +227,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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -49,28 +49,20 @@ func Test_parseResponse(t *testing.T) {
|
|||||||
want *IPRecord
|
want *IPRecord
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{"empty",
|
||||||
"empty",
|
|
||||||
&IPRecord{0, []net.Address(nil), time.Time{}, dnsmessage.RCodeSuccess},
|
&IPRecord{0, []net.Address(nil), time.Time{}, dnsmessage.RCodeSuccess},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{"error",
|
||||||
"error",
|
|
||||||
nil,
|
nil,
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{"a record",
|
||||||
"a record",
|
&IPRecord{1, []net.Address{net.ParseAddress("8.8.8.8"), net.ParseAddress("8.8.4.4")},
|
||||||
&IPRecord{
|
time.Time{}, dnsmessage.RCodeSuccess},
|
||||||
1,
|
|
||||||
[]net.Address{net.ParseAddress("8.8.8.8"), net.ParseAddress("8.8.4.4")},
|
|
||||||
time.Time{},
|
|
||||||
dnsmessage.RCodeSuccess,
|
|
||||||
},
|
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{"aaaa record",
|
||||||
"aaaa record",
|
|
||||||
&IPRecord{2, []net.Address{net.ParseAddress("2001::123:8888"), net.ParseAddress("2001::123:8844")}, time.Time{}, dnsmessage.RCodeSuccess},
|
&IPRecord{2, []net.Address{net.ParseAddress("2001::123:8888"), net.ParseAddress("2001::123:8844")}, time.Time{}, dnsmessage.RCodeSuccess},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -12,7 +13,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/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"
|
||||||
@@ -32,20 +32,20 @@ import (
|
|||||||
type DoHNameServer struct {
|
type DoHNameServer struct {
|
||||||
dispatcher routing.Dispatcher
|
dispatcher routing.Dispatcher
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
ips map[string]*record
|
ips map[string]record
|
||||||
pub *pubsub.Service
|
pub *pubsub.Service
|
||||||
cleanup *task.Periodic
|
cleanup *task.Periodic
|
||||||
reqID uint32
|
reqID uint32
|
||||||
httpClient *http.Client
|
clientIP net.IP
|
||||||
dohURL string
|
httpClient *http.Client
|
||||||
name string
|
dohURL string
|
||||||
queryStrategy QueryStrategy
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDoHNameServer creates DOH server object for remote resolving.
|
// NewDoHNameServer creates DOH client object for remote resolving
|
||||||
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (*DoHNameServer, error) {
|
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, clientIP net.IP) (*DoHNameServer, error) {
|
||||||
errors.LogInfo(context.Background(), "DNS: created Remote DOH client for ", url.String())
|
newError("DNS: created Remote DOH client for ", url.String()).AtInfo().WriteToLog()
|
||||||
s := baseDOHNameServer(url, "DOH", queryStrategy)
|
s := baseDOHNameServer(url, "DOH", clientIP)
|
||||||
|
|
||||||
s.dispatcher = dispatcher
|
s.dispatcher = dispatcher
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
@@ -54,11 +54,23 @@ func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy
|
|||||||
TLSHandshakeTimeout: 30 * time.Second,
|
TLSHandshakeTimeout: 30 * time.Second,
|
||||||
ForceAttemptHTTP2: true,
|
ForceAttemptHTTP2: true,
|
||||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
dispatcherCtx := context.Background()
|
||||||
|
|
||||||
dest, err := net.ParseDestination(network + ":" + addr)
|
dest, err := net.ParseDestination(network + ":" + addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
link, err := s.dispatcher.Dispatch(toDnsContext(ctx, s.dohURL), dest)
|
|
||||||
|
dispatcherCtx = session.ContextWithContent(dispatcherCtx, session.ContentFromContext(ctx))
|
||||||
|
dispatcherCtx = session.ContextWithInbound(dispatcherCtx, session.InboundFromContext(ctx))
|
||||||
|
dispatcherCtx = log.ContextWithAccessMessage(dispatcherCtx, &log.AccessMessage{
|
||||||
|
From: "DoH",
|
||||||
|
To: s.dohURL,
|
||||||
|
Status: log.AccessAccepted,
|
||||||
|
Reason: "",
|
||||||
|
})
|
||||||
|
|
||||||
|
link, err := s.dispatcher.Dispatch(dispatcherCtx, dest)
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil, ctx.Err()
|
return nil, ctx.Err()
|
||||||
@@ -92,9 +104,9 @@ func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewDoHLocalNameServer creates DOH client object for local resolving
|
// NewDoHLocalNameServer creates DOH client object for local resolving
|
||||||
func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameServer {
|
func NewDoHLocalNameServer(url *url.URL, clientIP net.IP) *DoHNameServer {
|
||||||
url.Scheme = "https"
|
url.Scheme = "https"
|
||||||
s := baseDOHNameServer(url, "DOHL", queryStrategy)
|
s := baseDOHNameServer(url, "DOHL", clientIP)
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
IdleConnTimeout: 90 * time.Second,
|
IdleConnTimeout: 90 * time.Second,
|
||||||
ForceAttemptHTTP2: true,
|
ForceAttemptHTTP2: true,
|
||||||
@@ -105,7 +117,7 @@ func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameSe
|
|||||||
}
|
}
|
||||||
conn, err := internet.DialSystem(ctx, dest, nil)
|
conn, err := internet.DialSystem(ctx, dest, nil)
|
||||||
log.Record(&log.AccessMessage{
|
log.Record(&log.AccessMessage{
|
||||||
From: "DNS",
|
From: "DoH",
|
||||||
To: s.dohURL,
|
To: s.dohURL,
|
||||||
Status: log.AccessAccepted,
|
Status: log.AccessAccepted,
|
||||||
Detour: "local",
|
Detour: "local",
|
||||||
@@ -120,26 +132,27 @@ func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameSe
|
|||||||
Timeout: time.Second * 180,
|
Timeout: time.Second * 180,
|
||||||
Transport: tr,
|
Transport: tr,
|
||||||
}
|
}
|
||||||
errors.LogInfo(context.Background(), "DNS: created Local DOH client for ", url.String())
|
newError("DNS: created Local DOH client for ", url.String()).AtInfo().WriteToLog()
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func baseDOHNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) *DoHNameServer {
|
func baseDOHNameServer(url *url.URL, prefix string, clientIP net.IP) *DoHNameServer {
|
||||||
s := &DoHNameServer{
|
s := &DoHNameServer{
|
||||||
ips: make(map[string]*record),
|
ips: make(map[string]record),
|
||||||
pub: pubsub.NewService(),
|
clientIP: clientIP,
|
||||||
name: prefix + "//" + url.Host,
|
pub: pubsub.NewService(),
|
||||||
dohURL: url.String(),
|
name: prefix + "//" + url.Host,
|
||||||
queryStrategy: queryStrategy,
|
dohURL: url.String(),
|
||||||
}
|
}
|
||||||
s.cleanup = &task.Periodic{
|
s.cleanup = &task.Periodic{
|
||||||
Interval: time.Minute,
|
Interval: time.Minute,
|
||||||
Execute: s.Cleanup,
|
Execute: s.Cleanup,
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name implements Server.
|
// Name returns client name
|
||||||
func (s *DoHNameServer) Name() string {
|
func (s *DoHNameServer) Name() string {
|
||||||
return s.name
|
return s.name
|
||||||
}
|
}
|
||||||
@@ -151,7 +164,7 @@ func (s *DoHNameServer) Cleanup() error {
|
|||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
||||||
if len(s.ips) == 0 {
|
if len(s.ips) == 0 {
|
||||||
return errors.New("nothing to do. stopping...")
|
return newError("nothing to do. stopping...")
|
||||||
}
|
}
|
||||||
|
|
||||||
for domain, record := range s.ips {
|
for domain, record := range s.ips {
|
||||||
@@ -163,7 +176,7 @@ func (s *DoHNameServer) Cleanup() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if record.A == nil && record.AAAA == nil {
|
if record.A == nil && record.AAAA == nil {
|
||||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog()
|
||||||
delete(s.ips, domain)
|
delete(s.ips, domain)
|
||||||
} else {
|
} else {
|
||||||
s.ips[domain] = record
|
s.ips[domain] = record
|
||||||
@@ -171,7 +184,7 @@ func (s *DoHNameServer) Cleanup() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(s.ips) == 0 {
|
if len(s.ips) == 0 {
|
||||||
s.ips = make(map[string]*record)
|
s.ips = make(map[string]record)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -181,10 +194,7 @@ func (s *DoHNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
|||||||
elapsed := time.Since(req.start)
|
elapsed := time.Since(req.start)
|
||||||
|
|
||||||
s.Lock()
|
s.Lock()
|
||||||
rec, found := s.ips[req.domain]
|
rec := s.ips[req.domain]
|
||||||
if !found {
|
|
||||||
rec = &record{}
|
|
||||||
}
|
|
||||||
updated := false
|
updated := false
|
||||||
|
|
||||||
switch req.reqType {
|
switch req.reqType {
|
||||||
@@ -194,7 +204,7 @@ func (s *DoHNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
|||||||
updated = true
|
updated = true
|
||||||
}
|
}
|
||||||
case dnsmessage.TypeAAAA:
|
case dnsmessage.TypeAAAA:
|
||||||
addr := make([]net.Address, 0, len(ipRec.IP))
|
addr := make([]net.Address, 0)
|
||||||
for _, ip := range ipRec.IP {
|
for _, ip := range ipRec.IP {
|
||||||
if len(ip.IP()) == net.IPv6len {
|
if len(ip.IP()) == net.IPv6len {
|
||||||
addr = append(addr, ip)
|
addr = append(addr, ip)
|
||||||
@@ -206,7 +216,7 @@ func (s *DoHNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
|||||||
updated = true
|
updated = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog()
|
||||||
|
|
||||||
if updated {
|
if updated {
|
||||||
s.ips[req.domain] = rec
|
s.ips[req.domain] = rec
|
||||||
@@ -225,15 +235,15 @@ func (s *DoHNameServer) newReqID() uint16 {
|
|||||||
return uint16(atomic.AddUint32(&s.reqID, 1))
|
return uint16(atomic.AddUint32(&s.reqID, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, 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))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP))
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
@@ -246,7 +256,7 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP n
|
|||||||
go func(r *dnsRequest) {
|
go func(r *dnsRequest) {
|
||||||
// generate new context for each req, using same context
|
// generate new context for each req, using same context
|
||||||
// may cause reqs all aborted if any one encounter an error
|
// may cause reqs all aborted if any one encounter an error
|
||||||
dnsCtx := ctx
|
dnsCtx := context.Background()
|
||||||
|
|
||||||
// reserve internal dns server requested Inbound
|
// reserve internal dns server requested Inbound
|
||||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||||
@@ -254,12 +264,12 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP n
|
|||||||
}
|
}
|
||||||
|
|
||||||
dnsCtx = session.ContextWithContent(dnsCtx, &session.Content{
|
dnsCtx = session.ContextWithContent(dnsCtx, &session.Content{
|
||||||
Protocol: "https",
|
Protocol: "https",
|
||||||
SkipDNSResolve: true,
|
//SkipRoutePick: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 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)
|
||||||
@@ -267,17 +277,17 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP n
|
|||||||
|
|
||||||
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()
|
||||||
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()
|
||||||
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()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.updateIP(r, rec)
|
s.updateIP(r, rec)
|
||||||
@@ -304,11 +314,11 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
|
|||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
io.Copy(io.Discard, resp.Body) // flush resp.Body so that the conn is reusable
|
io.Copy(ioutil.Discard, resp.Body) // flush resp.Body so that the conn is reusable
|
||||||
return nil, fmt.Errorf("DOH server returned code %d", resp.StatusCode)
|
return nil, fmt.Errorf("DOH server returned code %d", resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
return io.ReadAll(resp.Body)
|
return ioutil.ReadAll(resp.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DoHNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
func (s *DoHNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||||
@@ -320,30 +330,30 @@ func (s *DoHNameServer) findIPsForDomain(domain string, option dns_feature.IPOpt
|
|||||||
return nil, errRecordNotFound
|
return nil, errRecordNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
var err4 error
|
|
||||||
var err6 error
|
|
||||||
var ips []net.Address
|
var ips []net.Address
|
||||||
var ip6 []net.Address
|
var lastErr error
|
||||||
|
if option.IPv6Enable && record.AAAA != nil && record.AAAA.RCode == dnsmessage.RCodeSuccess {
|
||||||
if option.IPv4Enable {
|
aaaa, err := record.AAAA.getIPs()
|
||||||
ips, err4 = record.A.getIPs()
|
if err != nil {
|
||||||
|
lastErr = err
|
||||||
|
}
|
||||||
|
ips = append(ips, aaaa...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if option.IPv6Enable {
|
if option.IPv4Enable && record.A != nil && record.A.RCode == dnsmessage.RCodeSuccess {
|
||||||
ip6, err6 = record.AAAA.getIPs()
|
a, err := record.A.getIPs()
|
||||||
ips = append(ips, ip6...)
|
if err != nil {
|
||||||
|
lastErr = err
|
||||||
|
}
|
||||||
|
ips = append(ips, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ips) > 0 {
|
if len(ips) > 0 {
|
||||||
return toNetIP(ips)
|
return toNetIP(ips), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err4 != nil {
|
if lastErr != nil {
|
||||||
return nil, err4
|
return nil, lastErr
|
||||||
}
|
|
||||||
|
|
||||||
if err6 != nil {
|
|
||||||
return nil, err6
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {
|
if (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {
|
||||||
@@ -353,23 +363,15 @@ func (s *DoHNameServer) findIPsForDomain(domain string, option dns_feature.IPOpt
|
|||||||
return nil, errRecordNotFound
|
return nil, errRecordNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryIP implements Server.
|
// QueryIP is called from dns.Server->queryIPTimeout
|
||||||
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) { // nolint: dupl
|
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, error) { // nolint: dupl
|
||||||
fqdn := Fqdn(domain)
|
fqdn := Fqdn(domain)
|
||||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
|
||||||
if !option.IPv4Enable && !option.IPv6Enable {
|
|
||||||
return nil, dns_feature.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
if disableCache {
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
if err != errRecordNotFound {
|
||||||
} else {
|
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||||
ips, err := s.findIPsForDomain(fqdn, option)
|
log.Record(&log.DNSLog{s.name, domain, ips, log.DNSCacheHit, 0, err})
|
||||||
if err == nil || err == dns_feature.ErrEmptyResponse {
|
return ips, err
|
||||||
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
|
|
||||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
|
||||||
return ips, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ipv4 and ipv6 belong to different subscription groups
|
// ipv4 and ipv6 belong to different subscription groups
|
||||||
@@ -398,13 +400,13 @@ func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net
|
|||||||
}
|
}
|
||||||
close(done)
|
close(done)
|
||||||
}()
|
}()
|
||||||
s.sendQuery(ctx, fqdn, clientIP, option)
|
s.sendQuery(ctx, fqdn, option)
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
ips, err := s.findIPsForDomain(fqdn, option)
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
if err != errRecordNotFound {
|
if err != errRecordNotFound {
|
||||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
log.Record(&log.DNSLog{s.name, domain, ips, log.DNSQueried, time.Since(start), err})
|
||||||
return ips, err
|
return ips, err
|
||||||
}
|
}
|
||||||
|
|
||||||
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,41 +16,21 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fkdns *Holder) IsIPInIPPool(ip net.Address) bool {
|
|
||||||
if ip.Family().IsDomain() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return fkdns.ipRange.Contains(ip.IP())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fkdns *Holder) GetFakeIPForDomain3(domain string, ipv4, ipv6 bool) []net.Address {
|
|
||||||
isIPv6 := fkdns.ipRange.IP.To4() == nil
|
|
||||||
if (isIPv6 && ipv6) || (!isIPv6 && ipv4) {
|
|
||||||
return fkdns.GetFakeIPForDomain(domain)
|
|
||||||
}
|
|
||||||
return []net.Address{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Holder) Type() interface{} {
|
func (*Holder) Type() interface{} {
|
||||||
return (*dns.FakeDNSEngine)(nil)
|
return (*dns.FakeDNSEngine)(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fkdns *Holder) Start() error {
|
func (fkdns *Holder) Start() error {
|
||||||
if fkdns.config != nil && fkdns.config.IpPool != "" && fkdns.config.LruSize != 0 {
|
return fkdns.initializeFromConfig()
|
||||||
return fkdns.initializeFromConfig()
|
|
||||||
}
|
|
||||||
return errors.New("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,9 +39,9 @@ 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.FakeIPPool, 65535)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -71,7 +49,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,34 +61,31 @@ 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)}
|
||||||
}
|
}
|
||||||
currentTimeMillis := uint64(time.Now().UnixNano() / 1e6)
|
var currentTimeMillis = uint64(time.Now().UnixNano() / 1e6)
|
||||||
ones, bits := fkdns.ipRange.Mask.Size()
|
ones, bits := fkdns.ipRange.Mask.Size()
|
||||||
rooms := bits - ones
|
rooms := bits - ones
|
||||||
if rooms < 64 {
|
if rooms < 64 {
|
||||||
currentTimeMillis %= (uint64(1) << rooms)
|
currentTimeMillis %= (uint64(1) << rooms)
|
||||||
}
|
}
|
||||||
bigIntIP := big.NewInt(0).SetBytes(fkdns.ipRange.IP)
|
var bigIntIP = big.NewInt(0).SetBytes(fkdns.ipRange.IP)
|
||||||
bigIntIP = bigIntIP.Add(bigIntIP, new(big.Int).SetUint64(currentTimeMillis))
|
bigIntIP = bigIntIP.Add(bigIntIP, new(big.Int).SetUint64(currentTimeMillis))
|
||||||
var ip net.Address
|
var ip net.Address
|
||||||
for {
|
for {
|
||||||
@@ -130,7 +105,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,96 +113,13 @@ 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 ""
|
||||||
}
|
}
|
||||||
|
|
||||||
type HolderMulti struct {
|
// GetFakeIPRange return fake IP range from configuration
|
||||||
holders []*Holder
|
func (fkdns *Holder) GetFakeIPRange() *gonet.IPNet {
|
||||||
|
return fkdns.ipRange
|
||||||
config *FakeDnsPoolMulti
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HolderMulti) IsIPInIPPool(ip net.Address) bool {
|
|
||||||
if ip.Family().IsDomain() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, v := range h.holders {
|
|
||||||
if v.IsIPInIPPool(ip) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HolderMulti) GetFakeIPForDomain3(domain string, ipv4, ipv6 bool) []net.Address {
|
|
||||||
var ret []net.Address
|
|
||||||
for _, v := range h.holders {
|
|
||||||
ret = append(ret, v.GetFakeIPForDomain3(domain, ipv4, ipv6)...)
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HolderMulti) GetFakeIPForDomain(domain string) []net.Address {
|
|
||||||
var ret []net.Address
|
|
||||||
for _, v := range h.holders {
|
|
||||||
ret = append(ret, v.GetFakeIPForDomain(domain)...)
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HolderMulti) GetDomainFromFakeDNS(ip net.Address) string {
|
|
||||||
for _, v := range h.holders {
|
|
||||||
if domain := v.GetDomainFromFakeDNS(ip); domain != "" {
|
|
||||||
return domain
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HolderMulti) Type() interface{} {
|
|
||||||
return (*dns.FakeDNSEngine)(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HolderMulti) Start() error {
|
|
||||||
for _, v := range h.holders {
|
|
||||||
if v.config != nil && v.config.IpPool != "" && v.config.LruSize != 0 {
|
|
||||||
if err := v.Start(); err != nil {
|
|
||||||
return errors.New("Cannot start all fake dns pools").Base(err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return errors.New("invalid fakeDNS setting")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HolderMulti) Close() error {
|
|
||||||
for _, v := range h.holders {
|
|
||||||
if err := v.Close(); err != nil {
|
|
||||||
return errors.New("Cannot close all fake dns pools").Base(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HolderMulti) createHolderGroups() error {
|
|
||||||
for _, v := range h.config.Pools {
|
|
||||||
holder, err := NewFakeDNSHolderConfigOnly(v)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
h.holders = append(h.holders, holder)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFakeDNSHolderMulti(conf *FakeDnsPoolMulti) (*HolderMulti, error) {
|
|
||||||
holderMulti := &HolderMulti{nil, conf}
|
|
||||||
if err := holderMulti.createHolderGroups(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return holderMulti, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -239,13 +131,4 @@ func init() {
|
|||||||
}
|
}
|
||||||
return f, nil
|
return f, nil
|
||||||
}))
|
}))
|
||||||
|
|
||||||
common.Must(common.RegisterConfig((*FakeDnsPoolMulti)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
|
||||||
var f *HolderMulti
|
|
||||||
var err error
|
|
||||||
if f, err = NewFakeDNSHolderMulti(config.(*FakeDnsPoolMulti)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return f, nil
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
package fakedns
|
package fakedns
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.25.0
|
||||||
// protoc v5.28.2
|
// protoc v3.13.0
|
||||||
// source: app/dns/fakedns/fakedns.proto
|
// source: app/dns/fakedns/fakedns.proto
|
||||||
|
|
||||||
package fakedns
|
package fakedns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
@@ -20,6 +21,10 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||||
|
// of the legacy proto package is being used.
|
||||||
|
const _ = proto.ProtoPackageIsVersion4
|
||||||
|
|
||||||
type FakeDnsPool struct {
|
type FakeDnsPool struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -31,9 +36,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 +51,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)
|
||||||
@@ -73,73 +80,24 @@ func (x *FakeDnsPool) GetLruSize() int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
type FakeDnsPoolMulti struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Pools []*FakeDnsPool `protobuf:"bytes,1,rep,name=pools,proto3" json:"pools,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *FakeDnsPoolMulti) Reset() {
|
|
||||||
*x = FakeDnsPoolMulti{}
|
|
||||||
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *FakeDnsPoolMulti) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*FakeDnsPoolMulti) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *FakeDnsPoolMulti) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_dns_fakedns_fakedns_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 FakeDnsPoolMulti.ProtoReflect.Descriptor instead.
|
|
||||||
func (*FakeDnsPoolMulti) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_dns_fakedns_fakedns_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *FakeDnsPoolMulti) GetPools() []*FakeDnsPool {
|
|
||||||
if x != nil {
|
|
||||||
return x.Pools
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_app_dns_fakedns_fakedns_proto protoreflect.FileDescriptor
|
var File_app_dns_fakedns_fakedns_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_app_dns_fakedns_fakedns_proto_rawDesc = []byte{
|
var file_app_dns_fakedns_fakedns_proto_rawDesc = []byte{
|
||||||
0x0a, 0x1d, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
|
0x0a, 0x1d, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
|
||||||
0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
||||||
0x14, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61,
|
0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||||
0x6b, 0x65, 0x64, 0x6e, 0x73, 0x22, 0x40, 0x0a, 0x0b, 0x46, 0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73,
|
0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x22, 0x40, 0x0a, 0x0b, 0x46,
|
||||||
0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x70, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x18,
|
0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x70,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x70, 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x18, 0x0a,
|
0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x70, 0x50,
|
||||||
0x07, 0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07,
|
0x6f, 0x6f, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02,
|
||||||
0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x4b, 0x0a, 0x10, 0x46, 0x61, 0x6b, 0x65, 0x44,
|
0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x5f, 0x0a,
|
||||||
0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x12, 0x37, 0x0a, 0x05, 0x70,
|
0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
||||||
0x6f, 0x6f, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61,
|
0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x50,
|
||||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
|
0x01, 0x5a, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72,
|
||||||
0x73, 0x2e, 0x46, 0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x05, 0x70,
|
0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
|
||||||
0x6f, 0x6f, 0x6c, 0x73, 0x42, 0x5e, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
0x73, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41,
|
||||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73,
|
0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x62, 0x06,
|
||||||
0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
|
|
||||||
0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x14,
|
|
||||||
0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6b,
|
|
||||||
0x65, 0x64, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -154,18 +112,16 @@ func file_app_dns_fakedns_fakedns_proto_rawDescGZIP() []byte {
|
|||||||
return file_app_dns_fakedns_fakedns_proto_rawDescData
|
return file_app_dns_fakedns_fakedns_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_app_dns_fakedns_fakedns_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
var file_app_dns_fakedns_fakedns_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
var file_app_dns_fakedns_fakedns_proto_depIdxs = []int32{
|
var file_app_dns_fakedns_fakedns_proto_depIdxs = []int32{
|
||||||
0, // 0: xray.app.dns.fakedns.FakeDnsPoolMulti.pools:type_name -> xray.app.dns.fakedns.FakeDnsPool
|
0, // [0:0] is the sub-list for method output_type
|
||||||
1, // [1:1] is the sub-list for method output_type
|
0, // [0:0] is the sub-list for method input_type
|
||||||
1, // [1:1] is the sub-list for method input_type
|
0, // [0:0] is the sub-list for extension type_name
|
||||||
1, // [1:1] is the sub-list for extension type_name
|
0, // [0:0] is the sub-list for extension extendee
|
||||||
1, // [1:1] is the sub-list for extension extendee
|
0, // [0:0] is the sub-list for field type_name
|
||||||
0, // [0:1] is the sub-list for field type_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_dns_fakedns_fakedns_proto_init() }
|
func init() { file_app_dns_fakedns_fakedns_proto_init() }
|
||||||
@@ -173,13 +129,27 @@ 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
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_fakedns_fakedns_proto_rawDesc,
|
RawDescriptor: file_app_dns_fakedns_fakedns_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 2,
|
NumMessages: 1,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -9,8 +9,4 @@ option java_multiple_files = true;
|
|||||||
message FakeDnsPool{
|
message FakeDnsPool{
|
||||||
string ip_pool = 1; //CIDR of IP pool used as fake DNS IP
|
string ip_pool = 1; //CIDR of IP pool used as fake DNS IP
|
||||||
int64 lruSize = 2; //Size of Pool for remembering relationship between domain name and IP address
|
int64 lruSize = 2; //Size of Pool for remembering relationship between domain name and IP address
|
||||||
}
|
|
||||||
|
|
||||||
message FakeDnsPoolMulti{
|
|
||||||
repeated FakeDnsPool pools = 1;
|
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
package fakedns
|
package fakedns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gonet "net"
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"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.18."
|
||||||
|
)
|
||||||
|
|
||||||
func TestNewFakeDnsHolder(_ *testing.T) {
|
func TestNewFakeDnsHolder(_ *testing.T) {
|
||||||
_, err := NewFakeDNSHolder()
|
_, err := NewFakeDNSHolder()
|
||||||
@@ -67,34 +67,9 @@ 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.FakeIPPool,
|
||||||
LruSize: 256,
|
LruSize: 256,
|
||||||
})
|
})
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
@@ -128,79 +103,3 @@ func TestFakeDnsHolderCreateMappingAndRollOver(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFakeDNSMulti(t *testing.T) {
|
|
||||||
fakeMulti, err := NewFakeDNSHolderMulti(&FakeDnsPoolMulti{
|
|
||||||
Pools: []*FakeDnsPool{{
|
|
||||||
IpPool: "240.0.0.0/12",
|
|
||||||
LruSize: 256,
|
|
||||||
}, {
|
|
||||||
IpPool: "fddd:c5b4:ff5f:f4f0::/64",
|
|
||||||
LruSize: 256,
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
err = fakeMulti.Start()
|
|
||||||
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
assert.Nil(t, err, "Should not throw error")
|
|
||||||
_ = fakeMulti
|
|
||||||
|
|
||||||
t.Run("checkInRange", func(t *testing.T) {
|
|
||||||
t.Run("ipv4", func(t *testing.T) {
|
|
||||||
inPool := fakeMulti.IsIPInIPPool(net.IPAddress([]byte{240, 0, 0, 5}))
|
|
||||||
assert.True(t, inPool)
|
|
||||||
})
|
|
||||||
t.Run("ipv6", func(t *testing.T) {
|
|
||||||
ip, err := gonet.ResolveIPAddr("ip", "fddd:c5b4:ff5f:f4f0::5")
|
|
||||||
assert.Nil(t, err)
|
|
||||||
inPool := fakeMulti.IsIPInIPPool(net.IPAddress(ip.IP))
|
|
||||||
assert.True(t, inPool)
|
|
||||||
})
|
|
||||||
t.Run("ipv4_inverse", func(t *testing.T) {
|
|
||||||
inPool := fakeMulti.IsIPInIPPool(net.IPAddress([]byte{241, 0, 0, 5}))
|
|
||||||
assert.False(t, inPool)
|
|
||||||
})
|
|
||||||
t.Run("ipv6_inverse", func(t *testing.T) {
|
|
||||||
ip, err := gonet.ResolveIPAddr("ip", "fcdd:c5b4:ff5f:f4f0::5")
|
|
||||||
assert.Nil(t, err)
|
|
||||||
inPool := fakeMulti.IsIPInIPPool(net.IPAddress(ip.IP))
|
|
||||||
assert.False(t, inPool)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("allocateTwoAddressForTwoPool", func(t *testing.T) {
|
|
||||||
address := fakeMulti.GetFakeIPForDomain("fakednstest.example.com")
|
|
||||||
assert.Len(t, address, 2, "should be 2 address one for each pool")
|
|
||||||
t.Run("eachOfThemShouldResolve:0", func(t *testing.T) {
|
|
||||||
domain := fakeMulti.GetDomainFromFakeDNS(address[0])
|
|
||||||
assert.Equal(t, "fakednstest.example.com", domain)
|
|
||||||
})
|
|
||||||
t.Run("eachOfThemShouldResolve:1", func(t *testing.T) {
|
|
||||||
domain := fakeMulti.GetDomainFromFakeDNS(address[1])
|
|
||||||
assert.Equal(t, "fakednstest.example.com", domain)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("understandIPTypeSelector", func(t *testing.T) {
|
|
||||||
t.Run("ipv4", func(t *testing.T) {
|
|
||||||
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv4.example.com", true, false)
|
|
||||||
assert.Len(t, address, 1, "should be 1 address")
|
|
||||||
assert.True(t, address[0].Family().IsIPv4())
|
|
||||||
})
|
|
||||||
t.Run("ipv6", func(t *testing.T) {
|
|
||||||
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv6.example.com", false, true)
|
|
||||||
assert.Len(t, address, 1, "should be 1 address")
|
|
||||||
assert.True(t, address[0].Family().IsIPv6())
|
|
||||||
})
|
|
||||||
t.Run("ipv46", func(t *testing.T) {
|
|
||||||
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv46.example.com", true, true)
|
|
||||||
assert.Len(t, address, 2, "should be 2 address")
|
|
||||||
assert.True(t, address[0].Family().IsIPv4())
|
|
||||||
assert.True(t, address[1].Family().IsIPv6())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
102
app/dns/hosts.go
102
app/dns/hosts.go
@@ -1,11 +1,10 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"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/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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,34 +14,77 @@ type StaticHosts struct {
|
|||||||
matchers *strmatcher.MatcherGroup
|
matchers *strmatcher.MatcherGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var typeMap = map[DomainMatchingType]strmatcher.Type{
|
||||||
|
DomainMatchingType_Full: strmatcher.Full,
|
||||||
|
DomainMatchingType_Subdomain: strmatcher.Domain,
|
||||||
|
DomainMatchingType_Keyword: strmatcher.Substr,
|
||||||
|
DomainMatchingType_Regex: strmatcher.Regex,
|
||||||
|
}
|
||||||
|
|
||||||
|
func toStrMatcher(t DomainMatchingType, domain string) (strmatcher.Matcher, error) {
|
||||||
|
strMType, f := typeMap[t]
|
||||||
|
if !f {
|
||||||
|
return nil, newError("unknown mapping type", t).AtWarning()
|
||||||
|
}
|
||||||
|
matcher, err := strMType.New(domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, newError("failed to create str matcher").Base(err)
|
||||||
|
}
|
||||||
|
return matcher, nil
|
||||||
|
}
|
||||||
|
|
||||||
// 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:
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case len(mapping.ProxiedDomain) > 0:
|
||||||
|
ips = append(ips, net.DomainAddress(mapping.ProxiedDomain))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("neither IP address nor proxied domain specified for domain: ", mapping.Domain).AtWarning()
|
return nil, newError("neither IP address nor proxied domain specified for domain: ", mapping.Domain).AtWarning()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special handling for localhost IPv6. This is a dirty workaround as JSON config supports only single IP mapping.
|
||||||
|
if len(ips) == 1 && ips[0] == net.LocalHostIP {
|
||||||
|
ips = append(ips, net.LocalHostIPv6)
|
||||||
}
|
}
|
||||||
|
|
||||||
sh.ips[id] = ips
|
sh.ips[id] = ips
|
||||||
@@ -58,36 +100,24 @@ func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
|
|||||||
filtered = append(filtered, ip)
|
filtered = append(filtered, ip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(filtered) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return filtered
|
return filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *StaticHosts) lookupInternal(domain string) []net.Address {
|
// LookupIP returns IP address for the given domain, if exists in this StaticHosts.
|
||||||
var ips []net.Address
|
func (h *StaticHosts) LookupIP(domain string, option dns.IPOption) []net.Address {
|
||||||
for _, id := range h.matchers.Match(domain) {
|
indices := h.matchers.Match(domain)
|
||||||
|
if len(indices) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ips := []net.Address{}
|
||||||
|
for _, id := range indices {
|
||||||
ips = append(ips, h.ips[id]...)
|
ips = append(ips, h.ips[id]...)
|
||||||
}
|
}
|
||||||
return ips
|
if len(ips) == 1 && ips[0].Family().IsDomain() {
|
||||||
}
|
return ips
|
||||||
|
|
||||||
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) []net.Address {
|
|
||||||
switch addrs := h.lookupInternal(domain); {
|
|
||||||
case len(addrs) == 0: // Not recorded in static hosts, return nil
|
|
||||||
return nil
|
|
||||||
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")
|
|
||||||
if maxDepth > 0 {
|
|
||||||
unwrapped := h.lookup(addrs[0].Domain(), option, maxDepth-1)
|
|
||||||
if unwrapped != nil {
|
|
||||||
return unwrapped
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return addrs
|
|
||||||
default: // IP record found, return a non-nil IP array
|
|
||||||
return filterIP(addrs, option)
|
|
||||||
}
|
}
|
||||||
}
|
return filterIP(ips, option)
|
||||||
|
|
||||||
// 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 {
|
|
||||||
return h.lookup(domain, option, 5)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"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"
|
||||||
@@ -19,20 +20,6 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
{1, 1, 1, 1},
|
{1, 1, 1, 1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Type: DomainMatchingType_Full,
|
|
||||||
Domain: "proxy.xray.com",
|
|
||||||
Ip: [][]byte{
|
|
||||||
{1, 2, 3, 4},
|
|
||||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
},
|
|
||||||
ProxiedDomain: "another-proxy.xray.com",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Type: DomainMatchingType_Full,
|
|
||||||
Domain: "proxy2.xray.com",
|
|
||||||
ProxiedDomain: "proxy.xray.com",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Type: DomainMatchingType_Subdomain,
|
Type: DomainMatchingType_Subdomain,
|
||||||
Domain: "example.cn",
|
Domain: "example.cn",
|
||||||
@@ -45,16 +32,15 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
Domain: "baidu.com",
|
Domain: "baidu.com",
|
||||||
Ip: [][]byte{
|
Ip: [][]byte{
|
||||||
{127, 0, 0, 1},
|
{127, 0, 0, 1},
|
||||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
hosts, err := NewStaticHosts(pb)
|
hosts, err := NewStaticHosts(pb, nil)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
{
|
{
|
||||||
ips := hosts.Lookup("example.com", dns.IPOption{
|
ips := hosts.LookupIP("example.com", dns.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
})
|
||||||
@@ -67,33 +53,7 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
domain := hosts.Lookup("proxy.xray.com", dns.IPOption{
|
ips := hosts.LookupIP("www.example.cn", dns.IPOption{
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: false,
|
|
||||||
})
|
|
||||||
if len(domain) != 1 {
|
|
||||||
t.Error("expect 1 domain, but got ", len(domain))
|
|
||||||
}
|
|
||||||
if diff := cmp.Diff(domain[0].Domain(), "another-proxy.xray.com"); diff != "" {
|
|
||||||
t.Error(diff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
domain := hosts.Lookup("proxy2.xray.com", dns.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: false,
|
|
||||||
})
|
|
||||||
if len(domain) != 1 {
|
|
||||||
t.Error("expect 1 domain, but got ", len(domain))
|
|
||||||
}
|
|
||||||
if diff := cmp.Diff(domain[0].Domain(), "another-proxy.xray.com"); diff != "" {
|
|
||||||
t.Error(diff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
ips := hosts.Lookup("www.example.cn", dns.IPOption{
|
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
})
|
||||||
@@ -106,7 +66,7 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ips := hosts.Lookup("baidu.com", dns.IPOption{
|
ips := hosts.LookupIP("baidu.com", dns.IPOption{
|
||||||
IPv4Enable: false,
|
IPv4Enable: false,
|
||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,222 +2,40 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/router"
|
|
||||||
"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/core"
|
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/dns/localdns"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server is the interface for Name Server.
|
// Client is the interface for DNS client.
|
||||||
type Server interface {
|
type Client 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, clientIP net.IP, option dns.IPOption, disableCache bool) ([]net.IP, error)
|
QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client is the interface for DNS client.
|
type LocalNameServer struct {
|
||||||
type Client struct {
|
client *localdns.Client
|
||||||
server Server
|
|
||||||
clientIP net.IP
|
|
||||||
skipFallback bool
|
|
||||||
domains []string
|
|
||||||
expectIPs []*router.GeoIPMatcher
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var errExpectedIPNonMatch = errors.New("expectIPs not match")
|
func (s *LocalNameServer) QueryIP(_ context.Context, domain string, option dns.IPOption) ([]net.IP, error) {
|
||||||
|
if option.IPv4Enable || option.IPv6Enable {
|
||||||
|
return s.client.LookupIP(domain, option)
|
||||||
|
}
|
||||||
|
|
||||||
// NewServer creates a name server object according to the network destination url.
|
return nil, newError("neither IPv4 nor IPv6 is enabled")
|
||||||
func NewServer(dest net.Destination, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (Server, error) {
|
|
||||||
if address := dest.Address; address.Family().IsDomain() {
|
|
||||||
u, err := url.Parse(address.Domain())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case strings.EqualFold(u.String(), "localhost"):
|
|
||||||
return NewLocalNameServer(), nil
|
|
||||||
case strings.EqualFold(u.Scheme, "https"): // DOH Remote mode
|
|
||||||
return NewDoHNameServer(u, dispatcher, queryStrategy)
|
|
||||||
case strings.EqualFold(u.Scheme, "https+local"): // DOH Local mode
|
|
||||||
return NewDoHLocalNameServer(u, queryStrategy), nil
|
|
||||||
case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode
|
|
||||||
return NewQUICNameServer(u, queryStrategy)
|
|
||||||
case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode
|
|
||||||
return NewTCPNameServer(u, dispatcher, queryStrategy)
|
|
||||||
case strings.EqualFold(u.Scheme, "tcp+local"): // DNS-over-TCP Local mode
|
|
||||||
return NewTCPLocalNameServer(u, queryStrategy)
|
|
||||||
case strings.EqualFold(u.String(), "fakedns"):
|
|
||||||
return NewFakeDNSServer(), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if dest.Network == net.Network_Unknown {
|
|
||||||
dest.Network = net.Network_UDP
|
|
||||||
}
|
|
||||||
if dest.Network == net.Network_UDP { // UDP classic DNS mode
|
|
||||||
return NewClassicNameServer(dest, dispatcher, queryStrategy), nil
|
|
||||||
}
|
|
||||||
return nil, errors.New("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.
|
func (s *LocalNameServer) Name() string {
|
||||||
func NewClient(
|
return "localhost"
|
||||||
ctx context.Context,
|
|
||||||
ns *NameServer,
|
|
||||||
clientIP net.IP,
|
|
||||||
container router.GeoIPMatcherContainer,
|
|
||||||
matcherInfos *[]*DomainMatcherInfo,
|
|
||||||
updateDomainRule func(strmatcher.Matcher, int, []*DomainMatcherInfo) error,
|
|
||||||
) (*Client, error) {
|
|
||||||
client := &Client{}
|
|
||||||
|
|
||||||
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
|
|
||||||
// Create a new server for each client for now
|
|
||||||
server, err := NewServer(ns.Address.AsDestination(), dispatcher, ns.GetQueryStrategy())
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("failed to create nameserver").Base(err).AtWarning()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prioritize local domains with specific TLDs or those without any dot for the local DNS
|
|
||||||
if _, isLocalDNS := server.(*LocalNameServer); isLocalDNS {
|
|
||||||
ns.PrioritizedDomain = append(ns.PrioritizedDomain, localTLDsAndDotlessDomains...)
|
|
||||||
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.
|
|
||||||
// Because the `localhost` DNS client will append 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).
|
|
||||||
// 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:
|
|
||||||
// https://github.com/v2fly/v2ray-core/issues/529
|
|
||||||
// https://github.com/v2fly/v2ray-core/issues/719
|
|
||||||
for i := 0; i < len(localTLDsAndDotlessDomains); i++ {
|
|
||||||
*matcherInfos = append(*matcherInfos, &DomainMatcherInfo{
|
|
||||||
clientIdx: uint16(0),
|
|
||||||
domainRuleIdx: uint16(0),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Establish domain rules
|
|
||||||
var rules []string
|
|
||||||
ruleCurr := 0
|
|
||||||
ruleIter := 0
|
|
||||||
for _, domain := range ns.PrioritizedDomain {
|
|
||||||
domainRule, err := toStrMatcher(domain.Type, domain.Domain)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("failed to create prioritized domain").Base(err).AtWarning()
|
|
||||||
}
|
|
||||||
originalRuleIdx := ruleCurr
|
|
||||||
if ruleCurr < len(ns.OriginalRules) {
|
|
||||||
rule := ns.OriginalRules[ruleCurr]
|
|
||||||
if ruleCurr >= len(rules) {
|
|
||||||
rules = append(rules, rule.Rule)
|
|
||||||
}
|
|
||||||
ruleIter++
|
|
||||||
if ruleIter >= int(rule.Size) {
|
|
||||||
ruleIter = 0
|
|
||||||
ruleCurr++
|
|
||||||
}
|
|
||||||
} else { // No original rule, generate one according to current domain matcher (majorly for compatibility with tests)
|
|
||||||
rules = append(rules, domainRule.String())
|
|
||||||
ruleCurr++
|
|
||||||
}
|
|
||||||
err = updateDomainRule(domainRule, originalRuleIdx, *matcherInfos)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("failed to create prioritized domain").Base(err).AtWarning()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Establish expected IPs
|
|
||||||
var matchers []*router.GeoIPMatcher
|
|
||||||
for _, geoip := range ns.Geoip {
|
|
||||||
matcher, err := container.Add(geoip)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("failed to create ip matcher").Base(err).AtWarning()
|
|
||||||
}
|
|
||||||
matchers = append(matchers, matcher)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(clientIP) > 0 {
|
|
||||||
switch ns.Address.Address.GetAddress().(type) {
|
|
||||||
case *net.IPOrDomain_Domain:
|
|
||||||
errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetDomain(), " uses clientIP ", clientIP.String())
|
|
||||||
case *net.IPOrDomain_Ip:
|
|
||||||
errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetIp(), " uses clientIP ", clientIP.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
client.server = server
|
|
||||||
client.clientIP = clientIP
|
|
||||||
client.skipFallback = ns.SkipFallback
|
|
||||||
client.domains = rules
|
|
||||||
client.expectIPs = matchers
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return client, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name returns the server name the client manages.
|
func NewLocalNameServer() *LocalNameServer {
|
||||||
func (c *Client) Name() string {
|
newError("DNS: created localhost client").AtInfo().WriteToLog()
|
||||||
return c.server.Name()
|
return &LocalNameServer{
|
||||||
}
|
client: localdns.New(),
|
||||||
|
|
||||||
// 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, disableCache bool) ([]net.IP, error) {
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, 4*time.Second)
|
|
||||||
ips, err := c.server.QueryIP(ctx, domain, c.clientIP, option, disableCache)
|
|
||||||
cancel()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return ips, err
|
|
||||||
}
|
|
||||||
return c.MatchExpectedIPs(domain, ips)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchExpectedIPs matches queried domain IPs with expected IPs and returns matched ones.
|
|
||||||
func (c *Client) MatchExpectedIPs(domain string, ips []net.IP) ([]net.IP, error) {
|
|
||||||
if len(c.expectIPs) == 0 {
|
|
||||||
return ips, nil
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
errors.LogDebug(context.Background(), "domain ", domain, " expectIPs ", newIps, " matched at server ", c.Name())
|
|
||||||
return newIps, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ResolveIpOptionOverride(queryStrategy QueryStrategy, ipOption dns.IPOption) dns.IPOption {
|
|
||||||
switch queryStrategy {
|
|
||||||
case QueryStrategy_USE_IP:
|
|
||||||
return ipOption
|
|
||||||
case QueryStrategy_USE_IP4:
|
|
||||||
return dns.IPOption{
|
|
||||||
IPv4Enable: ipOption.IPv4Enable,
|
|
||||||
IPv6Enable: false,
|
|
||||||
FakeEnable: false,
|
|
||||||
}
|
|
||||||
case QueryStrategy_USE_IP6:
|
|
||||||
return dns.IPOption{
|
|
||||||
IPv4Enable: false,
|
|
||||||
IPv6Enable: ipOption.IPv6Enable,
|
|
||||||
FakeEnable: false,
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return ipOption
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
package dns_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/url"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
. "github.com/xtls/xray-core/app/dns"
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDOHNameServer(t *testing.T) {
|
|
||||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
}, false)
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDOHNameServerWithCache(t *testing.T) {
|
|
||||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
}, false)
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips2, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns_feature.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
}, true)
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if r := cmp.Diff(ips2, ips); r != "" {
|
|
||||||
t.Fatal(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDOHNameServerWithIPv4Override(t *testing.T) {
|
|
||||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP4)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
}, false)
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ip := range ips {
|
|
||||||
if len(ip) != net.IPv4len {
|
|
||||||
t.Error("expect only IPv4 response from DNS query")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDOHNameServerWithIPv6Override(t *testing.T) {
|
|
||||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP6)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
}, false)
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ip := range ips {
|
|
||||||
if len(ip) != net.IPv6len {
|
|
||||||
t.Error("expect only IPv6 response from DNS query")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ 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/core"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
@@ -21,30 +20,22 @@ func (FakeDNSServer) Name() string {
|
|||||||
return "FakeDNS"
|
return "FakeDNS"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, opt dns.IPOption, _ bool) ([]net.IP, error) {
|
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ dns.IPOption) ([]net.IP, error) {
|
||||||
if f.fakeDNSEngine == nil {
|
if f.fakeDNSEngine == nil {
|
||||||
if err := core.RequireFeatures(ctx, func(fd dns.FakeDNSEngine) {
|
if err := core.RequireFeatures(ctx, func(fd dns.FakeDNSEngine) {
|
||||||
f.fakeDNSEngine = fd
|
f.fakeDNSEngine = fd
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, errors.New("Unable to locate a fake DNS Engine").Base(err).AtError()
|
return nil, newError("Unable to locate a fake DNS Engine").Base(err).AtError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var ips []net.Address
|
ips := f.fakeDNSEngine.GetFakeIPForDomain(domain)
|
||||||
if fkr0, ok := f.fakeDNSEngine.(dns.FakeDNSEngineRev0); ok {
|
|
||||||
ips = fkr0.GetFakeIPForDomain3(domain, opt.IPv4Enable, opt.IPv6Enable)
|
netIP := toNetIP(ips)
|
||||||
} else {
|
if netIP == nil {
|
||||||
ips = f.fakeDNSEngine.GetFakeIPForDomain(domain)
|
return nil, newError("Unable to convert IP to net ip").AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
netIP, err := toNetIP(ips)
|
newError(f.Name(), " got answer: ", domain, " -> ", ips).AtInfo().WriteToLog()
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("Unable to convert IP to net ip").Base(err).AtError()
|
|
||||||
}
|
|
||||||
|
|
||||||
errors.LogInfo(ctx, f.Name(), " got answer: ", domain, " -> ", ips)
|
return netIP, nil
|
||||||
|
|
||||||
if len(netIP) > 0 {
|
|
||||||
return netIP, nil
|
|
||||||
}
|
|
||||||
return nil, dns.ErrEmptyResponse
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
package dns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/log"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/features/dns"
|
|
||||||
"github.com/xtls/xray-core/features/dns/localdns"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LocalNameServer is an wrapper over local DNS feature.
|
|
||||||
type LocalNameServer struct {
|
|
||||||
client *localdns.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
const errEmptyResponse = "No address associated with hostname"
|
|
||||||
|
|
||||||
// QueryIP implements Server.
|
|
||||||
func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, _ net.IP, option dns.IPOption, _ bool) (ips []net.IP, err error) {
|
|
||||||
start := time.Now()
|
|
||||||
ips, err = s.client.LookupIP(domain, option)
|
|
||||||
|
|
||||||
if err != nil && strings.HasSuffix(err.Error(), errEmptyResponse) {
|
|
||||||
err = dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ips) > 0 {
|
|
||||||
errors.LogInfo(ctx, "Localhost got answer: ", domain, " -> ", ips)
|
|
||||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name implements Server.
|
|
||||||
func (s *LocalNameServer) Name() string {
|
|
||||||
return "localhost"
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLocalNameServer creates localdns server object for directly lookup in system DNS.
|
|
||||||
func NewLocalNameServer() *LocalNameServer {
|
|
||||||
errors.LogInfo(context.Background(), "DNS: created localhost client")
|
|
||||||
return &LocalNameServer{
|
|
||||||
client: localdns.New(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLocalDNSClient creates localdns client object for directly lookup in system DNS.
|
|
||||||
func NewLocalDNSClient() *Client {
|
|
||||||
return &Client{server: NewLocalNameServer()}
|
|
||||||
}
|
|
||||||
@@ -1,425 +0,0 @@
|
|||||||
package dns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/binary"
|
|
||||||
"net/url"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/quic-go/quic-go"
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/buf"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/log"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/common/protocol/dns"
|
|
||||||
"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"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/tls"
|
|
||||||
"golang.org/x/net/dns/dnsmessage"
|
|
||||||
"golang.org/x/net/http2"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NextProtoDQ - During connection establishment, DNS/QUIC support is indicated
|
|
||||||
// by selecting the ALPN token "dq" in the crypto handshake.
|
|
||||||
const NextProtoDQ = "doq"
|
|
||||||
|
|
||||||
const handshakeTimeout = time.Second * 8
|
|
||||||
|
|
||||||
// QUICNameServer implemented DNS over QUIC
|
|
||||||
type QUICNameServer struct {
|
|
||||||
sync.RWMutex
|
|
||||||
ips map[string]*record
|
|
||||||
pub *pubsub.Service
|
|
||||||
cleanup *task.Periodic
|
|
||||||
reqID uint32
|
|
||||||
name string
|
|
||||||
destination *net.Destination
|
|
||||||
connection quic.Connection
|
|
||||||
queryStrategy QueryStrategy
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewQUICNameServer creates DNS-over-QUIC client object for local resolving
|
|
||||||
func NewQUICNameServer(url *url.URL, queryStrategy QueryStrategy) (*QUICNameServer, error) {
|
|
||||||
errors.LogInfo(context.Background(), "DNS: created Local DNS-over-QUIC client for ", url.String())
|
|
||||||
|
|
||||||
var err error
|
|
||||||
port := net.Port(853)
|
|
||||||
if url.Port() != "" {
|
|
||||||
port, err = net.PortFromString(url.Port())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dest := net.UDPDestination(net.ParseAddress(url.Hostname()), port)
|
|
||||||
|
|
||||||
s := &QUICNameServer{
|
|
||||||
ips: make(map[string]*record),
|
|
||||||
pub: pubsub.NewService(),
|
|
||||||
name: url.String(),
|
|
||||||
destination: &dest,
|
|
||||||
queryStrategy: queryStrategy,
|
|
||||||
}
|
|
||||||
s.cleanup = &task.Periodic{
|
|
||||||
Interval: time.Minute,
|
|
||||||
Execute: s.Cleanup,
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns client name
|
|
||||||
func (s *QUICNameServer) Name() string {
|
|
||||||
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 errors.New("nothing to do. stopping...")
|
|
||||||
}
|
|
||||||
|
|
||||||
for domain, record := range s.ips {
|
|
||||||
if record.A != nil && record.A.Expire.Before(now) {
|
|
||||||
record.A = nil
|
|
||||||
}
|
|
||||||
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
|
||||||
record.AAAA = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if record.A == nil && record.AAAA == nil {
|
|
||||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
|
||||||
delete(s.ips, domain)
|
|
||||||
} else {
|
|
||||||
s.ips[domain] = record
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(s.ips) == 0 {
|
|
||||||
s.ips = make(map[string]*record)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *QUICNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
|
||||||
elapsed := time.Since(req.start)
|
|
||||||
|
|
||||||
s.Lock()
|
|
||||||
rec, found := s.ips[req.domain]
|
|
||||||
if !found {
|
|
||||||
rec = &record{}
|
|
||||||
}
|
|
||||||
updated := false
|
|
||||||
|
|
||||||
switch req.reqType {
|
|
||||||
case dnsmessage.TypeA:
|
|
||||||
if isNewer(rec.A, ipRec) {
|
|
||||||
rec.A = ipRec
|
|
||||||
updated = true
|
|
||||||
}
|
|
||||||
case dnsmessage.TypeAAAA:
|
|
||||||
addr := make([]net.Address, 0)
|
|
||||||
for _, ip := range ipRec.IP {
|
|
||||||
if len(ip.IP()) == net.IPv6len {
|
|
||||||
addr = append(addr, ip)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ipRec.IP = addr
|
|
||||||
if isNewer(rec.AAAA, ipRec) {
|
|
||||||
rec.AAAA = ipRec
|
|
||||||
updated = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
|
||||||
|
|
||||||
if updated {
|
|
||||||
s.ips[req.domain] = rec
|
|
||||||
}
|
|
||||||
switch req.reqType {
|
|
||||||
case dnsmessage.TypeA:
|
|
||||||
s.pub.Publish(req.domain+"4", nil)
|
|
||||||
case dnsmessage.TypeAAAA:
|
|
||||||
s.pub.Publish(req.domain+"6", nil)
|
|
||||||
}
|
|
||||||
s.Unlock()
|
|
||||||
common.Must(s.cleanup.Start())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *QUICNameServer) newReqID() uint16 {
|
|
||||||
return uint16(atomic.AddUint32(&s.reqID, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
|
||||||
errors.LogInfo(ctx, s.name, " querying: ", domain)
|
|
||||||
|
|
||||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
|
||||||
|
|
||||||
var deadline time.Time
|
|
||||||
if d, ok := ctx.Deadline(); ok {
|
|
||||||
deadline = d
|
|
||||||
} else {
|
|
||||||
deadline = time.Now().Add(time.Second * 5)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, req := range reqs {
|
|
||||||
go func(r *dnsRequest) {
|
|
||||||
// generate new context for each req, using same context
|
|
||||||
// may cause reqs all aborted if any one encounter an error
|
|
||||||
dnsCtx := ctx
|
|
||||||
|
|
||||||
// reserve internal dns server requested Inbound
|
|
||||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
|
||||||
dnsCtx = session.ContextWithInbound(dnsCtx, inbound)
|
|
||||||
}
|
|
||||||
|
|
||||||
dnsCtx = session.ContextWithContent(dnsCtx, &session.Content{
|
|
||||||
Protocol: "quic",
|
|
||||||
SkipDNSResolve: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
var cancel context.CancelFunc
|
|
||||||
dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
b, err := dns.PackMessage(r.msg)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
dnsReqBuf := buf.New()
|
|
||||||
binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
|
||||||
dnsReqBuf.Write(b.Bytes())
|
|
||||||
b.Release()
|
|
||||||
|
|
||||||
conn, err := s.openStream(dnsCtx)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to open quic connection")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = conn.Write(dnsReqBuf.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to send query")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = conn.Close()
|
|
||||||
|
|
||||||
respBuf := buf.New()
|
|
||||||
defer respBuf.Release()
|
|
||||||
n, err := respBuf.ReadFullFrom(conn, 2)
|
|
||||||
if err != nil && n == 0 {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
|
||||||
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")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
respBuf.Clear()
|
|
||||||
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
|
||||||
if err != nil && n == 0 {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rec, err := parseResponse(respBuf.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to handle response")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.updateIP(r, rec)
|
|
||||||
}(req)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *QUICNameServer) 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
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {
|
|
||||||
return nil, dns_feature.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errRecordNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryIP is called from dns.Server->queryIPTimeout
|
|
||||||
func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
|
|
||||||
fqdn := Fqdn(domain)
|
|
||||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
|
||||||
if !option.IPv4Enable && !option.IPv6Enable {
|
|
||||||
return nil, dns_feature.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
if disableCache {
|
|
||||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
|
||||||
} else {
|
|
||||||
ips, err := s.findIPsForDomain(fqdn, option)
|
|
||||||
if err == nil || err == dns_feature.ErrEmptyResponse {
|
|
||||||
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
|
|
||||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
|
||||||
return ips, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ipv4 and ipv6 belong to different subscription groups
|
|
||||||
var sub4, sub6 *pubsub.Subscriber
|
|
||||||
if option.IPv4Enable {
|
|
||||||
sub4 = s.pub.Subscribe(fqdn + "4")
|
|
||||||
defer sub4.Close()
|
|
||||||
}
|
|
||||||
if option.IPv6Enable {
|
|
||||||
sub6 = s.pub.Subscribe(fqdn + "6")
|
|
||||||
defer sub6.Close()
|
|
||||||
}
|
|
||||||
done := make(chan interface{})
|
|
||||||
go func() {
|
|
||||||
if sub4 != nil {
|
|
||||||
select {
|
|
||||||
case <-sub4.Wait():
|
|
||||||
case <-ctx.Done():
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sub6 != nil {
|
|
||||||
select {
|
|
||||||
case <-sub6.Wait():
|
|
||||||
case <-ctx.Done():
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
s.sendQuery(ctx, fqdn, clientIP, option)
|
|
||||||
start := time.Now()
|
|
||||||
|
|
||||||
for {
|
|
||||||
ips, err := s.findIPsForDomain(fqdn, option)
|
|
||||||
if err != errRecordNotFound {
|
|
||||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
|
||||||
return ips, err
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, ctx.Err()
|
|
||||||
case <-done:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isActive(s quic.Connection) bool {
|
|
||||||
select {
|
|
||||||
case <-s.Context().Done():
|
|
||||||
return false
|
|
||||||
default:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *QUICNameServer) getConnection() (quic.Connection, error) {
|
|
||||||
var conn quic.Connection
|
|
||||||
s.RLock()
|
|
||||||
conn = s.connection
|
|
||||||
if conn != nil && isActive(conn) {
|
|
||||||
s.RUnlock()
|
|
||||||
return conn, nil
|
|
||||||
}
|
|
||||||
if conn != nil {
|
|
||||||
// we're recreating the connection, let's create a new one
|
|
||||||
_ = conn.CloseWithError(0, "")
|
|
||||||
}
|
|
||||||
s.RUnlock()
|
|
||||||
|
|
||||||
s.Lock()
|
|
||||||
defer s.Unlock()
|
|
||||||
|
|
||||||
var err error
|
|
||||||
conn, err = s.openConnection()
|
|
||||||
if err != nil {
|
|
||||||
// This does not look too nice, but QUIC (or maybe quic-go)
|
|
||||||
// doesn't seem stable enough.
|
|
||||||
// Maybe retransmissions aren't fully implemented in quic-go?
|
|
||||||
// Anyways, the simple solution is to make a second try when
|
|
||||||
// it fails to open the QUIC connection.
|
|
||||||
conn, err = s.openConnection()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.connection = conn
|
|
||||||
return conn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *QUICNameServer) openConnection() (quic.Connection, error) {
|
|
||||||
tlsConfig := tls.Config{}
|
|
||||||
quicConfig := &quic.Config{
|
|
||||||
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)
|
|
||||||
log.Record(&log.AccessMessage{
|
|
||||||
From: "DNS",
|
|
||||||
To: s.destination,
|
|
||||||
Status: log.AccessAccepted,
|
|
||||||
Detour: "local",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return conn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *QUICNameServer) openStream(ctx context.Context) (quic.Stream, error) {
|
|
||||||
conn, err := s.getConnection()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// open a new stream
|
|
||||||
return conn.OpenStreamSync(ctx)
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
package dns_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/url"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
. "github.com/xtls/xray-core/app/dns"
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/features/dns"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestQUICNameServer(t *testing.T) {
|
|
||||||
url, err := url.Parse("quic://dns.adguard.com")
|
|
||||||
common.Must(err)
|
|
||||||
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP)
|
|
||||||
common.Must(err)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
|
||||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
}, false)
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips2, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
}, true)
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if r := cmp.Diff(ips2, ips); r != "" {
|
|
||||||
t.Fatal(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestQUICNameServerWithIPv4Override(t *testing.T) {
|
|
||||||
url, err := url.Parse("quic://dns.adguard.com")
|
|
||||||
common.Must(err)
|
|
||||||
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP4)
|
|
||||||
common.Must(err)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
|
||||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
}, false)
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ip := range ips {
|
|
||||||
if len(ip) != net.IPv4len {
|
|
||||||
t.Error("expect only IPv4 response from DNS query")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestQUICNameServerWithIPv6Override(t *testing.T) {
|
|
||||||
url, err := url.Parse("quic://dns.adguard.com")
|
|
||||||
common.Must(err)
|
|
||||||
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP6)
|
|
||||||
common.Must(err)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
|
||||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
}, false)
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ip := range ips {
|
|
||||||
if len(ip) != net.IPv6len {
|
|
||||||
t.Error("expect only IPv6 response from DNS query")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,375 +0,0 @@
|
|||||||
package dns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/binary"
|
|
||||||
"net/url"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"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/cnc"
|
|
||||||
"github.com/xtls/xray-core/common/protocol/dns"
|
|
||||||
"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"
|
|
||||||
"github.com/xtls/xray-core/features/routing"
|
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
|
||||||
"golang.org/x/net/dns/dnsmessage"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TCPNameServer implemented DNS over TCP (RFC7766).
|
|
||||||
type TCPNameServer struct {
|
|
||||||
sync.RWMutex
|
|
||||||
name string
|
|
||||||
destination *net.Destination
|
|
||||||
ips map[string]*record
|
|
||||||
pub *pubsub.Service
|
|
||||||
cleanup *task.Periodic
|
|
||||||
reqID uint32
|
|
||||||
dial func(context.Context) (net.Conn, error)
|
|
||||||
queryStrategy QueryStrategy
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTCPNameServer creates DNS over TCP server object for remote resolving.
|
|
||||||
func NewTCPNameServer(
|
|
||||||
url *url.URL,
|
|
||||||
dispatcher routing.Dispatcher,
|
|
||||||
queryStrategy QueryStrategy,
|
|
||||||
) (*TCPNameServer, error) {
|
|
||||||
s, err := baseTCPNameServer(url, "TCP", queryStrategy)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
s.dial = func(ctx context.Context) (net.Conn, error) {
|
|
||||||
link, err := dispatcher.Dispatch(toDnsContext(ctx, s.destination.String()), *s.destination)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return cnc.NewConnection(
|
|
||||||
cnc.ConnectionInputMulti(link.Writer),
|
|
||||||
cnc.ConnectionOutputMulti(link.Reader),
|
|
||||||
), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTCPLocalNameServer creates DNS over TCP client object for local resolving
|
|
||||||
func NewTCPLocalNameServer(url *url.URL, queryStrategy QueryStrategy) (*TCPNameServer, error) {
|
|
||||||
s, err := baseTCPNameServer(url, "TCPL", queryStrategy)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
s.dial = func(ctx context.Context) (net.Conn, error) {
|
|
||||||
return internet.DialSystem(ctx, *s.destination, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func baseTCPNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) (*TCPNameServer, error) {
|
|
||||||
port := net.Port(53)
|
|
||||||
if url.Port() != "" {
|
|
||||||
var err error
|
|
||||||
if port, err = net.PortFromString(url.Port()); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dest := net.TCPDestination(net.ParseAddress(url.Hostname()), port)
|
|
||||||
|
|
||||||
s := &TCPNameServer{
|
|
||||||
destination: &dest,
|
|
||||||
ips: make(map[string]*record),
|
|
||||||
pub: pubsub.NewService(),
|
|
||||||
name: prefix + "//" + dest.NetAddr(),
|
|
||||||
queryStrategy: queryStrategy,
|
|
||||||
}
|
|
||||||
s.cleanup = &task.Periodic{
|
|
||||||
Interval: time.Minute,
|
|
||||||
Execute: s.Cleanup,
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name implements Server.
|
|
||||||
func (s *TCPNameServer) Name() string {
|
|
||||||
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 errors.New("nothing to do. stopping...")
|
|
||||||
}
|
|
||||||
|
|
||||||
for domain, record := range s.ips {
|
|
||||||
if record.A != nil && record.A.Expire.Before(now) {
|
|
||||||
record.A = nil
|
|
||||||
}
|
|
||||||
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
|
||||||
record.AAAA = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if record.A == nil && record.AAAA == nil {
|
|
||||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
|
||||||
delete(s.ips, domain)
|
|
||||||
} else {
|
|
||||||
s.ips[domain] = record
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(s.ips) == 0 {
|
|
||||||
s.ips = make(map[string]*record)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *TCPNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
|
||||||
elapsed := time.Since(req.start)
|
|
||||||
|
|
||||||
s.Lock()
|
|
||||||
rec, found := s.ips[req.domain]
|
|
||||||
if !found {
|
|
||||||
rec = &record{}
|
|
||||||
}
|
|
||||||
updated := false
|
|
||||||
|
|
||||||
switch req.reqType {
|
|
||||||
case dnsmessage.TypeA:
|
|
||||||
if isNewer(rec.A, ipRec) {
|
|
||||||
rec.A = ipRec
|
|
||||||
updated = true
|
|
||||||
}
|
|
||||||
case dnsmessage.TypeAAAA:
|
|
||||||
addr := make([]net.Address, 0)
|
|
||||||
for _, ip := range ipRec.IP {
|
|
||||||
if len(ip.IP()) == net.IPv6len {
|
|
||||||
addr = append(addr, ip)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ipRec.IP = addr
|
|
||||||
if isNewer(rec.AAAA, ipRec) {
|
|
||||||
rec.AAAA = ipRec
|
|
||||||
updated = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
|
||||||
|
|
||||||
if updated {
|
|
||||||
s.ips[req.domain] = rec
|
|
||||||
}
|
|
||||||
switch req.reqType {
|
|
||||||
case dnsmessage.TypeA:
|
|
||||||
s.pub.Publish(req.domain+"4", nil)
|
|
||||||
case dnsmessage.TypeAAAA:
|
|
||||||
s.pub.Publish(req.domain+"6", nil)
|
|
||||||
}
|
|
||||||
s.Unlock()
|
|
||||||
common.Must(s.cleanup.Start())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *TCPNameServer) newReqID() uint16 {
|
|
||||||
return uint16(atomic.AddUint32(&s.reqID, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
|
||||||
|
|
||||||
var deadline time.Time
|
|
||||||
if d, ok := ctx.Deadline(); ok {
|
|
||||||
deadline = d
|
|
||||||
} else {
|
|
||||||
deadline = time.Now().Add(time.Second * 5)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, req := range reqs {
|
|
||||||
go func(r *dnsRequest) {
|
|
||||||
dnsCtx := ctx
|
|
||||||
|
|
||||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
|
||||||
dnsCtx = session.ContextWithInbound(dnsCtx, inbound)
|
|
||||||
}
|
|
||||||
|
|
||||||
dnsCtx = session.ContextWithContent(dnsCtx, &session.Content{
|
|
||||||
Protocol: "dns",
|
|
||||||
SkipDNSResolve: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
var cancel context.CancelFunc
|
|
||||||
dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
b, err := dns.PackMessage(r.msg)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
conn, err := s.dial(dnsCtx)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to dial namesever")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
dnsReqBuf := buf.New()
|
|
||||||
binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
|
||||||
dnsReqBuf.Write(b.Bytes())
|
|
||||||
b.Release()
|
|
||||||
|
|
||||||
_, err = conn.Write(dnsReqBuf.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to send query")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
dnsReqBuf.Release()
|
|
||||||
|
|
||||||
respBuf := buf.New()
|
|
||||||
defer respBuf.Release()
|
|
||||||
n, err := respBuf.ReadFullFrom(conn, 2)
|
|
||||||
if err != nil && n == 0 {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
|
||||||
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")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
respBuf.Clear()
|
|
||||||
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
|
||||||
if err != nil && n == 0 {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rec, err := parseResponse(respBuf.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to parse DNS over TCP response")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
s.updateIP(r, rec)
|
|
||||||
}(req)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *TCPNameServer) 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.
|
|
||||||
func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
|
|
||||||
fqdn := Fqdn(domain)
|
|
||||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
|
||||||
if !option.IPv4Enable && !option.IPv6Enable {
|
|
||||||
return nil, dns_feature.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
if disableCache {
|
|
||||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
|
||||||
} else {
|
|
||||||
ips, err := s.findIPsForDomain(fqdn, option)
|
|
||||||
if err == nil || err == dns_feature.ErrEmptyResponse {
|
|
||||||
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
|
|
||||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
|
||||||
return ips, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ipv4 and ipv6 belong to different subscription groups
|
|
||||||
var sub4, sub6 *pubsub.Subscriber
|
|
||||||
if option.IPv4Enable {
|
|
||||||
sub4 = s.pub.Subscribe(fqdn + "4")
|
|
||||||
defer sub4.Close()
|
|
||||||
}
|
|
||||||
if option.IPv6Enable {
|
|
||||||
sub6 = s.pub.Subscribe(fqdn + "6")
|
|
||||||
defer sub6.Close()
|
|
||||||
}
|
|
||||||
done := make(chan interface{})
|
|
||||||
go func() {
|
|
||||||
if sub4 != nil {
|
|
||||||
select {
|
|
||||||
case <-sub4.Wait():
|
|
||||||
case <-ctx.Done():
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sub6 != nil {
|
|
||||||
select {
|
|
||||||
case <-sub6.Wait():
|
|
||||||
case <-ctx.Done():
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
s.sendQuery(ctx, fqdn, clientIP, option)
|
|
||||||
start := time.Now()
|
|
||||||
|
|
||||||
for {
|
|
||||||
ips, err := s.findIPsForDomain(fqdn, option)
|
|
||||||
if err != errRecordNotFound {
|
|
||||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
|
||||||
return ips, err
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, ctx.Err()
|
|
||||||
case <-done:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
package dns_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/url"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
. "github.com/xtls/xray-core/app/dns"
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestTCPLocalNameServer(t *testing.T) {
|
|
||||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
|
||||||
common.Must(err)
|
|
||||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP)
|
|
||||||
common.Must(err)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
}, false)
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTCPLocalNameServerWithCache(t *testing.T) {
|
|
||||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
|
||||||
common.Must(err)
|
|
||||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP)
|
|
||||||
common.Must(err)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
}, false)
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips2, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns_feature.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
}, true)
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
if r := cmp.Diff(ips2, ips); r != "" {
|
|
||||||
t.Fatal(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTCPLocalNameServerWithIPv4Override(t *testing.T) {
|
|
||||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
|
||||||
common.Must(err)
|
|
||||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP4)
|
|
||||||
common.Must(err)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
}, false)
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ip := range ips {
|
|
||||||
if len(ip) != net.IPv4len {
|
|
||||||
t.Error("expect only IPv4 response from DNS query")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTCPLocalNameServerWithIPv6Override(t *testing.T) {
|
|
||||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
|
||||||
common.Must(err)
|
|
||||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP6)
|
|
||||||
common.Must(err)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
}, false)
|
|
||||||
cancel()
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
if len(ips) == 0 {
|
|
||||||
t.Error("expect some ips, but got 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ip := range ips {
|
|
||||||
if len(ip) != net.IPv6len {
|
|
||||||
t.Error("expect only IPv6 response from DNS query")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,18 +7,17 @@ import (
|
|||||||
|
|
||||||
. "github.com/xtls/xray-core/app/dns"
|
. "github.com/xtls/xray-core/app/dns"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/net"
|
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLocalNameServer(t *testing.T) {
|
func TestLocalNameServer(t *testing.T) {
|
||||||
s := NewLocalNameServer()
|
s := NewLocalNameServer()
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||||
ips, err := s.QueryIP(ctx, "google.com", net.IP{}, dns.IPOption{
|
ips, err := s.QueryIP(ctx, "google.com", dns_feature.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 {
|
||||||
439
app/dns/server.go
Normal file
439
app/dns/server.go
Normal file
@@ -0,0 +1,439 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/app/router"
|
||||||
|
"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/session"
|
||||||
|
"github.com/xtls/xray-core/common/strmatcher"
|
||||||
|
"github.com/xtls/xray-core/common/uuid"
|
||||||
|
core "github.com/xtls/xray-core/core"
|
||||||
|
"github.com/xtls/xray-core/features"
|
||||||
|
"github.com/xtls/xray-core/features/dns"
|
||||||
|
"github.com/xtls/xray-core/features/routing"
|
||||||
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Server is a DNS rely server.
|
||||||
|
type Server struct {
|
||||||
|
sync.Mutex
|
||||||
|
hosts *StaticHosts
|
||||||
|
clientIP net.IP
|
||||||
|
clients []Client // clientIdx -> Client
|
||||||
|
ctx context.Context
|
||||||
|
ipIndexMap []*MultiGeoIPMatcher // clientIdx -> *MultiGeoIPMatcher
|
||||||
|
domainRules [][]string // clientIdx -> domainRuleIdx -> DomainRule
|
||||||
|
domainMatcher strmatcher.IndexMatcher
|
||||||
|
matcherInfos []DomainMatcherInfo // matcherIdx -> DomainMatcherInfo
|
||||||
|
tag string
|
||||||
|
}
|
||||||
|
|
||||||
|
// DomainMatcherInfo contains information attached to index returned by Server.domainMatcher
|
||||||
|
type DomainMatcherInfo struct {
|
||||||
|
clientIdx uint16
|
||||||
|
domainRuleIdx uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// MultiGeoIPMatcher for match
|
||||||
|
type MultiGeoIPMatcher struct {
|
||||||
|
matchers []*router.GeoIPMatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
var errExpectedIPNonMatch = errors.New("expectIPs not match")
|
||||||
|
|
||||||
|
// Match check ip match
|
||||||
|
func (c *MultiGeoIPMatcher) Match(ip net.IP) bool {
|
||||||
|
for _, matcher := range c.matchers {
|
||||||
|
if matcher.Match(ip) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasMatcher check has matcher
|
||||||
|
func (c *MultiGeoIPMatcher) HasMatcher() bool {
|
||||||
|
return len(c.matchers) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateRandomTag() string {
|
||||||
|
id := uuid.New()
|
||||||
|
return "xray.system." + id.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new DNS server with given configuration.
|
||||||
|
func New(ctx context.Context, config *Config) (*Server, error) {
|
||||||
|
server := &Server{
|
||||||
|
clients: make([]Client, 0, len(config.NameServers)+len(config.NameServer)),
|
||||||
|
ctx: ctx,
|
||||||
|
tag: config.Tag,
|
||||||
|
}
|
||||||
|
if server.tag == "" {
|
||||||
|
server.tag = generateRandomTag()
|
||||||
|
}
|
||||||
|
if len(config.ClientIp) > 0 {
|
||||||
|
if len(config.ClientIp) != net.IPv4len && len(config.ClientIp) != net.IPv6len {
|
||||||
|
return nil, newError("unexpected IP length", len(config.ClientIp))
|
||||||
|
}
|
||||||
|
server.clientIP = net.IP(config.ClientIp)
|
||||||
|
}
|
||||||
|
|
||||||
|
hosts, err := NewStaticHosts(config.StaticHosts, config.Hosts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, newError("failed to create hosts").Base(err)
|
||||||
|
}
|
||||||
|
server.hosts = hosts
|
||||||
|
|
||||||
|
addNameServer := func(ns *NameServer) int {
|
||||||
|
endpoint := ns.Address
|
||||||
|
address := endpoint.Address.AsAddress()
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case address.Family().IsDomain() && address.Domain() == "localhost":
|
||||||
|
server.clients = append(server.clients, NewLocalNameServer())
|
||||||
|
// Priotize local domains with specific TLDs or without any dot to local DNS
|
||||||
|
// References:
|
||||||
|
// https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml
|
||||||
|
// https://unix.stackexchange.com/questions/92441/whats-the-difference-between-local-home-and-lan
|
||||||
|
localTLDsAndDotlessDomains := []*NameServer_PriorityDomain{
|
||||||
|
{Type: DomainMatchingType_Regex, Domain: "^[^.]+$"}, // This will only match domains without any dot
|
||||||
|
{Type: DomainMatchingType_Subdomain, Domain: "local"},
|
||||||
|
{Type: DomainMatchingType_Subdomain, Domain: "localdomain"},
|
||||||
|
{Type: DomainMatchingType_Subdomain, Domain: "localhost"},
|
||||||
|
{Type: DomainMatchingType_Subdomain, Domain: "lan"},
|
||||||
|
{Type: DomainMatchingType_Subdomain, Domain: "home.arpa"},
|
||||||
|
{Type: DomainMatchingType_Subdomain, Domain: "example"},
|
||||||
|
{Type: DomainMatchingType_Subdomain, Domain: "invalid"},
|
||||||
|
{Type: DomainMatchingType_Subdomain, Domain: "test"},
|
||||||
|
}
|
||||||
|
ns.PrioritizedDomain = append(ns.PrioritizedDomain, localTLDsAndDotlessDomains...)
|
||||||
|
|
||||||
|
case address.Family().IsDomain() && strings.HasPrefix(address.Domain(), "https+local://"):
|
||||||
|
// URI schemed string treated as domain
|
||||||
|
// DOH Local mode
|
||||||
|
u, err := url.Parse(address.Domain())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(newError("DNS config error").Base(err))
|
||||||
|
}
|
||||||
|
server.clients = append(server.clients, NewDoHLocalNameServer(u, server.clientIP))
|
||||||
|
|
||||||
|
case address.Family().IsDomain() && strings.HasPrefix(address.Domain(), "https://"):
|
||||||
|
// DOH Remote mode
|
||||||
|
u, err := url.Parse(address.Domain())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(newError("DNS config error").Base(err))
|
||||||
|
}
|
||||||
|
idx := len(server.clients)
|
||||||
|
server.clients = append(server.clients, nil)
|
||||||
|
|
||||||
|
// need the core dispatcher, register DOHClient at callback
|
||||||
|
common.Must(core.RequireFeatures(ctx, func(d routing.Dispatcher) {
|
||||||
|
c, err := NewDoHNameServer(u, d, server.clientIP)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(newError("DNS config error").Base(err))
|
||||||
|
}
|
||||||
|
server.clients[idx] = c
|
||||||
|
}))
|
||||||
|
|
||||||
|
case address.Family().IsDomain() && address.Domain() == "fakedns":
|
||||||
|
server.clients = append(server.clients, NewFakeDNSServer())
|
||||||
|
|
||||||
|
default:
|
||||||
|
// UDP classic DNS mode
|
||||||
|
dest := endpoint.AsDestination()
|
||||||
|
if dest.Network == net.Network_Unknown {
|
||||||
|
dest.Network = net.Network_UDP
|
||||||
|
}
|
||||||
|
if dest.Network == net.Network_UDP {
|
||||||
|
idx := len(server.clients)
|
||||||
|
server.clients = append(server.clients, nil)
|
||||||
|
|
||||||
|
common.Must(core.RequireFeatures(ctx, func(d routing.Dispatcher) {
|
||||||
|
server.clients[idx] = NewClassicNameServer(dest, d, server.clientIP)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
server.ipIndexMap = append(server.ipIndexMap, nil)
|
||||||
|
return len(server.clients) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.NameServers) > 0 {
|
||||||
|
features.PrintDeprecatedFeatureWarning("simple DNS server")
|
||||||
|
for _, destPB := range config.NameServers {
|
||||||
|
addNameServer(&NameServer{Address: destPB})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.NameServer) > 0 {
|
||||||
|
clientIndices := []int{}
|
||||||
|
domainRuleCount := 0
|
||||||
|
for _, ns := range config.NameServer {
|
||||||
|
idx := addNameServer(ns)
|
||||||
|
clientIndices = append(clientIndices, idx)
|
||||||
|
domainRuleCount += len(ns.PrioritizedDomain)
|
||||||
|
}
|
||||||
|
|
||||||
|
domainRules := make([][]string, len(server.clients))
|
||||||
|
domainMatcher := &strmatcher.MatcherGroup{}
|
||||||
|
matcherInfos := make([]DomainMatcherInfo, domainRuleCount+1) // matcher index starts from 1
|
||||||
|
var geoIPMatcherContainer router.GeoIPMatcherContainer
|
||||||
|
for nidx, ns := range config.NameServer {
|
||||||
|
idx := clientIndices[nidx]
|
||||||
|
|
||||||
|
// Establish domain rule matcher
|
||||||
|
rules := []string{}
|
||||||
|
ruleCurr := 0
|
||||||
|
ruleIter := 0
|
||||||
|
for _, domain := range ns.PrioritizedDomain {
|
||||||
|
matcher, err := toStrMatcher(domain.Type, domain.Domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, newError("failed to create prioritized domain").Base(err).AtWarning()
|
||||||
|
}
|
||||||
|
midx := domainMatcher.Add(matcher)
|
||||||
|
if midx >= uint32(len(matcherInfos)) { // This rarely happens according to current matcher's implementation
|
||||||
|
newError("expanding domain matcher info array to size ", midx, " when adding ", matcher).AtDebug().WriteToLog()
|
||||||
|
matcherInfos = append(matcherInfos, make([]DomainMatcherInfo, midx-uint32(len(matcherInfos))+1)...)
|
||||||
|
}
|
||||||
|
info := &matcherInfos[midx]
|
||||||
|
info.clientIdx = uint16(idx)
|
||||||
|
if ruleCurr < len(ns.OriginalRules) {
|
||||||
|
info.domainRuleIdx = uint16(ruleCurr)
|
||||||
|
rule := ns.OriginalRules[ruleCurr]
|
||||||
|
if ruleCurr >= len(rules) {
|
||||||
|
rules = append(rules, rule.Rule)
|
||||||
|
}
|
||||||
|
ruleIter++
|
||||||
|
if ruleIter >= int(rule.Size) {
|
||||||
|
ruleIter = 0
|
||||||
|
ruleCurr++
|
||||||
|
}
|
||||||
|
} else { // No original rule, generate one according to current domain matcher (majorly for compatibility with tests)
|
||||||
|
info.domainRuleIdx = uint16(len(rules))
|
||||||
|
rules = append(rules, matcher.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
domainRules[idx] = rules
|
||||||
|
|
||||||
|
// only add to ipIndexMap if GeoIP is configured
|
||||||
|
if len(ns.Geoip) > 0 {
|
||||||
|
var matchers []*router.GeoIPMatcher
|
||||||
|
for _, geoip := range ns.Geoip {
|
||||||
|
matcher, err := geoIPMatcherContainer.Add(geoip)
|
||||||
|
if err != nil {
|
||||||
|
return nil, newError("failed to create ip matcher").Base(err).AtWarning()
|
||||||
|
}
|
||||||
|
matchers = append(matchers, matcher)
|
||||||
|
}
|
||||||
|
matcher := &MultiGeoIPMatcher{matchers: matchers}
|
||||||
|
server.ipIndexMap[idx] = matcher
|
||||||
|
}
|
||||||
|
}
|
||||||
|
server.domainRules = domainRules
|
||||||
|
server.domainMatcher = domainMatcher
|
||||||
|
server.matcherInfos = matcherInfos
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(server.clients) == 0 {
|
||||||
|
server.clients = append(server.clients, NewLocalNameServer())
|
||||||
|
server.ipIndexMap = append(server.ipIndexMap, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return server, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type implements common.HasType.
|
||||||
|
func (*Server) Type() interface{} {
|
||||||
|
return dns.ClientType()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start implements common.Runnable.
|
||||||
|
func (s *Server) Start() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close implements common.Closable.
|
||||||
|
func (s *Server) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) IsOwnLink(ctx context.Context) bool {
|
||||||
|
inbound := session.InboundFromContext(ctx)
|
||||||
|
return inbound != nil && inbound.Tag == s.tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match check dns ip match geoip
|
||||||
|
func (s *Server) Match(idx int, client Client, domain string, ips []net.IP) ([]net.IP, error) {
|
||||||
|
var matcher *MultiGeoIPMatcher
|
||||||
|
if idx < len(s.ipIndexMap) {
|
||||||
|
matcher = s.ipIndexMap[idx]
|
||||||
|
}
|
||||||
|
if matcher == nil {
|
||||||
|
return ips, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !matcher.HasMatcher() {
|
||||||
|
newError("domain ", domain, " server has no valid matcher: ", client.Name(), " idx:", idx).AtDebug().WriteToLog()
|
||||||
|
return ips, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newIps := []net.IP{}
|
||||||
|
for _, ip := range ips {
|
||||||
|
if matcher.Match(ip) {
|
||||||
|
newIps = append(newIps, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(newIps) == 0 {
|
||||||
|
return nil, errExpectedIPNonMatch
|
||||||
|
}
|
||||||
|
newError("domain ", domain, " expectIPs ", newIps, " matched at server ", client.Name(), " idx:", idx).AtDebug().WriteToLog()
|
||||||
|
return newIps, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) queryIPTimeout(idx int, client Client, domain string, option dns.IPOption) ([]net.IP, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(s.ctx, time.Second*4)
|
||||||
|
if len(s.tag) > 0 {
|
||||||
|
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||||
|
Tag: s.tag,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ctx = internet.ContextWithLookupDomain(ctx, domain)
|
||||||
|
ips, err := client.QueryIP(ctx, domain, option)
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return ips, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ips, err = s.Match(idx, client, domain, ips)
|
||||||
|
return ips, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) lookupStatic(domain string, option dns.IPOption, depth int32) []net.Address {
|
||||||
|
ips := s.hosts.LookupIP(domain, option)
|
||||||
|
if ips == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if ips[0].Family().IsDomain() && depth < 5 {
|
||||||
|
if newIPs := s.lookupStatic(ips[0].Domain(), option, depth+1); newIPs != nil {
|
||||||
|
return newIPs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ips
|
||||||
|
}
|
||||||
|
|
||||||
|
func toNetIP(ips []net.Address) []net.IP {
|
||||||
|
if len(ips) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
netips := make([]net.IP, 0, len(ips))
|
||||||
|
for _, ip := range ips {
|
||||||
|
netips = append(netips, ip.IP())
|
||||||
|
}
|
||||||
|
return netips
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupIP implements dns.Client.
|
||||||
|
func (s *Server) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
|
||||||
|
if domain == "" {
|
||||||
|
return nil, newError("empty domain name")
|
||||||
|
}
|
||||||
|
domain = strings.ToLower(domain)
|
||||||
|
|
||||||
|
// normalize the FQDN form query
|
||||||
|
if strings.HasSuffix(domain, ".") {
|
||||||
|
domain = domain[:len(domain)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
ips := s.lookupStatic(domain, option, 0)
|
||||||
|
if ips != nil && ips[0].Family().IsIP() {
|
||||||
|
newError("returning ", len(ips), " IPs for domain ", domain).WriteToLog()
|
||||||
|
return toNetIP(ips), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ips != nil && ips[0].Family().IsDomain() {
|
||||||
|
newdomain := ips[0].Domain()
|
||||||
|
newError("domain replaced: ", domain, " -> ", newdomain).WriteToLog()
|
||||||
|
domain = newdomain
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastErr error
|
||||||
|
var matchedClient Client
|
||||||
|
if s.domainMatcher != nil {
|
||||||
|
indices := s.domainMatcher.Match(domain)
|
||||||
|
domainRules := []string{}
|
||||||
|
matchingDNS := []string{}
|
||||||
|
for _, idx := range indices {
|
||||||
|
info := s.matcherInfos[idx]
|
||||||
|
rule := s.domainRules[info.clientIdx][info.domainRuleIdx]
|
||||||
|
domainRules = append(domainRules, fmt.Sprintf("%s(DNS idx:%d)", rule, info.clientIdx))
|
||||||
|
matchingDNS = append(matchingDNS, s.clients[info.clientIdx].Name())
|
||||||
|
}
|
||||||
|
if len(domainRules) > 0 {
|
||||||
|
newError("domain ", domain, " matches following rules: ", domainRules).AtDebug().WriteToLog()
|
||||||
|
}
|
||||||
|
if len(matchingDNS) > 0 {
|
||||||
|
newError("domain ", domain, " uses following DNS first: ", matchingDNS).AtDebug().WriteToLog()
|
||||||
|
}
|
||||||
|
for _, idx := range indices {
|
||||||
|
clientIdx := int(s.matcherInfos[idx].clientIdx)
|
||||||
|
matchedClient = s.clients[clientIdx]
|
||||||
|
if !option.FakeEnable && strings.EqualFold(matchedClient.Name(), "FakeDNS") {
|
||||||
|
newError("skip DNS resolution for domain ", domain, " at server ", matchedClient.Name()).AtDebug().WriteToLog()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ips, err := s.queryIPTimeout(clientIdx, matchedClient, domain, option)
|
||||||
|
if len(ips) > 0 {
|
||||||
|
return ips, nil
|
||||||
|
}
|
||||||
|
if err == dns.ErrEmptyResponse {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
newError("failed to lookup ip for domain ", domain, " at server ", matchedClient.Name()).Base(err).WriteToLog()
|
||||||
|
lastErr = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for idx, client := range s.clients {
|
||||||
|
if client == matchedClient {
|
||||||
|
newError("domain ", domain, " at server ", client.Name(), " idx:", idx, " already lookup failed, just ignore").AtDebug().WriteToLog()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
|
||||||
|
newError("skip DNS resolution for domain ", domain, " at server ", client.Name()).AtDebug().WriteToLog()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ips, err := s.queryIPTimeout(idx, client, domain, option)
|
||||||
|
if len(ips) > 0 {
|
||||||
|
return ips, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog()
|
||||||
|
lastErr = err
|
||||||
|
}
|
||||||
|
if err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, newError("returning nil for domain ", domain).Base(lastErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||||
|
return New(ctx, config.(*Config))
|
||||||
|
}))
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/dispatcher"
|
"github.com/xtls/xray-core/app/dispatcher"
|
||||||
. "github.com/xtls/xray-core/app/dns"
|
. "github.com/xtls/xray-core/app/dns"
|
||||||
"github.com/xtls/xray-core/app/policy"
|
"github.com/xtls/xray-core/app/policy"
|
||||||
@@ -13,7 +14,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"
|
||||||
@@ -22,7 +22,8 @@ import (
|
|||||||
"github.com/xtls/xray-core/testing/servers/udp"
|
"github.com/xtls/xray-core/testing/servers/udp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type staticHandler struct{}
|
type staticHandler struct {
|
||||||
|
}
|
||||||
|
|
||||||
func (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
func (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
||||||
ans := new(dns.Msg)
|
ans := new(dns.Msg)
|
||||||
@@ -100,8 +101,8 @@ func (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||||||
rr, _ := dns.NewRR("localhost-b. IN A 127.0.0.4")
|
rr, _ := dns.NewRR("localhost-b. IN A 127.0.0.4")
|
||||||
ans.Answer = append(ans.Answer, rr)
|
ans.Answer = append(ans.Answer, rr)
|
||||||
|
|
||||||
case q.Name == "Mijia\\ Cloud." && q.Qtype == dns.TypeA:
|
case q.Name == "mijia\\ cloud." && q.Qtype == dns.TypeA:
|
||||||
rr, _ := dns.NewRR("Mijia\\ Cloud. IN A 127.0.0.1")
|
rr, _ := dns.NewRR("mijia\\ cloud. IN A 127.0.0.1")
|
||||||
ans.Answer = append(ans.Answer, rr)
|
ans.Answer = append(ans.Answer, rr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,17 +125,15 @@ func TestUDPServerSubnet(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),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ClientIp: []byte{7, 8, 9, 10},
|
ClientIp: []byte{7, 8, 9, 10},
|
||||||
@@ -185,17 +184,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),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -265,7 +262,7 @@ func TestUDPServer(t *testing.T) {
|
|||||||
IPv6Enable: true,
|
IPv6Enable: true,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
})
|
})
|
||||||
if !errors.AllEqual(feature_dns.ErrEmptyResponse, errors.Cause(err)) {
|
if err != feature_dns.ErrEmptyResponse {
|
||||||
t.Fatal("error: ", err)
|
t.Fatal("error: ", err)
|
||||||
}
|
}
|
||||||
if len(ips) != 0 {
|
if len(ips) != 0 {
|
||||||
@@ -307,18 +304,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,
|
||||||
@@ -393,17 +390,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),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -454,17 +449,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{
|
||||||
@@ -639,18 +632,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,
|
||||||
@@ -867,18 +860,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,
|
||||||
@@ -2,17 +2,18 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/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/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"
|
||||||
@@ -21,57 +22,53 @@ import (
|
|||||||
"golang.org/x/net/dns/dnsmessage"
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ClassicNameServer implemented traditional UDP DNS.
|
|
||||||
type ClassicNameServer struct {
|
type ClassicNameServer struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
name string
|
name string
|
||||||
address *net.Destination
|
address net.Destination
|
||||||
ips map[string]*record
|
ips map[string]record
|
||||||
requests map[uint16]*dnsRequest
|
requests map[uint16]dnsRequest
|
||||||
pub *pubsub.Service
|
pub *pubsub.Service
|
||||||
udpServer *udp.Dispatcher
|
udpServer *udp.Dispatcher
|
||||||
cleanup *task.Periodic
|
cleanup *task.Periodic
|
||||||
reqID uint32
|
reqID uint32
|
||||||
queryStrategy QueryStrategy
|
clientIP net.IP
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClassicNameServer creates udp server object for remote resolving.
|
func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher, clientIP net.IP) *ClassicNameServer {
|
||||||
func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) *ClassicNameServer {
|
|
||||||
// default to 53 if unspecific
|
// default to 53 if unspecific
|
||||||
if address.Port == 0 {
|
if address.Port == 0 {
|
||||||
address.Port = net.Port(53)
|
address.Port = net.Port(53)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := &ClassicNameServer{
|
s := &ClassicNameServer{
|
||||||
address: &address,
|
address: address,
|
||||||
ips: make(map[string]*record),
|
ips: make(map[string]record),
|
||||||
requests: make(map[uint16]*dnsRequest),
|
requests: make(map[uint16]dnsRequest),
|
||||||
pub: pubsub.NewService(),
|
clientIP: clientIP,
|
||||||
name: strings.ToUpper(address.String()),
|
pub: pubsub.NewService(),
|
||||||
queryStrategy: queryStrategy,
|
name: strings.ToUpper(address.String()),
|
||||||
}
|
}
|
||||||
s.cleanup = &task.Periodic{
|
s.cleanup = &task.Periodic{
|
||||||
Interval: time.Minute,
|
Interval: time.Minute,
|
||||||
Execute: s.Cleanup,
|
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.
|
|
||||||
func (s *ClassicNameServer) Name() string {
|
func (s *ClassicNameServer) Name() string {
|
||||||
return s.name
|
return s.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup clears expired items from cache
|
|
||||||
func (s *ClassicNameServer) Cleanup() 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.ips) == 0 && 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 {
|
for domain, record := range s.ips {
|
||||||
@@ -83,7 +80,6 @@ func (s *ClassicNameServer) Cleanup() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if record.A == nil && record.AAAA == nil {
|
if record.A == nil && record.AAAA == nil {
|
||||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
|
||||||
delete(s.ips, domain)
|
delete(s.ips, domain)
|
||||||
} else {
|
} else {
|
||||||
s.ips[domain] = record
|
s.ips[domain] = record
|
||||||
@@ -91,7 +87,7 @@ func (s *ClassicNameServer) Cleanup() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(s.ips) == 0 {
|
if len(s.ips) == 0 {
|
||||||
s.ips = make(map[string]*record)
|
s.ips = make(map[string]record)
|
||||||
}
|
}
|
||||||
|
|
||||||
for id, req := range s.requests {
|
for id, req := range s.requests {
|
||||||
@@ -101,17 +97,16 @@ func (s *ClassicNameServer) Cleanup() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(s.requests) == 0 {
|
if len(s.requests) == 0 {
|
||||||
s.requests = make(map[uint16]*dnsRequest)
|
s.requests = make(map[uint16]dnsRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleResponse handles udp response packet from remote DNS server.
|
|
||||||
func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_proto.Packet) {
|
func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_proto.Packet) {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +119,7 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,19 +132,17 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
|||||||
}
|
}
|
||||||
|
|
||||||
elapsed := time.Since(req.start)
|
elapsed := time.Since(req.start)
|
||||||
errors.LogInfo(ctx, s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
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) {
|
if len(req.domain) > 0 && (rec.A != nil || rec.AAAA != nil) {
|
||||||
s.updateIP(req.domain, &rec)
|
s.updateIP(req.domain, rec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ClassicNameServer) updateIP(domain string, newRec *record) {
|
func (s *ClassicNameServer) updateIP(domain string, newRec record) {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
|
|
||||||
rec, found := s.ips[domain]
|
newError(s.name, " updating IP records for domain:", domain).AtDebug().WriteToLog()
|
||||||
if !found {
|
rec := s.ips[domain]
|
||||||
rec = &record{}
|
|
||||||
}
|
|
||||||
|
|
||||||
updated := false
|
updated := false
|
||||||
if isNewer(rec.A, newRec.A) {
|
if isNewer(rec.A, newRec.A) {
|
||||||
@@ -162,7 +155,6 @@ func (s *ClassicNameServer) updateIP(domain string, newRec *record) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if updated {
|
if updated {
|
||||||
errors.LogDebug(context.Background(), s.name, " updating IP records for domain:", domain)
|
|
||||||
s.ips[domain] = rec
|
s.ips[domain] = rec
|
||||||
}
|
}
|
||||||
if newRec.A != nil {
|
if newRec.A != nil {
|
||||||
@@ -185,18 +177,32 @@ func (s *ClassicNameServer) addPendingRequest(req *dnsRequest) {
|
|||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, 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(clientIP))
|
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP))
|
||||||
|
|
||||||
for _, req := range reqs {
|
for _, req := range reqs {
|
||||||
s.addPendingRequest(req)
|
s.addPendingRequest(req)
|
||||||
b, _ := dns.PackMessage(req.msg)
|
b, _ := dns.PackMessage(req.msg)
|
||||||
s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b)
|
udpCtx := context.Background()
|
||||||
|
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||||
|
udpCtx = session.ContextWithInbound(udpCtx, inbound)
|
||||||
|
}
|
||||||
|
udpCtx = internet.ContextWithLookupDomain(udpCtx, internet.LookupDomainFromContext(ctx))
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,52 +215,44 @@ func (s *ClassicNameServer) findIPsForDomain(domain string, option dns_feature.I
|
|||||||
return nil, errRecordNotFound
|
return nil, errRecordNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
var err4 error
|
|
||||||
var err6 error
|
|
||||||
var ips []net.Address
|
var ips []net.Address
|
||||||
var ip6 []net.Address
|
var lastErr error
|
||||||
|
|
||||||
if option.IPv4Enable {
|
if option.IPv4Enable {
|
||||||
ips, err4 = record.A.getIPs()
|
a, err := record.A.getIPs()
|
||||||
|
if err != nil {
|
||||||
|
lastErr = err
|
||||||
|
}
|
||||||
|
ips = append(ips, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if option.IPv6Enable {
|
if option.IPv6Enable {
|
||||||
ip6, err6 = record.AAAA.getIPs()
|
aaaa, err := record.AAAA.getIPs()
|
||||||
ips = append(ips, ip6...)
|
if err != nil {
|
||||||
|
lastErr = err
|
||||||
|
}
|
||||||
|
ips = append(ips, aaaa...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ips) > 0 {
|
if len(ips) > 0 {
|
||||||
return toNetIP(ips)
|
return toNetIP(ips), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err4 != nil {
|
if lastErr != nil {
|
||||||
return nil, err4
|
return nil, lastErr
|
||||||
}
|
|
||||||
|
|
||||||
if err6 != nil {
|
|
||||||
return nil, err6
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, dns_feature.ErrEmptyResponse
|
return nil, dns_feature.ErrEmptyResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryIP implements Server.
|
// QueryIP implements Server.
|
||||||
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
|
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||||
fqdn := Fqdn(domain)
|
fqdn := Fqdn(domain)
|
||||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
|
||||||
if !option.IPv4Enable && !option.IPv6Enable {
|
|
||||||
return nil, dns_feature.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
if disableCache {
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
if err != errRecordNotFound {
|
||||||
} else {
|
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||||
ips, err := s.findIPsForDomain(fqdn, option)
|
log.Record(&log.DNSLog{s.name, domain, ips, log.DNSCacheHit, 0, err})
|
||||||
if err == nil || err == dns_feature.ErrEmptyResponse {
|
return ips, err
|
||||||
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
|
|
||||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
|
||||||
return ips, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ipv4 and ipv6 belong to different subscription groups
|
// ipv4 and ipv6 belong to different subscription groups
|
||||||
@@ -283,13 +281,13 @@ func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP
|
|||||||
}
|
}
|
||||||
close(done)
|
close(done)
|
||||||
}()
|
}()
|
||||||
s.sendQuery(ctx, fqdn, clientIP, option)
|
s.sendQuery(ctx, fqdn, option)
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
ips, err := s.findIPsForDomain(fqdn, option)
|
ips, err := s.findIPsForDomain(fqdn, option)
|
||||||
if err != errRecordNotFound {
|
if err != errRecordNotFound {
|
||||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
log.Record(&log.DNSLog{s.name, domain, ips, log.DNSQueried, time.Since(start), err})
|
||||||
return ips, err
|
return ips, 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,12 +1,13 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.25.0
|
||||||
// protoc v5.28.2
|
// protoc v3.14.0
|
||||||
// source: app/log/command/config.proto
|
// source: app/log/command/config.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
@@ -20,6 +21,10 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||||
|
// of the legacy proto package is being used.
|
||||||
|
const _ = proto.ProtoPackageIsVersion4
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -28,9 +33,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 +48,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 +71,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 +86,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 +109,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 +124,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 +179,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 +199,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,12 +1,13 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.25.0
|
||||||
// protoc v5.28.2
|
// protoc v3.14.0
|
||||||
// source: app/log/config.proto
|
// source: app/log/config.proto
|
||||||
|
|
||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
log "github.com/xtls/xray-core/common/log"
|
log "github.com/xtls/xray-core/common/log"
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
@@ -21,6 +22,10 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||||
|
// of the legacy proto package is being used.
|
||||||
|
const _ = proto.ProtoPackageIsVersion4
|
||||||
|
|
||||||
type LogType int32
|
type LogType int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -84,14 +89,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 +108,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)
|
||||||
@@ -128,7 +134,7 @@ func (x *Config) GetErrorLogLevel() log.Severity {
|
|||||||
if x != nil {
|
if x != nil {
|
||||||
return x.ErrorLogLevel
|
return x.ErrorLogLevel
|
||||||
}
|
}
|
||||||
return log.Severity(0)
|
return log.Severity_Unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetErrorLogPath() string {
|
func (x *Config) GetErrorLogPath() string {
|
||||||
@@ -159,20 +165,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 +191,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 +216,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 +237,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 instantly on initialization
|
// start logger instantly on inited
|
||||||
// Other modules would 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))
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -14,29 +11,23 @@ type HandlerCreatorOptions struct {
|
|||||||
|
|
||||||
type HandlerCreator func(LogType, HandlerCreatorOptions) (log.Handler, error)
|
type HandlerCreator func(LogType, HandlerCreatorOptions) (log.Handler, error)
|
||||||
|
|
||||||
var handlerCreatorMap = make(map[LogType]HandlerCreator)
|
var (
|
||||||
|
handlerCreatorMap = make(map[LogType]HandlerCreator)
|
||||||
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()
|
|
||||||
defer handlerCreatorMapLock.Unlock()
|
|
||||||
|
|
||||||
handlerCreatorMap[logType] = f
|
handlerCreatorMap[logType] = f
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createHandler(logType LogType, options HandlerCreatorOptions) (log.Handler, error) {
|
func createHandler(logType LogType, options HandlerCreatorOptions) (log.Handler, error) {
|
||||||
handlerCreatorMapLock.RLock()
|
|
||||||
defer handlerCreatorMapLock.RUnlock()
|
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,133 +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"`
|
|
||||||
}
|
|
||||||
|
|
||||||
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 ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_app_metrics_config_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_app_metrics_config_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x18, 0x61, 0x70, 0x70, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x63, 0x6f,
|
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61, 0x79,
|
|
||||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x1a, 0x0a, 0x06,
|
|
||||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20,
|
|
||||||
0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x42, 0x52, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e,
|
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
|
|
||||||
0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
|
|
||||||
0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
|
|
||||||
0x70, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0xaa, 0x02, 0x10, 0x58, 0x72, 0x61, 0x79,
|
|
||||||
0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72,
|
|
||||||
0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_app_metrics_config_proto_rawDescOnce sync.Once
|
|
||||||
file_app_metrics_config_proto_rawDescData = file_app_metrics_config_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_app_metrics_config_proto_rawDescGZIP() []byte {
|
|
||||||
file_app_metrics_config_proto_rawDescOnce.Do(func() {
|
|
||||||
file_app_metrics_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_metrics_config_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_app_metrics_config_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_app_metrics_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
|
||||||
var file_app_metrics_config_proto_goTypes = []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,13 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package xray.app.metrics;
|
|
||||||
option csharp_namespace = "Xray.App.Metrics";
|
|
||||||
option go_package = "github.com/xtls/xray-core/app/metrics";
|
|
||||||
option java_package = "com.xray.app.metrics";
|
|
||||||
option java_multiple_files = true;
|
|
||||||
|
|
||||||
// Config is the settings for metrics.
|
|
||||||
message Config {
|
|
||||||
// Tag of the outbound handler that handles metrics http connections.
|
|
||||||
string tag = 1;
|
|
||||||
}
|
|
||||||
@@ -1,119 +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
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMetricsHandler creates a new MetricsHandler based on the given config.
|
|
||||||
func NewMetricsHandler(ctx context.Context, config *Config) (*MetricsHandler, error) {
|
|
||||||
c := &MetricsHandler{
|
|
||||||
tag: config.Tag,
|
|
||||||
}
|
|
||||||
common.Must(core.RequireFeatures(ctx, func(om outbound.Manager, sm feature_stats.Manager) {
|
|
||||||
c.statsManager = sm
|
|
||||||
c.ohm = om
|
|
||||||
}))
|
|
||||||
expvar.Publish("stats", expvar.Func(func() interface{} {
|
|
||||||
manager, ok := c.statsManager.(*stats.Manager)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
resp := map[string]map[string]map[string]int64{
|
|
||||||
"inbound": {},
|
|
||||||
"outbound": {},
|
|
||||||
"user": {},
|
|
||||||
}
|
|
||||||
manager.VisitCounters(func(name string, counter feature_stats.Counter) bool {
|
|
||||||
nameSplit := strings.Split(name, ">>>")
|
|
||||||
typeName, tagOrUser, direction := nameSplit[0], nameSplit[1], nameSplit[3]
|
|
||||||
if item, found := resp[typeName][tagOrUser]; found {
|
|
||||||
item[direction] = counter.Value()
|
|
||||||
} else {
|
|
||||||
resp[typeName][tagOrUser] = map[string]int64{
|
|
||||||
direction: counter.Value(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return resp
|
|
||||||
}))
|
|
||||||
expvar.Publish("observatory", expvar.Func(func() interface{} {
|
|
||||||
if c.observatory == nil {
|
|
||||||
common.Must(core.RequireFeatures(ctx, func(observatory extension.Observatory) error {
|
|
||||||
c.observatory = observatory
|
|
||||||
return nil
|
|
||||||
}))
|
|
||||||
if c.observatory == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resp := map[string]*observatory.OutboundStatus{}
|
|
||||||
if o, err := c.observatory.GetObservation(context.Background()); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
for _, x := range o.(*observatory.ObservationResult).GetStatus() {
|
|
||||||
resp[x.OutboundTag] = x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resp
|
|
||||||
}))
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MetricsHandler) Type() interface{} {
|
|
||||||
return (*MetricsHandler)(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MetricsHandler) Start() error {
|
|
||||||
listener := &OutboundListener{
|
|
||||||
buffer: make(chan net.Conn, 4),
|
|
||||||
done: done.New(),
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if err := http.Serve(listener, http.DefaultServeMux); err != nil {
|
|
||||||
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,110 +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/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()
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package burst
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
rttFailed = time.Duration(math.MaxInt64 - iota)
|
|
||||||
rttUntested
|
|
||||||
rttUnqualified
|
|
||||||
)
|
|
||||||
@@ -1,110 +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"
|
|
||||||
"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
|
|
||||||
err := core.RequireFeatures(ctx, func(om outbound.Manager) {
|
|
||||||
outboundManager = om
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("Cannot get depended features").Base(err)
|
|
||||||
}
|
|
||||||
hp := NewHealthPing(ctx, config.PingConfig)
|
|
||||||
return &Observer{
|
|
||||||
config: config,
|
|
||||||
ctx: ctx,
|
|
||||||
ohm: outboundManager,
|
|
||||||
hp: hp,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
|
||||||
return New(ctx, config.(*Config))
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
@@ -1,246 +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"`
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_app_observatory_burst_config_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x22, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
|
|
||||||
0x79, 0x2f, 0x62, 0x75, 0x72, 0x73, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70,
|
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1f, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
|
||||||
0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e,
|
|
||||||
0x62, 0x75, 0x72, 0x73, 0x74, 0x22, 0x87, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
|
||||||
0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65,
|
|
||||||
0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a,
|
|
||||||
0x65, 0x63, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x52, 0x0a, 0x0b, 0x70,
|
|
||||||
0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
|
|
||||||
0x32, 0x31, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
|
|
||||||
0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x62, 0x75, 0x72,
|
|
||||||
0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
|
|
||||||
0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22,
|
|
||||||
0xb4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
|
|
||||||
0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69,
|
|
||||||
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
|
||||||
0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f,
|
|
||||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e,
|
|
||||||
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x6e,
|
|
||||||
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x69,
|
|
||||||
0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73,
|
|
||||||
0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07,
|
|
||||||
0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74,
|
|
||||||
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
|
|
||||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
|
|
||||||
0x72, 0x79, 0x2e, 0x62, 0x75, 0x72, 0x73, 0x74, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68,
|
|
||||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
|
||||||
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76,
|
|
||||||
0x61, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x62, 0x75, 0x72, 0x73, 0x74, 0xaa, 0x02, 0x1a, 0x58, 0x72,
|
|
||||||
0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
|
|
||||||
0x72, 0x79, 0x2e, 0x42, 0x75, 0x72, 0x73, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_app_observatory_burst_config_proto_rawDescOnce sync.Once
|
|
||||||
file_app_observatory_burst_config_proto_rawDescData = file_app_observatory_burst_config_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_app_observatory_burst_config_proto_rawDescGZIP() []byte {
|
|
||||||
file_app_observatory_burst_config_proto_rawDescOnce.Do(func() {
|
|
||||||
file_app_observatory_burst_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_observatory_burst_config_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_app_observatory_burst_config_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_app_observatory_burst_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
|
||||||
var file_app_observatory_burst_config_proto_goTypes = []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,29 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package xray.core.app.observatory.burst;
|
|
||||||
option csharp_namespace = "Xray.App.Observatory.Burst";
|
|
||||||
option go_package = "github.com/xtls/xray-core/app/observatory/burst";
|
|
||||||
option java_package = "com.xray.app.observatory.burst";
|
|
||||||
option java_multiple_files = true;
|
|
||||||
|
|
||||||
message Config {
|
|
||||||
/* @Document The selectors for outbound under observation
|
|
||||||
*/
|
|
||||||
repeated string subject_selector = 2;
|
|
||||||
|
|
||||||
HealthPingConfig ping_config = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message HealthPingConfig {
|
|
||||||
// destination url, need 204 for success return
|
|
||||||
// default https://connectivitycheck.gstatic.com/generate_204
|
|
||||||
string destination = 1;
|
|
||||||
// connectivity check url
|
|
||||||
string connectivity = 2;
|
|
||||||
// health check interval, int64 values of time.Duration
|
|
||||||
int64 interval = 3;
|
|
||||||
// sampling count is the amount of recent ping results which are kept for calculation
|
|
||||||
int32 samplingCount = 4;
|
|
||||||
// ping timeout, int64 values of time.Duration
|
|
||||||
int64 timeout = 5;
|
|
||||||
}
|
|
||||||
@@ -1,254 +0,0 @@
|
|||||||
package burst
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/dice"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HealthPingSettings holds settings for health Checker
|
|
||||||
type HealthPingSettings struct {
|
|
||||||
Destination string `json:"destination"`
|
|
||||||
Connectivity string `json:"connectivity"`
|
|
||||||
Interval time.Duration `json:"interval"`
|
|
||||||
SamplingCount int `json:"sampling"`
|
|
||||||
Timeout time.Duration `json:"timeout"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// HealthPing is the health checker for balancers
|
|
||||||
type HealthPing struct {
|
|
||||||
ctx context.Context
|
|
||||||
access sync.Mutex
|
|
||||||
ticker *time.Ticker
|
|
||||||
tickerClose chan struct{}
|
|
||||||
|
|
||||||
Settings *HealthPingSettings
|
|
||||||
Results map[string]*HealthPingRTTS
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHealthPing creates a new HealthPing with settings
|
|
||||||
func NewHealthPing(ctx context.Context, config *HealthPingConfig) *HealthPing {
|
|
||||||
settings := &HealthPingSettings{}
|
|
||||||
if config != nil {
|
|
||||||
settings = &HealthPingSettings{
|
|
||||||
Connectivity: strings.TrimSpace(config.Connectivity),
|
|
||||||
Destination: strings.TrimSpace(config.Destination),
|
|
||||||
Interval: time.Duration(config.Interval),
|
|
||||||
SamplingCount: int(config.SamplingCount),
|
|
||||||
Timeout: time.Duration(config.Timeout),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if settings.Destination == "" {
|
|
||||||
// Destination URL, need 204 for success return default to chromium
|
|
||||||
// https://github.com/chromium/chromium/blob/main/components/safety_check/url_constants.cc#L10
|
|
||||||
// https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/safety_check/url_constants.cc#10
|
|
||||||
settings.Destination = "https://connectivitycheck.gstatic.com/generate_204"
|
|
||||||
}
|
|
||||||
if settings.Interval == 0 {
|
|
||||||
settings.Interval = time.Duration(1) * time.Minute
|
|
||||||
} else if settings.Interval < 10 {
|
|
||||||
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,
|
|
||||||
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.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()
|
|
||||||
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(); 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,69 +0,0 @@
|
|||||||
package burst
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/tagged"
|
|
||||||
)
|
|
||||||
|
|
||||||
type pingClient struct {
|
|
||||||
destination string
|
|
||||||
httpClient *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPingClient(ctx context.Context, destination string, timeout time.Duration, handler string) *pingClient {
|
|
||||||
return &pingClient{
|
|
||||||
destination: destination,
|
|
||||||
httpClient: newHTTPClient(ctx, handler, timeout),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newDirectPingClient(destination string, timeout time.Duration) *pingClient {
|
|
||||||
return &pingClient{
|
|
||||||
destination: destination,
|
|
||||||
httpClient: &http.Client{Timeout: timeout},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newHTTPClient(ctxv context.Context, handler string, timeout time.Duration) *http.Client {
|
|
||||||
tr := &http.Transport{
|
|
||||||
DisableKeepAlives: true,
|
|
||||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
||||||
dest, err := net.ParseDestination(network + ":" + addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return tagged.Dialer(ctxv, dest, handler)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return &http.Client{
|
|
||||||
Transport: tr,
|
|
||||||
Timeout: timeout,
|
|
||||||
// don't follow redirect
|
|
||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
||||||
return http.ErrUseLastResponse
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MeasureDelay returns the delay time of the request to dest
|
|
||||||
func (s *pingClient) MeasureDelay() (time.Duration, error) {
|
|
||||||
if s.httpClient == nil {
|
|
||||||
panic("pingClient no initialized")
|
|
||||||
}
|
|
||||||
req, err := http.NewRequest(http.MethodHead, s.destination, nil)
|
|
||||||
if err != nil {
|
|
||||||
return rttFailed, err
|
|
||||||
}
|
|
||||||
start := time.Now()
|
|
||||||
resp, err := s.httpClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return rttFailed, err
|
|
||||||
}
|
|
||||||
// don't wait for body
|
|
||||||
resp.Body.Close()
|
|
||||||
return time.Since(start), nil
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/observatory"
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
core "github.com/xtls/xray-core/core"
|
|
||||||
"github.com/xtls/xray-core/features/extension"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
type service struct {
|
|
||||||
UnimplementedObservatoryServiceServer
|
|
||||||
v *core.Instance
|
|
||||||
|
|
||||||
observatory extension.Observatory
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) GetOutboundStatus(ctx context.Context, request *GetOutboundStatusRequest) (*GetOutboundStatusResponse, error) {
|
|
||||||
resp, err := s.observatory.GetObservation(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
retdata := resp.(*observatory.ObservationResult)
|
|
||||||
return &GetOutboundStatusResponse{
|
|
||||||
Status: retdata,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) Register(server *grpc.Server) {
|
|
||||||
RegisterObservatoryServiceServer(server, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
|
|
||||||
s := core.MustFromContext(ctx)
|
|
||||||
sv := &service{v: s}
|
|
||||||
err := s.RequireFeatures(func(Observatory extension.Observatory) {
|
|
||||||
sv.observatory = Observatory
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return sv, nil
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
@@ -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,568 +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/config.proto
|
|
||||||
|
|
||||||
package observatory
|
|
||||||
|
|
||||||
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 ObservationResult struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Status []*OutboundStatus `protobuf:"bytes,1,rep,name=status,proto3" json:"status,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ObservationResult) Reset() {
|
|
||||||
*x = ObservationResult{}
|
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ObservationResult) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*ObservationResult) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *ObservationResult) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_observatory_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 ObservationResult.ProtoReflect.Descriptor instead.
|
|
||||||
func (*ObservationResult) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_observatory_config_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ObservationResult) GetStatus() []*OutboundStatus {
|
|
||||||
if x != nil {
|
|
||||||
return x.Status
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
// @Document Whether this outbound is usable
|
|
||||||
// @Restriction ReadOnlyForUser
|
|
||||||
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
|
|
||||||
// @Document The time for probe request to finish.
|
|
||||||
// @Type time.ms
|
|
||||||
// @Restriction ReadOnlyForUser
|
|
||||||
Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"`
|
|
||||||
// @Document The last error caused this outbound failed to relay probe request
|
|
||||||
// @Restriction NotMachineReadable
|
|
||||||
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
|
|
||||||
// @Type id.outboundTag
|
|
||||||
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
|
|
||||||
// @Type id.outboundTag
|
|
||||||
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
|
|
||||||
// @Type id.outboundTag
|
|
||||||
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() {
|
|
||||||
*x = OutboundStatus{}
|
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[2]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OutboundStatus) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*OutboundStatus) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *OutboundStatus) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_observatory_config_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 OutboundStatus.ProtoReflect.Descriptor instead.
|
|
||||||
func (*OutboundStatus) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_observatory_config_proto_rawDescGZIP(), []int{2}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OutboundStatus) GetAlive() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.Alive
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OutboundStatus) GetDelay() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Delay
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OutboundStatus) GetLastErrorReason() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.LastErrorReason
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OutboundStatus) GetOutboundTag() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.OutboundTag
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OutboundStatus) GetLastSeenTime() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.LastSeenTime
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OutboundStatus) GetLastTryTime() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.LastTryTime
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OutboundStatus) GetHealthPing() *HealthPingMeasurementResult {
|
|
||||||
if x != nil {
|
|
||||||
return x.HealthPing
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProbeResult struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
// @Document Whether this outbound is usable
|
|
||||||
// @Restriction ReadOnlyForUser
|
|
||||||
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
|
|
||||||
// @Document The time for probe request to finish.
|
|
||||||
// @Type time.ms
|
|
||||||
// @Restriction ReadOnlyForUser
|
|
||||||
Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"`
|
|
||||||
// @Document The error caused this outbound failed to relay probe request
|
|
||||||
// @Restriction NotMachineReadable
|
|
||||||
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ProbeResult) Reset() {
|
|
||||||
*x = ProbeResult{}
|
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[3]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ProbeResult) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*ProbeResult) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *ProbeResult) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[3]
|
|
||||||
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 ProbeResult.ProtoReflect.Descriptor instead.
|
|
||||||
func (*ProbeResult) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_observatory_config_proto_rawDescGZIP(), []int{3}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ProbeResult) GetAlive() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.Alive
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ProbeResult) GetDelay() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Delay
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ProbeResult) GetLastErrorReason() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.LastErrorReason
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type Intensity struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
// @Document The time interval for a probe request in ms.
|
|
||||||
// @Type time.ms
|
|
||||||
ProbeInterval uint32 `protobuf:"varint,1,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Intensity) Reset() {
|
|
||||||
*x = Intensity{}
|
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[4]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Intensity) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Intensity) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Intensity) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[4]
|
|
||||||
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 Intensity.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Intensity) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_observatory_config_proto_rawDescGZIP(), []int{4}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Intensity) GetProbeInterval() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.ProbeInterval
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
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"`
|
|
||||||
ProbeUrl string `protobuf:"bytes,3,opt,name=probe_url,json=probeUrl,proto3" json:"probe_url,omitempty"`
|
|
||||||
ProbeInterval int64 `protobuf:"varint,4,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
|
|
||||||
EnableConcurrency bool `protobuf:"varint,5,opt,name=enable_concurrency,json=enableConcurrency,proto3" json:"enable_concurrency,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
|
||||||
*x = Config{}
|
|
||||||
mi := &file_app_observatory_config_proto_msgTypes[5]
|
|
||||||
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_config_proto_msgTypes[5]
|
|
||||||
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_config_proto_rawDescGZIP(), []int{5}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetSubjectSelector() []string {
|
|
||||||
if x != nil {
|
|
||||||
return x.SubjectSelector
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetProbeUrl() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.ProbeUrl
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetProbeInterval() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.ProbeInterval
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetEnableConcurrency() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.EnableConcurrency
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_app_observatory_config_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_app_observatory_config_proto_rawDesc = []byte{
|
|
||||||
0x0a, 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, 0x12, 0x19,
|
|
||||||
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, 0x22, 0x56, 0x0a, 0x11, 0x4f, 0x62, 0x73,
|
|
||||||
0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x41,
|
|
||||||
0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29,
|
|
||||||
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,
|
|
||||||
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,
|
|
||||||
0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c,
|
|
||||||
0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03,
|
|
||||||
0x61, 0x6c, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28,
|
|
||||||
0x03, 0x52, 0x04, 0x66, 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x61,
|
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69,
|
|
||||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65,
|
|
||||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65, 0x12,
|
|
||||||
0x10, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6d, 0x61,
|
|
||||||
0x78, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03,
|
|
||||||
0x6d, 0x69, 0x6e, 0x22, 0xae, 0x02, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,
|
|
||||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18,
|
|
||||||
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05,
|
|
||||||
0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c,
|
|
||||||
0x61, 0x79, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
|
||||||
0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c,
|
|
||||||
0x61, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21,
|
|
||||||
0x0a, 0x0c, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x04,
|
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61,
|
|
||||||
0x67, 0x12, 0x24, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x74,
|
|
||||||
0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53,
|
|
||||||
0x65, 0x65, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x5f,
|
|
||||||
0x74, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b,
|
|
||||||
0x6c, 0x61, 0x73, 0x74, 0x54, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x57, 0x0a, 0x0b, 0x68,
|
|
||||||
0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
|
|
||||||
0x32, 0x36, 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, 0x48, 0x65, 0x61,
|
|
||||||
0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65,
|
|
||||||
0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0a, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68,
|
|
||||||
0x50, 0x69, 0x6e, 0x67, 0x22, 0x65, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x73,
|
|
||||||
0x75, 0x6c, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01,
|
|
||||||
0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c,
|
|
||||||
0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12,
|
|
||||||
0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x72, 0x65,
|
|
||||||
0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c, 0x61, 0x73, 0x74,
|
|
||||||
0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x32, 0x0a, 0x09, 0x49,
|
|
||||||
0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x62,
|
|
||||||
0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
|
|
||||||
0x52, 0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22,
|
|
||||||
0xa6, 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, 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 (
|
|
||||||
file_app_observatory_config_proto_rawDescOnce sync.Once
|
|
||||||
file_app_observatory_config_proto_rawDescData = file_app_observatory_config_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_app_observatory_config_proto_rawDescGZIP() []byte {
|
|
||||||
file_app_observatory_config_proto_rawDescOnce.Do(func() {
|
|
||||||
file_app_observatory_config_proto_rawDescData = protoimpl.X.CompressGZIP(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_goTypes = []any{
|
|
||||||
(*ObservationResult)(nil), // 0: xray.core.app.observatory.ObservationResult
|
|
||||||
(*HealthPingMeasurementResult)(nil), // 1: xray.core.app.observatory.HealthPingMeasurementResult
|
|
||||||
(*OutboundStatus)(nil), // 2: xray.core.app.observatory.OutboundStatus
|
|
||||||
(*ProbeResult)(nil), // 3: xray.core.app.observatory.ProbeResult
|
|
||||||
(*Intensity)(nil), // 4: xray.core.app.observatory.Intensity
|
|
||||||
(*Config)(nil), // 5: xray.core.app.observatory.Config
|
|
||||||
}
|
|
||||||
var file_app_observatory_config_proto_depIdxs = []int32{
|
|
||||||
2, // 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
|
|
||||||
2, // [2:2] is the sub-list for method output_type
|
|
||||||
2, // [2:2] is the sub-list for method input_type
|
|
||||||
2, // [2:2] is the sub-list for extension type_name
|
|
||||||
2, // [2:2] is the sub-list for extension extendee
|
|
||||||
0, // [0:2] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_app_observatory_config_proto_init() }
|
|
||||||
func file_app_observatory_config_proto_init() {
|
|
||||||
if File_app_observatory_config_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_app_observatory_config_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 6,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_app_observatory_config_proto_goTypes,
|
|
||||||
DependencyIndexes: file_app_observatory_config_proto_depIdxs,
|
|
||||||
MessageInfos: file_app_observatory_config_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_app_observatory_config_proto = out.File
|
|
||||||
file_app_observatory_config_proto_rawDesc = nil
|
|
||||||
file_app_observatory_config_proto_goTypes = nil
|
|
||||||
file_app_observatory_config_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package xray.core.app.observatory;
|
|
||||||
option csharp_namespace = "Xray.App.Observatory";
|
|
||||||
option go_package = "github.com/xtls/xray-core/app/observatory";
|
|
||||||
option java_package = "com.xray.app.observatory";
|
|
||||||
option java_multiple_files = true;
|
|
||||||
|
|
||||||
message ObservationResult {
|
|
||||||
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{
|
|
||||||
/* @Document Whether this outbound is usable
|
|
||||||
@Restriction ReadOnlyForUser
|
|
||||||
*/
|
|
||||||
bool alive = 1;
|
|
||||||
/* @Document The time for probe request to finish.
|
|
||||||
@Type time.ms
|
|
||||||
@Restriction ReadOnlyForUser
|
|
||||||
*/
|
|
||||||
int64 delay = 2;
|
|
||||||
/* @Document The last error caused this outbound failed to relay probe request
|
|
||||||
@Restriction NotMachineReadable
|
|
||||||
*/
|
|
||||||
string last_error_reason = 3;
|
|
||||||
/* @Document The outbound tag for this Server
|
|
||||||
@Type id.outboundTag
|
|
||||||
*/
|
|
||||||
string outbound_tag = 4;
|
|
||||||
/* @Document The time this outbound is known to be alive
|
|
||||||
@Type id.outboundTag
|
|
||||||
*/
|
|
||||||
int64 last_seen_time = 5;
|
|
||||||
/* @Document The time this outbound is tried
|
|
||||||
@Type id.outboundTag
|
|
||||||
*/
|
|
||||||
int64 last_try_time = 6;
|
|
||||||
|
|
||||||
HealthPingMeasurementResult health_ping = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ProbeResult{
|
|
||||||
/* @Document Whether this outbound is usable
|
|
||||||
@Restriction ReadOnlyForUser
|
|
||||||
*/
|
|
||||||
bool alive = 1;
|
|
||||||
/* @Document The time for probe request to finish.
|
|
||||||
@Type time.ms
|
|
||||||
@Restriction ReadOnlyForUser
|
|
||||||
*/
|
|
||||||
int64 delay = 2;
|
|
||||||
/* @Document The error caused this outbound failed to relay probe request
|
|
||||||
@Restriction NotMachineReadable
|
|
||||||
*/
|
|
||||||
string last_error_reason = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Intensity{
|
|
||||||
/* @Document The time interval for a probe request in ms.
|
|
||||||
@Type time.ms
|
|
||||||
*/
|
|
||||||
uint32 probe_interval = 1;
|
|
||||||
}
|
|
||||||
message Config {
|
|
||||||
/* @Document The selectors for outbound under observation
|
|
||||||
*/
|
|
||||||
repeated string subject_selector = 2;
|
|
||||||
|
|
||||||
string probe_url = 3;
|
|
||||||
|
|
||||||
int64 probe_interval = 4;
|
|
||||||
|
|
||||||
bool enable_concurrency = 5;
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package observatory
|
|
||||||
|
|
||||||
import "github.com/xtls/xray-core/common/errors"
|
|
||||||
|
|
||||||
type errorCollector struct {
|
|
||||||
errors *errors.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *errorCollector) SubmitError(err error) {
|
|
||||||
if e.errors == nil {
|
|
||||||
e.errors = errors.New("underlying connection error").Base(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
e.errors = e.errors.Base(errors.New("underlying connection error").Base(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
func newErrorCollector() *errorCollector {
|
|
||||||
return &errorCollector{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *errorCollector) UnderlyingError() error {
|
|
||||||
if e.errors == nil {
|
|
||||||
return errors.New("failed to produce report")
|
|
||||||
}
|
|
||||||
return e.errors
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
package observatory
|
|
||||||
@@ -1,235 +0,0 @@
|
|||||||
package observatory
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"sort"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
v2net "github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/common/session"
|
|
||||||
"github.com/xtls/xray-core/common/signal/done"
|
|
||||||
"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/outbound"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/tagged"
|
|
||||||
"google.golang.org/protobuf/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Observer struct {
|
|
||||||
config *Config
|
|
||||||
ctx context.Context
|
|
||||||
|
|
||||||
statusLock sync.Mutex
|
|
||||||
status []*OutboundStatus
|
|
||||||
|
|
||||||
finished *done.Instance
|
|
||||||
|
|
||||||
ohm outbound.Manager
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Observer) GetObservation(ctx context.Context) (proto.Message, error) {
|
|
||||||
return &ObservationResult{Status: o.status}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
go o.background()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Observer) Close() error {
|
|
||||||
if o.finished != nil {
|
|
||||||
return o.finished.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Observer) background() {
|
|
||||||
for !o.finished.Done() {
|
|
||||||
hs, ok := o.ohm.(outbound.HandlerSelector)
|
|
||||||
if !ok {
|
|
||||||
errors.LogInfo(o.ctx, "outbound.Manager is not a HandlerSelector")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
outbounds := hs.Select(o.config.SubjectSelector)
|
|
||||||
|
|
||||||
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 {
|
|
||||||
go func(v string) {
|
|
||||||
result := o.probe(v)
|
|
||||||
o.updateStatusForResult(v, &result)
|
|
||||||
ch <- struct{}{}
|
|
||||||
}(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
for range outbounds {
|
|
||||||
select {
|
|
||||||
case <-ch:
|
|
||||||
case <-o.finished.Wait():
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
time.Sleep(sleepTime)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Observer) updateStatus(outbounds []string) {
|
|
||||||
o.statusLock.Lock()
|
|
||||||
defer o.statusLock.Unlock()
|
|
||||||
// TODO should remove old inbound that is removed
|
|
||||||
_ = outbounds
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Observer) probe(outbound string) ProbeResult {
|
|
||||||
errorCollectorForRequest := newErrorCollector()
|
|
||||||
|
|
||||||
httpTransport := http.Transport{
|
|
||||||
Proxy: func(*http.Request) (*url.URL, error) {
|
|
||||||
return nil, nil
|
|
||||||
},
|
|
||||||
DialContext: func(ctx context.Context, network string, addr string) (net.Conn, error) {
|
|
||||||
var connection net.Conn
|
|
||||||
taskErr := task.Run(ctx, func() error {
|
|
||||||
// MUST use Xray's built in context system
|
|
||||||
dest, err := v2net.ParseDestination(network + ":" + addr)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("cannot understand address").Base(err)
|
|
||||||
}
|
|
||||||
trackedCtx := session.TrackedConnectionError(o.ctx, errorCollectorForRequest)
|
|
||||||
conn, err := tagged.Dialer(trackedCtx, dest, outbound)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("cannot dial remote address ", dest).Base(err)
|
|
||||||
}
|
|
||||||
connection = conn
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if taskErr != nil {
|
|
||||||
return nil, errors.New("cannot finish connection").Base(taskErr)
|
|
||||||
}
|
|
||||||
return connection, nil
|
|
||||||
},
|
|
||||||
TLSHandshakeTimeout: time.Second * 5,
|
|
||||||
}
|
|
||||||
httpClient := &http.Client{
|
|
||||||
Transport: &httpTransport,
|
|
||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
||||||
return http.ErrUseLastResponse
|
|
||||||
},
|
|
||||||
Jar: nil,
|
|
||||||
Timeout: time.Second * 5,
|
|
||||||
}
|
|
||||||
var GETTime time.Duration
|
|
||||||
err := task.Run(o.ctx, func() error {
|
|
||||||
startTime := time.Now()
|
|
||||||
probeURL := "https://www.google.com/generate_204"
|
|
||||||
if o.config.ProbeUrl != "" {
|
|
||||||
probeURL = o.config.ProbeUrl
|
|
||||||
}
|
|
||||||
response, err := httpClient.Get(probeURL)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("outbound failed to relay connection").Base(err)
|
|
||||||
}
|
|
||||||
if response.Body != nil {
|
|
||||||
response.Body.Close()
|
|
||||||
}
|
|
||||||
endTime := time.Now()
|
|
||||||
GETTime = endTime.Sub(startTime)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
var errorMessage = "the outbound " + outbound + " is dead: GET request failed:" + err.Error() + "with outbound handler report underlying connection failed"
|
|
||||||
errors.LogInfoInner(o.ctx, errorCollectorForRequest.UnderlyingError(), errorMessage)
|
|
||||||
return ProbeResult{Alive: false, LastErrorReason: errorMessage}
|
|
||||||
}
|
|
||||||
errors.LogInfo(o.ctx, "the outbound ", outbound, " is alive:", GETTime.Seconds())
|
|
||||||
return ProbeResult{Alive: true, Delay: GETTime.Milliseconds()}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Observer) updateStatusForResult(outbound string, result *ProbeResult) {
|
|
||||||
o.statusLock.Lock()
|
|
||||||
defer o.statusLock.Unlock()
|
|
||||||
var status *OutboundStatus
|
|
||||||
if location := o.findStatusLocationLockHolderOnly(outbound); location != -1 {
|
|
||||||
status = o.status[location]
|
|
||||||
} else {
|
|
||||||
status = &OutboundStatus{}
|
|
||||||
o.status = append(o.status, status)
|
|
||||||
}
|
|
||||||
|
|
||||||
status.LastTryTime = time.Now().Unix()
|
|
||||||
status.OutboundTag = outbound
|
|
||||||
status.Alive = result.Alive
|
|
||||||
if result.Alive {
|
|
||||||
status.Delay = result.Delay
|
|
||||||
status.LastSeenTime = status.LastTryTime
|
|
||||||
status.LastErrorReason = ""
|
|
||||||
} else {
|
|
||||||
status.LastErrorReason = result.LastErrorReason
|
|
||||||
status.Delay = 99999999
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Observer) findStatusLocationLockHolderOnly(outbound string) int {
|
|
||||||
for i, v := range o.status {
|
|
||||||
if v.OutboundTag == outbound {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(ctx context.Context, config *Config) (*Observer, error) {
|
|
||||||
var outboundManager outbound.Manager
|
|
||||||
err := core.RequireFeatures(ctx, func(om outbound.Manager) {
|
|
||||||
outboundManager = om
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("Cannot get depended features").Base(err)
|
|
||||||
}
|
|
||||||
return &Observer{
|
|
||||||
config: config,
|
|
||||||
ctx: ctx,
|
|
||||||
ohm: outboundManager,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
|
||||||
return New(ctx, config.(*Config))
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.25.0
|
||||||
// protoc v5.28.2
|
// protoc v3.14.0
|
||||||
// source: app/policy/config.proto
|
// source: app/policy/config.proto
|
||||||
|
|
||||||
package policy
|
package policy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
@@ -20,6 +21,10 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||||
|
// of the legacy proto package is being used.
|
||||||
|
const _ = proto.ProtoPackageIsVersion4
|
||||||
|
|
||||||
type Second struct {
|
type Second struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -30,9 +35,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 +50,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 +84,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 +99,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 +145,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 +160,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 +193,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 +208,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 +251,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 +266,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)
|
||||||
@@ -305,9 +320,11 @@ type Policy_Stats struct {
|
|||||||
|
|
||||||
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 {
|
||||||
@@ -318,7 +335,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)
|
||||||
@@ -358,9 +375,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 {
|
||||||
@@ -371,7 +390,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)
|
||||||
@@ -406,9 +425,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 {
|
||||||
@@ -419,7 +440,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)
|
||||||
@@ -554,7 +575,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
|
||||||
@@ -589,6 +610,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{
|
||||||
|
|||||||
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,13 +3,13 @@ package command
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"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.
|
||||||
@@ -27,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
|
||||||
}
|
}
|
||||||
@@ -40,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)
|
||||||
}
|
}
|
||||||
@@ -57,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)
|
||||||
}
|
}
|
||||||
@@ -83,16 +83,16 @@ 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)
|
||||||
@@ -112,11 +112,11 @@ 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)
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.25.0
|
||||||
// protoc v5.28.2
|
// protoc v3.14.0
|
||||||
// source: app/proxyman/command/command.proto
|
// source: app/proxyman/command/command.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
protocol "github.com/xtls/xray-core/common/protocol"
|
protocol "github.com/xtls/xray-core/common/protocol"
|
||||||
serial "github.com/xtls/xray-core/common/serial"
|
serial "github.com/xtls/xray-core/common/serial"
|
||||||
core "github.com/xtls/xray-core/core"
|
core "github.com/xtls/xray-core/core"
|
||||||
@@ -23,6 +24,10 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||||
|
// of the legacy proto package is being used.
|
||||||
|
const _ = proto.ProtoPackageIsVersion4
|
||||||
|
|
||||||
type AddUserOperation struct {
|
type AddUserOperation struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -33,9 +38,11 @@ type AddUserOperation struct {
|
|||||||
|
|
||||||
func (x *AddUserOperation) Reset() {
|
func (x *AddUserOperation) Reset() {
|
||||||
*x = AddUserOperation{}
|
*x = AddUserOperation{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[0]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[0]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddUserOperation) String() string {
|
func (x *AddUserOperation) String() string {
|
||||||
@@ -46,7 +53,7 @@ func (*AddUserOperation) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *AddUserOperation) ProtoReflect() protoreflect.Message {
|
func (x *AddUserOperation) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[0]
|
mi := &file_app_proxyman_command_command_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)
|
||||||
@@ -78,9 +85,11 @@ type RemoveUserOperation struct {
|
|||||||
|
|
||||||
func (x *RemoveUserOperation) Reset() {
|
func (x *RemoveUserOperation) Reset() {
|
||||||
*x = RemoveUserOperation{}
|
*x = RemoveUserOperation{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[1]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[1]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveUserOperation) String() string {
|
func (x *RemoveUserOperation) String() string {
|
||||||
@@ -91,7 +100,7 @@ func (*RemoveUserOperation) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *RemoveUserOperation) ProtoReflect() protoreflect.Message {
|
func (x *RemoveUserOperation) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[1]
|
mi := &file_app_proxyman_command_command_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)
|
||||||
@@ -123,9 +132,11 @@ type AddInboundRequest struct {
|
|||||||
|
|
||||||
func (x *AddInboundRequest) Reset() {
|
func (x *AddInboundRequest) Reset() {
|
||||||
*x = AddInboundRequest{}
|
*x = AddInboundRequest{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[2]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[2]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddInboundRequest) String() string {
|
func (x *AddInboundRequest) String() string {
|
||||||
@@ -136,7 +147,7 @@ func (*AddInboundRequest) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *AddInboundRequest) ProtoReflect() protoreflect.Message {
|
func (x *AddInboundRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[2]
|
mi := &file_app_proxyman_command_command_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)
|
||||||
@@ -166,9 +177,11 @@ type AddInboundResponse struct {
|
|||||||
|
|
||||||
func (x *AddInboundResponse) Reset() {
|
func (x *AddInboundResponse) Reset() {
|
||||||
*x = AddInboundResponse{}
|
*x = AddInboundResponse{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[3]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[3]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddInboundResponse) String() string {
|
func (x *AddInboundResponse) String() string {
|
||||||
@@ -179,7 +192,7 @@ func (*AddInboundResponse) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *AddInboundResponse) ProtoReflect() protoreflect.Message {
|
func (x *AddInboundResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[3]
|
mi := &file_app_proxyman_command_command_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)
|
||||||
@@ -204,9 +217,11 @@ type RemoveInboundRequest struct {
|
|||||||
|
|
||||||
func (x *RemoveInboundRequest) Reset() {
|
func (x *RemoveInboundRequest) Reset() {
|
||||||
*x = RemoveInboundRequest{}
|
*x = RemoveInboundRequest{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[4]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[4]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveInboundRequest) String() string {
|
func (x *RemoveInboundRequest) String() string {
|
||||||
@@ -217,7 +232,7 @@ func (*RemoveInboundRequest) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *RemoveInboundRequest) ProtoReflect() protoreflect.Message {
|
func (x *RemoveInboundRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[4]
|
mi := &file_app_proxyman_command_command_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)
|
||||||
@@ -247,9 +262,11 @@ type RemoveInboundResponse struct {
|
|||||||
|
|
||||||
func (x *RemoveInboundResponse) Reset() {
|
func (x *RemoveInboundResponse) Reset() {
|
||||||
*x = RemoveInboundResponse{}
|
*x = RemoveInboundResponse{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[5]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[5]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveInboundResponse) String() string {
|
func (x *RemoveInboundResponse) String() string {
|
||||||
@@ -260,7 +277,7 @@ func (*RemoveInboundResponse) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *RemoveInboundResponse) ProtoReflect() protoreflect.Message {
|
func (x *RemoveInboundResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[5]
|
mi := &file_app_proxyman_command_command_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)
|
||||||
@@ -286,9 +303,11 @@ type AlterInboundRequest struct {
|
|||||||
|
|
||||||
func (x *AlterInboundRequest) Reset() {
|
func (x *AlterInboundRequest) Reset() {
|
||||||
*x = AlterInboundRequest{}
|
*x = AlterInboundRequest{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[6]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[6]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AlterInboundRequest) String() string {
|
func (x *AlterInboundRequest) String() string {
|
||||||
@@ -299,7 +318,7 @@ func (*AlterInboundRequest) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *AlterInboundRequest) ProtoReflect() protoreflect.Message {
|
func (x *AlterInboundRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[6]
|
mi := &file_app_proxyman_command_command_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)
|
||||||
@@ -336,9 +355,11 @@ type AlterInboundResponse struct {
|
|||||||
|
|
||||||
func (x *AlterInboundResponse) Reset() {
|
func (x *AlterInboundResponse) Reset() {
|
||||||
*x = AlterInboundResponse{}
|
*x = AlterInboundResponse{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[7]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[7]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AlterInboundResponse) String() string {
|
func (x *AlterInboundResponse) String() string {
|
||||||
@@ -349,7 +370,7 @@ func (*AlterInboundResponse) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *AlterInboundResponse) ProtoReflect() protoreflect.Message {
|
func (x *AlterInboundResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[7]
|
mi := &file_app_proxyman_command_command_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)
|
||||||
@@ -374,9 +395,11 @@ type AddOutboundRequest struct {
|
|||||||
|
|
||||||
func (x *AddOutboundRequest) Reset() {
|
func (x *AddOutboundRequest) Reset() {
|
||||||
*x = AddOutboundRequest{}
|
*x = AddOutboundRequest{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddOutboundRequest) String() string {
|
func (x *AddOutboundRequest) String() string {
|
||||||
@@ -387,7 +410,7 @@ func (*AddOutboundRequest) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *AddOutboundRequest) ProtoReflect() protoreflect.Message {
|
func (x *AddOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
mi := &file_app_proxyman_command_command_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)
|
||||||
@@ -417,9 +440,11 @@ type AddOutboundResponse struct {
|
|||||||
|
|
||||||
func (x *AddOutboundResponse) Reset() {
|
func (x *AddOutboundResponse) Reset() {
|
||||||
*x = AddOutboundResponse{}
|
*x = AddOutboundResponse{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddOutboundResponse) String() string {
|
func (x *AddOutboundResponse) String() string {
|
||||||
@@ -430,7 +455,7 @@ func (*AddOutboundResponse) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *AddOutboundResponse) ProtoReflect() protoreflect.Message {
|
func (x *AddOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
mi := &file_app_proxyman_command_command_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)
|
||||||
@@ -455,9 +480,11 @@ type RemoveOutboundRequest struct {
|
|||||||
|
|
||||||
func (x *RemoveOutboundRequest) Reset() {
|
func (x *RemoveOutboundRequest) Reset() {
|
||||||
*x = RemoveOutboundRequest{}
|
*x = RemoveOutboundRequest{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveOutboundRequest) String() string {
|
func (x *RemoveOutboundRequest) String() string {
|
||||||
@@ -468,7 +495,7 @@ func (*RemoveOutboundRequest) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *RemoveOutboundRequest) ProtoReflect() protoreflect.Message {
|
func (x *RemoveOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
||||||
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)
|
||||||
@@ -498,9 +525,11 @@ type RemoveOutboundResponse struct {
|
|||||||
|
|
||||||
func (x *RemoveOutboundResponse) Reset() {
|
func (x *RemoveOutboundResponse) Reset() {
|
||||||
*x = RemoveOutboundResponse{}
|
*x = RemoveOutboundResponse{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveOutboundResponse) String() string {
|
func (x *RemoveOutboundResponse) String() string {
|
||||||
@@ -511,7 +540,7 @@ func (*RemoveOutboundResponse) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *RemoveOutboundResponse) ProtoReflect() protoreflect.Message {
|
func (x *RemoveOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
||||||
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)
|
||||||
@@ -537,9 +566,11 @@ type AlterOutboundRequest struct {
|
|||||||
|
|
||||||
func (x *AlterOutboundRequest) Reset() {
|
func (x *AlterOutboundRequest) Reset() {
|
||||||
*x = AlterOutboundRequest{}
|
*x = AlterOutboundRequest{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AlterOutboundRequest) String() string {
|
func (x *AlterOutboundRequest) String() string {
|
||||||
@@ -550,7 +581,7 @@ func (*AlterOutboundRequest) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *AlterOutboundRequest) ProtoReflect() protoreflect.Message {
|
func (x *AlterOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
||||||
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)
|
||||||
@@ -587,9 +618,11 @@ type AlterOutboundResponse struct {
|
|||||||
|
|
||||||
func (x *AlterOutboundResponse) Reset() {
|
func (x *AlterOutboundResponse) Reset() {
|
||||||
*x = AlterOutboundResponse{}
|
*x = AlterOutboundResponse{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AlterOutboundResponse) String() string {
|
func (x *AlterOutboundResponse) String() string {
|
||||||
@@ -600,7 +633,7 @@ func (*AlterOutboundResponse) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *AlterOutboundResponse) ProtoReflect() protoreflect.Message {
|
func (x *AlterOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
||||||
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)
|
||||||
@@ -623,9 +656,11 @@ type Config struct {
|
|||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
if protoimpl.UnsafeEnabled {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
||||||
ms.StoreMessageInfo(mi)
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) String() string {
|
func (x *Config) String() string {
|
||||||
@@ -636,7 +671,7 @@ func (*Config) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
||||||
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)
|
||||||
@@ -776,7 +811,7 @@ func file_app_proxyman_command_command_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_app_proxyman_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
|
var file_app_proxyman_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
|
||||||
var file_app_proxyman_command_command_proto_goTypes = []any{
|
var file_app_proxyman_command_command_proto_goTypes = []interface{}{
|
||||||
(*AddUserOperation)(nil), // 0: xray.app.proxyman.command.AddUserOperation
|
(*AddUserOperation)(nil), // 0: xray.app.proxyman.command.AddUserOperation
|
||||||
(*RemoveUserOperation)(nil), // 1: xray.app.proxyman.command.RemoveUserOperation
|
(*RemoveUserOperation)(nil), // 1: xray.app.proxyman.command.RemoveUserOperation
|
||||||
(*AddInboundRequest)(nil), // 2: xray.app.proxyman.command.AddInboundRequest
|
(*AddInboundRequest)(nil), // 2: xray.app.proxyman.command.AddInboundRequest
|
||||||
@@ -827,6 +862,188 @@ func file_app_proxyman_command_command_proto_init() {
|
|||||||
if File_app_proxyman_command_command_proto != nil {
|
if File_app_proxyman_command_command_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*AddUserOperation); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*RemoveUserOperation); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*AddInboundRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*AddInboundResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*RemoveInboundRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*RemoveInboundResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*AlterInboundRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*AlterInboundResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*AddOutboundRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*AddOutboundResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*RemoveOutboundRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*RemoveOutboundResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*AlterOutboundRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*AlterOutboundResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_app_proxyman_command_command_proto_msgTypes[14].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,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,17 +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_AddOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AddOutbound"
|
|
||||||
HandlerService_RemoveOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/RemoveOutbound"
|
|
||||||
HandlerService_AlterOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AlterOutbound"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HandlerServiceClient is the client API for HandlerService service.
|
// HandlerServiceClient is the client API for HandlerService service.
|
||||||
//
|
//
|
||||||
@@ -48,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
|
||||||
}
|
}
|
||||||
@@ -58,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
|
||||||
}
|
}
|
||||||
@@ -68,9 +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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -78,9 +62,8 @@ func (c *handlerServiceClient) AlterInbound(ctx context.Context, in *AlterInboun
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *handlerServiceClient) AddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error) {
|
func (c *handlerServiceClient) AddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error) {
|
||||||
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
|
||||||
}
|
}
|
||||||
@@ -88,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
|
||||||
}
|
}
|
||||||
@@ -98,9 +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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -109,7 +90,7 @@ func (c *handlerServiceClient) AlterOutbound(ctx context.Context, in *AlterOutbo
|
|||||||
|
|
||||||
// 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)
|
||||||
@@ -120,12 +101,9 @@ type HandlerServiceServer interface {
|
|||||||
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")
|
||||||
@@ -146,7 +124,6 @@ func (UnimplementedHandlerServiceServer) AlterOutbound(context.Context, *AlterOu
|
|||||||
return nil, status.Errorf(codes.Unimplemented, "method AlterOutbound not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method AlterOutbound 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
|
||||||
@@ -156,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,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))
|
||||||
@@ -194,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))
|
||||||
@@ -212,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))
|
||||||
@@ -230,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))
|
||||||
@@ -248,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))
|
||||||
@@ -266,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))
|
||||||
|
|||||||
@@ -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,12 +1,13 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.25.0
|
||||||
// protoc v5.28.2
|
// protoc (unknown)
|
||||||
// source: app/proxyman/config.proto
|
// source: app/proxyman/config.proto
|
||||||
|
|
||||||
package proxyman
|
package proxyman
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
net "github.com/xtls/xray-core/common/net"
|
net "github.com/xtls/xray-core/common/net"
|
||||||
serial "github.com/xtls/xray-core/common/serial"
|
serial "github.com/xtls/xray-core/common/serial"
|
||||||
internet "github.com/xtls/xray-core/transport/internet"
|
internet "github.com/xtls/xray-core/transport/internet"
|
||||||
@@ -23,6 +24,56 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||||
|
// of the legacy proto package is being used.
|
||||||
|
const _ = proto.ProtoPackageIsVersion4
|
||||||
|
|
||||||
|
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 AllocationStrategy_Type int32
|
type AllocationStrategy_Type int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -59,11 +110,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[1].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[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x AllocationStrategy_Type) Number() protoreflect.EnumNumber {
|
func (x AllocationStrategy_Type) Number() protoreflect.EnumNumber {
|
||||||
@@ -83,9 +134,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 +149,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 +180,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 +195,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 +243,17 @@ 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"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 +264,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)
|
||||||
@@ -252,33 +307,33 @@ func (x *SniffingConfig) GetMetadataOnly() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SniffingConfig) GetRouteOnly() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.RouteOnly
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReceiverConfig struct {
|
type ReceiverConfig struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
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 +344,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 +359,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 +394,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 +421,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 +436,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 +480,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 +495,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)
|
||||||
@@ -453,14 +520,15 @@ type SenderConfig struct {
|
|||||||
StreamSettings *internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
StreamSettings *internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
||||||
ProxySettings *internet.ProxyConfig `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"`
|
ProxySettings *internet.ProxyConfig `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"`
|
||||||
MultiplexSettings *MultiplexingConfig `protobuf:"bytes,4,opt,name=multiplex_settings,json=multiplexSettings,proto3" json:"multiplex_settings,omitempty"`
|
MultiplexSettings *MultiplexingConfig `protobuf:"bytes,4,opt,name=multiplex_settings,json=multiplexSettings,proto3" json:"multiplex_settings,omitempty"`
|
||||||
ViaCidr string `protobuf:"bytes,5,opt,name=via_cidr,json=viaCidr,proto3" json:"via_cidr,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
@@ -471,7 +539,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)
|
||||||
@@ -514,13 +582,6 @@ func (x *SenderConfig) GetMultiplexSettings() *MultiplexingConfig {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SenderConfig) GetViaCidr() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.ViaCidr
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type MultiplexingConfig struct {
|
type MultiplexingConfig struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -529,18 +590,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 {
|
||||||
@@ -551,7 +610,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)
|
||||||
@@ -573,27 +632,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
|
||||||
@@ -604,9 +649,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 {
|
||||||
@@ -617,7 +664,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)
|
||||||
@@ -649,9 +696,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 {
|
||||||
@@ -662,7 +711,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)
|
||||||
@@ -725,7 +774,7 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
|
|||||||
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12,
|
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12,
|
||||||
0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52,
|
0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52,
|
||||||
0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72,
|
0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72,
|
||||||
0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0xcc, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69,
|
0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0xad, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69,
|
||||||
0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62,
|
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,
|
0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c,
|
||||||
0x65, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
|
0x65, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
|
||||||
@@ -736,87 +785,86 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
|
|||||||
0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64,
|
0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64,
|
||||||
0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6f, 0x6e, 0x6c,
|
0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6f, 0x6e, 0x6c,
|
||||||
0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
|
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, 0x22, 0x90, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76,
|
||||||
0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74,
|
||||||
0x4f, 0x6e, 0x6c, 0x79, 0x22, 0xbd, 0x03, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
|
0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78,
|
||||||
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f,
|
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50,
|
||||||
0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61,
|
0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61,
|
||||||
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72,
|
0x6e, 0x67, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20,
|
||||||
0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12,
|
0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
|
||||||
0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||||
0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
|
0x52, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f,
|
||||||
0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69,
|
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18,
|
||||||
0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28,
|
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61,
|
||||||
0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f,
|
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c,
|
||||||
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||||
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61,
|
0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4e, 0x0a, 0x0f,
|
0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
|
0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72,
|
||||||
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
|
0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
|
0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
||||||
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74,
|
0x12, 0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67,
|
||||||
0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x1c,
|
0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||||
0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
|
0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f,
|
||||||
0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01,
|
0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69,
|
||||||
0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69,
|
0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65,
|
||||||
0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e,
|
0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72,
|
||||||
0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
|
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e,
|
||||||
0x6e, 0x67, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x42, 0x02,
|
||||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e,
|
0x18, 0x01, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
||||||
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e,
|
0x64, 0x65, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73,
|
||||||
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04,
|
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e,
|
||||||
0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
|
||||||
0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a,
|
0x6e, 0x2e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12,
|
0x52, 0x10, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
||||||
0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74,
|
0x67, 0x73, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62,
|
||||||
0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61,
|
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,
|
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,
|
0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72,
|
||||||
0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47,
|
0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f,
|
||||||
0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xb0, 0x02,
|
||||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d,
|
||||||
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65,
|
0x0a, 0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72,
|
||||||
0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53,
|
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50,
|
||||||
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f,
|
0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a,
|
||||||
0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xcb, 0x02, 0x0a, 0x0c, 0x53, 0x65,
|
0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
||||||
0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x03, 0x76, 0x69,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72,
|
||||||
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
|
||||||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f,
|
0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73,
|
||||||
0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72,
|
0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a,
|
||||||
0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01,
|
0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
|
||||||
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
|
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
|
||||||
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72,
|
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
|
||||||
0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61,
|
0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f,
|
||||||
0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e, 0x70, 0x72, 0x6f,
|
0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75,
|
||||||
0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
|
0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
||||||
0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
|
0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||||
0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78,
|
0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69,
|
||||||
0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65,
|
0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d,
|
||||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70,
|
0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
||||||
0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01,
|
0x22, 0x50, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67,
|
||||||
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
|
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
|
||||||
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78,
|
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
|
||||||
0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69,
|
0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18,
|
||||||
0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08,
|
0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
|
||||||
0x76, 0x69, 0x61, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
0x63, 0x79, 0x2a, 0x23, 0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x76, 0x69, 0x61, 0x43, 0x69, 0x64, 0x72, 0x22, 0xa4, 0x01, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74,
|
0x63, 0x6f, 0x6c, 0x73, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07,
|
||||||
0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18,
|
0x0a, 0x03, 0x54, 0x4c, 0x53, 0x10, 0x01, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
|
||||||
0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e,
|
||||||
0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63,
|
0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
|
||||||
0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x63,
|
0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
|
||||||
0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75,
|
0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61,
|
||||||
0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x03, 0x20,
|
0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06,
|
||||||
0x01, 0x28, 0x05, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72,
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
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 (
|
||||||
@@ -831,46 +879,48 @@ 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, 2)
|
||||||
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
|
(AllocationStrategy_Type)(0), // 1: xray.app.proxyman.AllocationStrategy.Type
|
||||||
(*AllocationStrategy)(nil), // 2: xray.app.proxyman.AllocationStrategy
|
(*InboundConfig)(nil), // 2: xray.app.proxyman.InboundConfig
|
||||||
(*SniffingConfig)(nil), // 3: xray.app.proxyman.SniffingConfig
|
(*AllocationStrategy)(nil), // 3: xray.app.proxyman.AllocationStrategy
|
||||||
(*ReceiverConfig)(nil), // 4: xray.app.proxyman.ReceiverConfig
|
(*SniffingConfig)(nil), // 4: xray.app.proxyman.SniffingConfig
|
||||||
(*InboundHandlerConfig)(nil), // 5: xray.app.proxyman.InboundHandlerConfig
|
(*ReceiverConfig)(nil), // 5: xray.app.proxyman.ReceiverConfig
|
||||||
(*OutboundConfig)(nil), // 6: xray.app.proxyman.OutboundConfig
|
(*InboundHandlerConfig)(nil), // 6: xray.app.proxyman.InboundHandlerConfig
|
||||||
(*SenderConfig)(nil), // 7: xray.app.proxyman.SenderConfig
|
(*OutboundConfig)(nil), // 7: xray.app.proxyman.OutboundConfig
|
||||||
(*MultiplexingConfig)(nil), // 8: xray.app.proxyman.MultiplexingConfig
|
(*SenderConfig)(nil), // 8: xray.app.proxyman.SenderConfig
|
||||||
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 9: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
|
(*MultiplexingConfig)(nil), // 9: xray.app.proxyman.MultiplexingConfig
|
||||||
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
|
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
|
||||||
(*net.PortList)(nil), // 11: xray.common.net.PortList
|
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 11: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
|
||||||
(*net.IPOrDomain)(nil), // 12: xray.common.net.IPOrDomain
|
(*net.PortRange)(nil), // 12: xray.common.net.PortRange
|
||||||
(*internet.StreamConfig)(nil), // 13: xray.transport.internet.StreamConfig
|
(*net.IPOrDomain)(nil), // 13: xray.common.net.IPOrDomain
|
||||||
(*serial.TypedMessage)(nil), // 14: xray.common.serial.TypedMessage
|
(*internet.StreamConfig)(nil), // 14: xray.transport.internet.StreamConfig
|
||||||
(*internet.ProxyConfig)(nil), // 15: xray.transport.internet.ProxyConfig
|
(*serial.TypedMessage)(nil), // 15: xray.common.serial.TypedMessage
|
||||||
|
(*internet.ProxyConfig)(nil), // 16: 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
|
1, // 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
|
10, // 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
|
11, // 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
|
12, // 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
|
13, // 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
|
3, // 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
|
14, // 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
|
4, // 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
|
15, // 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
|
15, // 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
|
13, // 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
|
14, // 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
|
16, // 13: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
|
||||||
14, // [14:14] is the sub-list for method output_type
|
9, // 14: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
||||||
14, // [14:14] is the sub-list for method input_type
|
15, // [15:15] is the sub-list for method output_type
|
||||||
14, // [14:14] is the sub-list for extension type_name
|
15, // [15:15] is the sub-list for method input_type
|
||||||
14, // [14:14] is the sub-list for extension extendee
|
15, // [15:15] is the sub-list for extension type_name
|
||||||
0, // [0:14] is the sub-list for field type_name
|
15, // [15:15] is the sub-list for extension extendee
|
||||||
|
0, // [0:15] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_proxyman_config_proto_init() }
|
func init() { file_app_proxyman_config_proto_init() }
|
||||||
@@ -878,12 +928,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: 2,
|
||||||
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;
|
||||||
@@ -48,25 +57,25 @@ message SniffingConfig {
|
|||||||
// Supported values are "http", "tls", "fakedns".
|
// Supported values are "http", "tls", "fakedns".
|
||||||
repeated string destination_override = 2;
|
repeated string destination_override = 2;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
@@ -83,16 +92,11 @@ message SenderConfig {
|
|||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
}
|
}
|
||||||
p, ok := rawProxy.(proxy.Inbound)
|
p, ok := rawProxy.(proxy.Inbound)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an inbound proxy.")
|
return nil, newError("not an inbound proxy.")
|
||||||
}
|
}
|
||||||
|
|
||||||
h := &AlwaysOnInboundHandler{
|
h := &AlwaysOnInboundHandler{
|
||||||
@@ -67,7 +67,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
uplinkCounter, downlinkCounter := getStatCounter(core.MustFromContext(ctx), tag)
|
uplinkCounter, downlinkCounter := getStatCounter(core.MustFromContext(ctx), tag)
|
||||||
|
|
||||||
nl := p.Network()
|
nl := p.Network()
|
||||||
pl := receiverConfig.PortList
|
pr := receiverConfig.PortRange
|
||||||
address := receiverConfig.Listen.AsAddress()
|
address := receiverConfig.Listen.AsAddress()
|
||||||
if address == nil {
|
if address == nil {
|
||||||
address = net.AnyIP
|
address = net.AnyIP
|
||||||
@@ -75,7 +75,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
|
|
||||||
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to parse stream config").Base(err).AtWarning()
|
return nil, newError("failed to parse stream config").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
if receiverConfig.ReceiveOriginalDestination {
|
if receiverConfig.ReceiveOriginalDestination {
|
||||||
@@ -87,9 +87,9 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
}
|
}
|
||||||
mss.SocketSettings.ReceiveOriginalDestAddress = true
|
mss.SocketSettings.ReceiveOriginalDestAddress = true
|
||||||
}
|
}
|
||||||
if pl == nil {
|
if pr == nil {
|
||||||
if net.HasNetwork(nl, net.Network_UNIX) {
|
if net.HasNetwork(nl, net.Network_UNIX) {
|
||||||
errors.LogDebug(ctx, "creating unix domain socket worker on ", address)
|
newError("creating unix domain socket worker on ", address).AtDebug().WriteToLog()
|
||||||
|
|
||||||
worker := &dsWorker{
|
worker := &dsWorker{
|
||||||
address: address,
|
address: address,
|
||||||
@@ -105,43 +105,41 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
h.workers = append(h.workers, worker)
|
h.workers = append(h.workers, worker)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pl != nil {
|
if pr != nil {
|
||||||
for _, pr := range pl.Range {
|
for port := pr.From; port <= pr.To; port++ {
|
||||||
for port := pr.From; port <= pr.To; port++ {
|
if net.HasNetwork(nl, net.Network_TCP) {
|
||||||
if net.HasNetwork(nl, net.Network_TCP) {
|
newError("creating stream worker on ", address, ":", port).AtDebug().WriteToLog()
|
||||||
errors.LogDebug(ctx, "creating stream worker on ", address, ":", port)
|
|
||||||
|
|
||||||
worker := &tcpWorker{
|
worker := &tcpWorker{
|
||||||
address: address,
|
address: address,
|
||||||
port: net.Port(port),
|
port: net.Port(port),
|
||||||
proxy: p,
|
proxy: p,
|
||||||
stream: mss,
|
stream: mss,
|
||||||
recvOrigDest: receiverConfig.ReceiveOriginalDestination,
|
recvOrigDest: receiverConfig.ReceiveOriginalDestination,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
dispatcher: h.mux,
|
dispatcher: h.mux,
|
||||||
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
|
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
uplinkCounter: uplinkCounter,
|
uplinkCounter: uplinkCounter,
|
||||||
downlinkCounter: downlinkCounter,
|
downlinkCounter: downlinkCounter,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
}
|
|
||||||
h.workers = append(h.workers, worker)
|
|
||||||
}
|
}
|
||||||
|
h.workers = append(h.workers, worker)
|
||||||
|
}
|
||||||
|
|
||||||
if net.HasNetwork(nl, net.Network_UDP) {
|
if net.HasNetwork(nl, net.Network_UDP) {
|
||||||
worker := &udpWorker{
|
worker := &udpWorker{
|
||||||
tag: tag,
|
tag: tag,
|
||||||
proxy: p,
|
proxy: p,
|
||||||
address: address,
|
address: address,
|
||||||
port: net.Port(port),
|
port: net.Port(port),
|
||||||
dispatcher: h.mux,
|
dispatcher: h.mux,
|
||||||
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
|
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
uplinkCounter: uplinkCounter,
|
uplinkCounter: uplinkCounter,
|
||||||
downlinkCounter: downlinkCounter,
|
downlinkCounter: downlinkCounter,
|
||||||
stream: mss,
|
stream: mss,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
}
|
|
||||||
h.workers = append(h.workers, worker)
|
|
||||||
}
|
}
|
||||||
|
h.workers = append(h.workers, worker)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,7 +165,7 @@ func (h *AlwaysOnInboundHandler) Close() error {
|
|||||||
}
|
}
|
||||||
errs = append(errs, h.mux.Close())
|
errs = append(errs, h.mux.Close())
|
||||||
if err := errors.Combine(errs...); err != nil {
|
if err := errors.Combine(errs...); err != nil {
|
||||||
return errors.New("failed to close all resources").Base(err)
|
return newError("failed to close all resources").Base(err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
"github.com/xtls/xray-core/app/proxyman"
|
"github.com/xtls/xray-core/app/proxyman"
|
||||||
"github.com/xtls/xray-core/common/dice"
|
"github.com/xtls/xray-core/common/dice"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/mux"
|
"github.com/xtls/xray-core/common/mux"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/task"
|
"github.com/xtls/xray-core/common/task"
|
||||||
@@ -47,7 +46,7 @@ func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *p
|
|||||||
|
|
||||||
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to parse stream settings").Base(err).AtWarning()
|
return nil, newError("failed to parse stream settings").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
if receiverConfig.ReceiveOriginalDestination {
|
if receiverConfig.ReceiveOriginalDestination {
|
||||||
if mss.SocketSettings == nil {
|
if mss.SocketSettings == nil {
|
||||||
@@ -70,18 +69,15 @@ func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *p
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *DynamicInboundHandler) allocatePort() net.Port {
|
func (h *DynamicInboundHandler) allocatePort() net.Port {
|
||||||
allPorts := []int32{}
|
from := int(h.receiverConfig.PortRange.From)
|
||||||
for _, pr := range h.receiverConfig.PortList.Range {
|
delta := int(h.receiverConfig.PortRange.To) - from + 1
|
||||||
for i := pr.From; i <= pr.To; i++ {
|
|
||||||
allPorts = append(allPorts, int32(i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h.portMutex.Lock()
|
h.portMutex.Lock()
|
||||||
defer h.portMutex.Unlock()
|
defer h.portMutex.Unlock()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
r := dice.Roll(len(allPorts))
|
r := dice.Roll(delta)
|
||||||
port := net.Port(allPorts[r])
|
port := net.Port(from + r)
|
||||||
_, used := h.portsInUse[port]
|
_, used := h.portsInUse[port]
|
||||||
if !used {
|
if !used {
|
||||||
h.portsInUse[port] = true
|
h.portsInUse[port] = true
|
||||||
@@ -95,7 +91,7 @@ func (h *DynamicInboundHandler) closeWorkers(workers []worker) {
|
|||||||
for idx, worker := range workers {
|
for idx, worker := range workers {
|
||||||
ports2Del[idx] = worker.Port()
|
ports2Del[idx] = worker.Port()
|
||||||
if err := worker.Close(); err != nil {
|
if err := worker.Close(); err != nil {
|
||||||
errors.LogInfoInner(h.ctx, err, "failed to close worker")
|
newError("failed to close worker").Base(err).WriteToLog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +120,7 @@ func (h *DynamicInboundHandler) refresh() error {
|
|||||||
port := h.allocatePort()
|
port := h.allocatePort()
|
||||||
rawProxy, err := core.CreateObject(h.v, h.proxyConfig)
|
rawProxy, err := core.CreateObject(h.v, h.proxyConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogWarningInner(h.ctx, err, "failed to create proxy instance")
|
newError("failed to create proxy instance").Base(err).AtWarning().WriteToLog()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p := rawProxy.(proxy.Inbound)
|
p := rawProxy.(proxy.Inbound)
|
||||||
@@ -144,7 +140,7 @@ func (h *DynamicInboundHandler) refresh() error {
|
|||||||
ctx: h.ctx,
|
ctx: h.ctx,
|
||||||
}
|
}
|
||||||
if err := worker.Start(); err != nil {
|
if err := worker.Start(); err != nil {
|
||||||
errors.LogWarningInner(h.ctx, err, "failed to create TCP worker")
|
newError("failed to create TCP worker").Base(err).AtWarning().WriteToLog()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
workers = append(workers, worker)
|
workers = append(workers, worker)
|
||||||
@@ -164,7 +160,7 @@ func (h *DynamicInboundHandler) refresh() error {
|
|||||||
ctx: h.ctx,
|
ctx: h.ctx,
|
||||||
}
|
}
|
||||||
if err := worker.Start(); err != nil {
|
if err := worker.Start(); err != nil {
|
||||||
errors.LogWarningInner(h.ctx, err, "failed to create UDP worker")
|
newError("failed to create UDP worker").Base(err).AtWarning().WriteToLog()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
workers = append(workers, worker)
|
workers = append(workers, worker)
|
||||||
|
|||||||
9
app/proxyman/inbound/errors.generated.go
Normal file
9
app/proxyman/inbound/errors.generated.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package inbound
|
||||||
|
|
||||||
|
import "github.com/xtls/xray-core/common/errors"
|
||||||
|
|
||||||
|
type errPathObjHolder struct{}
|
||||||
|
|
||||||
|
func newError(values ...interface{}) *errors.Error {
|
||||||
|
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||||
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
package inbound
|
package inbound
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/proxyman"
|
"github.com/xtls/xray-core/app/proxyman"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
@@ -42,7 +43,7 @@ func (m *Manager) AddHandler(ctx context.Context, handler inbound.Handler) error
|
|||||||
tag := handler.Tag()
|
tag := handler.Tag()
|
||||||
if len(tag) > 0 {
|
if len(tag) > 0 {
|
||||||
if _, found := m.taggedHandlers[tag]; found {
|
if _, found := m.taggedHandlers[tag]; found {
|
||||||
return errors.New("existing tag found: " + tag)
|
return newError("existing tag found: " + tag)
|
||||||
}
|
}
|
||||||
m.taggedHandlers[tag] = handler
|
m.taggedHandlers[tag] = handler
|
||||||
} else {
|
} else {
|
||||||
@@ -63,7 +64,7 @@ func (m *Manager) GetHandler(ctx context.Context, tag string) (inbound.Handler,
|
|||||||
|
|
||||||
handler, found := m.taggedHandlers[tag]
|
handler, found := m.taggedHandlers[tag]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, errors.New("handler not found: ", tag)
|
return nil, newError("handler not found: ", tag)
|
||||||
}
|
}
|
||||||
return handler, nil
|
return handler, nil
|
||||||
}
|
}
|
||||||
@@ -79,7 +80,7 @@ func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
|
|||||||
|
|
||||||
if handler, found := m.taggedHandlers[tag]; found {
|
if handler, found := m.taggedHandlers[tag]; found {
|
||||||
if err := handler.Close(); err != nil {
|
if err := handler.Close(); err != nil {
|
||||||
errors.LogWarningInner(ctx, err, "failed to close handler ", tag)
|
newError("failed to close handler ", tag).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))
|
||||||
}
|
}
|
||||||
delete(m.taggedHandlers, tag)
|
delete(m.taggedHandlers, tag)
|
||||||
return nil
|
return nil
|
||||||
@@ -116,20 +117,20 @@ func (m *Manager) Close() error {
|
|||||||
|
|
||||||
m.running = false
|
m.running = false
|
||||||
|
|
||||||
var errs []interface{}
|
var errors []interface{}
|
||||||
for _, handler := range m.taggedHandlers {
|
for _, handler := range m.taggedHandlers {
|
||||||
if err := handler.Close(); err != nil {
|
if err := handler.Close(); err != nil {
|
||||||
errs = append(errs, err)
|
errors = append(errors, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, handler := range m.untaggedHandler {
|
for _, handler := range m.untaggedHandler {
|
||||||
if err := handler.Close(); err != nil {
|
if err := handler.Close(); err != nil {
|
||||||
errs = append(errs, err)
|
errors = append(errors, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(errs) > 0 {
|
if len(errors) > 0 {
|
||||||
return errors.New("failed to close all handlers").Base(errors.New(serial.Concat(errs...)))
|
return newError("failed to close all handlers").Base(newError(serial.Concat(errors...)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -149,7 +150,7 @@ func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound
|
|||||||
|
|
||||||
receiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig)
|
receiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not a ReceiverConfig").AtError()
|
return nil, newError("not a ReceiverConfig").AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
streamSettings := receiverSettings.StreamSettings
|
streamSettings := receiverSettings.StreamSettings
|
||||||
@@ -167,7 +168,7 @@ func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound
|
|||||||
if allocStrategy.Type == proxyman.AllocationStrategy_Random {
|
if allocStrategy.Type == proxyman.AllocationStrategy_Random {
|
||||||
return NewDynamicInboundHandler(ctx, tag, receiverSettings, proxySettings)
|
return NewDynamicInboundHandler(ctx, tag, receiverSettings, proxySettings)
|
||||||
}
|
}
|
||||||
return nil, errors.New("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).AtError()
|
return nil, newError("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/app/proxyman"
|
"github.com/xtls/xray-core/app/proxyman"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
c "github.com/xtls/xray-core/common/ctx"
|
|
||||||
"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/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
@@ -20,7 +18,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/features/stats"
|
"github.com/xtls/xray-core/features/stats"
|
||||||
"github.com/xtls/xray-core/proxy"
|
"github.com/xtls/xray-core/proxy"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/tcp"
|
"github.com/xtls/xray-core/transport/internet/tcp"
|
||||||
"github.com/xtls/xray-core/transport/internet/udp"
|
"github.com/xtls/xray-core/transport/internet/udp"
|
||||||
"github.com/xtls/xray-core/transport/pipe"
|
"github.com/xtls/xray-core/transport/pipe"
|
||||||
@@ -57,19 +54,18 @@ func getTProxyType(s *internet.MemoryStreamConfig) internet.SocketConfig_TProxyM
|
|||||||
return s.SocketSettings.Tproxy
|
return s.SocketSettings.Tproxy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *tcpWorker) callback(conn stat.Connection) {
|
func (w *tcpWorker) callback(conn internet.Connection) {
|
||||||
ctx, cancel := context.WithCancel(w.ctx)
|
ctx, cancel := context.WithCancel(w.ctx)
|
||||||
sid := session.NewID()
|
sid := session.NewID()
|
||||||
ctx = c.ContextWithID(ctx, sid)
|
ctx = session.ContextWithID(ctx, sid)
|
||||||
|
|
||||||
outbounds := []*session.Outbound{{}}
|
|
||||||
if w.recvOrigDest {
|
if w.recvOrigDest {
|
||||||
var dest net.Destination
|
var dest net.Destination
|
||||||
switch getTProxyType(w.stream) {
|
switch getTProxyType(w.stream) {
|
||||||
case internet.SocketConfig_Redirect:
|
case internet.SocketConfig_Redirect:
|
||||||
d, err := tcp.GetOriginalDestination(conn)
|
d, err := tcp.GetOriginalDestination(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogInfoInner(ctx, err, "failed to get original destination")
|
newError("failed to get original destination").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||||
} else {
|
} else {
|
||||||
dest = d
|
dest = d
|
||||||
}
|
}
|
||||||
@@ -77,13 +73,14 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
|||||||
dest = net.DestinationFromAddr(conn.LocalAddr())
|
dest = net.DestinationFromAddr(conn.LocalAddr())
|
||||||
}
|
}
|
||||||
if dest.IsValid() {
|
if dest.IsValid() {
|
||||||
outbounds[0].Target = dest
|
ctx = session.ContextWithOutbound(ctx, &session.Outbound{
|
||||||
|
Target: dest,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx = session.ContextWithOutbounds(ctx, outbounds)
|
|
||||||
|
|
||||||
if w.uplinkCounter != nil || w.downlinkCounter != nil {
|
if w.uplinkCounter != nil || w.downlinkCounter != nil {
|
||||||
conn = &stat.CounterConnection{
|
conn = &internet.StatCouterConnection{
|
||||||
Connection: conn,
|
Connection: conn,
|
||||||
ReadCounter: w.uplinkCounter,
|
ReadCounter: w.uplinkCounter,
|
||||||
WriteCounter: w.downlinkCounter,
|
WriteCounter: w.downlinkCounter,
|
||||||
@@ -102,15 +99,16 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
|||||||
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
||||||
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
||||||
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||||
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
|
||||||
}
|
}
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
|
|
||||||
if err := w.proxy.Process(ctx, net.Network_TCP, conn, w.dispatcher); err != nil {
|
if err := w.proxy.Process(ctx, net.Network_TCP, conn, w.dispatcher); err != nil {
|
||||||
errors.LogInfoInner(ctx, err, "connection ends")
|
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||||
}
|
}
|
||||||
cancel()
|
cancel()
|
||||||
conn.Close()
|
if err := conn.Close(); err != nil {
|
||||||
|
newError("failed to close connection").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *tcpWorker) Proxy() proxy.Inbound {
|
func (w *tcpWorker) Proxy() proxy.Inbound {
|
||||||
@@ -119,28 +117,28 @@ func (w *tcpWorker) Proxy() proxy.Inbound {
|
|||||||
|
|
||||||
func (w *tcpWorker) Start() error {
|
func (w *tcpWorker) Start() error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
hub, err := internet.ListenTCP(ctx, w.address, w.port, w.stream, func(conn stat.Connection) {
|
hub, err := internet.ListenTCP(ctx, w.address, w.port, w.stream, func(conn internet.Connection) {
|
||||||
go w.callback(conn)
|
go w.callback(conn)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to listen TCP on ", w.port).AtWarning().Base(err)
|
return newError("failed to listen TCP on ", w.port).AtWarning().Base(err)
|
||||||
}
|
}
|
||||||
w.hub = hub
|
w.hub = hub
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *tcpWorker) Close() error {
|
func (w *tcpWorker) Close() error {
|
||||||
var errs []interface{}
|
var errors []interface{}
|
||||||
if w.hub != nil {
|
if w.hub != nil {
|
||||||
if err := common.Close(w.hub); err != nil {
|
if err := common.Close(w.hub); err != nil {
|
||||||
errs = append(errs, err)
|
errors = append(errors, err)
|
||||||
}
|
}
|
||||||
if err := common.Close(w.proxy); err != nil {
|
if err := common.Close(w.proxy); err != nil {
|
||||||
errs = append(errs, err)
|
errors = append(errors, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
if len(errors) > 0 {
|
||||||
return errors.New("failed to close all resources").Base(errors.New(serial.Concat(errs...)))
|
return newError("failed to close all resources").Base(newError(serial.Concat(errors...)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -160,11 +158,6 @@ type udpConn struct {
|
|||||||
done *done.Instance
|
done *done.Instance
|
||||||
uplink stats.Counter
|
uplink stats.Counter
|
||||||
downlink stats.Counter
|
downlink stats.Counter
|
||||||
inactive bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *udpConn) setInactive() {
|
|
||||||
c.inactive = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *udpConn) updateActivity() {
|
func (c *udpConn) updateActivity() {
|
||||||
@@ -308,13 +301,13 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
|||||||
go func() {
|
go func() {
|
||||||
ctx := w.ctx
|
ctx := w.ctx
|
||||||
sid := session.NewID()
|
sid := session.NewID()
|
||||||
ctx = c.ContextWithID(ctx, sid)
|
ctx = session.ContextWithID(ctx, sid)
|
||||||
|
|
||||||
outbounds := []*session.Outbound{{}}
|
|
||||||
if originalDest.IsValid() {
|
if originalDest.IsValid() {
|
||||||
outbounds[0].Target = originalDest
|
ctx = session.ContextWithOutbound(ctx, &session.Outbound{
|
||||||
|
Target: originalDest,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
ctx = session.ContextWithOutbounds(ctx, outbounds)
|
|
||||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||||
Source: source,
|
Source: source,
|
||||||
Gateway: net.UDPDestination(w.address, w.port),
|
Gateway: net.UDPDestination(w.address, w.port),
|
||||||
@@ -325,18 +318,13 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
|||||||
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
|
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
|
||||||
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
||||||
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||||
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
|
||||||
}
|
}
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
|
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
|
||||||
errors.LogInfoInner(ctx, err, "connection ends")
|
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||||
}
|
}
|
||||||
conn.Close()
|
conn.Close()
|
||||||
// conn not removed by checker TODO may be lock worker here is better
|
w.removeConn(id)
|
||||||
if !conn.inactive {
|
|
||||||
conn.setInactive()
|
|
||||||
w.removeConn(id)
|
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,15 +348,12 @@ func (w *udpWorker) clean() error {
|
|||||||
defer w.Unlock()
|
defer w.Unlock()
|
||||||
|
|
||||||
if len(w.activeConn) == 0 {
|
if len(w.activeConn) == 0 {
|
||||||
return errors.New("no more connections. stopping...")
|
return newError("no more connections. stopping...")
|
||||||
}
|
}
|
||||||
|
|
||||||
for addr, conn := range w.activeConn {
|
for addr, conn := range w.activeConn {
|
||||||
if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 2*60 {
|
if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 300 {
|
||||||
if !conn.inactive {
|
delete(w.activeConn, addr)
|
||||||
conn.setInactive()
|
|
||||||
delete(w.activeConn, addr)
|
|
||||||
}
|
|
||||||
conn.Close()
|
conn.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -404,26 +389,26 @@ func (w *udpWorker) Close() error {
|
|||||||
w.Lock()
|
w.Lock()
|
||||||
defer w.Unlock()
|
defer w.Unlock()
|
||||||
|
|
||||||
var errs []interface{}
|
var errors []interface{}
|
||||||
|
|
||||||
if w.hub != nil {
|
if w.hub != nil {
|
||||||
if err := w.hub.Close(); err != nil {
|
if err := w.hub.Close(); err != nil {
|
||||||
errs = append(errs, err)
|
errors = append(errors, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.checker != nil {
|
if w.checker != nil {
|
||||||
if err := w.checker.Close(); err != nil {
|
if err := w.checker.Close(); err != nil {
|
||||||
errs = append(errs, err)
|
errors = append(errors, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := common.Close(w.proxy); err != nil {
|
if err := common.Close(w.proxy); err != nil {
|
||||||
errs = append(errs, err)
|
errors = append(errors, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(errs) > 0 {
|
if len(errors) > 0 {
|
||||||
return errors.New("failed to close all resources").Base(errors.New(serial.Concat(errs...)))
|
return newError("failed to close all resources").Base(newError(serial.Concat(errors...)))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -451,13 +436,13 @@ type dsWorker struct {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *dsWorker) callback(conn stat.Connection) {
|
func (w *dsWorker) callback(conn internet.Connection) {
|
||||||
ctx, cancel := context.WithCancel(w.ctx)
|
ctx, cancel := context.WithCancel(w.ctx)
|
||||||
sid := session.NewID()
|
sid := session.NewID()
|
||||||
ctx = c.ContextWithID(ctx, sid)
|
ctx = session.ContextWithID(ctx, sid)
|
||||||
|
|
||||||
if w.uplinkCounter != nil || w.downlinkCounter != nil {
|
if w.uplinkCounter != nil || w.downlinkCounter != nil {
|
||||||
conn = &stat.CounterConnection{
|
conn = &internet.StatCouterConnection{
|
||||||
Connection: conn,
|
Connection: conn,
|
||||||
ReadCounter: w.uplinkCounter,
|
ReadCounter: w.uplinkCounter,
|
||||||
WriteCounter: w.downlinkCounter,
|
WriteCounter: w.downlinkCounter,
|
||||||
@@ -476,16 +461,15 @@ func (w *dsWorker) callback(conn stat.Connection) {
|
|||||||
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
||||||
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
||||||
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||||
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
|
||||||
}
|
}
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
|
|
||||||
if err := w.proxy.Process(ctx, net.Network_UNIX, conn, w.dispatcher); err != nil {
|
if err := w.proxy.Process(ctx, net.Network_UNIX, conn, w.dispatcher); err != nil {
|
||||||
errors.LogInfoInner(ctx, err, "connection ends")
|
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||||
}
|
}
|
||||||
cancel()
|
cancel()
|
||||||
if err := conn.Close(); err != nil {
|
if err := conn.Close(); err != nil {
|
||||||
errors.LogInfoInner(ctx, err, "failed to close connection")
|
newError("failed to close connection").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,31 +480,30 @@ func (w *dsWorker) Proxy() proxy.Inbound {
|
|||||||
func (w *dsWorker) Port() net.Port {
|
func (w *dsWorker) Port() net.Port {
|
||||||
return net.Port(0)
|
return net.Port(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *dsWorker) Start() error {
|
func (w *dsWorker) Start() error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
hub, err := internet.ListenUnix(ctx, w.address, w.stream, func(conn stat.Connection) {
|
hub, err := internet.ListenUnix(ctx, w.address, w.stream, func(conn internet.Connection) {
|
||||||
go w.callback(conn)
|
go w.callback(conn)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to listen Unix Domain Socket on ", w.address).AtWarning().Base(err)
|
return newError("failed to listen Unix Domain Socket on ", w.address).AtWarning().Base(err)
|
||||||
}
|
}
|
||||||
w.hub = hub
|
w.hub = hub
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *dsWorker) Close() error {
|
func (w *dsWorker) Close() error {
|
||||||
var errs []interface{}
|
var errors []interface{}
|
||||||
if w.hub != nil {
|
if w.hub != nil {
|
||||||
if err := common.Close(w.hub); err != nil {
|
if err := common.Close(w.hub); err != nil {
|
||||||
errs = append(errs, err)
|
errors = append(errors, err)
|
||||||
}
|
}
|
||||||
if err := common.Close(w.proxy); err != nil {
|
if err := common.Close(w.proxy); err != nil {
|
||||||
errs = append(errs, err)
|
errors = append(errors, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
if len(errors) > 0 {
|
||||||
return errors.New("failed to close all resources").Base(errors.New(serial.Concat(errs...)))
|
return newError("failed to close all resources").Base(newError(serial.Concat(errors...)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user