Compare commits

..

46 Commits

Author SHA1 Message Date
Jim Han
8a647c1d8e Update config.yaml 2021-03-20 18:22:06 +08:00
Jim Han
ea3be76fd5 Add links 2021-03-16 19:25:42 +08:00
秋のかえで
7abb02ab44 Chore: add issues config (#344) 2021-03-07 14:09:59 +08:00
JimhHan
18574aca47 Fix: grammar
Co-Authored-By: R3pl4c3r <30682790+R3pl4c3r@users.noreply.github.com>
2021-03-07 12:56:52 +08:00
JimhHan
769bed9dbc Update issue templates
Co-Authored-By: 惜别 <realsekibetu@gmail.com>
Co-Authored-By: R3pl4c3r <30682790+R3pl4c3r@users.noreply.github.com>
2021-03-07 12:51:54 +08:00
JimhHan
1233bd5031 Chore: issue templates
Co-Authored-By: 惜别 <realsekibetu@gmail.com>
2021-03-06 22:01:06 +08:00
JimhHan
039c8e63e7 Add: Issue templates 2021-03-06 21:06:58 +08:00
Jim Han
29db059a87 Create: Bug report(zh-CN) template 2021-03-06 16:34:05 +08:00
RPRX
e1a5392beb Use buf.PacketReader when UDPOverride is available 2021-03-06 07:19:09 +00:00
秋のかえで
24f564b401 Chore: Adjust release.yml (#337)
Co-authored-by: Jim Han <50871214+JimhHan@users.noreply.github.com>
Co-authored-by: RPRX <63339210+rprx@users.noreply.github.com>
2021-03-06 14:34:40 +08:00
RPRX
54af48a1ae linux-rppc64le -> linux-ppc64le 2021-03-05 13:36:52 +00:00
RPRX
055fb51ed9 Apply UDPOverride to Freedom Outbound PacketReader 2021-03-05 12:06:37 +00:00
秋のかえで
6380abca73 feat: enforcing VMessAEAD via environment variable (#334) 2021-03-05 08:41:51 +00:00
秋のかえで
1dae2c5636 feat: vmess zero encryption (#333) 2021-03-05 08:41:18 +00:00
RPRX
e9ea658852 1.15 -> 1.16 2021-03-02 15:20:08 +00:00
AkinoKaede
d67cf3d598 v1.3.1 2021-03-02 22:59:27 +08:00
kokeri
ca633fc8c5 Chore: Add GitHub Actions (#251)
Co-authored-by: xinb <netwhilt@outlook.com>
Co-authored-by: 秋のかえで <autmaple@protonmail.com>
Co-authored-by: Jim Han <50871214+JimhHan@users.noreply.github.com>
2021-03-02 22:46:50 +08:00
Xray9
c345d4818e Fix available mux picker in reverse portal (#274) 2021-03-01 07:26:53 +00:00
Jim Han
7fb1f65354 Fix https://github.com/XTLS/Xray-core/issues/289 (#300) 2021-03-01 02:43:27 +00:00
RPRX
4b97edae74 Fix https://github.com/XTLS/Xray-core/issues/320 2021-03-01 01:29:17 +00:00
Kid
8aabbeefe1 Add /opt to assets location (#312) 2021-02-27 23:09:44 +08:00
RPRX
48fab4d398 Add Xray_onekey 2021-02-22 02:21:17 +00:00
RPRX
8b9c0ae593 Enable (X)TLS hot reloading by default (#281)
Super BiuBiu
2021-02-20 02:15:57 +00:00
秋のかえで
347d9735da Remove (x)tls.WithNextProto("h2") in tcp/hub.go (#260) 2021-02-18 11:50:09 +00:00
Jim Han
9aa49be703 Restrict tag to be unique (#258) 2021-02-18 09:53:10 +00:00
RPRX
fed8610d3f Fix Freedom Outbound UDP redirect
已检查 b.UDP 各源头:Mux(VLESS、VMess)、Trojan、Shadowsocks、Socks、TPROXY(Dokodemo-door)
2021-02-17 13:37:55 +00:00
RPRX
d22c2d034c Avoid panic in KDF func for Go 1.16
2a206c7fcc
2021-02-17 03:02:03 +00:00
RPRX
4c10a9eb4e Add Xray-yes 2021-02-15 10:50:30 +00:00
RPRX
4ff1ff1d7d Add Netch (NetFilter & TUN/TAP) 2021-02-15 09:10:19 +00:00
RPRX
573b7807c0 v1.3.0 2021-02-12 15:59:56 +00:00
eMeab
81d993158f Support hot reloading of certificate and key files (#225) 2021-02-12 15:33:19 +00:00
秋のかえで
df39991bb3 Refactor: Add Shadowsocks Validator (#233) 2021-02-12 15:17:31 +00:00
Monsoon
1b87264c53 Support loading config from different formats (#228) 2021-02-12 14:12:58 +00:00
秋のかえで
96d7156eba Fix a typo (#236) 2021-02-12 13:23:30 +00:00
RPRX
d170416219 Add environment variable XRAY_CONE_DISABLED option 2021-02-11 15:37:02 +00:00
RPRX
8ca8a7126b Add XUDP support by simply renaming vudp to xudp
https://t.me/projectXray/243505
2021-02-11 11:33:08 +00:00
RPRX
1174ff3090 Refactor: VLESS & VMess & Mux UDP FullCone NAT
https://t.me/projectXray/242770
2021-02-11 01:28:21 +00:00
RPRX
523c416bb5 v1.2.4 2021-01-31 11:56:39 +00:00
eMeab
c13b8ec9bb Fix OCSP Stapling (#172)
Co-authored-by: RPRX <63339210+rprx@users.noreply.github.com>
2021-01-30 23:17:07 +00:00
Jim Han
4cd343f2d5 Fix tests (#201)
Co-authored-by: RPRX <63339210+rprx@users.noreply.github.com>
2021-01-30 13:01:20 +00:00
RPRX
d032a8deb7 Fix acceptProxyProtocol
https://github.com/XTLS/Xray-core/pull/182#issuecomment-768336178
2021-01-28 12:08:57 +00:00
RPRX
303fd6e261 Standardize Socks Outbound Authentication Behavior 2021-01-28 03:11:17 +00:00
RPRX
c880b916ee Avoid panic in BytesTo func 2021-01-27 01:09:58 +00:00
RPRX
ceff4185dc Improve the request for UDP Associate in Socks5 2021-01-26 23:53:01 +00:00
RPRX
59c7c4897c Add luci-app-xray (openwrt-xray) 2021-01-26 22:50:28 +00:00
RPRX
8ffc430351 Fix VLESS & Trojan fallbacks xver 2021-01-23 21:06:15 +00:00
65 changed files with 1696 additions and 324 deletions

92
.github/ISSUE_TEMPLATE/bug-en.md vendored Normal file
View File

@@ -0,0 +1,92 @@
---
name: Bug Report
about: Create a bug report of Xray.
title: '[Bug] <bug you are reporting>'
labels: ''
assignees: ''
---
<!-- Thanks for your reporting.
1. Please make sure you are submitting a bug of Xray-Core instead of acquiring usage or bug in third-party programs. If you are not sure, please contact us in our official Telegram group.
2. Bug: **An error, flaw or fault in a program ** that causes it to produce an incorrect or unexpected result. (Reference: Wikipedia)
3. Please check existing Issues and Discussions first and read the documentation in detail. Duplicated issues will be closed.
4. Please don't report issue like "I can't use a feature". It's probably your own mistake.
5. You should fully complete the following contents or this issue may not be handled.
6. Please *make sure* the content you are submitting does not contain your private information.
-->
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
**To Reproduce**
<!-- Steps to reproduce the bug: -->
1.
2.
3.
4.
**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
**Client Log**
<details>
```
Please paste your client log here:
```
</details>
**Server Log**
<details>
```
Please paste your server log here:
```
</details>
**Client config**
<details>
```json
Please paste your client config file here:
```
</details>
**Server Config**
<details>
```json
Please paste your server config file here:
```
</details>
**Client Information**
- OS: [e.g. Windows 10]
- Xray version [e.g. 1.3.1]
- Xray installing approach[e.g. Xray-install]
**Server Information**
- OS: [e.g. Windows 10]
- Xray version [e.g. 1.3.1]
- Xray installing approach[e.g. Xray-install]
**Additional Information**
<!-- Add any other information about the problem here. -->

91
.github/ISSUE_TEMPLATE/bug-zh-CN.md vendored Normal file
View File

@@ -0,0 +1,91 @@
---
name: Bug 反馈
about: 这是 Xray 的一个 bug。
title: '[Bug] 你发现的bug'
labels: ''
assignees: ''
---
<!-- 感谢您的反馈!
1. 请先确认您提交的是 Xray-Core 的 Bug而非使用咨询抑或是第三方程序的 Bug。如果您不确定请在 Telegram 群中反馈。
2. Bug软件运行中因为 **程序本身有错误** 而造成的功能不正常。(Reference: Wikipedia)
3. 请先查询已有的 Issues 与 Discussions ,并且详细阅读文档的相关内容。如果您提出的是已知的问题,此 issue 将有可能被关闭。
4. 请不要轻易提出类似“不能使用某功能”的问题。这往往是你自己的问题。
5. 您需要完整地完成下列内容,否则此 issue 可能不会被处理。
6. *务必* 确保不包含任何个人隐私信息。
-->
**问题描述**
<!-- 请清晰简洁地描述此问题。-->
**复现方式**
<!-- 复现此步骤的过程: -->
1.
2.
3.
4.
**预期行为**
<!-- 请清晰简洁地描述您期望的的行为。-->
**客户端日志**
<details>
```
请删除此行,并在此处粘贴客户端日志
```
</details>
**服务端日志**
<details>
```
请删除此行,并在此处粘贴服务端日志
```
</details>
**客户端配置**
<details>
```json
请删除此行,并在此处粘贴客户端配置
```
</details>
**服务端配置**
<details>
```json
请删除此行,并在此处粘贴服务端日志
```
</details>
**客户端环境**
- 系统与版本: [如 Windows 10]
- Xray 版本 [如 1.3.1]
- Xray 安装方式:[如 Xray-install]
**服务端环境**
- 系统与版本: [如 Windows 10]
- Xray 版本 [如 1.3.1]
- Xray 安装方式:[如 Xray-install]
**附加信息**
<!-- 如果您有额外的信息,请在此处说明。-->

9
.github/ISSUE_TEMPLATE/config.yaml vendored Normal file
View File

@@ -0,0 +1,9 @@
contact_links:
- name: 加入 Telegram 群组 / Join Telegram Group
url: https://t.me/projectXray
- name: 官方文档 / Official Document
url: https://xtls.github.io/
- name: 安装脚本 / Installing Script
url: https://github.com/XTLS/Xray-install
- name: 示例配置 / Example Config
url: https://github.com/XTLS/Xray-examples

32
.github/ISSUE_TEMPLATE/feature-en.md vendored Normal file
View File

@@ -0,0 +1,32 @@
---
name: Feature Request
about: Suggest an idea for Xray
title: '[Feature] your idea'
labels: ''
assignees: ''
---
<!-- Thanks for your support!
1. Please confirm that you are submitting a feature request.
2. We do not recommend any inexperienced users to request a new feature.
3. Please check existing Issues and Discussions first and read the documentation in detail. Duplicated issues will be closed
4. To be clear: none of developers is obliged to meet your needs. In particular, features that do not make any sense.
5. You should fully complete the following contents.
-->
**What's your idea**
<!-- A clear and concise description of your idea. -->
**Is it related to an issue?**
<!-- Please specify here if yes. -->
**What's your solution?**
<!-- Describe the solution you'd like. -->
1.
2.
3.
4.
**Is there any additional information?**
<!-- Add any other information here. -->

32
.github/ISSUE_TEMPLATE/feature-zh-CN.md vendored Normal file
View File

@@ -0,0 +1,32 @@
---
name: 功能请求
about: 希望 Xray 添加一个新功能。
title: '[Feature] 你的想法'
labels: ''
assignees: ''
---
<!-- 感谢您的反馈!
1. 请先确认您提交的是功能请求。
2. 我们不建议缺少经验的用户提出功能请求。
3. 请先查询已有的 Issues 与 Discussions ,并且详细阅读文档的相关内容。重复的 issue 将有可能被关闭。
4. 需要向您明确一点:任何开发者均没有义务满足您的需求。特别是不合理或没有意义的功能。
5. 您需要完整地完成下列内容,否则此 issue 可能不会被处理。
-->
**您的想法是什么?**
<!-- 请清晰简洁地描述您预期中的功能。-->
**是否与已知的 issue 相关?**
<!-- 如果是,请在此注明 -->
**您认为应如何实现此功能?**
<!-- 请清晰简洁地描述如何实现此功能。-->
1.
2.
3.
4.
**有没有额外的信息?**
<!-- 如果您有额外的信息,请在此处说明。-->

17
.github/ISSUE_TEMPLATE/question-en.md vendored Normal file
View File

@@ -0,0 +1,17 @@
---
name: Question
about: Question of Xray.
title: ''
labels: ''
assignees: ''
---
<!-- Thanks for your support
1. Issue is **NOT** a proper place to ask a question, otherwise your issue may be closed.
2. Please check existing Issues, Discussions and documentation in detail first. You may find the answers you want before you ask the question.
3. If it is still not resolved, please give feedback in the our official Telegram group or Discussions.
4. Wherever you ask a question, please *make sure* the content does not contain your private information.
5. We highly recommend you to read https://github.com/tvvocold/How-To-Ask-Questions-The-Smart-Way.
-->

View File

@@ -0,0 +1,17 @@
---
name: 使用疑问
about: 使用 Xray 时的疑问。
title: ''
labels: ''
assignees: ''
---
<!-- 感谢您的支持!
1. Issue **不是**用来提问的, 否则将可能会被 close。
2. 请先查询已有的 issue、discussion ,并且详细阅读文档的相关内容。那里可能有您需要的答案。
3. 如果仍未解决,请在官方 Telegram 群中或 Discussion 区反馈。
4. 无论在何处提问,请 *务必确保* 其不包含任何个人隐私信息。
5. 我们强烈推荐您阅读 https://github.com/tvvocold/How-To-Ask-Questions-The-Smart-Way。
-->

33
.github/build/friendly-filenames.json vendored Normal file
View File

@@ -0,0 +1,33 @@
{
"android-arm64": { "friendlyName": "android-arm64-v8a" },
"darwin-amd64": { "friendlyName": "macos-64" },
"darwin-arm64": { "friendlyName": "macos-arm64-v8a" },
"dragonfly-amd64": { "friendlyName": "dragonfly-64" },
"freebsd-386": { "friendlyName": "freebsd-32" },
"freebsd-amd64": { "friendlyName": "freebsd-64" },
"freebsd-arm64": { "friendlyName": "freebsd-arm64-v8a" },
"freebsd-arm7": { "friendlyName": "freebsd-arm32-v7a" },
"linux-386": { "friendlyName": "linux-32" },
"linux-amd64": { "friendlyName": "linux-64" },
"linux-arm5": { "friendlyName": "linux-arm32-v5" },
"linux-arm64": { "friendlyName": "linux-arm64-v8a" },
"linux-arm6": { "friendlyName": "linux-arm32-v6" },
"linux-arm7": { "friendlyName": "linux-arm32-v7a" },
"linux-mips64le": { "friendlyName": "linux-mips64le" },
"linux-mips64": { "friendlyName": "linux-mips64" },
"linux-mipslesoftfloat": { "friendlyName": "linux-mips32le-softfloat" },
"linux-mipsle": { "friendlyName": "linux-mips32le" },
"linux-mipssoftfloat": { "friendlyName": "linux-mips32-softfloat" },
"linux-mips": { "friendlyName": "linux-mips32" },
"linux-ppc64le": { "friendlyName": "linux-ppc64le" },
"linux-ppc64": { "friendlyName": "linux-ppc64" },
"linux-riscv64": { "friendlyName": "linux-riscv64" },
"linux-s390x": { "friendlyName": "linux-s390x" },
"openbsd-386": { "friendlyName": "openbsd-32" },
"openbsd-amd64": { "friendlyName": "openbsd-64" },
"openbsd-arm64": { "friendlyName": "openbsd-arm64-v8a" },
"openbsd-arm7": { "friendlyName": "openbsd-arm32-v7a" },
"windows-386": { "friendlyName": "windows-32" },
"windows-amd64": { "friendlyName": "windows-64" },
"windows-arm7": { "friendlyName": "windows-arm32-v7a" }
}

204
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,204 @@
name: Build and Release
on:
workflow_dispatch:
release:
types: [published]
push:
branches:
- main
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
jobs:
build:
strategy:
matrix:
# Include amd64 on all platforms.
goos: [windows, freebsd, openbsd, linux, dragonfly, darwin]
goarch: [amd64, 386]
exclude:
# Exclude i386 on darwin and dragonfly.
- goarch: 386
goos: dragonfly
- goarch: 386
goos: darwin
include:
# BEIGIN MacOS ARM64
- goos: darwin
goarch: arm64
# END MacOS ARM64
# BEGIN Linux ARM 5 6 7
- goos: linux
goarch: arm
goarm: 7
- goos: linux
goarch: arm
goarm: 6
- goos: linux
goarch: arm
goarm: 5
# END Linux ARM 5 6 7
# BEGIN Android ARM 8
- goos: android
goarch: arm64
# END Android ARM 8
# Windows ARM 7
- goos: windows
goarch: arm
goarm: 7
# BEGIN Other architectures
# BEGIN riscv64 & ARM64
- goos: linux
goarch: arm64
- goos: linux
goarch: riscv64
# END riscv64 & ARM64
# BEGIN MIPS
- goos: linux
goarch: mips64
- goos: linux
goarch: mips64le
- goos: linux
goarch: mipsle
- goos: linux
goarch: mips
# END MIPS
# BEGIN PPC
- goos: linux
goarch: ppc64
- goos: linux
goarch: ppc64le
# END PPC
# BEGIN FreeBSD ARM
- goos: freebsd
goarch: arm64
- goos: freebsd
goarch: arm
goarm: 7
# END FreeBSD ARM
# BEGIN S390X
- goos: linux
goarch: s390x
# END S390X
# END Other architectures
# BEGIN OPENBSD ARM
- goos: openbsd
goarch: arm64
- goos: openbsd
goarch: arm
goarm: 7
# END OPENBSD ARM
fail-fast: false
runs-on: ubuntu-latest
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
GOARM: ${{ matrix.goarm }}
CGO_ENABLED: 0
steps:
- name: Checkout codebase
uses: actions/checkout@v2
- name: Show workflow information
id: get_filename
run: |
export _NAME=$(jq ".[\"$GOOS-$GOARCH$GOARM$GOMIPS\"].friendlyName" -r < .github/build/friendly-filenames.json)
echo "GOOS: $GOOS, GOARCH: $GOARCH, GOARM: $GOARM, GOMIPS: $GOMIPS, RELEASE_NAME: $_NAME"
echo "::set-output name=ASSET_NAME::$_NAME"
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ^1.16
- name: Get project dependencies
run: go mod download
- name: Replace Custom to Commit ID
if: github.event_name != 'release'
run: |
ID=$(git rev-parse --short ${{ github.sha }})
if [ "${{ github.event_name }}" == 'pull_request' ]
then
ID=$(git rev-parse --short ${{ github.event.pull_request.head.sha }})
fi
sed -i '/build/ s/Custom/'$ID'/' ./core/core.go
- name: Build Xray
run: |
mkdir -p build_assets
go build -v -o build_assets/xray -trimpath -ldflags "-s -w -buildid=" ./main
- name: Build Mips softfloat Xray
if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle'
run: |
GOMIPS=softfloat go build -v -o build_assets/xray_softfloat -trimpath -ldflags "-s -w -buildid=" ./main
- name: Rename Windows Xray
if: matrix.goos == 'windows'
run: |
cd ./build_assets || exit 1
mv xray xray.exe
- name: Prepare to release
run: |
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite')
for i in "${LIST[@]}"
do
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3}'))
LASTEST_TAG="$(curl -sL "https://api.github.com/repos/v2fly/${INFO[0]}/releases" | jq -r ".[0].tag_name" || echo "latest")"
FILE_NAME="${INFO[2]}.dat"
echo -e "Downloading ${FILE_NAME}..."
curl -L "https://github.com/v2fly/${INFO[0]}/releases/download/${LASTEST_TAG}/${INFO[1]}.dat" -o ./build_assets/${FILE_NAME}
echo -e "Verifying HASH key..."
HASH="$(curl -sL "https://github.com/v2fly/${INFO[0]}/releases/download/${LASTEST_TAG}/${INFO[1]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
[ "$(sha256sum "./build_assets/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ] || { echo -e "The HASH key of ${FILE_NAME} does not match cloud one."; exit 1; }
done
- name: Create ZIP archive
shell: bash
run: |
pushd build_assets || exit 1
touch -mt $(date +%Y01010000) *
zip -9vr ../Xray-$ASSET_NAME.zip .
popd || exit 1
FILE=./Xray-$ASSET_NAME.zip
DGST=$FILE.dgst
for METHOD in {"md5","sha1","sha256","sha512"}
do
openssl dgst -$METHOD $FILE | sed 's/([^)]*)//g' >>$DGST
done
- name: Change the name
run: |
mv build_assets Xray-$ASSET_NAME
- name: Upload files to Artifacts
uses: actions/upload-artifact@v2
with:
name: Xray-${{ steps.get_filename.outputs.ASSET_NAME }}
path: |
./Xray-${{ steps.get_filename.outputs.ASSET_NAME }}/*
- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
if: github.event_name == 'release'
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ./Xray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip*
tag: ${{ github.ref }}
file_glob: true

48
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: Test
on:
push:
branches:
- main
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
steps:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ^1.16
- name: Checkout codebase
uses: actions/checkout@v2
- name: Prepare geo*dat
if: ${{ matrix.os != 'windows-latest' }}
run: |
mkdir resources
wget -O ./resources/geoip.dat https://github.com/v2fly/geoip/releases/latest/download/geoip.dat
wget -O ./resources/geosite.dat https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat
- name: Prepare geo*dat for Windows
if: ${{ matrix.os == 'windows-latest' }}
run: |
mkdir resources
Invoke-WebRequest -Uri "https://github.com/v2fly/geoip/releases/latest/download/geoip.dat" -OutFile "./resources/geoip.dat"
Invoke-WebRequest -Uri "https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat" -OutFile "./resources/geosite.dat"
- name: Test
run: go test -timeout 1h -v ./...

View File

@@ -17,6 +17,8 @@
- One Click
- [ProxySU](https://github.com/proxysu/ProxySU)
- [v2ray-agent](https://github.com/mack-a/v2ray-agent)
- [Xray-yes](https://github.com/jiuqi9997/Xray-yes)
- [Xray_onekey](https://github.com/wulabing/Xray_onekey)
- Magisk
- [Xray4Magisk](https://github.com/CerteKim/Xray4Magisk)
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
@@ -34,9 +36,11 @@
- [PassWall](https://github.com/xiaorouji/openwrt-passwall)
- [Hello World](https://github.com/jerrykuku/luci-app-vssr)
- [ShadowSocksR Plus+](https://github.com/fw876/helloworld)
- [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray))
- Windows
- [v2rayN](https://github.com/2dust/v2rayN)
- [Qv2ray](https://github.com/Qv2ray/Qv2ray)
- [Netch (NetFilter & TUN/TAP)](https://github.com/NetchX/Netch)
- Android
- [v2rayNG](https://github.com/2dust/v2rayNG)
- [Kitsunebi](https://github.com/rurirei/Kitsunebi/tree/release_xtls)

View File

@@ -101,8 +101,8 @@ func (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
rr, _ := dns.NewRR("localhost-b. IN A 127.0.0.4")
ans.Answer = append(ans.Answer, rr)
case q.Name == "Mijia\\ Cloud." && q.Qtype == dns.TypeA:
rr, _ := dns.NewRR("Mijia\\ Cloud. IN A 127.0.0.1")
case q.Name == "mijia\\ cloud." && q.Qtype == dns.TypeA:
rr, _ := dns.NewRR("mijia\\ cloud. IN A 127.0.0.1")
ans.Answer = append(ans.Answer, rr)
}
}

View File

@@ -42,6 +42,9 @@ func (m *Manager) AddHandler(ctx context.Context, handler inbound.Handler) error
tag := handler.Tag()
if len(tag) > 0 {
if _, found := m.taggedHandlers[tag]; found {
return newError("existing tag found: " + tag)
}
m.taggedHandlers[tag] = handler
} else {
m.untaggedHandler = append(m.untaggedHandler, handler)

View File

@@ -109,6 +109,9 @@ func (m *Manager) AddHandler(ctx context.Context, handler outbound.Handler) erro
tag := handler.Tag()
if len(tag) > 0 {
if _, found := m.taggedHandler[tag]; found {
return newError("existing tag found: " + tag)
}
m.taggedHandler[tag] = handler
} else {
m.untaggedHandlers = append(m.untaggedHandlers, handler)

View File

@@ -157,6 +157,9 @@ func (p *StaticMuxPicker) PickAvailable() (*mux.ClientWorker, error) {
if w.draining {
continue
}
if w.client.Closed() {
continue
}
if w.client.ActiveConnections() < minConn {
minConn = w.client.ActiveConnections()
minIdx = i

View File

@@ -18,10 +18,10 @@ func init() {
common.Must(err)
if _, err := os.Stat(platform.GetAssetLocation("geoip.dat")); err != nil && os.IsNotExist(err) {
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "release", "config", "geoip.dat")))
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "resources", "geoip.dat")))
}
if _, err := os.Stat(platform.GetAssetLocation("geosite.dat")); err != nil && os.IsNotExist(err) {
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geosite.dat"), filepath.Join(wd, "..", "..", "release", "config", "geosite.dat")))
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geosite.dat"), filepath.Join(wd, "..", "..", "resources", "geosite.dat")))
}
}

View File

@@ -110,6 +110,9 @@ func (b *Buffer) BytesTo(to int32) []byte {
if to < 0 {
to += b.Len()
}
if to < 0 {
to = 0
}
return b.v[b.start : b.start+to]
}

View File

@@ -330,7 +330,7 @@ func (m *ClientWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.Buffere
return buf.Copy(NewStreamReader(reader), buf.Discard)
}
rr := s.NewReader(reader)
rr := s.NewReader(reader, &meta.Target)
err := buf.Copy(rr, s.output)
if err != nil && buf.IsWriteError(err) {
newError("failed to write to downstream. closing session ", s.ID).Base(err).WriteToLog()

View File

@@ -81,6 +81,9 @@ func (f FrameMetadata) WriteTo(b *buf.Buffer) error {
if err := addrParser.WriteAddressPort(b, f.Target.Address, f.Target.Port); err != nil {
return err
}
} else if b.UDP != nil {
b.WriteByte(byte(TargetNetworkUDP))
addrParser.WriteAddressPort(b, b.UDP.Address, b.UDP.Port)
}
len1 := b.Len()
@@ -119,7 +122,7 @@ func (f *FrameMetadata) UnmarshalFromBuffer(b *buf.Buffer) error {
f.Option = bitmask.Byte(b.Byte(3))
f.Target.Network = net.Network_Unknown
if f.SessionStatus == SessionStatusNew {
if f.SessionStatus == SessionStatusNew || (f.SessionStatus == SessionStatusKeep && b.Len() != 4) {
if b.Len() < 8 {
return newError("insufficient buffer: ", b.Len())
}

View File

@@ -5,6 +5,7 @@ import (
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial"
)
@@ -12,13 +13,15 @@ import (
type PacketReader struct {
reader io.Reader
eof bool
dest *net.Destination
}
// NewPacketReader creates a new PacketReader.
func NewPacketReader(reader io.Reader) *PacketReader {
func NewPacketReader(reader io.Reader, dest *net.Destination) *PacketReader {
return &PacketReader{
reader: reader,
eof: false,
dest: dest,
}
}
@@ -43,6 +46,9 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
return nil, err
}
r.eof = true
if r.dest != nil && r.dest.Network == net.Network_UDP {
b.UDP = r.dest
}
return buf.MultiBuffer{b}, nil
}

View File

@@ -145,7 +145,7 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
return nil
}
rr := s.NewReader(reader)
rr := s.NewReader(reader, &meta.Target)
if err := buf.Copy(rr, s.output); err != nil {
buf.Copy(rr, buf.Discard)
common.Interrupt(s.input)
@@ -168,7 +168,7 @@ func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.Buffere
return buf.Copy(NewStreamReader(reader), buf.Discard)
}
rr := s.NewReader(reader)
rr := s.NewReader(reader, &meta.Target)
err := buf.Copy(rr, s.output)
if err != nil && buf.IsWriteError(err) {

View File

@@ -5,6 +5,7 @@ import (
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
)
@@ -152,9 +153,9 @@ func (s *Session) Close() error {
}
// NewReader creates a buf.Reader based on the transfer type of this Session.
func (s *Session) NewReader(reader *buf.BufferedReader) buf.Reader {
func (s *Session) NewReader(reader *buf.BufferedReader, dest *net.Destination) buf.Reader {
if s.transferType == protocol.TransferTypeStream {
return NewStreamReader(reader)
}
return NewPacketReader(reader)
return NewPacketReader(reader, dest)
}

View File

@@ -63,6 +63,9 @@ func (w *Writer) writeMetaOnly() error {
func writeMetaWithFrame(writer buf.Writer, meta FrameMetadata, data buf.MultiBuffer) error {
frame := buf.New()
if len(data) == 1 {
frame.UDP = data[0].UDP
}
if err := meta.WriteTo(frame); err != nil {
return err
}

View File

@@ -30,6 +30,7 @@ func GetAssetLocation(file string) string {
defPath,
filepath.Join("/usr/local/share/xray/", file),
filepath.Join("/usr/share/xray/", file),
filepath.Join("/opt/share/xray/", file),
} {
if _, err := os.Stat(p); os.IsNotExist(err) {
continue

View File

@@ -55,7 +55,7 @@ func TestAddressReading(t *testing.T) {
},
{
Options: []AddressOption{AddressFamilyByte(0x03, net.AddressFamilyDomain)},
Input: []byte{3, 9, 118, 50, 114, 97, 121, 46, 99, 111, 109, 0, 80},
Input: []byte{3, 11, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109, 0, 80},
Address: net.DomainAddress("example.com"),
Port: net.Port(80),
},
@@ -84,8 +84,9 @@ func TestAddressReading(t *testing.T) {
}
for _, tc := range data {
b := buf.New()
parser := NewAddressParser(tc.Options...)
b := buf.New()
addr, port, err := parser.ReadAddressPort(b, bytes.NewReader(tc.Input))
b.Release()
if tc.Error {

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.14.0
// protoc v3.15.4
// source: common/protocol/headers.proto
package protocol
@@ -34,6 +34,7 @@ const (
SecurityType_AES128_GCM SecurityType = 3
SecurityType_CHACHA20_POLY1305 SecurityType = 4
SecurityType_NONE SecurityType = 5
SecurityType_ZERO SecurityType = 6
)
// Enum value maps for SecurityType.
@@ -45,6 +46,7 @@ var (
3: "AES128_GCM",
4: "CHACHA20_POLY1305",
5: "NONE",
6: "ZERO",
}
SecurityType_value = map[string]int32{
"UNKNOWN": 0,
@@ -53,6 +55,7 @@ var (
"AES128_GCM": 3,
"CHACHA20_POLY1305": 4,
"NONE": 5,
"ZERO": 6,
}
)
@@ -141,19 +144,20 @@ var file_common_protocol_headers_proto_rawDesc = []byte{
0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x63,
0x75, 0x72, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x2a,
0x62, 0x0a, 0x0c, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12,
0x6c, 0x0a, 0x0c, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12,
0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06,
0x4c, 0x45, 0x47, 0x41, 0x43, 0x59, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x55, 0x54, 0x4f,
0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x45, 0x53, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43, 0x4d,
0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x50,
0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e,
0x45, 0x10, 0x05, 0x42, 0x5e, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x50,
0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74,
0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0xaa, 0x02, 0x14, 0x58,
0x72, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x45, 0x10, 0x05, 0x12, 0x08, 0x0a, 0x04, 0x5a, 0x45, 0x52, 0x4f, 0x10, 0x06, 0x42, 0x5e, 0x0a,
0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0xaa, 0x02, 0x14, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x43, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@@ -13,6 +13,7 @@ enum SecurityType {
AES128_GCM = 3;
CHACHA20_POLY1305 = 4;
NONE = 5;
ZERO = 6;
}
message SecurityConfig {

137
common/xudp/xudp.go Normal file
View File

@@ -0,0 +1,137 @@
package xudp
import (
"io"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
)
var addrParser = protocol.NewAddressParser(
protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4),
protocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain),
protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv6), net.AddressFamilyIPv6),
protocol.PortThenAddress(),
)
func NewPacketWriter(writer buf.Writer, dest net.Destination) *PacketWriter {
return &PacketWriter{
Writer: writer,
Dest: dest,
}
}
type PacketWriter struct {
Writer buf.Writer
Dest net.Destination
}
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
defer buf.ReleaseMulti(mb)
mb2Write := make(buf.MultiBuffer, 0, len(mb))
for _, b := range mb {
length := b.Len()
if length == 0 || length+666 > buf.Size {
continue
}
eb := buf.New()
eb.Write([]byte{0, 0, 0, 0})
if w.Dest.Network == net.Network_UDP {
eb.WriteByte(1) // New
eb.WriteByte(1) // Opt
eb.WriteByte(2) // UDP
addrParser.WriteAddressPort(eb, w.Dest.Address, w.Dest.Port)
w.Dest.Network = net.Network_Unknown
} else {
eb.WriteByte(2) // Keep
eb.WriteByte(1)
if b.UDP != nil {
eb.WriteByte(2)
addrParser.WriteAddressPort(eb, b.UDP.Address, b.UDP.Port)
}
}
l := eb.Len() - 2
eb.SetByte(0, byte(l>>8))
eb.SetByte(1, byte(l))
eb.WriteByte(byte(length >> 8))
eb.WriteByte(byte(length))
eb.Write(b.Bytes())
mb2Write = append(mb2Write, eb)
}
if mb2Write.IsEmpty() {
return nil
}
return w.Writer.WriteMultiBuffer(mb2Write)
}
func NewPacketReader(reader io.Reader) *PacketReader {
return &PacketReader{
Reader: reader,
cache: make([]byte, 2),
}
}
type PacketReader struct {
Reader io.Reader
cache []byte
}
func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
for {
if _, err := io.ReadFull(r.Reader, r.cache); err != nil {
return nil, err
}
l := int32(r.cache[0])<<8 | int32(r.cache[1])
if l < 4 {
return nil, io.EOF
}
b := buf.New()
if _, err := b.ReadFullFrom(r.Reader, l); err != nil {
b.Release()
return nil, err
}
discard := false
switch b.Byte(2) {
case 2:
if l != 4 {
b.Advance(5)
addr, port, err := addrParser.ReadAddressPort(nil, b)
if err != nil {
b.Release()
return nil, err
}
b.UDP = &net.Destination{
Network: net.Network_UDP,
Address: addr,
Port: port,
}
}
case 4:
discard = true
default:
b.Release()
return nil, io.EOF
}
if b.Byte(3) == 1 {
if _, err := io.ReadFull(r.Reader, r.cache); err != nil {
b.Release()
return nil, err
}
length := int32(r.cache[0])<<8 | int32(r.cache[1])
if length > 0 {
b.Clear()
if _, err := b.ReadFullFrom(r.Reader, length); err != nil {
b.Release()
return nil, err
}
if !discard {
return buf.MultiBuffer{b}, nil
}
}
}
b.Release()
}
}

View File

@@ -22,9 +22,13 @@ type ConfigFormat struct {
// ConfigLoader is a utility to load Xray config from external source.
type ConfigLoader func(input interface{}) (*Config, error)
// ConfigBuilder is a builder to build core.Config from filenames and formats
type ConfigBuilder func(files []string, formats []string) (*Config, error)
var (
configLoaderByName = make(map[string]*ConfigFormat)
configLoaderByExt = make(map[string]*ConfigFormat)
ConfigBuilderForFiles ConfigBuilder
)
// RegisterConfigLoader add a new ConfigLoader.
@@ -46,6 +50,21 @@ func RegisterConfigLoader(format *ConfigFormat) error {
return nil
}
func GetFormatByExtension(ext string) string {
switch strings.ToLower(ext) {
case "pb", "protobuf":
return "protobuf"
case "yaml", "yml":
return "yaml"
case "toml":
return "toml"
case "json":
return "json"
default:
return ""
}
}
func getExtension(filename string) string {
idx := strings.LastIndexByte(filename, '.')
if idx == -1 {
@@ -54,23 +73,48 @@ func getExtension(filename string) string {
return filename[idx+1:]
}
// LoadConfig loads config with given format from given source.
// input accepts 2 different types:
// * []string slice of multiple filename/url(s) to open to read
// * io.Reader that reads a config content (the original way)
func LoadConfig(formatName string, filename string, input interface{}) (*Config, error) {
ext := getExtension(filename)
if len(ext) > 0 {
if f, found := configLoaderByExt[ext]; found {
return f.Loader(input)
func getFormat(filename string) string {
return GetFormatByExtension(getExtension(filename))
}
func LoadConfig(formatName string, input interface{}) (*Config, error) {
switch v := input.(type) {
case cmdarg.Arg:
formats := make([]string, len(v))
hasProtobuf := false
for i, file := range v {
f := getFormat(file)
if f == "" {
f = formatName
}
if f == "protobuf" {
hasProtobuf = true
}
formats[i] = f
}
// only one protobuf config file is allowed
if hasProtobuf {
if len(v) == 1 {
return configLoaderByName["protobuf"].Loader(v)
} else {
return nil, newError("Only one protobuf config file is allowed").AtWarning()
}
}
// to avoid import cycle
return ConfigBuilderForFiles(v, formats)
case io.Reader:
if f, found := configLoaderByName[formatName]; found {
return f.Loader(input)
return f.Loader(v)
} else {
return nil, newError("Unable to load config in", formatName).AtWarning()
}
}
return nil, newError("Unable to load config in ", formatName).AtWarning()
return nil, newError("Unable to load config").AtWarning()
}
func loadProtobufConfig(data []byte) (*Config, error) {

View File

@@ -18,7 +18,7 @@ import (
)
var (
version = "1.2.3"
version = "1.3.1"
build = "Custom"
codename = "Xray, Penetrates Everything."
intro = "A unified platform for anti-censorship."

View File

@@ -25,7 +25,7 @@ func CreateObject(v *Instance, config interface{}) (interface{}, error) {
//
// xray:api:stable
func StartInstance(configFormat string, configBytes []byte) (*Instance, error) {
config, err := LoadConfig(configFormat, "", bytes.NewReader(configBytes))
config, err := LoadConfig(configFormat, bytes.NewReader(configBytes))
if err != nil {
return nil, err
}

View File

@@ -2,14 +2,10 @@ package core
import (
"context"
"os"
"reflect"
"runtime/debug"
"strings"
"sync"
"github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/features"
@@ -184,30 +180,7 @@ func NewWithContext(ctx context.Context, config *Config) (*Instance, error) {
}
func initInstanceWithConfig(config *Config, server *Instance) (bool, error) {
cone := true
v, t := false, false
for _, outbound := range config.Outbound {
s := strings.ToLower(outbound.ProxySettings.Type)
l := len(s)
if l >= 16 && s[11:16] == "vless" || l >= 16 && s[11:16] == "vmess" {
v = true
continue
}
if l >= 17 && s[11:17] == "trojan" || l >= 22 && s[11:22] == "shadowsocks" {
t = true
var m proxyman.SenderConfig
proto.Unmarshal(outbound.SenderSettings.Value, &m)
if m.MultiplexSettings != nil && m.MultiplexSettings.Enabled {
cone = false
break
}
}
}
if v && !t {
cone = false
}
server.ctx = context.WithValue(server.ctx, "cone", cone)
defer debug.FreeOSMemory()
server.ctx = context.WithValue(server.ctx, "cone", os.Getenv("XRAY_CONE_DISABLED") != "true")
if config.Transport != nil {
features.PrintDeprecatedFeatureWarning("global transport settings")

20
go.mod
View File

@@ -1,26 +1,26 @@
module github.com/xtls/xray-core
go 1.15
go 1.16
require (
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
github.com/golang/mock v1.4.4
github.com/golang/mock v1.5.0
github.com/golang/protobuf v1.4.3
github.com/google/go-cmp v0.5.4
github.com/gorilla/websocket v1.4.2
github.com/lucas-clemente/quic-go v0.19.3
github.com/miekg/dns v1.1.35
github.com/miekg/dns v1.1.40
github.com/pelletier/go-toml v1.8.1
github.com/pires/go-proxyproto v0.4.1
github.com/pires/go-proxyproto v0.4.2
github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c
github.com/stretchr/testify v1.7.0
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499
go.starlark.net v0.0.0-20210121225809-cea917ab6e0f
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4
google.golang.org/grpc v1.35.0
go.starlark.net v0.0.0-20210223155950-e043a3d3c984
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b
google.golang.org/grpc v1.36.0
google.golang.org/protobuf v1.25.0
h12.io/socks v1.0.2
)

45
go.sum
View File

@@ -49,8 +49,9 @@ github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200j
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -69,6 +70,7 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
@@ -107,8 +109,8 @@ github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07Vxb
github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs=
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.40 h1:pyyPFfGMnciYUk/mXpKkVmeMQjfXqt3FAJ2hy7tPiLA=
github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
@@ -127,8 +129,8 @@ github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNC
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pires/go-proxyproto v0.4.1 h1:30QkyOjKU3FcTLiu1359sSQ7ml56wpM4i/uViqODSsI=
github.com/pires/go-proxyproto v0.4.1/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
github.com/pires/go-proxyproto v0.4.2 h1:VRAvsUCTrmiahoU5fqQqkbY0GWcJ1Q0F7b7CkFaipSU=
github.com/pires/go-proxyproto v0.4.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -169,7 +171,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -180,8 +181,8 @@ github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499 h1:QHESTXtfgc1ABV+ArlbPVqU
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499/go.mod h1:5TB2+k58gx4A4g2Nf5miSHNDF6CuAzHKpWBooLAshTs=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.starlark.net v0.0.0-20210121225809-cea917ab6e0f h1:MfDkeyR3bphbh1zJ3Z7cTsZ8Ydd4mXQiBEhcZRltwaM=
go.starlark.net v0.0.0-20210121225809-cea917ab6e0f/go.mod h1:vxxlMsgCAPH7BR2LtxjJC4WhhZhCGd/b01+CIpj8H4k=
go.starlark.net v0.0.0-20210223155950-e043a3d3c984 h1:xwwDQW5We85NaTk2APgoN9202w/l0DVGp+GZMfsrh7s=
go.starlark.net v0.0.0-20210223155950-e043a3d3c984/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -190,14 +191,15 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -212,8 +214,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -225,8 +227,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -242,10 +244,10 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b h1:kHlr0tATeLRMEiZJu5CknOw/E8V6h69sXXQFGoPtjcc=
golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -264,10 +266,13 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
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-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
@@ -292,8 +297,8 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.35.0 h1:TwIQcH3es+MojMVojxxfQ3l3OF2KzlRxML2xZq0kRo8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0 h1:o1bcQ6imQMIOpdrO3SWf2z5RV72WbDwdXuK0MDlc8As=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View File

@@ -21,7 +21,7 @@ func init() {
common.Must(err)
if _, err := os.Stat(platform.GetAssetLocation("geoip.dat")); err != nil && os.IsNotExist(err) {
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "release", "config", "geoip.dat")))
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "resources", "geoip.dat")))
}
geositeFilePath := filepath.Join(wd, "geosite.dat")
@@ -112,6 +112,11 @@ func TestDNSConfigParsing(t *testing.T) {
Domain: "example.com",
ProxiedDomain: "google.com",
},
{
Type: dns.DomainMatchingType_Full,
Domain: "example.com",
Ip: [][]byte{{127, 0, 0, 1}},
},
{
Type: dns.DomainMatchingType_Full,
Domain: "example.com",
@@ -127,11 +132,6 @@ func TestDNSConfigParsing(t *testing.T) {
Domain: ".*\\.com",
Ip: [][]byte{{8, 8, 4, 4}},
},
{
Type: dns.DomainMatchingType_Full,
Domain: "example.com",
Ip: [][]byte{{127, 0, 0, 1}},
},
},
ClientIp: []byte{10, 0, 0, 1},
},

View File

@@ -0,0 +1,44 @@
package serial
import (
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/main/confloader"
"io"
)
func BuildConfig(files []string, formats []string) (*core.Config, error) {
cf := &conf.Config{}
for i, file := range files {
newError("Reading config: ", file).AtInfo().WriteToLog()
r, err := confloader.LoadConfig(file)
if err != nil {
return nil, newError("failed to read config: ", file).Base(err)
}
c, err := ReaderDecoderByFormat[formats[i]](r)
if err != nil {
return nil, newError("failed to decode config: ", file).Base(err)
}
if i == 0 {
*cf = *c
continue
}
cf.Override(c, file)
}
return cf.Build()
}
type readerDecoder func(io.Reader) (*conf.Config, error)
var (
ReaderDecoderByFormat = make(map[string]readerDecoder)
)
func init() {
ReaderDecoderByFormat["json"] = DecodeJSONConfig
ReaderDecoderByFormat["yaml"] = DecodeYAMLConfig
ReaderDecoderByFormat["toml"] = DecodeTOMLConfig
core.ConfigBuilderForFiles = BuildConfig
}

View File

@@ -252,7 +252,8 @@ type TLSCertConfig struct {
KeyFile string `json:"keyFile"`
KeyStr []string `json:"key"`
Usage string `json:"usage"`
OcspStapling int64 `json:"ocspStapling"`
OcspStapling uint64 `json:"ocspStapling"`
OneTimeLoading bool `json:"oneTimeLoading"`
}
// Build implements Buildable.
@@ -264,6 +265,7 @@ func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
return nil, newError("failed to parse certificate").Base(err)
}
certificate.Certificate = cert
certificate.CertificatePath = c.CertFile
if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {
key, err := readFileOrString(c.KeyFile, c.KeyStr)
@@ -271,6 +273,7 @@ func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
return nil, newError("failed to parse key").Base(err)
}
certificate.Key = key
certificate.KeyPath = c.KeyFile
}
switch strings.ToLower(c.Usage) {
@@ -283,7 +286,11 @@ func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
default:
certificate.Usage = tls.Certificate_ENCIPHERMENT
}
if certificate.KeyPath == "" && certificate.CertificatePath == "" {
certificate.OneTimeLoading = true
} else {
certificate.OneTimeLoading = c.OneTimeLoading
}
certificate.OcspStapling = c.OcspStapling
return certificate, nil
@@ -336,18 +343,19 @@ type XTLSCertConfig struct {
KeyFile string `json:"keyFile"`
KeyStr []string `json:"key"`
Usage string `json:"usage"`
OcspStapling int64 `json:"ocspStapling"`
OcspStapling uint64 `json:"ocspStapling"`
OneTimeLoading bool `json:"oneTimeLoading"`
}
// Build implements Buildable.
func (c *XTLSCertConfig) Build() (*xtls.Certificate, error) {
certificate := new(xtls.Certificate)
cert, err := readFileOrString(c.CertFile, c.CertStr)
if err != nil {
return nil, newError("failed to parse certificate").Base(err)
}
certificate.Certificate = cert
certificate.CertificatePath = c.CertFile
if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {
key, err := readFileOrString(c.KeyFile, c.KeyStr)
@@ -355,6 +363,7 @@ func (c *XTLSCertConfig) Build() (*xtls.Certificate, error) {
return nil, newError("failed to parse key").Base(err)
}
certificate.Key = key
certificate.KeyPath = c.KeyFile
}
switch strings.ToLower(c.Usage) {
@@ -367,7 +376,11 @@ func (c *XTLSCertConfig) Build() (*xtls.Certificate, error) {
default:
certificate.Usage = xtls.Certificate_ENCIPHERMENT
}
if certificate.KeyPath == "" && certificate.CertificatePath == "" {
certificate.OneTimeLoading = true
} else {
certificate.OneTimeLoading = c.OneTimeLoading
}
certificate.OcspStapling = c.OcspStapling
return certificate, nil

View File

@@ -32,6 +32,8 @@ func (a *VMessAccount) Build() *vmess.Account {
st = protocol.SecurityType_AUTO
case "none":
st = protocol.SecurityType_NONE
case "zero":
st = protocol.SecurityType_ZERO
default:
st = protocol.SecurityType_AUTO
}

View File

@@ -11,13 +11,11 @@ import (
"regexp"
"runtime"
"runtime/debug"
"strings"
"syscall"
"github.com/xtls/xray-core/common/cmdarg"
"github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/main/commands/base"
)
@@ -83,9 +81,11 @@ func executeRun(cmd *base.Command, args []string) {
}
defer server.Close()
/*
conf.FileCache = nil
conf.IPCache = nil
conf.SiteCache = nil
*/
// Explicitly triggering GC to remove garbage from config loading.
runtime.GC()
@@ -158,30 +158,25 @@ func getConfigFilePath() cmdarg.Arg {
}
func getConfigFormat() string {
switch strings.ToLower(*format) {
case "pb", "protobuf":
return "protobuf"
case "yaml", "yml":
return "yaml"
case "toml":
return "toml"
default:
return "json"
f := core.GetFormatByExtension(*format)
if f == "" {
f = "json"
}
return f
}
func startXray() (core.Server, error) {
configFiles := getConfigFilePath()
config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles)
//config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles)
//config, err := core.LoadConfigs(getConfigFormat(), configFiles)
c, err := core.LoadConfig(getConfigFormat(), configFiles)
if err != nil {
return nil, newError("failed to load config files: [", configFiles.String(), "]").Base(err)
}
server, err := core.New(config)
server, err := core.New(c)
if err != nil {
return nil, newError("failed to create server").Base(err)
}

View File

@@ -97,13 +97,16 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return newError("target not specified.")
}
destination := outbound.Target
UDPOverride := net.UDPDestination(nil, 0)
if h.config.DestinationOverride != nil {
server := h.config.DestinationOverride.Server
if isValidAddress(server.Address) {
destination.Address = server.Address.AsAddress()
UDPOverride.Address = destination.Address
}
if server.Port != 0 {
destination.Port = net.Port(server.Port)
UDPOverride.Port = destination.Port
}
}
newError("opening connection to ", destination).WriteToLog(session.ExportIDToError(ctx))
@@ -149,7 +152,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
if destination.Network == net.Network_TCP {
writer = buf.NewWriter(conn)
} else {
writer = NewPacketWriter(conn, h, ctx)
writer = NewPacketWriter(conn, h, ctx, UDPOverride)
}
if err := buf.Copy(input, writer, buf.UpdateActivity(timer)); err != nil {
@@ -166,7 +169,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
if destination.Network == net.Network_TCP {
reader = buf.NewReader(conn)
} else {
reader = NewPacketReader(conn)
reader = NewPacketReader(conn, UDPOverride)
}
if err := buf.Copy(reader, output, buf.UpdateActivity(timer)); err != nil {
return newError("failed to process response").Base(err)
@@ -182,7 +185,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return nil
}
func NewPacketReader(conn net.Conn) buf.Reader {
func NewPacketReader(conn net.Conn, UDPOverride net.Destination) buf.Reader {
iConn := conn
statConn, ok := iConn.(*internet.StatCouterConnection)
if ok {
@@ -192,7 +195,7 @@ func NewPacketReader(conn net.Conn) buf.Reader {
if statConn != nil {
counter = statConn.ReadCounter
}
if c, ok := iConn.(*internet.PacketConnWrapper); ok {
if c, ok := iConn.(*internet.PacketConnWrapper); ok && UDPOverride.Address == nil && UDPOverride.Port == 0 {
return &PacketReader{
PacketConnWrapper: c,
Counter: counter,
@@ -226,7 +229,7 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
return buf.MultiBuffer{b}, nil
}
func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context) buf.Writer {
func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride net.Destination) buf.Writer {
iConn := conn
statConn, ok := iConn.(*internet.StatCouterConnection)
if ok {
@@ -242,6 +245,7 @@ func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context) buf.Writer
Counter: counter,
Handler: h,
Context: ctx,
UDPOverride: UDPOverride,
}
}
return &buf.SequentialWriter{Writer: conn}
@@ -252,6 +256,7 @@ type PacketWriter struct {
stats.Counter
*Handler
context.Context
UDPOverride net.Destination
}
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
@@ -264,6 +269,12 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
var n int
var err error
if b.UDP != nil {
if w.UDPOverride.Address != nil {
b.UDP.Address = w.UDPOverride.Address
}
if w.UDPOverride.Port != 0 {
b.UDP.Port = w.UDPOverride.Port
}
if w.Handler.config.useIP() && b.UDP.Address.Family().IsDomain() {
ip := w.Handler.resolveIP(w.Context, b.UDP.Address.Domain(), nil)
if ip != nil {

View File

@@ -7,6 +7,8 @@ import (
"crypto/md5"
"crypto/sha1"
"io"
"reflect"
"strconv"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/hkdf"
@@ -31,6 +33,31 @@ func (a *MemoryAccount) Equals(another protocol.Account) bool {
return false
}
func (a *MemoryAccount) GetCipherName() string {
switch a.Cipher.(type) {
case *AesCfb:
keyBytes := a.Cipher.(*AesCfb).KeyBytes
return "AES_" + strconv.FormatInt(int64(keyBytes*8), 10) + "_CFB"
case *ChaCha20:
if a.Cipher.(*ChaCha20).IVBytes == 8 {
return "CHACHA20"
}
return "CHACHA20_IETF"
case *AEADCipher:
switch reflect.ValueOf(a.Cipher.(*AEADCipher).AEADAuthCreator).Pointer() {
case reflect.ValueOf(createAesGcm).Pointer():
keyBytes := a.Cipher.(*AEADCipher).KeyBytes
return "AES_" + strconv.FormatInt(int64(keyBytes*8), 10) + "_GCM"
case reflect.ValueOf(createChacha20Poly1305).Pointer():
return "CHACHA20_POLY1305"
}
case *NoneCipher:
return "NONE"
}
return ""
}
func createAesGcm(key []byte) cipher.AEAD {
block, err := aes.NewCipher(key)
common.Must(err)

View File

@@ -54,12 +54,9 @@ func (r *FullReader) Read(p []byte) (n int, err error) {
}
// ReadTCPSession reads a Shadowsocks TCP session from the given reader, returns its header and remaining parts.
func ReadTCPSession(users []*protocol.MemoryUser, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {
user := users[0]
account := user.Account.(*MemoryAccount)
func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {
hashkdf := hmac.New(sha256.New, []byte("SSBSKDF"))
hashkdf.Write(account.Key)
behaviorSeed := crc32.ChecksumIEEE(hashkdf.Sum(nil))
@@ -71,11 +68,21 @@ func ReadTCPSession(users []*protocol.MemoryUser, reader io.Reader) (*protocol.R
readSizeRemain := DrainSize
var r2 buf.Reader
if len(users) > 1 {
buffer := buf.New()
defer buffer.Release()
var user *protocol.MemoryUser
var ivLen int32
var err error
count := validator.Count()
if count == 0 {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("invalid user")
} else if count > 1 {
var aead cipher.AEAD
if _, err := buffer.ReadFullFrom(reader, 50); err != nil {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
@@ -83,22 +90,9 @@ func ReadTCPSession(users []*protocol.MemoryUser, reader io.Reader) (*protocol.R
}
bs := buffer.Bytes()
user, aead, _, ivLen, err = validator.Get(bs, protocol.RequestCommandTCP)
var aeadCipher *AEADCipher
var ivLen int32
subkey := make([]byte, 32)
length := make([]byte, 16)
var aead cipher.AEAD
var err error
for _, user = range users {
account = user.Account.(*MemoryAccount)
aeadCipher = account.Cipher.(*AEADCipher)
ivLen = aeadCipher.IVSize()
subkey = subkey[:aeadCipher.KeyBytes]
hkdfSHA1(account.Key, bs[:ivLen], subkey)
aead = aeadCipher.AEADAuthCreator(subkey)
_, err = aead.Open(length[:0], length[4:16], bs[ivLen:ivLen+18], nil)
if err == nil {
if user != nil {
reader = &FullReader{reader, bs[ivLen:]}
auth := &crypto.AEADAuthenticator{
AEAD: aead,
@@ -107,21 +101,15 @@ func ReadTCPSession(users []*protocol.MemoryUser, reader io.Reader) (*protocol.R
r2 = crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
Auth: auth,
}, reader, protocol.TransferTypeStream, nil)
break
}
}
if err != nil {
} else {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed to match an user").Base(err)
}
}
buffer := buf.New()
defer buffer.Release()
if r2 == nil {
ivLen := account.Cipher.IVSize()
} else {
user, ivLen = validator.GetOnlyUser()
account := user.Account.(*MemoryAccount)
hashkdf.Write(account.Key)
var iv []byte
if ivLen > 0 {
if _, err := buffer.ReadFullFrom(reader, ivLen); err != nil {
@@ -261,40 +249,31 @@ func EncodeUDPPacket(request *protocol.RequestHeader, payload []byte) (*buf.Buff
return buffer, nil
}
func DecodeUDPPacket(users []*protocol.MemoryUser, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) {
var user *protocol.MemoryUser
var account *MemoryAccount
var err error
if len(users) > 1 {
func DecodeUDPPacket(validator *Validator, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) {
bs := payload.Bytes()
if len(bs) <= 32 {
return nil, nil, newError("len(bs) <= 32")
}
var aeadCipher *AEADCipher
var ivLen int32
subkey := make([]byte, 32)
data := make([]byte, 8192)
var aead cipher.AEAD
var user *protocol.MemoryUser
var err error
count := validator.Count()
if count == 0 {
return nil, nil, newError("invalid user")
} else if count > 1 {
var d []byte
for _, user = range users {
account = user.Account.(*MemoryAccount)
aeadCipher = account.Cipher.(*AEADCipher)
ivLen = aeadCipher.IVSize()
subkey = subkey[:aeadCipher.KeyBytes]
hkdfSHA1(account.Key, bs[:ivLen], subkey)
aead = aeadCipher.AEADAuthCreator(subkey)
d, err = aead.Open(data[:0], data[8180:8192], bs[ivLen:], nil)
if err == nil {
user, _, d, _, err = validator.Get(bs, protocol.RequestCommandUDP)
if user != nil {
payload.Clear()
payload.Write(d)
break
}
} else {
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
}
} else {
user = users[0]
account = user.Account.(*MemoryAccount)
user, _ = validator.GetOnlyUser()
account := user.Account.(*MemoryAccount)
var iv []byte
if !account.Cipher.IsAEAD() && account.Cipher.IVSize() > 0 {
@@ -302,13 +281,10 @@ func DecodeUDPPacket(users []*protocol.MemoryUser, payload *buf.Buffer) (*protoc
iv = make([]byte, account.Cipher.IVSize())
copy(iv, payload.BytesTo(account.Cipher.IVSize()))
}
err = account.Cipher.DecodePacket(account.Key, payload)
}
if err != nil {
if err = account.Cipher.DecodePacket(account.Key, payload); err != nil {
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
}
}
request := &protocol.RequestHeader{
Version: Version,
@@ -341,7 +317,10 @@ func (v *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
buffer.Release()
return nil, err
}
u, payload, err := DecodeUDPPacket([]*protocol.MemoryUser{v.User}, buffer)
validator := new(Validator)
validator.Add(v.User)
u, payload, err := DecodeUDPPacket(validator, buffer)
if err != nil {
buffer.Release()
return nil, err

View File

@@ -38,14 +38,16 @@ func TestUDPEncoding(t *testing.T) {
encodedData, err := EncodeUDPPacket(request, data.Bytes())
common.Must(err)
decodedRequest, decodedData, err := DecodeUDPPacket([]*protocol.MemoryUser{request.User}, encodedData)
validator := new(Validator)
validator.Add(request.User)
decodedRequest, decodedData, err := DecodeUDPPacket(validator, encodedData)
common.Must(err)
if r := cmp.Diff(decodedData.Bytes(), data.Bytes()); r != "" {
t.Error("data: ", r)
}
if r := cmp.Diff(decodedRequest, request); r != "" {
if r := cmp.Diff(decodedRequest, request, cmp.Comparer(func(a1, a2 protocol.Account) bool { return a1.Equals(a2) })); r != "" {
t.Error("request: ", r)
}
}
@@ -117,9 +119,11 @@ func TestTCPRequest(t *testing.T) {
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{data}))
decodedRequest, reader, err := ReadTCPSession([]*protocol.MemoryUser{request.User}, cache)
validator := new(Validator)
validator.Add(request.User)
decodedRequest, reader, err := ReadTCPSession(validator, cache)
common.Must(err)
if r := cmp.Diff(decodedRequest, request); r != "" {
if r := cmp.Diff(decodedRequest, request, cmp.Comparer(func(a1, a2 protocol.Account) bool { return a1.Equals(a2) })); r != "" {
t.Error("request: ", r)
}

View File

@@ -22,33 +22,44 @@ import (
type Server struct {
config *ServerConfig
users []*protocol.MemoryUser
validator *Validator
policyManager policy.Manager
cone bool
}
// NewServer create a new Shadowsocks server.
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
if config.Users == nil {
return nil, newError("empty users")
validator := new(Validator)
for _, user := range config.Users {
u, err := user.ToMemoryUser()
if err != nil {
return nil, newError("failed to get shadowsocks user").Base(err).AtError()
}
if err := validator.Add(u); err != nil {
return nil, newError("failed to add user").Base(err).AtError()
}
}
v := core.MustFromContext(ctx)
s := &Server{
config: config,
validator: validator,
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
cone: ctx.Value("cone").(bool),
}
for _, user := range config.Users {
u, err := user.ToMemoryUser()
if err != nil {
return nil, newError("failed to parse user account").Base(err)
}
s.users = append(s.users, u)
return s, nil
}
return s, nil
// AddUser implements proxy.UserManager.AddUser().
func (s *Server) AddUser(ctx context.Context, u *protocol.MemoryUser) error {
return s.validator.Add(u)
}
// RemoveUser implements proxy.UserManager.RemoveUser().
func (s *Server) RemoveUser(ctx context.Context, e string) error {
return s.validator.Del(e)
}
func (s *Server) Network() []net.Network {
@@ -64,13 +75,13 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
case net.Network_TCP:
return s.handleConnection(ctx, conn, dispatcher)
case net.Network_UDP:
return s.handlerUDPPayload(ctx, conn, dispatcher)
return s.handleUDPPayload(ctx, conn, dispatcher)
default:
return newError("unknown network: ", network)
}
}
func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error {
func (s *Server) handleUDPPayload(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error {
udpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) {
request := protocol.RequestHeaderFromContext(ctx)
if request == nil {
@@ -102,8 +113,9 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
if inbound == nil {
panic("no inbound metadata")
}
if len(s.users) == 1 {
inbound.User = s.users[0]
if s.validator.Count() == 1 {
inbound.User, _ = s.validator.GetOnlyUser()
}
var dest *net.Destination
@@ -121,9 +133,11 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
var err error
if inbound.User != nil {
request, data, err = DecodeUDPPacket([]*protocol.MemoryUser{inbound.User}, payload)
validator := new(Validator)
validator.Add(inbound.User)
request, data, err = DecodeUDPPacket(validator, payload)
} else {
request, data, err = DecodeUDPPacket(s.users, payload)
request, data, err = DecodeUDPPacket(s.validator, payload)
if err == nil {
inbound.User = request.User
}
@@ -178,7 +192,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
}
bufferedReader := buf.BufferedReader{Reader: buf.NewReader(conn)}
request, bodyReader, err := ReadTCPSession(s.users, &bufferedReader)
request, bodyReader, err := ReadTCPSession(s.validator, &bufferedReader)
if err != nil {
log.Record(&log.AccessMessage{
From: conn.RemoteAddr(),

View File

@@ -0,0 +1,113 @@
package shadowsocks
import (
"crypto/cipher"
"strings"
"sync"
"github.com/xtls/xray-core/common/protocol"
)
// Validator stores valid Shadowsocks users.
type Validator struct {
// Considering email's usage here, map + sync.Mutex/RWMutex may have better performance.
email sync.Map
users sync.Map
}
// Add a Shadowsocks user, Email must be empty or unique.
func (v *Validator) Add(u *protocol.MemoryUser) error {
account := u.Account.(*MemoryAccount)
if !account.Cipher.IsAEAD() && v.Count() > 0 {
return newError("The cipher do not support Single-port Multi-user")
}
if u.Email != "" {
_, loaded := v.email.LoadOrStore(strings.ToLower(u.Email), u)
if loaded {
return newError("User ", u.Email, " already exists.")
}
}
v.users.Store(string(account.Key)+"&"+account.GetCipherName(), u)
return nil
}
// Del a Shadowsocks user with a non-empty Email.
func (v *Validator) Del(e string) error {
if e == "" {
return newError("Email must not be empty.")
}
le := strings.ToLower(e)
u, _ := v.email.Load(le)
if u == nil {
return newError("User ", e, " not found.")
}
account := u.(*protocol.MemoryUser).Account.(*MemoryAccount)
v.email.Delete(le)
v.users.Delete(string(account.Key) + "&" + account.GetCipherName())
return nil
}
// Count the number of Shadowsocks users
func (v *Validator) Count() int {
length := 0
v.users.Range(func(_, _ interface{}) bool {
length++
return true
})
return length
}
// Get a Shadowsocks user and the user's cipher.
func (v *Validator) Get(bs []byte, command protocol.RequestCommand) (u *protocol.MemoryUser, aead cipher.AEAD, ret []byte, ivLen int32, err error) {
var dataSize int
switch command {
case protocol.RequestCommandTCP:
dataSize = 16
case protocol.RequestCommandUDP:
dataSize = 8192
}
var aeadCipher *AEADCipher
subkey := make([]byte, 32)
data := make([]byte, dataSize)
v.users.Range(func(key, user interface{}) bool {
account := user.(*protocol.MemoryUser).Account.(*MemoryAccount)
aeadCipher = account.Cipher.(*AEADCipher)
ivLen = aeadCipher.IVSize()
subkey = subkey[:aeadCipher.KeyBytes]
hkdfSHA1(account.Key, bs[:ivLen], subkey)
aead = aeadCipher.AEADAuthCreator(subkey)
switch command {
case protocol.RequestCommandTCP:
ret, err = aead.Open(data[:0], data[4:16], bs[ivLen:ivLen+18], nil)
case protocol.RequestCommandUDP:
ret, err = aead.Open(data[:0], data[8180:8192], bs[ivLen:], nil)
}
if err == nil {
u = user.(*protocol.MemoryUser)
return false
}
return true
})
return
}
// Get the only user without authentication
func (v *Validator) GetOnlyUser() (u *protocol.MemoryUser, ivLen int32) {
v.users.Range(func(_, user interface{}) bool {
u = user.(*protocol.MemoryUser)
return false
})
ivLen = u.Account.(*MemoryAccount).Cipher.IVSize()
return
}

View File

@@ -422,16 +422,6 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
defer b.Release()
common.Must2(b.Write([]byte{socks5Version, 0x01, authByte}))
if authByte == authPassword {
account := request.User.Account.(*Account)
common.Must(b.WriteByte(0x01))
common.Must(b.WriteByte(byte(len(account.Username))))
common.Must2(b.WriteString(account.Username))
common.Must(b.WriteByte(byte(len(account.Password))))
common.Must2(b.WriteString(account.Password))
}
if err := buf.WriteAllBytes(writer, b.Bytes()); err != nil {
return nil, err
}
@@ -449,6 +439,17 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
}
if authByte == authPassword {
b.Clear()
account := request.User.Account.(*Account)
common.Must(b.WriteByte(0x01))
common.Must(b.WriteByte(byte(len(account.Username))))
common.Must2(b.WriteString(account.Username))
common.Must(b.WriteByte(byte(len(account.Password))))
common.Must2(b.WriteString(account.Password))
if err := buf.WriteAllBytes(writer, b.Bytes()); err != nil {
return nil, err
}
b.Clear()
if _, err := b.ReadFullFrom(reader, 2); err != nil {
return nil, err
@@ -465,9 +466,13 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
command = byte(cmdUDPAssociate)
}
common.Must2(b.Write([]byte{socks5Version, command, 0x00 /* reserved */}))
if request.Command == protocol.RequestCommandUDP {
common.Must2(b.Write([]byte{1, 0, 0, 0, 0, 0, 0 /* RFC 1928 */}))
} else {
if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil {
return nil, err
}
}
if err := buf.WriteAllBytes(writer, b.Bytes()); err != nil {
return nil, err

View File

@@ -500,19 +500,16 @@ func (s *Server) fallback(ctx context.Context, sid errors.ExportOption, err erro
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
if fb.Xver != 0 {
var remoteAddr, remotePort, localAddr, localPort string
ipType, network := 0, connection.RemoteAddr().Network()
if len(network) >= 3 && network[:3] == "tcp" {
var err error
remoteAddr, remotePort, err = net.SplitHostPort(connection.RemoteAddr().String())
ipType := 4
remoteAddr, remotePort, err := net.SplitHostPort(connection.RemoteAddr().String())
if err != nil {
return err
ipType = 0
}
localAddr, localPort, err = net.SplitHostPort(connection.LocalAddr().String())
localAddr, localPort, err := net.SplitHostPort(connection.LocalAddr().String())
if err != nil {
return err
ipType = 0
}
ipType = 4
if ipType == 4 {
for i := 0; i < len(remoteAddr); i++ {
if remoteAddr[i] == ':' {
ipType = 6

View File

@@ -335,19 +335,16 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
if fb.Xver != 0 {
var remoteAddr, remotePort, localAddr, localPort string
ipType, network := 0, connection.RemoteAddr().Network()
if len(network) >= 3 && network[:3] == "tcp" {
var err error
remoteAddr, remotePort, err = net.SplitHostPort(connection.RemoteAddr().String())
ipType := 4
remoteAddr, remotePort, err := net.SplitHostPort(connection.RemoteAddr().String())
if err != nil {
return err
ipType = 0
}
localAddr, localPort, err = net.SplitHostPort(connection.LocalAddr().String())
localAddr, localPort, err := net.SplitHostPort(connection.LocalAddr().String())
if err != nil {
return err
ipType = 0
}
ipType = 4
if ipType == 4 {
for i := 0; i < len(remoteAddr); i++ {
if remoteAddr[i] == ':' {
ipType = 6

View File

@@ -16,6 +16,7 @@ import (
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/common/xudp"
core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/stats"
@@ -48,6 +49,7 @@ type Handler struct {
serverList *protocol.ServerList
serverPicker protocol.ServerPicker
policyManager policy.Manager
cone bool
}
// New creates a new VLess outbound handler.
@@ -66,6 +68,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
serverList: serverList,
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
cone: ctx.Value("cone").(bool),
}
return handler, nil
@@ -175,6 +178,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
clientReader := link.Reader // .(*pipe.Reader)
clientWriter := link.Writer // .(*pipe.Writer)
if request.Command == protocol.RequestCommandUDP && h.cone {
request.Command = protocol.RequestCommandMux
request.Address = net.DomainAddress("v1.mux.cool")
request.Port = net.Port(666)
}
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
@@ -185,6 +194,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
// default: serverWriter := bufferWriter
serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons)
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
serverWriter = xudp.NewPacketWriter(serverWriter, target)
}
if err := buf.CopyOnceTimeout(clientReader, serverWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
return err // ...
}
@@ -216,6 +228,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
// default: serverReader := buf.NewReader(conn)
serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons)
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
serverReader = xudp.NewPacketReader(conn)
}
if rawConn != nil {
var counter stats.Counter

View File

@@ -6,11 +6,20 @@ import (
"hash"
)
type hash2 struct {
hash.Hash
}
func KDF(key []byte, path ...string) []byte {
hmacf := hmac.New(sha256.New, []byte(KDFSaltConstVMessAEADKDF))
for _, v := range path {
first := true
hmacf = hmac.New(func() hash.Hash {
if first {
first = false
return hash2{hmacf}
}
return hmacf
}, []byte(v))
}

View File

@@ -118,6 +118,11 @@ func NewServerSession(validator *vmess.TimedUserValidator, sessionHistory *Sessi
}
}
// SetAEADForced sets isAEADForced for a ServerSession.
func (s *ServerSession) SetAEADForced(isAEADForced bool) {
s.isAEADForced = isAEADForced
}
func parseSecurityType(b byte) protocol.SecurityType {
if _, f := protocol.SecurityType_name[int32(b)]; f {
st := protocol.SecurityType(b)

View File

@@ -14,6 +14,7 @@ import (
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
@@ -28,6 +29,10 @@ import (
"github.com/xtls/xray-core/transport/internet"
)
var (
aeadForced = false
)
type userByEmail struct {
sync.Mutex
cache map[string]*protocol.MemoryUser
@@ -231,6 +236,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
reader := &buf.BufferedReader{Reader: buf.NewReader(connection)}
svrSession := encoding.NewServerSession(h.clients, h.sessionHistory)
svrSession.SetAEADForced(aeadForced)
request, err := svrSession.DecodeRequestHeader(reader, isDrain)
if err != nil {
if errors.Cause(err) != io.EOF {
@@ -361,4 +367,9 @@ func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
}))
const defaultFlagValue = "NOT_DEFINED_AT_ALL"
isAeadForced := platform.NewEnvFlag("xray.vmess.aead.forced").GetValue(func() string { return defaultFlagValue })
aeadForced = (isAeadForced == "true")
}

View File

@@ -15,6 +15,7 @@ import (
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/common/xudp"
core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/proxy/vmess"
@@ -28,6 +29,7 @@ type Handler struct {
serverList *protocol.ServerList
serverPicker protocol.ServerPicker
policyManager policy.Manager
cone bool
}
// New creates a new VMess outbound handler.
@@ -46,6 +48,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
serverList: serverList,
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
cone: ctx.Value("cone").(bool),
}
return handler, nil
@@ -108,6 +111,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
request.Option.Set(protocol.RequestOptionGlobalPadding)
}
if request.Security == protocol.SecurityType_ZERO {
request.Security = protocol.SecurityType_NONE
request.Option.Clear(protocol.RequestOptionChunkStream)
request.Option.Clear(protocol.RequestOptionChunkMasking)
}
input := link.Reader
output := link.Writer
@@ -122,6 +131,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
if request.Command == protocol.RequestCommandUDP && h.cone {
request.Command = protocol.RequestCommandMux
request.Address = net.DomainAddress("v1.mux.cool")
request.Port = net.Port(666)
}
requestDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
@@ -131,6 +146,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
}
bodyWriter := session.EncodeRequestBody(request, writer)
bodyWriter2 := bodyWriter
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
bodyWriter = xudp.NewPacketWriter(bodyWriter, target)
}
if err := buf.CopyOnceTimeout(input, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
return newError("failed to write first payload").Base(err)
}
@@ -144,7 +163,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
}
if request.Option.Has(protocol.RequestOptionChunkStream) {
if err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {
if err := bodyWriter2.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {
return err
}
}
@@ -163,6 +182,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
h.handleCommand(rec.Destination(), header.Command)
bodyReader := session.DecodeResponseBody(request, reader)
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
bodyReader = xudp.NewPacketReader(&buf.BufferedReader{Reader: bodyReader})
}
return buf.Copy(bodyReader, output, buf.UpdateActivity(timer))
}

View File

@@ -118,7 +118,7 @@ func genTestBinaryPath() {
}
func GetSourcePath() string {
return filepath.Join("example.com", "core", "main")
return filepath.Join("github.com", "xtls", "xray-core", "main")
}
func CloseAllServers(servers []*exec.Cmd) {

View File

@@ -17,6 +17,8 @@ func BuildXray() error {
fmt.Printf("Building Xray into path (%s)\n", testBinaryPath)
cmd := exec.Command("go", "build", "-o="+testBinaryPath, GetSourcePath())
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}

View File

@@ -583,7 +583,7 @@ func TestHTTP2(t *testing.T) {
var errg errgroup.Group
for i := 0; i < 10; i++ {
errg.Go(testTCPConn(clientPort, 10240*1024, time.Second*40))
errg.Go(testTCPConn(clientPort, 1024*1024, time.Second*40))
}
if err := errg.Wait(); err != nil {
t.Error(err)

View File

@@ -1183,3 +1183,106 @@ func TestVMessGCMMuxUDP(t *testing.T) {
CloseAllServers(servers)
}()
}
func TestVMessZero(t *testing.T) {
tcpServer := tcp.Server{
MsgProcessor: xor,
}
dest, err := tcpServer.Start()
common.Must(err)
defer tcpServer.Close()
userID := protocol.NewID(uuid.New())
serverPort := tcp.PickPort()
serverConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort),
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(),
AlterId: 64,
}),
},
},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
clientPort := tcp.PickPort()
clientConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(clientPort),
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
NetworkList: &net.NetworkList{
Network: []net.Network{net.Network_TCP},
},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{
{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(serverPort),
User: []*protocol.User{
{
Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(),
AlterId: 64,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_ZERO,
},
}),
},
},
},
},
}),
},
},
}
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
common.Must(err)
defer CloseAllServers(servers)
var errg errgroup.Group
for i := 0; i < 10; i++ {
errg.Go(testTCPConn(clientPort, 1024*1024, time.Second*30))
}
if err := errg.Wait(); err != nil {
t.Error(err)
}
}

View File

@@ -11,6 +11,7 @@ import (
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/pipe"
@@ -22,7 +23,7 @@ var (
globalDialerAccess sync.Mutex
)
func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.Config) (*http.Client, error) {
func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.Config, sockopt *internet.SocketConfig) (*http.Client, error) {
globalDialerAccess.Lock()
defer globalDialerAccess.Unlock()
@@ -49,17 +50,24 @@ func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.C
}
address := net.ParseAddress(rawHost)
pconn, err := internet.DialSystem(ctx, net.TCPDestination(address, port), nil)
dctx := context.Background()
dctx = session.ContextWithID(dctx, session.IDFromContext(ctx))
dctx = session.ContextWithOutbound(dctx, session.OutboundFromContext(ctx))
pconn, err := internet.DialSystem(dctx, net.TCPDestination(address, port), sockopt)
if err != nil {
newError("failed to dial to " + addr).Base(err).AtError().WriteToLog()
return nil, err
}
cn := gotls.Client(pconn, tlsConfig)
if err := cn.Handshake(); err != nil {
newError("failed to dial to " + addr).Base(err).AtError().WriteToLog()
return nil, err
}
if !tlsConfig.InsecureSkipVerify {
if err := cn.VerifyHostname(tlsConfig.ServerName); err != nil {
newError("failed to dial to " + addr).Base(err).AtError().WriteToLog()
return nil, err
}
}
@@ -90,7 +98,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
if tlsConfig == nil {
return nil, newError("TLS must be enabled for http transport.").AtWarning()
}
client, err := getHTTPClient(ctx, dest, tlsConfig)
client, err := getHTTPClient(ctx, dest, tlsConfig, streamSettings.SocketSettings)
if err != nil {
return nil, err
}

View File

@@ -73,10 +73,10 @@ func ListenTCP(ctx context.Context, address net.Address, port net.Port, streamSe
l.listener = listener
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
l.tlsConfig = config.GetTLSConfig(tls.WithNextProto("h2"))
l.tlsConfig = config.GetTLSConfig()
}
if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {
l.xtlsConfig = config.GetXTLSConfig(xtls.WithNextProto("h2"))
l.xtlsConfig = config.GetXTLSConfig()
}
if tcpSettings.HeaderSettings != nil {

View File

@@ -9,6 +9,7 @@ import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/ocsp"
"github.com/xtls/xray-core/common/platform/filesystem"
"github.com/xtls/xray-core/common/protocol/tls/cert"
"github.com/xtls/xray-core/transport/internet"
)
@@ -42,8 +43,8 @@ func (c *Config) loadSelfCertPool() (*x509.CertPool, error) {
}
// BuildCertificates builds a list of TLS certificates from proto definition.
func (c *Config) BuildCertificates() []tls.Certificate {
certs := make([]tls.Certificate, 0, len(c.Certificate))
func (c *Config) BuildCertificates() []*tls.Certificate {
certs := make([]*tls.Certificate, 0, len(c.Certificate))
for _, entry := range c.Certificate {
if entry.Usage != Certificate_ENCIPHERMENT {
continue
@@ -53,19 +54,62 @@ func (c *Config) BuildCertificates() []tls.Certificate {
newError("ignoring invalid X509 key pair").Base(err).AtWarning().WriteToLog()
continue
}
certs = append(certs, keyPair)
if entry.OcspStapling != 0 {
go func(cert *tls.Certificate) {
t := time.NewTicker(time.Duration(entry.OcspStapling) * time.Second)
for {
if newData, err := ocsp.GetOCSPForCert(cert.Certificate); err != nil {
newError("ignoring invalid OCSP").Base(err).AtWarning().WriteToLog()
} else if string(newData) != string(cert.OCSPStaple) {
cert.OCSPStaple = newData
keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
if err != nil {
newError("ignoring invalid certificate").Base(err).AtWarning().WriteToLog()
continue
}
certs = append(certs, &keyPair)
if !entry.OneTimeLoading {
var isOcspstapling bool
hotReloadCertInterval := uint64(3600)
if entry.OcspStapling != 0 {
hotReloadCertInterval = entry.OcspStapling
isOcspstapling = true
}
index := len(certs) - 1
go func(cert *tls.Certificate, index int) {
t := time.NewTicker(time.Duration(hotReloadCertInterval) * time.Second)
for {
if entry.CertificatePath != "" && entry.KeyPath != "" {
newCert, err := filesystem.ReadFile(entry.CertificatePath)
if err != nil {
newError("failed to parse certificate").Base(err).AtError().WriteToLog()
<-t.C
continue
}
newKey, err := filesystem.ReadFile(entry.KeyPath)
if err != nil {
newError("failed to parse key").Base(err).AtError().WriteToLog()
<-t.C
continue
}
if string(newCert) != string(entry.Certificate) && string(newKey) != string(entry.Key) {
newKeyPair, err := tls.X509KeyPair(newCert, newKey)
if err != nil {
newError("ignoring invalid X509 key pair").Base(err).AtError().WriteToLog()
<-t.C
continue
}
if newKeyPair.Leaf, err = x509.ParseCertificate(newKeyPair.Certificate[0]); err != nil {
newError("ignoring invalid certificate").Base(err).AtError().WriteToLog()
<-t.C
continue
}
cert = &newKeyPair
}
}
if isOcspstapling {
if newOCSPData, err := ocsp.GetOCSPForCert(cert.Certificate); err != nil {
newError("ignoring invalid OCSP").Base(err).AtWarning().WriteToLog()
} else if string(newOCSPData) != string(cert.OCSPStaple) {
cert.OCSPStaple = newOCSPData
}
}
certs[index] = cert
<-t.C
}
}(&certs[len(certs)-1])
}(certs[len(certs)-1], index)
}
}
return certs
@@ -169,6 +213,33 @@ func getGetCertificateFunc(c *tls.Config, ca []*Certificate) func(hello *tls.Cli
}
}
func getNewGetCertficateFunc(certs []*tls.Certificate) func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
return func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
if len(certs) == 0 {
return nil, newError("empty certs")
}
sni := strings.ToLower(hello.ServerName)
if len(certs) == 1 || sni == "" {
return certs[0], nil
}
gsni := "*"
if index := strings.IndexByte(sni, '.'); index != -1 {
gsni += sni[index:]
}
for _, keyPair := range certs {
if keyPair.Leaf.Subject.CommonName == sni || keyPair.Leaf.Subject.CommonName == gsni {
return keyPair, nil
}
for _, name := range keyPair.Leaf.DNSNames {
if name == sni || name == gsni {
return keyPair, nil
}
}
}
return certs[0], nil
}
}
func (c *Config) IsExperiment8357() bool {
return strings.HasPrefix(c.ServerName, exp8357)
}
@@ -210,12 +281,11 @@ func (c *Config) GetTLSConfig(opts ...Option) *tls.Config {
opt(config)
}
config.Certificates = c.BuildCertificates()
config.BuildNameToCertificate()
caCerts := c.getCustomCA()
if len(caCerts) > 0 {
config.GetCertificate = getGetCertificateFunc(config, caCerts)
} else {
config.GetCertificate = getNewGetCertficateFunc(c.BuildCertificates())
}
if sn := c.parseServerName(); len(sn) > 0 {

View File

@@ -84,7 +84,13 @@ type Certificate struct {
// TLS key in x509 format.
Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
Usage Certificate_Usage `protobuf:"varint,3,opt,name=usage,proto3,enum=xray.transport.internet.tls.Certificate_Usage" json:"usage,omitempty"`
OcspStapling int64 `protobuf:"varint,4,opt,name=ocsp_stapling,json=ocspStapling,proto3" json:"ocsp_stapling,omitempty"`
OcspStapling uint64 `protobuf:"varint,4,opt,name=ocsp_stapling,json=ocspStapling,proto3" json:"ocsp_stapling,omitempty"`
// TLS certificate path
CertificatePath string `protobuf:"bytes,5,opt,name=certificate_path,json=certificatePath,proto3" json:"certificate_path,omitempty"`
// TLS Key path
KeyPath string `protobuf:"bytes,6,opt,name=key_path,json=keyPath,proto3" json:"key_path,omitempty"`
// If true, one-Time Loading
OneTimeLoading bool `protobuf:"varint,7,opt,name=One_time_loading,json=OneTimeLoading,proto3" json:"One_time_loading,omitempty"`
}
func (x *Certificate) Reset() {
@@ -140,13 +146,34 @@ func (x *Certificate) GetUsage() Certificate_Usage {
return Certificate_ENCIPHERMENT
}
func (x *Certificate) GetOcspStapling() int64 {
func (x *Certificate) GetOcspStapling() uint64 {
if x != nil {
return x.OcspStapling
}
return 0
}
func (x *Certificate) GetCertificatePath() string {
if x != nil {
return x.CertificatePath
}
return ""
}
func (x *Certificate) GetKeyPath() string {
if x != nil {
return x.KeyPath
}
return ""
}
func (x *Certificate) GetOneTimeLoading() bool {
if x != nil {
return x.OneTimeLoading
}
return false
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -284,7 +311,7 @@ var file_transport_internet_tls_config_proto_rawDesc = []byte{
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74,
0x6c, 0x73, 0x22, 0xf2, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x6c, 0x73, 0x22, 0xe2, 0x02, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28,
@@ -294,7 +321,14 @@ var file_transport_internet_tls_config_proto_rawDesc = []byte{
0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x2e,
0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x0d,
0x6f, 0x63, 0x73, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20,
0x01, 0x28, 0x03, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x53, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e,
0x01, 0x28, 0x04, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x53, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e,
0x67, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x65, 0x72,
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08,
0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x6b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x12, 0x28, 0x0a, 0x10, 0x4f, 0x6e, 0x65, 0x5f, 0x74,
0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28,
0x08, 0x52, 0x0e, 0x4f, 0x6e, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x61, 0x64, 0x69, 0x6e,
0x67, 0x22, 0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x4e,
0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10,
0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52, 0x49, 0x46, 0x59,

View File

@@ -21,7 +21,16 @@ message Certificate {
Usage usage = 3;
int64 ocsp_stapling = 4;
uint64 ocsp_stapling = 4;
// TLS certificate path
string certificate_path = 5;
// TLS Key path
string key_path = 6;
// If true, one-Time Loading
bool One_time_loading = 7;
}
message Config {

View File

@@ -10,6 +10,7 @@ import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/ocsp"
"github.com/xtls/xray-core/common/platform/filesystem"
"github.com/xtls/xray-core/common/protocol/tls/cert"
"github.com/xtls/xray-core/transport/internet"
)
@@ -41,8 +42,8 @@ func (c *Config) loadSelfCertPool() (*x509.CertPool, error) {
}
// BuildCertificates builds a list of TLS certificates from proto definition.
func (c *Config) BuildCertificates() []xtls.Certificate {
certs := make([]xtls.Certificate, 0, len(c.Certificate))
func (c *Config) BuildCertificates() []*xtls.Certificate {
certs := make([]*xtls.Certificate, 0, len(c.Certificate))
for _, entry := range c.Certificate {
if entry.Usage != Certificate_ENCIPHERMENT {
continue
@@ -52,19 +53,62 @@ func (c *Config) BuildCertificates() []xtls.Certificate {
newError("ignoring invalid X509 key pair").Base(err).AtWarning().WriteToLog()
continue
}
certs = append(certs, keyPair)
if entry.OcspStapling != 0 {
go func(cert *xtls.Certificate) {
t := time.NewTicker(time.Duration(entry.OcspStapling) * time.Second)
for {
if newData, err := ocsp.GetOCSPForCert(cert.Certificate); err != nil {
newError("ignoring invalid OCSP").Base(err).AtWarning().WriteToLog()
} else if string(newData) != string(cert.OCSPStaple) {
cert.OCSPStaple = newData
keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
if err != nil {
newError("ignoring invalid certificate").Base(err).AtWarning().WriteToLog()
continue
}
certs = append(certs, &keyPair)
if !entry.OneTimeLoading {
var isOcspstapling bool
hotRelodaInterval := uint64(3600)
if entry.OcspStapling != 0 {
hotRelodaInterval = entry.OcspStapling
isOcspstapling = true
}
index := len(certs) - 1
go func(cert *xtls.Certificate, index int) {
t := time.NewTicker(time.Duration(hotRelodaInterval) * time.Second)
for {
if entry.CertificatePath != "" && entry.KeyPath != "" {
newCert, err := filesystem.ReadFile(entry.CertificatePath)
if err != nil {
newError("failed to parse certificate").Base(err).AtError().WriteToLog()
<-t.C
continue
}
newKey, err := filesystem.ReadFile(entry.KeyPath)
if err != nil {
newError("failed to parse key").Base(err).AtError().WriteToLog()
<-t.C
continue
}
if string(newCert) != string(entry.Certificate) && string(newKey) != string(entry.Key) {
newKeyPair, err := xtls.X509KeyPair(newCert, newKey)
if err != nil {
newError("ignoring invalid X509 key pair").Base(err).AtError().WriteToLog()
<-t.C
continue
}
if newKeyPair.Leaf, err = x509.ParseCertificate(newKeyPair.Certificate[0]); err != nil {
newError("ignoring invalid certificate").Base(err).AtError().WriteToLog()
<-t.C
continue
}
cert = &newKeyPair
}
}
if isOcspstapling {
if newOCSPData, err := ocsp.GetOCSPForCert(cert.Certificate); err != nil {
newError("ignoring invalid OCSP").Base(err).AtWarning().WriteToLog()
} else if string(newOCSPData) != string(cert.OCSPStaple) {
cert.OCSPStaple = newOCSPData
}
}
certs[index] = cert
<-t.C
}
}(&certs[len(certs)-1])
}(certs[len(certs)-1], index)
}
}
return certs
@@ -168,6 +212,33 @@ func getGetCertificateFunc(c *xtls.Config, ca []*Certificate) func(hello *xtls.C
}
}
func getNewGetCertficateFunc(certs []*xtls.Certificate) func(hello *xtls.ClientHelloInfo) (*xtls.Certificate, error) {
return func(hello *xtls.ClientHelloInfo) (*xtls.Certificate, error) {
if len(certs) == 0 {
return nil, newError("empty certs")
}
sni := strings.ToLower(hello.ServerName)
if len(certs) == 1 || sni == "" {
return certs[0], nil
}
gsni := "*"
if index := strings.IndexByte(sni, '.'); index != -1 {
gsni += sni[index:]
}
for _, keyPair := range certs {
if keyPair.Leaf.Subject.CommonName == sni || keyPair.Leaf.Subject.CommonName == gsni {
return keyPair, nil
}
for _, name := range keyPair.Leaf.DNSNames {
if name == sni || name == gsni {
return keyPair, nil
}
}
}
return certs[0], nil
}
}
func (c *Config) parseServerName() string {
return c.ServerName
}
@@ -201,12 +272,11 @@ func (c *Config) GetXTLSConfig(opts ...Option) *xtls.Config {
opt(config)
}
config.Certificates = c.BuildCertificates()
config.BuildNameToCertificate()
caCerts := c.getCustomCA()
if len(caCerts) > 0 {
config.GetCertificate = getGetCertificateFunc(config, caCerts)
} else {
config.GetCertificate = getNewGetCertficateFunc(c.BuildCertificates())
}
if sn := c.parseServerName(); len(sn) > 0 {

View File

@@ -84,7 +84,13 @@ type Certificate struct {
// TLS key in x509 format.
Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
Usage Certificate_Usage `protobuf:"varint,3,opt,name=usage,proto3,enum=xray.transport.internet.xtls.Certificate_Usage" json:"usage,omitempty"`
OcspStapling int64 `protobuf:"varint,4,opt,name=ocsp_stapling,json=ocspStapling,proto3" json:"ocsp_stapling,omitempty"`
OcspStapling uint64 `protobuf:"varint,4,opt,name=ocsp_stapling,json=ocspStapling,proto3" json:"ocsp_stapling,omitempty"`
// TLS certificate path
CertificatePath string `protobuf:"bytes,5,opt,name=certificate_path,json=certificatePath,proto3" json:"certificate_path,omitempty"`
// TLS Key path
KeyPath string `protobuf:"bytes,6,opt,name=key_path,json=keyPath,proto3" json:"key_path,omitempty"`
// If true, one-Time Loading
OneTimeLoading bool `protobuf:"varint,7,opt,name=One_time_loading,json=OneTimeLoading,proto3" json:"One_time_loading,omitempty"`
}
func (x *Certificate) Reset() {
@@ -140,13 +146,34 @@ func (x *Certificate) GetUsage() Certificate_Usage {
return Certificate_ENCIPHERMENT
}
func (x *Certificate) GetOcspStapling() int64 {
func (x *Certificate) GetOcspStapling() uint64 {
if x != nil {
return x.OcspStapling
}
return 0
}
func (x *Certificate) GetCertificatePath() string {
if x != nil {
return x.CertificatePath
}
return ""
}
func (x *Certificate) GetKeyPath() string {
if x != nil {
return x.KeyPath
}
return ""
}
func (x *Certificate) GetOneTimeLoading() bool {
if x != nil {
return x.OneTimeLoading
}
return false
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -284,7 +311,7 @@ var file_transport_internet_xtls_config_proto_rawDesc = []byte{
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
0x78, 0x74, 0x6c, 0x73, 0x22, 0xf3, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x78, 0x74, 0x6c, 0x73, 0x22, 0xe3, 0x02, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69,
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20,
@@ -294,8 +321,15 @@ var file_transport_internet_xtls_config_proto_rawDesc = []byte{
0x74, 0x2e, 0x78, 0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x65, 0x2e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x12,
0x23, 0x0a, 0x0d, 0x6f, 0x63, 0x73, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67,
0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x53, 0x74, 0x61, 0x70,
0x6c, 0x69, 0x6e, 0x67, 0x22, 0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a,
0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x53, 0x74, 0x61, 0x70,
0x6c, 0x69, 0x6e, 0x67, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f,
0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12,
0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28,
0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x12, 0x28, 0x0a, 0x10, 0x4f, 0x6e,
0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x07,
0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x4f, 0x6e, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x61,
0x64, 0x69, 0x6e, 0x67, 0x22, 0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a,
0x0c, 0x45, 0x4e, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12,
0x14, 0x0a, 0x10, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52,
0x49, 0x46, 0x59, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49,

View File

@@ -21,7 +21,16 @@ message Certificate {
Usage usage = 3;
int64 ocsp_stapling = 4;
uint64 ocsp_stapling = 4;
// TLS certificate path
string certificate_path = 5;
// TLS Key path
string key_path = 6;
// If true, one-Time Loading
bool One_time_loading = 7;
}
message Config {