mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-08-22 17:46:48 +08:00
Compare commits
143 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4c82ef8a1b | ||
![]() |
30af792777 | ||
![]() |
33daa0c94b | ||
![]() |
70383c50cc | ||
![]() |
521d8ef6a1 | ||
![]() |
4531a7e228 | ||
![]() |
a342db3e28 | ||
![]() |
60553a6c26 | ||
![]() |
59f6685774 | ||
![]() |
4cb2a128db | ||
![]() |
8a4217fdf5 | ||
![]() |
7cf5ee8afd | ||
![]() |
2becdd6414 | ||
![]() |
edae38c620 | ||
![]() |
36f427f22b | ||
![]() |
c27d652d80 | ||
![]() |
0f65aa8ed8 | ||
![]() |
22535d8643 | ||
![]() |
529f206d33 | ||
![]() |
964859b4bc | ||
![]() |
8deb953aec | ||
![]() |
a0040f13dd | ||
![]() |
d8994b7603 | ||
![]() |
b277bacdf6 | ||
![]() |
9288a7c0dc | ||
![]() |
c40fc44a34 | ||
![]() |
02cd3b8c74 | ||
![]() |
a7e198e1e2 | ||
![]() |
9e6d7a3cb0 | ||
![]() |
a4bc422ed1 | ||
![]() |
59819e2a1b | ||
![]() |
573fb4f643 | ||
![]() |
558cfcc507 | ||
![]() |
39675b7ef7 | ||
![]() |
16de0937a8 | ||
![]() |
c69d38ae82 | ||
![]() |
73a001dd7a | ||
![]() |
c8f6ba9ff0 | ||
![]() |
308f0c64c3 | ||
![]() |
ce637c0c23 | ||
![]() |
0d130a0489 | ||
![]() |
01a3b4912b | ||
![]() |
b8c0768b16 | ||
![]() |
4c51636788 | ||
![]() |
1113ee7fa2 | ||
![]() |
e13f9f59da | ||
![]() |
60b2c349d2 | ||
![]() |
c6a57b2cc1 | ||
![]() |
079d0bd8a9 | ||
![]() |
8320732743 | ||
![]() |
c0f3bf66fd | ||
![]() |
e4f9d03bef | ||
![]() |
7acd5a623b | ||
![]() |
ee2000f6e1 | ||
![]() |
74d233dd64 | ||
![]() |
eb4f9429e6 | ||
![]() |
028a640b1b | ||
![]() |
9432a600e6 | ||
![]() |
8fe976d7ee | ||
![]() |
c1a7602412 | ||
![]() |
404af13b56 | ||
![]() |
c10bd28731 | ||
![]() |
501d5dec60 | ||
![]() |
d04a9d4fc9 | ||
![]() |
ae97821e40 | ||
![]() |
219a7dac20 | ||
![]() |
a1626cbf94 | ||
![]() |
f7dd84d6b9 | ||
![]() |
ea02ae74ed | ||
![]() |
c15974f7ee | ||
![]() |
13f0eccb8f | ||
![]() |
f0cb292dc6 | ||
![]() |
3654c0d710 | ||
![]() |
f8ec93dfdd | ||
![]() |
980236f2b6 | ||
![]() |
be29cc39d7 | ||
![]() |
9c6685d2ee | ||
![]() |
f5a70e4200 | ||
![]() |
75b3ef71a1 | ||
![]() |
df53afceae | ||
![]() |
459504300c | ||
![]() |
075051a693 | ||
![]() |
bbf25b14d9 | ||
![]() |
89074a14b6 | ||
![]() |
73c5650b17 | ||
![]() |
0a3c449cdf | ||
![]() |
ca07a705dc | ||
![]() |
3120ca4121 | ||
![]() |
9b6141b83f | ||
![]() |
416f2df11c | ||
![]() |
29c6318ffe | ||
![]() |
9ee9a0634e | ||
![]() |
544f7661ca | ||
![]() |
121eb7b4fc | ||
![]() |
3168d27b0b | ||
![]() |
b98d060ee0 | ||
![]() |
26d49df22e | ||
![]() |
1d450cfbd2 | ||
![]() |
017f53b5fc | ||
![]() |
0735053348 | ||
![]() |
e41a61c6f7 | ||
![]() |
a9715295b8 | ||
![]() |
f0b0a7cd4b | ||
![]() |
cefae55d7c | ||
![]() |
84eeb56ae4 | ||
![]() |
eba2906d3a | ||
![]() |
cc2849025d | ||
![]() |
c1ad35fba8 | ||
![]() |
447a49d16a | ||
![]() |
51504c624c | ||
![]() |
98a2e2c7a1 | ||
![]() |
a476310aec | ||
![]() |
b8924782a1 | ||
![]() |
45ab4cb5ba | ||
![]() |
8ce2a0e245 | ||
![]() |
61800fcc66 | ||
![]() |
ae0eec41d8 | ||
![]() |
080bd8241c | ||
![]() |
b356b35312 | ||
![]() |
1593677b09 | ||
![]() |
c85a91bc29 | ||
![]() |
dd16dcec03 | ||
![]() |
e9eec57b46 | ||
![]() |
32f0017449 | ||
![]() |
12f5b05aca | ||
![]() |
befa7b8138 | ||
![]() |
0c61752829 | ||
![]() |
cabc4c6013 | ||
![]() |
fbc56b88da | ||
![]() |
fc41874508 | ||
![]() |
03c20bf3b4 | ||
![]() |
2843167761 | ||
![]() |
021868afca | ||
![]() |
548646fb06 | ||
![]() |
e64fb3ca9b | ||
![]() |
09db7e1cca | ||
![]() |
457c1f65e0 | ||
![]() |
592157bb00 | ||
![]() |
8374d59ce6 | ||
![]() |
ec3b2b0907 | ||
![]() |
4b893fdd22 | ||
![]() |
ec2224974d | ||
![]() |
ba57ccdd45 |
89
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
89
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
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
|
||||
- type: input
|
||||
attributes:
|
||||
label: Version
|
||||
description: Version of Xray-core
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: Please provide a detailed description of the error. And the information you think valuable.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Reproduction Method
|
||||
description: |-
|
||||
Based on the configuration you provided below, provide the method to reproduce the bug.
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |-
|
||||
## Configuration and Log Section
|
||||
|
||||
### For config
|
||||
Please provide the configuration files that can reproduce the problem, including the server and client.
|
||||
Don't just paste a big exported config file here. Eliminate useless inbound/outbound, rules, options, this can help determine the problem, if you really want to get help.
|
||||
|
||||
### For logs
|
||||
Please set the log level to debug 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
|
89
.github/ISSUE_TEMPLATE/bug_report_zh.yml
vendored
Normal file
89
.github/ISSUE_TEMPLATE/bug_report_zh.yml
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
name: bug反馈
|
||||
description: "提交 Xray-core bug"
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: 完整性要求
|
||||
description: |-
|
||||
请勾选以下所有选项以证明您已经阅读并理解了以下要求,否则该 issue 将被关闭。
|
||||
options:
|
||||
- label: 我保证阅读了文档,了解所有我编写的配置文件项的含义,而不是大量堆砌看似有用的选项或默认值。
|
||||
required: true
|
||||
- label: 我提供了完整的配置文件和日志,而不是出于自己的判断只给出截取的部分。
|
||||
required: true
|
||||
- label: 我搜索了issues,没有发现已提出的类似问题。
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: 版本
|
||||
description: 使用的Xray-core版本
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 描述
|
||||
description: 请提供错误的详细描述。以及你认为有价值的信息。
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 重现方式
|
||||
description: |-
|
||||
基于你下面提供的配置,提供重现BUG方法。
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |-
|
||||
## 配置与日志部分
|
||||
|
||||
### 对于配置文件
|
||||
请提供可以重现问题的配置文件,包括服务端和客户端。
|
||||
不要直接在这里黏贴一大段导出的 config 文件。去掉无用的出入站、规则、选项,这可以帮助确定问题,如果你真的想得到帮助。
|
||||
|
||||
### 对于日志
|
||||
请先将日志等级设置为 debug, 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
Normal file
4
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
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.
|
28
.github/docker/Dockerfile
vendored
28
.github/docker/Dockerfile
vendored
@@ -2,21 +2,27 @@
|
||||
FROM --platform=$BUILDPLATFORM golang:alpine AS build
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
ARG TARGETOS TARGETARCH
|
||||
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
|
||||
|
||||
FROM --platform=${TARGETPLATFORM} alpine:latest
|
||||
WORKDIR /root
|
||||
# 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 /src/xray /usr/bin/xray
|
||||
RUN set -ex \
|
||||
&& apk add --no-cache tzdata ca-certificates \
|
||||
&& mkdir -p /var/log/xray /usr/share/xray \
|
||||
&& chmod +x /usr/bin/xray \
|
||||
&& wget -O /usr/share/xray/geosite.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat \
|
||||
&& wget -O /usr/share/xray/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
|
||||
COPY --from=build --chmod=755 /src/xray /usr/bin/xray
|
||||
|
||||
USER root
|
||||
WORKDIR /root
|
||||
VOLUME /etc/xray
|
||||
ENV TZ=Asia/Shanghai
|
||||
ARG TZ=Asia/Shanghai
|
||||
ENV TZ=$TZ
|
||||
ENTRYPOINT [ "/usr/bin/xray" ]
|
||||
CMD [ "-config", "/etc/xray/config.json" ]
|
||||
|
||||
ARG flavor=v2fly
|
||||
COPY --from=build /$flavor /usr/share/xray
|
||||
|
47
.github/workflows/docker.yml
vendored
47
.github/workflows/docker.yml
vendored
@@ -1,6 +1,8 @@
|
||||
name: Build docker image
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
@@ -17,8 +19,22 @@ jobs:
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/xray-core
|
||||
flavor: latest=true
|
||||
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}}
|
||||
@@ -28,18 +44,33 @@ jobs:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- # Add support for more platforms with QEMU (optional)
|
||||
# https://github.com/docker/setup-qemu-action
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm64
|
||||
linux/loong64
|
||||
linux/riscv64
|
||||
provenance: false
|
||||
file: .github/docker/Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
- 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 }}
|
||||
|
35
.github/workflows/release.yml
vendored
35
.github/workflows/release.yml
vendored
@@ -1,5 +1,11 @@
|
||||
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:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
@@ -11,14 +17,14 @@ on:
|
||||
- "**/*.go"
|
||||
- "go.mod"
|
||||
- "go.sum"
|
||||
- ".github/workflows/*.yml"
|
||||
- ".github/workflows/release.yml"
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
paths:
|
||||
- "**/*.go"
|
||||
- "go.mod"
|
||||
- "go.sum"
|
||||
- ".github/workflows/*.yml"
|
||||
- ".github/workflows/release.yml"
|
||||
jobs:
|
||||
prepare:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -72,12 +78,15 @@ jobs:
|
||||
# Include amd64 on all platforms.
|
||||
goos: [windows, freebsd, openbsd, linux, darwin]
|
||||
goarch: [amd64, 386]
|
||||
gotoolchain: [""]
|
||||
patch-assetname: [""]
|
||||
|
||||
exclude:
|
||||
# Exclude i386 on darwin
|
||||
- goarch: 386
|
||||
goos: darwin
|
||||
include:
|
||||
# BEIGIN MacOS ARM64
|
||||
# BEGIN MacOS ARM64
|
||||
- goos: darwin
|
||||
goarch: arm64
|
||||
# END MacOS ARM64
|
||||
@@ -146,6 +155,16 @@ jobs:
|
||||
goarch: arm
|
||||
goarm: 7
|
||||
# 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
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
@@ -158,16 +177,17 @@ jobs:
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Show workflow information
|
||||
- name: Show workflow information
|
||||
run: |
|
||||
export _NAME=$(jq ".[\"$GOOS-$GOARCH$GOARM$GOMIPS\"].friendlyName" -r < .github/build/friendly-filenames.json)
|
||||
_NAME=${{ matrix.patch-assetname }}
|
||||
[ -n "$_NAME" ] || _NAME=$(jq ".[\"$GOOS-$GOARCH$GOARM$GOMIPS\"].friendlyName" -r < .github/build/friendly-filenames.json)
|
||||
echo "GOOS: $GOOS, GOARCH: $GOARCH, GOARM: $GOARM, GOMIPS: $GOMIPS, RELEASE_NAME: $_NAME"
|
||||
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
go-version: ${{ matrix.gotoolchain || '1.22' }}
|
||||
check-latest: true
|
||||
|
||||
- name: Get project dependencies
|
||||
@@ -177,7 +197,7 @@ jobs:
|
||||
run: |
|
||||
mkdir -p build_assets
|
||||
make
|
||||
find . -maxdepth 1 -type f -regex '.*\(wxray\|xray\|xray_softfloat\)\(\|.exe\)' -exec mv {} ./build_assets/ \;
|
||||
find . -maxdepth 1 -type f -regex './\(wxray\|xray\|xray_softfloat\)\(\|.exe\)' -exec mv {} ./build_assets/ \;
|
||||
|
||||
- name: Restore Cache
|
||||
uses: actions/cache/restore@v4
|
||||
@@ -192,6 +212,7 @@ jobs:
|
||||
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
|
||||
|
||||
- name: Create ZIP archive
|
||||
if: github.event_name == 'release'
|
||||
shell: bash
|
||||
run: |
|
||||
pushd build_assets || exit 1
|
||||
|
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
go-version: '1.22'
|
||||
check-latest: true
|
||||
- name: Restore Cache
|
||||
uses: actions/cache/restore@v4
|
||||
|
20
Makefile
20
Makefile
@@ -2,6 +2,17 @@ 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
|
||||
@@ -12,18 +23,15 @@ ADDITION = go build -o w$(NAME).exe -trimpath -ldflags "-H windowsgui $(LDFLAGS)
|
||||
else
|
||||
OUTPUT = $(NAME)
|
||||
endif
|
||||
ifeq ($(shell echo "$(GOARCH)" | grep -Pq "(mips|mipsle)" && echo true),true) #
|
||||
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
|
||||
.PHONY: clean build
|
||||
|
||||
build:
|
||||
go build -o $(OUTPUT) $(PARAMS) $(MAIN)
|
||||
$(ADDITION)
|
||||
|
||||
install:
|
||||
go build -o $(PREFIX)/bin/$(OUTPUT) $(PARAMS) $(MAIN)
|
||||
|
||||
clean:
|
||||
go clean -v -i $(PWD)
|
||||
rm -f xray xray.exe wxray.exe xray_softfloat
|
||||
rm -f xray xray.exe wxray.exe xray_softfloat
|
||||
|
20
README.md
20
README.md
@@ -21,15 +21,13 @@
|
||||
## Installation
|
||||
|
||||
- Linux Script
|
||||
- [XTLS/Xray-install](https://github.com/XTLS/Xray-install)
|
||||
- [team-cloudchaser/tempest](https://github.com/team-cloudchaser/tempest) (supports [`systemd`](https://systemd.io) and [OpenRC](https://github.com/OpenRC/openrc); Linux-only)
|
||||
- [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
|
||||
- Official: [ghcr.io/xtls/xray-core](https://ghcr.io/xtls/xray-core)
|
||||
- [iamybj/docker-xray](https://hub.docker.com/r/iamybj/docker-xray)
|
||||
- [ghcr.io/xtls/xray-core](https://ghcr.io/xtls/xray-core) (**Official**)
|
||||
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
|
||||
- Web Panel
|
||||
- [X-UI-English](https://github.com/NidukaAkalanka/x-ui-english), [3X-UI](https://github.com/MHSanaei/3x-ui), [X-UI](https://github.com/alireza0/x-ui), [X-UI](https://github.com/diditra/x-ui)
|
||||
- [Xray-UI](https://github.com/qist/xray-ui), [X-UI](https://github.com/sing-web/x-ui)
|
||||
- [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)
|
||||
- [Marzban](https://github.com/Gozargah/Marzban)
|
||||
- [Libertea](https://github.com/VZiChoushaDui/Libertea)
|
||||
@@ -68,13 +66,10 @@
|
||||
- [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray))
|
||||
- Windows
|
||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
||||
- [NekoRay](https://github.com/Matsuridayo/nekoray)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
- [HiddifyN](https://github.com/hiddify/HiddifyN)
|
||||
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
|
||||
- Android
|
||||
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
||||
- [HiddifyNG](https://github.com/hiddify/HiddifyNG)
|
||||
- [X-flutter](https://github.com/XTLS/X-flutter)
|
||||
- iOS & macOS arm64
|
||||
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
|
||||
@@ -86,7 +81,6 @@
|
||||
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
|
||||
- Linux
|
||||
- [v2rayA](https://github.com/v2rayA/v2rayA)
|
||||
- [NekoRay](https://github.com/Matsuridayo/nekoray)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
|
||||
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
||||
@@ -99,21 +93,15 @@
|
||||
- [XTLS/libXray](https://github.com/XTLS/libXray)
|
||||
- [xtlsapi](https://github.com/hiddify/xtlsapi)
|
||||
- [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite)
|
||||
- [XrayKit](https://github.com/arror/XrayKit)
|
||||
- [Xray-core-python](https://github.com/LorenEteval/Xray-core-python)
|
||||
- [xray-api](https://github.com/XVGuardian/xray-api)
|
||||
- [XrayR](https://github.com/XrayR-project/XrayR)
|
||||
- [XrayR-release](https://github.com/XrayR-project/XrayR-release)
|
||||
- [XrayR-V2Board](https://github.com/missuo/XrayR-V2Board)
|
||||
- [Clash.Meta](https://github.com/MetaCubeX/Clash.Meta)
|
||||
- [Clash Verge](https://github.com/zzzgydi/clash-verge)
|
||||
- [clashN](https://github.com/2dust/clashN)
|
||||
- [Clash Meta for Android](https://github.com/MetaCubeX/ClashMetaForAndroid)
|
||||
- [meta_for_ios](https://t.me/meta_for_ios)
|
||||
- [sing-box](https://github.com/SagerNet/sing-box)
|
||||
- [installReality](https://github.com/BoxXt/installReality)
|
||||
- [sbox-reality](https://github.com/Misaka-blog/sbox-reality)
|
||||
- [sing-box-for-ios](https://github.com/SagerNet/sing-box-for-ios)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@@ -8,6 +8,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/signal/done"
|
||||
core "github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
@@ -21,12 +22,14 @@ type Commander struct {
|
||||
services []Service
|
||||
ohm outbound.Manager
|
||||
tag string
|
||||
listen string
|
||||
}
|
||||
|
||||
// NewCommander creates a new Commander based on the given config.
|
||||
func NewCommander(ctx context.Context, config *Config) (*Commander, error) {
|
||||
c := &Commander{
|
||||
tag: config.Tag,
|
||||
tag: config.Tag,
|
||||
listen: config.Listen,
|
||||
}
|
||||
|
||||
common.Must(core.RequireFeatures(ctx, func(om outbound.Manager) {
|
||||
@@ -44,7 +47,7 @@ func NewCommander(ctx context.Context, config *Config) (*Commander, error) {
|
||||
}
|
||||
service, ok := rawService.(Service)
|
||||
if !ok {
|
||||
return nil, newError("not a Service.")
|
||||
return nil, errors.New("not a Service.")
|
||||
}
|
||||
c.services = append(c.services, service)
|
||||
}
|
||||
@@ -66,19 +69,32 @@ func (c *Commander) Start() error {
|
||||
}
|
||||
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{
|
||||
buffer: make(chan net.Conn, 4),
|
||||
done: done.New(),
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := c.server.Serve(listener); err != nil {
|
||||
newError("failed to start grpc server").Base(err).AtError().WriteToLog()
|
||||
}
|
||||
}()
|
||||
go listen(listener)
|
||||
|
||||
if err := c.ohm.RemoveHandler(context.Background(), c.tag); err != nil {
|
||||
newError("failed to remove existing handler").WriteToLog()
|
||||
errors.LogInfoInner(context.Background(), err, "failed to remove existing handler")
|
||||
}
|
||||
|
||||
return c.ohm.AddHandler(context.Background(), &Outbound{
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/commander/config.proto
|
||||
|
||||
package commander
|
||||
@@ -29,6 +29,8 @@ type Config struct {
|
||||
|
||||
// Tag of the outbound handler that handles grpc connections.
|
||||
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
|
||||
// interface.
|
||||
Service []*serial.TypedMessage `protobuf:"bytes,2,rep,name=service,proto3" json:"service,omitempty"`
|
||||
@@ -73,6 +75,13 @@ func (x *Config) GetTag() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Config) GetListen() string {
|
||||
if x != nil {
|
||||
return x.Listen
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Config) GetService() []*serial.TypedMessage {
|
||||
if x != nil {
|
||||
return x.Service
|
||||
@@ -127,20 +136,21 @@ var file_app_commander_config_proto_rawDesc = []byte{
|
||||
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,
|
||||
0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x22, 0x56, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a,
|
||||
0x6f, 0x74, 0x6f, 0x22, 0x6e, 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,
|
||||
0x3a, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x03, 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, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52,
|
||||
0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42,
|
||||
0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x27, 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, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
||||
0x6e, 0x64, 0x65, 0x72, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e,
|
||||
0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
0x16, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x3a, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||
0x63, 0x65, 0x18, 0x02, 0x20, 0x03, 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, 0x07, 0x73, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65,
|
||||
0x72, 0x50, 0x01, 0x5a, 0x27, 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, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0xaa, 0x02, 0x12, 0x58,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65,
|
||||
0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@@ -12,6 +12,10 @@ import "common/serial/typed_message.proto";
|
||||
message Config {
|
||||
// Tag of the outbound handler that handles grpc connections.
|
||||
string tag = 1;
|
||||
|
||||
// Network address of commander grpc service.
|
||||
string listen = 3;
|
||||
|
||||
// Services that supported by this server. All services must implement Service
|
||||
// interface.
|
||||
repeated xray.common.serial.TypedMessage service = 2;
|
||||
|
@@ -1,9 +0,0 @@
|
||||
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,6 +5,7 @@ import (
|
||||
"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"
|
||||
@@ -31,7 +32,7 @@ func (l *OutboundListener) add(conn net.Conn) {
|
||||
func (l *OutboundListener) Accept() (net.Conn, error) {
|
||||
select {
|
||||
case <-l.done.Wait():
|
||||
return nil, newError("listen closed")
|
||||
return nil, errors.New("listen closed")
|
||||
case c := <-l.buffer:
|
||||
return c, nil
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/dispatcher/config.proto
|
||||
|
||||
package dispatcher
|
||||
|
@@ -4,11 +4,13 @@ package dispatcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/log"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
@@ -25,7 +27,7 @@ import (
|
||||
"github.com/xtls/xray-core/transport/pipe"
|
||||
)
|
||||
|
||||
var errSniffingTimeout = newError("timeout on sniffing")
|
||||
var errSniffingTimeout = errors.New("timeout on sniffing")
|
||||
|
||||
type cachedReader struct {
|
||||
sync.Mutex
|
||||
@@ -186,8 +188,20 @@ func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResu
|
||||
return false
|
||||
}
|
||||
for _, d := range request.ExcludeForDomain {
|
||||
if strings.ToLower(domain) == d {
|
||||
return false
|
||||
if strings.HasPrefix(d, "regexp:") {
|
||||
pattern := d[7:]
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
protocolString := result.Protocol()
|
||||
@@ -200,7 +214,7 @@ func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResu
|
||||
}
|
||||
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && protocolString != "bittorrent" && p == "fakedns" &&
|
||||
fkr0.IsIPInIPPool(destination.Address) {
|
||||
newError("Using sniffer ", protocolString, " since the fake DNS missed").WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfo(ctx, "Using sniffer ", protocolString, " since the fake DNS missed")
|
||||
return true
|
||||
}
|
||||
if resultSubset, ok := result.(SnifferIsProtoSubsetOf); ok {
|
||||
@@ -218,11 +232,12 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
||||
if !destination.IsValid() {
|
||||
panic("Dispatcher: Invalid destination.")
|
||||
}
|
||||
ob := session.OutboundFromContext(ctx)
|
||||
if ob == nil {
|
||||
ob = &session.Outbound{}
|
||||
ctx = session.ContextWithOutbound(ctx, ob)
|
||||
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)
|
||||
@@ -247,7 +262,7 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
||||
}
|
||||
if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) {
|
||||
domain := result.Domain()
|
||||
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfo(ctx, "sniffed domain: ", domain)
|
||||
destination.Address = net.ParseAddress(domain)
|
||||
protocol := result.Protocol()
|
||||
if resComp, ok := result.(SnifferResultComposite); ok {
|
||||
@@ -272,13 +287,14 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
||||
// DispatchLink implements routing.Dispatcher.
|
||||
func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.Destination, outbound *transport.Link) error {
|
||||
if !destination.IsValid() {
|
||||
return newError("Dispatcher: Invalid destination.")
|
||||
return errors.New("Dispatcher: Invalid destination.")
|
||||
}
|
||||
ob := session.OutboundFromContext(ctx)
|
||||
if ob == nil {
|
||||
ob = &session.Outbound{}
|
||||
ctx = session.ContextWithOutbound(ctx, ob)
|
||||
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)
|
||||
@@ -300,7 +316,7 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
||||
}
|
||||
if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) {
|
||||
domain := result.Domain()
|
||||
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfo(ctx, "sniffed domain: ", domain)
|
||||
destination.Address = net.ParseAddress(domain)
|
||||
protocol := result.Protocol()
|
||||
if resComp, ok := result.(SnifferResultComposite); ok {
|
||||
@@ -368,7 +384,8 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
|
||||
return contentResult, contentErr
|
||||
}
|
||||
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
||||
ob := session.OutboundFromContext(ctx)
|
||||
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 {
|
||||
@@ -391,10 +408,10 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
||||
ctx = session.SetForcedOutboundTagToContext(ctx, "")
|
||||
if h := d.ohm.GetHandler(forcedOutboundTag); h != nil {
|
||||
isPickRoute = 1
|
||||
newError("taking platform initialized detour [", forcedOutboundTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfo(ctx, "taking platform initialized detour [", forcedOutboundTag, "] for [", destination, "]")
|
||||
handler = h
|
||||
} else {
|
||||
newError("non existing tag for platform initialized detour: ", forcedOutboundTag).AtError().WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogError(ctx, "non existing tag for platform initialized detour: ", forcedOutboundTag)
|
||||
common.Close(link.Writer)
|
||||
common.Interrupt(link.Reader)
|
||||
return
|
||||
@@ -404,13 +421,13 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
||||
outTag := route.GetOutboundTag()
|
||||
if h := d.ohm.GetHandler(outTag); h != nil {
|
||||
isPickRoute = 2
|
||||
newError("taking detour [", outTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfo(ctx, "taking detour [", outTag, "] for [", destination, "]")
|
||||
handler = h
|
||||
} else {
|
||||
newError("non existing outTag: ", outTag).AtWarning().WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogWarning(ctx, "non existing outTag: ", outTag)
|
||||
}
|
||||
} else {
|
||||
newError("default route for ", destination).WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfo(ctx, "default route for ", destination)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,12 +436,13 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
||||
}
|
||||
|
||||
if handler == nil {
|
||||
newError("default outbound handler not exist").WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfo(ctx, "default outbound handler not exist")
|
||||
common.Close(link.Writer)
|
||||
common.Interrupt(link.Reader)
|
||||
return
|
||||
}
|
||||
|
||||
ob.Tag = handler.Tag()
|
||||
if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil {
|
||||
if tag := handler.Tag(); tag != "" {
|
||||
if inTag == "" {
|
||||
|
@@ -1,9 +0,0 @@
|
||||
package dispatcher
|
||||
|
||||
import "github.com/xtls/xray-core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
@@ -5,6 +5,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"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/core"
|
||||
@@ -22,15 +23,16 @@ func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error)
|
||||
}
|
||||
|
||||
if fakeDNSEngine == nil {
|
||||
errNotInit := newError("FakeDNSEngine is not initialized, but such a sniffer is used").AtError()
|
||||
errNotInit := errors.New("FakeDNSEngine is not initialized, but such a sniffer is used").AtError()
|
||||
return protocolSnifferWithMetadata{}, errNotInit
|
||||
}
|
||||
return protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) {
|
||||
Target := session.OutboundFromContext(ctx).Target
|
||||
if Target.Network == net.Network_TCP || Target.Network == net.Network_UDP {
|
||||
domainFromFakeDNS := fakeDNSEngine.GetDomainFromFakeDNS(Target.Address)
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
if ob.Target.Network == net.Network_TCP || ob.Target.Network == net.Network_UDP {
|
||||
domainFromFakeDNS := fakeDNSEngine.GetDomainFromFakeDNS(ob.Target.Address)
|
||||
if domainFromFakeDNS != "" {
|
||||
newError("fake dns got domain: ", domainFromFakeDNS, " for ip: ", Target.Address.String()).WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfo(ctx, "fake dns got domain: ", domainFromFakeDNS, " for ip: ", ob.Target.Address.String())
|
||||
return &fakeDNSSniffResult{domainName: domainFromFakeDNS}, nil
|
||||
}
|
||||
}
|
||||
@@ -38,7 +40,7 @@ func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error)
|
||||
if ipAddressInRangeValueI := ctx.Value(ipAddressInRange); ipAddressInRangeValueI != nil {
|
||||
ipAddressInRangeValue := ipAddressInRangeValueI.(*ipAddressInRangeOpt)
|
||||
if fkr0, ok := fakeDNSEngine.(dns.FakeDNSEngineRev0); ok {
|
||||
inPool := fkr0.IsIPInIPPool(Target.Address)
|
||||
inPool := fkr0.IsIPInIPPool(ob.Target.Address)
|
||||
ipAddressInRangeValue.addressInRange = &inPool
|
||||
}
|
||||
}
|
||||
@@ -108,10 +110,10 @@ func newFakeDNSThenOthers(ctx context.Context, fakeDNSSniffer protocolSnifferWit
|
||||
}
|
||||
return nil, common.ErrNoClue
|
||||
}
|
||||
newError("ip address not in fake dns range, return as is").AtDebug().WriteToLog()
|
||||
errors.LogDebug(ctx, "ip address not in fake dns range, return as is")
|
||||
return nil, common.ErrNoClue
|
||||
}
|
||||
newError("fake dns sniffer did not set address in range option, assume false.").AtWarning().WriteToLog()
|
||||
errors.LogWarning(ctx, "fake dns sniffer did not set address in range option, assume false.")
|
||||
return nil, common.ErrNoClue
|
||||
},
|
||||
metadataSniffer: false,
|
||||
|
@@ -4,6 +4,7 @@ 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/protocol/bittorrent"
|
||||
"github.com/xtls/xray-core/common/protocol/http"
|
||||
@@ -52,7 +53,7 @@ func NewSniffer(ctx context.Context) *Sniffer {
|
||||
return ret
|
||||
}
|
||||
|
||||
var errUnknownContent = newError("unknown content")
|
||||
var errUnknownContent = errors.New("unknown content")
|
||||
|
||||
func (s *Sniffer) Sniff(c context.Context, payload []byte, network net.Network) (SniffResult, error) {
|
||||
var pendingSniffer []protocolSnifferWithMetadata
|
||||
|
@@ -1,6 +1,7 @@
|
||||
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"
|
||||
@@ -36,11 +37,11 @@ var localTLDsAndDotlessDomainsRule = &NameServer_OriginalRule{
|
||||
func toStrMatcher(t DomainMatchingType, domain string) (strmatcher.Matcher, error) {
|
||||
strMType, f := typeMap[t]
|
||||
if !f {
|
||||
return nil, newError("unknown mapping type", t).AtWarning()
|
||||
return nil, errors.New("unknown mapping type", t).AtWarning()
|
||||
}
|
||||
matcher, err := strMType.New(domain)
|
||||
if err != nil {
|
||||
return nil, newError("failed to create str matcher").Base(err)
|
||||
return nil, errors.New("failed to create str matcher").Base(err)
|
||||
}
|
||||
return matcher, nil
|
||||
}
|
||||
@@ -51,7 +52,7 @@ func toNetIP(addrs []net.Address) ([]net.IP, error) {
|
||||
if addr.Family().IsIP() {
|
||||
ips = append(ips, addr.IP())
|
||||
} else {
|
||||
return nil, newError("Failed to convert address", addr, "to Net IP.").AtWarning()
|
||||
return nil, errors.New("Failed to convert address", addr, "to Net IP.").AtWarning()
|
||||
}
|
||||
}
|
||||
return ips, nil
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/dns/config.proto
|
||||
|
||||
package dns
|
||||
|
@@ -54,7 +54,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
case 0, net.IPv4len, net.IPv6len:
|
||||
clientIP = net.IP(config.ClientIp)
|
||||
default:
|
||||
return nil, newError("unexpected client IP length ", len(config.ClientIp))
|
||||
return nil, errors.New("unexpected client IP length ", len(config.ClientIp))
|
||||
}
|
||||
|
||||
var ipOption *dns.IPOption
|
||||
@@ -81,7 +81,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
|
||||
hosts, err := NewStaticHosts(config.StaticHosts, config.Hosts)
|
||||
if err != nil {
|
||||
return nil, newError("failed to create hosts").Base(err)
|
||||
return nil, errors.New("failed to create hosts").Base(err)
|
||||
}
|
||||
|
||||
clients := []*Client{}
|
||||
@@ -99,7 +99,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
features.PrintDeprecatedFeatureWarning("simple DNS server")
|
||||
client, err := NewSimpleClient(ctx, endpoint, clientIP)
|
||||
if err != nil {
|
||||
return nil, newError("failed to create client").Base(err)
|
||||
return nil, errors.New("failed to create client").Base(err)
|
||||
}
|
||||
clients = append(clients, client)
|
||||
}
|
||||
@@ -122,7 +122,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
}
|
||||
client, err := NewClient(ctx, ns, myClientIP, geoipContainer, &matcherInfos, updateDomain)
|
||||
if err != nil {
|
||||
return nil, newError("failed to create client").Base(err)
|
||||
return nil, errors.New("failed to create client").Base(err)
|
||||
}
|
||||
clients = append(clients, client)
|
||||
}
|
||||
@@ -170,7 +170,7 @@ func (s *DNS) IsOwnLink(ctx context.Context) bool {
|
||||
// LookupIP implements dns.Client.
|
||||
func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
|
||||
if domain == "" {
|
||||
return nil, newError("empty domain name")
|
||||
return nil, errors.New("empty domain name")
|
||||
}
|
||||
|
||||
option.IPv4Enable = option.IPv4Enable && s.ipOption.IPv4Enable
|
||||
@@ -190,10 +190,10 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
|
||||
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
|
||||
newError("domain replaced: ", domain, " -> ", addrs[0].Domain()).WriteToLog()
|
||||
errors.LogInfo(s.ctx, "domain replaced: ", domain, " -> ", addrs[0].Domain())
|
||||
domain = addrs[0].Domain()
|
||||
default: // Successfully found ip records in static host
|
||||
newError("returning ", len(addrs), " IP(s) for domain ", domain, " -> ", addrs).WriteToLog()
|
||||
errors.LogInfo(s.ctx, "returning ", len(addrs), " IP(s) for domain ", domain, " -> ", addrs)
|
||||
return toNetIP(addrs)
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, 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") {
|
||||
newError("skip DNS resolution for domain ", domain, " at server ", client.Name()).AtDebug().WriteToLog()
|
||||
errors.LogDebug(s.ctx, "skip DNS resolution for domain ", domain, " at server ", client.Name())
|
||||
continue
|
||||
}
|
||||
ips, err := client.QueryIP(ctx, domain, option, s.disableCache)
|
||||
@@ -210,7 +210,7 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
|
||||
return ips, nil
|
||||
}
|
||||
if err != nil {
|
||||
newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog()
|
||||
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
|
||||
@@ -219,7 +219,7 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return nil, newError("returning nil for domain ", domain).Base(errors.Combine(errs...))
|
||||
return nil, errors.New("returning nil for domain ", domain).Base(errors.Combine(errs...))
|
||||
}
|
||||
|
||||
// LookupHosts implements dns.HostsLookup.
|
||||
@@ -231,7 +231,7 @@ func (s *DNS) LookupHosts(domain string) *net.Address {
|
||||
// Normalize the FQDN form query
|
||||
addrs := s.hosts.Lookup(domain, *s.ipOption)
|
||||
if len(addrs) > 0 {
|
||||
newError("domain replaced: ", domain, " -> ", addrs[0].String()).AtInfo().WriteToLog()
|
||||
errors.LogInfo(s.ctx, "domain replaced: ", domain, " -> ", addrs[0].String())
|
||||
return &addrs[0]
|
||||
}
|
||||
|
||||
@@ -289,16 +289,16 @@ func (s *DNS) sortClients(domain string) []*Client {
|
||||
}
|
||||
|
||||
if len(domainRules) > 0 {
|
||||
newError("domain ", domain, " matches following rules: ", domainRules).AtDebug().WriteToLog()
|
||||
errors.LogDebug(s.ctx, "domain ", domain, " matches following rules: ", domainRules)
|
||||
}
|
||||
if len(clientNames) > 0 {
|
||||
newError("domain ", domain, " will use DNS in order: ", clientNames).AtDebug().WriteToLog()
|
||||
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())
|
||||
newError("domain ", domain, " will use the first DNS: ", clientNames).AtDebug().WriteToLog()
|
||||
errors.LogDebug(s.ctx, "domain ", domain, " will use the first DNS: ", clientNames)
|
||||
}
|
||||
|
||||
return clients
|
||||
|
@@ -171,10 +171,10 @@ func parseResponse(payload []byte) (*IPRecord, error) {
|
||||
var parser dnsmessage.Parser
|
||||
h, err := parser.Start(payload)
|
||||
if err != nil {
|
||||
return nil, newError("failed to parse DNS response").Base(err).AtWarning()
|
||||
return nil, errors.New("failed to parse DNS response").Base(err).AtWarning()
|
||||
}
|
||||
if err := parser.SkipAllQuestions(); err != nil {
|
||||
return nil, newError("failed to skip questions in DNS response").Base(err).AtWarning()
|
||||
return nil, errors.New("failed to skip questions in DNS response").Base(err).AtWarning()
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
@@ -189,7 +189,7 @@ L:
|
||||
ah, err := parser.AnswerHeader()
|
||||
if err != nil {
|
||||
if err != dnsmessage.ErrSectionDone {
|
||||
newError("failed to parse answer section for domain: ", ah.Name.String()).Base(err).WriteToLog()
|
||||
errors.LogInfoInner(context.Background(), err, "failed to parse answer section for domain: ", ah.Name.String())
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -207,20 +207,20 @@ L:
|
||||
case dnsmessage.TypeA:
|
||||
ans, err := parser.AResource()
|
||||
if err != nil {
|
||||
newError("failed to parse A record for domain: ", ah.Name).Base(err).WriteToLog()
|
||||
errors.LogInfoInner(context.Background(), err, "failed to parse A record for domain: ", ah.Name)
|
||||
break L
|
||||
}
|
||||
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.A[:]))
|
||||
case dnsmessage.TypeAAAA:
|
||||
ans, err := parser.AAAAResource()
|
||||
if err != nil {
|
||||
newError("failed to parse AAAA record for domain: ", ah.Name).Base(err).WriteToLog()
|
||||
errors.LogInfoInner(context.Background(), err, "failed to parse AAAA record for domain: ", ah.Name)
|
||||
break L
|
||||
}
|
||||
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.AAAA[:]))
|
||||
default:
|
||||
if err := parser.SkipAnswer(); err != nil {
|
||||
newError("failed to skip answer").Base(err).WriteToLog()
|
||||
errors.LogInfoInner(context.Background(), err, "failed to skip answer")
|
||||
break L
|
||||
}
|
||||
continue
|
||||
|
@@ -1,9 +0,0 @@
|
||||
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{})
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
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{})
|
||||
}
|
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"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/features/dns"
|
||||
)
|
||||
@@ -45,7 +46,7 @@ func (fkdns *Holder) Start() error {
|
||||
if fkdns.config != nil && fkdns.config.IpPool != "" && fkdns.config.LruSize != 0 {
|
||||
return fkdns.initializeFromConfig()
|
||||
}
|
||||
return newError("invalid fakeDNS setting")
|
||||
return errors.New("invalid fakeDNS setting")
|
||||
}
|
||||
|
||||
func (fkdns *Holder) Close() error {
|
||||
@@ -60,7 +61,7 @@ func NewFakeDNSHolder() (*Holder, error) {
|
||||
var err error
|
||||
|
||||
if fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil {
|
||||
return nil, newError("Unable to create Fake Dns Engine").Base(err).AtError()
|
||||
return nil, errors.New("Unable to create Fake Dns Engine").Base(err).AtError()
|
||||
}
|
||||
err = fkdns.initialize(dns.FakeIPv4Pool, 65535)
|
||||
if err != nil {
|
||||
@@ -82,13 +83,13 @@ func (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error {
|
||||
var err error
|
||||
|
||||
if _, ipRange, err = gonet.ParseCIDR(ipPoolCidr); err != nil {
|
||||
return newError("Unable to parse CIDR for Fake DNS IP assignment").Base(err).AtError()
|
||||
return errors.New("Unable to parse CIDR for Fake DNS IP assignment").Base(err).AtError()
|
||||
}
|
||||
|
||||
ones, bits := ipRange.Mask.Size()
|
||||
rooms := bits - ones
|
||||
if math.Log2(float64(lruSize)) >= float64(rooms) {
|
||||
return newError("LRU size is bigger than subnet size").AtError()
|
||||
return errors.New("LRU size is bigger than subnet size").AtError()
|
||||
}
|
||||
fkdns.domainToIP = cache.NewLru(lruSize)
|
||||
fkdns.ipRange = ipRange
|
||||
@@ -137,7 +138,7 @@ func (fkdns *Holder) GetDomainFromFakeDNS(ip net.Address) string {
|
||||
if k, ok := fkdns.domainToIP.GetKeyFromValue(ip); ok {
|
||||
return k.(string)
|
||||
}
|
||||
newError("A fake ip request to ", ip, ", however there is no matching domain name in fake DNS").AtInfo().WriteToLog()
|
||||
errors.LogInfo(context.Background(), "A fake ip request to ", ip, ", however there is no matching domain name in fake DNS")
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -192,10 +193,10 @@ 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 newError("Cannot start all fake dns pools").Base(err)
|
||||
return errors.New("Cannot start all fake dns pools").Base(err)
|
||||
}
|
||||
} else {
|
||||
return newError("invalid fakeDNS setting")
|
||||
return errors.New("invalid fakeDNS setting")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -204,7 +205,7 @@ func (h *HolderMulti) Start() error {
|
||||
func (h *HolderMulti) Close() error {
|
||||
for _, v := range h.holders {
|
||||
if err := v.Close(); err != nil {
|
||||
return newError("Cannot close all fake dns pools").Base(err)
|
||||
return errors.New("Cannot close all fake dns pools").Base(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/dns/fakedns/fakedns.proto
|
||||
|
||||
package fakedns
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package dns
|
||||
|
||||
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/strmatcher"
|
||||
"github.com/xtls/xray-core/features"
|
||||
@@ -32,7 +35,7 @@ func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDoma
|
||||
|
||||
address := ip.AsAddress()
|
||||
if address.Family().IsDomain() {
|
||||
return nil, newError("invalid domain address in static hosts: ", address.Domain()).AtWarning()
|
||||
return nil, errors.New("invalid domain address in static hosts: ", address.Domain()).AtWarning()
|
||||
}
|
||||
|
||||
sh.ips[id] = []net.Address{address}
|
||||
@@ -42,7 +45,7 @@ func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDoma
|
||||
for _, mapping := range hosts {
|
||||
matcher, err := toStrMatcher(mapping.Type, mapping.Domain)
|
||||
if err != nil {
|
||||
return nil, newError("failed to create domain matcher").Base(err)
|
||||
return nil, errors.New("failed to create domain matcher").Base(err)
|
||||
}
|
||||
id := g.Add(matcher)
|
||||
ips := make([]net.Address, 0, len(mapping.Ip)+1)
|
||||
@@ -53,12 +56,12 @@ func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDoma
|
||||
for _, ip := range mapping.Ip {
|
||||
addr := net.IPAddress(ip)
|
||||
if addr == nil {
|
||||
return nil, newError("invalid IP address in static hosts: ", ip).AtWarning()
|
||||
return nil, errors.New("invalid IP address in static hosts: ", ip).AtWarning()
|
||||
}
|
||||
ips = append(ips, addr)
|
||||
}
|
||||
default:
|
||||
return nil, newError("neither IP address nor proxied domain specified for domain: ", mapping.Domain).AtWarning()
|
||||
return nil, errors.New("neither IP address nor proxied domain specified for domain: ", mapping.Domain).AtWarning()
|
||||
}
|
||||
|
||||
sh.ips[id] = ips
|
||||
@@ -90,7 +93,7 @@ func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) [
|
||||
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
|
||||
newError("found replaced domain: ", domain, " -> ", addrs[0].Domain(), ". Try to unwrap it").AtDebug().WriteToLog()
|
||||
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 {
|
||||
|
@@ -64,7 +64,7 @@ func NewServer(dest net.Destination, dispatcher routing.Dispatcher, queryStrateg
|
||||
if dest.Network == net.Network_UDP { // UDP classic DNS mode
|
||||
return NewClassicNameServer(dest, dispatcher), nil
|
||||
}
|
||||
return nil, newError("No available name server could be created from ", dest).AtWarning()
|
||||
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.
|
||||
@@ -82,10 +82,10 @@ func NewClient(
|
||||
// Create a new server for each client for now
|
||||
server, err := NewServer(ns.Address.AsDestination(), dispatcher, ns.GetQueryStrategy())
|
||||
if err != nil {
|
||||
return newError("failed to create nameserver").Base(err).AtWarning()
|
||||
return errors.New("failed to create nameserver").Base(err).AtWarning()
|
||||
}
|
||||
|
||||
// Priotize local domains with specific TLDs or without any dot to local DNS
|
||||
// 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)
|
||||
@@ -111,7 +111,7 @@ func NewClient(
|
||||
for _, domain := range ns.PrioritizedDomain {
|
||||
domainRule, err := toStrMatcher(domain.Type, domain.Domain)
|
||||
if err != nil {
|
||||
return newError("failed to create prioritized domain").Base(err).AtWarning()
|
||||
return errors.New("failed to create prioritized domain").Base(err).AtWarning()
|
||||
}
|
||||
originalRuleIdx := ruleCurr
|
||||
if ruleCurr < len(ns.OriginalRules) {
|
||||
@@ -130,7 +130,7 @@ func NewClient(
|
||||
}
|
||||
err = updateDomainRule(domainRule, originalRuleIdx, *matcherInfos)
|
||||
if err != nil {
|
||||
return newError("failed to create prioritized domain").Base(err).AtWarning()
|
||||
return errors.New("failed to create prioritized domain").Base(err).AtWarning()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ func NewClient(
|
||||
for _, geoip := range ns.Geoip {
|
||||
matcher, err := container.Add(geoip)
|
||||
if err != nil {
|
||||
return newError("failed to create ip matcher").Base(err).AtWarning()
|
||||
return errors.New("failed to create ip matcher").Base(err).AtWarning()
|
||||
}
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
@@ -147,9 +147,9 @@ func NewClient(
|
||||
if len(clientIP) > 0 {
|
||||
switch ns.Address.Address.GetAddress().(type) {
|
||||
case *net.IPOrDomain_Domain:
|
||||
newError("DNS: client ", ns.Address.Address.GetDomain(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
|
||||
errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetDomain(), " uses clientIP ", clientIP.String())
|
||||
case *net.IPOrDomain_Ip:
|
||||
newError("DNS: client ", ns.Address.Address.GetIp(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
|
||||
errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetIp(), " uses clientIP ", clientIP.String())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ func NewSimpleClient(ctx context.Context, endpoint *net.Endpoint, clientIP net.I
|
||||
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
|
||||
server, err := NewServer(endpoint.AsDestination(), dispatcher, QueryStrategy_USE_IP)
|
||||
if err != nil {
|
||||
return newError("failed to create nameserver").Base(err).AtWarning()
|
||||
return errors.New("failed to create nameserver").Base(err).AtWarning()
|
||||
}
|
||||
client.server = server
|
||||
client.clientIP = clientIP
|
||||
@@ -179,9 +179,9 @@ func NewSimpleClient(ctx context.Context, endpoint *net.Endpoint, clientIP net.I
|
||||
if len(clientIP) > 0 {
|
||||
switch endpoint.Address.GetAddress().(type) {
|
||||
case *net.IPOrDomain_Domain:
|
||||
newError("DNS: client ", endpoint.Address.GetDomain(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
|
||||
errors.LogInfo(ctx, "DNS: client ", endpoint.Address.GetDomain(), " uses clientIP ", clientIP.String())
|
||||
case *net.IPOrDomain_Ip:
|
||||
newError("DNS: client ", endpoint.Address.GetIp(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
|
||||
errors.LogInfo(ctx, "DNS: client ", endpoint.Address.GetIp(), " uses clientIP ", clientIP.String())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ func (c *Client) MatchExpectedIPs(domain string, ips []net.IP) ([]net.IP, error)
|
||||
if len(newIps) == 0 {
|
||||
return nil, errExpectedIPNonMatch
|
||||
}
|
||||
newError("domain ", domain, " expectIPs ", newIps, " matched at server ", c.Name()).AtDebug().WriteToLog()
|
||||
errors.LogDebug(context.Background(), "domain ", domain, " expectIPs ", newIps, " matched at server ", c.Name())
|
||||
return newIps, nil
|
||||
}
|
||||
|
||||
|
@@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"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/net"
|
||||
"github.com/xtls/xray-core/common/net/cnc"
|
||||
@@ -43,7 +44,7 @@ type DoHNameServer struct {
|
||||
|
||||
// NewDoHNameServer creates DOH server object for remote resolving.
|
||||
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (*DoHNameServer, error) {
|
||||
newError("DNS: created Remote DOH client for ", url.String()).AtInfo().WriteToLog()
|
||||
errors.LogInfo(context.Background(), "DNS: created Remote DOH client for ", url.String())
|
||||
s := baseDOHNameServer(url, "DOH", queryStrategy)
|
||||
|
||||
s.dispatcher = dispatcher
|
||||
@@ -119,7 +120,7 @@ func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameSe
|
||||
Timeout: time.Second * 180,
|
||||
Transport: tr,
|
||||
}
|
||||
newError("DNS: created Local DOH client for ", url.String()).AtInfo().WriteToLog()
|
||||
errors.LogInfo(context.Background(), "DNS: created Local DOH client for ", url.String())
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -150,7 +151,7 @@ func (s *DoHNameServer) Cleanup() error {
|
||||
defer s.Unlock()
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
return newError("nothing to do. stopping...")
|
||||
return errors.New("nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for domain, record := range s.ips {
|
||||
@@ -162,7 +163,7 @@ func (s *DoHNameServer) Cleanup() error {
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog()
|
||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||
delete(s.ips, domain)
|
||||
} else {
|
||||
s.ips[domain] = record
|
||||
@@ -205,7 +206,7 @@ func (s *DoHNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog()
|
||||
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||
|
||||
if updated {
|
||||
s.ips[req.domain] = rec
|
||||
@@ -225,10 +226,10 @@ func (s *DoHNameServer) newReqID() uint16 {
|
||||
}
|
||||
|
||||
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||
newError(s.name, " querying: ", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfo(ctx, s.name, " querying: ", domain)
|
||||
|
||||
if s.name+"." == "DOH//"+domain {
|
||||
newError(s.name, " tries to resolve itself! Use IP or set \"hosts\" instead.").AtError().WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogError(ctx, s.name, " tries to resolve itself! Use IP or set \"hosts\" instead.")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -258,7 +259,7 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP n
|
||||
})
|
||||
|
||||
// forced to use mux for DOH
|
||||
// dnsCtx = session.ContextWithMuxPrefered(dnsCtx, true)
|
||||
// dnsCtx = session.ContextWithMuxPreferred(dnsCtx, true)
|
||||
|
||||
var cancel context.CancelFunc
|
||||
dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline)
|
||||
@@ -266,17 +267,17 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP n
|
||||
|
||||
b, err := dns.PackMessage(r.msg)
|
||||
if err != nil {
|
||||
newError("failed to pack dns query for ", domain).Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to pack dns query for ", domain)
|
||||
return
|
||||
}
|
||||
resp, err := s.dohHTTPSContext(dnsCtx, b.Bytes())
|
||||
if err != nil {
|
||||
newError("failed to retrieve response for ", domain).Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to retrieve response for ", domain)
|
||||
return
|
||||
}
|
||||
rec, err := parseResponse(resp)
|
||||
if err != nil {
|
||||
newError("failed to handle DOH response for ", domain).Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to handle DOH response for ", domain)
|
||||
return
|
||||
}
|
||||
s.updateIP(r, rec)
|
||||
@@ -361,11 +362,11 @@ func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net
|
||||
}
|
||||
|
||||
if disableCache {
|
||||
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
||||
} else {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||
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
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package dns
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
@@ -25,7 +26,7 @@ func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, op
|
||||
if err := core.RequireFeatures(ctx, func(fd dns.FakeDNSEngine) {
|
||||
f.fakeDNSEngine = fd
|
||||
}); err != nil {
|
||||
return nil, newError("Unable to locate a fake DNS Engine").Base(err).AtError()
|
||||
return nil, errors.New("Unable to locate a fake DNS Engine").Base(err).AtError()
|
||||
}
|
||||
}
|
||||
var ips []net.Address
|
||||
@@ -37,10 +38,10 @@ func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, op
|
||||
|
||||
netIP, err := toNetIP(ips)
|
||||
if err != nil {
|
||||
return nil, newError("Unable to convert IP to net ip").Base(err).AtError()
|
||||
return nil, errors.New("Unable to convert IP to net ip").Base(err).AtError()
|
||||
}
|
||||
|
||||
newError(f.Name(), " got answer: ", domain, " -> ", ips).AtInfo().WriteToLog()
|
||||
errors.LogInfo(ctx, f.Name(), " got answer: ", domain, " -> ", ips)
|
||||
|
||||
if len(netIP) > 0 {
|
||||
return netIP, nil
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"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"
|
||||
@@ -19,7 +20,7 @@ type LocalNameServer struct {
|
||||
const errEmptyResponse = "No address associated with hostname"
|
||||
|
||||
// QueryIP implements Server.
|
||||
func (s *LocalNameServer) QueryIP(_ context.Context, domain string, _ net.IP, option dns.IPOption, _ bool) (ips []net.IP, err error) {
|
||||
func (s *LocalNameServer) QueryIP(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)
|
||||
|
||||
@@ -28,7 +29,7 @@ func (s *LocalNameServer) QueryIP(_ context.Context, domain string, _ net.IP, op
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
newError("Localhost got answer: ", domain, " -> ", ips).AtInfo().WriteToLog()
|
||||
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})
|
||||
}
|
||||
|
||||
@@ -42,7 +43,7 @@ func (s *LocalNameServer) Name() string {
|
||||
|
||||
// NewLocalNameServer creates localdns server object for directly lookup in system DNS.
|
||||
func NewLocalNameServer() *LocalNameServer {
|
||||
newError("DNS: created localhost client").AtInfo().WriteToLog()
|
||||
errors.LogInfo(context.Background(), "DNS: created localhost client")
|
||||
return &LocalNameServer{
|
||||
client: localdns.New(),
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ import (
|
||||
"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"
|
||||
@@ -45,7 +46,7 @@ type QUICNameServer struct {
|
||||
|
||||
// NewQUICNameServer creates DNS-over-QUIC client object for local resolving
|
||||
func NewQUICNameServer(url *url.URL, queryStrategy QueryStrategy) (*QUICNameServer, error) {
|
||||
newError("DNS: created Local DNS-over-QUIC client for ", url.String()).AtInfo().WriteToLog()
|
||||
errors.LogInfo(context.Background(), "DNS: created Local DNS-over-QUIC client for ", url.String())
|
||||
|
||||
var err error
|
||||
port := net.Port(853)
|
||||
@@ -84,7 +85,7 @@ func (s *QUICNameServer) Cleanup() error {
|
||||
defer s.Unlock()
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
return newError("nothing to do. stopping...")
|
||||
return errors.New("nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for domain, record := range s.ips {
|
||||
@@ -96,7 +97,7 @@ func (s *QUICNameServer) Cleanup() error {
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog()
|
||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||
delete(s.ips, domain)
|
||||
} else {
|
||||
s.ips[domain] = record
|
||||
@@ -139,7 +140,7 @@ func (s *QUICNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog()
|
||||
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||
|
||||
if updated {
|
||||
s.ips[req.domain] = rec
|
||||
@@ -159,7 +160,7 @@ func (s *QUICNameServer) newReqID() uint16 {
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||
newError(s.name, " querying: ", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfo(ctx, s.name, " querying: ", domain)
|
||||
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||
|
||||
@@ -192,7 +193,7 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP
|
||||
|
||||
b, err := dns.PackMessage(r.msg)
|
||||
if err != nil {
|
||||
newError("failed to pack dns query").Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -203,13 +204,13 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP
|
||||
|
||||
conn, err := s.openStream(dnsCtx)
|
||||
if err != nil {
|
||||
newError("failed to open quic connection").Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to open quic connection")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = conn.Write(dnsReqBuf.Bytes())
|
||||
if err != nil {
|
||||
newError("failed to send query").Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to send query")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -219,25 +220,25 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP
|
||||
defer respBuf.Release()
|
||||
n, err := respBuf.ReadFullFrom(conn, 2)
|
||||
if err != nil && n == 0 {
|
||||
newError("failed to read response length").Base(err).AtError().WriteToLog()
|
||||
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 {
|
||||
newError("failed to parse response length").Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
||||
return
|
||||
}
|
||||
respBuf.Clear()
|
||||
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
||||
if err != nil && n == 0 {
|
||||
newError("failed to read response length").Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||
return
|
||||
}
|
||||
|
||||
rec, err := parseResponse(respBuf.Bytes())
|
||||
if err != nil {
|
||||
newError("failed to handle response").Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to handle response")
|
||||
return
|
||||
}
|
||||
s.updateIP(r, rec)
|
||||
@@ -296,11 +297,11 @@ func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP ne
|
||||
}
|
||||
|
||||
if disableCache {
|
||||
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
||||
} else {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||
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
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"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"
|
||||
@@ -114,7 +115,7 @@ func (s *TCPNameServer) Cleanup() error {
|
||||
defer s.Unlock()
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
return newError("nothing to do. stopping...")
|
||||
return errors.New("nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for domain, record := range s.ips {
|
||||
@@ -126,7 +127,7 @@ func (s *TCPNameServer) Cleanup() error {
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog()
|
||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||
delete(s.ips, domain)
|
||||
} else {
|
||||
s.ips[domain] = record
|
||||
@@ -169,7 +170,7 @@ func (s *TCPNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog()
|
||||
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||
|
||||
if updated {
|
||||
s.ips[req.domain] = rec
|
||||
@@ -189,7 +190,7 @@ func (s *TCPNameServer) newReqID() uint16 {
|
||||
}
|
||||
|
||||
func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||
newError(s.name, " querying DNS for: ", domain).AtDebug().WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogDebug(ctx, s.name, " querying DNS for: ", domain)
|
||||
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||
|
||||
@@ -219,13 +220,13 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP n
|
||||
|
||||
b, err := dns.PackMessage(r.msg)
|
||||
if err != nil {
|
||||
newError("failed to pack dns query").Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := s.dial(dnsCtx)
|
||||
if err != nil {
|
||||
newError("failed to dial namesever").Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to dial namesever")
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
@@ -236,7 +237,7 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP n
|
||||
|
||||
_, err = conn.Write(dnsReqBuf.Bytes())
|
||||
if err != nil {
|
||||
newError("failed to send query").Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to send query")
|
||||
return
|
||||
}
|
||||
dnsReqBuf.Release()
|
||||
@@ -245,25 +246,25 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP n
|
||||
defer respBuf.Release()
|
||||
n, err := respBuf.ReadFullFrom(conn, 2)
|
||||
if err != nil && n == 0 {
|
||||
newError("failed to read response length").Base(err).AtError().WriteToLog()
|
||||
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 {
|
||||
newError("failed to parse response length").Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
||||
return
|
||||
}
|
||||
respBuf.Clear()
|
||||
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
||||
if err != nil && n == 0 {
|
||||
newError("failed to read response length").Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||
return
|
||||
}
|
||||
|
||||
rec, err := parseResponse(respBuf.Bytes())
|
||||
if err != nil {
|
||||
newError("failed to parse DNS over TCP response").Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(ctx, err, "failed to parse DNS over TCP response")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -319,11 +320,11 @@ func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, clientIP net
|
||||
}
|
||||
|
||||
if disableCache {
|
||||
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
||||
} else {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||
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
|
||||
}
|
||||
|
@@ -8,11 +8,11 @@ import (
|
||||
"time"
|
||||
|
||||
"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/net"
|
||||
"github.com/xtls/xray-core/common/protocol/dns"
|
||||
udp_proto "github.com/xtls/xray-core/common/protocol/udp"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
@@ -53,7 +53,7 @@ func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher
|
||||
Execute: s.Cleanup,
|
||||
}
|
||||
s.udpServer = udp.NewDispatcher(dispatcher, s.HandleResponse)
|
||||
newError("DNS: created UDP client initialized for ", address.NetAddr()).AtInfo().WriteToLog()
|
||||
errors.LogInfo(context.Background(), "DNS: created UDP client initialized for ", address.NetAddr())
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ func (s *ClassicNameServer) Cleanup() error {
|
||||
defer s.Unlock()
|
||||
|
||||
if len(s.ips) == 0 && len(s.requests) == 0 {
|
||||
return newError(s.name, " nothing to do. stopping...")
|
||||
return errors.New(s.name, " nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for domain, record := range s.ips {
|
||||
@@ -81,7 +81,7 @@ func (s *ClassicNameServer) Cleanup() error {
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog()
|
||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||
delete(s.ips, domain)
|
||||
} else {
|
||||
s.ips[domain] = record
|
||||
@@ -109,7 +109,7 @@ func (s *ClassicNameServer) Cleanup() error {
|
||||
func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_proto.Packet) {
|
||||
ipRec, err := parseResponse(packet.Payload.Bytes())
|
||||
if err != nil {
|
||||
newError(s.name, " fail to parse responded DNS udp").AtError().WriteToLog()
|
||||
errors.LogError(ctx, s.name, " fail to parse responded DNS udp")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
||||
}
|
||||
s.Unlock()
|
||||
if !ok {
|
||||
newError(s.name, " cannot find the pending request").AtError().WriteToLog()
|
||||
errors.LogError(ctx, s.name, " cannot find the pending request")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
||||
}
|
||||
|
||||
elapsed := time.Since(req.start)
|
||||
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog()
|
||||
errors.LogInfo(ctx, s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||
if len(req.domain) > 0 && (rec.A != nil || rec.AAAA != nil) {
|
||||
s.updateIP(req.domain, &rec)
|
||||
}
|
||||
@@ -160,7 +160,7 @@ func (s *ClassicNameServer) updateIP(domain string, newRec *record) {
|
||||
}
|
||||
|
||||
if updated {
|
||||
newError(s.name, " updating IP records for domain:", domain).AtDebug().WriteToLog()
|
||||
errors.LogDebug(context.Background(), s.name, " updating IP records for domain:", domain)
|
||||
s.ips[domain] = rec
|
||||
}
|
||||
if newRec.A != nil {
|
||||
@@ -187,7 +187,7 @@ func (s *ClassicNameServer) addPendingRequest(req *dnsRequest) {
|
||||
}
|
||||
|
||||
func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||
newError(s.name, " querying DNS for: ", domain).AtDebug().WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogDebug(ctx, s.name, " querying DNS for: ", domain)
|
||||
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||
|
||||
@@ -241,11 +241,11 @@ func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP
|
||||
fqdn := Fqdn(domain)
|
||||
|
||||
if disableCache {
|
||||
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
||||
} else {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||
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
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/xtls/xray-core/app/log"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/core"
|
||||
grpc "google.golang.org/grpc"
|
||||
)
|
||||
@@ -19,13 +20,13 @@ type LoggerServer struct {
|
||||
func (s *LoggerServer) RestartLogger(ctx context.Context, request *RestartLoggerRequest) (*RestartLoggerResponse, error) {
|
||||
logger := s.V.GetFeature((*log.Instance)(nil))
|
||||
if logger == nil {
|
||||
return nil, newError("unable to get logger instance")
|
||||
return nil, errors.New("unable to get logger instance")
|
||||
}
|
||||
if err := logger.Close(); err != nil {
|
||||
return nil, newError("failed to close logger").Base(err)
|
||||
return nil, errors.New("failed to close logger").Base(err)
|
||||
}
|
||||
if err := logger.Start(); err != nil {
|
||||
return nil, newError("failed to start logger").Base(err)
|
||||
return nil, errors.New("failed to start logger").Base(err)
|
||||
}
|
||||
return &RestartLoggerResponse{}, nil
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/log/command/config.proto
|
||||
|
||||
package command
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc v4.23.1
|
||||
// - protoc v5.27.0
|
||||
// source: app/log/command/config.proto
|
||||
|
||||
package command
|
||||
|
@@ -1,9 +0,0 @@
|
||||
package command
|
||||
|
||||
import "github.com/xtls/xray-core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/log/config.proto
|
||||
|
||||
package log
|
||||
|
@@ -1,9 +0,0 @@
|
||||
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{})
|
||||
}
|
@@ -7,6 +7,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/log"
|
||||
)
|
||||
|
||||
@@ -29,13 +30,13 @@ func New(ctx context.Context, config *Config) (*Instance, error) {
|
||||
}
|
||||
log.RegisterHandler(g)
|
||||
|
||||
// start logger instantly on inited
|
||||
// other modules would log during init
|
||||
// Start logger instantly on initialization
|
||||
// Other modules would log during initialization
|
||||
if err := g.startInternal(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newError("Logger started").AtDebug().WriteToLog()
|
||||
errors.LogDebug(ctx, "Logger started")
|
||||
return g, nil
|
||||
}
|
||||
|
||||
@@ -77,10 +78,10 @@ func (g *Instance) startInternal() error {
|
||||
g.active = true
|
||||
|
||||
if err := g.initAccessLogger(); err != nil {
|
||||
return newError("failed to initialize access logger").Base(err).AtWarning()
|
||||
return errors.New("failed to initialize access logger").Base(err).AtWarning()
|
||||
}
|
||||
if err := g.initErrorLogger(); err != nil {
|
||||
return newError("failed to initialize error logger").Base(err).AtWarning()
|
||||
return errors.New("failed to initialize error logger").Base(err).AtWarning()
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -120,7 +121,7 @@ func (g *Instance) Handle(msg log.Message) {
|
||||
|
||||
// Close implements common.Closable.Close().
|
||||
func (g *Instance) Close() error {
|
||||
newError("Logger closing").AtDebug().WriteToLog()
|
||||
errors.LogDebug(context.Background(), "Logger closing")
|
||||
|
||||
g.Lock()
|
||||
defer g.Unlock()
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/log"
|
||||
)
|
||||
|
||||
@@ -19,7 +20,7 @@ var handlerCreatorMapLock = &sync.RWMutex{}
|
||||
|
||||
func RegisterHandlerCreator(logType LogType, f HandlerCreator) error {
|
||||
if f == nil {
|
||||
return newError("nil HandlerCreator")
|
||||
return errors.New("nil HandlerCreator")
|
||||
}
|
||||
|
||||
handlerCreatorMapLock.Lock()
|
||||
@@ -35,7 +36,7 @@ func createHandler(logType LogType, options HandlerCreatorOptions) (log.Handler,
|
||||
|
||||
creator, found := handlerCreatorMap[logType]
|
||||
if !found {
|
||||
return nil, newError("unable to create log handler for ", logType)
|
||||
return nil, errors.New("unable to create log handler for ", logType)
|
||||
}
|
||||
return creator(logType, options)
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/metrics/config.proto
|
||||
|
||||
package metrics
|
||||
|
@@ -1,9 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import "github.com/xtls/xray-core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
@@ -10,6 +10,7 @@ import (
|
||||
"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"
|
||||
@@ -93,12 +94,12 @@ func (p *MetricsHandler) Start() error {
|
||||
|
||||
go func() {
|
||||
if err := http.Serve(listener, http.DefaultServeMux); err != nil {
|
||||
newError("failed to start metrics server").Base(err).AtError().WriteToLog()
|
||||
errors.LogErrorInner(context.Background(), err, "failed to start metrics server")
|
||||
}
|
||||
}()
|
||||
|
||||
if err := p.ohm.RemoveHandler(context.Background(), p.tag); err != nil {
|
||||
newError("failed to remove existing handler").WriteToLog()
|
||||
errors.LogInfo(context.Background(), "failed to remove existing handler")
|
||||
}
|
||||
|
||||
return p.ohm.AddHandler(context.Background(), &Outbound{
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"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"
|
||||
@@ -31,7 +32,7 @@ func (l *OutboundListener) add(conn net.Conn) {
|
||||
func (l *OutboundListener) Accept() (net.Conn, error) {
|
||||
select {
|
||||
case <-l.done.Wait():
|
||||
return nil, newError("listen closed")
|
||||
return nil, errors.New("listen closed")
|
||||
case c := <-l.buffer:
|
||||
return c, nil
|
||||
}
|
||||
|
@@ -2,15 +2,17 @@ package burst
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/core"
|
||||
|
||||
"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"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Observer struct {
|
||||
@@ -66,7 +68,7 @@ func (o *Observer) Start() error {
|
||||
hs, ok := o.ohm.(outbound.HandlerSelector)
|
||||
if !ok {
|
||||
|
||||
return nil, newError("outbound.Manager is not a HandlerSelector")
|
||||
return nil, errors.New("outbound.Manager is not a HandlerSelector")
|
||||
}
|
||||
|
||||
outbounds := hs.Select(o.config.SubjectSelector)
|
||||
@@ -90,7 +92,7 @@ func New(ctx context.Context, config *Config) (*Observer, error) {
|
||||
outboundManager = om
|
||||
})
|
||||
if err != nil {
|
||||
return nil, newError("Cannot get depended features").Base(err)
|
||||
return nil, errors.New("Cannot get depended features").Base(err)
|
||||
}
|
||||
hp := NewHealthPing(ctx, config.PingConfig)
|
||||
return &Observer{
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/observatory/burst/config.proto
|
||||
|
||||
package burst
|
||||
|
@@ -1,9 +0,0 @@
|
||||
package burst
|
||||
|
||||
import "github.com/xtls/xray-core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
)
|
||||
|
||||
// HealthPingSettings holds settings for health Checker
|
||||
@@ -51,7 +52,7 @@ func NewHealthPing(ctx context.Context, config *HealthPingConfig) *HealthPing {
|
||||
if settings.Interval == 0 {
|
||||
settings.Interval = time.Duration(1) * time.Minute
|
||||
} else if settings.Interval < 10 {
|
||||
newError("health check interval is too small, 10s is applied").AtWarning().WriteToLog()
|
||||
errors.LogWarning(ctx, "health check interval is too small, 10s is applied")
|
||||
settings.Interval = time.Duration(10) * time.Second
|
||||
}
|
||||
if settings.SamplingCount <= 0 {
|
||||
@@ -82,7 +83,7 @@ func (h *HealthPing) StartScheduler(selector func() ([]string, error)) {
|
||||
go func() {
|
||||
tags, err := selector()
|
||||
if err != nil {
|
||||
newError("error select outbounds for initial health check: ", err).AtWarning().WriteToLog()
|
||||
errors.LogWarning(h.ctx, "error select outbounds for initial health check: ", err)
|
||||
return
|
||||
}
|
||||
h.Check(tags)
|
||||
@@ -93,7 +94,7 @@ func (h *HealthPing) StartScheduler(selector func() ([]string, error)) {
|
||||
go func() {
|
||||
tags, err := selector()
|
||||
if err != nil {
|
||||
newError("error select outbounds for scheduled health check: ", err).AtWarning().WriteToLog()
|
||||
errors.LogWarning(h.ctx, "error select outbounds for scheduled health check: ", err)
|
||||
return
|
||||
}
|
||||
h.doCheck(tags, interval, h.Settings.SamplingCount)
|
||||
@@ -125,7 +126,7 @@ func (h *HealthPing) Check(tags []string) error {
|
||||
if len(tags) == 0 {
|
||||
return nil
|
||||
}
|
||||
newError("perform one-time health check for tags ", tags).AtInfo().WriteToLog()
|
||||
errors.LogInfo(h.ctx, "perform one-time health check for tags ", tags)
|
||||
h.doCheck(tags, 0, 1)
|
||||
return nil
|
||||
}
|
||||
@@ -158,7 +159,7 @@ func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int)
|
||||
delay = time.Duration(dice.Roll(int(duration)))
|
||||
}
|
||||
time.AfterFunc(delay, func() {
|
||||
newError("checking ", handler).AtDebug().WriteToLog()
|
||||
errors.LogDebug(h.ctx, "checking ", handler)
|
||||
delay, err := client.MeasureDelay()
|
||||
if err == nil {
|
||||
ch <- &rtt{
|
||||
@@ -168,19 +169,19 @@ func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int)
|
||||
return
|
||||
}
|
||||
if !h.checkConnectivity() {
|
||||
newError("network is down").AtWarning().WriteToLog()
|
||||
errors.LogWarning(h.ctx, "network is down")
|
||||
ch <- &rtt{
|
||||
handler: handler,
|
||||
value: 0,
|
||||
}
|
||||
return
|
||||
}
|
||||
newError(fmt.Sprintf(
|
||||
errors.LogWarning(h.ctx, fmt.Sprintf(
|
||||
"error ping %s with %s: %s",
|
||||
h.Settings.Destination,
|
||||
handler,
|
||||
err,
|
||||
)).AtWarning().WriteToLog()
|
||||
))
|
||||
ch <- &rtt{
|
||||
handler: handler,
|
||||
value: rttFailed,
|
||||
@@ -208,7 +209,7 @@ func (h *HealthPing) PutResult(tag string, rtt time.Duration) {
|
||||
if !ok {
|
||||
// validity is 2 times to sampling period, since the check are
|
||||
// distributed in the time line randomly, in extreme cases,
|
||||
// previous checks are distributed on the left, and latters
|
||||
// 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)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/observatory/command/command.proto
|
||||
|
||||
package command
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc v4.23.1
|
||||
// - protoc v5.27.0
|
||||
// source: app/observatory/command/command.proto
|
||||
|
||||
package command
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/observatory/config.proto
|
||||
|
||||
package observatory
|
||||
|
@@ -1,9 +0,0 @@
|
||||
package observatory
|
||||
|
||||
import "github.com/xtls/xray-core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
@@ -8,10 +8,10 @@ type errorCollector struct {
|
||||
|
||||
func (e *errorCollector) SubmitError(err error) {
|
||||
if e.errors == nil {
|
||||
e.errors = newError("underlying connection error").Base(err)
|
||||
e.errors = errors.New("underlying connection error").Base(err)
|
||||
return
|
||||
}
|
||||
e.errors = e.errors.Base(newError("underlying connection error").Base(err))
|
||||
e.errors = e.errors.Base(errors.New("underlying connection error").Base(err))
|
||||
}
|
||||
|
||||
func newErrorCollector() *errorCollector {
|
||||
@@ -20,7 +20,7 @@ func newErrorCollector() *errorCollector {
|
||||
|
||||
func (e *errorCollector) UnderlyingError() error {
|
||||
if e.errors == nil {
|
||||
return newError("failed to produce report")
|
||||
return errors.New("failed to produce report")
|
||||
}
|
||||
return e.errors
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"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"
|
||||
@@ -60,7 +61,7 @@ func (o *Observer) background() {
|
||||
for !o.finished.Done() {
|
||||
hs, ok := o.ohm.(outbound.HandlerSelector)
|
||||
if !ok {
|
||||
newError("outbound.Manager is not a HandlerSelector").WriteToLog()
|
||||
errors.LogInfo(o.ctx, "outbound.Manager is not a HandlerSelector")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -127,18 +128,18 @@ func (o *Observer) probe(outbound string) ProbeResult {
|
||||
// MUST use Xray's built in context system
|
||||
dest, err := v2net.ParseDestination(network + ":" + addr)
|
||||
if err != nil {
|
||||
return newError("cannot understand address").Base(err)
|
||||
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 newError("cannot dial remote address ", dest).Base(err)
|
||||
return errors.New("cannot dial remote address ", dest).Base(err)
|
||||
}
|
||||
connection = conn
|
||||
return nil
|
||||
})
|
||||
if taskErr != nil {
|
||||
return nil, newError("cannot finish connection").Base(taskErr)
|
||||
return nil, errors.New("cannot finish connection").Base(taskErr)
|
||||
}
|
||||
return connection, nil
|
||||
},
|
||||
@@ -161,7 +162,7 @@ func (o *Observer) probe(outbound string) ProbeResult {
|
||||
}
|
||||
response, err := httpClient.Get(probeURL)
|
||||
if err != nil {
|
||||
return newError("outbound failed to relay connection").Base(err)
|
||||
return errors.New("outbound failed to relay connection").Base(err)
|
||||
}
|
||||
if response.Body != nil {
|
||||
response.Body.Close()
|
||||
@@ -171,15 +172,11 @@ func (o *Observer) probe(outbound string) ProbeResult {
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
fullerr := newError("underlying connection failed").Base(errorCollectorForRequest.UnderlyingError())
|
||||
fullerr = newError("with outbound handler report").Base(fullerr)
|
||||
fullerr = newError("GET request failed:", err).Base(fullerr)
|
||||
fullerr = newError("the outbound ", outbound, " is dead:").Base(fullerr)
|
||||
fullerr = fullerr.AtInfo()
|
||||
fullerr.WriteToLog()
|
||||
return ProbeResult{Alive: false, LastErrorReason: fullerr.Error()}
|
||||
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}
|
||||
}
|
||||
newError("the outbound ", outbound, " is alive:", GETTime.Seconds()).AtInfo().WriteToLog()
|
||||
errors.LogInfo(o.ctx, "the outbound ", outbound, " is alive:", GETTime.Seconds())
|
||||
return ProbeResult{Alive: true, Delay: GETTime.Milliseconds()}
|
||||
}
|
||||
|
||||
@@ -222,7 +219,7 @@ func New(ctx context.Context, config *Config) (*Observer, error) {
|
||||
outboundManager = om
|
||||
})
|
||||
if err != nil {
|
||||
return nil, newError("Cannot get depended features").Base(err)
|
||||
return nil, errors.New("Cannot get depended features").Base(err)
|
||||
}
|
||||
return &Observer{
|
||||
config: config,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/policy/config.proto
|
||||
|
||||
package policy
|
||||
|
@@ -1,9 +0,0 @@
|
||||
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{})
|
||||
}
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/inbound"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
@@ -26,7 +27,7 @@ type OutboundOperation interface {
|
||||
func getInbound(handler inbound.Handler) (proxy.Inbound, error) {
|
||||
gi, ok := handler.(proxy.GetInbound)
|
||||
if !ok {
|
||||
return nil, newError("can't get inbound proxy from handler.")
|
||||
return nil, errors.New("can't get inbound proxy from handler.")
|
||||
}
|
||||
return gi.GetInbound(), nil
|
||||
}
|
||||
@@ -39,11 +40,11 @@ func (op *AddUserOperation) ApplyInbound(ctx context.Context, handler inbound.Ha
|
||||
}
|
||||
um, ok := p.(proxy.UserManager)
|
||||
if !ok {
|
||||
return newError("proxy is not a UserManager")
|
||||
return errors.New("proxy is not a UserManager")
|
||||
}
|
||||
mUser, err := op.User.ToMemoryUser()
|
||||
if err != nil {
|
||||
return newError("failed to parse user").Base(err)
|
||||
return errors.New("failed to parse user").Base(err)
|
||||
}
|
||||
return um.AddUser(ctx, mUser)
|
||||
}
|
||||
@@ -56,7 +57,7 @@ func (op *RemoveUserOperation) ApplyInbound(ctx context.Context, handler inbound
|
||||
}
|
||||
um, ok := p.(proxy.UserManager)
|
||||
if !ok {
|
||||
return newError("proxy is not a UserManager")
|
||||
return errors.New("proxy is not a UserManager")
|
||||
}
|
||||
return um.RemoveUser(ctx, op.Email)
|
||||
}
|
||||
@@ -82,16 +83,16 @@ func (s *handlerServer) RemoveInbound(ctx context.Context, request *RemoveInboun
|
||||
func (s *handlerServer) AlterInbound(ctx context.Context, request *AlterInboundRequest) (*AlterInboundResponse, error) {
|
||||
rawOperation, err := request.Operation.GetInstance()
|
||||
if err != nil {
|
||||
return nil, newError("unknown operation").Base(err)
|
||||
return nil, errors.New("unknown operation").Base(err)
|
||||
}
|
||||
operation, ok := rawOperation.(InboundOperation)
|
||||
if !ok {
|
||||
return nil, newError("not an inbound operation")
|
||||
return nil, errors.New("not an inbound operation")
|
||||
}
|
||||
|
||||
handler, err := s.ihm.GetHandler(ctx, request.Tag)
|
||||
if err != nil {
|
||||
return nil, newError("failed to get handler: ", request.Tag).Base(err)
|
||||
return nil, errors.New("failed to get handler: ", request.Tag).Base(err)
|
||||
}
|
||||
|
||||
return &AlterInboundResponse{}, operation.ApplyInbound(ctx, handler)
|
||||
@@ -111,11 +112,11 @@ func (s *handlerServer) RemoveOutbound(ctx context.Context, request *RemoveOutbo
|
||||
func (s *handlerServer) AlterOutbound(ctx context.Context, request *AlterOutboundRequest) (*AlterOutboundResponse, error) {
|
||||
rawOperation, err := request.Operation.GetInstance()
|
||||
if err != nil {
|
||||
return nil, newError("unknown operation").Base(err)
|
||||
return nil, errors.New("unknown operation").Base(err)
|
||||
}
|
||||
operation, ok := rawOperation.(OutboundOperation)
|
||||
if !ok {
|
||||
return nil, newError("not an outbound operation")
|
||||
return nil, errors.New("not an outbound operation")
|
||||
}
|
||||
|
||||
handler := s.ohm.GetHandler(request.Tag)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/proxyman/command/command.proto
|
||||
|
||||
package command
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc v4.23.1
|
||||
// - protoc v5.27.0
|
||||
// source: app/proxyman/command/command.proto
|
||||
|
||||
package command
|
||||
|
@@ -1,9 +0,0 @@
|
||||
package command
|
||||
|
||||
import "github.com/xtls/xray-core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/proxyman/config.proto
|
||||
|
||||
package proxyman
|
||||
|
@@ -55,7 +55,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
||||
}
|
||||
p, ok := rawProxy.(proxy.Inbound)
|
||||
if !ok {
|
||||
return nil, newError("not an inbound proxy.")
|
||||
return nil, errors.New("not an inbound proxy.")
|
||||
}
|
||||
|
||||
h := &AlwaysOnInboundHandler{
|
||||
@@ -75,7 +75,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
||||
|
||||
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
||||
if err != nil {
|
||||
return nil, newError("failed to parse stream config").Base(err).AtWarning()
|
||||
return nil, errors.New("failed to parse stream config").Base(err).AtWarning()
|
||||
}
|
||||
|
||||
if receiverConfig.ReceiveOriginalDestination {
|
||||
@@ -89,7 +89,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
||||
}
|
||||
if pl == nil {
|
||||
if net.HasNetwork(nl, net.Network_UNIX) {
|
||||
newError("creating unix domain socket worker on ", address).AtDebug().WriteToLog()
|
||||
errors.LogDebug(ctx, "creating unix domain socket worker on ", address)
|
||||
|
||||
worker := &dsWorker{
|
||||
address: address,
|
||||
@@ -109,7 +109,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
||||
for _, pr := range pl.Range {
|
||||
for port := pr.From; port <= pr.To; port++ {
|
||||
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{
|
||||
address: address,
|
||||
@@ -167,7 +167,7 @@ func (h *AlwaysOnInboundHandler) Close() error {
|
||||
}
|
||||
errs = append(errs, h.mux.Close())
|
||||
if err := errors.Combine(errs...); err != nil {
|
||||
return newError("failed to close all resources").Base(err)
|
||||
return errors.New("failed to close all resources").Base(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/xtls/xray-core/app/proxyman"
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
@@ -46,7 +47,7 @@ func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *p
|
||||
|
||||
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
||||
if err != nil {
|
||||
return nil, newError("failed to parse stream settings").Base(err).AtWarning()
|
||||
return nil, errors.New("failed to parse stream settings").Base(err).AtWarning()
|
||||
}
|
||||
if receiverConfig.ReceiveOriginalDestination {
|
||||
if mss.SocketSettings == nil {
|
||||
@@ -94,7 +95,7 @@ func (h *DynamicInboundHandler) closeWorkers(workers []worker) {
|
||||
for idx, worker := range workers {
|
||||
ports2Del[idx] = worker.Port()
|
||||
if err := worker.Close(); err != nil {
|
||||
newError("failed to close worker").Base(err).WriteToLog()
|
||||
errors.LogInfoInner(h.ctx, err, "failed to close worker")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +124,7 @@ func (h *DynamicInboundHandler) refresh() error {
|
||||
port := h.allocatePort()
|
||||
rawProxy, err := core.CreateObject(h.v, h.proxyConfig)
|
||||
if err != nil {
|
||||
newError("failed to create proxy instance").Base(err).AtWarning().WriteToLog()
|
||||
errors.LogWarningInner(h.ctx, err, "failed to create proxy instance")
|
||||
continue
|
||||
}
|
||||
p := rawProxy.(proxy.Inbound)
|
||||
@@ -143,7 +144,7 @@ func (h *DynamicInboundHandler) refresh() error {
|
||||
ctx: h.ctx,
|
||||
}
|
||||
if err := worker.Start(); err != nil {
|
||||
newError("failed to create TCP worker").Base(err).AtWarning().WriteToLog()
|
||||
errors.LogWarningInner(h.ctx, err, "failed to create TCP worker")
|
||||
continue
|
||||
}
|
||||
workers = append(workers, worker)
|
||||
@@ -163,7 +164,7 @@ func (h *DynamicInboundHandler) refresh() error {
|
||||
ctx: h.ctx,
|
||||
}
|
||||
if err := worker.Start(); err != nil {
|
||||
newError("failed to create UDP worker").Base(err).AtWarning().WriteToLog()
|
||||
errors.LogWarningInner(h.ctx, err, "failed to create UDP worker")
|
||||
continue
|
||||
}
|
||||
workers = append(workers, worker)
|
||||
|
@@ -1,9 +0,0 @@
|
||||
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{})
|
||||
}
|
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/xtls/xray-core/app/proxyman"
|
||||
"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/session"
|
||||
"github.com/xtls/xray-core/core"
|
||||
@@ -43,7 +44,7 @@ func (m *Manager) AddHandler(ctx context.Context, handler inbound.Handler) error
|
||||
tag := handler.Tag()
|
||||
if len(tag) > 0 {
|
||||
if _, found := m.taggedHandlers[tag]; found {
|
||||
return newError("existing tag found: " + tag)
|
||||
return errors.New("existing tag found: " + tag)
|
||||
}
|
||||
m.taggedHandlers[tag] = handler
|
||||
} else {
|
||||
@@ -64,7 +65,7 @@ func (m *Manager) GetHandler(ctx context.Context, tag string) (inbound.Handler,
|
||||
|
||||
handler, found := m.taggedHandlers[tag]
|
||||
if !found {
|
||||
return nil, newError("handler not found: ", tag)
|
||||
return nil, errors.New("handler not found: ", tag)
|
||||
}
|
||||
return handler, nil
|
||||
}
|
||||
@@ -80,7 +81,7 @@ func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
|
||||
|
||||
if handler, found := m.taggedHandlers[tag]; found {
|
||||
if err := handler.Close(); err != nil {
|
||||
newError("failed to close handler ", tag).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogWarningInner(ctx, err, "failed to close handler ", tag)
|
||||
}
|
||||
delete(m.taggedHandlers, tag)
|
||||
return nil
|
||||
@@ -117,20 +118,20 @@ func (m *Manager) Close() error {
|
||||
|
||||
m.running = false
|
||||
|
||||
var errors []interface{}
|
||||
var errs []interface{}
|
||||
for _, handler := range m.taggedHandlers {
|
||||
if err := handler.Close(); err != nil {
|
||||
errors = append(errors, err)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
for _, handler := range m.untaggedHandler {
|
||||
if err := handler.Close(); err != nil {
|
||||
errors = append(errors, err)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return newError("failed to close all handlers").Base(newError(serial.Concat(errors...)))
|
||||
if len(errs) > 0 {
|
||||
return errors.New("failed to close all handlers").Base(errors.New(serial.Concat(errs...)))
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -150,7 +151,7 @@ func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound
|
||||
|
||||
receiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig)
|
||||
if !ok {
|
||||
return nil, newError("not a ReceiverConfig").AtError()
|
||||
return nil, errors.New("not a ReceiverConfig").AtError()
|
||||
}
|
||||
|
||||
streamSettings := receiverSettings.StreamSettings
|
||||
@@ -168,7 +169,7 @@ func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound
|
||||
if allocStrategy.Type == proxyman.AllocationStrategy_Random {
|
||||
return NewDynamicInboundHandler(ctx, tag, receiverSettings, proxySettings)
|
||||
}
|
||||
return nil, newError("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).AtError()
|
||||
return nil, errors.New("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).AtError()
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@@ -9,6 +9,8 @@ import (
|
||||
"github.com/xtls/xray-core/app/proxyman"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"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/serial"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
@@ -58,16 +60,16 @@ func getTProxyType(s *internet.MemoryStreamConfig) internet.SocketConfig_TProxyM
|
||||
func (w *tcpWorker) callback(conn stat.Connection) {
|
||||
ctx, cancel := context.WithCancel(w.ctx)
|
||||
sid := session.NewID()
|
||||
ctx = session.ContextWithID(ctx, sid)
|
||||
ctx = c.ContextWithID(ctx, sid)
|
||||
|
||||
var outbound = &session.Outbound{}
|
||||
outbounds := []*session.Outbound{{}}
|
||||
if w.recvOrigDest {
|
||||
var dest net.Destination
|
||||
switch getTProxyType(w.stream) {
|
||||
case internet.SocketConfig_Redirect:
|
||||
d, err := tcp.GetOriginalDestination(conn)
|
||||
if err != nil {
|
||||
newError("failed to get original destination").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfoInner(ctx, err, "failed to get original destination")
|
||||
} else {
|
||||
dest = d
|
||||
}
|
||||
@@ -75,10 +77,10 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
||||
dest = net.DestinationFromAddr(conn.LocalAddr())
|
||||
}
|
||||
if dest.IsValid() {
|
||||
outbound.Target = dest
|
||||
outbounds[0].Target = dest
|
||||
}
|
||||
}
|
||||
ctx = session.ContextWithOutbound(ctx, outbound)
|
||||
ctx = session.ContextWithOutbounds(ctx, outbounds)
|
||||
|
||||
if w.uplinkCounter != nil || w.downlinkCounter != nil {
|
||||
conn = &stat.CounterConnection{
|
||||
@@ -105,7 +107,7 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
||||
ctx = session.ContextWithContent(ctx, content)
|
||||
|
||||
if err := w.proxy.Process(ctx, net.Network_TCP, conn, w.dispatcher); err != nil {
|
||||
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfoInner(ctx, err, "connection ends")
|
||||
}
|
||||
cancel()
|
||||
conn.Close()
|
||||
@@ -121,24 +123,24 @@ func (w *tcpWorker) Start() error {
|
||||
go w.callback(conn)
|
||||
})
|
||||
if err != nil {
|
||||
return newError("failed to listen TCP on ", w.port).AtWarning().Base(err)
|
||||
return errors.New("failed to listen TCP on ", w.port).AtWarning().Base(err)
|
||||
}
|
||||
w.hub = hub
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *tcpWorker) Close() error {
|
||||
var errors []interface{}
|
||||
var errs []interface{}
|
||||
if w.hub != nil {
|
||||
if err := common.Close(w.hub); err != nil {
|
||||
errors = append(errors, err)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := common.Close(w.proxy); err != nil {
|
||||
errors = append(errors, err)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
return newError("failed to close all resources").Base(newError(serial.Concat(errors...)))
|
||||
if len(errs) > 0 {
|
||||
return errors.New("failed to close all resources").Base(errors.New(serial.Concat(errs...)))
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -306,13 +308,13 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
||||
go func() {
|
||||
ctx := w.ctx
|
||||
sid := session.NewID()
|
||||
ctx = session.ContextWithID(ctx, sid)
|
||||
ctx = c.ContextWithID(ctx, sid)
|
||||
|
||||
outbounds := []*session.Outbound{{}}
|
||||
if originalDest.IsValid() {
|
||||
ctx = session.ContextWithOutbound(ctx, &session.Outbound{
|
||||
Target: originalDest,
|
||||
})
|
||||
outbounds[0].Target = originalDest
|
||||
}
|
||||
ctx = session.ContextWithOutbounds(ctx, outbounds)
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||
Source: source,
|
||||
Gateway: net.UDPDestination(w.address, w.port),
|
||||
@@ -327,7 +329,7 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
||||
}
|
||||
ctx = session.ContextWithContent(ctx, content)
|
||||
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
|
||||
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfoInner(ctx, err, "connection ends")
|
||||
}
|
||||
conn.Close()
|
||||
// conn not removed by checker TODO may be lock worker here is better
|
||||
@@ -358,7 +360,7 @@ func (w *udpWorker) clean() error {
|
||||
defer w.Unlock()
|
||||
|
||||
if len(w.activeConn) == 0 {
|
||||
return newError("no more connections. stopping...")
|
||||
return errors.New("no more connections. stopping...")
|
||||
}
|
||||
|
||||
for addr, conn := range w.activeConn {
|
||||
@@ -402,26 +404,26 @@ func (w *udpWorker) Close() error {
|
||||
w.Lock()
|
||||
defer w.Unlock()
|
||||
|
||||
var errors []interface{}
|
||||
var errs []interface{}
|
||||
|
||||
if w.hub != nil {
|
||||
if err := w.hub.Close(); err != nil {
|
||||
errors = append(errors, err)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if w.checker != nil {
|
||||
if err := w.checker.Close(); err != nil {
|
||||
errors = append(errors, err)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := common.Close(w.proxy); err != nil {
|
||||
errors = append(errors, err)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return newError("failed to close all resources").Base(newError(serial.Concat(errors...)))
|
||||
if len(errs) > 0 {
|
||||
return errors.New("failed to close all resources").Base(errors.New(serial.Concat(errs...)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -452,7 +454,7 @@ type dsWorker struct {
|
||||
func (w *dsWorker) callback(conn stat.Connection) {
|
||||
ctx, cancel := context.WithCancel(w.ctx)
|
||||
sid := session.NewID()
|
||||
ctx = session.ContextWithID(ctx, sid)
|
||||
ctx = c.ContextWithID(ctx, sid)
|
||||
|
||||
if w.uplinkCounter != nil || w.downlinkCounter != nil {
|
||||
conn = &stat.CounterConnection{
|
||||
@@ -479,11 +481,11 @@ func (w *dsWorker) callback(conn stat.Connection) {
|
||||
ctx = session.ContextWithContent(ctx, content)
|
||||
|
||||
if err := w.proxy.Process(ctx, net.Network_UNIX, conn, w.dispatcher); err != nil {
|
||||
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfoInner(ctx, err, "connection ends")
|
||||
}
|
||||
cancel()
|
||||
if err := conn.Close(); err != nil {
|
||||
newError("failed to close connection").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfoInner(ctx, err, "failed to close connection")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,24 +503,24 @@ func (w *dsWorker) Start() error {
|
||||
go w.callback(conn)
|
||||
})
|
||||
if err != nil {
|
||||
return newError("failed to listen Unix Domain Socket on ", w.address).AtWarning().Base(err)
|
||||
return errors.New("failed to listen Unix Domain Socket on ", w.address).AtWarning().Base(err)
|
||||
}
|
||||
w.hub = hub
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *dsWorker) Close() error {
|
||||
var errors []interface{}
|
||||
var errs []interface{}
|
||||
if w.hub != nil {
|
||||
if err := common.Close(w.hub); err != nil {
|
||||
errors = append(errors, err)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := common.Close(w.proxy); err != nil {
|
||||
errors = append(errors, err)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
return newError("failed to close all resources").Base(newError(serial.Concat(errors...)))
|
||||
if len(errs) > 0 {
|
||||
return errors.New("failed to close all resources").Base(errors.New(serial.Concat(errs...)))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@@ -1,9 +0,0 @@
|
||||
package outbound
|
||||
|
||||
import "github.com/xtls/xray-core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
@@ -2,14 +2,16 @@ package outbound
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"crypto/rand"
|
||||
goerrors "errors"
|
||||
"io"
|
||||
"math/rand"
|
||||
"math/big"
|
||||
gonet "net"
|
||||
"os"
|
||||
|
||||
"github.com/xtls/xray-core/app/proxyman"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
@@ -87,11 +89,11 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
||||
h.senderSettings = s
|
||||
mss, err := internet.ToMemoryStreamConfig(s.StreamSettings)
|
||||
if err != nil {
|
||||
return nil, newError("failed to parse stream settings").Base(err).AtWarning()
|
||||
return nil, errors.New("failed to parse stream settings").Base(err).AtWarning()
|
||||
}
|
||||
h.streamSettings = mss
|
||||
default:
|
||||
return nil, newError("settings is not SenderConfig")
|
||||
return nil, errors.New("settings is not SenderConfig")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +109,7 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
||||
|
||||
proxyHandler, ok := rawProxyHandler.(proxy.Outbound)
|
||||
if !ok {
|
||||
return nil, newError("not an outbound handler")
|
||||
return nil, errors.New("not an outbound handler")
|
||||
}
|
||||
|
||||
if h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil {
|
||||
@@ -169,30 +171,31 @@ func (h *Handler) Tag() string {
|
||||
|
||||
// Dispatch implements proxy.Outbound.Dispatch.
|
||||
func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound.Target.Network == net.Network_UDP && outbound.OriginalTarget.Address != nil && outbound.OriginalTarget.Address != outbound.Target.Address {
|
||||
link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: outbound.Target.Address, OriginalDest: outbound.OriginalTarget.Address}
|
||||
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: outbound.Target.Address, OriginalDest: outbound.OriginalTarget.Address}
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil && ob.OriginalTarget.Address != ob.Target.Address {
|
||||
link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
||||
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
||||
}
|
||||
if h.mux != nil {
|
||||
test := func(err error) {
|
||||
if err != nil {
|
||||
err := newError("failed to process mux outbound traffic").Base(err)
|
||||
err := errors.New("failed to process mux outbound traffic").Base(err)
|
||||
session.SubmitOutboundErrorToOriginator(ctx, err)
|
||||
err.WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfo(ctx, err.Error())
|
||||
common.Interrupt(link.Writer)
|
||||
}
|
||||
}
|
||||
if outbound.Target.Network == net.Network_UDP && outbound.Target.Port == 443 {
|
||||
if ob.Target.Network == net.Network_UDP && ob.Target.Port == 443 {
|
||||
switch h.udp443 {
|
||||
case "reject":
|
||||
test(newError("XUDP rejected UDP/443 traffic").AtInfo())
|
||||
test(errors.New("XUDP rejected UDP/443 traffic").AtInfo())
|
||||
return
|
||||
case "skip":
|
||||
goto out
|
||||
}
|
||||
}
|
||||
if h.xudp != nil && outbound.Target.Network == net.Network_UDP {
|
||||
if h.xudp != nil && ob.Target.Network == net.Network_UDP {
|
||||
if !h.xudp.Enabled {
|
||||
goto out
|
||||
}
|
||||
@@ -207,15 +210,15 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
||||
out:
|
||||
err := h.proxy.Process(ctx, link, h)
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, context.Canceled) {
|
||||
if goerrors.Is(err, io.EOF) || goerrors.Is(err, io.ErrClosedPipe) || goerrors.Is(err, context.Canceled) {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
// Ensure outbound ray is properly closed.
|
||||
err := newError("failed to process outbound traffic").Base(err)
|
||||
err := errors.New("failed to process outbound traffic").Base(err)
|
||||
session.SubmitOutboundErrorToOriginator(ctx, err)
|
||||
err.WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfo(ctx, err.Error())
|
||||
common.Interrupt(link.Writer)
|
||||
} else {
|
||||
common.Close(link.Writer)
|
||||
@@ -242,11 +245,12 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
||||
tag := h.senderSettings.ProxySettings.Tag
|
||||
handler := h.outboundManager.GetHandler(tag)
|
||||
if handler != nil {
|
||||
newError("proxying to ", tag, " for dest ", dest).AtDebug().WriteToLog(session.ExportIDToError(ctx))
|
||||
ctx = session.ContextWithOutbound(ctx, &session.Outbound{
|
||||
errors.LogDebug(ctx, "proxying to ", tag, " for dest ", dest)
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ctx = session.ContextWithOutbounds(ctx, append(outbounds, &session.Outbound{
|
||||
Target: dest,
|
||||
})
|
||||
|
||||
Tag: tag,
|
||||
})) // add another outbound in session ctx
|
||||
opts := pipe.OptionsFromContext(ctx)
|
||||
uplinkReader, uplinkWriter := pipe.New(opts...)
|
||||
downlinkReader, downlinkWriter := pipe.New(opts...)
|
||||
@@ -262,19 +266,16 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
||||
return h.getStatCouterConnection(conn), nil
|
||||
}
|
||||
|
||||
newError("failed to get outbound handler with tag: ", tag).AtWarning().WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogWarning(ctx, "failed to get outbound handler with tag: ", tag)
|
||||
}
|
||||
|
||||
if h.senderSettings.Via != nil {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil {
|
||||
outbound = new(session.Outbound)
|
||||
ctx = session.ContextWithOutbound(ctx, outbound)
|
||||
}
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
if h.senderSettings.ViaCidr == "" {
|
||||
outbound.Gateway = h.senderSettings.Via.AsAddress()
|
||||
ob.Gateway = h.senderSettings.Via.AsAddress()
|
||||
} else { //Get a random address.
|
||||
outbound.Gateway = ParseRandomIPv6(h.senderSettings.Via.AsAddress(), h.senderSettings.ViaCidr)
|
||||
ob.Gateway = ParseRandomIPv6(h.senderSettings.Via.AsAddress(), h.senderSettings.ViaCidr)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -285,10 +286,9 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
||||
|
||||
conn, err := internet.Dial(ctx, dest, h.streamSettings)
|
||||
conn = h.getStatCouterConnection(conn)
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound != nil {
|
||||
outbound.Conn = conn
|
||||
}
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
ob.Conn = conn
|
||||
return conn, err
|
||||
}
|
||||
|
||||
@@ -319,16 +319,20 @@ func (h *Handler) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return random IPv6 in a CIDR block
|
||||
func ParseRandomIPv6(address net.Address, prefix string) net.Address {
|
||||
addr := address.IP().String()
|
||||
_, network, _ := gonet.ParseCIDR(addr + "/" + prefix)
|
||||
_, network, _ := gonet.ParseCIDR(address.IP().String() + "/" + prefix)
|
||||
|
||||
ipv6 := network.IP.To16()
|
||||
prefixLen, _ := network.Mask.Size()
|
||||
for i := prefixLen / 8; i < 16; i++ {
|
||||
ipv6[i] = byte(rand.Intn(256))
|
||||
}
|
||||
maskSize, totalBits := network.Mask.Size()
|
||||
subnetSize := big.NewInt(1).Lsh(big.NewInt(1), uint(totalBits-maskSize))
|
||||
|
||||
return net.ParseAddress(gonet.IP(ipv6).String())
|
||||
// random
|
||||
randomBigInt, _ := rand.Int(rand.Reader, subnetSize)
|
||||
|
||||
startIPBigInt := big.NewInt(0).SetBytes(network.IP.To16())
|
||||
randomIPBigInt := big.NewInt(0).Add(startIPBigInt, randomBigInt)
|
||||
|
||||
randomIPBytes := randomIPBigInt.Bytes()
|
||||
randomIPBytes = append(make([]byte, 16-len(randomIPBytes)), randomIPBytes...)
|
||||
|
||||
return net.ParseAddress(gonet.IP(randomIPBytes).String())
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/xtls/xray-core/app/stats"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
core "github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
"github.com/xtls/xray-core/proxy/freedom"
|
||||
@@ -44,6 +45,7 @@ func TestOutboundWithoutStatCounter(t *testing.T) {
|
||||
v, _ := core.New(config)
|
||||
v.AddFeature((outbound.Manager)(new(Manager)))
|
||||
ctx := context.WithValue(context.Background(), xrayKey, v)
|
||||
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})
|
||||
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
|
||||
Tag: "tag",
|
||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||
@@ -73,6 +75,7 @@ func TestOutboundWithStatCounter(t *testing.T) {
|
||||
v, _ := core.New(config)
|
||||
v.AddFeature((outbound.Manager)(new(Manager)))
|
||||
ctx := context.WithValue(context.Background(), xrayKey, v)
|
||||
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})
|
||||
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
|
||||
Tag: "tag",
|
||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||
|
@@ -115,7 +115,7 @@ func (m *Manager) AddHandler(ctx context.Context, handler outbound.Handler) erro
|
||||
tag := handler.Tag()
|
||||
if len(tag) > 0 {
|
||||
if _, found := m.taggedHandler[tag]; found {
|
||||
return newError("existing tag found: " + tag)
|
||||
return errors.New("existing tag found: " + tag)
|
||||
}
|
||||
m.taggedHandler[tag] = handler
|
||||
} else {
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/sagernet/sing/common/uot"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
@@ -12,7 +13,7 @@ import (
|
||||
|
||||
func (h *Handler) getUoTConnection(ctx context.Context, dest net.Destination) (stat.Connection, error) {
|
||||
if dest.Address == nil {
|
||||
return nil, newError("nil destination address")
|
||||
return nil, errors.New("nil destination address")
|
||||
}
|
||||
if !dest.Address.Family().IsDomain() {
|
||||
return nil, os.ErrInvalid
|
||||
@@ -27,7 +28,7 @@ func (h *Handler) getUoTConnection(ctx context.Context, dest net.Destination) (s
|
||||
}
|
||||
packetConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{IP: net.AnyIP.IP(), Port: 0}, h.streamSettings.SocketSettings)
|
||||
if err != nil {
|
||||
return nil, newError("unable to listen socket").Base(err)
|
||||
return nil, errors.New("unable to listen socket").Base(err)
|
||||
}
|
||||
conn := uot.NewServerConn(packetConn, uotVersion)
|
||||
return h.getStatCouterConnection(conn), nil
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
@@ -26,10 +27,10 @@ type Bridge struct {
|
||||
// NewBridge creates a new Bridge instance.
|
||||
func NewBridge(config *BridgeConfig, dispatcher routing.Dispatcher) (*Bridge, error) {
|
||||
if config.Tag == "" {
|
||||
return nil, newError("bridge tag is empty")
|
||||
return nil, errors.New("bridge tag is empty")
|
||||
}
|
||||
if config.Domain == "" {
|
||||
return nil, newError("bridge domain is empty")
|
||||
return nil, errors.New("bridge domain is empty")
|
||||
}
|
||||
|
||||
b := &Bridge{
|
||||
@@ -74,7 +75,7 @@ func (b *Bridge) monitor() error {
|
||||
if numWorker == 0 || numConnections/numWorker > 16 {
|
||||
worker, err := NewBridgeWorker(b.domain, b.tag, b.dispatcher)
|
||||
if err != nil {
|
||||
newError("failed to create bridge worker").Base(err).AtWarning().WriteToLog()
|
||||
errors.LogWarningInner(context.Background(), err, "failed to create bridge worker")
|
||||
return nil
|
||||
}
|
||||
b.workers = append(b.workers, worker)
|
||||
@@ -157,7 +158,7 @@ func (w *BridgeWorker) handleInternalConn(link *transport.Link) {
|
||||
for _, b := range mb {
|
||||
var ctl Control
|
||||
if err := proto.Unmarshal(b.Bytes(), &ctl); err != nil {
|
||||
newError("failed to parse proto message").Base(err).WriteToLog()
|
||||
errors.LogInfoInner(context.Background(), err, "failed to parse proto message")
|
||||
break
|
||||
}
|
||||
if ctl.State != w.state {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/reverse/config.proto
|
||||
|
||||
package reverse
|
||||
|
@@ -1,9 +0,0 @@
|
||||
package reverse
|
||||
|
||||
import "github.com/xtls/xray-core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"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/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
@@ -27,11 +28,11 @@ type Portal struct {
|
||||
|
||||
func NewPortal(config *PortalConfig, ohm outbound.Manager) (*Portal, error) {
|
||||
if config.Tag == "" {
|
||||
return nil, newError("portal tag is empty")
|
||||
return nil, errors.New("portal tag is empty")
|
||||
}
|
||||
|
||||
if config.Domain == "" {
|
||||
return nil, newError("portal domain is empty")
|
||||
return nil, errors.New("portal domain is empty")
|
||||
}
|
||||
|
||||
picker, err := NewStaticMuxPicker()
|
||||
@@ -62,20 +63,21 @@ func (p *Portal) Close() error {
|
||||
}
|
||||
|
||||
func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) error {
|
||||
outboundMeta := session.OutboundFromContext(ctx)
|
||||
if outboundMeta == nil {
|
||||
return newError("outbound metadata not found").AtError()
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
if ob == nil {
|
||||
return errors.New("outbound metadata not found").AtError()
|
||||
}
|
||||
|
||||
if isDomain(outboundMeta.Target, p.domain) {
|
||||
if isDomain(ob.Target, p.domain) {
|
||||
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
|
||||
if err != nil {
|
||||
return newError("failed to create mux client worker").Base(err).AtWarning()
|
||||
return errors.New("failed to create mux client worker").Base(err).AtWarning()
|
||||
}
|
||||
|
||||
worker, err := NewPortalWorker(muxClient)
|
||||
if err != nil {
|
||||
return newError("failed to create portal worker").Base(err)
|
||||
return errors.New("failed to create portal worker").Base(err)
|
||||
}
|
||||
|
||||
p.picker.AddWorker(worker)
|
||||
@@ -96,7 +98,7 @@ func (o *Outbound) Tag() string {
|
||||
|
||||
func (o *Outbound) Dispatch(ctx context.Context, link *transport.Link) {
|
||||
if err := o.portal.HandleConnection(ctx, link); err != nil {
|
||||
newError("failed to process reverse connection").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||
errors.LogInfoInner(ctx, err, "failed to process reverse connection")
|
||||
common.Interrupt(link.Writer)
|
||||
}
|
||||
}
|
||||
@@ -148,7 +150,7 @@ func (p *StaticMuxPicker) PickAvailable() (*mux.ClientWorker, error) {
|
||||
defer p.access.Unlock()
|
||||
|
||||
if len(p.workers) == 0 {
|
||||
return nil, newError("empty worker list")
|
||||
return nil, errors.New("empty worker list")
|
||||
}
|
||||
|
||||
var minIdx int = -1
|
||||
@@ -182,7 +184,7 @@ func (p *StaticMuxPicker) PickAvailable() (*mux.ClientWorker, error) {
|
||||
return p.workers[minIdx].client, nil
|
||||
}
|
||||
|
||||
return nil, newError("no mux client worker available")
|
||||
return nil, errors.New("no mux client worker available")
|
||||
}
|
||||
|
||||
func (p *StaticMuxPicker) AddWorker(worker *PortalWorker) {
|
||||
@@ -206,15 +208,16 @@ func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
||||
downlinkReader, downlinkWriter := pipe.New(opt...)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = session.ContextWithOutbound(ctx, &session.Outbound{
|
||||
outbounds := []*session.Outbound{{
|
||||
Target: net.UDPDestination(net.DomainAddress(internalDomain), 0),
|
||||
})
|
||||
}}
|
||||
ctx = session.ContextWithOutbounds(ctx, outbounds)
|
||||
f := client.Dispatch(ctx, &transport.Link{
|
||||
Reader: uplinkReader,
|
||||
Writer: downlinkWriter,
|
||||
})
|
||||
if !f {
|
||||
return nil, newError("unable to dispatch control connection")
|
||||
return nil, errors.New("unable to dispatch control connection")
|
||||
}
|
||||
w := &PortalWorker{
|
||||
client: client,
|
||||
@@ -231,11 +234,11 @@ func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
||||
|
||||
func (w *PortalWorker) heartbeat() error {
|
||||
if w.client.Closed() {
|
||||
return newError("client worker stopped")
|
||||
return errors.New("client worker stopped")
|
||||
}
|
||||
|
||||
if w.draining || w.writer == nil {
|
||||
return newError("already disposed")
|
||||
return errors.New("already disposed")
|
||||
}
|
||||
|
||||
msg := &Control{}
|
||||
|
@@ -4,6 +4,10 @@ import (
|
||||
"context"
|
||||
sync "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/core"
|
||||
"github.com/xtls/xray-core/features/extension"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
)
|
||||
@@ -17,14 +21,58 @@ type BalancingPrincipleTarget interface {
|
||||
}
|
||||
|
||||
type RoundRobinStrategy struct {
|
||||
mu sync.Mutex
|
||||
index int
|
||||
FallbackTag string
|
||||
|
||||
ctx context.Context
|
||||
observatory extension.Observatory
|
||||
mu sync.Mutex
|
||||
index int
|
||||
}
|
||||
|
||||
func (s *RoundRobinStrategy) InjectContext(ctx context.Context) {
|
||||
s.ctx = ctx
|
||||
}
|
||||
|
||||
func (s *RoundRobinStrategy) GetPrincipleTarget(strings []string) []string {
|
||||
return strings
|
||||
}
|
||||
|
||||
func (s *RoundRobinStrategy) PickOutbound(tags []string) string {
|
||||
if len(s.FallbackTag) > 0 && s.observatory == nil {
|
||||
common.Must(core.RequireFeatures(s.ctx, func(observatory extension.Observatory) error {
|
||||
s.observatory = observatory
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
if s.observatory != nil {
|
||||
observeReport, err := s.observatory.GetObservation(s.ctx)
|
||||
if err == nil {
|
||||
aliveTags := make([]string, 0)
|
||||
if result, ok := observeReport.(*observatory.ObservationResult); ok {
|
||||
status := result.Status
|
||||
statusMap := make(map[string]*observatory.OutboundStatus)
|
||||
for _, outboundStatus := range status {
|
||||
statusMap[outboundStatus.OutboundTag] = outboundStatus
|
||||
}
|
||||
for _, candidate := range tags {
|
||||
if outboundStatus, found := statusMap[candidate]; found {
|
||||
if outboundStatus.Alive {
|
||||
aliveTags = append(aliveTags, candidate)
|
||||
}
|
||||
} else {
|
||||
// unfound candidate is considered alive
|
||||
aliveTags = append(aliveTags, candidate)
|
||||
}
|
||||
}
|
||||
tags = aliveTags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n := len(tags)
|
||||
if n == 0 {
|
||||
panic("0 tags")
|
||||
// goes to fallbackTag
|
||||
return ""
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
@@ -48,7 +96,7 @@ func (b *Balancer) PickOutbound() (string, error) {
|
||||
candidates, err := b.SelectOutbounds()
|
||||
if err != nil {
|
||||
if b.fallbackTag != "" {
|
||||
newError("fallback to [", b.fallbackTag, "], due to error: ", err).AtInfo().WriteToLog()
|
||||
errors.LogInfo(context.Background(), "fallback to [", b.fallbackTag, "], due to error: ", err)
|
||||
return b.fallbackTag, nil
|
||||
}
|
||||
return "", err
|
||||
@@ -61,11 +109,11 @@ func (b *Balancer) PickOutbound() (string, error) {
|
||||
}
|
||||
if tag == "" {
|
||||
if b.fallbackTag != "" {
|
||||
newError("fallback to [", b.fallbackTag, "], due to empty tag returned").AtInfo().WriteToLog()
|
||||
errors.LogInfo(context.Background(), "fallback to [", b.fallbackTag, "], due to empty tag returned")
|
||||
return b.fallbackTag, nil
|
||||
}
|
||||
// will use default handler
|
||||
return "", newError("balancing strategy returns empty tag")
|
||||
return "", errors.New("balancing strategy returns empty tag")
|
||||
}
|
||||
return tag, nil
|
||||
}
|
||||
@@ -80,7 +128,7 @@ func (b *Balancer) InjectContext(ctx context.Context) {
|
||||
func (b *Balancer) SelectOutbounds() ([]string, error) {
|
||||
hs, ok := b.ohm.(outbound.HandlerSelector)
|
||||
if !ok {
|
||||
return nil, newError("outbound.Manager is not a HandlerSelector")
|
||||
return nil, errors.New("outbound.Manager is not a HandlerSelector")
|
||||
}
|
||||
tags := hs.Select(b.selectors)
|
||||
return tags, nil
|
||||
@@ -92,13 +140,13 @@ func (r *Router) GetPrincipleTarget(tag string) ([]string, error) {
|
||||
if s, ok := b.strategy.(BalancingPrincipleTarget); ok {
|
||||
candidates, err := b.SelectOutbounds()
|
||||
if err != nil {
|
||||
return nil, newError("unable to select outbounds").Base(err)
|
||||
return nil, errors.New("unable to select outbounds").Base(err)
|
||||
}
|
||||
return s.GetPrincipleTarget(candidates), nil
|
||||
}
|
||||
return nil, newError("unsupported GetPrincipleTarget")
|
||||
return nil, errors.New("unsupported GetPrincipleTarget")
|
||||
}
|
||||
return nil, newError("cannot find tag")
|
||||
return nil, errors.New("cannot find tag")
|
||||
}
|
||||
|
||||
// SetOverrideTarget implements routing.BalancerOverrider
|
||||
@@ -107,7 +155,7 @@ func (r *Router) SetOverrideTarget(tag, target string) error {
|
||||
b.override.Put(target)
|
||||
return nil
|
||||
}
|
||||
return newError("cannot find tag")
|
||||
return errors.New("cannot find tag")
|
||||
}
|
||||
|
||||
// GetOverrideTarget implements routing.BalancerOverrider
|
||||
@@ -115,5 +163,5 @@ func (r *Router) GetOverrideTarget(tag string) (string, error) {
|
||||
if b, ok := r.balancers[tag]; ok {
|
||||
return b.override.Get(), nil
|
||||
}
|
||||
return "", newError("cannot find tag")
|
||||
return "", errors.New("cannot find tag")
|
||||
}
|
||||
|
@@ -2,6 +2,8 @@ package router
|
||||
|
||||
import (
|
||||
sync "sync"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
)
|
||||
|
||||
func (r *Router) OverrideBalancer(balancer string, target string) error {
|
||||
@@ -13,7 +15,7 @@ func (r *Router) OverrideBalancer(balancer string, target string) error {
|
||||
}
|
||||
}
|
||||
if b == nil {
|
||||
return newError("balancer '", balancer, "' not found")
|
||||
return errors.New("balancer '", balancer, "' not found")
|
||||
}
|
||||
b.override.Put(target)
|
||||
return nil
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
@@ -38,7 +39,7 @@ func (s *routingServer) GetBalancerInfo(ctx context.Context, request *GetBalance
|
||||
{
|
||||
res, err := pt.GetPrincipleTarget(request.GetTag())
|
||||
if err != nil {
|
||||
newError("unable to obtain principle target").Base(err).AtInfo().WriteToLog()
|
||||
errors.LogInfoInner(ctx, err, "unable to obtain principle target")
|
||||
} else {
|
||||
ret.Balancer.PrincipleTarget = &PrincipleTargetInfo{Tag: res}
|
||||
}
|
||||
@@ -51,21 +52,21 @@ func (s *routingServer) OverrideBalancerTarget(ctx context.Context, request *Ove
|
||||
if bo, ok := s.router.(routing.BalancerOverrider); ok {
|
||||
return &OverrideBalancerTargetResponse{}, bo.SetOverrideTarget(request.BalancerTag, request.Target)
|
||||
}
|
||||
return nil, newError("unsupported router implementation")
|
||||
return nil, errors.New("unsupported router implementation")
|
||||
}
|
||||
|
||||
func (s *routingServer) AddRule(ctx context.Context, request *AddRuleRequest) (*AddRuleResponse, error) {
|
||||
if bo, ok := s.router.(routing.Router); ok {
|
||||
return &AddRuleResponse{}, bo.AddRule(request.Config, request.ShouldAppend)
|
||||
}
|
||||
return nil, newError("unsupported router implementation")
|
||||
return nil, errors.New("unsupported router implementation")
|
||||
|
||||
}
|
||||
func (s *routingServer) RemoveRule(ctx context.Context, request *RemoveRuleRequest) (*RemoveRuleResponse, error) {
|
||||
if bo, ok := s.router.(routing.Router); ok {
|
||||
return &RemoveRuleResponse{}, bo.RemoveRule(request.RuleTag)
|
||||
}
|
||||
return nil, newError("unsupported router implementation")
|
||||
return nil, errors.New("unsupported router implementation")
|
||||
}
|
||||
|
||||
// NewRoutingServer creates a statistics service with statistics manager.
|
||||
@@ -78,7 +79,7 @@ func NewRoutingServer(router routing.Router, routingStats stats.Channel) Routing
|
||||
|
||||
func (s *routingServer) TestRoute(ctx context.Context, request *TestRouteRequest) (*RoutingContext, error) {
|
||||
if request.RoutingContext == nil {
|
||||
return nil, newError("Invalid routing request.")
|
||||
return nil, errors.New("Invalid routing request.")
|
||||
}
|
||||
route, err := s.router.PickRoute(AsRoutingContext(request.RoutingContext))
|
||||
if err != nil {
|
||||
@@ -93,7 +94,7 @@ func (s *routingServer) TestRoute(ctx context.Context, request *TestRouteRequest
|
||||
|
||||
func (s *routingServer) SubscribeRoutingStats(request *SubscribeRoutingStatsRequest, stream RoutingService_SubscribeRoutingStatsServer) error {
|
||||
if s.routingStats == nil {
|
||||
return newError("Routing statistics not enabled.")
|
||||
return errors.New("Routing statistics not enabled.")
|
||||
}
|
||||
genMessage := AsProtobufMessage(request.FieldSelectors)
|
||||
subscriber, err := stats.SubscribeRunnableChannel(s.routingStats)
|
||||
@@ -105,11 +106,11 @@ func (s *routingServer) SubscribeRoutingStats(request *SubscribeRoutingStatsRequ
|
||||
select {
|
||||
case value, ok := <-subscriber:
|
||||
if !ok {
|
||||
return newError("Upstream closed the subscriber channel.")
|
||||
return errors.New("Upstream closed the subscriber channel.")
|
||||
}
|
||||
route, ok := value.(routing.Route)
|
||||
if !ok {
|
||||
return newError("Upstream sent malformed statistics.")
|
||||
return errors.New("Upstream sent malformed statistics.")
|
||||
}
|
||||
err := stream.Send(genMessage(route))
|
||||
if err != nil {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/router/command/command.proto
|
||||
|
||||
package command
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc v4.23.1
|
||||
// - protoc v5.27.0
|
||||
// source: app/router/command/command.proto
|
||||
|
||||
package command
|
||||
|
@@ -272,7 +272,7 @@ func TestServiceSubscribeSubsetOfFields(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSerivceTestRoute(t *testing.T) {
|
||||
func TestServiceTestRoute(t *testing.T) {
|
||||
c := stats.NewChannel(&stats.ChannelConfig{
|
||||
SubscriberLimit: 1,
|
||||
BufferSize: 16,
|
||||
|
@@ -1,9 +0,0 @@
|
||||
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{})
|
||||
}
|
@@ -4,6 +4,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"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/features/routing"
|
||||
@@ -49,12 +50,12 @@ var matcherTypeMap = map[Domain_Type]strmatcher.Type{
|
||||
func domainToMatcher(domain *Domain) (strmatcher.Matcher, error) {
|
||||
matcherType, f := matcherTypeMap[domain.Type]
|
||||
if !f {
|
||||
return nil, newError("unsupported domain type", domain.Type)
|
||||
return nil, errors.New("unsupported domain type", domain.Type)
|
||||
}
|
||||
|
||||
matcher, err := matcherType.New(domain.Value)
|
||||
if err != nil {
|
||||
return nil, newError("failed to create domain matcher").Base(err)
|
||||
return nil, errors.New("failed to create domain matcher").Base(err)
|
||||
}
|
||||
|
||||
return matcher, nil
|
||||
@@ -69,7 +70,7 @@ func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
|
||||
for _, d := range domains {
|
||||
matcherType, f := matcherTypeMap[d.Type]
|
||||
if !f {
|
||||
return nil, newError("unsupported domain type", d.Type)
|
||||
return nil, errors.New("unsupported domain type", d.Type)
|
||||
}
|
||||
_, err := g.AddPattern(d.Value, matcherType)
|
||||
if err != nil {
|
||||
|
@@ -1,9 +1,11 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
@@ -36,7 +38,7 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||
case "linear":
|
||||
matcher, err := NewDomainMatcher(rr.Domain)
|
||||
if err != nil {
|
||||
return nil, newError("failed to build domain condition").Base(err)
|
||||
return nil, errors.New("failed to build domain condition").Base(err)
|
||||
}
|
||||
conds.Add(matcher)
|
||||
case "mph", "hybrid":
|
||||
@@ -44,9 +46,9 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||
default:
|
||||
matcher, err := NewMphMatcherGroup(rr.Domain)
|
||||
if err != nil {
|
||||
return nil, newError("failed to build domain condition with MphDomainMatcher").Base(err)
|
||||
return nil, errors.New("failed to build domain condition with MphDomainMatcher").Base(err)
|
||||
}
|
||||
newError("MphDomainMatcher is enabled for ", len(rr.Domain), " domain rule(s)").AtDebug().WriteToLog()
|
||||
errors.LogDebug(context.Background(), "MphDomainMatcher is enabled for ", len(rr.Domain), " domain rule(s)")
|
||||
conds.Add(matcher)
|
||||
}
|
||||
}
|
||||
@@ -116,7 +118,7 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||
}
|
||||
|
||||
if conds.Len() == 0 {
|
||||
return nil, newError("this rule has no effective fields").AtWarning()
|
||||
return nil, errors.New("this rule has no effective fields").AtWarning()
|
||||
}
|
||||
|
||||
return conds, nil
|
||||
@@ -135,7 +137,7 @@ func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatch
|
||||
case "roundrobin":
|
||||
return &Balancer{
|
||||
selectors: br.OutboundSelector,
|
||||
strategy: &RoundRobinStrategy{},
|
||||
strategy: &RoundRobinStrategy{FallbackTag: br.FallbackTag},
|
||||
fallbackTag: br.FallbackTag,
|
||||
ohm: ohm,
|
||||
}, nil
|
||||
@@ -146,7 +148,7 @@ func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatch
|
||||
}
|
||||
s, ok := i.(*StrategyLeastLoadConfig)
|
||||
if !ok {
|
||||
return nil, newError("not a StrategyLeastLoadConfig").AtError()
|
||||
return nil, errors.New("not a StrategyLeastLoadConfig").AtError()
|
||||
}
|
||||
leastLoadStrategy := NewLeastLoadStrategy(s)
|
||||
return &Balancer{
|
||||
@@ -162,9 +164,9 @@ func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatch
|
||||
selectors: br.OutboundSelector,
|
||||
ohm: ohm,
|
||||
fallbackTag: br.FallbackTag,
|
||||
strategy: &RandomStrategy{},
|
||||
strategy: &RandomStrategy{FallbackTag: br.FallbackTag},
|
||||
}, nil
|
||||
default:
|
||||
return nil, newError("unrecognized balancer type")
|
||||
return nil, errors.New("unrecognized balancer type")
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/router/config.proto
|
||||
|
||||
package router
|
||||
@@ -864,7 +864,7 @@ type StrategyLeastLoadConfig struct {
|
||||
Baselines []int64 `protobuf:"varint,3,rep,packed,name=baselines,proto3" json:"baselines,omitempty"`
|
||||
// expected nodes count to select
|
||||
Expected int32 `protobuf:"varint,4,opt,name=expected,proto3" json:"expected,omitempty"`
|
||||
// max acceptable rtt, filter away high delay nodes. defalut 0
|
||||
// max acceptable rtt, filter away high delay nodes. default 0
|
||||
MaxRTT int64 `protobuf:"varint,5,opt,name=maxRTT,proto3" json:"maxRTT,omitempty"`
|
||||
// acceptable failure rate
|
||||
Tolerance float32 `protobuf:"fixed32,6,opt,name=tolerance,proto3" json:"tolerance,omitempty"`
|
||||
|
@@ -147,7 +147,7 @@ message StrategyLeastLoadConfig {
|
||||
repeated int64 baselines = 3;
|
||||
// expected nodes count to select
|
||||
int32 expected = 4;
|
||||
// max acceptable rtt, filter away high delay nodes. defalut 0
|
||||
// max acceptable rtt, filter away high delay nodes. default 0
|
||||
int64 maxRTT = 5;
|
||||
// acceptable failure rate
|
||||
float tolerance = 6;
|
||||
|
@@ -1,9 +0,0 @@
|
||||
package router
|
||||
|
||||
import "github.com/xtls/xray-core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
@@ -7,6 +7,7 @@ import (
|
||||
sync "sync"
|
||||
|
||||
"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/core"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
@@ -68,7 +69,7 @@ func (r *Router) Init(ctx context.Context, config *Config, d dns.Client, ohm out
|
||||
if len(btag) > 0 {
|
||||
brule, found := r.balancers[btag]
|
||||
if !found {
|
||||
return newError("balancer ", btag, " not found")
|
||||
return errors.New("balancer ", btag, " not found")
|
||||
}
|
||||
rr.Balancer = brule
|
||||
}
|
||||
@@ -101,7 +102,7 @@ func (r *Router) AddRule(config *serial.TypedMessage, shouldAppend bool) error {
|
||||
if c, ok := inst.(*Config); ok {
|
||||
return r.ReloadRules(c, shouldAppend)
|
||||
}
|
||||
return newError("AddRule: config type error")
|
||||
return errors.New("AddRule: config type error")
|
||||
}
|
||||
|
||||
func (r *Router) ReloadRules(config *Config, shouldAppend bool) error {
|
||||
@@ -115,7 +116,7 @@ func (r *Router) ReloadRules(config *Config, shouldAppend bool) error {
|
||||
for _, rule := range config.BalancingRule {
|
||||
_, found := r.balancers[rule.Tag]
|
||||
if found {
|
||||
return newError("duplicate balancer tag")
|
||||
return errors.New("duplicate balancer tag")
|
||||
}
|
||||
balancer, err := rule.Build(r.ohm, r.dispatcher)
|
||||
if err != nil {
|
||||
@@ -127,7 +128,7 @@ func (r *Router) ReloadRules(config *Config, shouldAppend bool) error {
|
||||
|
||||
for _, rule := range config.Rule {
|
||||
if r.RuleExists(rule.GetRuleTag()) {
|
||||
return newError("duplicate ruleTag ", rule.GetRuleTag())
|
||||
return errors.New("duplicate ruleTag ", rule.GetRuleTag())
|
||||
}
|
||||
cond, err := rule.BuildCondition()
|
||||
if err != nil {
|
||||
@@ -142,7 +143,7 @@ func (r *Router) ReloadRules(config *Config, shouldAppend bool) error {
|
||||
if len(btag) > 0 {
|
||||
brule, found := r.balancers[btag]
|
||||
if !found {
|
||||
return newError("balancer ", btag, " not found")
|
||||
return errors.New("balancer ", btag, " not found")
|
||||
}
|
||||
rr.Balancer = brule
|
||||
}
|
||||
@@ -178,7 +179,7 @@ func (r *Router) RemoveRule(tag string) error {
|
||||
r.rules = newRules
|
||||
return nil
|
||||
}
|
||||
return newError("empty tag name!")
|
||||
return errors.New("empty tag name!")
|
||||
|
||||
}
|
||||
func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context, error) {
|
||||
|
@@ -45,7 +45,9 @@ func TestSimpleRouter(t *testing.T) {
|
||||
HandlerSelector: mockHs,
|
||||
}, nil))
|
||||
|
||||
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("example.com"), 80)})
|
||||
ctx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{
|
||||
Target: net.TCPDestination(net.DomainAddress("example.com"), 80),
|
||||
}})
|
||||
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
||||
common.Must(err)
|
||||
if tag := route.GetOutboundTag(); tag != "test" {
|
||||
@@ -86,7 +88,9 @@ func TestSimpleBalancer(t *testing.T) {
|
||||
HandlerSelector: mockHs,
|
||||
}, nil))
|
||||
|
||||
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("example.com"), 80)})
|
||||
ctx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{
|
||||
Target: net.TCPDestination(net.DomainAddress("example.com"), 80),
|
||||
}})
|
||||
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
||||
common.Must(err)
|
||||
if tag := route.GetOutboundTag(); tag != "test" {
|
||||
@@ -174,7 +178,9 @@ func TestIPOnDemand(t *testing.T) {
|
||||
r := new(Router)
|
||||
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
|
||||
|
||||
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("example.com"), 80)})
|
||||
ctx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{
|
||||
Target: net.TCPDestination(net.DomainAddress("example.com"), 80),
|
||||
}})
|
||||
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
||||
common.Must(err)
|
||||
if tag := route.GetOutboundTag(); tag != "test" {
|
||||
@@ -213,7 +219,9 @@ func TestIPIfNonMatchDomain(t *testing.T) {
|
||||
r := new(Router)
|
||||
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
|
||||
|
||||
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("example.com"), 80)})
|
||||
ctx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{
|
||||
Target: net.TCPDestination(net.DomainAddress("example.com"), 80),
|
||||
}})
|
||||
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
||||
common.Must(err)
|
||||
if tag := route.GetOutboundTag(); tag != "test" {
|
||||
@@ -247,7 +255,9 @@ func TestIPIfNonMatchIP(t *testing.T) {
|
||||
r := new(Router)
|
||||
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
|
||||
|
||||
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 80)})
|
||||
ctx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{
|
||||
Target: net.TCPDestination(net.LocalHostIP, 80),
|
||||
}})
|
||||
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
|
||||
common.Must(err)
|
||||
if tag := route.GetOutboundTag(); tag != "test" {
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/xtls/xray-core/app/observatory"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/extension"
|
||||
)
|
||||
@@ -95,7 +96,7 @@ func (s *LeastLoadStrategy) pickOutbounds(candidates []string) []*node {
|
||||
// with 'balancer.fallbackTag', it means: selects qualified nodes or use the fallback.
|
||||
func (s *LeastLoadStrategy) selectLeastLoad(nodes []*node) []*node {
|
||||
if len(nodes) == 0 {
|
||||
newError("least load: no qualified outbound").AtInfo().WriteToLog()
|
||||
errors.LogInfo(s.ctx, "least load: no qualified outbound")
|
||||
return nil
|
||||
}
|
||||
expected := int(s.settings.Expected)
|
||||
@@ -123,7 +124,7 @@ func (s *LeastLoadStrategy) selectLeastLoad(nodes []*node) []*node {
|
||||
}
|
||||
// don't continue if find expected selects
|
||||
if count >= expected {
|
||||
newError("applied baseline: ", baseline).AtDebug().WriteToLog()
|
||||
errors.LogDebug(s.ctx, "applied baseline: ", baseline)
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -142,7 +143,7 @@ func (s *LeastLoadStrategy) getNodes(candidates []string, maxRTT time.Duration)
|
||||
}
|
||||
observeResult, err := s.observer.GetObservation(s.ctx)
|
||||
if err != nil {
|
||||
newError("cannot get observation").Base(err).WriteToLog()
|
||||
errors.LogInfoInner(s.ctx, err, "cannot get observation")
|
||||
return make([]*node, 0)
|
||||
}
|
||||
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"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/core"
|
||||
"github.com/xtls/xray-core/features/extension"
|
||||
)
|
||||
@@ -32,7 +33,7 @@ func (l *LeastPingStrategy) PickOutbound(strings []string) string {
|
||||
|
||||
observeReport, err := l.observatory.GetObservation(l.ctx)
|
||||
if err != nil {
|
||||
newError("cannot get observe report").Base(err).WriteToLog()
|
||||
errors.LogInfoInner(l.ctx, err, "cannot get observe report")
|
||||
return ""
|
||||
}
|
||||
outboundsList := outboundList(strings)
|
||||
|
@@ -1,17 +1,63 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/app/observatory"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/extension"
|
||||
)
|
||||
|
||||
// RandomStrategy represents a random balancing strategy
|
||||
type RandomStrategy struct{}
|
||||
type RandomStrategy struct{
|
||||
FallbackTag string
|
||||
|
||||
ctx context.Context
|
||||
observatory extension.Observatory
|
||||
}
|
||||
|
||||
func (s *RandomStrategy) InjectContext(ctx context.Context) {
|
||||
s.ctx = ctx
|
||||
}
|
||||
|
||||
func (s *RandomStrategy) GetPrincipleTarget(strings []string) []string {
|
||||
return strings
|
||||
}
|
||||
|
||||
func (s *RandomStrategy) PickOutbound(candidates []string) string {
|
||||
if len(s.FallbackTag) > 0 && s.observatory == nil {
|
||||
common.Must(core.RequireFeatures(s.ctx, func(observatory extension.Observatory) error {
|
||||
s.observatory = observatory
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
if s.observatory != nil {
|
||||
observeReport, err := s.observatory.GetObservation(s.ctx)
|
||||
if err == nil {
|
||||
aliveTags := make([]string, 0)
|
||||
if result, ok := observeReport.(*observatory.ObservationResult); ok {
|
||||
status := result.Status
|
||||
statusMap := make(map[string]*observatory.OutboundStatus)
|
||||
for _, outboundStatus := range status {
|
||||
statusMap[outboundStatus.OutboundTag] = outboundStatus
|
||||
}
|
||||
for _, candidate := range candidates {
|
||||
if outboundStatus, found := statusMap[candidate]; found {
|
||||
if outboundStatus.Alive {
|
||||
aliveTags = append(aliveTags, candidate)
|
||||
}
|
||||
} else {
|
||||
// unfound candidate is considered alive
|
||||
aliveTags = append(aliveTags, candidate)
|
||||
}
|
||||
}
|
||||
candidates = aliveTags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count := len(candidates)
|
||||
if count == 0 {
|
||||
// goes to fallbackTag
|
||||
|
@@ -1,10 +1,13 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
)
|
||||
|
||||
type weightScaler func(value, weight float64) float64
|
||||
@@ -64,7 +67,7 @@ func (s *WeightManager) findValue(tag string) float64 {
|
||||
}
|
||||
weight, err := strconv.ParseFloat(numStr, 64)
|
||||
if err != nil {
|
||||
newError("unexpected error from ParseFloat: ", err).AtError().WriteToLog()
|
||||
errors.LogError(context.Background(), "unexpected error from ParseFloat: ", err)
|
||||
return s.defaultWeight
|
||||
}
|
||||
return weight
|
||||
@@ -82,7 +85,7 @@ func (s *WeightManager) getMatch(tag, find string, isRegexp bool) string {
|
||||
}
|
||||
r, err := regexp.Compile(find)
|
||||
if err != nil {
|
||||
newError("invalid regexp: ", find, "err: ", err).AtError().WriteToLog()
|
||||
errors.LogError(context.Background(), "invalid regexp: ", find, "err: ", err)
|
||||
return ""
|
||||
}
|
||||
return r.FindString(tag)
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
)
|
||||
|
||||
// Channel is an implementation of stats.Channel.
|
||||
@@ -44,7 +45,7 @@ func (c *Channel) Subscribe() (chan interface{}, error) {
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
if c.subsLimit > 0 && len(c.subscribers) >= c.subsLimit {
|
||||
return nil, newError("Number of subscribers has reached limit")
|
||||
return nil, errors.New("Number of subscribers has reached limit")
|
||||
}
|
||||
subscriber := make(chan interface{}, c.bufferSize)
|
||||
c.subscribers = append(c.subscribers, subscriber)
|
||||
|
@@ -95,7 +95,7 @@ func TestStatsChannel(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsChannelUnsubcribe(t *testing.T) {
|
||||
func TestStatsChannelUnsubscribe(t *testing.T) {
|
||||
c := NewChannel(&ChannelConfig{Blocking: true})
|
||||
common.Must(c.Start())
|
||||
defer c.Close()
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"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/strmatcher"
|
||||
"github.com/xtls/xray-core/core"
|
||||
feature_stats "github.com/xtls/xray-core/features/stats"
|
||||
@@ -31,7 +32,7 @@ func NewStatsServer(manager feature_stats.Manager) StatsServiceServer {
|
||||
func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {
|
||||
c := s.stats.GetCounter(request.Name)
|
||||
if c == nil {
|
||||
return nil, newError(request.Name, " not found.")
|
||||
return nil, errors.New(request.Name, " not found.")
|
||||
}
|
||||
var value int64
|
||||
if request.Reset_ {
|
||||
@@ -57,7 +58,7 @@ func (s *statsServer) QueryStats(ctx context.Context, request *QueryStatsRequest
|
||||
|
||||
manager, ok := s.stats.(*stats.Manager)
|
||||
if !ok {
|
||||
return nil, newError("QueryStats only works its own stats.Manager.")
|
||||
return nil, errors.New("QueryStats only works its own stats.Manager.")
|
||||
}
|
||||
|
||||
manager.VisitCounters(func(name string, c feature_stats.Counter) bool {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.23.1
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v5.27.0
|
||||
// source: app/stats/command/command.proto
|
||||
|
||||
package command
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user