mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-12-18 21:24:37 +03:00
Compare commits
84 Commits
v25.8.3
...
fix-router
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc7a3c14d7 | ||
|
|
83c5370eec | ||
|
|
1a48453bea | ||
|
|
3167e5cec0 | ||
|
|
5148c5786f | ||
|
|
3edfb0e335 | ||
|
|
d3248a4f8e | ||
|
|
30e10be95d | ||
|
|
cced1477a0 | ||
|
|
9f5dcb1591 | ||
|
|
ce5c51d3ba | ||
|
|
11f670c8a6 | ||
|
|
a387ae9590 | ||
|
|
4ae497106d | ||
|
|
1f4fc2e7bb | ||
|
|
ae44b86b0d | ||
|
|
8276a443bc | ||
|
|
1e2f251bb3 | ||
|
|
845010b535 | ||
|
|
a0c63ba1cf | ||
|
|
2b82366148 | ||
|
|
ab1fa13ebe | ||
|
|
4740ba2425 | ||
|
|
4b0ee28f1c | ||
|
|
6ec0291d4e | ||
|
|
118131fcaf | ||
|
|
197b319f9a | ||
|
|
8b579bf3ec | ||
|
|
cbade89ab1 | ||
|
|
d20397c15d | ||
|
|
19f8907296 | ||
|
|
e943de5300 | ||
|
|
4064f8dd80 | ||
|
|
2acd206821 | ||
|
|
4c6fd94d97 | ||
|
|
fd54b10d97 | ||
|
|
6830089d3c | ||
|
|
6768a22f67 | ||
|
|
e8b02cd664 | ||
|
|
fbb0ecfb83 | ||
|
|
a31842feaa | ||
|
|
79325ead2e | ||
|
|
81b7cd718a | ||
|
|
ea1a3ae8f1 | ||
|
|
593ededd3e | ||
|
|
82ea7a3cc5 | ||
|
|
56a45ad578 | ||
|
|
4976085ddb | ||
|
|
fcdd4df446 | ||
|
|
12b077f33b | ||
|
|
702d2c06ca | ||
|
|
7951a5c4bf | ||
|
|
c2141f09e7 | ||
|
|
ef640ed309 | ||
|
|
5fa5f3fbb9 | ||
|
|
2ee372e758 | ||
|
|
11f0513bce | ||
|
|
b65da77267 | ||
|
|
33272a0499 | ||
|
|
87b643a388 | ||
|
|
6d1695a686 | ||
|
|
3a54924045 | ||
|
|
573300bc22 | ||
|
|
7f300dbf0c | ||
|
|
5464862ee6 | ||
|
|
337b4b814e | ||
|
|
105b306d07 | ||
|
|
de23e51077 | ||
|
|
40ce850bd9 | ||
|
|
2485f4831f | ||
|
|
aac0d6a6a5 | ||
|
|
f557bf7da4 | ||
|
|
6fc0a40c2a | ||
|
|
f3cdcad541 | ||
|
|
5a8e9c25a4 | ||
|
|
836b6487e4 | ||
|
|
b1107b9810 | ||
|
|
0cceea75da | ||
|
|
4b21c9aed3 | ||
|
|
cde6e33ec9 | ||
|
|
5dce7e4e25 | ||
|
|
9359844149 | ||
|
|
8222f43eea | ||
|
|
04e6439b51 |
29
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
29
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -7,6 +7,8 @@ body:
|
||||
description: |-
|
||||
Please check all of the following options to prove that you have read and understood the requirements, otherwise this issue will be closed.
|
||||
options:
|
||||
- label: I have read all the comments in the issue template and ensured that this issue meet the requirements.
|
||||
required: true
|
||||
- label: I confirm that I have read the documentation, understand the meaning of all the configuration items I wrote, and did not pile up seemingly useful options or default values.
|
||||
required: true
|
||||
- label: I provided the complete config and logs, rather than just providing the truncated parts based on my own judgment.
|
||||
@@ -38,6 +40,8 @@ body:
|
||||
### For config
|
||||
Please provide the configuration files that can reproduce the problem, including the server and client.
|
||||
Don't just paste a big exported config file here. Eliminate useless inbound/outbound, rules, options, this can help determine the problem, if you really want to get help.
|
||||
After removing parts that do not affect reproduction, provide the actual running **complete** file.
|
||||
meaning of complete: This config can be directly used to start the core, **not a truncated part of the config**. For fields like keys, use newly generated valid parameters that have not been actually used to fill in.
|
||||
|
||||
### For logs
|
||||
Please set the log level to debug and dnsLog to true first.
|
||||
@@ -46,42 +50,29 @@ body:
|
||||
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.
|
||||
The specific content to be filled in each of the following text boxes needs to be placed between ```<details><pre><code>``` and ```</code></pre></details>```, like this
|
||||
```
|
||||
<details><pre><code>
|
||||
(config)
|
||||
</code></pre></details>
|
||||
```
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Client config
|
||||
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
|
||||
29
.github/ISSUE_TEMPLATE/bug_report_zh.yml
vendored
29
.github/ISSUE_TEMPLATE/bug_report_zh.yml
vendored
@@ -7,6 +7,8 @@ body:
|
||||
description: |-
|
||||
请勾选以下所有选项以证明您已经阅读并理解了以下要求,否则该 issue 将被关闭。
|
||||
options:
|
||||
- label: 我读完了 issue 模板中的所有注释,确保填写符合要求。
|
||||
required: true
|
||||
- label: 我保证阅读了文档,了解所有我编写的配置文件项的含义,而不是大量堆砌看似有用的选项或默认值。
|
||||
required: true
|
||||
- label: 我提供了完整的配置文件和日志,而不是出于自己的判断只给出截取的部分。
|
||||
@@ -38,6 +40,8 @@ body:
|
||||
### 对于配置文件
|
||||
请提供可以重现问题的配置文件,包括服务端和客户端。
|
||||
不要直接在这里黏贴一大段导出的 config 文件。去掉无用的出入站、规则、选项,这可以帮助确定问题,如果你真的想得到帮助。
|
||||
在去掉不影响复现的部分后,提供实际运行的**完整**文件。
|
||||
完整的含义:可以直接使用这个配置启动核心,**不是截取的部分配置**。对于密钥等参数使用重新生成未实际使用的有效参数填充。
|
||||
|
||||
### 对于日志
|
||||
请先将日志等级设置为 debug, dnsLog 设置为true.
|
||||
@@ -46,42 +50,29 @@ body:
|
||||
提供 Xray-core 的日志,而不是面板或者别的东西输出的日志。
|
||||
|
||||
### 最后
|
||||
在去掉不影响复现的部分后,提供实际运行的**完整**文件,不要出于自己的判断只提供入站出站或者几行日志。
|
||||
把内容放在文本框预置的 ```<details><pre><code>``` 和 ```</code></pre></details>``` 中间。
|
||||
如果问题十分明确只出现在某一端(如按文档正确编写配置后核心启动失败/崩溃),可以在下面不需要的项目填入N/A.
|
||||
把下面的每格具体内容需要放在 ```<details><pre><code>``` 和 ```</code></pre></details>``` 中间,如
|
||||
```
|
||||
<details><pre><code>
|
||||
(config)
|
||||
</code></pre></details>
|
||||
```
|
||||
- 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
|
||||
|
||||
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
@@ -65,7 +65,7 @@ jobs:
|
||||
echo "LATEST=$LATEST" >>${GITHUB_ENV}
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
8
.github/workflows/release-win7.yml
vendored
8
.github/workflows/release-win7.yml
vendored
@@ -63,7 +63,7 @@ jobs:
|
||||
CGO_ENABLED: 0
|
||||
steps:
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Show workflow information
|
||||
run: |
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
@@ -94,11 +94,11 @@ jobs:
|
||||
mkdir -p build_assets
|
||||
COMMID=$(git describe --always --dirty)
|
||||
echo 'Building Xray for Windows 7...'
|
||||
go build -o build_assets/xray.exe -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||
go build -o build_assets/xray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||
echo 'CreateObject("Wscript.Shell").Run "xray.exe -config config.json",0' > build_assets/xray_no_window.vbs
|
||||
echo 'Start-Process -FilePath ".\xray.exe" -ArgumentList "-config .\config.json" -WindowStyle Hidden' > build_assets/xray_no_window.ps1
|
||||
# The line below is for without running conhost.exe version. Commented for not being used. Provided for reference.
|
||||
# go build -o build_assets/wxray.exe -trimpath -buildvcs=false -ldflags="-H windowsgui -X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||
# go build -o build_assets/wxray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-H windowsgui -X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||
|
||||
- name: Restore Geodat Cache
|
||||
uses: actions/cache/restore@v4
|
||||
|
||||
16
.github/workflows/release.yml
vendored
16
.github/workflows/release.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
|
||||
- name: Trigger Asset Update Workflow if Assets Missing
|
||||
if: steps.check-assets.outputs.missing == 'true'
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
@@ -153,7 +153,7 @@ jobs:
|
||||
CGO_ENABLED: 0
|
||||
steps:
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up NDK
|
||||
if: matrix.goos == 'android'
|
||||
@@ -176,7 +176,7 @@ jobs:
|
||||
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
@@ -190,17 +190,19 @@ jobs:
|
||||
COMMID=$(git describe --always --dirty)
|
||||
if [[ ${GOOS} == 'windows' ]]; then
|
||||
echo 'Building Xray for Windows...'
|
||||
go build -o build_assets/xray.exe -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||
go build -o build_assets/xray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||
echo 'CreateObject("Wscript.Shell").Run "xray.exe -config config.json",0' > build_assets/xray_no_window.vbs
|
||||
echo 'Start-Process -FilePath ".\xray.exe" -ArgumentList "-config .\config.json" -WindowStyle Hidden' > build_assets/xray_no_window.ps1
|
||||
# The line below is for without running conhost.exe version. Commented for not being used. Provided for reference.
|
||||
# go build -o build_assets/wxray.exe -trimpath -buildvcs=false -ldflags="-H windowsgui -X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||
# go build -o build_assets/wxray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-H windowsgui -X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||
else
|
||||
echo 'Building Xray...'
|
||||
go build -o build_assets/xray -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||
if [[ ${GOARCH} == 'mips' || ${GOARCH} == 'mipsle' ]]; then
|
||||
go build -o build_assets/xray -trimpath -buildvcs=false -gcflags="-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||
echo 'Building soft-float Xray for MIPS/MIPSLE 32-bit...'
|
||||
GOMIPS=softfloat go build -o build_assets/xray_softfloat -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||
GOMIPS=softfloat go build -o build_assets/xray_softfloat -trimpath -buildvcs=false -gcflags="-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||
else
|
||||
go build -o build_assets/xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -45,9 +45,9 @@ jobs:
|
||||
os: [windows-latest, ubuntu-latest, macos-latest]
|
||||
steps:
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
|
||||
40
.gitignore
vendored
40
.gitignore
vendored
@@ -11,21 +11,23 @@
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# macOS specific files
|
||||
*.DS_Store
|
||||
.DS_Store
|
||||
|
||||
# IDE specific files
|
||||
# IDE/editor specific files
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Archive files
|
||||
# Archives and compressed files
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.tar
|
||||
*.gz
|
||||
*.bz2
|
||||
|
||||
# Binaries
|
||||
# Go build binaries
|
||||
xray
|
||||
xray_softfloat
|
||||
mockgen
|
||||
@@ -36,11 +38,31 @@ errorgen
|
||||
*.dat
|
||||
|
||||
# Build assets
|
||||
/build_assets
|
||||
/build_assets/
|
||||
|
||||
# Output from dlv test
|
||||
**/debug.*
|
||||
|
||||
# Certificates
|
||||
# Certificates and keys
|
||||
*.crt
|
||||
*.key
|
||||
|
||||
# Dependency directories (uncomment if needed)
|
||||
# vendor/
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
||||
# Coverage reports
|
||||
coverage.*
|
||||
|
||||
# Node modules (in case of frontend assets)
|
||||
node_modules/
|
||||
|
||||
# System files
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Other common ignores
|
||||
*.bak
|
||||
*.tmp
|
||||
|
||||
13
README.md
13
README.md
@@ -11,8 +11,10 @@
|
||||
[<img alt="Project X NFT" width="150px" src="https://raw2.seadn.io/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/7fa9ce900fb39b44226348db330e32/8b7fa9ce900fb39b44226348db330e32.svg" />](https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1)
|
||||
|
||||
- **ETH/USDT/USDC: `0xDc3Fe44F0f25D13CACb1C4896CD0D321df3146Ee`**
|
||||
- **Project X NFT: https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1**
|
||||
- **VLESS NFT: https://opensea.io/collection/vless**
|
||||
- **REALITY NFT: https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/2**
|
||||
- **Related links: https://opensea.io/collection/xtls, [Announcement of NFTs by Project X](https://github.com/XTLS/Xray-core/discussions/3633), [XHTTP: Beyond REALITY](https://github.com/XTLS/Xray-core/discussions/4113)**
|
||||
- **Related links: [VLESS Post-Quantum Encryption](https://github.com/XTLS/Xray-core/pull/5067), [XHTTP: Beyond REALITY](https://github.com/XTLS/Xray-core/discussions/4113), [Announcement of NFTs by Project X](https://github.com/XTLS/Xray-core/discussions/3633)**
|
||||
|
||||
## License
|
||||
|
||||
@@ -42,6 +44,7 @@
|
||||
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
|
||||
- [wulabing/xray_docker](https://github.com/wulabing/xray_docker)
|
||||
- Web Panel - **WARNING: Please DO NOT USE plain HTTP panels like 3X-UI**, as they are believed to be bribed by Iran GFW for supporting plain HTTP by default and refused to change (https://github.com/XTLS/Xray-core/pull/3884#issuecomment-2439595331), which has already put many users' data security in danger in the past few years. **If you are already using 3X-UI, please switch to the following panels, which are verified to support HTTPS and SSH port forwarding only:**
|
||||
- [X-Panel](https://github.com/xeefei/X-Panel)
|
||||
- [Remnawave](https://github.com/remnawave/panel)
|
||||
- [Marzban](https://github.com/Gozargah/Marzban)
|
||||
- [Xray-UI](https://github.com/qist/xray-ui)
|
||||
@@ -165,7 +168,13 @@ CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -ldflags="-s -w -buildi
|
||||
Make sure that you are using the same Go version, and remember to set the git commit id (7 bytes):
|
||||
|
||||
```bash
|
||||
CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=REPLACE -s -w -buildid=" -v ./main
|
||||
CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=REPLACE -s -w -buildid=" -v ./main
|
||||
```
|
||||
|
||||
If you are compiling a 32-bit MIPS/MIPSLE target, use this command instead:
|
||||
|
||||
```bash
|
||||
CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -gcflags="-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=REPLACE -s -w -buildid=" -v ./main
|
||||
```
|
||||
|
||||
## Stargazers over time
|
||||
|
||||
@@ -2,6 +2,7 @@ package dispatcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
go_errors "errors"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -29,7 +30,7 @@ var errSniffingTimeout = errors.New("timeout on sniffing")
|
||||
|
||||
type cachedReader struct {
|
||||
sync.Mutex
|
||||
reader *pipe.Reader
|
||||
reader buf.TimeoutReader // *pipe.Reader or *buf.TimeoutWrapperReader
|
||||
cache buf.MultiBuffer
|
||||
}
|
||||
|
||||
@@ -87,7 +88,9 @@ func (r *cachedReader) Interrupt() {
|
||||
r.cache = buf.ReleaseMulti(r.cache)
|
||||
}
|
||||
r.Unlock()
|
||||
r.reader.Interrupt()
|
||||
if p, ok := r.reader.(*pipe.Reader); ok {
|
||||
p.Interrupt()
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultDispatcher is a default implementation of Dispatcher.
|
||||
@@ -194,6 +197,47 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
|
||||
return inboundLink, outboundLink
|
||||
}
|
||||
|
||||
func (d *DefaultDispatcher) WrapLink(ctx context.Context, link *transport.Link) *transport.Link {
|
||||
sessionInbound := session.InboundFromContext(ctx)
|
||||
var user *protocol.MemoryUser
|
||||
if sessionInbound != nil {
|
||||
user = sessionInbound.User
|
||||
}
|
||||
|
||||
link.Reader = &buf.TimeoutWrapperReader{Reader: link.Reader}
|
||||
|
||||
if user != nil && len(user.Email) > 0 {
|
||||
p := d.policy.ForLevel(user.Level)
|
||||
if p.Stats.UserUplink {
|
||||
name := "user>>>" + user.Email + ">>>traffic>>>uplink"
|
||||
if c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
|
||||
link.Reader.(*buf.TimeoutWrapperReader).Counter = c
|
||||
}
|
||||
}
|
||||
if p.Stats.UserDownlink {
|
||||
name := "user>>>" + user.Email + ">>>traffic>>>downlink"
|
||||
if c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
|
||||
link.Writer = &SizeStatWriter{
|
||||
Counter: c,
|
||||
Writer: link.Writer,
|
||||
}
|
||||
}
|
||||
}
|
||||
if p.Stats.UserOnline {
|
||||
name := "user>>>" + user.Email + ">>>online"
|
||||
if om, _ := stats.GetOrRegisterOnlineMap(d.stats, name); om != nil {
|
||||
sessionInbounds := session.InboundFromContext(ctx)
|
||||
userIP := sessionInbounds.Source.Address.String()
|
||||
om.AddIP(userIP)
|
||||
// log Online user with ips
|
||||
// errors.LogDebug(ctx, "user>>>" + user.Email + ">>>online", om.Count(), om.List())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return link
|
||||
}
|
||||
|
||||
func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
||||
domain := result.Domain()
|
||||
if domain == "" {
|
||||
@@ -314,12 +358,13 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
||||
content = new(session.Content)
|
||||
ctx = session.ContextWithContent(ctx, content)
|
||||
}
|
||||
outbound = d.WrapLink(ctx, outbound)
|
||||
sniffingRequest := content.SniffingRequest
|
||||
if !sniffingRequest.Enabled {
|
||||
d.routedDispatch(ctx, outbound, destination)
|
||||
} else {
|
||||
cReader := &cachedReader{
|
||||
reader: outbound.Reader.(*pipe.Reader),
|
||||
reader: outbound.Reader.(buf.TimeoutReader),
|
||||
}
|
||||
outbound.Reader = cReader
|
||||
result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly, destination.Network)
|
||||
@@ -439,8 +484,17 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
||||
handler = h
|
||||
} else {
|
||||
errors.LogWarning(ctx, "non existing outTag: ", outTag)
|
||||
common.Close(link.Writer)
|
||||
common.Interrupt(link.Reader)
|
||||
return // DO NOT CHANGE: the traffic shouldn't be processed by default outbound if the specified outbound tag doesn't exist (yet), e.g., VLESS Reverse Proxy
|
||||
}
|
||||
} else {
|
||||
if !go_errors.Is(err, common.ErrNoClue) {
|
||||
errors.LogWarningInner(ctx, err, "get error during route pick ")
|
||||
common.Close(link.Writer)
|
||||
common.Interrupt(link.Reader)
|
||||
return
|
||||
}
|
||||
errors.LogInfo(ctx, "default route for ", destination)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ func init() {
|
||||
}
|
||||
|
||||
func checkSystemNetwork() (supportIPv4 bool, supportIPv6 bool) {
|
||||
conn4, err4 := net.Dial("udp4", "8.8.8.8:53")
|
||||
conn4, err4 := net.Dial("udp4", "192.33.4.12:53")
|
||||
if err4 != nil {
|
||||
supportIPv4 = false
|
||||
} else {
|
||||
@@ -337,7 +337,7 @@ func checkSystemNetwork() (supportIPv4 bool, supportIPv6 bool) {
|
||||
conn4.Close()
|
||||
}
|
||||
|
||||
conn6, err6 := net.Dial("udp6", "[2001:4860:4860::8888]:53")
|
||||
conn6, err6 := net.Dial("udp6", "[2001:500:2::c]:53")
|
||||
if err6 != nil {
|
||||
supportIPv6 = false
|
||||
} else {
|
||||
|
||||
@@ -42,12 +42,15 @@ func (r *IPRecord) getIPs() ([]net.IP, uint32, error) {
|
||||
if r == nil {
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
untilExpire := time.Until(r.Expire)
|
||||
untilExpire := time.Until(r.Expire).Seconds()
|
||||
if untilExpire <= 0 {
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
|
||||
ttl := uint32(untilExpire/time.Second) + uint32(1)
|
||||
ttl := uint32(untilExpire) + 1
|
||||
if ttl == 1 {
|
||||
r.Expire = time.Now().Add(time.Second) // To ensure that two consecutive requests get the same result
|
||||
}
|
||||
if r.RCode != dnsmessage.RCodeSuccess {
|
||||
return nil, ttl, dns_feature.RCodeError(r.RCode)
|
||||
}
|
||||
|
||||
@@ -18,31 +18,31 @@ func Test_parseResponse(t *testing.T) {
|
||||
|
||||
ans := new(dns.Msg)
|
||||
ans.Id = 0
|
||||
p = append(p, common.Must2(ans.Pack()).([]byte))
|
||||
p = append(p, common.Must2(ans.Pack()))
|
||||
|
||||
p = append(p, []byte{})
|
||||
|
||||
ans = new(dns.Msg)
|
||||
ans.Id = 1
|
||||
ans.Answer = append(ans.Answer,
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN A 8.8.8.8")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN A 8.8.4.4")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")),
|
||||
common.Must2(dns.NewRR("google.com. IN A 8.8.8.8")),
|
||||
common.Must2(dns.NewRR("google.com. IN A 8.8.4.4")),
|
||||
)
|
||||
p = append(p, common.Must2(ans.Pack()).([]byte))
|
||||
p = append(p, common.Must2(ans.Pack()))
|
||||
|
||||
ans = new(dns.Msg)
|
||||
ans.Id = 2
|
||||
ans.Answer = append(ans.Answer,
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME test.google.com")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8888")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8844")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME test.google.com")),
|
||||
common.Must2(dns.NewRR("google.com. IN AAAA 2001:4860:4860::8888")),
|
||||
common.Must2(dns.NewRR("google.com. IN AAAA 2001:4860:4860::8844")),
|
||||
)
|
||||
p = append(p, common.Must2(ans.Pack()).([]byte))
|
||||
p = append(p, common.Must2(ans.Pack()))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -72,7 +72,7 @@ func Test_parseResponse(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"aaaa record",
|
||||
&IPRecord{2, []net.IP{net.ParseIP("2001::123:8888"), net.ParseIP("2001::123:8844")}, time.Time{}, dnsmessage.RCodeSuccess, nil},
|
||||
&IPRecord{2, []net.IP{net.ParseIP("2001:4860:4860::8888"), net.ParseIP("2001:4860:4860::8844")}, time.Time{}, dnsmessage.RCodeSuccess, nil},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -90,7 +90,9 @@ func (s *ClassicNameServer) RequestsCleanup() error {
|
||||
|
||||
// HandleResponse handles udp response packet from remote DNS server.
|
||||
func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_proto.Packet) {
|
||||
ipRec, err := parseResponse(packet.Payload.Bytes())
|
||||
payload := packet.Payload
|
||||
ipRec, err := parseResponse(payload.Bytes())
|
||||
payload.Release()
|
||||
if err != nil {
|
||||
errors.LogError(ctx, s.Name(), " fail to parse responded DNS udp")
|
||||
return
|
||||
@@ -125,6 +127,8 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
||||
newReq.msg = &newMsg
|
||||
s.addPendingRequest(&newReq)
|
||||
b, _ := dns.PackMessage(newReq.msg)
|
||||
copyDest := net.UDPDestination(s.address.Address, s.address.Port)
|
||||
b.UDP = ©Dest
|
||||
s.udpServer.Dispatch(toDnsContext(newReq.ctx, s.address.String()), *s.address, b)
|
||||
return
|
||||
}
|
||||
@@ -158,6 +162,8 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, _ chan<- error, domai
|
||||
}
|
||||
s.addPendingRequest(udpReq)
|
||||
b, _ := dns.PackMessage(req.msg)
|
||||
copyDest := net.UDPDestination(s.address.Address, s.address.Port)
|
||||
b.UDP = ©Dest
|
||||
s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,11 +449,12 @@ type SenderConfig struct {
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// Send traffic through the given IP. Only IP is allowed.
|
||||
Via *net.IPOrDomain `protobuf:"bytes,1,opt,name=via,proto3" json:"via,omitempty"`
|
||||
StreamSettings *internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
||||
ProxySettings *internet.ProxyConfig `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"`
|
||||
MultiplexSettings *MultiplexingConfig `protobuf:"bytes,4,opt,name=multiplex_settings,json=multiplexSettings,proto3" json:"multiplex_settings,omitempty"`
|
||||
ViaCidr string `protobuf:"bytes,5,opt,name=via_cidr,json=viaCidr,proto3" json:"via_cidr,omitempty"`
|
||||
Via *net.IPOrDomain `protobuf:"bytes,1,opt,name=via,proto3" json:"via,omitempty"`
|
||||
StreamSettings *internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
||||
ProxySettings *internet.ProxyConfig `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"`
|
||||
MultiplexSettings *MultiplexingConfig `protobuf:"bytes,4,opt,name=multiplex_settings,json=multiplexSettings,proto3" json:"multiplex_settings,omitempty"`
|
||||
ViaCidr string `protobuf:"bytes,5,opt,name=via_cidr,json=viaCidr,proto3" json:"via_cidr,omitempty"`
|
||||
TargetStrategy internet.DomainStrategy `protobuf:"varint,6,opt,name=target_strategy,json=targetStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"target_strategy,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SenderConfig) Reset() {
|
||||
@@ -521,6 +522,13 @@ func (x *SenderConfig) GetViaCidr() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SenderConfig) GetTargetStrategy() internet.DomainStrategy {
|
||||
if x != nil {
|
||||
return x.TargetStrategy
|
||||
}
|
||||
return internet.DomainStrategy(0)
|
||||
}
|
||||
|
||||
type MultiplexingConfig struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -779,7 +787,7 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
|
||||
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65,
|
||||
0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53,
|
||||
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f,
|
||||
0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xcb, 0x02, 0x0a, 0x0c, 0x53, 0x65,
|
||||
0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x9d, 0x03, 0x0a, 0x0c, 0x53, 0x65,
|
||||
0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x03, 0x76, 0x69,
|
||||
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f,
|
||||
@@ -800,23 +808,28 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
|
||||
0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69,
|
||||
0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08,
|
||||
0x76, 0x69, 0x61, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||
0x76, 0x69, 0x61, 0x43, 0x69, 0x64, 0x72, 0x22, 0xa4, 0x01, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74,
|
||||
0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63,
|
||||
0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x63,
|
||||
0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75,
|
||||
0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x05, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72,
|
||||
0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x78,
|
||||
0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x42, 0x55,
|
||||
0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d,
|
||||
0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
|
||||
0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f,
|
||||
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x76, 0x69, 0x61, 0x43, 0x69, 0x64, 0x72, 0x12, 0x50, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e,
|
||||
0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
||||
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, 0xa4, 0x01, 0x0a, 0x12, 0x4d, 0x75,
|
||||
0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f,
|
||||
0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||
0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f,
|
||||
0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75,
|
||||
0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72,
|
||||
0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33,
|
||||
0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74,
|
||||
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||
0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50,
|
||||
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -850,6 +863,7 @@ var file_app_proxyman_config_proto_goTypes = []any{
|
||||
(*internet.StreamConfig)(nil), // 13: xray.transport.internet.StreamConfig
|
||||
(*serial.TypedMessage)(nil), // 14: xray.common.serial.TypedMessage
|
||||
(*internet.ProxyConfig)(nil), // 15: xray.transport.internet.ProxyConfig
|
||||
(internet.DomainStrategy)(0), // 16: xray.transport.internet.DomainStrategy
|
||||
}
|
||||
var file_app_proxyman_config_proto_depIdxs = []int32{
|
||||
0, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type
|
||||
@@ -866,11 +880,12 @@ var file_app_proxyman_config_proto_depIdxs = []int32{
|
||||
13, // 11: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||
15, // 12: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
|
||||
8, // 13: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
||||
14, // [14:14] is the sub-list for method output_type
|
||||
14, // [14:14] is the sub-list for method input_type
|
||||
14, // [14:14] is the sub-list for extension type_name
|
||||
14, // [14:14] is the sub-list for extension extendee
|
||||
0, // [0:14] is the sub-list for field type_name
|
||||
16, // 14: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||
15, // [15:15] is the sub-list for method output_type
|
||||
15, // [15:15] is the sub-list for method input_type
|
||||
15, // [15:15] is the sub-list for extension type_name
|
||||
15, // [15:15] is the sub-list for extension extendee
|
||||
0, // [0:15] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_app_proxyman_config_proto_init() }
|
||||
|
||||
@@ -84,6 +84,7 @@ message SenderConfig {
|
||||
xray.transport.internet.ProxyConfig proxy_settings = 3;
|
||||
MultiplexingConfig multiplex_settings = 4;
|
||||
string via_cidr = 5;
|
||||
xray.transport.internet.DomainStrategy target_strategy = 6;
|
||||
}
|
||||
|
||||
message MultiplexingConfig {
|
||||
|
||||
@@ -2,6 +2,7 @@ package inbound
|
||||
|
||||
import (
|
||||
"context"
|
||||
gonet "net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@@ -76,7 +77,25 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
||||
case internet.SocketConfig_TProxy:
|
||||
dest = net.DestinationFromAddr(conn.LocalAddr())
|
||||
}
|
||||
|
||||
if dest.IsValid() {
|
||||
// Check if try to connect to this inbound itself (can cause loopback)
|
||||
var isLoopBack bool
|
||||
if w.address == net.AnyIP || w.address == net.AnyIPv6 {
|
||||
if dest.Port.Value() == w.port.Value() && IsLocal(dest.Address.IP()) {
|
||||
isLoopBack = true
|
||||
}
|
||||
} else {
|
||||
if w.hub.Addr().String() == dest.NetAddr() {
|
||||
isLoopBack = true
|
||||
}
|
||||
}
|
||||
if isLoopBack {
|
||||
cancel()
|
||||
conn.Close()
|
||||
errors.LogError(ctx, errors.New("loopback connection detected"))
|
||||
return
|
||||
}
|
||||
outbounds[0].Target = dest
|
||||
}
|
||||
}
|
||||
@@ -91,6 +110,7 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
||||
}
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||
Source: net.DestinationFromAddr(conn.RemoteAddr()),
|
||||
Local: net.DestinationFromAddr(conn.LocalAddr()),
|
||||
Gateway: net.TCPDestination(w.address, w.port),
|
||||
Tag: w.tag,
|
||||
Conn: conn,
|
||||
@@ -321,8 +341,18 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
||||
outbounds[0].Target = originalDest
|
||||
}
|
||||
ctx = session.ContextWithOutbounds(ctx, outbounds)
|
||||
local := net.DestinationFromAddr(w.hub.Addr())
|
||||
if local.Address == net.AnyIP || local.Address == net.AnyIPv6 {
|
||||
if source.Address.Family().IsIPv4() {
|
||||
local.Address = net.AnyIP
|
||||
} else if source.Address.Family().IsIPv6() {
|
||||
local.Address = net.AnyIPv6
|
||||
}
|
||||
}
|
||||
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||
Source: source,
|
||||
Local: local, // Due to some limitations, in UDP connections, localIP is always equal to listen interface IP
|
||||
Gateway: net.UDPDestination(w.address, w.port),
|
||||
Tag: w.tag,
|
||||
})
|
||||
@@ -472,6 +502,7 @@ func (w *dsWorker) callback(conn stat.Connection) {
|
||||
}
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||
Source: net.DestinationFromAddr(conn.RemoteAddr()),
|
||||
Local: net.DestinationFromAddr(conn.LocalAddr()),
|
||||
Gateway: net.UnixDestination(w.address),
|
||||
Tag: w.tag,
|
||||
Conn: conn,
|
||||
@@ -532,3 +563,18 @@ func (w *dsWorker) Close() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsLocal(ip net.IP) bool {
|
||||
addrs, err := gonet.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
if ipnet, ok := addr.(*gonet.IPNet); ok {
|
||||
if ipnet.IP.Equal(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
gonet "net"
|
||||
"os"
|
||||
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
|
||||
"github.com/xtls/xray-core/app/proxyman"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
@@ -106,6 +108,8 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
||||
}
|
||||
h.proxyConfig = proxyConfig
|
||||
|
||||
ctx = session.ContextWithHandler(ctx, h)
|
||||
|
||||
rawProxyHandler, err := common.CreateObject(ctx, proxyConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -177,6 +181,29 @@ func (h *Handler) Tag() string {
|
||||
func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
content := session.ContentFromContext(ctx)
|
||||
if h.senderSettings != nil && h.senderSettings.TargetStrategy.HasStrategy() && ob.Target.Address.Family().IsDomain() && (content == nil || !content.SkipDNSResolve) {
|
||||
strategy := h.senderSettings.TargetStrategy
|
||||
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil {
|
||||
strategy = strategy.GetDynamicStrategy(ob.OriginalTarget.Address.Family())
|
||||
}
|
||||
ips, err := internet.LookupForIP(ob.Target.Address.Domain(), strategy, nil)
|
||||
if err != nil {
|
||||
errors.LogInfoInner(ctx, err, "failed to resolve ip for target ", ob.Target.Address.Domain())
|
||||
if h.senderSettings.TargetStrategy.ForceIP() {
|
||||
err := errors.New("failed to resolve ip for target ", ob.Target.Address.Domain()).Base(err)
|
||||
session.SubmitOutboundErrorToOriginator(ctx, err)
|
||||
common.Interrupt(link.Writer)
|
||||
common.Interrupt(link.Reader)
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
unchangedDomain := ob.Target.Address.Domain()
|
||||
ob.Target.Address = net.IPAddress(ips[dice.Roll(len(ips))])
|
||||
errors.LogInfo(ctx, "target: ", unchangedDomain, " resolved to: ", ob.Target.Address.String())
|
||||
}
|
||||
}
|
||||
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil && ob.OriginalTarget.Address != ob.Target.Address {
|
||||
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}
|
||||
@@ -188,6 +215,7 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
||||
session.SubmitOutboundErrorToOriginator(ctx, err)
|
||||
errors.LogInfo(ctx, err.Error())
|
||||
common.Interrupt(link.Writer)
|
||||
common.Interrupt(link.Reader)
|
||||
}
|
||||
}
|
||||
if ob.Target.Network == net.Network_UDP && ob.Target.Port == 443 {
|
||||
@@ -213,8 +241,10 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
||||
}
|
||||
out:
|
||||
err := h.proxy.Process(ctx, link, h)
|
||||
var errC error
|
||||
if err != nil {
|
||||
if goerrors.Is(err, io.EOF) || goerrors.Is(err, io.ErrClosedPipe) || goerrors.Is(err, context.Canceled) {
|
||||
errC = errors.Cause(err)
|
||||
if goerrors.Is(errC, io.EOF) || goerrors.Is(errC, io.ErrClosedPipe) || goerrors.Is(errC, context.Canceled) {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
@@ -225,19 +255,15 @@ out:
|
||||
errors.LogInfo(ctx, err.Error())
|
||||
common.Interrupt(link.Writer)
|
||||
} else {
|
||||
common.Close(link.Writer)
|
||||
if errC != nil && goerrors.Is(errC, io.ErrClosedPipe) {
|
||||
common.Interrupt(link.Writer)
|
||||
} else {
|
||||
common.Close(link.Writer)
|
||||
}
|
||||
}
|
||||
common.Interrupt(link.Reader)
|
||||
}
|
||||
|
||||
// Address implements internet.Dialer.
|
||||
func (h *Handler) Address() net.Address {
|
||||
if h.senderSettings == nil || h.senderSettings.Via == nil {
|
||||
return nil
|
||||
}
|
||||
return h.senderSettings.Via.AsAddress()
|
||||
}
|
||||
|
||||
func (h *Handler) DestIpAddress() net.IP {
|
||||
return internet.DestIpAddress()
|
||||
}
|
||||
@@ -272,49 +298,16 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
||||
return h.getStatCouterConnection(conn), nil
|
||||
}
|
||||
|
||||
errors.LogWarning(ctx, "failed to get outbound handler with tag: ", tag)
|
||||
errors.LogError(ctx, "failed to get outbound handler with tag: ", tag)
|
||||
return nil, errors.New("failed to get outbound handler with tag: " + tag)
|
||||
}
|
||||
|
||||
if h.senderSettings.Via != nil {
|
||||
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
var domain string
|
||||
addr := h.senderSettings.Via.AsAddress()
|
||||
domain = h.senderSettings.Via.GetDomain()
|
||||
switch {
|
||||
case h.senderSettings.ViaCidr != "":
|
||||
ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr)
|
||||
|
||||
case domain == "origin":
|
||||
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if inbound.Conn != nil {
|
||||
origin, _, err := net.SplitHostPort(inbound.Conn.LocalAddr().String())
|
||||
if err == nil {
|
||||
ob.Gateway = net.ParseAddress(origin)
|
||||
errors.LogDebug(ctx, "use receive package ip as snedthrough: ", origin)
|
||||
}
|
||||
}
|
||||
}
|
||||
case domain == "srcip":
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if inbound.Conn != nil {
|
||||
clientaddr, _, err := net.SplitHostPort(inbound.Conn.RemoteAddr().String())
|
||||
if err == nil {
|
||||
ob.Gateway = net.ParseAddress(clientaddr)
|
||||
errors.LogDebug(ctx, "use client src ip as snedthrough: ", clientaddr)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//case addr.Family().IsDomain():
|
||||
default:
|
||||
ob.Gateway = addr
|
||||
|
||||
}
|
||||
|
||||
h.SetOutboundGateway(ctx, ob)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if conn, err := h.getUoTConnection(ctx, dest); err != os.ErrInvalid {
|
||||
@@ -329,6 +322,38 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
||||
return conn, err
|
||||
}
|
||||
|
||||
func (h *Handler) SetOutboundGateway(ctx context.Context, ob *session.Outbound) {
|
||||
if ob.Gateway == nil && h.senderSettings != nil && h.senderSettings.Via != nil && !h.senderSettings.ProxySettings.HasTag() && (h.streamSettings.SocketSettings == nil || len(h.streamSettings.SocketSettings.DialerProxy) == 0) {
|
||||
var domain string
|
||||
addr := h.senderSettings.Via.AsAddress()
|
||||
domain = h.senderSettings.Via.GetDomain()
|
||||
switch {
|
||||
case h.senderSettings.ViaCidr != "":
|
||||
ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr)
|
||||
|
||||
case domain == "origin":
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if inbound.Local.IsValid() && inbound.Local.Address.Family().IsIP() {
|
||||
ob.Gateway = inbound.Local.Address
|
||||
errors.LogDebug(ctx, "use inbound local ip as sendthrough: ", inbound.Local.Address.String())
|
||||
}
|
||||
}
|
||||
case domain == "srcip":
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if inbound.Source.IsValid() && inbound.Source.Address.Family().IsIP() {
|
||||
ob.Gateway = inbound.Source.Address
|
||||
errors.LogDebug(ctx, "use inbound source ip as sendthrough: ", inbound.Source.Address.String())
|
||||
}
|
||||
}
|
||||
//case addr.Family().IsDomain():
|
||||
default:
|
||||
ob.Gateway = addr
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) getStatCouterConnection(conn stat.Connection) stat.Connection {
|
||||
if h.uplinkCounter != nil || h.downlinkCounter != nil {
|
||||
return &stat.CounterConnection{
|
||||
|
||||
@@ -4,10 +4,12 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/app/dispatcher"
|
||||
"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"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
@@ -52,6 +54,11 @@ func (b *Bridge) cleanup() {
|
||||
if w.IsActive() {
|
||||
activeWorkers = append(activeWorkers, w)
|
||||
}
|
||||
if w.Closed() {
|
||||
if w.Timer != nil {
|
||||
w.Timer.SetTimeout(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(activeWorkers) != len(b.workers) {
|
||||
@@ -93,10 +100,11 @@ func (b *Bridge) Close() error {
|
||||
}
|
||||
|
||||
type BridgeWorker struct {
|
||||
tag string
|
||||
worker *mux.ServerWorker
|
||||
dispatcher routing.Dispatcher
|
||||
state Control_State
|
||||
Tag string
|
||||
Worker *mux.ServerWorker
|
||||
Dispatcher routing.Dispatcher
|
||||
State Control_State
|
||||
Timer *signal.ActivityTimer
|
||||
}
|
||||
|
||||
func NewBridgeWorker(domain string, tag string, d routing.Dispatcher) (*BridgeWorker, error) {
|
||||
@@ -114,16 +122,20 @@ func NewBridgeWorker(domain string, tag string, d routing.Dispatcher) (*BridgeWo
|
||||
}
|
||||
|
||||
w := &BridgeWorker{
|
||||
dispatcher: d,
|
||||
tag: tag,
|
||||
Dispatcher: d,
|
||||
Tag: tag,
|
||||
}
|
||||
|
||||
worker, err := mux.NewServerWorker(context.Background(), w, link)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
w.worker = worker
|
||||
w.Worker = worker
|
||||
|
||||
terminate := func() {
|
||||
worker.Close()
|
||||
}
|
||||
w.Timer = signal.CancelAfterInactivity(ctx, terminate, 60*time.Second)
|
||||
return w, nil
|
||||
}
|
||||
|
||||
@@ -140,48 +152,63 @@ func (w *BridgeWorker) Close() error {
|
||||
}
|
||||
|
||||
func (w *BridgeWorker) IsActive() bool {
|
||||
return w.state == Control_ACTIVE && !w.worker.Closed()
|
||||
return w.State == Control_ACTIVE && !w.Worker.Closed()
|
||||
}
|
||||
|
||||
func (w *BridgeWorker) Closed() bool {
|
||||
return w.Worker.Closed()
|
||||
}
|
||||
|
||||
func (w *BridgeWorker) Connections() uint32 {
|
||||
return w.worker.ActiveConnections()
|
||||
return w.Worker.ActiveConnections()
|
||||
}
|
||||
|
||||
func (w *BridgeWorker) handleInternalConn(link *transport.Link) {
|
||||
go func() {
|
||||
reader := link.Reader
|
||||
for {
|
||||
mb, err := reader.ReadMultiBuffer()
|
||||
if err != nil {
|
||||
break
|
||||
reader := link.Reader
|
||||
for {
|
||||
mb, err := reader.ReadMultiBuffer()
|
||||
if err != nil {
|
||||
if w.Timer != nil {
|
||||
if w.Closed() {
|
||||
w.Timer.SetTimeout(0)
|
||||
} else {
|
||||
w.Timer.SetTimeout(24 * time.Hour)
|
||||
}
|
||||
}
|
||||
for _, b := range mb {
|
||||
var ctl Control
|
||||
if err := proto.Unmarshal(b.Bytes(), &ctl); err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "failed to parse proto message")
|
||||
break
|
||||
}
|
||||
if ctl.State != w.state {
|
||||
w.state = ctl.State
|
||||
return
|
||||
}
|
||||
if w.Timer != nil {
|
||||
w.Timer.Update()
|
||||
}
|
||||
for _, b := range mb {
|
||||
var ctl Control
|
||||
if err := proto.Unmarshal(b.Bytes(), &ctl); err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "failed to parse proto message")
|
||||
if w.Timer != nil {
|
||||
w.Timer.SetTimeout(0)
|
||||
}
|
||||
return
|
||||
}
|
||||
if ctl.State != w.State {
|
||||
w.State = ctl.State
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {
|
||||
if !isInternalDomain(dest) {
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||
Tag: w.tag,
|
||||
Tag: w.Tag,
|
||||
})
|
||||
return w.dispatcher.Dispatch(ctx, dest)
|
||||
return w.Dispatcher.Dispatch(ctx, dest)
|
||||
}
|
||||
|
||||
opt := []pipe.Option{pipe.WithSizeLimit(16 * 1024)}
|
||||
uplinkReader, uplinkWriter := pipe.New(opt...)
|
||||
downlinkReader, downlinkWriter := pipe.New(opt...)
|
||||
|
||||
w.handleInternalConn(&transport.Link{
|
||||
go w.handleInternalConn(&transport.Link{
|
||||
Reader: downlinkReader,
|
||||
Writer: uplinkWriter,
|
||||
})
|
||||
@@ -195,11 +222,12 @@ func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*tra
|
||||
func (w *BridgeWorker) DispatchLink(ctx context.Context, dest net.Destination, link *transport.Link) error {
|
||||
if !isInternalDomain(dest) {
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||
Tag: w.tag,
|
||||
Tag: w.Tag,
|
||||
})
|
||||
return w.dispatcher.DispatchLink(ctx, dest, link)
|
||||
return w.Dispatcher.DispatchLink(ctx, dest, link)
|
||||
}
|
||||
|
||||
link = w.Dispatcher.(*dispatcher.DefaultDispatcher).WrapLink(ctx, link)
|
||||
w.handleInternalConn(link)
|
||||
|
||||
return nil
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
@@ -82,9 +83,21 @@ func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) err
|
||||
}
|
||||
|
||||
p.picker.AddWorker(worker)
|
||||
|
||||
if _, ok := link.Reader.(*pipe.Reader); !ok {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-muxClient.WaitClosed():
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil && ob.OriginalTarget.Address != ob.Target.Address {
|
||||
link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
||||
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
||||
}
|
||||
|
||||
return p.client.Dispatch(ctx, link)
|
||||
}
|
||||
|
||||
@@ -101,6 +114,7 @@ func (o *Outbound) Dispatch(ctx context.Context, link *transport.Link) {
|
||||
if err := o.portal.HandleConnection(ctx, link); err != nil {
|
||||
errors.LogInfoInner(ctx, err, "failed to process reverse connection")
|
||||
common.Interrupt(link.Writer)
|
||||
common.Interrupt(link.Reader)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +160,8 @@ func (p *StaticMuxPicker) cleanup() error {
|
||||
for _, w := range p.workers {
|
||||
if !w.Closed() {
|
||||
activeWorkers = append(activeWorkers, w)
|
||||
} else {
|
||||
w.timer.SetTimeout(0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +228,7 @@ type PortalWorker struct {
|
||||
reader buf.Reader
|
||||
draining bool
|
||||
counter uint32
|
||||
timer *signal.ActivityTimer
|
||||
}
|
||||
|
||||
func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
||||
@@ -231,10 +248,14 @@ func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
||||
if !f {
|
||||
return nil, errors.New("unable to dispatch control connection")
|
||||
}
|
||||
terminate := func() {
|
||||
client.Close()
|
||||
}
|
||||
w := &PortalWorker{
|
||||
client: client,
|
||||
reader: downlinkReader,
|
||||
writer: uplinkWriter,
|
||||
timer: signal.CancelAfterInactivity(ctx, terminate, 24*time.Hour), // // prevent leak
|
||||
}
|
||||
w.control = &task.Periodic{
|
||||
Execute: w.heartbeat,
|
||||
@@ -261,7 +282,6 @@ func (w *PortalWorker) heartbeat() error {
|
||||
msg.State = Control_DRAIN
|
||||
|
||||
defer func() {
|
||||
w.client.GetTimer().Reset(time.Second * 16)
|
||||
common.Close(w.writer)
|
||||
common.Interrupt(w.reader)
|
||||
w.writer = nil
|
||||
@@ -273,6 +293,7 @@ func (w *PortalWorker) heartbeat() error {
|
||||
b, err := proto.Marshal(msg)
|
||||
common.Must(err)
|
||||
mb := buf.MergeBytes(nil, b)
|
||||
w.timer.Update()
|
||||
return w.writer.WriteMultiBuffer(mb)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
internalDomain = "reverse.internal.v2fly.org" // make reverse proxy compatible with v2fly
|
||||
internalDomain = "reverse"
|
||||
)
|
||||
|
||||
func isDomain(dest net.Destination, domain string) bool {
|
||||
|
||||
@@ -42,6 +42,9 @@ type RoutingContext struct {
|
||||
Attributes map[string]string `protobuf:"bytes,10,rep,name=Attributes,proto3" json:"Attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
OutboundGroupTags []string `protobuf:"bytes,11,rep,name=OutboundGroupTags,proto3" json:"OutboundGroupTags,omitempty"`
|
||||
OutboundTag string `protobuf:"bytes,12,opt,name=OutboundTag,proto3" json:"OutboundTag,omitempty"`
|
||||
LocalIPs [][]byte `protobuf:"bytes,13,rep,name=LocalIPs,proto3" json:"LocalIPs,omitempty"`
|
||||
LocalPort uint32 `protobuf:"varint,14,opt,name=LocalPort,proto3" json:"LocalPort,omitempty"`
|
||||
VlessRoute uint32 `protobuf:"varint,15,opt,name=VlessRoute,proto3" json:"VlessRoute,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RoutingContext) Reset() {
|
||||
@@ -158,6 +161,27 @@ func (x *RoutingContext) GetOutboundTag() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RoutingContext) GetLocalIPs() [][]byte {
|
||||
if x != nil {
|
||||
return x.LocalIPs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *RoutingContext) GetLocalPort() uint32 {
|
||||
if x != nil {
|
||||
return x.LocalPort
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *RoutingContext) GetVlessRoute() uint32 {
|
||||
if x != nil {
|
||||
return x.VlessRoute
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// SubscribeRoutingStatsRequest subscribes to routing statistics channel if
|
||||
// opened by xray-core.
|
||||
// * FieldSelectors selects a subset of fields in routing statistics to return.
|
||||
@@ -827,7 +851,7 @@ var file_app_router_command_command_proto_rawDesc = []byte{
|
||||
0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65,
|
||||
0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9c, 0x04, 0x0a, 0x0e, 0x52, 0x6f, 0x75,
|
||||
0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf6, 0x04, 0x0a, 0x0e, 0x52, 0x6f, 0x75,
|
||||
0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x49,
|
||||
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0a, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x32, 0x0a, 0x07, 0x4e,
|
||||
@@ -857,123 +881,129 @@ var file_app_router_command_command_proto_rawDesc = []byte{
|
||||
0x03, 0x28, 0x09, 0x52, 0x11, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x47, 0x72, 0x6f,
|
||||
0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75,
|
||||
0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x75, 0x74,
|
||||
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72,
|
||||
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
|
||||
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
|
||||
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x46, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x73, 0x63,
|
||||
0x72, 0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64,
|
||||
0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||
0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22,
|
||||
0xb1, 0x01, 0x0a, 0x10, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x4f, 0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43,
|
||||
0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
||||
0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
||||
0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65,
|
||||
0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46,
|
||||
0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x24, 0x0a,
|
||||
0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73,
|
||||
0x75, 0x6c, 0x74, 0x22, 0x27, 0x0a, 0x13, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65,
|
||||
0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
|
||||
0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x26, 0x0a, 0x0c,
|
||||
0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x22, 0xa9, 0x01, 0x0a, 0x0b, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65,
|
||||
0x72, 0x4d, 0x73, 0x67, 0x12, 0x41, 0x0a, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61,
|
||||
0x6c, 0x49, 0x50, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x4c, 0x6f, 0x63, 0x61,
|
||||
0x6c, 0x49, 0x50, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72,
|
||||
0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f,
|
||||
0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x18, 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x75,
|
||||
0x74, 0x65, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
|
||||
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
|
||||
0x01, 0x22, 0x46, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f,
|
||||
0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74,
|
||||
0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64,
|
||||
0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xb1, 0x01, 0x0a, 0x10, 0x54, 0x65,
|
||||
0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4f,
|
||||
0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6f,
|
||||
0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x57, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x6e, 0x63,
|
||||
0x69, 0x70, 0x6c, 0x65, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
|
||||
0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x72, 0x69, 0x6e,
|
||||
0x63, 0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52,
|
||||
0x0f, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x22, 0x2a, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49,
|
||||
0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
|
||||
0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x5b, 0x0a, 0x17,
|
||||
0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x52,
|
||||
0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x22, 0x59, 0x0a, 0x1d, 0x4f, 0x76, 0x65,
|
||||
0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72,
|
||||
0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61,
|
||||
0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0b, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x22, 0x20, 0x0a, 0x1e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
|
||||
0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6e, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c,
|
||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79,
|
||||
0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x41, 0x70, 0x70, 0x65,
|
||||
0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64,
|
||||
0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x22, 0x11, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c,
|
||||
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2d, 0x0a, 0x11, 0x52, 0x65, 0x6d,
|
||||
0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x07, 0x72, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x67, 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f,
|
||||
0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08,
|
||||
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0xbf, 0x05, 0x0a, 0x0e, 0x52, 0x6f, 0x75,
|
||||
0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7b, 0x0a, 0x15, 0x53,
|
||||
0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53,
|
||||
0x74, 0x61, 0x74, 0x73, 0x12, 0x35, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53,
|
||||
0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53,
|
||||
0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x78, 0x72,
|
||||
0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52,
|
||||
0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12,
|
||||
0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72,
|
||||
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65,
|
||||
0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69,
|
||||
0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d,
|
||||
0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x27, 0x0a,
|
||||
0x13, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28,
|
||||
0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x26, 0x0a, 0x0c, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
||||
0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0xa9,
|
||||
0x01, 0x0a, 0x0b, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x41,
|
||||
0x0a, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72,
|
||||
0x69, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
|
||||
0x65, 0x12, 0x57, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x74,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
|
||||
0x74, 0x65, 0x78, 0x74, 0x22, 0x00, 0x30, 0x01, 0x12, 0x61, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74,
|
||||
0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
||||
0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00, 0x12, 0x76, 0x0a, 0x0f, 0x47,
|
||||
0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2f,
|
||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x54,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x70, 0x72, 0x69, 0x6e, 0x63,
|
||||
0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x2a, 0x0a, 0x16, 0x47, 0x65,
|
||||
0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x5b, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c,
|
||||
0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x00, 0x12, 0x8b, 0x01, 0x0a, 0x16, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
|
||||
0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x36,
|
||||
0x65, 0x12, 0x40, 0x0a, 0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x42, 0x61,
|
||||
0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x52, 0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x72, 0x22, 0x59, 0x0a, 0x1d, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42,
|
||||
0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72,
|
||||
0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x72, 0x54, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x20,
|
||||
0x0a, 0x1e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x6e, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x38, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x22, 0x0a, 0x0c,
|
||||
0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x08, 0x52, 0x0c, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64,
|
||||
0x22, 0x11, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x22, 0x2d, 0x0a, 0x11, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c,
|
||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65,
|
||||
0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x54,
|
||||
0x61, 0x67, 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x32, 0xbf, 0x05, 0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7b, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
|
||||
0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x35,
|
||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
|
||||
0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65,
|
||||
0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x00, 0x12, 0x5e, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x27, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
|
||||
0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
||||
0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x00, 0x12, 0x67, 0x0a, 0x0a, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x12,
|
||||
0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
||||
0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f,
|
||||
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74,
|
||||
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00,
|
||||
0x30, 0x01, 0x12, 0x61, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12,
|
||||
0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f,
|
||||
0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74,
|
||||
0x65, 0x78, 0x74, 0x22, 0x00, 0x12, 0x76, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
||||
0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e,
|
||||
0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49,
|
||||
0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x8b, 0x01,
|
||||
0x0a, 0x16, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x36, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
||||
0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x37, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72,
|
||||
0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x07, 0x41,
|
||||
0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x2e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c,
|
||||
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x67, 0x0a, 0x0a, 0x52,
|
||||
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
||||
0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x00, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65,
|
||||
0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -25,6 +25,9 @@ message RoutingContext {
|
||||
map<string, string> Attributes = 10;
|
||||
repeated string OutboundGroupTags = 11;
|
||||
string OutboundTag = 12;
|
||||
repeated bytes LocalIPs = 13;
|
||||
uint32 LocalPort = 14;
|
||||
uint32 VlessRoute = 15;
|
||||
}
|
||||
|
||||
// SubscribeRoutingStatsRequest subscribes to routing statistics channel if
|
||||
|
||||
@@ -28,6 +28,18 @@ func (c routingContext) GetTargetPort() net.Port {
|
||||
return net.Port(c.RoutingContext.GetTargetPort())
|
||||
}
|
||||
|
||||
func (c routingContext) GetLocalIPs() []net.IP {
|
||||
return mapBytesToIPs(c.RoutingContext.GetLocalIPs())
|
||||
}
|
||||
|
||||
func (c routingContext) GetLocalPort() net.Port {
|
||||
return net.Port(c.RoutingContext.GetLocalPort())
|
||||
}
|
||||
|
||||
func (c routingContext) GetVlessRoute() net.Port {
|
||||
return net.Port(c.RoutingContext.GetVlessRoute())
|
||||
}
|
||||
|
||||
func (c routingContext) GetRuleTag() string {
|
||||
return ""
|
||||
}
|
||||
@@ -39,6 +51,10 @@ func (c routingContext) GetSkipDNSResolve() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c routingContext) GetError() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AsRoutingContext converts a protobuf RoutingContext into an implementation of routing.Context.
|
||||
func AsRoutingContext(r *RoutingContext) routing.Context {
|
||||
return routingContext{r}
|
||||
@@ -54,8 +70,10 @@ var fieldMap = map[string]func(*RoutingContext, routing.Route){
|
||||
"network": func(s *RoutingContext, r routing.Route) { s.Network = r.GetNetwork() },
|
||||
"ip_source": func(s *RoutingContext, r routing.Route) { s.SourceIPs = mapIPsToBytes(r.GetSourceIPs()) },
|
||||
"ip_target": func(s *RoutingContext, r routing.Route) { s.TargetIPs = mapIPsToBytes(r.GetTargetIPs()) },
|
||||
"ip_local": func(s *RoutingContext, r routing.Route) { s.LocalIPs = mapIPsToBytes(r.GetLocalIPs()) },
|
||||
"port_source": func(s *RoutingContext, r routing.Route) { s.SourcePort = uint32(r.GetSourcePort()) },
|
||||
"port_target": func(s *RoutingContext, r routing.Route) { s.TargetPort = uint32(r.GetTargetPort()) },
|
||||
"port_local": func(s *RoutingContext, r routing.Route) { s.LocalPort = uint32(r.GetLocalPort()) },
|
||||
"domain": func(s *RoutingContext, r routing.Route) { s.TargetDomain = r.GetTargetDomain() },
|
||||
"protocol": func(s *RoutingContext, r routing.Route) { s.Protocol = r.GetProtocol() },
|
||||
"user": func(s *RoutingContext, r routing.Route) { s.User = r.GetUser() },
|
||||
|
||||
@@ -83,21 +83,6 @@ func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
|
||||
g := new(strmatcher.MatcherGroup)
|
||||
for _, d := range domains {
|
||||
m, err := domainToMatcher(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.Add(m)
|
||||
}
|
||||
|
||||
return &DomainMatcher{
|
||||
matchers: g,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *DomainMatcher) ApplyDomain(domain string) bool {
|
||||
return len(m.matchers.Match(strings.ToLower(domain))) > 0
|
||||
}
|
||||
@@ -113,10 +98,10 @@ func (m *DomainMatcher) Apply(ctx routing.Context) bool {
|
||||
|
||||
type MultiGeoIPMatcher struct {
|
||||
matchers []*GeoIPMatcher
|
||||
onSource bool
|
||||
asType string // local, source, target
|
||||
}
|
||||
|
||||
func NewMultiGeoIPMatcher(geoips []*GeoIP, onSource bool) (*MultiGeoIPMatcher, error) {
|
||||
func NewMultiGeoIPMatcher(geoips []*GeoIP, asType string) (*MultiGeoIPMatcher, error) {
|
||||
var matchers []*GeoIPMatcher
|
||||
for _, geoip := range geoips {
|
||||
matcher, err := GlobalGeoIPContainer.Add(geoip)
|
||||
@@ -128,7 +113,7 @@ func NewMultiGeoIPMatcher(geoips []*GeoIP, onSource bool) (*MultiGeoIPMatcher, e
|
||||
|
||||
matcher := &MultiGeoIPMatcher{
|
||||
matchers: matchers,
|
||||
onSource: onSource,
|
||||
asType: asType,
|
||||
}
|
||||
|
||||
return matcher, nil
|
||||
@@ -137,11 +122,18 @@ func NewMultiGeoIPMatcher(geoips []*GeoIP, onSource bool) (*MultiGeoIPMatcher, e
|
||||
// Apply implements Condition.
|
||||
func (m *MultiGeoIPMatcher) Apply(ctx routing.Context) bool {
|
||||
var ips []net.IP
|
||||
if m.onSource {
|
||||
|
||||
switch m.asType {
|
||||
case "local":
|
||||
ips = ctx.GetLocalIPs()
|
||||
case "source":
|
||||
ips = ctx.GetSourceIPs()
|
||||
} else {
|
||||
case "target":
|
||||
ips = ctx.GetTargetIPs()
|
||||
default:
|
||||
panic("unreachable, asType should be local or source or target")
|
||||
}
|
||||
|
||||
for _, ip := range ips {
|
||||
for _, matcher := range m.matchers {
|
||||
if matcher.Match(ip) {
|
||||
@@ -153,25 +145,33 @@ func (m *MultiGeoIPMatcher) Apply(ctx routing.Context) bool {
|
||||
}
|
||||
|
||||
type PortMatcher struct {
|
||||
port net.MemoryPortList
|
||||
onSource bool
|
||||
port net.MemoryPortList
|
||||
asType string // local, source, target
|
||||
}
|
||||
|
||||
// NewPortMatcher create a new port matcher that can match source or destination port
|
||||
func NewPortMatcher(list *net.PortList, onSource bool) *PortMatcher {
|
||||
// NewPortMatcher create a new port matcher that can match source or local or destination port
|
||||
func NewPortMatcher(list *net.PortList, asType string) *PortMatcher {
|
||||
return &PortMatcher{
|
||||
port: net.PortListFromProto(list),
|
||||
onSource: onSource,
|
||||
port: net.PortListFromProto(list),
|
||||
asType: asType,
|
||||
}
|
||||
}
|
||||
|
||||
// Apply implements Condition.
|
||||
func (v *PortMatcher) Apply(ctx routing.Context) bool {
|
||||
if v.onSource {
|
||||
switch v.asType {
|
||||
case "local":
|
||||
return v.port.Contains(ctx.GetLocalPort())
|
||||
case "source":
|
||||
return v.port.Contains(ctx.GetSourcePort())
|
||||
} else {
|
||||
case "target":
|
||||
return v.port.Contains(ctx.GetTargetPort())
|
||||
case "vlessRoute":
|
||||
return v.port.Contains(ctx.GetVlessRoute())
|
||||
default:
|
||||
panic("unreachable, asType should be local or source or target")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type NetworkMatcher struct {
|
||||
|
||||
@@ -328,9 +328,6 @@ func TestChinaSites(t *testing.T) {
|
||||
domains, err := loadGeoSite("CN")
|
||||
common.Must(err)
|
||||
|
||||
matcher, err := NewDomainMatcher(domains)
|
||||
common.Must(err)
|
||||
|
||||
acMatcher, err := NewMphMatcherGroup(domains)
|
||||
common.Must(err)
|
||||
|
||||
@@ -362,12 +359,9 @@ func TestChinaSites(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
r1 := matcher.ApplyDomain(testCase.Domain)
|
||||
r2 := acMatcher.ApplyDomain(testCase.Domain)
|
||||
if r1 != testCase.Output {
|
||||
t.Error("DomainMatcher expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r1)
|
||||
} else if r2 != testCase.Output {
|
||||
t.Error("ACDomainMatcher expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r2)
|
||||
r := acMatcher.ApplyDomain(testCase.Domain)
|
||||
if r != testCase.Output {
|
||||
t.Error("ACDomainMatcher expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -414,48 +408,6 @@ func BenchmarkMphDomainMatcher(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDomainMatcher(b *testing.B) {
|
||||
domains, err := loadGeoSite("CN")
|
||||
common.Must(err)
|
||||
|
||||
matcher, err := NewDomainMatcher(domains)
|
||||
common.Must(err)
|
||||
|
||||
type TestCase struct {
|
||||
Domain string
|
||||
Output bool
|
||||
}
|
||||
testCases := []TestCase{
|
||||
{
|
||||
Domain: "163.com",
|
||||
Output: true,
|
||||
},
|
||||
{
|
||||
Domain: "163.com",
|
||||
Output: true,
|
||||
},
|
||||
{
|
||||
Domain: "164.com",
|
||||
Output: false,
|
||||
},
|
||||
{
|
||||
Domain: "164.com",
|
||||
Output: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i := 0; i < 1024; i++ {
|
||||
testCases = append(testCases, TestCase{Domain: strconv.Itoa(i) + ".not-exists.com", Output: false})
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, testCase := range testCases {
|
||||
_ = matcher.ApplyDomain(testCase.Domain)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMultiGeoIPMatcher(b *testing.B) {
|
||||
var geoips []*GeoIP
|
||||
|
||||
@@ -495,7 +447,7 @@ func BenchmarkMultiGeoIPMatcher(b *testing.B) {
|
||||
})
|
||||
}
|
||||
|
||||
matcher, err := NewMultiGeoIPMatcher(geoips, false)
|
||||
matcher, err := NewMultiGeoIPMatcher(geoips, "target")
|
||||
common.Must(err)
|
||||
|
||||
ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)})
|
||||
|
||||
@@ -33,39 +33,36 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||
conds := NewConditionChan()
|
||||
|
||||
if len(rr.Domain) > 0 {
|
||||
switch rr.DomainMatcher {
|
||||
case "linear":
|
||||
matcher, err := NewDomainMatcher(rr.Domain)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build domain condition").Base(err)
|
||||
}
|
||||
conds.Add(matcher)
|
||||
case "mph", "hybrid":
|
||||
fallthrough
|
||||
default:
|
||||
matcher, err := NewMphMatcherGroup(rr.Domain)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build domain condition with MphDomainMatcher").Base(err)
|
||||
}
|
||||
errors.LogDebug(context.Background(), "MphDomainMatcher is enabled for ", len(rr.Domain), " domain rule(s)")
|
||||
conds.Add(matcher)
|
||||
matcher, err := NewMphMatcherGroup(rr.Domain)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build domain condition with MphDomainMatcher").Base(err)
|
||||
}
|
||||
errors.LogDebug(context.Background(), "MphDomainMatcher is enabled for ", len(rr.Domain), " domain rule(s)")
|
||||
conds.Add(matcher)
|
||||
}
|
||||
|
||||
if len(rr.UserEmail) > 0 {
|
||||
conds.Add(NewUserMatcher(rr.UserEmail))
|
||||
}
|
||||
|
||||
if rr.VlessRouteList != nil {
|
||||
conds.Add(NewPortMatcher(rr.VlessRouteList, "vlessRoute"))
|
||||
}
|
||||
|
||||
if len(rr.InboundTag) > 0 {
|
||||
conds.Add(NewInboundTagMatcher(rr.InboundTag))
|
||||
}
|
||||
|
||||
if rr.PortList != nil {
|
||||
conds.Add(NewPortMatcher(rr.PortList, false))
|
||||
conds.Add(NewPortMatcher(rr.PortList, "target"))
|
||||
}
|
||||
|
||||
if rr.SourcePortList != nil {
|
||||
conds.Add(NewPortMatcher(rr.SourcePortList, true))
|
||||
conds.Add(NewPortMatcher(rr.SourcePortList, "source"))
|
||||
}
|
||||
|
||||
if rr.LocalPortList != nil {
|
||||
conds.Add(NewPortMatcher(rr.LocalPortList, "local"))
|
||||
}
|
||||
|
||||
if len(rr.Networks) > 0 {
|
||||
@@ -73,7 +70,7 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||
}
|
||||
|
||||
if len(rr.Geoip) > 0 {
|
||||
cond, err := NewMultiGeoIPMatcher(rr.Geoip, false)
|
||||
cond, err := NewMultiGeoIPMatcher(rr.Geoip, "target")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -81,13 +78,22 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||
}
|
||||
|
||||
if len(rr.SourceGeoip) > 0 {
|
||||
cond, err := NewMultiGeoIPMatcher(rr.SourceGeoip, true)
|
||||
cond, err := NewMultiGeoIPMatcher(rr.SourceGeoip, "source")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conds.Add(cond)
|
||||
}
|
||||
|
||||
if len(rr.LocalGeoip) > 0 {
|
||||
cond, err := NewMultiGeoIPMatcher(rr.LocalGeoip, "local")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conds.Add(cond)
|
||||
errors.LogWarning(context.Background(), "Due to some limitations, in UDP connections, localIP is always equal to listen interface IP, so \"localIP\" rule condition does not work properly on UDP inbound connections that listen on all interfaces")
|
||||
}
|
||||
|
||||
if len(rr.Protocol) > 0 {
|
||||
conds.Add(NewProtocolMatcher(rr.Protocol))
|
||||
}
|
||||
|
||||
@@ -470,7 +470,7 @@ type RoutingRule struct {
|
||||
// *RoutingRule_Tag
|
||||
// *RoutingRule_BalancingTag
|
||||
TargetTag isRoutingRule_TargetTag `protobuf_oneof:"target_tag"`
|
||||
RuleTag string `protobuf:"bytes,18,opt,name=rule_tag,json=ruleTag,proto3" json:"rule_tag,omitempty"`
|
||||
RuleTag string `protobuf:"bytes,19,opt,name=rule_tag,json=ruleTag,proto3" json:"rule_tag,omitempty"`
|
||||
// List of domains for target domain matching.
|
||||
Domain []*Domain `protobuf:"bytes,2,rep,name=domain,proto3" json:"domain,omitempty"`
|
||||
// List of GeoIPs for target IP address matching. If this entry exists, the
|
||||
@@ -491,7 +491,9 @@ type RoutingRule struct {
|
||||
InboundTag []string `protobuf:"bytes,8,rep,name=inbound_tag,json=inboundTag,proto3" json:"inbound_tag,omitempty"`
|
||||
Protocol []string `protobuf:"bytes,9,rep,name=protocol,proto3" json:"protocol,omitempty"`
|
||||
Attributes map[string]string `protobuf:"bytes,15,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
DomainMatcher string `protobuf:"bytes,17,opt,name=domain_matcher,json=domainMatcher,proto3" json:"domain_matcher,omitempty"`
|
||||
LocalGeoip []*GeoIP `protobuf:"bytes,17,rep,name=local_geoip,json=localGeoip,proto3" json:"local_geoip,omitempty"`
|
||||
LocalPortList *net.PortList `protobuf:"bytes,18,opt,name=local_port_list,json=localPortList,proto3" json:"local_port_list,omitempty"`
|
||||
VlessRouteList *net.PortList `protobuf:"bytes,20,opt,name=vless_route_list,json=vlessRouteList,proto3" json:"vless_route_list,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RoutingRule) Reset() {
|
||||
@@ -622,11 +624,25 @@ func (x *RoutingRule) GetAttributes() map[string]string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *RoutingRule) GetDomainMatcher() string {
|
||||
func (x *RoutingRule) GetLocalGeoip() []*GeoIP {
|
||||
if x != nil {
|
||||
return x.DomainMatcher
|
||||
return x.LocalGeoip
|
||||
}
|
||||
return ""
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *RoutingRule) GetLocalPortList() *net.PortList {
|
||||
if x != nil {
|
||||
return x.LocalPortList
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *RoutingRule) GetVlessRouteList() *net.PortList {
|
||||
if x != nil {
|
||||
return x.VlessRouteList
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type isRoutingRule_TargetTag interface {
|
||||
@@ -1069,13 +1085,13 @@ var file_app_router_config_proto_rawDesc = []byte{
|
||||
0x6f, 0x53, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x05, 0x65, 0x6e, 0x74,
|
||||
0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x53, 0x69,
|
||||
0x74, 0x65, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xce, 0x05, 0x0a, 0x0b, 0x52, 0x6f,
|
||||
0x74, 0x65, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xe8, 0x06, 0x0a, 0x0b, 0x52, 0x6f,
|
||||
0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x03, 0x74, 0x61, 0x67,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x25, 0x0a,
|
||||
0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x0c,
|
||||
0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e,
|
||||
0x67, 0x54, 0x61, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x61, 0x67,
|
||||
0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x67, 0x12,
|
||||
0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x67, 0x12,
|
||||
0x2f, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x17, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
@@ -1107,69 +1123,79 @@ var file_app_router_config_proto_rawDesc = []byte{
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52,
|
||||
0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69,
|
||||
0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72,
|
||||
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
|
||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x1a, 0x3d, 0x0a,
|
||||
0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
|
||||
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
|
||||
0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0c, 0x0a, 0x0a,
|
||||
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x22, 0xdc, 0x01, 0x0a, 0x0d, 0x42,
|
||||
0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03,
|
||||
0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b,
|
||||
0x0a, 0x11, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63,
|
||||
0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f,
|
||||
0x75, 0x6e, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4d, 0x0a, 0x11, 0x73, 0x74, 0x72, 0x61, 0x74,
|
||||
0x65, 0x67, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x52, 0x10, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x53, 0x65,
|
||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61,
|
||||
0x63, 0x6b, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x66, 0x61,
|
||||
0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x54, 0x61, 0x67, 0x22, 0x54, 0x0a, 0x0e, 0x53, 0x74, 0x72,
|
||||
0x61, 0x74, 0x65, 0x67, 0x79, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72,
|
||||
0x65, 0x67, 0x65, 0x78, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x67,
|
||||
0x65, 0x78, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,
|
||||
0xc0, 0x01, 0x0a, 0x17, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x4c, 0x65, 0x61, 0x73,
|
||||
0x74, 0x4c, 0x6f, 0x61, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x05, 0x63,
|
||||
0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x72,
|
||||
0x61, 0x74, 0x65, 0x67, 0x79, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x05, 0x63, 0x6f, 0x73,
|
||||
0x74, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18,
|
||||
0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x09, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73,
|
||||
0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x05, 0x52, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x6d, 0x61, 0x78, 0x52, 0x54, 0x54, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6d, 0x61,
|
||||
0x78, 0x52, 0x54, 0x54, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x22, 0x9b, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4f, 0x0a,
|
||||
0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
|
||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e,
|
||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x30,
|
||||
0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52,
|
||||
0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65,
|
||||
0x12, 0x45, 0x0a, 0x0e, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75,
|
||||
0x6c, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63,
|
||||
0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x22, 0x47, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49,
|
||||
0x73, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x49, 0x70, 0x10, 0x01, 0x12, 0x10,
|
||||
0x0a, 0x0c, 0x49, 0x70, 0x49, 0x66, 0x4e, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x02,
|
||||
0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x70, 0x4f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x10, 0x03,
|
||||
0x42, 0x4f, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d,
|
||||
0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0xaa,
|
||||
0x02, 0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f,
|
||||
0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x11, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65,
|
||||
0x6f, 0x49, 0x50, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12,
|
||||
0x41, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69,
|
||||
0x73, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69,
|
||||
0x73, 0x74, 0x12, 0x43, 0x0a, 0x10, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x5f, 0x72, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50,
|
||||
0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x6f,
|
||||
0x75, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69,
|
||||
0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
|
||||
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
|
||||
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x5f, 0x74, 0x61, 0x67, 0x22, 0xdc, 0x01, 0x0a, 0x0d, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69,
|
||||
0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x62,
|
||||
0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20,
|
||||
0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x65, 0x6c,
|
||||
0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
|
||||
0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
|
||||
0x79, 0x12, 0x4d, 0x0a, 0x11, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x5f, 0x73, 0x65,
|
||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61,
|
||||
0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x10,
|
||||
0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
||||
0x12, 0x21, 0x0a, 0x0c, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x61, 0x67,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
|
||||
0x54, 0x61, 0x67, 0x22, 0x54, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x57,
|
||||
0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x12, 0x14, 0x0a,
|
||||
0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61,
|
||||
0x74, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xc0, 0x01, 0x0a, 0x17, 0x53, 0x74,
|
||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x4c, 0x6f, 0x61, 0x64, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x05, 0x63, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x57,
|
||||
0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x05, 0x63, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1c, 0x0a, 0x09,
|
||||
0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52,
|
||||
0x09, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78,
|
||||
0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x65, 0x78,
|
||||
0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x78, 0x52, 0x54, 0x54,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6d, 0x61, 0x78, 0x52, 0x54, 0x54, 0x12, 0x1c,
|
||||
0x0a, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28,
|
||||
0x02, 0x52, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x9b, 0x02, 0x0a,
|
||||
0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4f, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
|
||||
0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x30, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65,
|
||||
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67,
|
||||
0x52, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x45, 0x0a, 0x0e, 0x62, 0x61,
|
||||
0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
|
||||
0x75, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75,
|
||||
0x6c, 0x65, 0x52, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c,
|
||||
0x65, 0x22, 0x47, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74,
|
||||
0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49, 0x73, 0x10, 0x00, 0x12, 0x09, 0x0a,
|
||||
0x05, 0x55, 0x73, 0x65, 0x49, 0x70, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x70, 0x49, 0x66,
|
||||
0x4e, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x70,
|
||||
0x4f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x10, 0x03, 0x42, 0x4f, 0x0a, 0x13, 0x63, 0x6f,
|
||||
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x50, 0x01, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61,
|
||||
0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0xaa, 0x02, 0x0f, 0x58, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -1220,16 +1246,19 @@ var file_app_router_config_proto_depIdxs = []int32{
|
||||
4, // 10: xray.app.router.RoutingRule.source_geoip:type_name -> xray.app.router.GeoIP
|
||||
15, // 11: xray.app.router.RoutingRule.source_port_list:type_name -> xray.common.net.PortList
|
||||
14, // 12: xray.app.router.RoutingRule.attributes:type_name -> xray.app.router.RoutingRule.AttributesEntry
|
||||
17, // 13: xray.app.router.BalancingRule.strategy_settings:type_name -> xray.common.serial.TypedMessage
|
||||
10, // 14: xray.app.router.StrategyLeastLoadConfig.costs:type_name -> xray.app.router.StrategyWeight
|
||||
1, // 15: xray.app.router.Config.domain_strategy:type_name -> xray.app.router.Config.DomainStrategy
|
||||
8, // 16: xray.app.router.Config.rule:type_name -> xray.app.router.RoutingRule
|
||||
9, // 17: xray.app.router.Config.balancing_rule:type_name -> xray.app.router.BalancingRule
|
||||
18, // [18:18] is the sub-list for method output_type
|
||||
18, // [18:18] is the sub-list for method input_type
|
||||
18, // [18:18] is the sub-list for extension type_name
|
||||
18, // [18:18] is the sub-list for extension extendee
|
||||
0, // [0:18] is the sub-list for field type_name
|
||||
4, // 13: xray.app.router.RoutingRule.local_geoip:type_name -> xray.app.router.GeoIP
|
||||
15, // 14: xray.app.router.RoutingRule.local_port_list:type_name -> xray.common.net.PortList
|
||||
15, // 15: xray.app.router.RoutingRule.vless_route_list:type_name -> xray.common.net.PortList
|
||||
17, // 16: xray.app.router.BalancingRule.strategy_settings:type_name -> xray.common.serial.TypedMessage
|
||||
10, // 17: xray.app.router.StrategyLeastLoadConfig.costs:type_name -> xray.app.router.StrategyWeight
|
||||
1, // 18: xray.app.router.Config.domain_strategy:type_name -> xray.app.router.Config.DomainStrategy
|
||||
8, // 19: xray.app.router.Config.rule:type_name -> xray.app.router.RoutingRule
|
||||
9, // 20: xray.app.router.Config.balancing_rule:type_name -> xray.app.router.BalancingRule
|
||||
21, // [21:21] is the sub-list for method output_type
|
||||
21, // [21:21] is the sub-list for method input_type
|
||||
21, // [21:21] is the sub-list for extension type_name
|
||||
21, // [21:21] is the sub-list for extension extendee
|
||||
0, // [0:21] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_app_router_config_proto_init() }
|
||||
|
||||
@@ -79,7 +79,7 @@ message RoutingRule {
|
||||
// Tag of routing balancer.
|
||||
string balancing_tag = 12;
|
||||
}
|
||||
string rule_tag = 18;
|
||||
string rule_tag = 19;
|
||||
|
||||
// List of domains for target domain matching.
|
||||
repeated Domain domain = 2;
|
||||
@@ -109,7 +109,10 @@ message RoutingRule {
|
||||
|
||||
map<string, string> attributes = 15;
|
||||
|
||||
string domain_matcher = 17;
|
||||
repeated GeoIP local_geoip = 17;
|
||||
xray.common.net.PortList local_port_list = 18;
|
||||
|
||||
xray.common.net.PortList vless_route_list = 20;
|
||||
}
|
||||
|
||||
message BalancingRule {
|
||||
|
||||
@@ -195,6 +195,9 @@ func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context,
|
||||
if rule.Apply(ctx) {
|
||||
return rule, ctx, nil
|
||||
}
|
||||
if err := ctx.GetError(); err != nil {
|
||||
return nil, ctx, err
|
||||
}
|
||||
}
|
||||
|
||||
if r.domainStrategy != Config_IpIfNonMatch || len(ctx.GetTargetDomain()) == 0 || skipDNSResolve {
|
||||
@@ -208,6 +211,9 @@ func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context,
|
||||
if rule.Apply(ctx) {
|
||||
return rule, ctx, nil
|
||||
}
|
||||
if err := ctx.GetError(); err != nil {
|
||||
return nil, ctx, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ctx, common.ErrNoClue
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
// OnlineMap is an implementation of stats.OnlineMap.
|
||||
type OnlineMap struct {
|
||||
value int
|
||||
ipList map[string]time.Time
|
||||
access sync.RWMutex
|
||||
lastCleanup time.Time
|
||||
@@ -25,7 +24,10 @@ func NewOnlineMap() *OnlineMap {
|
||||
|
||||
// Count implements stats.OnlineMap.
|
||||
func (c *OnlineMap) Count() int {
|
||||
return c.value
|
||||
c.access.RLock()
|
||||
defer c.access.RUnlock()
|
||||
|
||||
return len(c.ipList)
|
||||
}
|
||||
|
||||
// List implements stats.OnlineMap.
|
||||
@@ -35,23 +37,18 @@ func (c *OnlineMap) List() []string {
|
||||
|
||||
// AddIP implements stats.OnlineMap.
|
||||
func (c *OnlineMap) AddIP(ip string) {
|
||||
list := c.ipList
|
||||
|
||||
if ip == "127.0.0.1" {
|
||||
return
|
||||
}
|
||||
|
||||
c.access.Lock()
|
||||
if _, ok := list[ip]; !ok {
|
||||
list[ip] = time.Now()
|
||||
}
|
||||
c.ipList[ip] = time.Now()
|
||||
c.access.Unlock()
|
||||
|
||||
if time.Since(c.lastCleanup) > c.cleanupPeriod {
|
||||
list = c.RemoveExpiredIPs(list)
|
||||
c.RemoveExpiredIPs()
|
||||
c.lastCleanup = time.Now()
|
||||
}
|
||||
|
||||
c.value = len(list)
|
||||
c.ipList = list
|
||||
}
|
||||
|
||||
func (c *OnlineMap) GetKeys() []string {
|
||||
@@ -65,24 +62,22 @@ func (c *OnlineMap) GetKeys() []string {
|
||||
return keys
|
||||
}
|
||||
|
||||
func (c *OnlineMap) RemoveExpiredIPs(list map[string]time.Time) map[string]time.Time {
|
||||
func (c *OnlineMap) RemoveExpiredIPs() {
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
for k, t := range list {
|
||||
for k, t := range c.ipList {
|
||||
diff := now.Sub(t)
|
||||
if diff.Seconds() > 20 {
|
||||
delete(list, k)
|
||||
delete(c.ipList, k)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func (c *OnlineMap) IpTimeMap() map[string]time.Time {
|
||||
list := c.ipList
|
||||
if time.Since(c.lastCleanup) > c.cleanupPeriod {
|
||||
list = c.RemoveExpiredIPs(list)
|
||||
c.RemoveExpiredIPs()
|
||||
c.lastCleanup = time.Now()
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ const (
|
||||
Size = 8192
|
||||
)
|
||||
|
||||
var zero = [Size * 10]byte{0}
|
||||
var ErrBufferFull = errors.New("buffer is full")
|
||||
|
||||
var pool = bytespool.GetPool(Size)
|
||||
|
||||
@@ -144,7 +144,7 @@ func (b *Buffer) Bytes() []byte {
|
||||
}
|
||||
|
||||
// Extend increases the buffer size by n bytes, and returns the extended part.
|
||||
// It panics if result size is larger than buf.Size.
|
||||
// It panics if result size is larger than size of this buffer.
|
||||
func (b *Buffer) Extend(n int32) []byte {
|
||||
end := b.end + n
|
||||
if end > int32(len(b.v)) {
|
||||
@@ -152,7 +152,7 @@ func (b *Buffer) Extend(n int32) []byte {
|
||||
}
|
||||
ext := b.v[b.end:end]
|
||||
b.end = end
|
||||
copy(ext, zero[:])
|
||||
clear(ext)
|
||||
return ext
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ func (b *Buffer) Resize(from, to int32) {
|
||||
b.start += from
|
||||
b.Check()
|
||||
if b.end > oldEnd {
|
||||
copy(b.v[oldEnd:b.end], zero[:])
|
||||
clear(b.v[oldEnd:b.end])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,6 +244,14 @@ func (b *Buffer) Cap() int32 {
|
||||
return int32(len(b.v))
|
||||
}
|
||||
|
||||
// Available returns the available capacity of the buffer content.
|
||||
func (b *Buffer) Available() int32 {
|
||||
if b == nil {
|
||||
return 0
|
||||
}
|
||||
return int32(len(b.v)) - b.end
|
||||
}
|
||||
|
||||
// IsEmpty returns true if the buffer is empty.
|
||||
func (b *Buffer) IsEmpty() bool {
|
||||
return b.Len() == 0
|
||||
@@ -258,13 +266,16 @@ func (b *Buffer) IsFull() bool {
|
||||
func (b *Buffer) Write(data []byte) (int, error) {
|
||||
nBytes := copy(b.v[b.end:], data)
|
||||
b.end += int32(nBytes)
|
||||
if nBytes < len(data) {
|
||||
return nBytes, ErrBufferFull
|
||||
}
|
||||
return nBytes, nil
|
||||
}
|
||||
|
||||
// WriteByte writes a single byte into the buffer.
|
||||
func (b *Buffer) WriteByte(v byte) error {
|
||||
if b.IsFull() {
|
||||
return errors.New("buffer full")
|
||||
return ErrBufferFull
|
||||
}
|
||||
b.v[b.end] = v
|
||||
b.end++
|
||||
|
||||
@@ -24,9 +24,59 @@ var ErrReadTimeout = errors.New("IO timeout")
|
||||
|
||||
// TimeoutReader is a reader that returns error if Read() operation takes longer than the given timeout.
|
||||
type TimeoutReader interface {
|
||||
Reader
|
||||
ReadMultiBufferTimeout(time.Duration) (MultiBuffer, error)
|
||||
}
|
||||
|
||||
type TimeoutWrapperReader struct {
|
||||
Reader
|
||||
stats.Counter
|
||||
mb MultiBuffer
|
||||
err error
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func (r *TimeoutWrapperReader) ReadMultiBuffer() (MultiBuffer, error) {
|
||||
if r.done != nil {
|
||||
<-r.done
|
||||
r.done = nil
|
||||
if r.Counter != nil {
|
||||
r.Counter.Add(int64(r.mb.Len()))
|
||||
}
|
||||
return r.mb, r.err
|
||||
}
|
||||
r.mb, r.err = r.Reader.ReadMultiBuffer()
|
||||
if r.Counter != nil {
|
||||
r.Counter.Add(int64(r.mb.Len()))
|
||||
}
|
||||
return r.mb, r.err
|
||||
}
|
||||
|
||||
func (r *TimeoutWrapperReader) ReadMultiBufferTimeout(duration time.Duration) (MultiBuffer, error) {
|
||||
if r.done == nil {
|
||||
r.done = make(chan struct{})
|
||||
go func() {
|
||||
r.mb, r.err = r.Reader.ReadMultiBuffer()
|
||||
close(r.done)
|
||||
}()
|
||||
}
|
||||
timeout := make(chan struct{})
|
||||
go func() {
|
||||
time.Sleep(duration)
|
||||
close(timeout)
|
||||
}()
|
||||
select {
|
||||
case <-r.done:
|
||||
r.done = nil
|
||||
if r.Counter != nil {
|
||||
r.Counter.Add(int64(r.mb.Len()))
|
||||
}
|
||||
return r.mb, r.err
|
||||
case <-timeout:
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Writer extends io.Writer with MultiBuffer.
|
||||
type Writer interface {
|
||||
// WriteMultiBuffer writes a MultiBuffer into underlying writer.
|
||||
|
||||
@@ -144,7 +144,7 @@ func Compact(mb MultiBuffer) MultiBuffer {
|
||||
|
||||
for i := 1; i < len(mb); i++ {
|
||||
curr := mb[i]
|
||||
if last.Len()+curr.Len() > Size {
|
||||
if curr.Len() > last.Available() {
|
||||
mb2 = append(mb2, last)
|
||||
last = curr
|
||||
} else {
|
||||
|
||||
@@ -175,6 +175,29 @@ func TestCompact(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompactWithConsumed(t *testing.T) {
|
||||
// make a consumed buffer (a.Start != 0)
|
||||
a := New()
|
||||
for range 8192 {
|
||||
common.Must2(a.WriteString("a"))
|
||||
}
|
||||
a.Read(make([]byte, 2))
|
||||
|
||||
b := New()
|
||||
for range 2 {
|
||||
common.Must2(b.WriteString("b"))
|
||||
}
|
||||
|
||||
mb := MultiBuffer{a, b}
|
||||
cmb := Compact(mb)
|
||||
mbc := &MultiBufferContainer{mb}
|
||||
mbc.Read(make([]byte, 8190))
|
||||
|
||||
if w := cmb.String(); w != "bb" {
|
||||
t.Error("unexpected Compact result ", w)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSplitBytes(b *testing.B) {
|
||||
var mb MultiBuffer
|
||||
raw := make([]byte, Size)
|
||||
|
||||
@@ -75,9 +75,10 @@ func (w *BufferToBytesWriter) ReadFrom(reader io.Reader) (int64, error) {
|
||||
// BufferedWriter is a Writer with internal buffer.
|
||||
type BufferedWriter struct {
|
||||
sync.Mutex
|
||||
writer Writer
|
||||
buffer *Buffer
|
||||
buffered bool
|
||||
writer Writer
|
||||
buffer *Buffer
|
||||
buffered bool
|
||||
flushNext bool
|
||||
}
|
||||
|
||||
// NewBufferedWriter creates a new BufferedWriter.
|
||||
@@ -161,6 +162,12 @@ func (w *BufferedWriter) WriteMultiBuffer(b MultiBuffer) error {
|
||||
}
|
||||
}
|
||||
|
||||
if w.flushNext {
|
||||
w.buffered = false
|
||||
w.flushNext = false
|
||||
return w.flushInternal()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -201,6 +208,13 @@ func (w *BufferedWriter) SetBuffered(f bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetFlushNext will wait the next WriteMultiBuffer to flush and set buffered = false
|
||||
func (w *BufferedWriter) SetFlushNext() {
|
||||
w.Lock()
|
||||
defer w.Unlock()
|
||||
w.flushNext = true
|
||||
}
|
||||
|
||||
// ReadFrom implements io.ReaderFrom.
|
||||
func (w *BufferedWriter) ReadFrom(reader io.Reader) (int64, error) {
|
||||
if err := w.SetBuffered(false); err != nil {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"go/build"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
@@ -23,7 +24,9 @@ func Must(err error) {
|
||||
}
|
||||
|
||||
// Must2 panics if the second parameter is not nil, otherwise returns the first parameter.
|
||||
func Must2(v interface{}, err error) interface{} {
|
||||
// This is useful when function returned "sth, err" and avoid many "if err != nil"
|
||||
// Internal usage only, if user input can cause err, it must be handled
|
||||
func Must2[T any](v T, err error) T {
|
||||
Must(err)
|
||||
return v
|
||||
}
|
||||
@@ -151,3 +154,14 @@ func GetModuleName(pathToProjectRoot string) (string, error) {
|
||||
}
|
||||
return moduleName, fmt.Errorf("no `go.mod` file in every parent directory of `%s`", pathToProjectRoot)
|
||||
}
|
||||
|
||||
// CloseIfExists call obj.Close() if obj is not nil.
|
||||
func CloseIfExists(obj any) error {
|
||||
if obj != nil {
|
||||
v := reflect.ValueOf(obj)
|
||||
if !v.IsNil() {
|
||||
return Close(obj)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -32,9 +32,7 @@ func NewAesCTRStream(key []byte, iv []byte) cipher.Stream {
|
||||
|
||||
// NewAesGcm creates a AEAD cipher based on AES-GCM.
|
||||
func NewAesGcm(key []byte) cipher.AEAD {
|
||||
block, err := aes.NewCipher(key)
|
||||
common.Must(err)
|
||||
aead, err := cipher.NewGCM(block)
|
||||
common.Must(err)
|
||||
block := common.Must2(aes.NewCipher(key))
|
||||
aead := common.Must2(cipher.NewGCM(block))
|
||||
return aead
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ package crypto_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"testing"
|
||||
@@ -18,11 +16,8 @@ import (
|
||||
func TestAuthenticationReaderWriter(t *testing.T) {
|
||||
key := make([]byte, 16)
|
||||
rand.Read(key)
|
||||
block, err := aes.NewCipher(key)
|
||||
common.Must(err)
|
||||
|
||||
aead, err := cipher.NewGCM(block)
|
||||
common.Must(err)
|
||||
aead := NewAesGcm(key)
|
||||
|
||||
const payloadSize = 1024 * 80
|
||||
rawPayload := make([]byte, payloadSize)
|
||||
@@ -71,7 +66,7 @@ func TestAuthenticationReaderWriter(t *testing.T) {
|
||||
t.Error(r)
|
||||
}
|
||||
|
||||
_, err = reader.ReadMultiBuffer()
|
||||
_, err := reader.ReadMultiBuffer()
|
||||
if err != io.EOF {
|
||||
t.Error("error: ", err)
|
||||
}
|
||||
@@ -80,11 +75,8 @@ func TestAuthenticationReaderWriter(t *testing.T) {
|
||||
func TestAuthenticationReaderWriterPacket(t *testing.T) {
|
||||
key := make([]byte, 16)
|
||||
common.Must2(rand.Read(key))
|
||||
block, err := aes.NewCipher(key)
|
||||
common.Must(err)
|
||||
|
||||
aead, err := cipher.NewGCM(block)
|
||||
common.Must(err)
|
||||
aead := NewAesGcm(key)
|
||||
|
||||
cache := buf.New()
|
||||
iv := make([]byte, 12)
|
||||
|
||||
@@ -10,6 +10,9 @@ func RandBetween(from int64, to int64) int64 {
|
||||
if from == to {
|
||||
return from
|
||||
}
|
||||
if from > to {
|
||||
from, to = to, from
|
||||
}
|
||||
bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from))
|
||||
return from + bigInt.Int64()
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package mux
|
||||
|
||||
import (
|
||||
"context"
|
||||
goerrors "errors"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -154,8 +155,11 @@ func (f *DialingWorkerFactory) Create() (*ClientWorker, error) {
|
||||
ctx := session.ContextWithOutbounds(context.Background(), outbounds)
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
if err := p.Process(ctx, &transport.Link{Reader: uplinkReader, Writer: downlinkWriter}, d); err != nil {
|
||||
errors.LogInfoInner(ctx, err, "failed to handler mux client connection")
|
||||
if errP := p.Process(ctx, &transport.Link{Reader: uplinkReader, Writer: downlinkWriter}, d); errP != nil {
|
||||
errC := errors.Cause(errP)
|
||||
if !(goerrors.Is(errC, io.EOF) || goerrors.Is(errC, io.ErrClosedPipe) || goerrors.Is(errC, context.Canceled)) {
|
||||
errors.LogInfoInner(ctx, errP, "failed to handler mux client connection")
|
||||
}
|
||||
}
|
||||
common.Must(c.Close())
|
||||
cancel()
|
||||
@@ -211,23 +215,28 @@ func (m *ClientWorker) Closed() bool {
|
||||
return m.done.Done()
|
||||
}
|
||||
|
||||
func (m *ClientWorker) GetTimer() *time.Ticker {
|
||||
return m.timer
|
||||
func (m *ClientWorker) WaitClosed() <-chan struct{} {
|
||||
return m.done.Wait()
|
||||
}
|
||||
|
||||
func (m *ClientWorker) Close() error {
|
||||
return m.done.Close()
|
||||
}
|
||||
|
||||
func (m *ClientWorker) monitor() {
|
||||
defer m.timer.Stop()
|
||||
|
||||
for {
|
||||
checkSize := m.sessionManager.Size()
|
||||
checkCount := m.sessionManager.Count()
|
||||
select {
|
||||
case <-m.done.Wait():
|
||||
m.sessionManager.Close()
|
||||
common.Close(m.link.Writer)
|
||||
common.Interrupt(m.link.Writer)
|
||||
common.Interrupt(m.link.Reader)
|
||||
return
|
||||
case <-m.timer.C:
|
||||
size := m.sessionManager.Size()
|
||||
if size == 0 && m.sessionManager.CloseIfNoSession() {
|
||||
if m.sessionManager.CloseIfNoSessionAndIdle(checkSize, checkCount) {
|
||||
common.Must(m.done.Close())
|
||||
}
|
||||
}
|
||||
@@ -308,6 +317,12 @@ func (m *ClientWorker) Dispatch(ctx context.Context, link *transport.Link) bool
|
||||
s.input = link.Reader
|
||||
s.output = link.Writer
|
||||
go fetchInput(ctx, s, m.link.Writer)
|
||||
if _, ok := link.Reader.(*pipe.Reader); !ok {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-s.done.Wait():
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,9 @@ package mux
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/app/dispatcher"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
@@ -11,6 +13,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal/done"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
@@ -61,8 +64,16 @@ func (s *Server) DispatchLink(ctx context.Context, dest net.Destination, link *t
|
||||
if dest.Address != muxCoolAddress {
|
||||
return s.dispatcher.DispatchLink(ctx, dest, link)
|
||||
}
|
||||
_, err := NewServerWorker(ctx, s.dispatcher, link)
|
||||
return err
|
||||
link = s.dispatcher.(*dispatcher.DefaultDispatcher).WrapLink(ctx, link)
|
||||
worker, err := NewServerWorker(ctx, s.dispatcher, link)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-worker.done.Wait():
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start implements common.Runnable.
|
||||
@@ -79,6 +90,8 @@ type ServerWorker struct {
|
||||
dispatcher routing.Dispatcher
|
||||
link *transport.Link
|
||||
sessionManager *SessionManager
|
||||
done *done.Instance
|
||||
timer *time.Ticker
|
||||
}
|
||||
|
||||
func NewServerWorker(ctx context.Context, d routing.Dispatcher, link *transport.Link) (*ServerWorker, error) {
|
||||
@@ -86,8 +99,14 @@ func NewServerWorker(ctx context.Context, d routing.Dispatcher, link *transport.
|
||||
dispatcher: d,
|
||||
link: link,
|
||||
sessionManager: NewSessionManager(),
|
||||
done: done.New(),
|
||||
timer: time.NewTicker(60 * time.Second),
|
||||
}
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
inbound.CanSpliceCopy = 3
|
||||
}
|
||||
go worker.run(ctx)
|
||||
go worker.monitor()
|
||||
return worker, nil
|
||||
}
|
||||
|
||||
@@ -102,12 +121,40 @@ func handle(ctx context.Context, s *Session, output buf.Writer) {
|
||||
s.Close(false)
|
||||
}
|
||||
|
||||
func (w *ServerWorker) monitor() {
|
||||
defer w.timer.Stop()
|
||||
|
||||
for {
|
||||
checkSize := w.sessionManager.Size()
|
||||
checkCount := w.sessionManager.Count()
|
||||
select {
|
||||
case <-w.done.Wait():
|
||||
w.sessionManager.Close()
|
||||
common.Interrupt(w.link.Writer)
|
||||
common.Interrupt(w.link.Reader)
|
||||
return
|
||||
case <-w.timer.C:
|
||||
if w.sessionManager.CloseIfNoSessionAndIdle(checkSize, checkCount) {
|
||||
common.Must(w.done.Close())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *ServerWorker) ActiveConnections() uint32 {
|
||||
return uint32(w.sessionManager.Size())
|
||||
}
|
||||
|
||||
func (w *ServerWorker) Closed() bool {
|
||||
return w.sessionManager.Closed()
|
||||
return w.done.Done()
|
||||
}
|
||||
|
||||
func (w *ServerWorker) WaitClosed() <-chan struct{} {
|
||||
return w.done.Wait()
|
||||
}
|
||||
|
||||
func (w *ServerWorker) Close() error {
|
||||
return w.done.Close()
|
||||
}
|
||||
|
||||
func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||
@@ -118,9 +165,7 @@ func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.Bu
|
||||
}
|
||||
|
||||
func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||
// deep-clone outbounds because it is going to be mutated concurrently
|
||||
// (Target and OriginalTarget)
|
||||
ctx = session.ContextCloneOutboundsAndContent(ctx)
|
||||
ctx = session.SubContextFromMuxInbound(ctx)
|
||||
errors.LogInfo(ctx, "received request for ", meta.Target)
|
||||
{
|
||||
msg := &log.AccessMessage{
|
||||
@@ -310,11 +355,11 @@ func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedRead
|
||||
}
|
||||
|
||||
func (w *ServerWorker) run(ctx context.Context) {
|
||||
reader := &buf.BufferedReader{Reader: w.link.Reader}
|
||||
defer func() {
|
||||
common.Must(w.done.Close())
|
||||
}()
|
||||
|
||||
defer w.sessionManager.Close()
|
||||
defer common.Close(w.link.Writer)
|
||||
defer common.Interrupt(w.link.Reader)
|
||||
reader := &buf.BufferedReader{Reader: w.link.Reader}
|
||||
|
||||
for {
|
||||
select {
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/signal/done"
|
||||
"github.com/xtls/xray-core/transport/pipe"
|
||||
)
|
||||
|
||||
@@ -53,7 +54,7 @@ func (m *SessionManager) Count() int {
|
||||
func (m *SessionManager) Allocate(Strategy *ClientStrategy) *Session {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
|
||||
MaxConcurrency := int(Strategy.MaxConcurrency)
|
||||
MaxConnection := uint16(Strategy.MaxConnection)
|
||||
|
||||
@@ -65,6 +66,7 @@ func (m *SessionManager) Allocate(Strategy *ClientStrategy) *Session {
|
||||
s := &Session{
|
||||
ID: m.count,
|
||||
parent: m,
|
||||
done: done.New(),
|
||||
}
|
||||
m.sessions[s.ID] = s
|
||||
return s
|
||||
@@ -115,7 +117,7 @@ func (m *SessionManager) Get(id uint16) (*Session, bool) {
|
||||
return s, found
|
||||
}
|
||||
|
||||
func (m *SessionManager) CloseIfNoSession() bool {
|
||||
func (m *SessionManager) CloseIfNoSessionAndIdle(checkSize int, checkCount int) bool {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
@@ -123,11 +125,13 @@ func (m *SessionManager) CloseIfNoSession() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(m.sessions) != 0 {
|
||||
if len(m.sessions) != 0 || checkSize != 0 || checkCount != int(m.count) {
|
||||
return false
|
||||
}
|
||||
|
||||
m.closed = true
|
||||
|
||||
m.sessions = nil
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -157,6 +161,7 @@ type Session struct {
|
||||
ID uint16
|
||||
transferType protocol.TransferType
|
||||
closed bool
|
||||
done *done.Instance
|
||||
XUDP *XUDP
|
||||
}
|
||||
|
||||
@@ -171,6 +176,9 @@ func (s *Session) Close(locked bool) error {
|
||||
return nil
|
||||
}
|
||||
s.closed = true
|
||||
if s.done != nil {
|
||||
s.done.Close()
|
||||
}
|
||||
if s.XUDP == nil {
|
||||
common.Interrupt(s.input)
|
||||
common.Close(s.output)
|
||||
|
||||
@@ -41,11 +41,11 @@ func TestSessionManagerClose(t *testing.T) {
|
||||
m := NewSessionManager()
|
||||
s := m.Allocate(&ClientStrategy{})
|
||||
|
||||
if m.CloseIfNoSession() {
|
||||
if m.CloseIfNoSessionAndIdle(m.Size(), m.Count()) {
|
||||
t.Error("able to close")
|
||||
}
|
||||
m.Remove(false, s.ID)
|
||||
if !m.CloseIfNoSession() {
|
||||
if !m.CloseIfNoSessionAndIdle(m.Size(), m.Count()) {
|
||||
t.Error("not able to close")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,12 @@ const (
|
||||
RequestCommandTCP = RequestCommand(0x01)
|
||||
RequestCommandUDP = RequestCommand(0x02)
|
||||
RequestCommandMux = RequestCommand(0x03)
|
||||
RequestCommandRvs = RequestCommand(0x04)
|
||||
)
|
||||
|
||||
func (c RequestCommand) TransferType() TransferType {
|
||||
switch c {
|
||||
case RequestCommandTCP, RequestCommandMux:
|
||||
case RequestCommandTCP, RequestCommandMux, RequestCommandRvs:
|
||||
return TransferTypeStream
|
||||
case RequestCommandUDP:
|
||||
return TransferTypePacket
|
||||
@@ -79,20 +80,18 @@ type CommandSwitchAccount struct {
|
||||
}
|
||||
|
||||
var (
|
||||
hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ
|
||||
// Keep in sync with crypto/tls/cipher_suites.go.
|
||||
hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ && cpu.X86.HasSSE41 && cpu.X86.HasSSSE3
|
||||
hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL
|
||||
// Keep in sync with crypto/aes/cipher_s390x.go.
|
||||
hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR &&
|
||||
(cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)
|
||||
hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCTR && cpu.S390X.HasGHASH
|
||||
hasGCMAsmPPC64 = runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le"
|
||||
|
||||
hasAESGCMHardwareSupport = runtime.GOARCH == "amd64" && hasGCMAsmAMD64 ||
|
||||
runtime.GOARCH == "arm64" && hasGCMAsmARM64 ||
|
||||
runtime.GOARCH == "s390x" && hasGCMAsmS390X
|
||||
HasAESGCMHardwareSupport = hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X || hasGCMAsmPPC64
|
||||
)
|
||||
|
||||
func (sc *SecurityConfig) GetSecurityType() SecurityType {
|
||||
if sc == nil || sc.Type == SecurityType_AUTO {
|
||||
if hasAESGCMHardwareSupport {
|
||||
if HasAESGCMHardwareSupport {
|
||||
return SecurityType_AES128_GCM
|
||||
}
|
||||
return SecurityType_CHACHA20_POLY1305
|
||||
|
||||
@@ -184,8 +184,7 @@ func getConfig() string {
|
||||
"inboundTag": [
|
||||
"api-in"
|
||||
],
|
||||
"outboundTag": "api",
|
||||
"type": "field"
|
||||
"outboundTag": "api"
|
||||
}
|
||||
],
|
||||
"domainStrategy": "AsIs"
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/xtls/xray-core/common/ctx"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
)
|
||||
|
||||
@@ -16,15 +17,15 @@ const (
|
||||
inboundSessionKey ctx.SessionKey = 1
|
||||
outboundSessionKey ctx.SessionKey = 2
|
||||
contentSessionKey ctx.SessionKey = 3
|
||||
muxPreferredSessionKey ctx.SessionKey = 4
|
||||
sockoptSessionKey ctx.SessionKey = 5
|
||||
trackedConnectionErrorKey ctx.SessionKey = 6
|
||||
dispatcherKey ctx.SessionKey = 7
|
||||
timeoutOnlyKey ctx.SessionKey = 8
|
||||
allowedNetworkKey ctx.SessionKey = 9
|
||||
handlerSessionKey ctx.SessionKey = 10
|
||||
mitmAlpn11Key ctx.SessionKey = 11
|
||||
mitmServerNameKey ctx.SessionKey = 12
|
||||
muxPreferredSessionKey ctx.SessionKey = 4 // unused
|
||||
sockoptSessionKey ctx.SessionKey = 5 // used by dokodemo to only receive sockopt.Mark
|
||||
trackedConnectionErrorKey ctx.SessionKey = 6 // used by observer to get outbound error
|
||||
dispatcherKey ctx.SessionKey = 7 // used by ss2022 inbounds to get dispatcher
|
||||
timeoutOnlyKey ctx.SessionKey = 8 // mux context's child contexts to only cancel when its own traffic times out
|
||||
allowedNetworkKey ctx.SessionKey = 9 // muxcool server control incoming request tcp/udp
|
||||
handlerSessionKey ctx.SessionKey = 10 // outbound gets full handler
|
||||
mitmAlpn11Key ctx.SessionKey = 11 // used by TLS dialer
|
||||
mitmServerNameKey ctx.SessionKey = 12 // used by TLS dialer
|
||||
)
|
||||
|
||||
func ContextWithInbound(ctx context.Context, inbound *Inbound) context.Context {
|
||||
@@ -42,18 +43,8 @@ func ContextWithOutbounds(ctx context.Context, outbounds []*Outbound) context.Co
|
||||
return context.WithValue(ctx, outboundSessionKey, outbounds)
|
||||
}
|
||||
|
||||
func ContextCloneOutboundsAndContent(ctx context.Context) context.Context {
|
||||
outbounds := OutboundsFromContext(ctx)
|
||||
newOutbounds := make([]*Outbound, len(outbounds))
|
||||
for i, ob := range outbounds {
|
||||
if ob == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// copy outbound by value
|
||||
v := *ob
|
||||
newOutbounds[i] = &v
|
||||
}
|
||||
func SubContextFromMuxInbound(ctx context.Context) context.Context {
|
||||
newOutbounds := []*Outbound{{}}
|
||||
|
||||
content := ContentFromContext(ctx)
|
||||
newContent := Content{}
|
||||
@@ -173,6 +164,17 @@ func AllowedNetworkFromContext(ctx context.Context) net.Network {
|
||||
return net.Network_Unknown
|
||||
}
|
||||
|
||||
func ContextWithHandler(ctx context.Context, handler outbound.Handler) context.Context {
|
||||
return context.WithValue(ctx, handlerSessionKey, handler)
|
||||
}
|
||||
|
||||
func HandlerFromContext(ctx context.Context) outbound.Handler {
|
||||
if val, ok := ctx.Value(handlerSessionKey).(outbound.Handler); ok {
|
||||
return val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ContextWithMitmAlpn11(ctx context.Context, alpn11 bool) context.Context {
|
||||
return context.WithValue(ctx, mitmAlpn11Key, alpn11)
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ func ExportIDToError(ctx context.Context) errors.ExportOption {
|
||||
type Inbound struct {
|
||||
// Source address of the inbound connection.
|
||||
Source net.Destination
|
||||
// Local address of the inbound connection.
|
||||
Local net.Destination
|
||||
// Gateway address.
|
||||
Gateway net.Destination
|
||||
// Tag of the inbound proxy that handles the connection.
|
||||
@@ -44,9 +46,11 @@ type Inbound struct {
|
||||
Name string
|
||||
// User is the user that authenticates for the inbound. May be nil if the protocol allows anonymous traffic.
|
||||
User *protocol.MemoryUser
|
||||
// Conn is actually internet.Connection. May be nil.
|
||||
// VlessRoute is the user-sent VLESS UUID's 7th<<8 | 8th bytes.
|
||||
VlessRoute net.Port
|
||||
// Used by splice copy. Conn is actually internet.Connection. May be nil.
|
||||
Conn net.Conn
|
||||
// Timer of the inbound buf copier. May be nil.
|
||||
// Used by splice copy. Timer of the inbound buf copier. May be nil.
|
||||
Timer *signal.ActivityTimer
|
||||
// CanSpliceCopy is a property for this connection
|
||||
// 1 = can, 2 = after processing protocol info should be able to, 3 = cannot
|
||||
@@ -65,31 +69,33 @@ type Outbound struct {
|
||||
Tag string
|
||||
// Name of the outbound proxy that handles the connection.
|
||||
Name string
|
||||
// Conn is actually internet.Connection. May be nil. It is currently nil for outbound with proxySettings
|
||||
// Unused. Conn is actually internet.Connection. May be nil. It is currently nil for outbound with proxySettings
|
||||
Conn net.Conn
|
||||
// CanSpliceCopy is a property for this connection
|
||||
// 1 = can, 2 = after processing protocol info should be able to, 3 = cannot
|
||||
CanSpliceCopy int
|
||||
}
|
||||
|
||||
// SniffingRequest controls the behavior of content sniffing.
|
||||
// SniffingRequest controls the behavior of content sniffing. They are from inbound config. Read-only
|
||||
type SniffingRequest struct {
|
||||
ExcludeForDomain []string // read-only once set
|
||||
OverrideDestinationForProtocol []string // read-only once set
|
||||
ExcludeForDomain []string
|
||||
OverrideDestinationForProtocol []string
|
||||
Enabled bool
|
||||
MetadataOnly bool
|
||||
RouteOnly bool
|
||||
}
|
||||
|
||||
// Content is the metadata of the connection content.
|
||||
// Content is the metadata of the connection content. Mainly used for routing.
|
||||
type Content struct {
|
||||
// Protocol of current content.
|
||||
Protocol string
|
||||
|
||||
SniffingRequest SniffingRequest
|
||||
|
||||
// HTTP traffic sniffed headers
|
||||
Attributes map[string]string
|
||||
|
||||
// SkipDNSResolve is set from DNS module. the DOH remote server maybe a domain name, this prevents cycle resolving dead loop
|
||||
SkipDNSResolve bool
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package signal
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
@@ -14,10 +15,12 @@ type ActivityUpdater interface {
|
||||
}
|
||||
|
||||
type ActivityTimer struct {
|
||||
sync.RWMutex
|
||||
mu sync.RWMutex
|
||||
updated chan struct{}
|
||||
checkTask *task.Periodic
|
||||
onTimeout func()
|
||||
consumed atomic.Bool
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func (t *ActivityTimer) Update() {
|
||||
@@ -37,39 +40,39 @@ func (t *ActivityTimer) check() error {
|
||||
}
|
||||
|
||||
func (t *ActivityTimer) finish() {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
t.once.Do(func() {
|
||||
t.consumed.Store(true)
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
if t.onTimeout != nil {
|
||||
common.CloseIfExists(t.checkTask)
|
||||
t.onTimeout()
|
||||
t.onTimeout = nil
|
||||
}
|
||||
if t.checkTask != nil {
|
||||
t.checkTask.Close()
|
||||
t.checkTask = nil
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
|
||||
if t.consumed.Load() {
|
||||
return
|
||||
}
|
||||
if timeout == 0 {
|
||||
t.finish()
|
||||
return
|
||||
}
|
||||
|
||||
checkTask := &task.Periodic{
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
// double check, just in case
|
||||
if t.consumed.Load() {
|
||||
return
|
||||
}
|
||||
newCheckTask := &task.Periodic{
|
||||
Interval: timeout,
|
||||
Execute: t.check,
|
||||
}
|
||||
|
||||
t.Lock()
|
||||
|
||||
if t.checkTask != nil {
|
||||
t.checkTask.Close()
|
||||
}
|
||||
t.checkTask = checkTask
|
||||
common.CloseIfExists(t.checkTask)
|
||||
t.checkTask = newCheckTask
|
||||
t.Update()
|
||||
common.Must(checkTask.Start())
|
||||
t.Unlock()
|
||||
common.Must(newCheckTask.Start())
|
||||
}
|
||||
|
||||
func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
|
||||
|
||||
@@ -18,8 +18,8 @@ import (
|
||||
|
||||
var (
|
||||
Version_x byte = 25
|
||||
Version_y byte = 8
|
||||
Version_z byte = 3
|
||||
Version_y byte = 9
|
||||
Version_z byte = 11
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -23,6 +23,12 @@ type Context interface {
|
||||
// GetTargetPort returns the target port of the connection.
|
||||
GetTargetPort() net.Port
|
||||
|
||||
// GetLocalIPs returns the local IPs bound to the connection.
|
||||
GetLocalIPs() []net.IP
|
||||
|
||||
// GetLocalPort returns the local port of the connection.
|
||||
GetLocalPort() net.Port
|
||||
|
||||
// GetTargetDomain returns the target domain of the connection, if exists.
|
||||
GetTargetDomain() string
|
||||
|
||||
@@ -35,9 +41,15 @@ type Context interface {
|
||||
// GetUser returns the user email from the connection content, if exists.
|
||||
GetUser() string
|
||||
|
||||
// GetVlessRoute returns the user-sent VLESS UUID's 7th<<8 | 8th bytes, if exists.
|
||||
GetVlessRoute() net.Port
|
||||
|
||||
// GetAttributes returns extra attributes from the conneciont content.
|
||||
GetAttributes() map[string]string
|
||||
|
||||
// GetSkipDNSResolve returns a flag switch for weather skip dns resolve during route pick.
|
||||
GetSkipDNSResolve() bool
|
||||
|
||||
// GetError returns errors during route pick, e.g., built-in-dns fail to resolve domain to IP
|
||||
GetError() error
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
@@ -14,6 +12,7 @@ type ResolvableContext struct {
|
||||
routing.Context
|
||||
dnsClient dns.Client
|
||||
resolvedIPs []net.IP
|
||||
lookupError error
|
||||
}
|
||||
|
||||
// GetTargetIPs overrides original routing.Context's implementation.
|
||||
@@ -22,6 +21,10 @@ func (ctx *ResolvableContext) GetTargetIPs() []net.IP {
|
||||
return ctx.resolvedIPs
|
||||
}
|
||||
|
||||
if ips := ctx.Context.GetTargetIPs(); len(ips) != 0 {
|
||||
return ips
|
||||
}
|
||||
|
||||
if domain := ctx.GetTargetDomain(); len(domain) != 0 {
|
||||
ips, _, err := ctx.dnsClient.LookupIP(domain, dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
@@ -32,16 +35,17 @@ func (ctx *ResolvableContext) GetTargetIPs() []net.IP {
|
||||
ctx.resolvedIPs = ips
|
||||
return ips
|
||||
}
|
||||
errors.LogInfoInner(context.Background(), err, "resolve ip for ", domain)
|
||||
}
|
||||
|
||||
if ips := ctx.Context.GetTargetIPs(); len(ips) != 0 {
|
||||
return ips
|
||||
ctx.lookupError = errors.New("resolve ip for ", domain).Base(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetError override original routing.Context's implementation.
|
||||
func (ctx *ResolvableContext) GetError() error {
|
||||
return ctx.lookupError
|
||||
}
|
||||
|
||||
// ContextWithDNSClient creates a new routing context with domain resolving capability.
|
||||
// Resolved domain IPs can be retrieved by GetTargetIPs().
|
||||
func ContextWithDNSClient(ctx routing.Context, client dns.Client) routing.Context {
|
||||
|
||||
@@ -28,12 +28,13 @@ func (ctx *Context) GetSourceIPs() []net.IP {
|
||||
if ctx.Inbound == nil || !ctx.Inbound.Source.IsValid() {
|
||||
return nil
|
||||
}
|
||||
dest := ctx.Inbound.Source
|
||||
if dest.Address.Family().IsDomain() {
|
||||
return nil
|
||||
|
||||
if ctx.Inbound.Source.Address.Family().IsIP() {
|
||||
return []net.IP{ctx.Inbound.Source.Address.IP()}
|
||||
}
|
||||
|
||||
return []net.IP{dest.Address.IP()}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// GetSourcePort implements routing.Context.
|
||||
@@ -65,6 +66,27 @@ func (ctx *Context) GetTargetPort() net.Port {
|
||||
return ctx.Outbound.Target.Port
|
||||
}
|
||||
|
||||
// GetLocalIPs implements routing.Context.
|
||||
func (ctx *Context) GetLocalIPs() []net.IP {
|
||||
if ctx.Inbound == nil || !ctx.Inbound.Local.IsValid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if ctx.Inbound.Local.Address.Family().IsIP() {
|
||||
return []net.IP{ctx.Inbound.Local.Address.IP()}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLocalPort implements routing.Context.
|
||||
func (ctx *Context) GetLocalPort() net.Port {
|
||||
if ctx.Inbound == nil || !ctx.Inbound.Local.IsValid() {
|
||||
return 0
|
||||
}
|
||||
return ctx.Inbound.Local.Port
|
||||
}
|
||||
|
||||
// GetTargetDomain implements routing.Context.
|
||||
func (ctx *Context) GetTargetDomain() string {
|
||||
if ctx.Outbound == nil || !ctx.Outbound.Target.IsValid() {
|
||||
@@ -106,6 +128,14 @@ func (ctx *Context) GetUser() string {
|
||||
return ctx.Inbound.User.Email
|
||||
}
|
||||
|
||||
// GetVlessRoute implements routing.Context.
|
||||
func (ctx *Context) GetVlessRoute() net.Port {
|
||||
if ctx.Inbound == nil {
|
||||
return 0
|
||||
}
|
||||
return ctx.Inbound.VlessRoute
|
||||
}
|
||||
|
||||
// GetAttributes implements routing.Context.
|
||||
func (ctx *Context) GetAttributes() map[string]string {
|
||||
if ctx.Content == nil {
|
||||
@@ -122,6 +152,11 @@ func (ctx *Context) GetSkipDNSResolve() bool {
|
||||
return ctx.Content.SkipDNSResolve
|
||||
}
|
||||
|
||||
// GetError implements routing.Context.
|
||||
func (ctx *Context) GetError() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AsRoutingContext creates a context from context.context with session info.
|
||||
func AsRoutingContext(ctx context.Context) routing.Context {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
|
||||
28
go.mod
28
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/xtls/xray-core
|
||||
|
||||
go 1.24
|
||||
go 1.25
|
||||
|
||||
require (
|
||||
github.com/cloudflare/circl v1.6.1
|
||||
@@ -8,7 +8,7 @@ require (
|
||||
github.com/golang/mock v1.7.0-rc.1
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/miekg/dns v1.1.67
|
||||
github.com/miekg/dns v1.1.68
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/pires/go-proxyproto v0.8.1
|
||||
github.com/quic-go/quic-go v0.54.0
|
||||
@@ -16,18 +16,18 @@ require (
|
||||
github.com/sagernet/sing v0.5.1
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7
|
||||
github.com/xtls/reality v0.0.0-20250904214705-431b6ff8c67c
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||
golang.org/x/crypto v0.40.0
|
||||
golang.org/x/net v0.42.0
|
||||
golang.org/x/sync v0.16.0
|
||||
golang.org/x/sys v0.34.0
|
||||
golang.org/x/crypto v0.42.0
|
||||
golang.org/x/net v0.44.0
|
||||
golang.org/x/sync v0.17.0
|
||||
golang.org/x/sys v0.36.0
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||
google.golang.org/grpc v1.74.2
|
||||
google.golang.org/protobuf v1.36.6
|
||||
google.golang.org/grpc v1.75.1
|
||||
google.golang.org/protobuf v1.36.9
|
||||
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5
|
||||
h12.io/socks v1.0.3
|
||||
lukechampine.com/blake3 v1.4.1
|
||||
@@ -47,12 +47,12 @@ require (
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
golang.org/x/mod v0.27.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
golang.org/x/tools v0.34.0 // indirect
|
||||
golang.org/x/tools v0.36.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
74
go.sum
74
go.sum
@@ -38,8 +38,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0=
|
||||
github.com/miekg/dns v1.1.67/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
|
||||
github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
|
||||
github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
|
||||
@@ -67,49 +67,49 @@ github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 h1:emzAzMZ1
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
|
||||
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
|
||||
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
|
||||
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7 h1:Ript0vN+nSO33+Vj4n0mgNY5M+oOxFQJdrJ1VnwTBO0=
|
||||
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7/go.mod h1:XxvnCCgBee4WWE0bc4E+a7wbk8gkJ/rS0vNVNtC5qp0=
|
||||
github.com/xtls/reality v0.0.0-20250904214705-431b6ff8c67c h1:LHLhQY3mKXSpTcQAkjFR4/6ar3rXjQryNeM7khK3AHU=
|
||||
github.com/xtls/reality v0.0.0-20250904214705-431b6ff8c67c/go.mod h1:XxvnCCgBee4WWE0bc4E+a7wbk8gkJ/rS0vNVNtC5qp0=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
|
||||
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -117,21 +117,21 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -139,12 +139,14 @@ golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeu
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -28,9 +28,7 @@ func (c *DNSOutboundConfig) Build() (proto.Message, error) {
|
||||
config.Server.Address = c.Address.Build()
|
||||
}
|
||||
switch c.NonIPQuery {
|
||||
case "":
|
||||
c.NonIPQuery = "drop"
|
||||
case "drop", "skip", "reject":
|
||||
case "", "reject", "drop", "skip":
|
||||
default:
|
||||
return nil, errors.New(`unknown "nonIPQuery": `, c.NonIPQuery)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ func TestDnsProxyConfig(t *testing.T) {
|
||||
Address: net.NewIPOrDomain(net.IPAddress([]byte{8, 8, 8, 8})),
|
||||
Port: 53,
|
||||
},
|
||||
Non_IPQuery: "drop",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -11,9 +11,11 @@ import (
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/proxy/freedom"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
)
|
||||
|
||||
type FreedomConfig struct {
|
||||
TargetStrategy string `json:"targetStrategy"`
|
||||
DomainStrategy string `json:"domainStrategy"`
|
||||
Redirect string `json:"redirect"`
|
||||
UserLevel uint32 `json:"userLevel"`
|
||||
@@ -27,42 +29,48 @@ type Fragment struct {
|
||||
Packets string `json:"packets"`
|
||||
Length *Int32Range `json:"length"`
|
||||
Interval *Int32Range `json:"interval"`
|
||||
MaxSplit *Int32Range `json:"maxSplit"`
|
||||
}
|
||||
|
||||
type Noise struct {
|
||||
Type string `json:"type"`
|
||||
Packet string `json:"packet"`
|
||||
Delay *Int32Range `json:"delay"`
|
||||
Type string `json:"type"`
|
||||
Packet string `json:"packet"`
|
||||
Delay *Int32Range `json:"delay"`
|
||||
ApplyTo string `json:"applyTo"`
|
||||
}
|
||||
|
||||
// Build implements Buildable
|
||||
func (c *FreedomConfig) Build() (proto.Message, error) {
|
||||
config := new(freedom.Config)
|
||||
switch strings.ToLower(c.DomainStrategy) {
|
||||
targetStrategy := c.TargetStrategy
|
||||
if targetStrategy == "" {
|
||||
targetStrategy = c.DomainStrategy
|
||||
}
|
||||
switch strings.ToLower(targetStrategy) {
|
||||
case "asis", "":
|
||||
config.DomainStrategy = freedom.Config_AS_IS
|
||||
config.DomainStrategy = internet.DomainStrategy_AS_IS
|
||||
case "useip":
|
||||
config.DomainStrategy = freedom.Config_USE_IP
|
||||
config.DomainStrategy = internet.DomainStrategy_USE_IP
|
||||
case "useipv4":
|
||||
config.DomainStrategy = freedom.Config_USE_IP4
|
||||
config.DomainStrategy = internet.DomainStrategy_USE_IP4
|
||||
case "useipv6":
|
||||
config.DomainStrategy = freedom.Config_USE_IP6
|
||||
config.DomainStrategy = internet.DomainStrategy_USE_IP6
|
||||
case "useipv4v6":
|
||||
config.DomainStrategy = freedom.Config_USE_IP46
|
||||
config.DomainStrategy = internet.DomainStrategy_USE_IP46
|
||||
case "useipv6v4":
|
||||
config.DomainStrategy = freedom.Config_USE_IP64
|
||||
config.DomainStrategy = internet.DomainStrategy_USE_IP64
|
||||
case "forceip":
|
||||
config.DomainStrategy = freedom.Config_FORCE_IP
|
||||
config.DomainStrategy = internet.DomainStrategy_FORCE_IP
|
||||
case "forceipv4":
|
||||
config.DomainStrategy = freedom.Config_FORCE_IP4
|
||||
config.DomainStrategy = internet.DomainStrategy_FORCE_IP4
|
||||
case "forceipv6":
|
||||
config.DomainStrategy = freedom.Config_FORCE_IP6
|
||||
config.DomainStrategy = internet.DomainStrategy_FORCE_IP6
|
||||
case "forceipv4v6":
|
||||
config.DomainStrategy = freedom.Config_FORCE_IP46
|
||||
config.DomainStrategy = internet.DomainStrategy_FORCE_IP46
|
||||
case "forceipv6v4":
|
||||
config.DomainStrategy = freedom.Config_FORCE_IP64
|
||||
config.DomainStrategy = internet.DomainStrategy_FORCE_IP64
|
||||
default:
|
||||
return nil, errors.New("unsupported domain strategy: ", c.DomainStrategy)
|
||||
return nil, errors.New("unsupported domain strategy: ", targetStrategy)
|
||||
}
|
||||
|
||||
if c.Fragment != nil {
|
||||
@@ -108,6 +116,13 @@ func (c *FreedomConfig) Build() (proto.Message, error) {
|
||||
config.Fragment.IntervalMin = uint64(c.Fragment.Interval.From)
|
||||
config.Fragment.IntervalMax = uint64(c.Fragment.Interval.To)
|
||||
}
|
||||
|
||||
{
|
||||
if c.Fragment.MaxSplit != nil {
|
||||
config.Fragment.MaxSplitMin = uint64(c.Fragment.MaxSplit.From)
|
||||
config.Fragment.MaxSplitMax = uint64(c.Fragment.MaxSplit.To)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if c.Noise != nil {
|
||||
@@ -193,5 +208,15 @@ func ParseNoise(noise *Noise) (*freedom.Noise, error) {
|
||||
NConfig.DelayMin = uint64(noise.Delay.From)
|
||||
NConfig.DelayMax = uint64(noise.Delay.To)
|
||||
}
|
||||
switch strings.ToLower(noise.ApplyTo) {
|
||||
case "", "ip", "all":
|
||||
NConfig.ApplyTo = "ip"
|
||||
case "ipv4":
|
||||
NConfig.ApplyTo = "ipv4"
|
||||
case "ipv6":
|
||||
NConfig.ApplyTo = "ipv6"
|
||||
default:
|
||||
return nil, errors.New("Invalid applyTo, only ip/ipv4/ipv6 are supported")
|
||||
}
|
||||
return NConfig, nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
. "github.com/xtls/xray-core/infra/conf"
|
||||
"github.com/xtls/xray-core/proxy/freedom"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
)
|
||||
|
||||
func TestFreedomConfig(t *testing.T) {
|
||||
@@ -23,7 +24,7 @@ func TestFreedomConfig(t *testing.T) {
|
||||
}`,
|
||||
Parser: loadJSON(creator),
|
||||
Output: &freedom.Config{
|
||||
DomainStrategy: freedom.Config_AS_IS,
|
||||
DomainStrategy: internet.DomainStrategy_AS_IS,
|
||||
DestinationOverride: &freedom.DestinationOverride{
|
||||
Server: &protocol.ServerEndpoint{
|
||||
Address: &net.IPOrDomain{
|
||||
|
||||
@@ -51,12 +51,27 @@ type HTTPRemoteConfig struct {
|
||||
}
|
||||
|
||||
type HTTPClientConfig struct {
|
||||
Servers []*HTTPRemoteConfig `json:"servers"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
Address *Address `json:"address"`
|
||||
Port uint16 `json:"port"`
|
||||
Level uint32 `json:"level"`
|
||||
Email string `json:"email"`
|
||||
Username string `json:"user"`
|
||||
Password string `json:"pass"`
|
||||
Servers []*HTTPRemoteConfig `json:"servers"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
}
|
||||
|
||||
func (v *HTTPClientConfig) Build() (proto.Message, error) {
|
||||
config := new(http.ClientConfig)
|
||||
if v.Address != nil {
|
||||
v.Servers = []*HTTPRemoteConfig{
|
||||
{
|
||||
Address: v.Address,
|
||||
Port: v.Port,
|
||||
Users: []json.RawMessage{{}},
|
||||
},
|
||||
}
|
||||
}
|
||||
config.Server = make([]*protocol.ServerEndpoint, len(v.Servers))
|
||||
for idx, serverConfig := range v.Servers {
|
||||
server := &protocol.ServerEndpoint{
|
||||
@@ -65,12 +80,22 @@ func (v *HTTPClientConfig) Build() (proto.Message, error) {
|
||||
}
|
||||
for _, rawUser := range serverConfig.Users {
|
||||
user := new(protocol.User)
|
||||
if err := json.Unmarshal(rawUser, user); err != nil {
|
||||
return nil, errors.New("failed to parse HTTP user").Base(err).AtError()
|
||||
if v.Address != nil {
|
||||
user.Level = v.Level
|
||||
user.Email = v.Email
|
||||
} else {
|
||||
if err := json.Unmarshal(rawUser, user); err != nil {
|
||||
return nil, errors.New("failed to parse HTTP user").Base(err).AtError()
|
||||
}
|
||||
}
|
||||
account := new(HTTPAccount)
|
||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||
return nil, errors.New("failed to parse HTTP account").Base(err).AtError()
|
||||
if v.Address != nil {
|
||||
account.Username = v.Username
|
||||
account.Password = v.Password
|
||||
} else {
|
||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||
return nil, errors.New("failed to parse HTTP account").Base(err).AtError()
|
||||
}
|
||||
}
|
||||
user.Account = serial.ToTypedMessage(account.Build())
|
||||
server.User = append(server.User, user)
|
||||
|
||||
@@ -74,8 +74,6 @@ type RouterConfig struct {
|
||||
RuleList []json.RawMessage `json:"rules"`
|
||||
DomainStrategy *string `json:"domainStrategy"`
|
||||
Balancers []*BalancingRule `json:"balancers"`
|
||||
|
||||
DomainMatcher string `json:"domainMatcher"`
|
||||
}
|
||||
|
||||
func (c *RouterConfig) getDomainStrategy() router.Config_DomainStrategy {
|
||||
@@ -111,10 +109,6 @@ func (c *RouterConfig) Build() (*router.Config, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if rule.DomainMatcher == "" {
|
||||
rule.DomainMatcher = c.DomainMatcher
|
||||
}
|
||||
|
||||
config.Rule = append(config.Rule, rule)
|
||||
}
|
||||
for _, rawBalancer := range c.Balancers {
|
||||
@@ -129,11 +123,8 @@ func (c *RouterConfig) Build() (*router.Config, error) {
|
||||
|
||||
type RouterRule struct {
|
||||
RuleTag string `json:"ruleTag"`
|
||||
Type string `json:"type"`
|
||||
OutboundTag string `json:"outboundTag"`
|
||||
BalancerTag string `json:"balancerTag"`
|
||||
|
||||
DomainMatcher string `json:"domainMatcher"`
|
||||
}
|
||||
|
||||
func ParseIP(s string) (*router.CIDR, error) {
|
||||
@@ -536,12 +527,16 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
|
||||
IP *StringList `json:"ip"`
|
||||
Port *PortList `json:"port"`
|
||||
Network *NetworkList `json:"network"`
|
||||
SourceIP *StringList `json:"source"`
|
||||
SourceIP *StringList `json:"sourceIP"`
|
||||
Source *StringList `json:"source"`
|
||||
SourcePort *PortList `json:"sourcePort"`
|
||||
User *StringList `json:"user"`
|
||||
VlessRoute *PortList `json:"vlessRoute"`
|
||||
InboundTag *StringList `json:"inboundTag"`
|
||||
Protocols *StringList `json:"protocol"`
|
||||
Attributes map[string]string `json:"attrs"`
|
||||
LocalIP *StringList `json:"localIP"`
|
||||
LocalPort *PortList `json:"localPort"`
|
||||
}
|
||||
rawFieldRule := new(RawFieldRule)
|
||||
err := json.Unmarshal(msg, rawFieldRule)
|
||||
@@ -564,10 +559,6 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
|
||||
return nil, errors.New("neither outboundTag nor balancerTag is specified in routing rule")
|
||||
}
|
||||
|
||||
if rawFieldRule.DomainMatcher != "" {
|
||||
rule.DomainMatcher = rawFieldRule.DomainMatcher
|
||||
}
|
||||
|
||||
if rawFieldRule.Domain != nil {
|
||||
for _, domain := range *rawFieldRule.Domain {
|
||||
rules, err := parseDomainRule(domain)
|
||||
@@ -604,6 +595,10 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
|
||||
rule.Networks = rawFieldRule.Network.Build()
|
||||
}
|
||||
|
||||
if rawFieldRule.SourceIP == nil {
|
||||
rawFieldRule.SourceIP = rawFieldRule.Source
|
||||
}
|
||||
|
||||
if rawFieldRule.SourceIP != nil {
|
||||
geoipList, err := ToCidrList(*rawFieldRule.SourceIP)
|
||||
if err != nil {
|
||||
@@ -616,12 +611,28 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
|
||||
rule.SourcePortList = rawFieldRule.SourcePort.Build()
|
||||
}
|
||||
|
||||
if rawFieldRule.LocalIP != nil {
|
||||
geoipList, err := ToCidrList(*rawFieldRule.LocalIP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule.LocalGeoip = geoipList
|
||||
}
|
||||
|
||||
if rawFieldRule.LocalPort != nil {
|
||||
rule.LocalPortList = rawFieldRule.LocalPort.Build()
|
||||
}
|
||||
|
||||
if rawFieldRule.User != nil {
|
||||
for _, s := range *rawFieldRule.User {
|
||||
rule.UserEmail = append(rule.UserEmail, s)
|
||||
}
|
||||
}
|
||||
|
||||
if rawFieldRule.VlessRoute != nil {
|
||||
rule.VlessRouteList = rawFieldRule.VlessRoute.Build()
|
||||
}
|
||||
|
||||
if rawFieldRule.InboundTag != nil {
|
||||
for _, s := range *rawFieldRule.InboundTag {
|
||||
rule.InboundTag = append(rule.InboundTag, s)
|
||||
@@ -647,12 +658,10 @@ func ParseRule(msg json.RawMessage) (*router.RoutingRule, error) {
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid router rule").Base(err)
|
||||
}
|
||||
if rawRule.Type == "" || strings.EqualFold(rawRule.Type, "field") {
|
||||
fieldrule, err := parseFieldRule(msg)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid field rule").Base(err)
|
||||
}
|
||||
return fieldrule, nil
|
||||
|
||||
fieldrule, err := parseFieldRule(msg)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid field rule").Base(err)
|
||||
}
|
||||
return nil, errors.New("unknown router rule type: ", rawRule.Type)
|
||||
return fieldrule, nil
|
||||
}
|
||||
|
||||
@@ -91,7 +91,6 @@ func TestRouterConfig(t *testing.T) {
|
||||
"domainStrategy": "AsIs",
|
||||
"rules": [
|
||||
{
|
||||
"type": "field",
|
||||
"domain": [
|
||||
"baidu.com",
|
||||
"qq.com"
|
||||
@@ -99,18 +98,15 @@ func TestRouterConfig(t *testing.T) {
|
||||
"outboundTag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"ip": [
|
||||
"10.0.0.0/8",
|
||||
"::1/128"
|
||||
],
|
||||
"outboundTag": "test"
|
||||
},{
|
||||
"type": "field",
|
||||
"port": "53, 443, 1000-2000",
|
||||
"outboundTag": "test"
|
||||
},{
|
||||
"type": "field",
|
||||
"port": 123,
|
||||
"outboundTag": "test"
|
||||
}
|
||||
@@ -249,7 +245,6 @@ func TestRouterConfig(t *testing.T) {
|
||||
"domainStrategy": "IPIfNonMatch",
|
||||
"rules": [
|
||||
{
|
||||
"type": "field",
|
||||
"domain": [
|
||||
"baidu.com",
|
||||
"qq.com"
|
||||
@@ -257,7 +252,6 @@ func TestRouterConfig(t *testing.T) {
|
||||
"outboundTag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"ip": [
|
||||
"10.0.0.0/8",
|
||||
"::1/128"
|
||||
|
||||
@@ -162,20 +162,44 @@ func buildShadowsocks2022(v *ShadowsocksServerConfig) (proto.Message, error) {
|
||||
type ShadowsocksServerTarget struct {
|
||||
Address *Address `json:"address"`
|
||||
Port uint16 `json:"port"`
|
||||
Level byte `json:"level"`
|
||||
Email string `json:"email"`
|
||||
Cipher string `json:"method"`
|
||||
Password string `json:"password"`
|
||||
Email string `json:"email"`
|
||||
Level byte `json:"level"`
|
||||
IVCheck bool `json:"ivCheck"`
|
||||
UoT bool `json:"uot"`
|
||||
UoTVersion int `json:"uotVersion"`
|
||||
}
|
||||
|
||||
type ShadowsocksClientConfig struct {
|
||||
Address *Address `json:"address"`
|
||||
Port uint16 `json:"port"`
|
||||
Level byte `json:"level"`
|
||||
Email string `json:"email"`
|
||||
Cipher string `json:"method"`
|
||||
Password string `json:"password"`
|
||||
IVCheck bool `json:"ivCheck"`
|
||||
UoT bool `json:"uot"`
|
||||
UoTVersion int `json:"uotVersion"`
|
||||
Servers []*ShadowsocksServerTarget `json:"servers"`
|
||||
}
|
||||
|
||||
func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
|
||||
if v.Address != nil {
|
||||
v.Servers = []*ShadowsocksServerTarget{
|
||||
{
|
||||
Address: v.Address,
|
||||
Port: v.Port,
|
||||
Level: v.Level,
|
||||
Email: v.Email,
|
||||
Cipher: v.Cipher,
|
||||
Password: v.Password,
|
||||
IVCheck: v.IVCheck,
|
||||
UoT: v.UoT,
|
||||
UoTVersion: v.UoTVersion,
|
||||
},
|
||||
}
|
||||
}
|
||||
if len(v.Servers) == 0 {
|
||||
return nil, errors.New("0 Shadowsocks server configured.")
|
||||
}
|
||||
|
||||
@@ -70,11 +70,26 @@ type SocksRemoteConfig struct {
|
||||
}
|
||||
|
||||
type SocksClientConfig struct {
|
||||
Servers []*SocksRemoteConfig `json:"servers"`
|
||||
Address *Address `json:"address"`
|
||||
Port uint16 `json:"port"`
|
||||
Level uint32 `json:"level"`
|
||||
Email string `json:"email"`
|
||||
Username string `json:"user"`
|
||||
Password string `json:"pass"`
|
||||
Servers []*SocksRemoteConfig `json:"servers"`
|
||||
}
|
||||
|
||||
func (v *SocksClientConfig) Build() (proto.Message, error) {
|
||||
config := new(socks.ClientConfig)
|
||||
if v.Address != nil {
|
||||
v.Servers = []*SocksRemoteConfig{
|
||||
{
|
||||
Address: v.Address,
|
||||
Port: v.Port,
|
||||
Users: []json.RawMessage{{}},
|
||||
},
|
||||
}
|
||||
}
|
||||
config.Server = make([]*protocol.ServerEndpoint, len(v.Servers))
|
||||
for idx, serverConfig := range v.Servers {
|
||||
server := &protocol.ServerEndpoint{
|
||||
@@ -83,12 +98,22 @@ func (v *SocksClientConfig) Build() (proto.Message, error) {
|
||||
}
|
||||
for _, rawUser := range serverConfig.Users {
|
||||
user := new(protocol.User)
|
||||
if err := json.Unmarshal(rawUser, user); err != nil {
|
||||
return nil, errors.New("failed to parse Socks user").Base(err).AtError()
|
||||
if v.Address != nil {
|
||||
user.Level = v.Level
|
||||
user.Email = v.Email
|
||||
} else {
|
||||
if err := json.Unmarshal(rawUser, user); err != nil {
|
||||
return nil, errors.New("failed to parse Socks user").Base(err).AtError()
|
||||
}
|
||||
}
|
||||
account := new(SocksAccount)
|
||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||
return nil, errors.New("failed to parse socks account").Base(err).AtError()
|
||||
if v.Address != nil {
|
||||
account.Username = v.Username
|
||||
account.Password = v.Password
|
||||
} else {
|
||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||
return nil, errors.New("failed to parse socks account").Base(err).AtError()
|
||||
}
|
||||
}
|
||||
user.Account = serial.ToTypedMessage(account.Build())
|
||||
server.User = append(server.User, user)
|
||||
|
||||
@@ -86,5 +86,36 @@ func TestSocksOutboundConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Input: `{
|
||||
"address": "127.0.0.1",
|
||||
"port": 1234,
|
||||
"user": "test user",
|
||||
"pass": "test pass",
|
||||
"email": "test@email.com"
|
||||
}`,
|
||||
Parser: loadJSON(creator),
|
||||
Output: &socks.ClientConfig{
|
||||
Server: []*protocol.ServerEndpoint{
|
||||
{
|
||||
Address: &net.IPOrDomain{
|
||||
Address: &net.IPOrDomain_Ip{
|
||||
Ip: []byte{127, 0, 0, 1},
|
||||
},
|
||||
},
|
||||
Port: 1234,
|
||||
User: []*protocol.User{
|
||||
{
|
||||
Email: "test@email.com",
|
||||
Account: serial.ToTypedMessage(&socks.Account{
|
||||
Username: "test user",
|
||||
Password: "test pass",
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -20,19 +20,37 @@ import (
|
||||
type TrojanServerTarget struct {
|
||||
Address *Address `json:"address"`
|
||||
Port uint16 `json:"port"`
|
||||
Password string `json:"password"`
|
||||
Email string `json:"email"`
|
||||
Level byte `json:"level"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
Flow string `json:"flow"`
|
||||
}
|
||||
|
||||
// TrojanClientConfig is configuration of trojan servers
|
||||
type TrojanClientConfig struct {
|
||||
Address *Address `json:"address"`
|
||||
Port uint16 `json:"port"`
|
||||
Level byte `json:"level"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
Flow string `json:"flow"`
|
||||
Servers []*TrojanServerTarget `json:"servers"`
|
||||
}
|
||||
|
||||
// Build implements Buildable
|
||||
func (c *TrojanClientConfig) Build() (proto.Message, error) {
|
||||
if c.Address != nil {
|
||||
c.Servers = []*TrojanServerTarget{
|
||||
{
|
||||
Address: c.Address,
|
||||
Port: c.Port,
|
||||
Level: c.Level,
|
||||
Email: c.Email,
|
||||
Password: c.Password,
|
||||
Flow: c.Flow,
|
||||
},
|
||||
}
|
||||
}
|
||||
if len(c.Servers) == 0 {
|
||||
return nil, errors.New("0 Trojan server configured.")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -32,12 +33,20 @@ type VLessInboundConfig struct {
|
||||
Clients []json.RawMessage `json:"clients"`
|
||||
Decryption string `json:"decryption"`
|
||||
Fallbacks []*VLessInboundFallback `json:"fallbacks"`
|
||||
Flow string `json:"flow"`
|
||||
}
|
||||
|
||||
// Build implements Buildable
|
||||
func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
||||
config := new(inbound.Config)
|
||||
config.Clients = make([]*protocol.User, len(c.Clients))
|
||||
switch c.Flow {
|
||||
case vless.None:
|
||||
c.Flow = ""
|
||||
case "", vless.XRV:
|
||||
default:
|
||||
return nil, errors.New(`VLESS "settings.flow" doesn't support "` + c.Flow + `" in this version`)
|
||||
}
|
||||
for idx, rawUser := range c.Clients {
|
||||
user := new(protocol.User)
|
||||
if err := json.Unmarshal(rawUser, user); err != nil {
|
||||
@@ -55,23 +64,81 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
||||
account.Id = u.String()
|
||||
|
||||
switch account.Flow {
|
||||
case "", vless.XRV:
|
||||
case "":
|
||||
account.Flow = c.Flow
|
||||
case vless.None:
|
||||
account.Flow = ""
|
||||
case vless.XRV:
|
||||
default:
|
||||
return nil, errors.New(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`)
|
||||
}
|
||||
|
||||
if account.Encryption != "" {
|
||||
return nil, errors.New(`VLESS clients: "encryption" should not in inbound settings`)
|
||||
return nil, errors.New(`VLESS clients: "encryption" should not be in inbound settings`)
|
||||
}
|
||||
|
||||
if account.Reverse != nil && account.Reverse.Tag == "" {
|
||||
return nil, errors.New(`VLESS clients: "tag" can't be empty for "reverse"`)
|
||||
}
|
||||
|
||||
user.Account = serial.ToTypedMessage(account)
|
||||
config.Clients[idx] = user
|
||||
}
|
||||
|
||||
if c.Decryption != "none" {
|
||||
return nil, errors.New(`VLESS settings: please add/set "decryption":"none" to every settings`)
|
||||
}
|
||||
config.Decryption = c.Decryption
|
||||
if !func() bool {
|
||||
s := strings.Split(config.Decryption, ".")
|
||||
if len(s) < 4 || s[0] != "mlkem768x25519plus" {
|
||||
return false
|
||||
}
|
||||
switch s[1] {
|
||||
case "native":
|
||||
case "xorpub":
|
||||
config.XorMode = 1
|
||||
case "random":
|
||||
config.XorMode = 2
|
||||
default:
|
||||
return false
|
||||
}
|
||||
t := strings.SplitN(strings.TrimSuffix(s[2], "s"), "-", 2)
|
||||
i, err := strconv.Atoi(t[0])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
config.SecondsFrom = int64(i)
|
||||
if len(t) == 2 {
|
||||
i, err := strconv.Atoi(t[1])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
config.SecondsTo = int64(i)
|
||||
}
|
||||
padding := 0
|
||||
for _, r := range s[3:] {
|
||||
if len(r) < 20 {
|
||||
padding += len(r) + 1
|
||||
continue
|
||||
}
|
||||
if b, _ := base64.RawURLEncoding.DecodeString(r); len(b) != 32 && len(b) != 64 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
config.Decryption = config.Decryption[27+len(s[2]):]
|
||||
if padding > 0 {
|
||||
config.Padding = config.Decryption[:padding-1]
|
||||
config.Decryption = config.Decryption[padding:]
|
||||
}
|
||||
return true
|
||||
}() && config.Decryption != "none" {
|
||||
if config.Decryption == "" {
|
||||
return nil, errors.New(`VLESS settings: please add/set "decryption":"none" to every settings`)
|
||||
}
|
||||
return nil, errors.New(`VLESS settings: unsupported "decryption": ` + config.Decryption)
|
||||
}
|
||||
|
||||
if config.Decryption != "none" && c.Fallbacks != nil {
|
||||
return nil, errors.New(`VLESS settings: "fallbacks" can not be used together with "decryption"`)
|
||||
}
|
||||
|
||||
for _, fb := range c.Fallbacks {
|
||||
var i uint16
|
||||
@@ -136,23 +203,40 @@ type VLessOutboundVnext struct {
|
||||
}
|
||||
|
||||
type VLessOutboundConfig struct {
|
||||
Vnext []*VLessOutboundVnext `json:"vnext"`
|
||||
Address *Address `json:"address"`
|
||||
Port uint16 `json:"port"`
|
||||
Level uint32 `json:"level"`
|
||||
Email string `json:"email"`
|
||||
Id string `json:"id"`
|
||||
Flow string `json:"flow"`
|
||||
Seed string `json:"seed"`
|
||||
Encryption string `json:"encryption"`
|
||||
Reverse *vless.Reverse `json:"reverse"`
|
||||
Vnext []*VLessOutboundVnext `json:"vnext"`
|
||||
}
|
||||
|
||||
// Build implements Buildable
|
||||
func (c *VLessOutboundConfig) Build() (proto.Message, error) {
|
||||
config := new(outbound.Config)
|
||||
|
||||
if len(c.Vnext) == 0 {
|
||||
return nil, errors.New(`VLESS settings: "vnext" is empty`)
|
||||
if c.Address != nil {
|
||||
c.Vnext = []*VLessOutboundVnext{
|
||||
{
|
||||
Address: c.Address,
|
||||
Port: c.Port,
|
||||
Users: []json.RawMessage{{}},
|
||||
},
|
||||
}
|
||||
}
|
||||
if len(c.Vnext) != 1 {
|
||||
return nil, errors.New(`VLESS settings: "vnext" should have one and only one member`)
|
||||
}
|
||||
config.Vnext = make([]*protocol.ServerEndpoint, len(c.Vnext))
|
||||
for idx, rec := range c.Vnext {
|
||||
if rec.Address == nil {
|
||||
return nil, errors.New(`VLESS vnext: "address" is not set`)
|
||||
}
|
||||
if len(rec.Users) == 0 {
|
||||
return nil, errors.New(`VLESS vnext: "users" is empty`)
|
||||
if len(rec.Users) != 1 {
|
||||
return nil, errors.New(`VLESS vnext: "users" should have one and only one member`)
|
||||
}
|
||||
spec := &protocol.ServerEndpoint{
|
||||
Address: rec.Address.Build(),
|
||||
@@ -161,12 +245,25 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
|
||||
}
|
||||
for idx, rawUser := range rec.Users {
|
||||
user := new(protocol.User)
|
||||
if err := json.Unmarshal(rawUser, user); err != nil {
|
||||
return nil, errors.New(`VLESS users: invalid user`).Base(err)
|
||||
if c.Address != nil {
|
||||
user.Level = c.Level
|
||||
user.Email = c.Email
|
||||
} else {
|
||||
if err := json.Unmarshal(rawUser, user); err != nil {
|
||||
return nil, errors.New(`VLESS users: invalid user`).Base(err)
|
||||
}
|
||||
}
|
||||
account := new(vless.Account)
|
||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||
return nil, errors.New(`VLESS users: invalid user`).Base(err)
|
||||
if c.Address != nil {
|
||||
account.Id = c.Id
|
||||
account.Flow = c.Flow
|
||||
//account.Seed = c.Seed
|
||||
account.Encryption = c.Encryption
|
||||
account.Reverse = c.Reverse
|
||||
} else {
|
||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||
return nil, errors.New(`VLESS users: invalid user`).Base(err)
|
||||
}
|
||||
}
|
||||
|
||||
u, err := uuid.ParseString(account.Id)
|
||||
@@ -181,8 +278,52 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
|
||||
return nil, errors.New(`VLESS users: "flow" doesn't support "` + account.Flow + `" in this version`)
|
||||
}
|
||||
|
||||
if account.Encryption != "none" {
|
||||
return nil, errors.New(`VLESS users: please add/set "encryption":"none" for every user`)
|
||||
if !func() bool {
|
||||
s := strings.Split(account.Encryption, ".")
|
||||
if len(s) < 4 || s[0] != "mlkem768x25519plus" {
|
||||
return false
|
||||
}
|
||||
switch s[1] {
|
||||
case "native":
|
||||
case "xorpub":
|
||||
account.XorMode = 1
|
||||
case "random":
|
||||
account.XorMode = 2
|
||||
default:
|
||||
return false
|
||||
}
|
||||
switch s[2] {
|
||||
case "1rtt":
|
||||
case "0rtt":
|
||||
account.Seconds = 1
|
||||
default:
|
||||
return false
|
||||
}
|
||||
padding := 0
|
||||
for _, r := range s[3:] {
|
||||
if len(r) < 20 {
|
||||
padding += len(r) + 1
|
||||
continue
|
||||
}
|
||||
if b, _ := base64.RawURLEncoding.DecodeString(r); len(b) != 32 && len(b) != 1184 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
account.Encryption = account.Encryption[27+len(s[2]):]
|
||||
if padding > 0 {
|
||||
account.Padding = account.Encryption[:padding-1]
|
||||
account.Encryption = account.Encryption[padding:]
|
||||
}
|
||||
return true
|
||||
}() && account.Encryption != "none" {
|
||||
if account.Encryption == "" {
|
||||
return nil, errors.New(`VLESS users: please add/set "encryption":"none" for every user`)
|
||||
}
|
||||
return nil, errors.New(`VLESS users: unsupported "encryption": ` + account.Encryption)
|
||||
}
|
||||
|
||||
if account.Reverse != nil && account.Reverse.Tag == "" {
|
||||
return nil, errors.New(`VLESS clients: "tag" can't be empty for "reverse"`)
|
||||
}
|
||||
|
||||
user.Account = serial.ToTypedMessage(account)
|
||||
|
||||
@@ -57,6 +57,39 @@ func TestVLessOutbound(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Input: `{
|
||||
"address": "example.com",
|
||||
"port": 443,
|
||||
"id": "27848739-7e62-4138-9fd3-098a63964b6b",
|
||||
"flow": "xtls-rprx-vision-udp443",
|
||||
"encryption": "none",
|
||||
"level": 0
|
||||
}`,
|
||||
Parser: loadJSON(creator),
|
||||
Output: &outbound.Config{
|
||||
Vnext: []*protocol.ServerEndpoint{
|
||||
{
|
||||
Address: &net.IPOrDomain{
|
||||
Address: &net.IPOrDomain_Domain{
|
||||
Domain: "example.com",
|
||||
},
|
||||
},
|
||||
Port: 443,
|
||||
User: []*protocol.User{
|
||||
{
|
||||
Account: serial.ToTypedMessage(&vless.Account{
|
||||
Id: "27848739-7e62-4138-9fd3-098a63964b6b",
|
||||
Flow: "xtls-rprx-vision-udp443",
|
||||
Encryption: "none",
|
||||
}),
|
||||
Level: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -117,13 +117,28 @@ type VMessOutboundTarget struct {
|
||||
}
|
||||
|
||||
type VMessOutboundConfig struct {
|
||||
Receivers []*VMessOutboundTarget `json:"vnext"`
|
||||
Address *Address `json:"address"`
|
||||
Port uint16 `json:"port"`
|
||||
Level uint32 `json:"level"`
|
||||
Email string `json:"email"`
|
||||
ID string `json:"id"`
|
||||
Security string `json:"security"`
|
||||
Experiments string `json:"experiments"`
|
||||
Receivers []*VMessOutboundTarget `json:"vnext"`
|
||||
}
|
||||
|
||||
// Build implements Buildable
|
||||
func (c *VMessOutboundConfig) Build() (proto.Message, error) {
|
||||
config := new(outbound.Config)
|
||||
|
||||
if c.Address != nil {
|
||||
c.Receivers = []*VMessOutboundTarget{
|
||||
{
|
||||
Address: c.Address,
|
||||
Port: c.Port,
|
||||
Users: []json.RawMessage{{}},
|
||||
},
|
||||
}
|
||||
}
|
||||
if len(c.Receivers) == 0 {
|
||||
return nil, errors.New("0 VMess receiver configured")
|
||||
}
|
||||
@@ -141,12 +156,23 @@ func (c *VMessOutboundConfig) Build() (proto.Message, error) {
|
||||
}
|
||||
for _, rawUser := range rec.Users {
|
||||
user := new(protocol.User)
|
||||
if err := json.Unmarshal(rawUser, user); err != nil {
|
||||
return nil, errors.New("invalid VMess user").Base(err)
|
||||
if c.Address != nil {
|
||||
user.Level = c.Level
|
||||
user.Email = c.Email
|
||||
} else {
|
||||
if err := json.Unmarshal(rawUser, user); err != nil {
|
||||
return nil, errors.New("invalid VMess user").Base(err)
|
||||
}
|
||||
}
|
||||
account := new(VMessAccount)
|
||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||
return nil, errors.New("invalid VMess user").Base(err)
|
||||
if c.Address != nil {
|
||||
account.ID = c.ID
|
||||
account.Security = c.Security
|
||||
account.Experiments = c.Experiments
|
||||
} else {
|
||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||
return nil, errors.New("invalid VMess user").Base(err)
|
||||
}
|
||||
}
|
||||
|
||||
u, err := uuid.ParseString(account.ID)
|
||||
|
||||
@@ -58,6 +58,40 @@ func TestVMessOutbound(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Input: `{
|
||||
"address": "127.0.0.1",
|
||||
"port": 80,
|
||||
"id": "e641f5ad-9397-41e3-bf1a-e8740dfed019",
|
||||
"email": "love@example.com",
|
||||
"level": 255
|
||||
}`,
|
||||
Parser: loadJSON(creator),
|
||||
Output: &outbound.Config{
|
||||
Receiver: []*protocol.ServerEndpoint{
|
||||
{
|
||||
Address: &net.IPOrDomain{
|
||||
Address: &net.IPOrDomain_Ip{
|
||||
Ip: []byte{127, 0, 0, 1},
|
||||
},
|
||||
},
|
||||
Port: 80,
|
||||
User: []*protocol.User{
|
||||
{
|
||||
Email: "love@example.com",
|
||||
Level: 255,
|
||||
Account: serial.ToTypedMessage(&vmess.Account{
|
||||
Id: "e641f5ad-9397-41e3-bf1a-e8740dfed019",
|
||||
SecuritySettings: &protocol.SecurityConfig{
|
||||
Type: protocol.SecurityType_AUTO,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -260,13 +260,14 @@ func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
|
||||
}
|
||||
|
||||
type OutboundDetourConfig struct {
|
||||
Protocol string `json:"protocol"`
|
||||
SendThrough *string `json:"sendThrough"`
|
||||
Tag string `json:"tag"`
|
||||
Settings *json.RawMessage `json:"settings"`
|
||||
StreamSetting *StreamConfig `json:"streamSettings"`
|
||||
ProxySettings *ProxyConfig `json:"proxySettings"`
|
||||
MuxSettings *MuxConfig `json:"mux"`
|
||||
Protocol string `json:"protocol"`
|
||||
SendThrough *string `json:"sendThrough"`
|
||||
Tag string `json:"tag"`
|
||||
Settings *json.RawMessage `json:"settings"`
|
||||
StreamSetting *StreamConfig `json:"streamSettings"`
|
||||
ProxySettings *ProxyConfig `json:"proxySettings"`
|
||||
MuxSettings *MuxConfig `json:"mux"`
|
||||
TargetStrategy string `json:"targetStrategy"`
|
||||
}
|
||||
|
||||
func (c *OutboundDetourConfig) checkChainProxyConfig() error {
|
||||
@@ -282,6 +283,32 @@ func (c *OutboundDetourConfig) checkChainProxyConfig() error {
|
||||
// Build implements Buildable.
|
||||
func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
||||
senderSettings := &proxyman.SenderConfig{}
|
||||
switch strings.ToLower(c.TargetStrategy) {
|
||||
case "asis", "":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_AS_IS
|
||||
case "useip":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_USE_IP
|
||||
case "useipv4":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_USE_IP4
|
||||
case "useipv6":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_USE_IP6
|
||||
case "useipv4v6":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_USE_IP46
|
||||
case "useipv6v4":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_USE_IP64
|
||||
case "forceip":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_FORCE_IP
|
||||
case "forceipv4":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_FORCE_IP4
|
||||
case "forceipv6":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_FORCE_IP6
|
||||
case "forceipv4v6":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_FORCE_IP46
|
||||
case "forceipv6v4":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_FORCE_IP64
|
||||
default:
|
||||
return nil, errors.New("unsupported target domain strategy: ", c.TargetStrategy)
|
||||
}
|
||||
if err := c.checkChainProxyConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ func TestXrayConfig(t *testing.T) {
|
||||
"ip": [
|
||||
"10.0.0.0/8"
|
||||
],
|
||||
"type": "field",
|
||||
"outboundTag": "blocked"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -93,7 +93,6 @@ func executeSourceIpBlock(cmd *base.Command, args []string) {
|
||||
"ruleTag" : "%s",
|
||||
"inboundTag": %s,
|
||||
"outboundTag": "%s",
|
||||
"type": "field",
|
||||
"source": %s
|
||||
}
|
||||
]
|
||||
|
||||
@@ -17,5 +17,7 @@ func init() {
|
||||
cmdX25519,
|
||||
cmdWG,
|
||||
cmdMLDSA65,
|
||||
cmdMLKEM768,
|
||||
cmdVLESSEnc,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package convert
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/common/cmdarg"
|
||||
creflect "github.com/xtls/xray-core/common/reflect"
|
||||
@@ -14,15 +15,18 @@ import (
|
||||
|
||||
var cmdProtobuf = &base.Command{
|
||||
CustomFlags: true,
|
||||
UsageLine: "{{.Exec}} convert pb [-debug] [-type] [json file] [json file] ...",
|
||||
UsageLine: "{{.Exec}} convert pb [-outpbfile file] [-debug] [-type] [json file] [json file] ...",
|
||||
Short: "Convert multiple json configs to protobuf",
|
||||
Long: `
|
||||
Convert multiple json configs to protobuf.
|
||||
Convert multiple configs to ProtoBuf. JSON, YAML and TOML can be used.
|
||||
|
||||
Arguments:
|
||||
|
||||
-o file, -outpbfile file
|
||||
Write the ProtoBuf output (eg. mix.pb) to specified file location.
|
||||
|
||||
-d, -debug
|
||||
Show mix.pb as json.
|
||||
Show mix.pb as JSON format.
|
||||
FOR DEBUGGING ONLY!
|
||||
DO NOT PASS THIS OUTPUT TO XRAY-CORE!
|
||||
|
||||
@@ -31,16 +35,20 @@ Arguments:
|
||||
|
||||
Examples:
|
||||
|
||||
{{.Exec}} convert pb config.json c1.json c2.json c3.json > mix.pb
|
||||
{{.Exec}} convert pb -outpbfile output.pb config.json c1.json c2.json c3.json
|
||||
{{.Exec}} convert pb -debug mix.pb
|
||||
`,
|
||||
Run: executeConvertConfigsToProtobuf,
|
||||
}
|
||||
|
||||
func executeConvertConfigsToProtobuf(cmd *base.Command, args []string) {
|
||||
|
||||
var optFile string
|
||||
var optDump bool
|
||||
var optType bool
|
||||
|
||||
cmd.Flag.StringVar(&optFile, "o", "", "")
|
||||
cmd.Flag.StringVar(&optFile, "outpbfile", "", "")
|
||||
cmd.Flag.BoolVar(&optDump, "d", false, "")
|
||||
cmd.Flag.BoolVar(&optDump, "debug", false, "")
|
||||
cmd.Flag.BoolVar(&optType, "t", false, "")
|
||||
@@ -52,6 +60,17 @@ func executeConvertConfigsToProtobuf(cmd *base.Command, args []string) {
|
||||
unnamedArgs.Set(v)
|
||||
}
|
||||
|
||||
if len(optFile) > 0 {
|
||||
switch core.GetFormatByExtension(getFileExtension(optFile)){
|
||||
case "protobuf", "":
|
||||
fmt.Println("Output ProtoBuf file is ", optFile)
|
||||
default:
|
||||
base.Fatalf("-outpbfile followed by a possible original config.")
|
||||
}
|
||||
} else if !optDump {
|
||||
base.Fatalf("-outpbfile not specified")
|
||||
}
|
||||
|
||||
if len(unnamedArgs) < 1 {
|
||||
base.Fatalf("invalid config list length: %d", len(unnamedArgs))
|
||||
}
|
||||
@@ -70,12 +89,28 @@ func executeConvertConfigsToProtobuf(cmd *base.Command, args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
bytesConfig, err := proto.Marshal(pbConfig)
|
||||
if err != nil {
|
||||
base.Fatalf("failed to marshal proto config: %s", err)
|
||||
}
|
||||
if len(optFile) > 0 {
|
||||
bytesConfig, err := proto.Marshal(pbConfig)
|
||||
if err != nil {
|
||||
base.Fatalf("failed to marshal proto config: %s", err)
|
||||
}
|
||||
|
||||
if _, err := os.Stdout.Write(bytesConfig); err != nil {
|
||||
base.Fatalf("failed to write proto config: %s", err)
|
||||
f, err := os.Create(optFile)
|
||||
if err != nil {
|
||||
base.Fatalf("failed to create proto file: %s", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := f.Write(bytesConfig); err != nil {
|
||||
base.Fatalf("failed to write proto file: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getFileExtension(filename string) string {
|
||||
idx := strings.LastIndexByte(filename, '.')
|
||||
if idx == -1 {
|
||||
return ""
|
||||
}
|
||||
return filename[idx+1:]
|
||||
}
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
package all
|
||||
|
||||
import (
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/curve25519"
|
||||
"lukechampine.com/blake3"
|
||||
)
|
||||
|
||||
func Curve25519Genkey(StdEncoding bool, input_base64 string) {
|
||||
var output string
|
||||
var err error
|
||||
var privateKey, publicKey []byte
|
||||
var encoding *base64.Encoding
|
||||
if *input_stdEncoding || StdEncoding {
|
||||
encoding = base64.StdEncoding
|
||||
@@ -19,40 +17,47 @@ func Curve25519Genkey(StdEncoding bool, input_base64 string) {
|
||||
encoding = base64.RawURLEncoding
|
||||
}
|
||||
|
||||
var privateKey []byte
|
||||
if len(input_base64) > 0 {
|
||||
privateKey, err = encoding.DecodeString(input_base64)
|
||||
if err != nil {
|
||||
output = err.Error()
|
||||
goto out
|
||||
}
|
||||
if len(privateKey) != curve25519.ScalarSize {
|
||||
output = "Invalid length of private key."
|
||||
goto out
|
||||
privateKey, _ = encoding.DecodeString(input_base64)
|
||||
if len(privateKey) != 32 {
|
||||
fmt.Println("Invalid length of X25519 private key.")
|
||||
return
|
||||
}
|
||||
}
|
||||
privateKey, password, hash32, err := genCurve25519(privateKey)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("PrivateKey: %v\nPassword: %v\nHash32: %v\n",
|
||||
encoding.EncodeToString(privateKey),
|
||||
encoding.EncodeToString(password),
|
||||
encoding.EncodeToString(hash32[:]))
|
||||
}
|
||||
|
||||
func genCurve25519(inputPrivateKey []byte) (privateKey []byte, password []byte, hash32 [32]byte, returnErr error) {
|
||||
if len(inputPrivateKey) > 0 {
|
||||
privateKey = inputPrivateKey
|
||||
}
|
||||
if privateKey == nil {
|
||||
privateKey = make([]byte, curve25519.ScalarSize)
|
||||
if _, err = rand.Read(privateKey); err != nil {
|
||||
output = err.Error()
|
||||
goto out
|
||||
}
|
||||
privateKey = make([]byte, 32)
|
||||
rand.Read(privateKey)
|
||||
}
|
||||
|
||||
// Modify random bytes using algorithm described at:
|
||||
// https://cr.yp.to/ecdh.html.
|
||||
// https://cr.yp.to/ecdh.html
|
||||
// (Just to make sure printing the real private key)
|
||||
privateKey[0] &= 248
|
||||
privateKey[31] &= 127
|
||||
privateKey[31] |= 64
|
||||
|
||||
if publicKey, err = curve25519.X25519(privateKey, curve25519.Basepoint); err != nil {
|
||||
output = err.Error()
|
||||
goto out
|
||||
key, err := ecdh.X25519().NewPrivateKey(privateKey)
|
||||
if err != nil {
|
||||
returnErr = err
|
||||
return
|
||||
}
|
||||
|
||||
output = fmt.Sprintf("Private key: %v\nPublic key: %v",
|
||||
encoding.EncodeToString(privateKey),
|
||||
encoding.EncodeToString(publicKey))
|
||||
out:
|
||||
fmt.Println(output)
|
||||
password = key.PublicKey().Bytes()
|
||||
hash32 = blake3.Sum256(password)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
|
||||
var cmdMLDSA65 = &base.Command{
|
||||
UsageLine: `{{.Exec}} mldsa65 [-i "seed (base64.RawURLEncoding)"]`,
|
||||
Short: `Generate key pair for ML-DSA-65 post-quantum signature`,
|
||||
Short: `Generate key pair for ML-DSA-65 post-quantum signature (REALITY)`,
|
||||
Long: `
|
||||
Generate key pair for ML-DSA-65 post-quantum signature.
|
||||
Generate key pair for ML-DSA-65 post-quantum signature (REALITY).
|
||||
|
||||
Random: {{.Exec}} mldsa65
|
||||
|
||||
@@ -25,18 +25,22 @@ func init() {
|
||||
cmdMLDSA65.Run = executeMLDSA65 // break init loop
|
||||
}
|
||||
|
||||
var input_seed = cmdMLDSA65.Flag.String("i", "", "")
|
||||
var input_mldsa65 = cmdMLDSA65.Flag.String("i", "", "")
|
||||
|
||||
func executeMLDSA65(cmd *base.Command, args []string) {
|
||||
var seed [32]byte
|
||||
if len(*input_seed) > 0 {
|
||||
s, _ := base64.RawURLEncoding.DecodeString(*input_seed)
|
||||
if len(*input_mldsa65) > 0 {
|
||||
s, _ := base64.RawURLEncoding.DecodeString(*input_mldsa65)
|
||||
if len(s) != 32 {
|
||||
fmt.Println("Invalid length of ML-DSA-65 seed.")
|
||||
return
|
||||
}
|
||||
seed = [32]byte(s)
|
||||
} else {
|
||||
rand.Read(seed[:])
|
||||
}
|
||||
pub, _ := mldsa65.NewKeyFromSeed(&seed)
|
||||
fmt.Printf("Seed: %v\nVerify: %v",
|
||||
fmt.Printf("Seed: %v\nVerify: %v\n",
|
||||
base64.RawURLEncoding.EncodeToString(seed[:]),
|
||||
base64.RawURLEncoding.EncodeToString(pub.Bytes()))
|
||||
}
|
||||
|
||||
60
main/commands/all/mlkem768.go
Normal file
60
main/commands/all/mlkem768.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package all
|
||||
|
||||
import (
|
||||
"crypto/mlkem"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"github.com/xtls/xray-core/main/commands/base"
|
||||
"lukechampine.com/blake3"
|
||||
)
|
||||
|
||||
var cmdMLKEM768 = &base.Command{
|
||||
UsageLine: `{{.Exec}} mlkem768 [-i "seed (base64.RawURLEncoding)"]`,
|
||||
Short: `Generate key pair for ML-KEM-768 post-quantum key exchange (VLESS Encryption)`,
|
||||
Long: `
|
||||
Generate key pair for ML-KEM-768 post-quantum key exchange (VLESS Encryption).
|
||||
|
||||
Random: {{.Exec}} mlkem768
|
||||
|
||||
From seed: {{.Exec}} mlkem768 -i "seed (base64.RawURLEncoding)"
|
||||
`,
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmdMLKEM768.Run = executeMLKEM768 // break init loop
|
||||
}
|
||||
|
||||
var input_mlkem768 = cmdMLKEM768.Flag.String("i", "", "")
|
||||
|
||||
func executeMLKEM768(cmd *base.Command, args []string) {
|
||||
var seed [64]byte
|
||||
if len(*input_mlkem768) > 0 {
|
||||
s, _ := base64.RawURLEncoding.DecodeString(*input_mlkem768)
|
||||
if len(s) != 64 {
|
||||
fmt.Println("Invalid length of ML-KEM-768 seed.")
|
||||
return
|
||||
}
|
||||
seed = [64]byte(s)
|
||||
} else {
|
||||
rand.Read(seed[:])
|
||||
}
|
||||
seed, client, hash32 := genMLKEM768(&seed)
|
||||
fmt.Printf("Seed: %v\nClient: %v\nHash32: %v\n",
|
||||
base64.RawURLEncoding.EncodeToString(seed[:]),
|
||||
base64.RawURLEncoding.EncodeToString(client),
|
||||
base64.RawURLEncoding.EncodeToString(hash32[:]))
|
||||
}
|
||||
|
||||
func genMLKEM768(inputSeed *[64]byte) (seed [64]byte, client []byte, hash32 [32]byte) {
|
||||
if inputSeed == nil {
|
||||
rand.Read(seed[:])
|
||||
} else {
|
||||
seed = *inputSeed
|
||||
}
|
||||
key, _ := mlkem.NewDecapsulationKey768(seed[:])
|
||||
client = key.EncapsulationKey().Bytes()
|
||||
hash32 = blake3.Sum256(client)
|
||||
return
|
||||
}
|
||||
@@ -6,9 +6,7 @@ import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
|
||||
"github.com/xtls/xray-core/main/commands/base"
|
||||
. "github.com/xtls/xray-core/transport/internet/tls"
|
||||
@@ -94,7 +92,7 @@ func executePing(cmd *base.Command, args []string) {
|
||||
fmt.Println("-------------------")
|
||||
fmt.Println("Pinging with SNI")
|
||||
{
|
||||
tcpConn, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: ip, Port: 443})
|
||||
tcpConn, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: ip, Port: TargetPort})
|
||||
if err != nil {
|
||||
base.Fatalf("Failed to dial tcp: %s", err)
|
||||
}
|
||||
@@ -139,14 +137,15 @@ func printCertificates(certs []*x509.Certificate) {
|
||||
}
|
||||
|
||||
func printTLSConnDetail(tlsConn *gotls.Conn) {
|
||||
connectionState := tlsConn.ConnectionState()
|
||||
var tlsVersion string
|
||||
if tlsConn.ConnectionState().Version == gotls.VersionTLS13 {
|
||||
if connectionState.Version == gotls.VersionTLS13 {
|
||||
tlsVersion = "TLS 1.3"
|
||||
} else if tlsConn.ConnectionState().Version == gotls.VersionTLS12 {
|
||||
} else if connectionState.Version == gotls.VersionTLS12 {
|
||||
tlsVersion = "TLS 1.2"
|
||||
}
|
||||
fmt.Println("TLS Version: ", tlsVersion)
|
||||
curveID := *(*gotls.CurveID)(unsafe.Pointer(reflect.ValueOf(tlsConn).Elem().FieldByName("curveID").UnsafeAddr()))
|
||||
curveID := connectionState.CurveID
|
||||
if curveID != 0 {
|
||||
PostQuantum := (curveID == gotls.X25519MLKEM768)
|
||||
fmt.Println("TLS Post-Quantum key exchange: ", PostQuantum, "("+curveID.String()+")")
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
|
||||
var cmdUUID = &base.Command{
|
||||
UsageLine: `{{.Exec}} uuid [-i "example"]`,
|
||||
Short: `Generate UUIDv4 or UUIDv5`,
|
||||
Short: `Generate UUIDv4 or UUIDv5 (VLESS)`,
|
||||
Long: `
|
||||
Generate UUIDv4 or UUIDv5.
|
||||
Generate UUIDv4 or UUIDv5 (VLESS).
|
||||
|
||||
UUIDv4 (random): {{.Exec}} uuid
|
||||
|
||||
|
||||
41
main/commands/all/vlessenc.go
Normal file
41
main/commands/all/vlessenc.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package all
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/main/commands/base"
|
||||
)
|
||||
|
||||
var cmdVLESSEnc = &base.Command{
|
||||
UsageLine: `{{.Exec}} vlessenc`,
|
||||
Short: `Generate decryption/encryption json pair (VLESS Encryption)`,
|
||||
Long: `
|
||||
Generate decryption/encryption json pair (VLESS Encryption).
|
||||
`,
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmdVLESSEnc.Run = executeVLESSEnc // break init loop
|
||||
}
|
||||
|
||||
func executeVLESSEnc(cmd *base.Command, args []string) {
|
||||
privateKey, password, _, _ := genCurve25519(nil)
|
||||
serverKey := base64.RawURLEncoding.EncodeToString(privateKey)
|
||||
clientKey := base64.RawURLEncoding.EncodeToString(password)
|
||||
decryption := generateDotConfig("mlkem768x25519plus", "native", "600s", serverKey)
|
||||
encryption := generateDotConfig("mlkem768x25519plus", "native", "0rtt", clientKey)
|
||||
seed, client, _ := genMLKEM768(nil)
|
||||
serverKeyPQ := base64.RawURLEncoding.EncodeToString(seed[:])
|
||||
clientKeyPQ := base64.RawURLEncoding.EncodeToString(client)
|
||||
decryptionPQ := generateDotConfig("mlkem768x25519plus", "native", "600s", serverKeyPQ)
|
||||
encryptionPQ := generateDotConfig("mlkem768x25519plus", "native", "0rtt", clientKeyPQ)
|
||||
fmt.Printf("Choose one Authentication to use, do not mix them. Ephemeral key exchange is Post-Quantum safe anyway.\n\n")
|
||||
fmt.Printf("Authentication: X25519, not Post-Quantum\n\"decryption\": \"%v\"\n\"encryption\": \"%v\"\n\n", decryption, encryption)
|
||||
fmt.Printf("Authentication: ML-KEM-768, Post-Quantum\n\"decryption\": \"%v\"\n\"encryption\": \"%v\"\n", decryptionPQ, encryptionPQ)
|
||||
}
|
||||
|
||||
func generateDotConfig(fields ...string) string {
|
||||
return strings.Join(fields, ".")
|
||||
}
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
|
||||
var cmdWG = &base.Command{
|
||||
UsageLine: `{{.Exec}} wg [-i "private key (base64.StdEncoding)"]`,
|
||||
Short: `Generate key pair for wireguard key exchange`,
|
||||
Short: `Generate key pair for X25519 key exchange (WireGuard)`,
|
||||
Long: `
|
||||
Generate key pair for wireguard key exchange.
|
||||
Generate key pair for X25519 key exchange (WireGuard).
|
||||
|
||||
Random: {{.Exec}} wg
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
|
||||
var cmdX25519 = &base.Command{
|
||||
UsageLine: `{{.Exec}} x25519 [-i "private key (base64.RawURLEncoding)"] [--std-encoding]`,
|
||||
Short: `Generate key pair for x25519 key exchange`,
|
||||
Short: `Generate key pair for X25519 key exchange (REALITY, VLESS Encryption)`,
|
||||
Long: `
|
||||
Generate key pair for x25519 key exchange.
|
||||
Generate key pair for X25519 key exchange (REALITY, VLESS Encryption).
|
||||
|
||||
Random: {{.Exec}} x25519
|
||||
|
||||
|
||||
13
main/run.go
13
main/run.go
@@ -182,12 +182,15 @@ func getConfigFilePath(verbose bool) cmdarg.Arg {
|
||||
}
|
||||
|
||||
if workingDir, err := os.Getwd(); err == nil {
|
||||
configFile := filepath.Join(workingDir, "config.json")
|
||||
if fileExists(configFile) {
|
||||
if verbose {
|
||||
log.Println("Using default config: ", configFile)
|
||||
suffixes := []string{".json", ".jsonc", ".toml", ".yaml", ".yml"}
|
||||
for _, suffix := range suffixes {
|
||||
configFile := filepath.Join(workingDir, "config"+suffix)
|
||||
if fileExists(configFile) {
|
||||
if verbose {
|
||||
log.Println("Using default config: ", configFile)
|
||||
}
|
||||
return cmdarg.Arg{configFile}
|
||||
}
|
||||
return cmdarg.Arg{configFile}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
go_errors "errors"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -65,6 +66,9 @@ func (h *Handler) Init(config *Config, dnsClient dns.Client, policyManager polic
|
||||
h.server = config.Server.AsDestination()
|
||||
}
|
||||
h.nonIPQuery = config.Non_IPQuery
|
||||
if h.nonIPQuery == "" {
|
||||
h.nonIPQuery = "reject"
|
||||
}
|
||||
h.blockTypes = config.BlockTypes
|
||||
return nil
|
||||
}
|
||||
@@ -165,11 +169,15 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
timer := signal.CancelAfterInactivity(ctx, cancel, h.timeout)
|
||||
terminate := func() {
|
||||
cancel()
|
||||
conn.Close()
|
||||
}
|
||||
timer := signal.CancelAfterInactivity(ctx, terminate, h.timeout)
|
||||
defer timer.SetTimeout(0)
|
||||
|
||||
request := func() error {
|
||||
defer conn.Close()
|
||||
|
||||
defer timer.SetTimeout(0)
|
||||
for {
|
||||
b, err := reader.ReadMessage()
|
||||
if err == io.EOF {
|
||||
@@ -187,24 +195,33 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.
|
||||
if len(h.blockTypes) > 0 {
|
||||
for _, blocktype := range h.blockTypes {
|
||||
if blocktype == int32(qType) {
|
||||
if h.nonIPQuery == "reject" {
|
||||
go h.rejectNonIPQuery(id, qType, domain, writer)
|
||||
}
|
||||
b.Release()
|
||||
errors.LogInfo(ctx, "blocked type ", qType, " query for domain ", domain)
|
||||
if h.nonIPQuery == "reject" {
|
||||
err := h.rejectNonIPQuery(id, qType, domain, writer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if isIPQuery {
|
||||
go h.handleIPQuery(id, qType, domain, writer)
|
||||
b.Release()
|
||||
go h.handleIPQuery(id, qType, domain, writer, timer)
|
||||
continue
|
||||
}
|
||||
if isIPQuery || h.nonIPQuery == "drop" {
|
||||
if h.nonIPQuery == "drop" {
|
||||
b.Release()
|
||||
continue
|
||||
}
|
||||
if h.nonIPQuery == "reject" {
|
||||
go h.rejectNonIPQuery(id, qType, domain, writer)
|
||||
b.Release()
|
||||
err := h.rejectNonIPQuery(id, qType, domain, writer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -216,6 +233,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.
|
||||
}
|
||||
|
||||
response := func() error {
|
||||
defer timer.SetTimeout(0)
|
||||
for {
|
||||
b, err := connReader.ReadMessage()
|
||||
if err == io.EOF {
|
||||
@@ -241,7 +259,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string, writer dns_proto.MessageWriter) {
|
||||
func (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string, writer dns_proto.MessageWriter, timer *signal.ActivityTimer) {
|
||||
var ips []net.IP
|
||||
var err error
|
||||
|
||||
@@ -316,16 +334,21 @@ func (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string,
|
||||
if err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "pack message")
|
||||
b.Release()
|
||||
return
|
||||
timer.SetTimeout(0)
|
||||
}
|
||||
b.Resize(0, int32(len(msgBytes)))
|
||||
|
||||
if err := writer.WriteMessage(b); err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "write IP answer")
|
||||
timer.SetTimeout(0)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) rejectNonIPQuery(id uint16, qType dnsmessage.Type, domain string, writer dns_proto.MessageWriter) {
|
||||
func (h *Handler) rejectNonIPQuery(id uint16, qType dnsmessage.Type, domain string, writer dns_proto.MessageWriter) error {
|
||||
domainT := strings.TrimSuffix(domain, ".")
|
||||
if domainT == "" {
|
||||
return errors.New("empty domain name")
|
||||
}
|
||||
b := buf.New()
|
||||
rawBytes := b.Extend(buf.Size)
|
||||
builder := dnsmessage.NewBuilder(rawBytes[:0], dnsmessage.Header{
|
||||
@@ -346,20 +369,22 @@ func (h *Handler) rejectNonIPQuery(id uint16, qType dnsmessage.Type, domain stri
|
||||
if err != nil {
|
||||
errors.LogInfo(context.Background(), "unexpected domain ", domain, " when building reject message: ", err)
|
||||
b.Release()
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
msgBytes, err := builder.Finish()
|
||||
if err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "pack reject message")
|
||||
b.Release()
|
||||
return
|
||||
return err
|
||||
}
|
||||
b.Resize(0, int32(len(msgBytes)))
|
||||
|
||||
if err := writer.WriteMessage(b); err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "write reject answer")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type outboundConn struct {
|
||||
@@ -368,6 +393,7 @@ type outboundConn struct {
|
||||
|
||||
conn net.Conn
|
||||
connReady chan struct{}
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (c *outboundConn) dial() error {
|
||||
@@ -382,12 +408,16 @@ func (c *outboundConn) dial() error {
|
||||
|
||||
func (c *outboundConn) Write(b []byte) (int, error) {
|
||||
c.access.Lock()
|
||||
if c.closed {
|
||||
c.access.Unlock()
|
||||
return 0, errors.New("outbound connection closed")
|
||||
}
|
||||
|
||||
if c.conn == nil {
|
||||
if err := c.dial(); err != nil {
|
||||
c.access.Unlock()
|
||||
errors.LogWarningInner(context.Background(), err, "failed to dial outbound connection")
|
||||
return len(b), nil
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,24 +427,27 @@ func (c *outboundConn) Write(b []byte) (int, error) {
|
||||
}
|
||||
|
||||
func (c *outboundConn) Read(b []byte) (int, error) {
|
||||
var conn net.Conn
|
||||
c.access.Lock()
|
||||
conn = c.conn
|
||||
c.access.Unlock()
|
||||
if c.closed {
|
||||
c.access.Unlock()
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
if conn == nil {
|
||||
if c.conn == nil {
|
||||
c.access.Unlock()
|
||||
_, open := <-c.connReady
|
||||
if !open {
|
||||
return 0, io.EOF
|
||||
}
|
||||
conn = c.conn
|
||||
return c.conn.Read(b)
|
||||
}
|
||||
|
||||
return conn.Read(b)
|
||||
c.access.Unlock()
|
||||
return c.conn.Read(b)
|
||||
}
|
||||
|
||||
func (c *outboundConn) Close() error {
|
||||
c.access.Lock()
|
||||
c.closed = true
|
||||
close(c.connReady)
|
||||
if c.conn != nil {
|
||||
c.conn.Close()
|
||||
|
||||
@@ -2,10 +2,8 @@ package dokodemo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
@@ -14,11 +12,10 @@ import (
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/policy"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
)
|
||||
@@ -91,7 +88,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
|
||||
}
|
||||
}
|
||||
if dest.Port == 0 {
|
||||
dest.Port = net.Port(common.Must2(strconv.Atoi(port)).(int))
|
||||
dest.Port = net.Port(common.Must2(strconv.Atoi(port)))
|
||||
}
|
||||
if d.portMap != nil && d.portMap[port] != "" {
|
||||
h, p, _ := net.SplitHostPort(d.portMap[port])
|
||||
@@ -99,7 +96,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
|
||||
dest.Address = net.ParseAddress(h)
|
||||
}
|
||||
if len(p) > 0 {
|
||||
dest.Port = net.Port(common.Must2(strconv.Atoi(p)).(int))
|
||||
dest.Port = net.Port(common.Must2(strconv.Atoi(p)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,39 +141,11 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
|
||||
})
|
||||
errors.LogInfo(ctx, "received request for ", conn.RemoteAddr())
|
||||
|
||||
plcy := d.policy()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
timer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle)
|
||||
|
||||
if inbound != nil {
|
||||
inbound.Timer = timer
|
||||
}
|
||||
|
||||
ctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer)
|
||||
link, err := dispatcher.Dispatch(ctx, dest)
|
||||
if err != nil {
|
||||
return errors.New("failed to dispatch request").Base(err)
|
||||
}
|
||||
|
||||
requestCount := int32(1)
|
||||
requestDone := func() error {
|
||||
defer func() {
|
||||
if atomic.AddInt32(&requestCount, -1) == 0 {
|
||||
timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
|
||||
}
|
||||
}()
|
||||
|
||||
var reader buf.Reader
|
||||
if dest.Network == net.Network_UDP {
|
||||
reader = buf.NewPacketReader(conn)
|
||||
} else {
|
||||
reader = buf.NewReader(conn)
|
||||
}
|
||||
if err := buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)); err != nil {
|
||||
return errors.New("failed to transport request").Base(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
var reader buf.Reader
|
||||
if dest.Network == net.Network_TCP {
|
||||
reader = buf.NewReader(conn)
|
||||
} else {
|
||||
reader = buf.NewPacketReader(conn)
|
||||
}
|
||||
|
||||
var writer buf.Writer
|
||||
@@ -208,72 +177,17 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
|
||||
return err
|
||||
}
|
||||
writer = NewPacketWriter(pConn, &dest, mark, back)
|
||||
defer func() {
|
||||
runtime.Gosched()
|
||||
common.Interrupt(link.Reader) // maybe duplicated
|
||||
runtime.Gosched()
|
||||
writer.(*PacketWriter).Close() // close fake UDP conns
|
||||
}()
|
||||
/*
|
||||
sockopt := &internet.SocketConfig{
|
||||
Tproxy: internet.SocketConfig_TProxy,
|
||||
}
|
||||
if dest.Address.Family().IsIP() {
|
||||
sockopt.BindAddress = dest.Address.IP()
|
||||
sockopt.BindPort = uint32(dest.Port)
|
||||
}
|
||||
if d.sockopt != nil {
|
||||
sockopt.Mark = d.sockopt.Mark
|
||||
}
|
||||
tConn, err := internet.DialSystem(ctx, net.DestinationFromAddr(conn.RemoteAddr()), sockopt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tConn.Close()
|
||||
|
||||
writer = &buf.SequentialWriter{Writer: tConn}
|
||||
tReader := buf.NewPacketReader(tConn)
|
||||
requestCount++
|
||||
tproxyRequest = func() error {
|
||||
defer func() {
|
||||
if atomic.AddInt32(&requestCount, -1) == 0 {
|
||||
timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
|
||||
}
|
||||
}()
|
||||
if err := buf.Copy(tReader, link.Writer, buf.UpdateActivity(timer)); err != nil {
|
||||
return errors.New("failed to transport request (TPROXY conn)").Base(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
defer writer.(*PacketWriter).Close() // close fake UDP conns
|
||||
}
|
||||
}
|
||||
|
||||
responseDone := func() error {
|
||||
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
|
||||
|
||||
if network == net.Network_UDP && destinationOverridden {
|
||||
buf.Copy(link.Reader, writer) // respect upload's timeout
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil {
|
||||
return errors.New("failed to transport response").Base(err)
|
||||
}
|
||||
return nil
|
||||
if err := dispatcher.DispatchLink(ctx, dest, &transport.Link{
|
||||
Reader: reader,
|
||||
Writer: writer},
|
||||
); err != nil {
|
||||
return errors.New("failed to dispatch request").Base(err)
|
||||
}
|
||||
|
||||
if err := task.Run(ctx,
|
||||
task.OnSuccess(func() error { return task.Run(ctx, requestDone) }, task.Close(link.Writer)),
|
||||
responseDone); err != nil {
|
||||
runtime.Gosched()
|
||||
common.Interrupt(link.Writer)
|
||||
runtime.Gosched()
|
||||
common.Interrupt(link.Reader)
|
||||
return errors.New("connection ends").Base(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil // Unlike Dispatch(), DispatchLink() will not return until the outbound finishes Process()
|
||||
}
|
||||
|
||||
func NewPacketWriter(conn net.PacketConn, d *net.Destination, mark int, back *net.UDPAddr) buf.Writer {
|
||||
|
||||
@@ -1,44 +1 @@
|
||||
package freedom
|
||||
|
||||
var strategy = [][]byte{
|
||||
// name strategy, prefer, fallback
|
||||
{0, 0, 0}, // AsIs none, /, /
|
||||
{1, 0, 0}, // UseIP use, both, none
|
||||
{1, 4, 0}, // UseIPv4 use, 4, none
|
||||
{1, 6, 0}, // UseIPv6 use, 6, none
|
||||
{1, 4, 6}, // UseIPv4v6 use, 4, 6
|
||||
{1, 6, 4}, // UseIPv6v4 use, 6, 4
|
||||
{2, 0, 0}, // ForceIP force, both, none
|
||||
{2, 4, 0}, // ForceIPv4 force, 4, none
|
||||
{2, 6, 0}, // ForceIPv6 force, 6, none
|
||||
{2, 4, 6}, // ForceIPv4v6 force, 4, 6
|
||||
{2, 6, 4}, // ForceIPv6v4 force, 6, 4
|
||||
}
|
||||
|
||||
func (c *Config) hasStrategy() bool {
|
||||
return strategy[c.DomainStrategy][0] != 0
|
||||
}
|
||||
|
||||
func (c *Config) forceIP() bool {
|
||||
return strategy[c.DomainStrategy][0] == 2
|
||||
}
|
||||
|
||||
func (c *Config) preferIP4() bool {
|
||||
return strategy[c.DomainStrategy][1] == 4 || strategy[c.DomainStrategy][1] == 0
|
||||
}
|
||||
|
||||
func (c *Config) preferIP6() bool {
|
||||
return strategy[c.DomainStrategy][1] == 6 || strategy[c.DomainStrategy][1] == 0
|
||||
}
|
||||
|
||||
func (c *Config) hasFallback() bool {
|
||||
return strategy[c.DomainStrategy][2] != 0
|
||||
}
|
||||
|
||||
func (c *Config) fallbackIP4() bool {
|
||||
return strategy[c.DomainStrategy][2] == 4
|
||||
}
|
||||
|
||||
func (c *Config) fallbackIP6() bool {
|
||||
return strategy[c.DomainStrategy][2] == 6
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ package freedom
|
||||
|
||||
import (
|
||||
protocol "github.com/xtls/xray-core/common/protocol"
|
||||
internet "github.com/xtls/xray-core/transport/internet"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -21,79 +22,6 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Config_DomainStrategy int32
|
||||
|
||||
const (
|
||||
Config_AS_IS Config_DomainStrategy = 0
|
||||
Config_USE_IP Config_DomainStrategy = 1
|
||||
Config_USE_IP4 Config_DomainStrategy = 2
|
||||
Config_USE_IP6 Config_DomainStrategy = 3
|
||||
Config_USE_IP46 Config_DomainStrategy = 4
|
||||
Config_USE_IP64 Config_DomainStrategy = 5
|
||||
Config_FORCE_IP Config_DomainStrategy = 6
|
||||
Config_FORCE_IP4 Config_DomainStrategy = 7
|
||||
Config_FORCE_IP6 Config_DomainStrategy = 8
|
||||
Config_FORCE_IP46 Config_DomainStrategy = 9
|
||||
Config_FORCE_IP64 Config_DomainStrategy = 10
|
||||
)
|
||||
|
||||
// Enum value maps for Config_DomainStrategy.
|
||||
var (
|
||||
Config_DomainStrategy_name = map[int32]string{
|
||||
0: "AS_IS",
|
||||
1: "USE_IP",
|
||||
2: "USE_IP4",
|
||||
3: "USE_IP6",
|
||||
4: "USE_IP46",
|
||||
5: "USE_IP64",
|
||||
6: "FORCE_IP",
|
||||
7: "FORCE_IP4",
|
||||
8: "FORCE_IP6",
|
||||
9: "FORCE_IP46",
|
||||
10: "FORCE_IP64",
|
||||
}
|
||||
Config_DomainStrategy_value = map[string]int32{
|
||||
"AS_IS": 0,
|
||||
"USE_IP": 1,
|
||||
"USE_IP4": 2,
|
||||
"USE_IP6": 3,
|
||||
"USE_IP46": 4,
|
||||
"USE_IP64": 5,
|
||||
"FORCE_IP": 6,
|
||||
"FORCE_IP4": 7,
|
||||
"FORCE_IP6": 8,
|
||||
"FORCE_IP46": 9,
|
||||
"FORCE_IP64": 10,
|
||||
}
|
||||
)
|
||||
|
||||
func (x Config_DomainStrategy) Enum() *Config_DomainStrategy {
|
||||
p := new(Config_DomainStrategy)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x Config_DomainStrategy) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (Config_DomainStrategy) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_proxy_freedom_config_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (Config_DomainStrategy) Type() protoreflect.EnumType {
|
||||
return &file_proxy_freedom_config_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x Config_DomainStrategy) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Config_DomainStrategy.Descriptor instead.
|
||||
func (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) {
|
||||
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{3, 0}
|
||||
}
|
||||
|
||||
type DestinationOverride struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -150,6 +78,8 @@ type Fragment struct {
|
||||
LengthMax uint64 `protobuf:"varint,4,opt,name=length_max,json=lengthMax,proto3" json:"length_max,omitempty"`
|
||||
IntervalMin uint64 `protobuf:"varint,5,opt,name=interval_min,json=intervalMin,proto3" json:"interval_min,omitempty"`
|
||||
IntervalMax uint64 `protobuf:"varint,6,opt,name=interval_max,json=intervalMax,proto3" json:"interval_max,omitempty"`
|
||||
MaxSplitMin uint64 `protobuf:"varint,7,opt,name=max_split_min,json=maxSplitMin,proto3" json:"max_split_min,omitempty"`
|
||||
MaxSplitMax uint64 `protobuf:"varint,8,opt,name=max_split_max,json=maxSplitMax,proto3" json:"max_split_max,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Fragment) Reset() {
|
||||
@@ -224,6 +154,20 @@ func (x *Fragment) GetIntervalMax() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Fragment) GetMaxSplitMin() uint64 {
|
||||
if x != nil {
|
||||
return x.MaxSplitMin
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Fragment) GetMaxSplitMax() uint64 {
|
||||
if x != nil {
|
||||
return x.MaxSplitMax
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Noise struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -234,6 +178,7 @@ type Noise struct {
|
||||
DelayMin uint64 `protobuf:"varint,3,opt,name=delay_min,json=delayMin,proto3" json:"delay_min,omitempty"`
|
||||
DelayMax uint64 `protobuf:"varint,4,opt,name=delay_max,json=delayMax,proto3" json:"delay_max,omitempty"`
|
||||
Packet []byte `protobuf:"bytes,5,opt,name=packet,proto3" json:"packet,omitempty"`
|
||||
ApplyTo string `protobuf:"bytes,6,opt,name=apply_to,json=applyTo,proto3" json:"apply_to,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Noise) Reset() {
|
||||
@@ -301,17 +246,24 @@ func (x *Noise) GetPacket() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Noise) GetApplyTo() string {
|
||||
if x != nil {
|
||||
return x.ApplyTo
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
DomainStrategy Config_DomainStrategy `protobuf:"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.proxy.freedom.Config_DomainStrategy" json:"domain_strategy,omitempty"`
|
||||
DestinationOverride *DestinationOverride `protobuf:"bytes,3,opt,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
|
||||
UserLevel uint32 `protobuf:"varint,4,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
|
||||
Fragment *Fragment `protobuf:"bytes,5,opt,name=fragment,proto3" json:"fragment,omitempty"`
|
||||
ProxyProtocol uint32 `protobuf:"varint,6,opt,name=proxy_protocol,json=proxyProtocol,proto3" json:"proxy_protocol,omitempty"`
|
||||
Noises []*Noise `protobuf:"bytes,7,rep,name=noises,proto3" json:"noises,omitempty"`
|
||||
DomainStrategy internet.DomainStrategy `protobuf:"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"`
|
||||
DestinationOverride *DestinationOverride `protobuf:"bytes,3,opt,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
|
||||
UserLevel uint32 `protobuf:"varint,4,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
|
||||
Fragment *Fragment `protobuf:"bytes,5,opt,name=fragment,proto3" json:"fragment,omitempty"`
|
||||
ProxyProtocol uint32 `protobuf:"varint,6,opt,name=proxy_protocol,json=proxyProtocol,proto3" json:"proxy_protocol,omitempty"`
|
||||
Noises []*Noise `protobuf:"bytes,7,rep,name=noises,proto3" json:"noises,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
@@ -344,11 +296,11 @@ func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *Config) GetDomainStrategy() Config_DomainStrategy {
|
||||
func (x *Config) GetDomainStrategy() internet.DomainStrategy {
|
||||
if x != nil {
|
||||
return x.DomainStrategy
|
||||
}
|
||||
return Config_AS_IS
|
||||
return internet.DomainStrategy(0)
|
||||
}
|
||||
|
||||
func (x *Config) GetDestinationOverride() *DestinationOverride {
|
||||
@@ -394,75 +346,72 @@ var file_proxy_freedom_config_proto_rawDesc = []byte{
|
||||
0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d,
|
||||
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
|
||||
0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x22, 0x53, 0x0a, 0x13, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65,
|
||||
0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
|
||||
0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
||||
0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0xd0, 0x01, 0x0a, 0x08, 0x46, 0x72, 0x61,
|
||||
0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73,
|
||||
0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x70, 0x61, 0x63,
|
||||
0x6b, 0x65, 0x74, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x63, 0x6b,
|
||||
0x65, 0x74, 0x73, 0x5f, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x70, 0x61,
|
||||
0x63, 0x6b, 0x65, 0x74, 0x73, 0x54, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74,
|
||||
0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e,
|
||||
0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68,
|
||||
0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67,
|
||||
0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61,
|
||||
0x6c, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x69, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65,
|
||||
0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b,
|
||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x61, 0x78, 0x22, 0x97, 0x01, 0x0a, 0x05,
|
||||
0x4e, 0x6f, 0x69, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f,
|
||||
0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74,
|
||||
0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d,
|
||||
0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68,
|
||||
0x4d, 0x61, 0x78, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x69, 0x6e,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x69, 0x6e,
|
||||
0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20,
|
||||
0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x61, 0x78, 0x12, 0x16, 0x0a,
|
||||
0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70,
|
||||
0x61, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x97, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x12, 0x52, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74,
|
||||
0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61,
|
||||
0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61,
|
||||
0x74, 0x65, 0x67, 0x79, 0x12, 0x5a, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
|
||||
0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x13, 0x64, 0x65, 0x73,
|
||||
0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
|
||||
0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12,
|
||||
0x38, 0x0a, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66,
|
||||
0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52,
|
||||
0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f,
|
||||
0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28,
|
||||
0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
|
||||
0x12, 0x31, 0x0a, 0x06, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72,
|
||||
0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x52, 0x06, 0x6e, 0x6f, 0x69,
|
||||
0x73, 0x65, 0x73, 0x22, 0xa9, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74,
|
||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x49, 0x53, 0x10,
|
||||
0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a,
|
||||
0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53,
|
||||
0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49,
|
||||
0x50, 0x34, 0x36, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36,
|
||||
0x34, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x10,
|
||||
0x06, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x07,
|
||||
0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x08, 0x12,
|
||||
0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10, 0x09, 0x12,
|
||||
0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, 0x10, 0x0a, 0x42,
|
||||
0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 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, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x66, 0x72, 0x65,
|
||||
0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x2e, 0x46, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69,
|
||||
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x22, 0x53, 0x0a, 0x13, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x73,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
|
||||
0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
|
||||
0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x98, 0x02, 0x0a, 0x08, 0x46, 0x72,
|
||||
0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74,
|
||||
0x73, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x70, 0x61,
|
||||
0x63, 0x6b, 0x65, 0x74, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x63,
|
||||
0x6b, 0x65, 0x74, 0x73, 0x5f, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x70,
|
||||
0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x54, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67,
|
||||
0x74, 0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65,
|
||||
0x6e, 0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74,
|
||||
0x68, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e,
|
||||
0x67, 0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76,
|
||||
0x61, 0x6c, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x69, 0x6e,
|
||||
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||
0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x61, 0x78, 0x12, 0x22, 0x0a, 0x0d,
|
||||
0x6d, 0x61, 0x78, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x07, 0x20,
|
||||
0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x4d, 0x69, 0x6e,
|
||||
0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6d, 0x61,
|
||||
0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x70, 0x6c, 0x69,
|
||||
0x74, 0x4d, 0x61, 0x78, 0x22, 0xb2, 0x01, 0x0a, 0x05, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x12, 0x1d,
|
||||
0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a,
|
||||
0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x1b, 0x0a, 0x09,
|
||||
0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||
0x08, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x69, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x6c,
|
||||
0x61, 0x79, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65,
|
||||
0x6c, 0x61, 0x79, 0x4d, 0x61, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x19,
|
||||
0x0a, 0x08, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x5f, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x07, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x22, 0xe9, 0x02, 0x0a, 0x06, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x50, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69,
|
||||
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74,
|
||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74,
|
||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x5a, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x13, 0x64,
|
||||
0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
||||
0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65,
|
||||
0x6c, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||
0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e,
|
||||
0x74, 0x52, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70,
|
||||
0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x06, 0x20,
|
||||
0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,
|
||||
0x6f, 0x6c, 0x12, 0x31, 0x0a, 0x06, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
|
||||
0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x52, 0x06, 0x6e,
|
||||
0x6f, 0x69, 0x73, 0x65, 0x73, 0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 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, 0x70, 0x72, 0x6f,
|
||||
0x78, 0x79, 0x2f, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x46, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -477,22 +426,21 @@ func file_proxy_freedom_config_proto_rawDescGZIP() []byte {
|
||||
return file_proxy_freedom_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_proxy_freedom_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_proxy_freedom_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_proxy_freedom_config_proto_goTypes = []any{
|
||||
(Config_DomainStrategy)(0), // 0: xray.proxy.freedom.Config.DomainStrategy
|
||||
(*DestinationOverride)(nil), // 1: xray.proxy.freedom.DestinationOverride
|
||||
(*Fragment)(nil), // 2: xray.proxy.freedom.Fragment
|
||||
(*Noise)(nil), // 3: xray.proxy.freedom.Noise
|
||||
(*Config)(nil), // 4: xray.proxy.freedom.Config
|
||||
(*protocol.ServerEndpoint)(nil), // 5: xray.common.protocol.ServerEndpoint
|
||||
(*DestinationOverride)(nil), // 0: xray.proxy.freedom.DestinationOverride
|
||||
(*Fragment)(nil), // 1: xray.proxy.freedom.Fragment
|
||||
(*Noise)(nil), // 2: xray.proxy.freedom.Noise
|
||||
(*Config)(nil), // 3: xray.proxy.freedom.Config
|
||||
(*protocol.ServerEndpoint)(nil), // 4: xray.common.protocol.ServerEndpoint
|
||||
(internet.DomainStrategy)(0), // 5: xray.transport.internet.DomainStrategy
|
||||
}
|
||||
var file_proxy_freedom_config_proto_depIdxs = []int32{
|
||||
5, // 0: xray.proxy.freedom.DestinationOverride.server:type_name -> xray.common.protocol.ServerEndpoint
|
||||
0, // 1: xray.proxy.freedom.Config.domain_strategy:type_name -> xray.proxy.freedom.Config.DomainStrategy
|
||||
1, // 2: xray.proxy.freedom.Config.destination_override:type_name -> xray.proxy.freedom.DestinationOverride
|
||||
2, // 3: xray.proxy.freedom.Config.fragment:type_name -> xray.proxy.freedom.Fragment
|
||||
3, // 4: xray.proxy.freedom.Config.noises:type_name -> xray.proxy.freedom.Noise
|
||||
4, // 0: xray.proxy.freedom.DestinationOverride.server:type_name -> xray.common.protocol.ServerEndpoint
|
||||
5, // 1: xray.proxy.freedom.Config.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||
0, // 2: xray.proxy.freedom.Config.destination_override:type_name -> xray.proxy.freedom.DestinationOverride
|
||||
1, // 3: xray.proxy.freedom.Config.fragment:type_name -> xray.proxy.freedom.Fragment
|
||||
2, // 4: xray.proxy.freedom.Config.noises:type_name -> xray.proxy.freedom.Noise
|
||||
5, // [5:5] is the sub-list for method output_type
|
||||
5, // [5:5] is the sub-list for method input_type
|
||||
5, // [5:5] is the sub-list for extension type_name
|
||||
@@ -510,14 +458,13 @@ func file_proxy_freedom_config_proto_init() {
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_proxy_freedom_config_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumEnums: 0,
|
||||
NumMessages: 4,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_proxy_freedom_config_proto_goTypes,
|
||||
DependencyIndexes: file_proxy_freedom_config_proto_depIdxs,
|
||||
EnumInfos: file_proxy_freedom_config_proto_enumTypes,
|
||||
MessageInfos: file_proxy_freedom_config_proto_msgTypes,
|
||||
}.Build()
|
||||
File_proxy_freedom_config_proto = out.File
|
||||
|
||||
@@ -7,6 +7,7 @@ option java_package = "com.xray.proxy.freedom";
|
||||
option java_multiple_files = true;
|
||||
|
||||
import "common/protocol/server_spec.proto";
|
||||
import "transport/internet/config.proto";
|
||||
|
||||
message DestinationOverride {
|
||||
xray.common.protocol.ServerEndpoint server = 1;
|
||||
@@ -19,6 +20,8 @@ message Fragment {
|
||||
uint64 length_max = 4;
|
||||
uint64 interval_min = 5;
|
||||
uint64 interval_max = 6;
|
||||
uint64 max_split_min = 7;
|
||||
uint64 max_split_max = 8;
|
||||
}
|
||||
message Noise {
|
||||
uint64 length_min = 1;
|
||||
@@ -26,23 +29,11 @@ message Noise {
|
||||
uint64 delay_min = 3;
|
||||
uint64 delay_max = 4;
|
||||
bytes packet = 5;
|
||||
string apply_to = 6;
|
||||
}
|
||||
|
||||
message Config {
|
||||
enum DomainStrategy {
|
||||
AS_IS = 0;
|
||||
USE_IP = 1;
|
||||
USE_IP4 = 2;
|
||||
USE_IP6 = 3;
|
||||
USE_IP46 = 4;
|
||||
USE_IP64 = 5;
|
||||
FORCE_IP = 6;
|
||||
FORCE_IP4 = 7;
|
||||
FORCE_IP6 = 8;
|
||||
FORCE_IP46 = 9;
|
||||
FORCE_IP64 = 10;
|
||||
}
|
||||
DomainStrategy domain_strategy = 1;
|
||||
xray.transport.internet.DomainStrategy domain_strategy = 1;
|
||||
DestinationOverride destination_override = 3;
|
||||
uint32 user_level = 4;
|
||||
Fragment fragment = 5;
|
||||
|
||||
@@ -20,14 +20,12 @@ import (
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
"github.com/xtls/xray-core/common/utils"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/policy"
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
)
|
||||
|
||||
var useSplice bool
|
||||
@@ -35,8 +33,8 @@ var useSplice bool
|
||||
func init() {
|
||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||
h := new(Handler)
|
||||
if err := core.RequireFeatures(ctx, func(pm policy.Manager, d dns.Client) error {
|
||||
return h.Init(config.(*Config), pm, d)
|
||||
if err := core.RequireFeatures(ctx, func(pm policy.Manager) error {
|
||||
return h.Init(config.(*Config), pm)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -53,16 +51,13 @@ func init() {
|
||||
// Handler handles Freedom connections.
|
||||
type Handler struct {
|
||||
policyManager policy.Manager
|
||||
dns dns.Client
|
||||
config *Config
|
||||
}
|
||||
|
||||
// Init initializes the Handler with necessary parameters.
|
||||
func (h *Handler) Init(config *Config, pm policy.Manager, d dns.Client) error {
|
||||
func (h *Handler) Init(config *Config, pm policy.Manager) error {
|
||||
h.config = config
|
||||
h.policyManager = pm
|
||||
h.dns = d
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -71,35 +66,13 @@ func (h *Handler) policy() policy.Session {
|
||||
return p
|
||||
}
|
||||
|
||||
func (h *Handler) resolveIP(ctx context.Context, domain string, localAddr net.Address) net.Address {
|
||||
ips, _, err := h.dns.LookupIP(domain, dns.IPOption{
|
||||
IPv4Enable: (localAddr == nil || localAddr.Family().IsIPv4()) && h.config.preferIP4(),
|
||||
IPv6Enable: (localAddr == nil || localAddr.Family().IsIPv6()) && h.config.preferIP6(),
|
||||
})
|
||||
{ // Resolve fallback
|
||||
if (len(ips) == 0 || err != nil) && h.config.hasFallback() && localAddr == nil {
|
||||
ips, _, err = h.dns.LookupIP(domain, dns.IPOption{
|
||||
IPv4Enable: h.config.fallbackIP4(),
|
||||
IPv6Enable: h.config.fallbackIP6(),
|
||||
})
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", domain)
|
||||
}
|
||||
if len(ips) == 0 {
|
||||
return nil
|
||||
}
|
||||
return net.IPAddress(ips[dice.Roll(len(ips))])
|
||||
}
|
||||
|
||||
func isValidAddress(addr *net.IPOrDomain) bool {
|
||||
if addr == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
a := addr.AsAddress()
|
||||
return a != net.AnyIP
|
||||
return a != net.AnyIP && a != net.AnyIPv6
|
||||
}
|
||||
|
||||
// Process implements proxy.Outbound.
|
||||
@@ -114,6 +87,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
|
||||
destination := ob.Target
|
||||
origTargetAddr := ob.OriginalTarget.Address
|
||||
if origTargetAddr == nil {
|
||||
origTargetAddr = ob.Target.Address
|
||||
}
|
||||
dialer.SetOutboundGateway(ctx, ob)
|
||||
outGateway := ob.Gateway
|
||||
UDPOverride := net.UDPDestination(nil, 0)
|
||||
if h.config.DestinationOverride != nil {
|
||||
server := h.config.DestinationOverride.Server
|
||||
@@ -133,17 +112,24 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
var conn stat.Connection
|
||||
err := retry.ExponentialBackoff(5, 100).On(func() error {
|
||||
dialDest := destination
|
||||
if h.config.hasStrategy() && dialDest.Address.Family().IsDomain() {
|
||||
ip := h.resolveIP(ctx, dialDest.Address.Domain(), dialer.Address())
|
||||
if ip != nil {
|
||||
if h.config.DomainStrategy.HasStrategy() && dialDest.Address.Family().IsDomain() {
|
||||
strategy := h.config.DomainStrategy
|
||||
if destination.Network == net.Network_UDP && origTargetAddr != nil && outGateway == nil {
|
||||
strategy = strategy.GetDynamicStrategy(origTargetAddr.Family())
|
||||
}
|
||||
ips, err := internet.LookupForIP(dialDest.Address.Domain(), strategy, outGateway)
|
||||
if err != nil {
|
||||
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
|
||||
if h.config.DomainStrategy.ForceIP() {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
dialDest = net.Destination{
|
||||
Network: dialDest.Network,
|
||||
Address: ip,
|
||||
Address: net.IPAddress(ips[dice.Roll(len(ips))]),
|
||||
Port: dialDest.Port,
|
||||
}
|
||||
errors.LogInfo(ctx, "dialing to ", dialDest)
|
||||
} else if h.config.forceIP() {
|
||||
return dns.ErrEmptyResponse
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +180,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
if destination.Network == net.Network_TCP {
|
||||
if h.config.Fragment != nil {
|
||||
errors.LogDebug(ctx, "FRAGMENT", h.config.Fragment.PacketsFrom, h.config.Fragment.PacketsTo, h.config.Fragment.LengthMin, h.config.Fragment.LengthMax,
|
||||
h.config.Fragment.IntervalMin, h.config.Fragment.IntervalMax)
|
||||
h.config.Fragment.IntervalMin, h.config.Fragment.IntervalMax, h.config.Fragment.MaxSplitMin, h.config.Fragment.MaxSplitMax)
|
||||
writer = buf.NewWriter(&FragmentWriter{
|
||||
fragment: h.config.Fragment,
|
||||
writer: conn,
|
||||
@@ -203,7 +189,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
writer = buf.NewWriter(conn)
|
||||
}
|
||||
} else {
|
||||
writer = NewPacketWriter(conn, h, ctx, UDPOverride, destination)
|
||||
writer = NewPacketWriter(conn, h, UDPOverride, destination)
|
||||
if h.config.Noises != nil {
|
||||
errors.LogDebug(ctx, "NOISE", h.config.Noises)
|
||||
writer = &NoisePacketWriter{
|
||||
@@ -211,6 +197,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
noises: h.config.Noises,
|
||||
firstWrite: true,
|
||||
UDPOverride: UDPOverride,
|
||||
remoteAddr: net.DestinationFromAddr(conn.RemoteAddr()).Address,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,16 +211,14 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
|
||||
responseDone := func() error {
|
||||
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
|
||||
if destination.Network == net.Network_TCP {
|
||||
if destination.Network == net.Network_TCP && useSplice && proxy.IsRAWTransportWithoutSecurity(conn) { // it would be tls conn in special use case of MITM, we need to let link handle traffic
|
||||
var writeConn net.Conn
|
||||
var inTimer *signal.ActivityTimer
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil && useSplice {
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil {
|
||||
writeConn = inbound.Conn
|
||||
inTimer = inbound.Timer
|
||||
}
|
||||
if !isTLSConn(conn) { // it would be tls conn in special use case of MITM, we need to let link handle traffic
|
||||
return proxy.CopyRawConnIfExist(ctx, conn, writeConn, link.Writer, timer, inTimer)
|
||||
}
|
||||
return proxy.CopyRawConnIfExist(ctx, conn, writeConn, link.Writer, timer, inTimer)
|
||||
}
|
||||
var reader buf.Reader
|
||||
if destination.Network == net.Network_TCP {
|
||||
@@ -258,22 +243,6 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
return nil
|
||||
}
|
||||
|
||||
func isTLSConn(conn stat.Connection) bool {
|
||||
if conn != nil {
|
||||
statConn, ok := conn.(*stat.CounterConnection)
|
||||
if ok {
|
||||
conn = statConn.Connection
|
||||
}
|
||||
if _, ok := conn.(*tls.Conn); ok {
|
||||
return true
|
||||
}
|
||||
if _, ok := conn.(*tls.UConn); ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.Destination) buf.Reader {
|
||||
iConn := conn
|
||||
statConn, ok := iConn.(*stat.CounterConnection)
|
||||
@@ -289,14 +258,13 @@ func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.De
|
||||
if UDPOverride.Address != nil || UDPOverride.Port != 0 {
|
||||
isOverridden = true
|
||||
}
|
||||
changedAddress, _, _ := net.SplitHostPort(conn.RemoteAddr().String())
|
||||
|
||||
return &PacketReader{
|
||||
PacketConnWrapper: c,
|
||||
Counter: counter,
|
||||
IsOverridden: isOverridden,
|
||||
InitUnchangedAddr: DialDest.Address,
|
||||
InitChangedAddr: net.ParseAddress(changedAddress),
|
||||
InitChangedAddr: net.DestinationFromAddr(conn.RemoteAddr()).Address,
|
||||
}
|
||||
}
|
||||
return &buf.PacketReader{Reader: conn}
|
||||
@@ -339,7 +307,7 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
||||
}
|
||||
|
||||
// DialDest means the dial target used in the dialer when creating conn
|
||||
func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride net.Destination, DialDest net.Destination) buf.Writer {
|
||||
func NewPacketWriter(conn net.Conn, h *Handler, UDPOverride net.Destination, DialDest net.Destination) buf.Writer {
|
||||
iConn := conn
|
||||
statConn, ok := iConn.(*stat.CounterConnection)
|
||||
if ok {
|
||||
@@ -354,16 +322,15 @@ func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride
|
||||
// check this behavior and add it to map
|
||||
resolvedUDPAddr := utils.NewTypedSyncMap[string, net.Address]()
|
||||
if DialDest.Address.Family().IsDomain() {
|
||||
RemoteAddress, _, _ := net.SplitHostPort(conn.RemoteAddr().String())
|
||||
resolvedUDPAddr.Store(DialDest.Address.String(), net.ParseAddress(RemoteAddress))
|
||||
resolvedUDPAddr.Store(DialDest.Address.Domain(), net.DestinationFromAddr(conn.RemoteAddr()).Address)
|
||||
}
|
||||
return &PacketWriter{
|
||||
PacketConnWrapper: c,
|
||||
Counter: counter,
|
||||
Handler: h,
|
||||
Context: ctx,
|
||||
UDPOverride: UDPOverride,
|
||||
resolvedUDPAddr: resolvedUDPAddr,
|
||||
ResolvedUDPAddr: resolvedUDPAddr,
|
||||
LocalAddr: net.DestinationFromAddr(conn.LocalAddr()).Address,
|
||||
}
|
||||
|
||||
}
|
||||
@@ -374,14 +341,14 @@ type PacketWriter struct {
|
||||
*internet.PacketConnWrapper
|
||||
stats.Counter
|
||||
*Handler
|
||||
context.Context
|
||||
UDPOverride net.Destination
|
||||
|
||||
// Dest of udp packets might be a domain, we will resolve them to IP
|
||||
// But resolver will return a random one if the domain has many IPs
|
||||
// Resulting in these packets being sent to many different IPs randomly
|
||||
// So, cache and keep the resolve result
|
||||
resolvedUDPAddr *utils.TypedSyncMap[string, net.Address]
|
||||
ResolvedUDPAddr *utils.TypedSyncMap[string, net.Address]
|
||||
LocalAddr net.Address
|
||||
}
|
||||
|
||||
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
@@ -401,20 +368,22 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
b.UDP.Port = w.UDPOverride.Port
|
||||
}
|
||||
if b.UDP.Address.Family().IsDomain() {
|
||||
if ip, ok := w.resolvedUDPAddr.Load(b.UDP.Address.Domain()); ok {
|
||||
if ip, ok := w.ResolvedUDPAddr.Load(b.UDP.Address.Domain()); ok {
|
||||
b.UDP.Address = ip
|
||||
} else {
|
||||
ShouldUseSystemResolver := true
|
||||
if w.Handler.config.hasStrategy() {
|
||||
ip = w.Handler.resolveIP(w.Context, b.UDP.Address.Domain(), nil)
|
||||
if ip != nil {
|
||||
if w.Handler.config.DomainStrategy.HasStrategy() {
|
||||
ips, err := internet.LookupForIP(b.UDP.Address.Domain(), w.Handler.config.DomainStrategy, w.LocalAddr)
|
||||
if err != nil {
|
||||
// drop packet if resolve failed when forceIP
|
||||
if w.Handler.config.DomainStrategy.ForceIP() {
|
||||
b.Release()
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
ip = net.IPAddress(ips[dice.Roll(len(ips))])
|
||||
ShouldUseSystemResolver = false
|
||||
}
|
||||
// drop packet if resolve failed when forceIP
|
||||
if ip == nil && w.Handler.config.forceIP() {
|
||||
b.Release()
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ShouldUseSystemResolver {
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", b.UDP.NetAddr())
|
||||
@@ -426,11 +395,11 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
}
|
||||
}
|
||||
if ip != nil {
|
||||
b.UDP.Address, _ = w.resolvedUDPAddr.LoadOrStore(b.UDP.Address.Domain(), ip)
|
||||
b.UDP.Address, _ = w.ResolvedUDPAddr.LoadOrStore(b.UDP.Address.Domain(), ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
destAddr, _ := net.ResolveUDPAddr("udp", b.UDP.NetAddr())
|
||||
destAddr := b.UDP.RawNetAddr()
|
||||
if destAddr == nil {
|
||||
b.Release()
|
||||
continue
|
||||
@@ -456,6 +425,7 @@ type NoisePacketWriter struct {
|
||||
noises []*Noise
|
||||
firstWrite bool
|
||||
UDPOverride net.Destination
|
||||
remoteAddr net.Address
|
||||
}
|
||||
|
||||
// MultiBuffer writer with Noise before first packet
|
||||
@@ -468,8 +438,24 @@ func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
}
|
||||
var noise []byte
|
||||
var err error
|
||||
if w.remoteAddr.Family().IsDomain() {
|
||||
panic("impossible, remoteAddr is always IP")
|
||||
}
|
||||
for _, n := range w.noises {
|
||||
//User input string or base64 encoded string
|
||||
switch n.ApplyTo {
|
||||
case "ipv4":
|
||||
if w.remoteAddr.Family().IsIPv6() {
|
||||
continue
|
||||
}
|
||||
case "ipv6":
|
||||
if w.remoteAddr.Family().IsIPv4() {
|
||||
continue
|
||||
}
|
||||
case "ip":
|
||||
default:
|
||||
panic("unreachable, applyTo is ip/ipv4/ipv6")
|
||||
}
|
||||
//User input string or base64 encoded string or hex string
|
||||
if n.Packet != nil {
|
||||
noise = n.Packet
|
||||
} else {
|
||||
@@ -480,7 +466,10 @@ func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)})
|
||||
err = w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n.DelayMin != 0 || n.DelayMax != 0 {
|
||||
time.Sleep(time.Duration(crypto.RandBetween(int64(n.DelayMin), int64(n.DelayMax))) * time.Millisecond)
|
||||
@@ -509,23 +498,29 @@ func (f *FragmentWriter) Write(b []byte) (int, error) {
|
||||
return f.writer.Write(b)
|
||||
}
|
||||
data := b[5:recordLen]
|
||||
buf := make([]byte, 1024)
|
||||
buff := make([]byte, 2048)
|
||||
var hello []byte
|
||||
maxSplit := crypto.RandBetween(int64(f.fragment.MaxSplitMin), int64(f.fragment.MaxSplitMax))
|
||||
var splitNum int64
|
||||
for from := 0; ; {
|
||||
to := from + int(crypto.RandBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax)))
|
||||
if to > len(data) {
|
||||
splitNum++
|
||||
if to > len(data) || (maxSplit > 0 && splitNum >= maxSplit) {
|
||||
to = len(data)
|
||||
}
|
||||
copy(buf[:3], b)
|
||||
copy(buf[5:], data[from:to])
|
||||
l := to - from
|
||||
if 5+l > len(buff) {
|
||||
buff = make([]byte, 5+l)
|
||||
}
|
||||
copy(buff[:3], b)
|
||||
copy(buff[5:], data[from:to])
|
||||
from = to
|
||||
buf[3] = byte(l >> 8)
|
||||
buf[4] = byte(l)
|
||||
buff[3] = byte(l >> 8)
|
||||
buff[4] = byte(l)
|
||||
if f.fragment.IntervalMax == 0 { // combine fragmented tlshello if interval is 0
|
||||
hello = append(hello, buf[:5+l]...)
|
||||
hello = append(hello, buff[:5+l]...)
|
||||
} else {
|
||||
_, err := f.writer.Write(buf[:5+l])
|
||||
_, err := f.writer.Write(buff[:5+l])
|
||||
time.Sleep(time.Duration(crypto.RandBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -552,17 +547,20 @@ func (f *FragmentWriter) Write(b []byte) (int, error) {
|
||||
if f.fragment.PacketsFrom != 0 && (f.count < f.fragment.PacketsFrom || f.count > f.fragment.PacketsTo) {
|
||||
return f.writer.Write(b)
|
||||
}
|
||||
maxSplit := crypto.RandBetween(int64(f.fragment.MaxSplitMin), int64(f.fragment.MaxSplitMax))
|
||||
var splitNum int64
|
||||
for from := 0; ; {
|
||||
to := from + int(crypto.RandBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax)))
|
||||
if to > len(b) {
|
||||
splitNum++
|
||||
if to > len(b) || (maxSplit > 0 && splitNum >= maxSplit) {
|
||||
to = len(b)
|
||||
}
|
||||
n, err := f.writer.Write(b[from:to])
|
||||
from += n
|
||||
time.Sleep(time.Duration(crypto.RandBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond)
|
||||
if err != nil {
|
||||
return from, err
|
||||
}
|
||||
time.Sleep(time.Duration(crypto.RandBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond)
|
||||
if from >= len(b) {
|
||||
return from, nil
|
||||
}
|
||||
|
||||
@@ -18,11 +18,12 @@ import (
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
http_proto "github.com/xtls/xray-core/common/protocol/http"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/policy"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
)
|
||||
|
||||
@@ -95,6 +96,9 @@ func (s *Server) ProcessWithFirstbyte(ctx context.Context, network net.Network,
|
||||
inbound.User = &protocol.MemoryUser{
|
||||
Level: s.config.UserLevel,
|
||||
}
|
||||
if !proxy.IsRAWTransportWithoutSecurity(conn) {
|
||||
inbound.CanSpliceCopy = 3
|
||||
}
|
||||
var reader *bufio.Reader
|
||||
if len(firstbyte) > 0 {
|
||||
readerWithoutFirstbyte := bufio.NewReaderSize(readerOnly{conn}, buf.Size)
|
||||
@@ -169,62 +173,31 @@ Start:
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Server) handleConnect(ctx context.Context, _ *http.Request, reader *bufio.Reader, conn stat.Connection, dest net.Destination, dispatcher routing.Dispatcher, inbound *session.Inbound) error {
|
||||
func (s *Server) handleConnect(ctx context.Context, _ *http.Request, buffer *bufio.Reader, conn stat.Connection, dest net.Destination, dispatcher routing.Dispatcher, inbound *session.Inbound) error {
|
||||
_, err := conn.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n"))
|
||||
if err != nil {
|
||||
return errors.New("failed to write back OK response").Base(err)
|
||||
}
|
||||
|
||||
plcy := s.policy()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
timer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle)
|
||||
|
||||
if inbound != nil {
|
||||
inbound.Timer = timer
|
||||
}
|
||||
|
||||
ctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer)
|
||||
link, err := dispatcher.Dispatch(ctx, dest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if reader.Buffered() > 0 {
|
||||
payload, err := buf.ReadFrom(io.LimitReader(reader, int64(reader.Buffered())))
|
||||
reader := buf.NewReader(conn)
|
||||
if buffer.Buffered() > 0 {
|
||||
payload, err := buf.ReadFrom(io.LimitReader(buffer, int64(buffer.Buffered())))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := link.Writer.WriteMultiBuffer(payload); err != nil {
|
||||
return err
|
||||
}
|
||||
reader = nil
|
||||
reader = &buf.BufferedReader{Reader: reader, Buffer: payload}
|
||||
buffer = nil
|
||||
}
|
||||
|
||||
requestDone := func() error {
|
||||
defer timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
|
||||
|
||||
return buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer))
|
||||
}
|
||||
|
||||
responseDone := func() error {
|
||||
if inbound.CanSpliceCopy == 2 {
|
||||
inbound.CanSpliceCopy = 1
|
||||
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
|
||||
|
||||
v2writer := buf.NewWriter(conn)
|
||||
if err := buf.Copy(link.Reader, v2writer, buf.UpdateActivity(timer)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
closeWriter := task.OnSuccess(requestDone, task.Close(link.Writer))
|
||||
if err := task.Run(ctx, closeWriter, responseDone); err != nil {
|
||||
common.Interrupt(link.Reader)
|
||||
common.Interrupt(link.Writer)
|
||||
return errors.New("connection ends").Base(err)
|
||||
if err := dispatcher.DispatchLink(ctx, dest, &transport.Link{
|
||||
Reader: reader,
|
||||
Writer: buf.NewWriter(conn)},
|
||||
); err != nil {
|
||||
return errors.New("failed to dispatch request").Base(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
235
proxy/proxy.go
235
proxy/proxy.go
@@ -25,6 +25,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
"github.com/xtls/xray-core/proxy/vless/encryption"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"github.com/xtls/xray-core/transport/internet/reality"
|
||||
@@ -176,63 +177,109 @@ type VisionReader struct {
|
||||
trafficState *TrafficState
|
||||
ctx context.Context
|
||||
isUplink bool
|
||||
conn net.Conn
|
||||
input *bytes.Reader
|
||||
rawInput *bytes.Buffer
|
||||
ob *session.Outbound
|
||||
|
||||
// internal
|
||||
directReadCounter stats.Counter
|
||||
}
|
||||
|
||||
func NewVisionReader(reader buf.Reader, state *TrafficState, isUplink bool, context context.Context) *VisionReader {
|
||||
func NewVisionReader(reader buf.Reader, trafficState *TrafficState, isUplink bool, ctx context.Context, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, ob *session.Outbound) *VisionReader {
|
||||
return &VisionReader{
|
||||
Reader: reader,
|
||||
trafficState: state,
|
||||
ctx: context,
|
||||
trafficState: trafficState,
|
||||
ctx: ctx,
|
||||
isUplink: isUplink,
|
||||
conn: conn,
|
||||
input: input,
|
||||
rawInput: rawInput,
|
||||
ob: ob,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
||||
buffer, err := w.Reader.ReadMultiBuffer()
|
||||
if !buffer.IsEmpty() {
|
||||
var withinPaddingBuffers *bool
|
||||
var remainingContent *int32
|
||||
var remainingPadding *int32
|
||||
var currentCommand *int
|
||||
var switchToDirectCopy *bool
|
||||
if w.isUplink {
|
||||
withinPaddingBuffers = &w.trafficState.Inbound.WithinPaddingBuffers
|
||||
remainingContent = &w.trafficState.Inbound.RemainingContent
|
||||
remainingPadding = &w.trafficState.Inbound.RemainingPadding
|
||||
currentCommand = &w.trafficState.Inbound.CurrentCommand
|
||||
switchToDirectCopy = &w.trafficState.Inbound.UplinkReaderDirectCopy
|
||||
} else {
|
||||
withinPaddingBuffers = &w.trafficState.Outbound.WithinPaddingBuffers
|
||||
remainingContent = &w.trafficState.Outbound.RemainingContent
|
||||
remainingPadding = &w.trafficState.Outbound.RemainingPadding
|
||||
currentCommand = &w.trafficState.Outbound.CurrentCommand
|
||||
switchToDirectCopy = &w.trafficState.Outbound.DownlinkReaderDirectCopy
|
||||
}
|
||||
if buffer.IsEmpty() {
|
||||
return buffer, err
|
||||
}
|
||||
|
||||
if *withinPaddingBuffers || w.trafficState.NumberOfPacketToFilter > 0 {
|
||||
mb2 := make(buf.MultiBuffer, 0, len(buffer))
|
||||
for _, b := range buffer {
|
||||
newbuffer := XtlsUnpadding(b, w.trafficState, w.isUplink, w.ctx)
|
||||
if newbuffer.Len() > 0 {
|
||||
mb2 = append(mb2, newbuffer)
|
||||
}
|
||||
}
|
||||
buffer = mb2
|
||||
if *remainingContent > 0 || *remainingPadding > 0 || *currentCommand == 0 {
|
||||
*withinPaddingBuffers = true
|
||||
} else if *currentCommand == 1 {
|
||||
*withinPaddingBuffers = false
|
||||
} else if *currentCommand == 2 {
|
||||
*withinPaddingBuffers = false
|
||||
*switchToDirectCopy = true
|
||||
} else {
|
||||
errors.LogInfo(w.ctx, "XtlsRead unknown command ", *currentCommand, buffer.Len())
|
||||
var withinPaddingBuffers *bool
|
||||
var remainingContent *int32
|
||||
var remainingPadding *int32
|
||||
var currentCommand *int
|
||||
var switchToDirectCopy *bool
|
||||
if w.isUplink {
|
||||
withinPaddingBuffers = &w.trafficState.Inbound.WithinPaddingBuffers
|
||||
remainingContent = &w.trafficState.Inbound.RemainingContent
|
||||
remainingPadding = &w.trafficState.Inbound.RemainingPadding
|
||||
currentCommand = &w.trafficState.Inbound.CurrentCommand
|
||||
switchToDirectCopy = &w.trafficState.Inbound.UplinkReaderDirectCopy
|
||||
} else {
|
||||
withinPaddingBuffers = &w.trafficState.Outbound.WithinPaddingBuffers
|
||||
remainingContent = &w.trafficState.Outbound.RemainingContent
|
||||
remainingPadding = &w.trafficState.Outbound.RemainingPadding
|
||||
currentCommand = &w.trafficState.Outbound.CurrentCommand
|
||||
switchToDirectCopy = &w.trafficState.Outbound.DownlinkReaderDirectCopy
|
||||
}
|
||||
|
||||
if *switchToDirectCopy {
|
||||
if w.directReadCounter != nil {
|
||||
w.directReadCounter.Add(int64(buffer.Len()))
|
||||
}
|
||||
return buffer, err
|
||||
}
|
||||
|
||||
if *withinPaddingBuffers || w.trafficState.NumberOfPacketToFilter > 0 {
|
||||
mb2 := make(buf.MultiBuffer, 0, len(buffer))
|
||||
for _, b := range buffer {
|
||||
newbuffer := XtlsUnpadding(b, w.trafficState, w.isUplink, w.ctx)
|
||||
if newbuffer.Len() > 0 {
|
||||
mb2 = append(mb2, newbuffer)
|
||||
}
|
||||
}
|
||||
if w.trafficState.NumberOfPacketToFilter > 0 {
|
||||
XtlsFilterTls(buffer, w.trafficState, w.ctx)
|
||||
buffer = mb2
|
||||
if *remainingContent > 0 || *remainingPadding > 0 || *currentCommand == 0 {
|
||||
*withinPaddingBuffers = true
|
||||
} else if *currentCommand == 1 {
|
||||
*withinPaddingBuffers = false
|
||||
} else if *currentCommand == 2 {
|
||||
*withinPaddingBuffers = false
|
||||
*switchToDirectCopy = true
|
||||
} else {
|
||||
errors.LogInfo(w.ctx, "XtlsRead unknown command ", *currentCommand, buffer.Len())
|
||||
}
|
||||
}
|
||||
if w.trafficState.NumberOfPacketToFilter > 0 {
|
||||
XtlsFilterTls(buffer, w.trafficState, w.ctx)
|
||||
}
|
||||
|
||||
if *switchToDirectCopy {
|
||||
// XTLS Vision processes TLS-like conn's input and rawInput
|
||||
if inputBuffer, err := buf.ReadFrom(w.input); err == nil && !inputBuffer.IsEmpty() {
|
||||
buffer, _ = buf.MergeMulti(buffer, inputBuffer)
|
||||
}
|
||||
if rawInputBuffer, err := buf.ReadFrom(w.rawInput); err == nil && !rawInputBuffer.IsEmpty() {
|
||||
buffer, _ = buf.MergeMulti(buffer, rawInputBuffer)
|
||||
}
|
||||
*w.input = bytes.Reader{} // release memory
|
||||
w.input = nil
|
||||
*w.rawInput = bytes.Buffer{} // release memory
|
||||
w.rawInput = nil
|
||||
|
||||
if inbound := session.InboundFromContext(w.ctx); inbound != nil && inbound.Conn != nil {
|
||||
if w.isUplink && inbound.CanSpliceCopy == 2 {
|
||||
inbound.CanSpliceCopy = 1
|
||||
}
|
||||
if !w.isUplink && w.ob != nil && w.ob.CanSpliceCopy == 2 { // ob need to be passed in due to context can have more than one ob
|
||||
w.ob.CanSpliceCopy = 1
|
||||
}
|
||||
}
|
||||
readerConn, readCounter, _ := UnwrapRawConn(w.conn)
|
||||
w.directReadCounter = readCounter
|
||||
w.Reader = buf.NewReader(readerConn)
|
||||
}
|
||||
return buffer, err
|
||||
}
|
||||
|
||||
@@ -240,28 +287,32 @@ func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
||||
// Note Vision probably only make sense as the inner most layer of writer, since it need assess traffic state from origin proxy traffic
|
||||
type VisionWriter struct {
|
||||
buf.Writer
|
||||
trafficState *TrafficState
|
||||
ctx context.Context
|
||||
writeOnceUserUUID []byte
|
||||
isUplink bool
|
||||
trafficState *TrafficState
|
||||
ctx context.Context
|
||||
isUplink bool
|
||||
conn net.Conn
|
||||
ob *session.Outbound
|
||||
|
||||
// internal
|
||||
writeOnceUserUUID []byte
|
||||
directWriteCounter stats.Counter
|
||||
}
|
||||
|
||||
func NewVisionWriter(writer buf.Writer, state *TrafficState, isUplink bool, context context.Context) *VisionWriter {
|
||||
w := make([]byte, len(state.UserUUID))
|
||||
copy(w, state.UserUUID)
|
||||
func NewVisionWriter(writer buf.Writer, trafficState *TrafficState, isUplink bool, ctx context.Context, conn net.Conn, ob *session.Outbound) *VisionWriter {
|
||||
w := make([]byte, len(trafficState.UserUUID))
|
||||
copy(w, trafficState.UserUUID)
|
||||
return &VisionWriter{
|
||||
Writer: writer,
|
||||
trafficState: state,
|
||||
ctx: context,
|
||||
trafficState: trafficState,
|
||||
ctx: ctx,
|
||||
writeOnceUserUUID: w,
|
||||
isUplink: isUplink,
|
||||
conn: conn,
|
||||
ob: ob,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
if w.trafficState.NumberOfPacketToFilter > 0 {
|
||||
XtlsFilterTls(mb, w.trafficState, w.ctx)
|
||||
}
|
||||
var isPadding *bool
|
||||
var switchToDirectCopy *bool
|
||||
if w.isUplink {
|
||||
@@ -271,6 +322,29 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
isPadding = &w.trafficState.Inbound.IsPadding
|
||||
switchToDirectCopy = &w.trafficState.Inbound.DownlinkWriterDirectCopy
|
||||
}
|
||||
|
||||
if *switchToDirectCopy {
|
||||
if inbound := session.InboundFromContext(w.ctx); inbound != nil {
|
||||
if !w.isUplink && inbound.CanSpliceCopy == 2 {
|
||||
inbound.CanSpliceCopy = 1
|
||||
}
|
||||
if w.isUplink && w.ob != nil && w.ob.CanSpliceCopy == 2 {
|
||||
w.ob.CanSpliceCopy = 1
|
||||
}
|
||||
}
|
||||
rawConn, _, writerCounter := UnwrapRawConn(w.conn)
|
||||
w.Writer = buf.NewWriter(rawConn)
|
||||
w.directWriteCounter = writerCounter
|
||||
*switchToDirectCopy = false
|
||||
}
|
||||
if !mb.IsEmpty() && w.directWriteCounter != nil {
|
||||
w.directWriteCounter.Add(int64(mb.Len()))
|
||||
}
|
||||
|
||||
if w.trafficState.NumberOfPacketToFilter > 0 {
|
||||
XtlsFilterTls(mb, w.trafficState, w.ctx)
|
||||
}
|
||||
|
||||
if *isPadding {
|
||||
if len(mb) == 1 && mb[0] == nil {
|
||||
mb[0] = XtlsPadding(nil, CommandPaddingContinue, &w.writeOnceUserUUID, true, w.ctx) // we do a long padding to hide vless header
|
||||
@@ -524,24 +598,33 @@ func XtlsFilterTls(buffer buf.MultiBuffer, trafficState *TrafficState, ctx conte
|
||||
}
|
||||
}
|
||||
|
||||
// UnwrapRawConn support unwrap stats, tls, utls, reality, proxyproto, uds-wrapper conn and get raw tcp/uds conn from it
|
||||
// UnwrapRawConn support unwrap encryption, stats, tls, utls, reality, proxyproto, uds-wrapper conn and get raw tcp/uds conn from it
|
||||
func UnwrapRawConn(conn net.Conn) (net.Conn, stats.Counter, stats.Counter) {
|
||||
var readCounter, writerCounter stats.Counter
|
||||
if conn != nil {
|
||||
statConn, ok := conn.(*stat.CounterConnection)
|
||||
if ok {
|
||||
isEncryption := false
|
||||
if commonConn, ok := conn.(*encryption.CommonConn); ok {
|
||||
conn = commonConn.Conn
|
||||
isEncryption = true
|
||||
}
|
||||
if xorConn, ok := conn.(*encryption.XorConn); ok {
|
||||
return xorConn, nil, nil // full-random xorConn should not be penetrated
|
||||
}
|
||||
if statConn, ok := conn.(*stat.CounterConnection); ok {
|
||||
conn = statConn.Connection
|
||||
readCounter = statConn.ReadCounter
|
||||
writerCounter = statConn.WriteCounter
|
||||
}
|
||||
if xc, ok := conn.(*tls.Conn); ok {
|
||||
conn = xc.NetConn()
|
||||
} else if utlsConn, ok := conn.(*tls.UConn); ok {
|
||||
conn = utlsConn.NetConn()
|
||||
} else if realityConn, ok := conn.(*reality.Conn); ok {
|
||||
conn = realityConn.NetConn()
|
||||
} else if realityUConn, ok := conn.(*reality.UConn); ok {
|
||||
conn = realityUConn.NetConn()
|
||||
if !isEncryption { // avoids double penetration
|
||||
if xc, ok := conn.(*tls.Conn); ok {
|
||||
conn = xc.NetConn()
|
||||
} else if utlsConn, ok := conn.(*tls.UConn); ok {
|
||||
conn = utlsConn.NetConn()
|
||||
} else if realityConn, ok := conn.(*reality.Conn); ok {
|
||||
conn = realityConn.NetConn()
|
||||
} else if realityUConn, ok := conn.(*reality.UConn); ok {
|
||||
conn = realityUConn.NetConn()
|
||||
}
|
||||
}
|
||||
if pc, ok := conn.(*proxyproto.Conn); ok {
|
||||
conn = pc.Raw()
|
||||
@@ -595,10 +678,10 @@ func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net
|
||||
errors.LogInfo(ctx, "CopyRawConn splice")
|
||||
statWriter, _ := writer.(*dispatcher.SizeStatWriter)
|
||||
//runtime.Gosched() // necessary
|
||||
time.Sleep(time.Millisecond) // without this, there will be a rare ssl error for freedom splice
|
||||
timer.SetTimeout(8 * time.Hour) // prevent leak, just in case
|
||||
time.Sleep(time.Millisecond) // without this, there will be a rare ssl error for freedom splice
|
||||
timer.SetTimeout(24 * time.Hour) // prevent leak, just in case
|
||||
if inTimer != nil {
|
||||
inTimer.SetTimeout(8 * time.Hour)
|
||||
inTimer.SetTimeout(24 * time.Hour)
|
||||
}
|
||||
w, err := tc.ReadFrom(readerConn)
|
||||
if readCounter != nil {
|
||||
@@ -626,15 +709,29 @@ func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if errors.Cause(err) == io.EOF {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readV(ctx context.Context, reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, readCounter stats.Counter) error {
|
||||
errors.LogInfo(ctx, "CopyRawConn readv")
|
||||
errors.LogInfo(ctx, "CopyRawConn (maybe) readv")
|
||||
if err := buf.Copy(reader, writer, buf.UpdateActivity(timer), buf.AddToStatCounter(readCounter)); err != nil {
|
||||
return errors.New("failed to process response").Base(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsRAWTransportWithoutSecurity(conn stat.Connection) bool {
|
||||
iConn := conn
|
||||
if statConn, ok := iConn.(*stat.CounterConnection); ok {
|
||||
iConn = statConn.Connection
|
||||
}
|
||||
_, ok1 := iConn.(*proxyproto.Conn)
|
||||
_, ok2 := iConn.(*net.TCPConn)
|
||||
_, ok3 := iConn.(*internet.UnixConnWrapper)
|
||||
return ok1 || ok2 || ok3
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package shadowsocks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
@@ -58,11 +57,7 @@ func (a *MemoryAccount) CheckIV(iv []byte) error {
|
||||
}
|
||||
|
||||
func createAesGcm(key []byte) cipher.AEAD {
|
||||
block, err := aes.NewCipher(key)
|
||||
common.Must(err)
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
common.Must(err)
|
||||
return gcm
|
||||
return crypto.NewAesGcm(key)
|
||||
}
|
||||
|
||||
func createChaCha20Poly1305(key []byte) cipher.AEAD {
|
||||
|
||||
@@ -104,12 +104,12 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
|
||||
func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
udpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) {
|
||||
request := protocol.RequestHeaderFromContext(ctx)
|
||||
payload := packet.Payload
|
||||
if request == nil {
|
||||
payload.Release()
|
||||
return
|
||||
}
|
||||
|
||||
payload := packet.Payload
|
||||
|
||||
if payload.UDP != nil {
|
||||
request = &protocol.RequestHeader{
|
||||
User: request.User,
|
||||
@@ -124,9 +124,9 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dis
|
||||
errors.LogWarningInner(ctx, err, "failed to encode UDP packet")
|
||||
return
|
||||
}
|
||||
defer data.Release()
|
||||
|
||||
conn.Write(data.Bytes())
|
||||
data.Release()
|
||||
})
|
||||
defer udpServer.RemoveRay()
|
||||
|
||||
|
||||
@@ -14,12 +14,12 @@ import (
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
udp_proto "github.com/xtls/xray-core/common/protocol/udp"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/policy"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
"github.com/xtls/xray-core/proxy/http"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
"github.com/xtls/xray-core/transport/internet/udp"
|
||||
)
|
||||
@@ -75,6 +75,9 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
|
||||
inbound.User = &protocol.MemoryUser{
|
||||
Level: s.config.UserLevel,
|
||||
}
|
||||
if !proxy.IsRAWTransportWithoutSecurity(conn) {
|
||||
inbound.CanSpliceCopy = 3
|
||||
}
|
||||
|
||||
switch network {
|
||||
case net.Network_TCP:
|
||||
@@ -154,8 +157,16 @@ func (s *Server) processTCP(ctx context.Context, conn stat.Connection, dispatche
|
||||
Reason: "",
|
||||
})
|
||||
}
|
||||
|
||||
return s.transport(ctx, reader, conn, dest, dispatcher, inbound)
|
||||
if inbound.CanSpliceCopy == 2 {
|
||||
inbound.CanSpliceCopy = 1
|
||||
}
|
||||
if err := dispatcher.DispatchLink(ctx, dest, &transport.Link{
|
||||
Reader: reader,
|
||||
Writer: buf.NewWriter(conn)},
|
||||
); err != nil {
|
||||
return errors.New("failed to dispatch request").Base(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if request.Command == protocol.RequestCommandUDP {
|
||||
@@ -174,52 +185,6 @@ func (*Server) handleUDP(c io.Reader) error {
|
||||
return common.Error2(io.Copy(buf.DiscardBytes, c))
|
||||
}
|
||||
|
||||
func (s *Server) transport(ctx context.Context, reader io.Reader, writer io.Writer, dest net.Destination, dispatcher routing.Dispatcher, inbound *session.Inbound) error {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
timer := signal.CancelAfterInactivity(ctx, cancel, s.policy().Timeouts.ConnectionIdle)
|
||||
|
||||
if inbound != nil {
|
||||
inbound.Timer = timer
|
||||
}
|
||||
|
||||
plcy := s.policy()
|
||||
ctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer)
|
||||
link, err := dispatcher.Dispatch(ctx, dest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
requestDone := func() error {
|
||||
defer timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
|
||||
if err := buf.Copy(buf.NewReader(reader), link.Writer, buf.UpdateActivity(timer)); err != nil {
|
||||
return errors.New("failed to transport all TCP request").Base(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
responseDone := func() error {
|
||||
inbound.CanSpliceCopy = 1
|
||||
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
|
||||
|
||||
v2writer := buf.NewWriter(writer)
|
||||
if err := buf.Copy(link.Reader, v2writer, buf.UpdateActivity(timer)); err != nil {
|
||||
return errors.New("failed to transport all TCP response").Base(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
requestDonePost := task.OnSuccess(requestDone, task.Close(link.Writer))
|
||||
if err := task.Run(ctx, requestDonePost, responseDone); err != nil {
|
||||
common.Interrupt(link.Reader)
|
||||
common.Interrupt(link.Writer)
|
||||
return errors.New("connection ends").Base(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
if s.udpFilter != nil && !s.udpFilter.Check(conn.RemoteAddr()) {
|
||||
errors.LogDebug(ctx, "Unauthorized UDP access from ", conn.RemoteAddr().String())
|
||||
@@ -231,6 +196,7 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dis
|
||||
|
||||
request := protocol.RequestHeaderFromContext(ctx)
|
||||
if request == nil {
|
||||
payload.Release()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -249,9 +215,9 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dis
|
||||
errors.LogWarningInner(ctx, err, "failed to write UDP response")
|
||||
return
|
||||
}
|
||||
defer udpMessage.Release()
|
||||
|
||||
conn.Write(udpMessage.Bytes())
|
||||
udpMessage.Release()
|
||||
})
|
||||
defer udpServer.RemoveRay()
|
||||
|
||||
@@ -259,7 +225,6 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dis
|
||||
if inbound != nil && inbound.Source.IsValid() {
|
||||
errors.LogInfo(ctx, "client UDP connection from ", inbound.Source)
|
||||
}
|
||||
inbound.CanSpliceCopy = 1
|
||||
|
||||
var dest *net.Destination
|
||||
|
||||
|
||||
@@ -113,9 +113,11 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
target = b.UDP
|
||||
}
|
||||
if _, err := w.writePacket(b.Bytes(), *target); err != nil {
|
||||
b.Release()
|
||||
buf.ReleaseMulti(mb)
|
||||
return err
|
||||
}
|
||||
b.Release()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
|
||||
sessionPolicy = s.policyManager.ForLevel(user.Level)
|
||||
|
||||
if destination.Network == net.Network_UDP { // handle udp request
|
||||
return s.handleUDPPayload(ctx, &PacketReader{Reader: clientReader}, &PacketWriter{Writer: conn}, dispatcher)
|
||||
return s.handleUDPPayload(ctx, sessionPolicy, &PacketReader{Reader: clientReader}, &PacketWriter{Writer: conn}, dispatcher)
|
||||
}
|
||||
|
||||
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
|
||||
@@ -248,7 +248,11 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
|
||||
return s.handleConnection(ctx, sessionPolicy, destination, clientReader, buf.NewWriter(conn), dispatcher)
|
||||
}
|
||||
|
||||
func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReader, clientWriter *PacketWriter, dispatcher routing.Dispatcher) error {
|
||||
func (s *Server) handleUDPPayload(ctx context.Context, sessionPolicy policy.Session, clientReader *PacketReader, clientWriter *PacketWriter, dispatcher routing.Dispatcher) error {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
|
||||
defer timer.SetTimeout(0)
|
||||
udpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) {
|
||||
udpPayload := packet.Payload
|
||||
if udpPayload.UDP == nil {
|
||||
@@ -257,6 +261,9 @@ func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReade
|
||||
|
||||
if err := clientWriter.WriteMultiBuffer(buf.MultiBuffer{udpPayload}); err != nil {
|
||||
errors.LogWarningInner(ctx, err, "failed to write response")
|
||||
cancel()
|
||||
} else {
|
||||
timer.Update()
|
||||
}
|
||||
})
|
||||
defer udpServer.RemoveRay()
|
||||
@@ -266,47 +273,56 @@ func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReade
|
||||
|
||||
var dest *net.Destination
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
default:
|
||||
mb, err := clientReader.ReadMultiBuffer()
|
||||
if err != nil {
|
||||
if errors.Cause(err) != io.EOF {
|
||||
return errors.New("unexpected EOF").Base(err)
|
||||
}
|
||||
requestDone := func() error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
mb, err := clientReader.ReadMultiBuffer()
|
||||
if err != nil {
|
||||
if errors.Cause(err) != io.EOF {
|
||||
return errors.New("unexpected EOF").Base(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
mb2, b := buf.SplitFirst(mb)
|
||||
if b == nil {
|
||||
continue
|
||||
}
|
||||
destination := *b.UDP
|
||||
mb2, b := buf.SplitFirst(mb)
|
||||
if b == nil {
|
||||
continue
|
||||
}
|
||||
timer.Update()
|
||||
destination := *b.UDP
|
||||
|
||||
currentPacketCtx := ctx
|
||||
if inbound.Source.IsValid() {
|
||||
currentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
|
||||
From: inbound.Source,
|
||||
To: destination,
|
||||
Status: log.AccessAccepted,
|
||||
Reason: "",
|
||||
Email: user.Email,
|
||||
})
|
||||
}
|
||||
errors.LogInfo(ctx, "tunnelling request to ", destination)
|
||||
currentPacketCtx := ctx
|
||||
if inbound.Source.IsValid() {
|
||||
currentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
|
||||
From: inbound.Source,
|
||||
To: destination,
|
||||
Status: log.AccessAccepted,
|
||||
Reason: "",
|
||||
Email: user.Email,
|
||||
})
|
||||
}
|
||||
errors.LogInfo(ctx, "tunnelling request to ", destination)
|
||||
|
||||
if !s.cone || dest == nil {
|
||||
dest = &destination
|
||||
}
|
||||
if !s.cone || dest == nil {
|
||||
dest = &destination
|
||||
}
|
||||
|
||||
udpServer.Dispatch(currentPacketCtx, *dest, b) // first packet
|
||||
for _, payload := range mb2 {
|
||||
udpServer.Dispatch(currentPacketCtx, *dest, payload)
|
||||
udpServer.Dispatch(currentPacketCtx, *dest, b) // first packet
|
||||
for _, payload := range mb2 {
|
||||
udpServer.Dispatch(currentPacketCtx, *dest, payload)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if err := task.Run(ctx, requestDone); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) handleConnection(ctx context.Context, sessionPolicy policy.Session,
|
||||
|
||||
@@ -18,6 +18,10 @@ func (a *Account) AsAccount() (protocol.Account, error) {
|
||||
ID: protocol.NewID(id),
|
||||
Flow: a.Flow, // needs parser here?
|
||||
Encryption: a.Encryption, // needs parser here?
|
||||
XorMode: a.XorMode,
|
||||
Seconds: a.Seconds,
|
||||
Padding: a.Padding,
|
||||
Reverse: a.Reverse,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -27,8 +31,13 @@ type MemoryAccount struct {
|
||||
ID *protocol.ID
|
||||
// Flow of the account. May be "xtls-rprx-vision".
|
||||
Flow string
|
||||
// Encryption of the account. Used for client connections, and only accepts "none" for now.
|
||||
|
||||
Encryption string
|
||||
XorMode uint32
|
||||
Seconds uint32
|
||||
Padding string
|
||||
|
||||
Reverse *Reverse
|
||||
}
|
||||
|
||||
// Equals implements protocol.Account.Equals().
|
||||
@@ -45,5 +54,9 @@ func (a *MemoryAccount) ToProto() proto.Message {
|
||||
Id: a.ID.String(),
|
||||
Flow: a.Flow,
|
||||
Encryption: a.Encryption,
|
||||
XorMode: a.XorMode,
|
||||
Seconds: a.Seconds,
|
||||
Padding: a.Padding,
|
||||
Reverse: a.Reverse,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,51 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Reverse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Reverse) Reset() {
|
||||
*x = Reverse{}
|
||||
mi := &file_proxy_vless_account_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Reverse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Reverse) ProtoMessage() {}
|
||||
|
||||
func (x *Reverse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proxy_vless_account_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Reverse.ProtoReflect.Descriptor instead.
|
||||
func (*Reverse) Descriptor() ([]byte, []int) {
|
||||
return file_proxy_vless_account_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Reverse) GetTag() string {
|
||||
if x != nil {
|
||||
return x.Tag
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -28,14 +73,17 @@ type Account struct {
|
||||
// ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
// Flow settings. May be "xtls-rprx-vision".
|
||||
Flow string `protobuf:"bytes,2,opt,name=flow,proto3" json:"flow,omitempty"`
|
||||
// Encryption settings. Only applies to client side, and only accepts "none" for now.
|
||||
Encryption string `protobuf:"bytes,3,opt,name=encryption,proto3" json:"encryption,omitempty"`
|
||||
Flow string `protobuf:"bytes,2,opt,name=flow,proto3" json:"flow,omitempty"`
|
||||
Encryption string `protobuf:"bytes,3,opt,name=encryption,proto3" json:"encryption,omitempty"`
|
||||
XorMode uint32 `protobuf:"varint,4,opt,name=xorMode,proto3" json:"xorMode,omitempty"`
|
||||
Seconds uint32 `protobuf:"varint,5,opt,name=seconds,proto3" json:"seconds,omitempty"`
|
||||
Padding string `protobuf:"bytes,6,opt,name=padding,proto3" json:"padding,omitempty"`
|
||||
Reverse *Reverse `protobuf:"bytes,7,opt,name=reverse,proto3" json:"reverse,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Account) Reset() {
|
||||
*x = Account{}
|
||||
mi := &file_proxy_vless_account_proto_msgTypes[0]
|
||||
mi := &file_proxy_vless_account_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -47,7 +95,7 @@ func (x *Account) String() string {
|
||||
func (*Account) ProtoMessage() {}
|
||||
|
||||
func (x *Account) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proxy_vless_account_proto_msgTypes[0]
|
||||
mi := &file_proxy_vless_account_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -60,7 +108,7 @@ func (x *Account) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Account.ProtoReflect.Descriptor instead.
|
||||
func (*Account) Descriptor() ([]byte, []int) {
|
||||
return file_proxy_vless_account_proto_rawDescGZIP(), []int{0}
|
||||
return file_proxy_vless_account_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *Account) GetId() string {
|
||||
@@ -84,23 +132,61 @@ func (x *Account) GetEncryption() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Account) GetXorMode() uint32 {
|
||||
if x != nil {
|
||||
return x.XorMode
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Account) GetSeconds() uint32 {
|
||||
if x != nil {
|
||||
return x.Seconds
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Account) GetPadding() string {
|
||||
if x != nil {
|
||||
return x.Padding
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Account) GetReverse() *Reverse {
|
||||
if x != nil {
|
||||
return x.Reverse
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_proxy_vless_account_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_proxy_vless_account_proto_rawDesc = []byte{
|
||||
0x0a, 0x19, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x61, 0x63,
|
||||
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x22, 0x4d, 0x0a,
|
||||
0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x6f, 0x77,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1e, 0x0a, 0x0a,
|
||||
0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x52, 0x0a, 0x14,
|
||||
0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76,
|
||||
0x6c, 0x65, 0x73, 0x73, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72,
|
||||
0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0xaa, 0x02, 0x10,
|
||||
0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x22, 0x1b, 0x0a,
|
||||
0x07, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0xd0, 0x01, 0x0a, 0x07, 0x41,
|
||||
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x6e,
|
||||
0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
|
||||
0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x78, 0x6f,
|
||||
0x72, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x78, 0x6f, 0x72,
|
||||
0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x33, 0x0a, 0x07, 0x72, 0x65, 0x76, 0x65,
|
||||
0x72, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x52, 0x65, 0x76,
|
||||
0x65, 0x72, 0x73, 0x65, 0x52, 0x07, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x42, 0x52, 0x0a,
|
||||
0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
|
||||
0x76, 0x6c, 0x65, 0x73, 0x73, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f,
|
||||
0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0xaa, 0x02,
|
||||
0x10, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73,
|
||||
0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -115,16 +201,18 @@ func file_proxy_vless_account_proto_rawDescGZIP() []byte {
|
||||
return file_proxy_vless_account_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_proxy_vless_account_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_proxy_vless_account_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_proxy_vless_account_proto_goTypes = []any{
|
||||
(*Account)(nil), // 0: xray.proxy.vless.Account
|
||||
(*Reverse)(nil), // 0: xray.proxy.vless.Reverse
|
||||
(*Account)(nil), // 1: xray.proxy.vless.Account
|
||||
}
|
||||
var file_proxy_vless_account_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
0, // 0: xray.proxy.vless.Account.reverse:type_name -> xray.proxy.vless.Reverse
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_proxy_vless_account_proto_init() }
|
||||
@@ -138,7 +226,7 @@ func file_proxy_vless_account_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_proxy_vless_account_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -6,11 +6,20 @@ option go_package = "github.com/xtls/xray-core/proxy/vless";
|
||||
option java_package = "com.xray.proxy.vless";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message Reverse {
|
||||
string tag = 1;
|
||||
}
|
||||
|
||||
message Account {
|
||||
// ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
|
||||
string id = 1;
|
||||
// Flow settings. May be "xtls-rprx-vision".
|
||||
string flow = 2;
|
||||
// Encryption settings. Only applies to client side, and only accepts "none" for now.
|
||||
|
||||
string encryption = 3;
|
||||
uint32 xorMode = 4;
|
||||
uint32 seconds = 5;
|
||||
string padding = 6;
|
||||
|
||||
Reverse reverse = 7;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@ package encoding
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
"github.com/xtls/xray-core/proxy/vless"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -61,15 +63,14 @@ func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {
|
||||
}
|
||||
|
||||
// EncodeBodyAddons returns a Writer that auto-encrypt content written by caller.
|
||||
func EncodeBodyAddons(writer io.Writer, request *protocol.RequestHeader, requestAddons *Addons, state *proxy.TrafficState, isUplink bool, context context.Context) buf.Writer {
|
||||
func EncodeBodyAddons(writer buf.Writer, request *protocol.RequestHeader, requestAddons *Addons, state *proxy.TrafficState, isUplink bool, context context.Context, conn net.Conn, ob *session.Outbound) buf.Writer {
|
||||
if request.Command == protocol.RequestCommandUDP {
|
||||
return NewMultiLengthPacketWriter(writer.(buf.Writer))
|
||||
return NewMultiLengthPacketWriter(writer)
|
||||
}
|
||||
w := buf.NewWriter(writer)
|
||||
if requestAddons.Flow == vless.XRV {
|
||||
w = proxy.NewVisionWriter(w, state, isUplink, context)
|
||||
return proxy.NewVisionWriter(writer, state, isUplink, context, conn, ob)
|
||||
}
|
||||
return w
|
||||
return writer
|
||||
}
|
||||
|
||||
// DecodeBodyAddons returns a Reader from which caller can fetch decrypted body.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user