pax_global_header 0000666 0000000 0000000 00000000064 13774574720 0014532 g ustar 00root root 0000000 0000000 52 comment=a6efb4d60b86789a68ed8ac8d52cfcec2d80229a
v2ray-core-4.34.0/ 0000775 0000000 0000000 00000000000 13774574720 0013613 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/.github/ 0000775 0000000 0000000 00000000000 13774574720 0015153 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/.github/CODE_OF_CONDUCT.md 0000664 0000000 0000000 00000006213 13774574720 0017754 0 ustar 00root root 0000000 0000000 # Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at love@v2ray.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
v2ray-core-4.34.0/.github/ISSUE_TEMPLATE.md 0000664 0000000 0000000 00000000571 13774574720 0017663 0 ustar 00root root 0000000 0000000 如果你遇到的问题不是 V2Ray 的 bug,比如你不清楚要如何配置,请使用[Discussion](https://github.com/v2fly/discussion/issues)进行讨论。
此 Issue 会被立即关闭。
If you are not sure if your question is truely a bug in V2Ray, please discuss it [here](https://github.com/v2fly/discussion/issues) first.
This issue will be closed immediately.
v2ray-core-4.34.0/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 13774574720 0017336 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/.github/ISSUE_TEMPLATE/bug_cn.md 0000664 0000000 0000000 00000003444 13774574720 0021122 0 ustar 00root root 0000000 0000000 ---
name: V2Ray 程序问题
about: "提交一个 V2Ray 的程序问题报告。"
---
除非特殊情况,请完整填写所有问题。不按模板发的 issue 将直接被关闭。
如果你遇到的问题不是 V2Ray 的 bug,比如你不清楚要如何配置,请使用[Discussion](https://github.com/v2fly/v2ray-core/discussions)进行讨论。
1) 你正在使用哪个版本的 V2Ray?(如果服务器和客户端使用了不同版本,请注明)
2) 你的使用场景是什么?比如使用 Chrome 通过 Socks/VMess 代理观看 YouTube 视频。
3) 你看到的不正常的现象是什么?(请描述具体现象,比如访问超时,TLS 证书错误等)
4) 你期待看到的正确表现是怎样的?
5) 请附上你的配置(提交 Issue 前请隐藏服务器端IP地址)。
服务器端配置:
```javascript
// 在这里附上服务器端配置文件
```
客户端配置:
```javascript
// 在这里附上客户端配置
```
6) 请附上出错时软件输出的错误日志。在 Linux 中,日志通常在 `/var/log/v2ray/error.log` 文件中。
服务器端错误日志:
```javascript
// 在这里附上服务器端日志
```
客户端错误日志:
```javascript
// 在这里附上客户端日志
```
7) 请附上访问日志。在 Linux 中,日志通常在 `/var/log/v2ray/access.log` 文件中。
```javascript
// 在这里附上服务器端日志
```
8) 其它相关的配置文件(如 Nginx)和相关日志。
9) 如果 V2Ray 无法启动,请附上 `--test` 输出。
通常的命令为 `/usr/bin/v2ray/v2ray --test --config /etc/v2ray/config.json`。请按实际情况修改。
10) 如果 V2Ray 服务运行不正常,请附上 journal 日志。
通常的命令为 `journalctl -u v2ray`。
请预览一下你填的内容再提交。
v2ray-core-4.34.0/.github/ISSUE_TEMPLATE/bug_en.md 0000664 0000000 0000000 00000003465 13774574720 0021127 0 ustar 00root root 0000000 0000000 ---
name: Bug report
about: "Create a bug report to help us improve"
---
Please answer all the questions with enough information. All issues not following this template will be closed immediately.
If you are not sure if your question is truely a bug in V2Ray, please discuss it [here](https://github.com/v2fly/v2ray-core/discussions) first.
1) What version of V2Ray are you using (If you deploy different version on server and client, please explicitly point out)?
2) What's your scenario of using V2Ray? E.g., Watching YouTube videos in Chrome via Socks/VMess proxy.
3) What did you see? (Please describe in detail, such as timeout, fake TLS certificate etc)
4) What's your expectation?
5) Please attach your configuration file (**Mask IP addresses before submit this issue**).
Server configuration:
```javascript
// Please attach your server configuration here.
```
Client configuration:
```javascript
// Please attach your client configuration here.
```
6) Please attach error logs, especially the bottom lines if the file is large. Error log file is usually at `/var/log/v2ray/error.log` on Linux.
Server error log:
```javascript
// Please attach your server error log here.
```
Client error log:
```javascript
// Please attach your client error log here.
```
7) Please attach access log. Access log is usually at '/var/log/v2ray/access.log' on Linux.
```javascript
// Please attach your server access log here.
```
8) Other configurations (such as Nginx) and logs.
9) If V2Ray doesn't run, please attach output from `--test`.
The command is usually `/usr/bin/v2ray/v2ray --test --config /etc/v2ray/config.json`, but may vary according to your scenario.
10) If V2Ray service doesn't run, please attach journal log.
Usual command is `journalctl -u v2ray`.
Please review your issue before submitting. v2ray-core-4.34.0/.github/ISSUE_TEMPLATE/other_en.md 0000664 0000000 0000000 00000001105 13774574720 0021460 0 ustar 00root root 0000000 0000000 ---
name: Other
about: "其它问题请使用 https://github.com/v2fly/v2ray-core/discussions 进行讨论 / Please discuss other issues at https://github.com/v2fly/v2ray-core/discussions"
---
如果你遇到的问题不是 V2Ray 的 bug,比如你不清楚要如何配置,请使用[Discussion](https://github.com/v2fly/v2ray-core/discussions)进行讨论。
此 Issue 会被立即关闭。
If you are not sure if your question is truely a bug in V2Ray, please discuss it [here](https://github.com/v2fly/v2ray-core/discussions) first.
This issue will be closed immediately.
v2ray-core-4.34.0/.github/dependabot.yml 0000664 0000000 0000000 00000001062 13774574720 0020002 0 ustar 00root root 0000000 0000000 # To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
v2ray-core-4.34.0/.github/linters/ 0000775 0000000 0000000 00000000000 13774574720 0016633 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/.github/linters/.golangci.yml 0000664 0000000 0000000 00000001073 13774574720 0021220 0 ustar 00root root 0000000 0000000 run:
timeout: 5m
skip-files:
- generated.*
issues:
new: true
exclude-rules:
- path: _test\.go
linters:
- scopelint
linters:
enable:
- bodyclose
- depguard
- gocritic
- gofmt
- goimports
- golint
- goprintffuncname
- gosimple
- govet
- ineffassign
- misspell
- nakedret
- rowserrcheck
- scopelint
- staticcheck
- structcheck
- stylecheck
- typecheck
- unconvert
- unparam
- varcheck
- whitespace
disable:
- deadcode
- errcheck
- unused
v2ray-core-4.34.0/.github/workflows/ 0000775 0000000 0000000 00000000000 13774574720 0017210 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/.github/workflows/codeql-analysis.yml 0000664 0000000 0000000 00000004472 13774574720 0023032 0 ustar 00root root 0000000 0000000 name: CodeQL
on:
push:
branches:
- master
- v*
paths:
- "**/*.go"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
jobs:
analyze:
if: github.repository != 'v2ray/v2ray-core'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['go']
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
v2ray-core-4.34.0/.github/workflows/coverage.yml 0000664 0000000 0000000 00000002036 13774574720 0021527 0 ustar 00root root 0000000 0000000 name: Coverage
on:
push:
branches:
- master
- v*
paths:
- "**/*.go"
jobs:
coverage:
if: github.repository != 'v2ray/v2ray-core'
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.15
- name: Checkout codebase
uses: actions/checkout@v2
- name: Cache go module
uses: actions/cache@v2
id: cache-gomodules
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Get dependencies
if: steps.cache-gomodules.outputs.cache-hit != 'true'
run: go get -v -t -d ./...
- name: Run coverage
run: |
chmod u+x ./testing/coverage/coverall.sh
./testing/coverage/coverall.sh
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
with:
file: ./coverage.txt
fail_ci_if_error: true
v2ray-core-4.34.0/.github/workflows/deb.yml 0000664 0000000 0000000 00000003242 13774574720 0020466 0 ustar 00root root 0000000 0000000 name: Build debian packages
on:
push:
branches:
- master
- v*
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
release:
types: [prereleased]
jobs:
package:
if: github.repository == 'v2fly/v2ray-core'
runs-on: ubuntu-latest
container: debian:sid
steps:
- name: Install git
run: |
apt-get update
apt-get install -y git
- name: Checkout codebase
uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Install build dependencies
run: |
apt-get install -y build-essential dh-golang golang-any reprepro
- name: Build
run: |
cp -r release/debian .
dpkg-buildpackage -us -uc -i -b
- name: Copy binary
run: |
cp ../*.deb ./
- name: Upload artifact
uses: actions/upload-artifact@v2
with:
name: v2ray-debian-packages
path: ./*.deb
- name: Setup Repository
if: github.event_name == 'release'
run: |
git clone https://github.com/v2fly/debian.git archive
echo ${{ secrets.DEBIAN_GPG_PRIVATE }} | base64 -d > private.key
gpg --import --batch private.key
gpg -K
cd archive
git config --local user.name "${{ github.actor }}"
git config --local user.email "${{ github.actor }}@users.noreply.github.com"
git remote set-url origin https://${{ github.actor }}:${{ secrets.DEBIAN_REPO_TOKEN }}@github.com/v2fly/debian.git
reprepro includedeb stable ../*.deb
git add -A
git commit -am 'update'
git push origin main
v2ray-core-4.34.0/.github/workflows/linter.yml 0000664 0000000 0000000 00000001225 13774574720 0021230 0 ustar 00root root 0000000 0000000 name: Linter
on:
push:
branches:
- master
- v*
paths:
- "**/*.go"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
jobs:
lint:
if: github.repository != 'v2ray/v2ray-core'
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.15
- name: Checkout codebase
uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v2.3.0
with:
version: v1.31
args: --config=.github/linters/.golangci.yml
only-new-issues: true
v2ray-core-4.34.0/.github/workflows/release.yml 0000664 0000000 0000000 00000014635 13774574720 0021364 0 ustar 00root root 0000000 0000000 name: Release
on:
release:
types: [prereleased]
push:
branches:
- master
- v*
- dev*
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:
if: github.repository != 'v2ray/v2ray-core'
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:
# 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
# Windows ARM 7
- goos: windows
goarch: arm
goarm: 7
# BEGIN Other architectures
- goos: linux
goarch: arm64
- goos: linux
goarch: riscv64
# BEGIN MIPS
- goos: linux
goarch: mips64
- goos: linux
goarch: mips64le
- goos: linux
goarch: mipsle
- goos: linux
goarch: mips
# END MIPS
# BEGIN Android
- goos: android
goarch: arm64
# END Android
# END Other architectures
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
with:
fetch-depth: 0
- name: Show workflow information
id: get_filename
run: |
export _NAME=$(jq ".[\"$GOOS-$GOARCH$GOARM\"].friendlyName" -r < release/friendly-filenames.json)
echo "GOOS: $GOOS, GOARCH: $GOARCH, GOARM: $GOARM, 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.15
- name: Get project dependencies
run: go mod download
- name: Build V2Ray
run: |
mkdir -p build_assets
go build -v -o build_assets/v2ray -trimpath -ldflags "-s -w -buildid=" ./main
go build -v -o build_assets/v2ctl -trimpath -ldflags "-s -w -buildid=" -tags confonly ./infra/control/main
- name: Build Windows wv2ray
if: matrix.goos == 'windows'
run: |
echo "::warning ::wv2ray.exe will be removed in v5"
go build -v -o build_assets/wv2ray.exe -trimpath -ldflags "-s -w -H windowsgui -buildid=" ./main
cd ./build_assets || exit 1
mv v2ray v2ray.exe
mv v2ctl v2ctl.exe
- name: Prepare package
run: cp -v ./release/config/*.* ./build_assets
- name: Prepare package for Linux
if: matrix.goos == 'linux'
run: cp -rv ./release/config/systemd ./build_assets/
- name: Create ZIP archive
run: |
pushd build_assets || exit 1
zip -9vr ../v2ray-$ASSET_NAME.zip .
popd || exit 1
FILE=./v2ray-$ASSET_NAME.zip
DGST=$FILE.dgst
openssl dgst -md5 $FILE | sed 's/([^)]*)//g' >>$DGST
openssl dgst -sha1 $FILE | sed 's/([^)]*)//g' >>$DGST
openssl dgst -sha256 $FILE | sed 's/([^)]*)//g' >>$DGST
openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >>$DGST
- name: Upload ZIP file to Artifacts
uses: actions/upload-artifact@v2
with:
name: v2ray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip
path: v2ray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip
- name: Upload files to GitHub release
uses: svenstaro/upload-release-action@v2
if: github.event_name == 'release'
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file_glob: true
file: ./v2ray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip*
tag: ${{ github.ref }}
signature:
if: github.repository != 'v2ray/v2ray-core'
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout codebase
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.15
- uses: actions/download-artifact@v2
with:
path: build_artifacts
- name: Generate shasum
run: |
cd build_artifacts || exit 1
mkdir .temp
mv ./*/*.zip ./.temp
rmdir ./*/
mv ./.temp/* .
ls -lah --recursive
{
go run github.com/v2fly/V2BuildAssist/v2buildutil gen version $(git describe --tags $(git rev-list --tags --max-count=1))
go run github.com/v2fly/V2BuildAssist/v2buildutil gen project "v2fly"
for zip in $(ls *.zip); do
go run github.com/v2fly/V2BuildAssist/v2buildutil gen file ${zip}
done
} >Release.unsigned.unsorted
go run github.com/v2fly/V2BuildAssist/v2buildutil gen sort < Release.unsigned.unsorted > Release.unsigned
rm -f Release.unsigned.unsorted
FILE=./Release.unsigned
DGST=$FILE.dgst
openssl dgst -md5 $FILE | sed 's/([^)]*)//g' >>$DGST
openssl dgst -sha1 $FILE | sed 's/([^)]*)//g' >>$DGST
openssl dgst -sha256 $FILE | sed 's/([^)]*)//g' >>$DGST
openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >>$DGST
- uses: actions/upload-artifact@v2
with:
name: Release.unsigned
path: build_artifacts/Release.unsigned
- uses: actions/upload-artifact@v2
with:
name: Release.unsigned.dgst
path: build_artifacts/Release.unsigned.dgst
- name: Upload Release.unsigned related files
uses: svenstaro/upload-release-action@v2
if: github.event_name == 'release'
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file_glob: true
file: build_artifacts/Release.unsigned*
tag: ${{ github.ref }}
v2ray-core-4.34.0/.github/workflows/semgrep.yml 0000664 0000000 0000000 00000000665 13774574720 0021404 0 ustar 00root root 0000000 0000000 name: Semgrep
on: [pull_request]
jobs:
semgrep:
name: Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: returntocorp/semgrep-action@v1
env: # Optional environment variable for inline PR comments (beta)
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
config: p/r2c
publishToken: ${{ secrets.SEMGREP_APP_TOKEN }}
publishDeployment: 241
v2ray-core-4.34.0/.github/workflows/sign.yml 0000664 0000000 0000000 00000001361 13774574720 0020674 0 ustar 00root root 0000000 0000000 name: Sign
on:
release:
types: [released]
jobs:
sign:
if: github.repository != 'v2ray/v2ray-core'
runs-on: ubuntu-latest
steps:
- name: Checkout default branch
uses: actions/checkout@v2
- name: Grant it execution permission
run: |
chmod +x $GITHUB_WORKSPACE/release/requestsign.sh
- name: Invoke release signing
env:
SIGN_SERVICE_PASSWORD: ${{ secrets.SIGN_SERVICE_PASSWORD }}
SIGN_SERIVCE_URL: ${{ secrets.SIGN_SERIVCE_URL }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
export SIGN_VERSION=$(cat $GITHUB_EVENT_PATH| jq -r ".release.tag_name")
echo $SIGN_VERSION
$GITHUB_WORKSPACE/release/requestsign.sh
v2ray-core-4.34.0/.github/workflows/stale.yml 0000664 0000000 0000000 00000001137 13774574720 0021045 0 ustar 00root root 0000000 0000000 name: Mark stale issues and pull requests
on:
schedule:
- cron: "30 1 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3.0.14
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: "This issue is stale because it has been open 120 days with no activity. Remove stale label or comment or this will be closed in 5 days"
stale-pr-message: 'It has been open 120 days with no activity. Remove stale label or comment or this will be closed in 5 days'
days-before-stale: 120
days-before-close: 5
v2ray-core-4.34.0/.github/workflows/test.yml 0000664 0000000 0000000 00000001274 13774574720 0020716 0 ustar 00root root 0000000 0000000 name: Test
on:
push:
branches:
- master
- v*
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
jobs:
test:
if: github.repository != 'v2ray/v2ray-core'
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.15
- name: Checkout codebase
uses: actions/checkout@v2
- name: Test
run: go test -v -race -timeout 1h ./... v2ray-core-4.34.0/.github/workflows/updateGeofile.yml 0000664 0000000 0000000 00000001323 13774574720 0022507 0 ustar 00root root 0000000 0000000 name: Update Geofiles
on:
schedule:
- cron: "0 0 * * FRI"
jobs:
update:
if: github.repository == 'v2fly/v2ray-core'
runs-on: ubuntu-latest
steps:
- name: Checkout codebase
uses: actions/checkout@v2
- name: Download
run: |
curl -L -o release/config/geoip.dat "https://github.com/v2fly/geoip/raw/release/geoip.dat"
curl -L -o release/config/geosite.dat "https://github.com/v2fly/domain-list-community/raw/release/dlc.dat"
- name: push
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git commit -am "update geoip, geosite"
git push -v --progress
v2ray-core-4.34.0/.gitignore 0000664 0000000 0000000 00000000030 13774574720 0015574 0 ustar 00root root 0000000 0000000 *.DS_Store
bazel-*
.idea v2ray-core-4.34.0/LICENSE 0000664 0000000 0000000 00000002100 13774574720 0014611 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2015-2020 V2Fly Community
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
v2ray-core-4.34.0/README.md 0000664 0000000 0000000 00000004475 13774574720 0015104 0 ustar 00root root 0000000 0000000
Project V
Project V is a set of network tools that helps you to build your own computer network. It secures your network connections and thus protects your privacy.
[](https://github.com/v2fly/v2ray-core/actions)
[](https://codecov.io/gh/v2fly/v2ray-core?branch=master)
[](https://goreportcard.com/report/github.com/v2fly/v2ray-core)
[](https://www.codacy.com/gh/v2fly/v2ray-core/dashboard?utm_source=github.com&utm_medium=referral&utm_content=v2fly/v2ray-core&utm_campaign=Badge_Grade)
[](https://github.com/v2fly/v2ray-core/releases/latest)
## Related Links
- [Documentation](https://www.v2fly.org) and [Newcomer's Instructions](https://www.v2fly.org/guide/start.html)
- Welcome to translate V2Ray documents via [Transifex](https://www.transifex.com/v2fly/public/)
## Packaging Status
> If you are willing to package V2Ray for other distros/platforms, please let us know or seek for help via [GitHub issues](https://github.com/v2fly/v2ray-core/issues).
[](https://repology.org/project/v2ray/versions)
## License
[The MIT License (MIT)](https://raw.githubusercontent.com/v2fly/v2ray-core/master/LICENSE)
## Credits
This repo relies on the following third-party projects:
- In production:
- [gorilla/websocket](https://github.com/gorilla/websocket)
- [lucas-clemente/quic-go](https://github.com/lucas-clemente/quic-go)
- [pires/go-proxyproto](https://github.com/pires/go-proxyproto)
- [seiflotfy/cuckoofilter](https://github.com/seiflotfy/cuckoofilter)
- [google/starlark-go](https://github.com/google/starlark-go)
- For testing only:
- [miekg/dns](https://github.com/miekg/dns)
- [h12w/socks](https://github.com/h12w/socks)
v2ray-core-4.34.0/SECURITY.md 0000664 0000000 0000000 00000014520 13774574720 0015406 0 ustar 00root root 0000000 0000000 # 安全策略 Security Policy
## 受支持的版本 Supported Versions
目前 v2ray-core 项目由 [V2Fly 社区](https://github.com/v2fly) 继续提供代码维护,由于精力有限且项目复杂度较高,只维护主线代码的功能和安全性完整。原则上主页的兼容性保证继续遵循,
如有例外另行说明。
Currently v2ray-core project is maintained by [V2Fly community](https://github.com/v2fly). Feature and security guarantee may only be limited to the
master branch, though we would still try our best to follow the compatiblity claims listed on the official website.
## 汇报安全风险 Reporting a Vulnerability
使用邮箱: security |at| v2fly.org。
Report to email: security |at| v2fly.org.
GPG public key:
```
pub rsa4096 2020-06-02 [SC] [有效至:2022-01-02]
E2E35E27914FB007C0D4B6DDB117BA3BE8B494A7
uid [ 绝对 ] V2Fly Developers
sub rsa4096 2020-06-02 [E] [有效至:2022-01-02]
sub rsa4096 2020-11-08 [S] [有效至:2022-01-02] // 用于 Debian / Ubuntu 签名
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBF7V7pQBEACozcw4/BlPgFWaz4AdN8HKSrCDLlN+/g7m4AKZIo13fAnDh+sJ
2H4NrWNr0xxgovbco5Xw4OSSwY1BuUhnb4AmIyxbwqUQD2UADe5xD6gMBwNiJTP4
02VCHhh7DnWTeLbAsUgRotxUCxsWVvd2F08SYGfJggOVftOnG+VNnwzTOvHWFVEw
1Pv1DaY7bKSA0voACerRbAPCYqhmElAGJHYNjBMaxqCaWFJWpAFfBxkvS1FDVyZk
BsABhn6sOcGJn8EYSHUIXhWwqtkQCjBB4OOik+Jn+S2DFGyk5l1NrGRQtX8C0BYn
nc7VaxtFOp5fnJ4y0GNd4AM9KO0/Ojosi6b64l407Fj9i9OXznmZUACQw2u+VcL3
qNy768hsTmka3pXzpRHZwYcOLOEr3jGHmLOtXgQ656OjF8Xd9DJ4cB42X8iBeqTp
iQchHIdBpnu27ZbBFy09OMak+STB5zA0JmxDaC8b48mVkc0BMRXdYl7wWXJsEJf1
roAOr3RCBKiE840w0PLOTnUljfqazPYTwzs91oP+SeZjBmGOpaAh7bh5BVOpzPSE
bdA61/n01GEb5bpOKpaTi9GviF3RCbfFnLKJnBq0vHvW9BqKTVFRPAKkBGuOPBdy
8MBNY+VY/2aP3ukZUoYe8Ypl9Q7dVPRjnoWaH0sEMzftoh+3s7GSSgAylQARAQAB
tCBWMkZseSBEZXZlbG9wZXJzIDxkZXZAdjJmbHkub3JnPokCVAQTAQgAPgIbAwUL
CQgHAgYVCgkICwIEFgIDAQIeAQIXgBYhBOLjXieRT7AHwNS23bEXujvotJSnBQJf
p4leBQkC+1DKAAoJELEXujvotJSn124P/0swu9POvEQtxVlRzNh2VjAGHZ5NEDnl
pMrhfC5ryCYtlVS/kc2WwRhIRHKzr9nbamgSxUCiyLagfnIjhIvAohun49grYNzG
MZWRURiuFrCnYbD7juJTvfbzZCzJk7LPsdnqHWr8fYcOZMTOZVzQiQB2jUx2KeRm
yV8aV21Z8gMLqSGjs06a0UaRbKB0FSysTURm91/jFmiH43aG1s/LcB9/lKf5HpNl
9or6LrEOrokAwtkMSBYTqm7Dp1j+cK0iOMw2CmMqmQZkV+i6msYrQRiX/X6YufiM
wfMMSdOZOz9KG+k+C6N1swSbGeDMrJfnDUDbvrAXKhDjNgY7UBwbk69Abd7Y9aQz
/jVmrFEWt4lisBxglBot60CRUTM2boK/uQS5zBCJhemeg14F9Q/FRiUTlS8jQoeK
PWeK2lagYJS8lpJZLXkqe4xSpjCgoT0Z+lYSfTjx+T0AFF+xz5E243Lb5kDxwnR9
Y5CZt3vV6GWBYOt9MEL3pk7AnYyNT1y1KIiMyONh/Z1koUdHr4J9exllnsmAJQUa
W/j0UtVsLsvUjFv9RTr9w5p/U0J0VLIN0YOpx4wYaBEwFIa8lsL+Ey1Vphkvvjfz
uMRAHe4v+axWb1f1hVCBjtyCVyvzf+i9RTAYsBJ3MJ0C8cvvrm10N9B7MHh0JZA5
PcJSilailp1TuQINBF7V7pQBEADkQdO75smeKnmPt0/aNNlb7JDOSWW5VY0kYgx3
6Toh139JstIQ2xz0CLSGReizUFB6eR3DXmezLrmhkgN2Aq5A+hCtFAJwWKuKr1HS
usvJ1el9h0oh7IO+tF8E/gNYwWfabjPX27FGVCHR1qG7ffN51Bghrnwi1T4YC98E
R9EGU6N0Xs9DeIJL9WQPH/DF22251i/OAXkqKVGn3PNe2cBsp0yKxr9mlSyzjrha
KXokPiPcvNqlnkiDCgfiRj7c2C2Lyl9PoEiGpsNZaCZYkMPgjM0xiLenQddwRyOU
z2cLG3d8WdCTRyHSZd/YQtSi5R6AnkJEsVtUiDN5zwNFVpQlTq3jNHsVUpjFU2nK
ourTZVCCLbAC60VTdxLN6eFO0f+lS2WjyJ7uZ9SGbS6uP0jMNphH/QjVF848bWXs
1CuZty5QQY7+MTNUAhSWWntrpTkdXYqT0zUqiOc1YNnkfg3hvC4d0dbnFTfcyZnB
Sg8e7/9n6+ms75/deYgnLuA6h7pkIcflm7pUMfVKXKz5Vlc8FC9ia0UtobeKBKqi
jObfiO/zmNL0HQBeX0e8GkJrCyv6ikD8cUqsmVtgw7jdxGsV0SL5CddDnGKsc68O
pGDmkAuRqR3QtXju/4r7a8IEVveGWc3rUvddYrtqbbCNWCN0JKX13PEvbNAm+2eD
MGQtcQARAQABiQI8BBgBCAAmAhsMFiEE4uNeJ5FPsAfA1LbdsRe6O+i0lKcFAl+n
dwcFCQL7PnMACgkQsRe6O+i0lKeWfxAApopL5I9p4btmkcLIg2lkA1n+czFekbdr
2tjFKrBER4QWkyDCUE8QaVo/ECveTHmnxrTB/djW6xqPVS77PL8xOATIYTo6qU38
oTCB1T7/P2L9qI72BzcRY5f9ZPyJhCtrkvjCPzjUjw+ZIPIOgQcWgKHWnE+OyUKD
0GkVEUME3QP5S4Nr3XGrgS7oxDAmD52u7pn0mSk5WmEcLW0oGwsVdc4aDXxpX+u/
gkBZysmAuomPov7iXVosMakl+4rz30yPcrL9A81m1WAeB3PGkpaO3B++8Ql+FBCQ
OrLtPn/nnIzEuAXB1Hd8vYzxtRM2CZvhRExM7xofnhkBJOtR/ddfbJa7H5+Aruc0
4S0JIaqMCrC6tZezjTACAzrWULmZZGmrHbLrmXBuLk0huRkeIRnDzHP+DoE2UciL
3hR9EGOHX9O/dGb3bb3y11LAf7GI28ZG7So1GeoFkEOga1IJnsBnXCqwM8vbDDWq
/7aLb3/m0gT7DUfjeXKfWPJXcnaq8r4llHzDn2i6ax4Uq/brCOLj9ovVGIctZTbt
yvsFOc1bVkSuUM+pMkCtBx80/sJSB2Nu94S6osdaUlRE+jaCcqEbPd+G68Yd0Khi
CL8zF1a3dX1dpuVFTLNpXOgrviGBzXQmzFeil7mWFs0l+1XZOPz9nhmRrMn6wV3n
i4KItRSJAXy5Ag0EX6d5hQEQAMsVyLTXdybeei2nWDb5jtzzC3AtSnPWtKG4B86C
BXncaZpU43hKI3oduW2+42eM8n8KTvO11r9xv4zKATfaHBZq2hkKZdDQjuSstovr
a3hapHHknHeNVTg3yuiakKzpr6FK23W/GE1lJfhz254v9+dRV0KazWksXvpGEdgI
+6sC4Nr5bKgJVEQibyrrL0gmzlVB/oQU/W4eGvk21zmgMlHri+edBLpVtlCmn7k/
0t+2X9D1Pq2nkjMUurB9EJ1z24LMldmPOl6P7iJCx9kSUjcHrEg56q5VSZq50FAj
DeSjAqsdussI8cdstCMktE9nhizxVKFXpbXifqoYfJwCo23wFqQJpyPgQqHIT12s
GWRUa/MF6hRYg/5CyeadDmkmnKPTPjmQ2S2SFNXX7xs+dZKvIvXP30z4cpuVY8i8
chZSRNb8K0L9T0Jme7CPm28F6lvDUkNDQ1WErXZruHbOKwQOfQBdXK3nedOiUpBt
401HVlGUJSInfEb3JXU01tRqnnzI/y5z7cWCGEMEa6TeaCrMbVvl8xeAA1w/nw0y
zHz6/Pnf4TITuCH22aa7+xfgpq8gRLhUUws89mbQT+9fd8tT65+Q8xcaLCyzrLAq
zND5sVZ4/PwaYc8UNZcHjeQR7aYWI1xgr/IwY1wyDWZLbWgkk0HVxpvYdMEpJryD
AyMdABEBAAGJBHIEGAEIACYWIQTi414nkU+wB8DUtt2xF7o76LSUpwUCX6d5hQIb
AgUJAim2AAJACRCxF7o76LSUp8F0IAQZAQgAHRYhBK8FZLGpNMztuW02YbJOz+X/
ddOBBQJfp3mFAAoJELJOz+X/ddOBNKQP/0nwIC4R9gQhY53vME7VA7elIrBiSM6d
Va26a7J1nrCcpDAE7Lp0TqzrDMqyen+IL4X5QK5sKTgenYTgjppEJIQn+Wup54ix
I+YOQ8MVLfN6/3QPACWMngSPRF+UKDg4hyTCEL+/GCgTp58oXrl/YIO6Oqt5drog
w4+4ufU1/eKTb2ruGULGl9jZvFSZpLdsvJ19xJB2kC1k8GVNu7MnUL+S2pU/9kO4
5EZ/jEa1wT45zev+HdmzX5TYW6SLaI9HKHMqbQz2EHc3tRYIDaz3FE3s4VdMjqpp
e42SvkOYaguc6cXToDbzBmU+iWGlXCTHfNhxwxoUYcKZlDEkEtvSYHJOb0k9eqbT
gvMb5GjbAgqqwOBwtN3v790j8jEG+cdXR3qHcEx0bw3F2Bd18U7j946OxHLKE5Xk
2sWEG422maVrE9o1DdeTV5oDFNNPBzqfjgGBZCCKrjkpldhDOHeoDU2aFMJ7yVqw
ZwKwJ5f8fdNS13UnQVwGsZ2BsW1cox5ZGZ/C5A7mfSF1WAgJcYIw4M2JQbDn4Yuw
yqjyg53lT3OurBONbEZ7unnsLqpT9qKwZ1qCemqGRJieXXxJwl7G4gBgZbH0rBJR
6dhbyt4c2JE8MMdC65mDWneltNM6pttC/j5jCuvIlZGACZ91UuLLediJJWAlOJ+1
fBQ0m8TD6d8ZrakP/RFMLZrxh9WPaFB43sW/b1Fq2h933HQ29oSQFuXhsHsx1Vaq
HTRTcBB7kywAr9+zMYsOsk0/WnoZNGoMkUWu/gFkb6CdUcsdEumgyZ8S24VoBCHB
T1fD/8eOA5K82hwAFcKbPwuuTLtf9b9HB4/xsObfcczTeqIknzIPsGlgVz4w1c9a
StSo4iI4bCSLL+/mqiXZ+ArXJ/z4Vejl92fNLWVOlOrjkBV+AY6iAFCCsxJ1O5ud
5a5r1bUeBXd0BcQ1m/hpjawMC1y0SkIBTQCgxIQoPoxJ27hHNIN1R2nkqfY9vboQ
7O0uIHF8fmuz93xg68ZTW0JHwOw4Mz88lGibE2laHApjKWZAtF/i+LlhbnewtESL
EuGTT7gt7cSHgnBiDEIm5UJVEGeM0sMReztxy9V7glohH5DV8GpVK/GncKlsrh1K
BuEuz7IrqKlBzhsDy0SrNZpX7EzsiU1uvoA6teT4EPey8qXH+7WR9B2ad1Zc5yE3
zv4BpnWkkJp8qdYu4fdCs/mrmnBR5G1YdOAIlNWhU74Wdyq+W4HfTWMgvJHmElnZ
UvQ9RDTWnw2+3n2ATeLf9ZwW1g4/Dqh55OaLtJZo5me8vU9W+vkm34xzfVfD/mus
ljogw5eiGyj8j3lUVjYWu28l/bz0zDUueWmHhV8E8z0Cn7OhrHPpUCHx2Aep
=quYd
-----END PGP PUBLIC KEY BLOCK-----
```
v2ray-core-4.34.0/annotations.go 0000664 0000000 0000000 00000001250 13774574720 0016475 0 ustar 00root root 0000000 0000000 package core
// Annotation is a concept in V2Ray. This struct is only for documentation. It is not used anywhere.
// Annotations begin with "v2ray:" in comment, as metadata of functions or types.
type Annotation struct {
// API is for types or functions that can be used in other libs. Possible values are:
//
// * v2ray:api:beta for types or functions that are ready for use, but maybe changed in the future.
// * v2ray:api:stable for types or functions with guarantee of backward compatibility.
// * v2ray:api:deprecated for types or functions that should not be used anymore.
//
// Types or functions without api annotation should not be used externally.
API string
}
v2ray-core-4.34.0/app/ 0000775 0000000 0000000 00000000000 13774574720 0014373 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/app.go 0000664 0000000 0000000 00000000162 13774574720 0015501 0 ustar 00root root 0000000 0000000 // Package app contains feature implementations of V2Ray. The features may be enabled during runtime.
package app
v2ray-core-4.34.0/app/commander/ 0000775 0000000 0000000 00000000000 13774574720 0016340 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/commander/commander.go 0000664 0000000 0000000 00000004355 13774574720 0020643 0 ustar 00root root 0000000 0000000 // +build !confonly
package commander
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"net"
"sync"
"google.golang.org/grpc"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/signal/done"
"v2ray.com/core/features/outbound"
)
// Commander is a V2Ray feature that provides gRPC methods to external clients.
type Commander struct {
sync.Mutex
server *grpc.Server
services []Service
ohm outbound.Manager
tag string
}
// NewCommander creates a new Commander based on the given config.
func NewCommander(ctx context.Context, config *Config) (*Commander, error) {
c := &Commander{
tag: config.Tag,
}
common.Must(core.RequireFeatures(ctx, func(om outbound.Manager) {
c.ohm = om
}))
for _, rawConfig := range config.Service {
config, err := rawConfig.GetInstance()
if err != nil {
return nil, err
}
rawService, err := common.CreateObject(ctx, config)
if err != nil {
return nil, err
}
service, ok := rawService.(Service)
if !ok {
return nil, newError("not a Service.")
}
c.services = append(c.services, service)
}
return c, nil
}
// Type implements common.HasType.
func (c *Commander) Type() interface{} {
return (*Commander)(nil)
}
// Start implements common.Runnable.
func (c *Commander) Start() error {
c.Lock()
c.server = grpc.NewServer()
for _, service := range c.services {
service.Register(c.server)
}
c.Unlock()
listener := &OutboundListener{
buffer: make(chan net.Conn, 4),
done: done.New(),
}
go func() {
if err := c.server.Serve(listener); err != nil {
newError("failed to start grpc server").Base(err).AtError().WriteToLog()
}
}()
if err := c.ohm.RemoveHandler(context.Background(), c.tag); err != nil {
newError("failed to remove existing handler").WriteToLog()
}
return c.ohm.AddHandler(context.Background(), &Outbound{
tag: c.tag,
listener: listener,
})
}
// Close implements common.Closable.
func (c *Commander) Close() error {
c.Lock()
defer c.Unlock()
if c.server != nil {
c.server.Stop()
c.server = nil
}
return nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
return NewCommander(ctx, cfg.(*Config))
}))
}
v2ray-core-4.34.0/app/commander/config.pb.go 0000664 0000000 0000000 00000017525 13774574720 0020546 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: app/commander/config.proto
package commander
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
serial "v2ray.com/core/common/serial"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// Config is the settings for Commander.
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Tag of the outbound handler that handles grpc connections.
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
// Services that supported by this server. All services must implement Service
// interface.
Service []*serial.TypedMessage `protobuf:"bytes,2,rep,name=service,proto3" json:"service,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_commander_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_commander_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_commander_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
func (x *Config) GetService() []*serial.TypedMessage {
if x != nil {
return x.Service
}
return nil
}
// ReflectionConfig is the placeholder config for ReflectionService.
type ReflectionConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ReflectionConfig) Reset() {
*x = ReflectionConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_app_commander_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReflectionConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReflectionConfig) ProtoMessage() {}
func (x *ReflectionConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_commander_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReflectionConfig.ProtoReflect.Descriptor instead.
func (*ReflectionConfig) Descriptor() ([]byte, []int) {
return file_app_commander_config_proto_rawDescGZIP(), []int{1}
}
var File_app_commander_config_proto protoreflect.FileDescriptor
var file_app_commander_config_proto_rawDesc = []byte{
0x0a, 0x1a, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x2f,
0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x18, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73,
0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5c, 0x0a, 0x06, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x40, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61,
0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x65, 0x66, 0x6c, 0x65,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x59, 0x0a, 0x1c, 0x63,
0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x1c, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0xaa, 0x02, 0x18, 0x56, 0x32,
0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x43, 0x6f, 0x6d,
0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_commander_config_proto_rawDescOnce sync.Once
file_app_commander_config_proto_rawDescData = file_app_commander_config_proto_rawDesc
)
func file_app_commander_config_proto_rawDescGZIP() []byte {
file_app_commander_config_proto_rawDescOnce.Do(func() {
file_app_commander_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_commander_config_proto_rawDescData)
})
return file_app_commander_config_proto_rawDescData
}
var file_app_commander_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_app_commander_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: v2ray.core.app.commander.Config
(*ReflectionConfig)(nil), // 1: v2ray.core.app.commander.ReflectionConfig
(*serial.TypedMessage)(nil), // 2: v2ray.core.common.serial.TypedMessage
}
var file_app_commander_config_proto_depIdxs = []int32{
2, // 0: v2ray.core.app.commander.Config.service:type_name -> v2ray.core.common.serial.TypedMessage
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_app_commander_config_proto_init() }
func file_app_commander_config_proto_init() {
if File_app_commander_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_commander_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_commander_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReflectionConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_commander_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_app_commander_config_proto_goTypes,
DependencyIndexes: file_app_commander_config_proto_depIdxs,
MessageInfos: file_app_commander_config_proto_msgTypes,
}.Build()
File_app_commander_config_proto = out.File
file_app_commander_config_proto_rawDesc = nil
file_app_commander_config_proto_goTypes = nil
file_app_commander_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/app/commander/config.proto 0000664 0000000 0000000 00000001266 13774574720 0020677 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.app.commander;
option csharp_namespace = "V2Ray.Core.App.Commander";
option go_package = "v2ray.com/core/app/commander";
option java_package = "com.v2ray.core.app.commander";
option java_multiple_files = true;
import "common/serial/typed_message.proto";
// Config is the settings for Commander.
message Config {
// Tag of the outbound handler that handles grpc connections.
string tag = 1;
// Services that supported by this server. All services must implement Service
// interface.
repeated v2ray.core.common.serial.TypedMessage service = 2;
}
// ReflectionConfig is the placeholder config for ReflectionService.
message ReflectionConfig {}
v2ray-core-4.34.0/app/commander/errors.generated.go 0000664 0000000 0000000 00000000317 13774574720 0022141 0 ustar 00root root 0000000 0000000 package commander
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/app/commander/outbound.go 0000664 0000000 0000000 00000004074 13774574720 0020533 0 ustar 00root root 0000000 0000000 // +build !confonly
package commander
import (
"context"
"sync"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/common/signal/done"
"v2ray.com/core/transport"
)
// OutboundListener is a net.Listener for listening gRPC connections.
type OutboundListener struct {
buffer chan net.Conn
done *done.Instance
}
func (l *OutboundListener) add(conn net.Conn) {
select {
case l.buffer <- conn:
case <-l.done.Wait():
conn.Close()
default:
conn.Close()
}
}
// Accept implements net.Listener.
func (l *OutboundListener) Accept() (net.Conn, error) {
select {
case <-l.done.Wait():
return nil, newError("listen closed")
case c := <-l.buffer:
return c, nil
}
}
// Close implement net.Listener.
func (l *OutboundListener) Close() error {
common.Must(l.done.Close())
L:
for {
select {
case c := <-l.buffer:
c.Close()
default:
break L
}
}
return nil
}
// Addr implements net.Listener.
func (l *OutboundListener) Addr() net.Addr {
return &net.TCPAddr{
IP: net.IP{0, 0, 0, 0},
Port: 0,
}
}
// Outbound is a outbound.Handler that handles gRPC connections.
type Outbound struct {
tag string
listener *OutboundListener
access sync.RWMutex
closed bool
}
// Dispatch implements outbound.Handler.
func (co *Outbound) Dispatch(ctx context.Context, link *transport.Link) {
co.access.RLock()
if co.closed {
common.Interrupt(link.Reader)
common.Interrupt(link.Writer)
co.access.RUnlock()
return
}
closeSignal := done.New()
c := net.NewConnection(net.ConnectionInputMulti(link.Writer), net.ConnectionOutputMulti(link.Reader), net.ConnectionOnClose(closeSignal))
co.listener.add(c)
co.access.RUnlock()
<-closeSignal.Wait()
}
// Tag implements outbound.Handler.
func (co *Outbound) Tag() string {
return co.tag
}
// Start implements common.Runnable.
func (co *Outbound) Start() error {
co.access.Lock()
co.closed = false
co.access.Unlock()
return nil
}
// Close implements common.Closable.
func (co *Outbound) Close() error {
co.access.Lock()
defer co.access.Unlock()
co.closed = true
return co.listener.Close()
}
v2ray-core-4.34.0/app/commander/service.go 0000664 0000000 0000000 00000001123 13774574720 0020324 0 ustar 00root root 0000000 0000000 // +build !confonly
package commander
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"v2ray.com/core/common"
)
// Service is a Commander service.
type Service interface {
// Register registers the service itself to a gRPC server.
Register(*grpc.Server)
}
type reflectionService struct{}
func (r reflectionService) Register(s *grpc.Server) {
reflection.Register(s)
}
func init() {
common.Must(common.RegisterConfig((*ReflectionConfig)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
return reflectionService{}, nil
}))
}
v2ray-core-4.34.0/app/dispatcher/ 0000775 0000000 0000000 00000000000 13774574720 0016521 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/dispatcher/config.pb.go 0000664 0000000 0000000 00000016067 13774574720 0020727 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: app/dispatcher/config.proto
package dispatcher
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type SessionConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *SessionConfig) Reset() {
*x = SessionConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_app_dispatcher_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SessionConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SessionConfig) ProtoMessage() {}
func (x *SessionConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_dispatcher_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SessionConfig.ProtoReflect.Descriptor instead.
func (*SessionConfig) Descriptor() ([]byte, []int) {
return file_app_dispatcher_config_proto_rawDescGZIP(), []int{0}
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Settings *SessionConfig `protobuf:"bytes,1,opt,name=settings,proto3" json:"settings,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_dispatcher_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_dispatcher_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_dispatcher_config_proto_rawDescGZIP(), []int{1}
}
func (x *Config) GetSettings() *SessionConfig {
if x != nil {
return x.Settings
}
return nil
}
var File_app_dispatcher_config_proto protoreflect.FileDescriptor
var file_app_dispatcher_config_proto_rawDesc = []byte{
0x0a, 0x1b, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,
0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x69,
0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x22, 0x15, 0x0a, 0x0d, 0x53, 0x65, 0x73, 0x73,
0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22,
0x4e, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x44, 0x0a, 0x08, 0x73, 0x65, 0x74,
0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x69, 0x73,
0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42,
0x5c, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,
0x50, 0x01, 0x5a, 0x1d, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f,
0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65,
0x72, 0xaa, 0x02, 0x19, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41,
0x70, 0x70, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_dispatcher_config_proto_rawDescOnce sync.Once
file_app_dispatcher_config_proto_rawDescData = file_app_dispatcher_config_proto_rawDesc
)
func file_app_dispatcher_config_proto_rawDescGZIP() []byte {
file_app_dispatcher_config_proto_rawDescOnce.Do(func() {
file_app_dispatcher_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_dispatcher_config_proto_rawDescData)
})
return file_app_dispatcher_config_proto_rawDescData
}
var file_app_dispatcher_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_app_dispatcher_config_proto_goTypes = []interface{}{
(*SessionConfig)(nil), // 0: v2ray.core.app.dispatcher.SessionConfig
(*Config)(nil), // 1: v2ray.core.app.dispatcher.Config
}
var file_app_dispatcher_config_proto_depIdxs = []int32{
0, // 0: v2ray.core.app.dispatcher.Config.settings:type_name -> v2ray.core.app.dispatcher.SessionConfig
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_app_dispatcher_config_proto_init() }
func file_app_dispatcher_config_proto_init() {
if File_app_dispatcher_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_dispatcher_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SessionConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_dispatcher_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_dispatcher_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_app_dispatcher_config_proto_goTypes,
DependencyIndexes: file_app_dispatcher_config_proto_depIdxs,
MessageInfos: file_app_dispatcher_config_proto_msgTypes,
}.Build()
File_app_dispatcher_config_proto = out.File
file_app_dispatcher_config_proto_rawDesc = nil
file_app_dispatcher_config_proto_goTypes = nil
file_app_dispatcher_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/app/dispatcher/config.proto 0000664 0000000 0000000 00000000530 13774574720 0021051 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.app.dispatcher;
option csharp_namespace = "V2Ray.Core.App.Dispatcher";
option go_package = "v2ray.com/core/app/dispatcher";
option java_package = "com.v2ray.core.app.dispatcher";
option java_multiple_files = true;
message SessionConfig {
reserved 1;
}
message Config {
SessionConfig settings = 1;
}
v2ray-core-4.34.0/app/dispatcher/default.go 0000664 0000000 0000000 00000016242 13774574720 0020501 0 ustar 00root root 0000000 0000000 // +build !confonly
package dispatcher
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"strings"
"sync"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/session"
"v2ray.com/core/features/outbound"
"v2ray.com/core/features/policy"
"v2ray.com/core/features/routing"
routing_session "v2ray.com/core/features/routing/session"
"v2ray.com/core/features/stats"
"v2ray.com/core/transport"
"v2ray.com/core/transport/pipe"
)
var (
errSniffingTimeout = newError("timeout on sniffing")
)
type cachedReader struct {
sync.Mutex
reader *pipe.Reader
cache buf.MultiBuffer
}
func (r *cachedReader) Cache(b *buf.Buffer) {
mb, _ := r.reader.ReadMultiBufferTimeout(time.Millisecond * 100)
r.Lock()
if !mb.IsEmpty() {
r.cache, _ = buf.MergeMulti(r.cache, mb)
}
b.Clear()
rawBytes := b.Extend(buf.Size)
n := r.cache.Copy(rawBytes)
b.Resize(0, int32(n))
r.Unlock()
}
func (r *cachedReader) readInternal() buf.MultiBuffer {
r.Lock()
defer r.Unlock()
if r.cache != nil && !r.cache.IsEmpty() {
mb := r.cache
r.cache = nil
return mb
}
return nil
}
func (r *cachedReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
mb := r.readInternal()
if mb != nil {
return mb, nil
}
return r.reader.ReadMultiBuffer()
}
func (r *cachedReader) ReadMultiBufferTimeout(timeout time.Duration) (buf.MultiBuffer, error) {
mb := r.readInternal()
if mb != nil {
return mb, nil
}
return r.reader.ReadMultiBufferTimeout(timeout)
}
func (r *cachedReader) Interrupt() {
r.Lock()
if r.cache != nil {
r.cache = buf.ReleaseMulti(r.cache)
}
r.Unlock()
r.reader.Interrupt()
}
// DefaultDispatcher is a default implementation of Dispatcher.
type DefaultDispatcher struct {
ohm outbound.Manager
router routing.Router
policy policy.Manager
stats stats.Manager
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
d := new(DefaultDispatcher)
if err := core.RequireFeatures(ctx, func(om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager) error {
return d.Init(config.(*Config), om, router, pm, sm)
}); err != nil {
return nil, err
}
return d, nil
}))
}
// Init initializes DefaultDispatcher.
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager) error {
d.ohm = om
d.router = router
d.policy = pm
d.stats = sm
return nil
}
// Type implements common.HasType.
func (*DefaultDispatcher) Type() interface{} {
return routing.DispatcherType()
}
// Start implements common.Runnable.
func (*DefaultDispatcher) Start() error {
return nil
}
// Close implements common.Closable.
func (*DefaultDispatcher) Close() error { return nil }
func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *transport.Link) {
opt := pipe.OptionsFromContext(ctx)
uplinkReader, uplinkWriter := pipe.New(opt...)
downlinkReader, downlinkWriter := pipe.New(opt...)
inboundLink := &transport.Link{
Reader: downlinkReader,
Writer: uplinkWriter,
}
outboundLink := &transport.Link{
Reader: uplinkReader,
Writer: downlinkWriter,
}
sessionInbound := session.InboundFromContext(ctx)
var user *protocol.MemoryUser
if sessionInbound != nil {
user = sessionInbound.User
}
if user != nil && len(user.Email) > 0 {
p := d.policy.ForLevel(user.Level)
if p.Stats.UserUplink {
name := "user>>>" + user.Email + ">>>traffic>>>uplink"
if c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
inboundLink.Writer = &SizeStatWriter{
Counter: c,
Writer: inboundLink.Writer,
}
}
}
if p.Stats.UserDownlink {
name := "user>>>" + user.Email + ">>>traffic>>>downlink"
if c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
outboundLink.Writer = &SizeStatWriter{
Counter: c,
Writer: outboundLink.Writer,
}
}
}
}
return inboundLink, outboundLink
}
func shouldOverride(result SniffResult, domainOverride []string) bool {
for _, p := range domainOverride {
if strings.HasPrefix(result.Protocol(), p) {
return true
}
}
return false
}
// Dispatch implements routing.Dispatcher.
func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destination) (*transport.Link, error) {
if !destination.IsValid() {
panic("Dispatcher: Invalid destination.")
}
ob := &session.Outbound{
Target: destination,
}
ctx = session.ContextWithOutbound(ctx, ob)
inbound, outbound := d.getLink(ctx)
content := session.ContentFromContext(ctx)
if content == nil {
content = new(session.Content)
ctx = session.ContextWithContent(ctx, content)
}
sniffingRequest := content.SniffingRequest
if destination.Network != net.Network_TCP || !sniffingRequest.Enabled {
go d.routedDispatch(ctx, outbound, destination)
} else {
go func() {
cReader := &cachedReader{
reader: outbound.Reader.(*pipe.Reader),
}
outbound.Reader = cReader
result, err := sniffer(ctx, cReader)
if err == nil {
content.Protocol = result.Protocol()
}
if err == nil && shouldOverride(result, sniffingRequest.OverrideDestinationForProtocol) {
domain := result.Domain()
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
destination.Address = net.ParseAddress(domain)
ob.Target = destination
}
d.routedDispatch(ctx, outbound, destination)
}()
}
return inbound, nil
}
func sniffer(ctx context.Context, cReader *cachedReader) (SniffResult, error) {
payload := buf.New()
defer payload.Release()
sniffer := NewSniffer()
totalAttempt := 0
for {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
totalAttempt++
if totalAttempt > 2 {
return nil, errSniffingTimeout
}
cReader.Cache(payload)
if !payload.IsEmpty() {
result, err := sniffer.Sniff(payload.Bytes())
if err != common.ErrNoClue {
return result, err
}
}
if payload.IsFull() {
return nil, errUnknownContent
}
}
}
}
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
var handler outbound.Handler
if d.router != nil {
if route, err := d.router.PickRoute(routing_session.AsRoutingContext(ctx)); err == nil {
tag := route.GetOutboundTag()
if h := d.ohm.GetHandler(tag); h != nil {
newError("taking detour [", tag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
handler = h
} else {
newError("non existing tag: ", tag).AtWarning().WriteToLog(session.ExportIDToError(ctx))
}
} else {
newError("default route for ", destination).WriteToLog(session.ExportIDToError(ctx))
}
}
if handler == nil {
handler = d.ohm.GetDefaultHandler()
}
if handler == nil {
newError("default outbound handler not exist").WriteToLog(session.ExportIDToError(ctx))
common.Close(link.Writer)
common.Interrupt(link.Reader)
return
}
if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil {
if tag := handler.Tag(); tag != "" {
accessMessage.Detour = tag
}
log.Record(accessMessage)
}
handler.Dispatch(ctx, link)
}
v2ray-core-4.34.0/app/dispatcher/dispatcher.go 0000664 0000000 0000000 00000000144 13774574720 0021175 0 ustar 00root root 0000000 0000000 // +build !confonly
package dispatcher
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/app/dispatcher/errors.generated.go 0000664 0000000 0000000 00000000320 13774574720 0022314 0 ustar 00root root 0000000 0000000 package dispatcher
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/app/dispatcher/sniffer.go 0000664 0000000 0000000 00000002234 13774574720 0020505 0 ustar 00root root 0000000 0000000 // +build !confonly
package dispatcher
import (
"v2ray.com/core/common"
"v2ray.com/core/common/protocol/bittorrent"
"v2ray.com/core/common/protocol/http"
"v2ray.com/core/common/protocol/tls"
)
type SniffResult interface {
Protocol() string
Domain() string
}
type protocolSniffer func([]byte) (SniffResult, error)
type Sniffer struct {
sniffer []protocolSniffer
}
func NewSniffer() *Sniffer {
return &Sniffer{
sniffer: []protocolSniffer{
func(b []byte) (SniffResult, error) { return http.SniffHTTP(b) },
func(b []byte) (SniffResult, error) { return tls.SniffTLS(b) },
func(b []byte) (SniffResult, error) { return bittorrent.SniffBittorrent(b) },
},
}
}
var errUnknownContent = newError("unknown content")
func (s *Sniffer) Sniff(payload []byte) (SniffResult, error) {
var pendingSniffer []protocolSniffer
for _, s := range s.sniffer {
result, err := s(payload)
if err == common.ErrNoClue {
pendingSniffer = append(pendingSniffer, s)
continue
}
if err == nil && result != nil {
return result, nil
}
}
if len(pendingSniffer) > 0 {
s.sniffer = pendingSniffer
return nil, common.ErrNoClue
}
return nil, errUnknownContent
}
v2ray-core-4.34.0/app/dispatcher/stats.go 0000664 0000000 0000000 00000000766 13774574720 0020217 0 ustar 00root root 0000000 0000000 // +build !confonly
package dispatcher
import (
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/features/stats"
)
type SizeStatWriter struct {
Counter stats.Counter
Writer buf.Writer
}
func (w *SizeStatWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
w.Counter.Add(int64(mb.Len()))
return w.Writer.WriteMultiBuffer(mb)
}
func (w *SizeStatWriter) Close() error {
return common.Close(w.Writer)
}
func (w *SizeStatWriter) Interrupt() {
common.Interrupt(w.Writer)
}
v2ray-core-4.34.0/app/dispatcher/stats_test.go 0000664 0000000 0000000 00000001421 13774574720 0021243 0 ustar 00root root 0000000 0000000 package dispatcher_test
import (
"testing"
. "v2ray.com/core/app/dispatcher"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
)
type TestCounter int64
func (c *TestCounter) Value() int64 {
return int64(*c)
}
func (c *TestCounter) Add(v int64) int64 {
x := int64(*c) + v
*c = TestCounter(x)
return x
}
func (c *TestCounter) Set(v int64) int64 {
*c = TestCounter(v)
return v
}
func TestStatsWriter(t *testing.T) {
var c TestCounter
writer := &SizeStatWriter{
Counter: &c,
Writer: buf.Discard,
}
mb := buf.MergeBytes(nil, []byte("abcd"))
common.Must(writer.WriteMultiBuffer(mb))
mb = buf.MergeBytes(nil, []byte("efg"))
common.Must(writer.WriteMultiBuffer(mb))
if c.Value() != 7 {
t.Fatal("unexpected counter value. want 7, but got ", c.Value())
}
}
v2ray-core-4.34.0/app/dns/ 0000775 0000000 0000000 00000000000 13774574720 0015157 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/dns/config.go 0000664 0000000 0000000 00000004065 13774574720 0016760 0 ustar 00root root 0000000 0000000 // +build !confonly
package dns
import (
"v2ray.com/core/common/net"
"v2ray.com/core/common/strmatcher"
"v2ray.com/core/common/uuid"
)
var typeMap = map[DomainMatchingType]strmatcher.Type{
DomainMatchingType_Full: strmatcher.Full,
DomainMatchingType_Subdomain: strmatcher.Domain,
DomainMatchingType_Keyword: strmatcher.Substr,
DomainMatchingType_Regex: strmatcher.Regex,
}
// References:
// https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml
// https://unix.stackexchange.com/questions/92441/whats-the-difference-between-local-home-and-lan
var localTLDsAndDotlessDomains = []*NameServer_PriorityDomain{
{Type: DomainMatchingType_Regex, Domain: "^[^.]+$"}, // This will only match domains without any dot
{Type: DomainMatchingType_Subdomain, Domain: "local"},
{Type: DomainMatchingType_Subdomain, Domain: "localdomain"},
{Type: DomainMatchingType_Subdomain, Domain: "localhost"},
{Type: DomainMatchingType_Subdomain, Domain: "lan"},
{Type: DomainMatchingType_Subdomain, Domain: "home.arpa"},
{Type: DomainMatchingType_Subdomain, Domain: "example"},
{Type: DomainMatchingType_Subdomain, Domain: "invalid"},
{Type: DomainMatchingType_Subdomain, Domain: "test"},
}
var localTLDsAndDotlessDomainsRule = &NameServer_OriginalRule{
Rule: "geosite:private",
Size: uint32(len(localTLDsAndDotlessDomains)),
}
func toStrMatcher(t DomainMatchingType, domain string) (strmatcher.Matcher, error) {
strMType, f := typeMap[t]
if !f {
return nil, newError("unknown mapping type", t).AtWarning()
}
matcher, err := strMType.New(domain)
if err != nil {
return nil, newError("failed to create str matcher").Base(err)
}
return matcher, nil
}
func toNetIP(addrs []net.Address) ([]net.IP, error) {
ips := make([]net.IP, 0, len(addrs))
for _, addr := range addrs {
if addr.Family().IsIP() {
ips = append(ips, addr.IP())
} else {
return nil, newError("Failed to convert address", addr, "to Net IP.").AtWarning()
}
}
return ips, nil
}
func generateRandomTag() string {
id := uuid.New()
return "v2ray.system." + id.String()
}
v2ray-core-4.34.0/app/dns/config.pb.go 0000664 0000000 0000000 00000061715 13774574720 0017365 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.14.0
// source: app/dns/config.proto
package dns
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
router "v2ray.com/core/app/router"
net "v2ray.com/core/common/net"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type DomainMatchingType int32
const (
DomainMatchingType_Full DomainMatchingType = 0
DomainMatchingType_Subdomain DomainMatchingType = 1
DomainMatchingType_Keyword DomainMatchingType = 2
DomainMatchingType_Regex DomainMatchingType = 3
)
// Enum value maps for DomainMatchingType.
var (
DomainMatchingType_name = map[int32]string{
0: "Full",
1: "Subdomain",
2: "Keyword",
3: "Regex",
}
DomainMatchingType_value = map[string]int32{
"Full": 0,
"Subdomain": 1,
"Keyword": 2,
"Regex": 3,
}
)
func (x DomainMatchingType) Enum() *DomainMatchingType {
p := new(DomainMatchingType)
*p = x
return p
}
func (x DomainMatchingType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (DomainMatchingType) Descriptor() protoreflect.EnumDescriptor {
return file_app_dns_config_proto_enumTypes[0].Descriptor()
}
func (DomainMatchingType) Type() protoreflect.EnumType {
return &file_app_dns_config_proto_enumTypes[0]
}
func (x DomainMatchingType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use DomainMatchingType.Descriptor instead.
func (DomainMatchingType) EnumDescriptor() ([]byte, []int) {
return file_app_dns_config_proto_rawDescGZIP(), []int{0}
}
type NameServer struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Address *net.Endpoint `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
ClientIp []byte `protobuf:"bytes,5,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
Geoip []*router.GeoIP `protobuf:"bytes,3,rep,name=geoip,proto3" json:"geoip,omitempty"`
OriginalRules []*NameServer_OriginalRule `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
}
func (x *NameServer) Reset() {
*x = NameServer{}
if protoimpl.UnsafeEnabled {
mi := &file_app_dns_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *NameServer) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NameServer) ProtoMessage() {}
func (x *NameServer) ProtoReflect() protoreflect.Message {
mi := &file_app_dns_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NameServer.ProtoReflect.Descriptor instead.
func (*NameServer) Descriptor() ([]byte, []int) {
return file_app_dns_config_proto_rawDescGZIP(), []int{0}
}
func (x *NameServer) GetAddress() *net.Endpoint {
if x != nil {
return x.Address
}
return nil
}
func (x *NameServer) GetClientIp() []byte {
if x != nil {
return x.ClientIp
}
return nil
}
func (x *NameServer) GetPrioritizedDomain() []*NameServer_PriorityDomain {
if x != nil {
return x.PrioritizedDomain
}
return nil
}
func (x *NameServer) GetGeoip() []*router.GeoIP {
if x != nil {
return x.Geoip
}
return nil
}
func (x *NameServer) GetOriginalRules() []*NameServer_OriginalRule {
if x != nil {
return x.OriginalRules
}
return nil
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Nameservers used by this DNS. Only traditional UDP servers are support at
// the moment. A special value 'localhost' as a domain address can be set to
// use DNS on local system.
//
// Deprecated: Do not use.
NameServers []*net.Endpoint `protobuf:"bytes,1,rep,name=NameServers,proto3" json:"NameServers,omitempty"`
// NameServer list used by this DNS client.
NameServer []*NameServer `protobuf:"bytes,5,rep,name=name_server,json=nameServer,proto3" json:"name_server,omitempty"`
// Static hosts. Domain to IP.
// Deprecated. Use static_hosts.
//
// Deprecated: Do not use.
Hosts map[string]*net.IPOrDomain `protobuf:"bytes,2,rep,name=Hosts,proto3" json:"Hosts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes
// (IPv6).
ClientIp []byte `protobuf:"bytes,3,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
StaticHosts []*Config_HostMapping `protobuf:"bytes,4,rep,name=static_hosts,json=staticHosts,proto3" json:"static_hosts,omitempty"`
// Tag is the inbound tag of DNS client.
Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_dns_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_dns_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_dns_config_proto_rawDescGZIP(), []int{1}
}
// Deprecated: Do not use.
func (x *Config) GetNameServers() []*net.Endpoint {
if x != nil {
return x.NameServers
}
return nil
}
func (x *Config) GetNameServer() []*NameServer {
if x != nil {
return x.NameServer
}
return nil
}
// Deprecated: Do not use.
func (x *Config) GetHosts() map[string]*net.IPOrDomain {
if x != nil {
return x.Hosts
}
return nil
}
func (x *Config) GetClientIp() []byte {
if x != nil {
return x.ClientIp
}
return nil
}
func (x *Config) GetStaticHosts() []*Config_HostMapping {
if x != nil {
return x.StaticHosts
}
return nil
}
func (x *Config) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
type NameServer_PriorityDomain struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type DomainMatchingType `protobuf:"varint,1,opt,name=type,proto3,enum=v2ray.core.app.dns.DomainMatchingType" json:"type,omitempty"`
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
}
func (x *NameServer_PriorityDomain) Reset() {
*x = NameServer_PriorityDomain{}
if protoimpl.UnsafeEnabled {
mi := &file_app_dns_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *NameServer_PriorityDomain) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NameServer_PriorityDomain) ProtoMessage() {}
func (x *NameServer_PriorityDomain) ProtoReflect() protoreflect.Message {
mi := &file_app_dns_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NameServer_PriorityDomain.ProtoReflect.Descriptor instead.
func (*NameServer_PriorityDomain) Descriptor() ([]byte, []int) {
return file_app_dns_config_proto_rawDescGZIP(), []int{0, 0}
}
func (x *NameServer_PriorityDomain) GetType() DomainMatchingType {
if x != nil {
return x.Type
}
return DomainMatchingType_Full
}
func (x *NameServer_PriorityDomain) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
type NameServer_OriginalRule struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Rule string `protobuf:"bytes,1,opt,name=rule,proto3" json:"rule,omitempty"`
Size uint32 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"`
}
func (x *NameServer_OriginalRule) Reset() {
*x = NameServer_OriginalRule{}
if protoimpl.UnsafeEnabled {
mi := &file_app_dns_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *NameServer_OriginalRule) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NameServer_OriginalRule) ProtoMessage() {}
func (x *NameServer_OriginalRule) ProtoReflect() protoreflect.Message {
mi := &file_app_dns_config_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NameServer_OriginalRule.ProtoReflect.Descriptor instead.
func (*NameServer_OriginalRule) Descriptor() ([]byte, []int) {
return file_app_dns_config_proto_rawDescGZIP(), []int{0, 1}
}
func (x *NameServer_OriginalRule) GetRule() string {
if x != nil {
return x.Rule
}
return ""
}
func (x *NameServer_OriginalRule) GetSize() uint32 {
if x != nil {
return x.Size
}
return 0
}
type Config_HostMapping struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type DomainMatchingType `protobuf:"varint,1,opt,name=type,proto3,enum=v2ray.core.app.dns.DomainMatchingType" json:"type,omitempty"`
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
Ip [][]byte `protobuf:"bytes,3,rep,name=ip,proto3" json:"ip,omitempty"`
// ProxiedDomain indicates the mapped domain has the same IP address on this
// domain. V2Ray will use this domain for IP queries. This field is only
// effective if ip is empty.
ProxiedDomain string `protobuf:"bytes,4,opt,name=proxied_domain,json=proxiedDomain,proto3" json:"proxied_domain,omitempty"`
}
func (x *Config_HostMapping) Reset() {
*x = Config_HostMapping{}
if protoimpl.UnsafeEnabled {
mi := &file_app_dns_config_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config_HostMapping) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config_HostMapping) ProtoMessage() {}
func (x *Config_HostMapping) ProtoReflect() protoreflect.Message {
mi := &file_app_dns_config_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config_HostMapping.ProtoReflect.Descriptor instead.
func (*Config_HostMapping) Descriptor() ([]byte, []int) {
return file_app_dns_config_proto_rawDescGZIP(), []int{1, 1}
}
func (x *Config_HostMapping) GetType() DomainMatchingType {
if x != nil {
return x.Type
}
return DomainMatchingType_Full
}
func (x *Config_HostMapping) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
func (x *Config_HostMapping) GetIp() [][]byte {
if x != nil {
return x.Ip
}
return nil
}
func (x *Config_HostMapping) GetProxiedDomain() string {
if x != nil {
return x.ProxiedDomain
}
return ""
}
var File_app_dns_config_proto protoreflect.FileDescriptor
var file_app_dns_config_proto_rawDesc = []byte{
0x0a, 0x14, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74,
0x2f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x1a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe8, 0x03, 0x0a, 0x0a,
0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x07, 0x61, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x07, 0x61, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f,
0x69, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
0x49, 0x70, 0x12, 0x5c, 0x0a, 0x12, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65,
0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d,
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50,
0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x11, 0x70,
0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x12, 0x32, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x1c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x67,
0x65, 0x6f, 0x69, 0x70, 0x12, 0x52, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e,
0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69,
0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69,
0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x1a, 0x64, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f,
0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3a, 0x0a, 0x04, 0x74, 0x79,
0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65,
0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36,
0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12,
0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75,
0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0xc3, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x12, 0x45, 0x0a, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73,
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45,
0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x4e, 0x61, 0x6d,
0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x3f, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65,
0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64,
0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a, 0x6e,
0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x05, 0x48, 0x6f, 0x73,
0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42,
0x02, 0x18, 0x01, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c,
0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63,
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x49, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69,
0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64,
0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61,
0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73,
0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x74, 0x61, 0x67, 0x1a, 0x5b, 0x0a, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74,
0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x6b, 0x65, 0x79, 0x12, 0x37, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72,
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x1a, 0x98, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e,
0x67, 0x12, 0x3a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68,
0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a,
0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28,
0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64,
0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70,
0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2a, 0x45, 0x0a, 0x12,
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79,
0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09,
0x53, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4b,
0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65,
0x78, 0x10, 0x03, 0x42, 0x47, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a,
0x16, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f,
0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x12, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,
0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_dns_config_proto_rawDescOnce sync.Once
file_app_dns_config_proto_rawDescData = file_app_dns_config_proto_rawDesc
)
func file_app_dns_config_proto_rawDescGZIP() []byte {
file_app_dns_config_proto_rawDescOnce.Do(func() {
file_app_dns_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_dns_config_proto_rawDescData)
})
return file_app_dns_config_proto_rawDescData
}
var file_app_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_app_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_app_dns_config_proto_goTypes = []interface{}{
(DomainMatchingType)(0), // 0: v2ray.core.app.dns.DomainMatchingType
(*NameServer)(nil), // 1: v2ray.core.app.dns.NameServer
(*Config)(nil), // 2: v2ray.core.app.dns.Config
(*NameServer_PriorityDomain)(nil), // 3: v2ray.core.app.dns.NameServer.PriorityDomain
(*NameServer_OriginalRule)(nil), // 4: v2ray.core.app.dns.NameServer.OriginalRule
nil, // 5: v2ray.core.app.dns.Config.HostsEntry
(*Config_HostMapping)(nil), // 6: v2ray.core.app.dns.Config.HostMapping
(*net.Endpoint)(nil), // 7: v2ray.core.common.net.Endpoint
(*router.GeoIP)(nil), // 8: v2ray.core.app.router.GeoIP
(*net.IPOrDomain)(nil), // 9: v2ray.core.common.net.IPOrDomain
}
var file_app_dns_config_proto_depIdxs = []int32{
7, // 0: v2ray.core.app.dns.NameServer.address:type_name -> v2ray.core.common.net.Endpoint
3, // 1: v2ray.core.app.dns.NameServer.prioritized_domain:type_name -> v2ray.core.app.dns.NameServer.PriorityDomain
8, // 2: v2ray.core.app.dns.NameServer.geoip:type_name -> v2ray.core.app.router.GeoIP
4, // 3: v2ray.core.app.dns.NameServer.original_rules:type_name -> v2ray.core.app.dns.NameServer.OriginalRule
7, // 4: v2ray.core.app.dns.Config.NameServers:type_name -> v2ray.core.common.net.Endpoint
1, // 5: v2ray.core.app.dns.Config.name_server:type_name -> v2ray.core.app.dns.NameServer
5, // 6: v2ray.core.app.dns.Config.Hosts:type_name -> v2ray.core.app.dns.Config.HostsEntry
6, // 7: v2ray.core.app.dns.Config.static_hosts:type_name -> v2ray.core.app.dns.Config.HostMapping
0, // 8: v2ray.core.app.dns.NameServer.PriorityDomain.type:type_name -> v2ray.core.app.dns.DomainMatchingType
9, // 9: v2ray.core.app.dns.Config.HostsEntry.value:type_name -> v2ray.core.common.net.IPOrDomain
0, // 10: v2ray.core.app.dns.Config.HostMapping.type:type_name -> v2ray.core.app.dns.DomainMatchingType
11, // [11:11] is the sub-list for method output_type
11, // [11:11] is the sub-list for method input_type
11, // [11:11] is the sub-list for extension type_name
11, // [11:11] is the sub-list for extension extendee
0, // [0:11] is the sub-list for field type_name
}
func init() { file_app_dns_config_proto_init() }
func file_app_dns_config_proto_init() {
if File_app_dns_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_dns_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NameServer); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_dns_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_dns_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NameServer_PriorityDomain); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_dns_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NameServer_OriginalRule); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_dns_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config_HostMapping); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_dns_config_proto_rawDesc,
NumEnums: 1,
NumMessages: 6,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_app_dns_config_proto_goTypes,
DependencyIndexes: file_app_dns_config_proto_depIdxs,
EnumInfos: file_app_dns_config_proto_enumTypes,
MessageInfos: file_app_dns_config_proto_msgTypes,
}.Build()
File_app_dns_config_proto = out.File
file_app_dns_config_proto_rawDesc = nil
file_app_dns_config_proto_goTypes = nil
file_app_dns_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/app/dns/config.proto 0000664 0000000 0000000 00000003542 13774574720 0017515 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.app.dns;
option csharp_namespace = "V2Ray.Core.App.Dns";
option go_package = "v2ray.com/core/app/dns";
option java_package = "com.v2ray.core.app.dns";
option java_multiple_files = true;
import "common/net/address.proto";
import "common/net/destination.proto";
import "app/router/config.proto";
message NameServer {
v2ray.core.common.net.Endpoint address = 1;
bytes client_ip = 5;
message PriorityDomain {
DomainMatchingType type = 1;
string domain = 2;
}
message OriginalRule {
string rule = 1;
uint32 size = 2;
}
repeated PriorityDomain prioritized_domain = 2;
repeated v2ray.core.app.router.GeoIP geoip = 3;
repeated OriginalRule original_rules = 4;
}
enum DomainMatchingType {
Full = 0;
Subdomain = 1;
Keyword = 2;
Regex = 3;
}
message Config {
// Nameservers used by this DNS. Only traditional UDP servers are support at
// the moment. A special value 'localhost' as a domain address can be set to
// use DNS on local system.
repeated v2ray.core.common.net.Endpoint NameServers = 1 [deprecated = true];
// NameServer list used by this DNS client.
repeated NameServer name_server = 5;
// Static hosts. Domain to IP.
// Deprecated. Use static_hosts.
map Hosts = 2 [deprecated = true];
// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes
// (IPv6).
bytes client_ip = 3;
message HostMapping {
DomainMatchingType type = 1;
string domain = 2;
repeated bytes ip = 3;
// ProxiedDomain indicates the mapped domain has the same IP address on this
// domain. V2Ray will use this domain for IP queries. This field is only
// effective if ip is empty.
string proxied_domain = 4;
}
repeated HostMapping static_hosts = 4;
// Tag is the inbound tag of DNS client.
string tag = 6;
}
v2ray-core-4.34.0/app/dns/dns.go 0000664 0000000 0000000 00000015676 13774574720 0016311 0 ustar 00root root 0000000 0000000 // +build !confonly
// Package dns is an implementation of core.DNS feature.
package dns
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"fmt"
"sync"
"v2ray.com/core/app/router"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/net"
"v2ray.com/core/common/session"
"v2ray.com/core/common/strmatcher"
"v2ray.com/core/features"
"v2ray.com/core/features/dns"
)
// DNS is a DNS rely server.
type DNS struct {
sync.Mutex
tag string
hosts *StaticHosts
clients []*Client
domainMatcher strmatcher.IndexMatcher
matcherInfos []DomainMatcherInfo
}
// DomainMatcherInfo contains information attached to index returned by Server.domainMatcher
type DomainMatcherInfo struct {
clientIdx uint16
domainRuleIdx uint16
}
// New creates a new DNS server with given configuration.
func New(ctx context.Context, config *Config) (*DNS, error) {
var tag string
if len(config.Tag) > 0 {
tag = config.Tag
} else {
tag = generateRandomTag()
}
var clientIP net.IP
switch len(config.ClientIp) {
case 0, net.IPv4len, net.IPv6len:
clientIP = net.IP(config.ClientIp)
default:
return nil, newError("unexpected client IP length ", len(config.ClientIp))
}
hosts, err := NewStaticHosts(config.StaticHosts, config.Hosts)
if err != nil {
return nil, newError("failed to create hosts").Base(err)
}
clients := []*Client{}
domainRuleCount := 0
for _, ns := range config.NameServer {
domainRuleCount += len(ns.PrioritizedDomain)
}
// Fixes https://github.com/v2fly/v2ray-core/issues/529
// Compatible with `localhost` nameserver specified in config file
domainRuleCount += len(localTLDsAndDotlessDomains)
// MatcherInfos is ensured to cover the maximum index domainMatcher could return, where matcher's index starts from 1
matcherInfos := make([]DomainMatcherInfo, domainRuleCount+1)
domainMatcher := &strmatcher.MatcherGroup{}
geoipContainer := router.GeoIPMatcherContainer{}
for _, endpoint := range config.NameServers {
features.PrintDeprecatedFeatureWarning("simple DNS server")
client, err := NewSimpleClient(ctx, endpoint, clientIP)
if err != nil {
return nil, newError("failed to create client").Base(err)
}
clients = append(clients, client)
}
for _, ns := range config.NameServer {
clientIdx := len(clients)
updateDomain := func(domainRule strmatcher.Matcher, originalRuleIdx int) error {
midx := domainMatcher.Add(domainRule)
matcherInfos[midx] = DomainMatcherInfo{
clientIdx: uint16(clientIdx),
domainRuleIdx: uint16(originalRuleIdx),
}
return nil
}
myClientIP := clientIP
switch len(ns.ClientIp) {
case net.IPv4len, net.IPv6len:
myClientIP = net.IP(ns.ClientIp)
}
client, err := NewClient(ctx, ns, myClientIP, geoipContainer, updateDomain)
if err != nil {
return nil, newError("failed to create client").Base(err)
}
clients = append(clients, client)
}
if len(clients) == 0 {
clients = append(clients, NewLocalDNSClient())
}
return &DNS{
tag: tag,
hosts: hosts,
clients: clients,
domainMatcher: domainMatcher,
matcherInfos: matcherInfos,
}, nil
}
// Type implements common.HasType.
func (*DNS) Type() interface{} {
return dns.ClientType()
}
// Start implements common.Runnable.
func (s *DNS) Start() error {
return nil
}
// Close implements common.Closable.
func (s *DNS) Close() error {
return nil
}
// IsOwnLink implements proxy.dns.ownLinkVerifier
func (s *DNS) IsOwnLink(ctx context.Context) bool {
inbound := session.InboundFromContext(ctx)
return inbound != nil && inbound.Tag == s.tag
}
// LookupIP implements dns.Client.
func (s *DNS) LookupIP(domain string) ([]net.IP, error) {
return s.lookupIPInternal(domain, IPOption{
IPv4Enable: true,
IPv6Enable: true,
})
}
// LookupIPv4 implements dns.IPv4Lookup.
func (s *DNS) LookupIPv4(domain string) ([]net.IP, error) {
return s.lookupIPInternal(domain, IPOption{
IPv4Enable: true,
IPv6Enable: false,
})
}
// LookupIPv6 implements dns.IPv6Lookup.
func (s *DNS) LookupIPv6(domain string) ([]net.IP, error) {
return s.lookupIPInternal(domain, IPOption{
IPv4Enable: false,
IPv6Enable: true,
})
}
func (s *DNS) lookupIPInternal(domain string, option IPOption) ([]net.IP, error) {
if domain == "" {
return nil, newError("empty domain name")
}
// Normalize the FQDN form query
if domain[len(domain)-1] == '.' {
domain = domain[:len(domain)-1]
}
// Static host lookup
switch addrs := s.hosts.Lookup(domain, option); {
case addrs == nil: // Domain not recorded in static host
break
case len(addrs) == 0: // Domain recorded, but no valid IP returned (e.g. IPv4 address with only IPv6 enabled)
return nil, dns.ErrEmptyResponse
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Domain replacement
newError("domain replaced: ", domain, " -> ", addrs[0].Domain()).WriteToLog()
domain = addrs[0].Domain()
default: // Successfully found ip records in static host
newError("returning ", len(addrs), " IPs for domain ", domain).WriteToLog()
return toNetIP(addrs)
}
// Name servers lookup
errs := []error{}
ctx := session.ContextWithInbound(context.Background(), &session.Inbound{Tag: s.tag})
for _, client := range s.sortClients(domain) {
ips, err := client.QueryIP(ctx, domain, option)
if len(ips) > 0 {
return ips, nil
}
if err != nil {
newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog()
errs = append(errs, err)
}
if err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch {
return nil, err
}
}
return nil, newError("returning nil for domain ", domain).Base(errors.Combine(errs...))
}
func (s *DNS) sortClients(domain string) []*Client {
clients := make([]*Client, 0, len(s.clients))
clientUsed := make([]bool, len(s.clients))
clientNames := make([]string, 0, len(s.clients))
domainRules := []string{}
// Priority domain matching
for _, match := range s.domainMatcher.Match(domain) {
info := s.matcherInfos[match]
client := s.clients[info.clientIdx]
domainRule := client.domains[info.domainRuleIdx]
domainRules = append(domainRules, fmt.Sprintf("%s(DNS idx:%d)", domainRule, info.clientIdx))
if clientUsed[info.clientIdx] {
continue
}
clientUsed[info.clientIdx] = true
clients = append(clients, client)
clientNames = append(clientNames, client.Name())
}
// Default round-robin query
for idx, client := range s.clients {
if clientUsed[idx] {
continue
}
clientUsed[idx] = true
clients = append(clients, client)
clientNames = append(clientNames, client.Name())
}
if len(domainRules) > 0 {
newError("domain ", domain, " matches following rules: ", domainRules).AtDebug().WriteToLog()
}
if len(clientNames) > 0 {
newError("domain ", domain, " will use DNS in order: ", clientNames).AtDebug().WriteToLog()
}
return clients
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
}))
}
v2ray-core-4.34.0/app/dns/dns_test.go 0000664 0000000 0000000 00000054105 13774574720 0017336 0 ustar 00root root 0000000 0000000 package dns_test
import (
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/miekg/dns"
"v2ray.com/core"
"v2ray.com/core/app/dispatcher"
. "v2ray.com/core/app/dns"
"v2ray.com/core/app/policy"
"v2ray.com/core/app/proxyman"
_ "v2ray.com/core/app/proxyman/outbound"
"v2ray.com/core/app/router"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/common/serial"
feature_dns "v2ray.com/core/features/dns"
"v2ray.com/core/proxy/freedom"
"v2ray.com/core/testing/servers/udp"
)
type staticHandler struct {
}
func (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
ans := new(dns.Msg)
ans.Id = r.Id
var clientIP net.IP
opt := r.IsEdns0()
if opt != nil {
for _, o := range opt.Option {
if o.Option() == dns.EDNS0SUBNET {
subnet := o.(*dns.EDNS0_SUBNET)
clientIP = subnet.Address
}
}
}
for _, q := range r.Question {
switch {
case q.Name == "google.com." && q.Qtype == dns.TypeA:
if clientIP == nil {
rr, _ := dns.NewRR("google.com. IN A 8.8.8.8")
ans.Answer = append(ans.Answer, rr)
} else {
rr, _ := dns.NewRR("google.com. IN A 8.8.4.4")
ans.Answer = append(ans.Answer, rr)
}
case q.Name == "api.google.com." && q.Qtype == dns.TypeA:
rr, _ := dns.NewRR("api.google.com. IN A 8.8.7.7")
ans.Answer = append(ans.Answer, rr)
case q.Name == "v2.api.google.com." && q.Qtype == dns.TypeA:
rr, _ := dns.NewRR("v2.api.google.com. IN A 8.8.7.8")
ans.Answer = append(ans.Answer, rr)
case q.Name == "facebook.com." && q.Qtype == dns.TypeA:
rr, _ := dns.NewRR("facebook.com. IN A 9.9.9.9")
ans.Answer = append(ans.Answer, rr)
case q.Name == "ipv6.google.com." && q.Qtype == dns.TypeA:
rr, err := dns.NewRR("ipv6.google.com. IN A 8.8.8.7")
common.Must(err)
ans.Answer = append(ans.Answer, rr)
case q.Name == "ipv6.google.com." && q.Qtype == dns.TypeAAAA:
rr, err := dns.NewRR("ipv6.google.com. IN AAAA 2001:4860:4860::8888")
common.Must(err)
ans.Answer = append(ans.Answer, rr)
case q.Name == "notexist.google.com." && q.Qtype == dns.TypeAAAA:
ans.MsgHdr.Rcode = dns.RcodeNameError
case q.Name == "hostname." && q.Qtype == dns.TypeA:
rr, _ := dns.NewRR("hostname. IN A 127.0.0.1")
ans.Answer = append(ans.Answer, rr)
case q.Name == "hostname.local." && q.Qtype == dns.TypeA:
rr, _ := dns.NewRR("hostname.local. IN A 127.0.0.1")
ans.Answer = append(ans.Answer, rr)
case q.Name == "hostname.localdomain." && q.Qtype == dns.TypeA:
rr, _ := dns.NewRR("hostname.localdomain. IN A 127.0.0.1")
ans.Answer = append(ans.Answer, rr)
case q.Name == "localhost." && q.Qtype == dns.TypeA:
rr, _ := dns.NewRR("localhost. IN A 127.0.0.2")
ans.Answer = append(ans.Answer, rr)
case q.Name == "localhost-a." && q.Qtype == dns.TypeA:
rr, _ := dns.NewRR("localhost-a. IN A 127.0.0.3")
ans.Answer = append(ans.Answer, rr)
case q.Name == "localhost-b." && q.Qtype == dns.TypeA:
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")
ans.Answer = append(ans.Answer, rr)
}
}
w.WriteMsg(ans)
}
func TestUDPServerSubnet(t *testing.T) {
port := udp.PickPort()
dnsServer := dns.Server{
Addr: "127.0.0.1:" + port.String(),
Net: "udp",
Handler: &staticHandler{},
UDPSize: 1200,
}
go dnsServer.ListenAndServe()
time.Sleep(time.Second)
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&Config{
NameServers: []*net.Endpoint{
{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
},
ClientIp: []byte{7, 8, 9, 10},
}),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(&policy.Config{}),
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
v, err := core.New(config)
common.Must(err)
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
ips, err := client.LookupIP("google.com")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{8, 8, 4, 4}}); r != "" {
t.Fatal(r)
}
}
func TestUDPServer(t *testing.T) {
port := udp.PickPort()
dnsServer := dns.Server{
Addr: "127.0.0.1:" + port.String(),
Net: "udp",
Handler: &staticHandler{},
UDPSize: 1200,
}
go dnsServer.ListenAndServe()
time.Sleep(time.Second)
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&Config{
NameServers: []*net.Endpoint{
{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
},
}),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(&policy.Config{}),
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
v, err := core.New(config)
common.Must(err)
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
{
ips, err := client.LookupIP("google.com")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
t.Fatal(r)
}
}
{
ips, err := client.LookupIP("facebook.com")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{9, 9, 9, 9}}); r != "" {
t.Fatal(r)
}
}
{
_, err := client.LookupIP("notexist.google.com")
if err == nil {
t.Fatal("nil error")
}
if r := feature_dns.RCodeFromError(err); r != uint16(dns.RcodeNameError) {
t.Fatal("expected NameError, but got ", r)
}
}
{
clientv6 := client.(feature_dns.IPv6Lookup)
ips, err := clientv6.LookupIPv6("ipv4only.google.com")
if err != feature_dns.ErrEmptyResponse {
t.Fatal("error: ", err)
}
if len(ips) != 0 {
t.Fatal("ips: ", ips)
}
}
dnsServer.Shutdown()
{
ips, err := client.LookupIP("google.com")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
t.Fatal(r)
}
}
}
func TestPrioritizedDomain(t *testing.T) {
port := udp.PickPort()
dnsServer := dns.Server{
Addr: "127.0.0.1:" + port.String(),
Net: "udp",
Handler: &staticHandler{},
UDPSize: 1200,
}
go dnsServer.ListenAndServe()
time.Sleep(time.Second)
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&Config{
NameServers: []*net.Endpoint{
{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: 9999, /* unreachable */
},
},
NameServer: []*NameServer{
{
Address: &net.Endpoint{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
PrioritizedDomain: []*NameServer_PriorityDomain{
{
Type: DomainMatchingType_Full,
Domain: "google.com",
},
},
},
},
}),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(&policy.Config{}),
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
v, err := core.New(config)
common.Must(err)
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
startTime := time.Now()
{
ips, err := client.LookupIP("google.com")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
t.Fatal(r)
}
}
endTime := time.Now()
if startTime.After(endTime.Add(time.Second * 2)) {
t.Error("DNS query doesn't finish in 2 seconds.")
}
}
func TestUDPServerIPv6(t *testing.T) {
port := udp.PickPort()
dnsServer := dns.Server{
Addr: "127.0.0.1:" + port.String(),
Net: "udp",
Handler: &staticHandler{},
UDPSize: 1200,
}
go dnsServer.ListenAndServe()
time.Sleep(time.Second)
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&Config{
NameServers: []*net.Endpoint{
{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
},
}),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(&policy.Config{}),
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
v, err := core.New(config)
common.Must(err)
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
client6 := client.(feature_dns.IPv6Lookup)
{
ips, err := client6.LookupIPv6("ipv6.google.com")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{32, 1, 72, 96, 72, 96, 0, 0, 0, 0, 0, 0, 0, 0, 136, 136}}); r != "" {
t.Fatal(r)
}
}
}
func TestStaticHostDomain(t *testing.T) {
port := udp.PickPort()
dnsServer := dns.Server{
Addr: "127.0.0.1:" + port.String(),
Net: "udp",
Handler: &staticHandler{},
UDPSize: 1200,
}
go dnsServer.ListenAndServe()
time.Sleep(time.Second)
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&Config{
NameServers: []*net.Endpoint{
{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
},
StaticHosts: []*Config_HostMapping{
{
Type: DomainMatchingType_Full,
Domain: "example.com",
ProxiedDomain: "google.com",
},
},
}),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(&policy.Config{}),
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
v, err := core.New(config)
common.Must(err)
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
{
ips, err := client.LookupIP("example.com")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
t.Fatal(r)
}
}
dnsServer.Shutdown()
}
func TestIPMatch(t *testing.T) {
port := udp.PickPort()
dnsServer := dns.Server{
Addr: "127.0.0.1:" + port.String(),
Net: "udp",
Handler: &staticHandler{},
UDPSize: 1200,
}
go dnsServer.ListenAndServe()
time.Sleep(time.Second)
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&Config{
NameServer: []*NameServer{
// private dns, not match
{
Address: &net.Endpoint{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
Geoip: []*router.GeoIP{
{
CountryCode: "local",
Cidr: []*router.CIDR{
{
// inner ip, will not match
Ip: []byte{192, 168, 11, 1},
Prefix: 32,
},
},
},
},
},
// second dns, match ip
{
Address: &net.Endpoint{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
Geoip: []*router.GeoIP{
{
CountryCode: "test",
Cidr: []*router.CIDR{
{
Ip: []byte{8, 8, 8, 8},
Prefix: 32,
},
},
},
{
CountryCode: "test",
Cidr: []*router.CIDR{
{
Ip: []byte{8, 8, 8, 4},
Prefix: 32,
},
},
},
},
},
},
}),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(&policy.Config{}),
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
v, err := core.New(config)
common.Must(err)
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
startTime := time.Now()
{
ips, err := client.LookupIP("google.com")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
t.Fatal(r)
}
}
endTime := time.Now()
if startTime.After(endTime.Add(time.Second * 2)) {
t.Error("DNS query doesn't finish in 2 seconds.")
}
}
func TestLocalDomain(t *testing.T) {
port := udp.PickPort()
dnsServer := dns.Server{
Addr: "127.0.0.1:" + port.String(),
Net: "udp",
Handler: &staticHandler{},
UDPSize: 1200,
}
go dnsServer.ListenAndServe()
time.Sleep(time.Second)
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&Config{
NameServers: []*net.Endpoint{
{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: 9999, /* unreachable */
},
},
NameServer: []*NameServer{
{
Address: &net.Endpoint{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
PrioritizedDomain: []*NameServer_PriorityDomain{
// Equivalent of dotless:localhost
{Type: DomainMatchingType_Regex, Domain: "^[^.]*localhost[^.]*$"},
},
Geoip: []*router.GeoIP{
{ // Will match localhost, localhost-a and localhost-b,
CountryCode: "local",
Cidr: []*router.CIDR{
{Ip: []byte{127, 0, 0, 2}, Prefix: 32},
{Ip: []byte{127, 0, 0, 3}, Prefix: 32},
{Ip: []byte{127, 0, 0, 4}, Prefix: 32},
},
},
},
},
{
Address: &net.Endpoint{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
PrioritizedDomain: []*NameServer_PriorityDomain{
// Equivalent of dotless: and domain:local
{Type: DomainMatchingType_Regex, Domain: "^[^.]*$"},
{Type: DomainMatchingType_Subdomain, Domain: "local"},
{Type: DomainMatchingType_Subdomain, Domain: "localdomain"},
},
},
},
StaticHosts: []*Config_HostMapping{
{
Type: DomainMatchingType_Full,
Domain: "hostnamestatic",
Ip: [][]byte{{127, 0, 0, 53}},
},
{
Type: DomainMatchingType_Full,
Domain: "hostnamealias",
ProxiedDomain: "hostname.localdomain",
},
},
}),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(&policy.Config{}),
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
v, err := core.New(config)
common.Must(err)
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
startTime := time.Now()
{ // Will match dotless:
ips, err := client.LookupIP("hostname")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 1}}); r != "" {
t.Fatal(r)
}
}
{ // Will match domain:local
ips, err := client.LookupIP("hostname.local")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 1}}); r != "" {
t.Fatal(r)
}
}
{ // Will match static ip
ips, err := client.LookupIP("hostnamestatic")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 53}}); r != "" {
t.Fatal(r)
}
}
{ // Will match domain replacing
ips, err := client.LookupIP("hostnamealias")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 1}}); r != "" {
t.Fatal(r)
}
}
{ // Will match dotless:localhost, but not expectIPs: 127.0.0.2, 127.0.0.3, then matches at dotless:
ips, err := client.LookupIP("localhost")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 2}}); r != "" {
t.Fatal(r)
}
}
{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3
ips, err := client.LookupIP("localhost-a")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 3}}); r != "" {
t.Fatal(r)
}
}
{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3
ips, err := client.LookupIP("localhost-b")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 4}}); r != "" {
t.Fatal(r)
}
}
{ // Will match dotless:
ips, err := client.LookupIP("Mijia Cloud")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 1}}); r != "" {
t.Fatal(r)
}
}
endTime := time.Now()
if startTime.After(endTime.Add(time.Second * 2)) {
t.Error("DNS query doesn't finish in 2 seconds.")
}
}
func TestMultiMatchPrioritizedDomain(t *testing.T) {
port := udp.PickPort()
dnsServer := dns.Server{
Addr: "127.0.0.1:" + port.String(),
Net: "udp",
Handler: &staticHandler{},
UDPSize: 1200,
}
go dnsServer.ListenAndServe()
time.Sleep(time.Second)
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&Config{
NameServers: []*net.Endpoint{
{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: 9999, /* unreachable */
},
},
NameServer: []*NameServer{
{
Address: &net.Endpoint{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
PrioritizedDomain: []*NameServer_PriorityDomain{
{
Type: DomainMatchingType_Subdomain,
Domain: "google.com",
},
},
Geoip: []*router.GeoIP{
{ // Will only match 8.8.8.8 and 8.8.4.4
Cidr: []*router.CIDR{
{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
{Ip: []byte{8, 8, 4, 4}, Prefix: 32},
},
},
},
},
{
Address: &net.Endpoint{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
PrioritizedDomain: []*NameServer_PriorityDomain{
{
Type: DomainMatchingType_Subdomain,
Domain: "google.com",
},
},
Geoip: []*router.GeoIP{
{ // Will match 8.8.8.8 and 8.8.8.7, etc
Cidr: []*router.CIDR{
{Ip: []byte{8, 8, 8, 7}, Prefix: 24},
},
},
},
},
{
Address: &net.Endpoint{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
PrioritizedDomain: []*NameServer_PriorityDomain{
{
Type: DomainMatchingType_Subdomain,
Domain: "api.google.com",
},
},
Geoip: []*router.GeoIP{
{ // Will only match 8.8.7.7 (api.google.com)
Cidr: []*router.CIDR{
{Ip: []byte{8, 8, 7, 7}, Prefix: 32},
},
},
},
},
{
Address: &net.Endpoint{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
PrioritizedDomain: []*NameServer_PriorityDomain{
{
Type: DomainMatchingType_Full,
Domain: "v2.api.google.com",
},
},
Geoip: []*router.GeoIP{
{ // Will only match 8.8.7.8 (v2.api.google.com)
Cidr: []*router.CIDR{
{Ip: []byte{8, 8, 7, 8}, Prefix: 32},
},
},
},
},
},
}),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(&policy.Config{}),
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
v, err := core.New(config)
common.Must(err)
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
startTime := time.Now()
{ // Will match server 1,2 and server 1 returns expected ip
ips, err := client.LookupIP("google.com")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
t.Fatal(r)
}
}
{ // Will match server 1,2 and server 1 returns unexpected ip, then server 2 returns expected one
clientv4 := client.(feature_dns.IPv4Lookup)
ips, err := clientv4.LookupIPv4("ipv6.google.com")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 7}}); r != "" {
t.Fatal(r)
}
}
{ // Will match server 3,1,2 and server 3 returns expected one
ips, err := client.LookupIP("api.google.com")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{8, 8, 7, 7}}); r != "" {
t.Fatal(r)
}
}
{ // Will match server 4,3,1,2 and server 4 returns expected one
ips, err := client.LookupIP("v2.api.google.com")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{8, 8, 7, 8}}); r != "" {
t.Fatal(r)
}
}
endTime := time.Now()
if startTime.After(endTime.Add(time.Second * 2)) {
t.Error("DNS query doesn't finish in 2 seconds.")
}
}
v2ray-core-4.34.0/app/dns/dnscommon.go 0000664 0000000 0000000 00000011722 13774574720 0017506 0 ustar 00root root 0000000 0000000 // +build !confonly
package dns
import (
"encoding/binary"
"time"
"golang.org/x/net/dns/dnsmessage"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/net"
dns_feature "v2ray.com/core/features/dns"
)
// Fqdn normalize domain make sure it ends with '.'
func Fqdn(domain string) string {
if len(domain) > 0 && domain[len(domain)-1] == '.' {
return domain
}
return domain + "."
}
type record struct {
A *IPRecord
AAAA *IPRecord
}
// IPRecord is a cacheable item for a resolved domain
type IPRecord struct {
ReqID uint16
IP []net.Address
Expire time.Time
RCode dnsmessage.RCode
}
func (r *IPRecord) getIPs() ([]net.Address, error) {
if r == nil || r.Expire.Before(time.Now()) {
return nil, errRecordNotFound
}
if r.RCode != dnsmessage.RCodeSuccess {
return nil, dns_feature.RCodeError(r.RCode)
}
return r.IP, nil
}
func isNewer(baseRec *IPRecord, newRec *IPRecord) bool {
if newRec == nil {
return false
}
if baseRec == nil {
return true
}
return baseRec.Expire.Before(newRec.Expire)
}
var (
errRecordNotFound = errors.New("record not found")
)
type dnsRequest struct {
reqType dnsmessage.Type
domain string
start time.Time
expire time.Time
msg *dnsmessage.Message
}
func genEDNS0Options(clientIP net.IP) *dnsmessage.Resource {
if len(clientIP) == 0 {
return nil
}
var netmask int
var family uint16
if len(clientIP) == 4 {
family = 1
netmask = 24 // 24 for IPV4, 96 for IPv6
} else {
family = 2
netmask = 96
}
b := make([]byte, 4)
binary.BigEndian.PutUint16(b[0:], family)
b[2] = byte(netmask)
b[3] = 0
switch family {
case 1:
ip := clientIP.To4().Mask(net.CIDRMask(netmask, net.IPv4len*8))
needLength := (netmask + 8 - 1) / 8 // division rounding up
b = append(b, ip[:needLength]...)
case 2:
ip := clientIP.Mask(net.CIDRMask(netmask, net.IPv6len*8))
needLength := (netmask + 8 - 1) / 8 // division rounding up
b = append(b, ip[:needLength]...)
}
const EDNS0SUBNET = 0x08
opt := new(dnsmessage.Resource)
common.Must(opt.Header.SetEDNS0(1350, 0xfe00, true))
opt.Body = &dnsmessage.OPTResource{
Options: []dnsmessage.Option{
{
Code: EDNS0SUBNET,
Data: b,
},
},
}
return opt
}
func buildReqMsgs(domain string, option IPOption, reqIDGen func() uint16, reqOpts *dnsmessage.Resource) []*dnsRequest {
qA := dnsmessage.Question{
Name: dnsmessage.MustNewName(domain),
Type: dnsmessage.TypeA,
Class: dnsmessage.ClassINET,
}
qAAAA := dnsmessage.Question{
Name: dnsmessage.MustNewName(domain),
Type: dnsmessage.TypeAAAA,
Class: dnsmessage.ClassINET,
}
var reqs []*dnsRequest
now := time.Now()
if option.IPv4Enable {
msg := new(dnsmessage.Message)
msg.Header.ID = reqIDGen()
msg.Header.RecursionDesired = true
msg.Questions = []dnsmessage.Question{qA}
if reqOpts != nil {
msg.Additionals = append(msg.Additionals, *reqOpts)
}
reqs = append(reqs, &dnsRequest{
reqType: dnsmessage.TypeA,
domain: domain,
start: now,
msg: msg,
})
}
if option.IPv6Enable {
msg := new(dnsmessage.Message)
msg.Header.ID = reqIDGen()
msg.Header.RecursionDesired = true
msg.Questions = []dnsmessage.Question{qAAAA}
if reqOpts != nil {
msg.Additionals = append(msg.Additionals, *reqOpts)
}
reqs = append(reqs, &dnsRequest{
reqType: dnsmessage.TypeAAAA,
domain: domain,
start: now,
msg: msg,
})
}
return reqs
}
// parseResponse parse DNS answers from the returned payload
func parseResponse(payload []byte) (*IPRecord, error) {
var parser dnsmessage.Parser
h, err := parser.Start(payload)
if err != nil {
return nil, newError("failed to parse DNS response").Base(err).AtWarning()
}
if err := parser.SkipAllQuestions(); err != nil {
return nil, newError("failed to skip questions in DNS response").Base(err).AtWarning()
}
now := time.Now()
ipRecord := &IPRecord{
ReqID: h.ID,
RCode: h.RCode,
Expire: now.Add(time.Second * 600),
}
L:
for {
ah, err := parser.AnswerHeader()
if err != nil {
if err != dnsmessage.ErrSectionDone {
newError("failed to parse answer section for domain: ", ah.Name.String()).Base(err).WriteToLog()
}
break
}
ttl := ah.TTL
if ttl == 0 {
ttl = 600
}
expire := now.Add(time.Duration(ttl) * time.Second)
if ipRecord.Expire.After(expire) {
ipRecord.Expire = expire
}
switch ah.Type {
case dnsmessage.TypeA:
ans, err := parser.AResource()
if err != nil {
newError("failed to parse A record for domain: ", ah.Name).Base(err).WriteToLog()
break L
}
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.A[:]))
case dnsmessage.TypeAAAA:
ans, err := parser.AAAAResource()
if err != nil {
newError("failed to parse A record for domain: ", ah.Name).Base(err).WriteToLog()
break L
}
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.AAAA[:]))
default:
if err := parser.SkipAnswer(); err != nil {
newError("failed to skip answer").Base(err).WriteToLog()
break L
}
continue
}
}
return ipRecord, nil
}
v2ray-core-4.34.0/app/dns/dnscommon_test.go 0000664 0000000 0000000 00000007763 13774574720 0020557 0 ustar 00root root 0000000 0000000 // +build !confonly
package dns
import (
"math/rand"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/miekg/dns"
"golang.org/x/net/dns/dnsmessage"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
)
func Test_parseResponse(t *testing.T) {
var p [][]byte
ans := new(dns.Msg)
ans.Id = 0
p = append(p, common.Must2(ans.Pack()).([]byte))
p = append(p, []byte{})
ans = new(dns.Msg)
ans.Id = 1
ans.Answer = append(ans.Answer,
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN A 8.8.8.8")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN A 8.8.4.4")).(dns.RR),
)
p = append(p, common.Must2(ans.Pack()).([]byte))
ans = new(dns.Msg)
ans.Id = 2
ans.Answer = append(ans.Answer,
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN CNAME test.google.com")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8888")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8844")).(dns.RR),
)
p = append(p, common.Must2(ans.Pack()).([]byte))
tests := []struct {
name string
want *IPRecord
wantErr bool
}{
{"empty",
&IPRecord{0, []net.Address(nil), time.Time{}, dnsmessage.RCodeSuccess},
false,
},
{"error",
nil,
true,
},
{"a record",
&IPRecord{1, []net.Address{net.ParseAddress("8.8.8.8"), net.ParseAddress("8.8.4.4")},
time.Time{}, dnsmessage.RCodeSuccess},
false,
},
{"aaaa record",
&IPRecord{2, []net.Address{net.ParseAddress("2001::123:8888"), net.ParseAddress("2001::123:8844")}, time.Time{}, dnsmessage.RCodeSuccess},
false,
},
}
for i, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseResponse(p[i])
if (err != nil) != tt.wantErr {
t.Errorf("handleResponse() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != nil {
// reset the time
got.Expire = time.Time{}
}
if cmp.Diff(got, tt.want) != "" {
t.Errorf(cmp.Diff(got, tt.want))
// t.Errorf("handleResponse() = %#v, want %#v", got, tt.want)
}
})
}
}
func Test_buildReqMsgs(t *testing.T) {
stubID := func() uint16 {
return uint16(rand.Uint32())
}
type args struct {
domain string
option IPOption
reqOpts *dnsmessage.Resource
}
tests := []struct {
name string
args args
want int
}{
{"dual stack", args{"test.com", IPOption{true, true}, nil}, 2},
{"ipv4 only", args{"test.com", IPOption{true, false}, nil}, 1},
{"ipv6 only", args{"test.com", IPOption{false, true}, nil}, 1},
{"none/error", args{"test.com", IPOption{false, false}, nil}, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := buildReqMsgs(tt.args.domain, tt.args.option, stubID, tt.args.reqOpts); !(len(got) == tt.want) {
t.Errorf("buildReqMsgs() = %v, want %v", got, tt.want)
}
})
}
}
func Test_genEDNS0Options(t *testing.T) {
type args struct {
clientIP net.IP
}
tests := []struct {
name string
args args
want *dnsmessage.Resource
}{
// TODO: Add test cases.
{"ipv4", args{net.ParseIP("4.3.2.1")}, nil},
{"ipv6", args{net.ParseIP("2001::4321")}, nil},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := genEDNS0Options(tt.args.clientIP); got == nil {
t.Errorf("genEDNS0Options() = %v, want %v", got, tt.want)
}
})
}
}
func TestFqdn(t *testing.T) {
type args struct {
domain string
}
tests := []struct {
name string
args args
want string
}{
{"with fqdn", args{"www.v2ray.com."}, "www.v2ray.com."},
{"without fqdn", args{"www.v2ray.com"}, "www.v2ray.com."},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Fqdn(tt.args.domain); got != tt.want {
t.Errorf("Fqdn() = %v, want %v", got, tt.want)
}
})
}
}
v2ray-core-4.34.0/app/dns/errors.generated.go 0000664 0000000 0000000 00000000311 13774574720 0020752 0 ustar 00root root 0000000 0000000 package dns
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/app/dns/hosts.go 0000664 0000000 0000000 00000006333 13774574720 0016653 0 ustar 00root root 0000000 0000000 // +build !confonly
package dns
import (
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/common/strmatcher"
"v2ray.com/core/features"
)
// StaticHosts represents static domain-ip mapping in DNS server.
type StaticHosts struct {
ips [][]net.Address
matchers *strmatcher.MatcherGroup
}
// NewStaticHosts creates a new StaticHosts instance.
func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDomain) (*StaticHosts, error) {
g := new(strmatcher.MatcherGroup)
sh := &StaticHosts{
ips: make([][]net.Address, len(hosts)+len(legacy)+16),
matchers: g,
}
if legacy != nil {
features.PrintDeprecatedFeatureWarning("simple host mapping")
for domain, ip := range legacy {
matcher, err := strmatcher.Full.New(domain)
common.Must(err)
id := g.Add(matcher)
address := ip.AsAddress()
if address.Family().IsDomain() {
return nil, newError("invalid domain address in static hosts: ", address.Domain()).AtWarning()
}
sh.ips[id] = []net.Address{address}
}
}
for _, mapping := range hosts {
matcher, err := toStrMatcher(mapping.Type, mapping.Domain)
if err != nil {
return nil, newError("failed to create domain matcher").Base(err)
}
id := g.Add(matcher)
ips := make([]net.Address, 0, len(mapping.Ip)+1)
switch {
case len(mapping.Ip) > 0:
for _, ip := range mapping.Ip {
addr := net.IPAddress(ip)
if addr == nil {
return nil, newError("invalid IP address in static hosts: ", ip).AtWarning()
}
ips = append(ips, addr)
}
case len(mapping.ProxiedDomain) > 0:
ips = append(ips, net.DomainAddress(mapping.ProxiedDomain))
default:
return nil, newError("neither IP address nor proxied domain specified for domain: ", mapping.Domain).AtWarning()
}
// Special handling for localhost IPv6. This is a dirty workaround as JSON config supports only single IP mapping.
if len(ips) == 1 && ips[0] == net.LocalHostIP {
ips = append(ips, net.LocalHostIPv6)
}
sh.ips[id] = ips
}
return sh, nil
}
func filterIP(ips []net.Address, option IPOption) []net.Address {
filtered := make([]net.Address, 0, len(ips))
for _, ip := range ips {
if (ip.Family().IsIPv4() && option.IPv4Enable) || (ip.Family().IsIPv6() && option.IPv6Enable) {
filtered = append(filtered, ip)
}
}
return filtered
}
func (h *StaticHosts) lookupInternal(domain string) []net.Address {
var ips []net.Address
for _, id := range h.matchers.Match(domain) {
ips = append(ips, h.ips[id]...)
}
return ips
}
func (h *StaticHosts) lookup(domain string, option IPOption, maxDepth int) []net.Address {
switch addrs := h.lookupInternal(domain); {
case len(addrs) == 0: // Not recorded in static hosts, return nil
return nil
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Try to unwrap domain
if maxDepth > 0 {
unwrapped := h.lookup(addrs[0].Domain(), option, maxDepth-1)
if unwrapped != nil {
return unwrapped
}
}
return addrs
default: // IP record found, return a non-nil IP array
return filterIP(addrs, option)
}
}
// Lookup returns IP addresses or proxied domain for the given domain, if exists in this StaticHosts.
func (h *StaticHosts) Lookup(domain string, option IPOption) []net.Address {
return h.lookup(domain, option, 5)
}
v2ray-core-4.34.0/app/dns/hosts_test.go 0000664 0000000 0000000 00000002647 13774574720 0017716 0 ustar 00root root 0000000 0000000 package dns_test
import (
"testing"
"github.com/google/go-cmp/cmp"
. "v2ray.com/core/app/dns"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
)
func TestStaticHosts(t *testing.T) {
pb := []*Config_HostMapping{
{
Type: DomainMatchingType_Full,
Domain: "v2ray.com",
Ip: [][]byte{
{1, 1, 1, 1},
},
},
{
Type: DomainMatchingType_Subdomain,
Domain: "v2ray.cn",
Ip: [][]byte{
{2, 2, 2, 2},
},
},
{
Type: DomainMatchingType_Subdomain,
Domain: "baidu.com",
Ip: [][]byte{
{127, 0, 0, 1},
},
},
}
hosts, err := NewStaticHosts(pb, nil)
common.Must(err)
{
ips := hosts.Lookup("v2ray.com", IPOption{
IPv4Enable: true,
IPv6Enable: true,
})
if len(ips) != 1 {
t.Error("expect 1 IP, but got ", len(ips))
}
if diff := cmp.Diff([]byte(ips[0].IP()), []byte{1, 1, 1, 1}); diff != "" {
t.Error(diff)
}
}
{
ips := hosts.Lookup("www.v2ray.cn", IPOption{
IPv4Enable: true,
IPv6Enable: true,
})
if len(ips) != 1 {
t.Error("expect 1 IP, but got ", len(ips))
}
if diff := cmp.Diff([]byte(ips[0].IP()), []byte{2, 2, 2, 2}); diff != "" {
t.Error(diff)
}
}
{
ips := hosts.Lookup("baidu.com", IPOption{
IPv4Enable: false,
IPv6Enable: true,
})
if len(ips) != 1 {
t.Error("expect 1 IP, but got ", len(ips))
}
if diff := cmp.Diff([]byte(ips[0].IP()), []byte(net.LocalHostIPv6.IP())); diff != "" {
t.Error(diff)
}
}
}
v2ray-core-4.34.0/app/dns/nameserver.go 0000664 0000000 0000000 00000014424 13774574720 0017662 0 ustar 00root root 0000000 0000000 // +build !confonly
package dns
import (
"context"
"net/url"
"time"
"v2ray.com/core"
"v2ray.com/core/app/router"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/net"
"v2ray.com/core/common/strmatcher"
"v2ray.com/core/features/routing"
)
// IPOption is an object for IP query options.
type IPOption struct {
IPv4Enable bool
IPv6Enable bool
}
// Server is the interface for Name Server.
type Server interface {
// Name of the Client.
Name() string
// QueryIP sends IP queries to its configured server.
QueryIP(ctx context.Context, domain string, clientIP net.IP, option IPOption) ([]net.IP, error)
}
// Client is the interface for DNS client.
type Client struct {
server Server
clientIP net.IP
domains []string
expectIPs []*router.GeoIPMatcher
}
var errExpectedIPNonMatch = errors.New("expectIPs not match")
// NewServer creates a name server object according to the network destination url.
func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, error) {
if address := dest.Address; address.Family().IsDomain() {
u, err := url.Parse(address.Domain())
if err != nil {
return nil, err
}
switch {
case u.String() == "localhost":
return NewLocalNameServer(), nil
case u.Scheme == "https": // DOH Remote mode
return NewDoHNameServer(u, dispatcher)
case u.Scheme == "https+local": // DOH Local mode
return NewDoHLocalNameServer(u), nil
case u.Scheme == "quic+local": // DNS-over-QUIC Local mode
return NewQUICNameServer(u)
}
}
if dest.Network == net.Network_Unknown {
dest.Network = net.Network_UDP
}
if dest.Network == net.Network_UDP { // UDP classic DNS mode
return NewClassicNameServer(dest, dispatcher), nil
}
return nil, newError("No available name server could be created from ", dest).AtWarning()
}
// NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container router.GeoIPMatcherContainer, updateDomainRule func(strmatcher.Matcher, int) error) (*Client, error) {
client := &Client{}
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
// Create a new server for each client for now
server, err := NewServer(ns.Address.AsDestination(), dispatcher)
if err != nil {
return newError("failed to create nameserver").Base(err).AtWarning()
}
// Priotize local domains with specific TLDs or without any dot to local DNS
if _, isLocalDNS := server.(*LocalNameServer); isLocalDNS {
ns.PrioritizedDomain = append(ns.PrioritizedDomain, localTLDsAndDotlessDomains...)
ns.OriginalRules = append(ns.OriginalRules, localTLDsAndDotlessDomainsRule)
}
// Establish domain rules
var rules []string
ruleCurr := 0
ruleIter := 0
for _, domain := range ns.PrioritizedDomain {
domainRule, err := toStrMatcher(domain.Type, domain.Domain)
if err != nil {
return newError("failed to create prioritized domain").Base(err).AtWarning()
}
originalRuleIdx := ruleCurr
if ruleCurr < len(ns.OriginalRules) {
rule := ns.OriginalRules[ruleCurr]
if ruleCurr >= len(rules) {
rules = append(rules, rule.Rule)
}
ruleIter++
if ruleIter >= int(rule.Size) {
ruleIter = 0
ruleCurr++
}
} else { // No original rule, generate one according to current domain matcher (majorly for compatibility with tests)
rules = append(rules, domainRule.String())
ruleCurr++
}
err = updateDomainRule(domainRule, originalRuleIdx)
if err != nil {
return newError("failed to create prioritized domain").Base(err).AtWarning()
}
}
// Establish expected IPs
var matchers []*router.GeoIPMatcher
for _, geoip := range ns.Geoip {
matcher, err := container.Add(geoip)
if err != nil {
return newError("failed to create ip matcher").Base(err).AtWarning()
}
matchers = append(matchers, matcher)
}
if len(clientIP) > 0 {
switch ns.Address.Address.GetAddress().(type) {
case *net.IPOrDomain_Domain:
newError("DNS: client ", ns.Address.Address.GetDomain(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
case *net.IPOrDomain_Ip:
newError("DNS: client ", ns.Address.Address.GetIp(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
}
}
client.server = server
client.clientIP = clientIP
client.domains = rules
client.expectIPs = matchers
return nil
})
return client, err
}
// NewSimpleClient creates a DNS client with a simple destination.
func NewSimpleClient(ctx context.Context, endpoint *net.Endpoint, clientIP net.IP) (*Client, error) {
client := &Client{}
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
server, err := NewServer(endpoint.AsDestination(), dispatcher)
if err != nil {
return newError("failed to create nameserver").Base(err).AtWarning()
}
client.server = server
client.clientIP = clientIP
return nil
})
if len(clientIP) > 0 {
switch endpoint.Address.GetAddress().(type) {
case *net.IPOrDomain_Domain:
newError("DNS: client ", endpoint.Address.GetDomain(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
case *net.IPOrDomain_Ip:
newError("DNS: client ", endpoint.Address.GetIp(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
}
}
return client, err
}
// Name returns the server name the client manages.
func (c *Client) Name() string {
return c.server.Name()
}
// QueryIP send DNS query to the name server with the client's IP.
func (c *Client) QueryIP(ctx context.Context, domain string, option IPOption) ([]net.IP, error) {
ctx, cancel := context.WithTimeout(ctx, 4*time.Second)
ips, err := c.server.QueryIP(ctx, domain, c.clientIP, option)
cancel()
if err != nil {
return ips, err
}
return c.MatchExpectedIPs(domain, ips)
}
// MatchExpectedIPs matches queried domain IPs with expected IPs and returns matched ones.
func (c *Client) MatchExpectedIPs(domain string, ips []net.IP) ([]net.IP, error) {
if len(c.expectIPs) == 0 {
return ips, nil
}
newIps := []net.IP{}
for _, ip := range ips {
for _, matcher := range c.expectIPs {
if matcher.Match(ip) {
newIps = append(newIps, ip)
break
}
}
}
if len(newIps) == 0 {
return nil, errExpectedIPNonMatch
}
newError("domain ", domain, " expectIPs ", newIps, " matched at server ", c.Name()).AtDebug().WriteToLog()
return newIps, nil
}
v2ray-core-4.34.0/app/dns/nameserver_doh.go 0000664 0000000 0000000 00000022303 13774574720 0020507 0 ustar 00root root 0000000 0000000 // +build !confonly
package dns
import (
"bytes"
"context"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"sync"
"sync/atomic"
"time"
"golang.org/x/net/dns/dnsmessage"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol/dns"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal/pubsub"
"v2ray.com/core/common/task"
dns_feature "v2ray.com/core/features/dns"
"v2ray.com/core/features/routing"
"v2ray.com/core/transport/internet"
)
// DoHNameServer implemented DNS over HTTPS (RFC8484) Wire Format,
// which is compatible with traditional dns over udp(RFC1035),
// thus most of the DOH implementation is copied from udpns.go
type DoHNameServer struct {
sync.RWMutex
ips map[string]record
pub *pubsub.Service
cleanup *task.Periodic
reqID uint32
httpClient *http.Client
dohURL string
name string
}
// NewDoHNameServer creates DOH server object for remote resolving.
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher) (*DoHNameServer, error) {
newError("DNS: created Remote DOH client for ", url.String()).AtInfo().WriteToLog()
s := baseDOHNameServer(url, "DOH")
// Dispatched connection will be closed (interrupted) after each request
// This makes DOH inefficient without a keep-alived connection
// See: core/app/proxyman/outbound/handler.go:113
// Using mux (https request wrapped in a stream layer) improves the situation.
// Recommend to use NewDoHLocalNameServer (DOHL:) if v2ray instance is running on
// a normal network eg. the server side of v2ray
tr := &http.Transport{
MaxIdleConns: 30,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 30 * time.Second,
ForceAttemptHTTP2: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dest, err := net.ParseDestination(network + ":" + addr)
if err != nil {
return nil, err
}
link, err := dispatcher.Dispatch(ctx, dest)
if err != nil {
return nil, err
}
return net.NewConnection(
net.ConnectionInputMulti(link.Writer),
net.ConnectionOutputMulti(link.Reader),
), nil
},
}
dispatchedClient := &http.Client{
Transport: tr,
Timeout: 60 * time.Second,
}
s.httpClient = dispatchedClient
return s, nil
}
// NewDoHLocalNameServer creates DOH client object for local resolving
func NewDoHLocalNameServer(url *url.URL) *DoHNameServer {
url.Scheme = "https"
s := baseDOHNameServer(url, "DOHL")
tr := &http.Transport{
IdleConnTimeout: 90 * time.Second,
ForceAttemptHTTP2: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dest, err := net.ParseDestination(network + ":" + addr)
if err != nil {
return nil, err
}
conn, err := internet.DialSystem(ctx, dest, nil)
if err != nil {
return nil, err
}
return conn, nil
},
}
s.httpClient = &http.Client{
Timeout: time.Second * 180,
Transport: tr,
}
newError("DNS: created Local DOH client for ", url.String()).AtInfo().WriteToLog()
return s
}
func baseDOHNameServer(url *url.URL, prefix string) *DoHNameServer {
s := &DoHNameServer{
ips: make(map[string]record),
pub: pubsub.NewService(),
name: prefix + "//" + url.Host,
dohURL: url.String(),
}
s.cleanup = &task.Periodic{
Interval: time.Minute,
Execute: s.Cleanup,
}
return s
}
// Name implements Server.
func (s *DoHNameServer) Name() string {
return s.name
}
// Cleanup clears expired items from cache
func (s *DoHNameServer) Cleanup() error {
now := time.Now()
s.Lock()
defer s.Unlock()
if len(s.ips) == 0 {
return newError("nothing to do. stopping...")
}
for domain, record := range s.ips {
if record.A != nil && record.A.Expire.Before(now) {
record.A = nil
}
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
record.AAAA = nil
}
if record.A == nil && record.AAAA == nil {
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog()
delete(s.ips, domain)
} else {
s.ips[domain] = record
}
}
if len(s.ips) == 0 {
s.ips = make(map[string]record)
}
return nil
}
func (s *DoHNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
elapsed := time.Since(req.start)
s.Lock()
rec := s.ips[req.domain]
updated := false
switch req.reqType {
case dnsmessage.TypeA:
if isNewer(rec.A, ipRec) {
rec.A = ipRec
updated = true
}
case dnsmessage.TypeAAAA:
addr := make([]net.Address, 0)
for _, ip := range ipRec.IP {
if len(ip.IP()) == net.IPv6len {
addr = append(addr, ip)
}
}
ipRec.IP = addr
if isNewer(rec.AAAA, ipRec) {
rec.AAAA = ipRec
updated = true
}
}
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog()
if updated {
s.ips[req.domain] = rec
}
switch req.reqType {
case dnsmessage.TypeA:
s.pub.Publish(req.domain+"4", nil)
case dnsmessage.TypeAAAA:
s.pub.Publish(req.domain+"6", nil)
}
s.Unlock()
common.Must(s.cleanup.Start())
}
func (s *DoHNameServer) newReqID() uint16 {
return uint16(atomic.AddUint32(&s.reqID, 1))
}
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option IPOption) {
newError(s.name, " querying: ", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx))
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
var deadline time.Time
if d, ok := ctx.Deadline(); ok {
deadline = d
} else {
deadline = time.Now().Add(time.Second * 5)
}
for _, req := range reqs {
go func(r *dnsRequest) {
// generate new context for each req, using same context
// may cause reqs all aborted if any one encounter an error
dnsCtx := context.Background()
// reserve internal dns server requested Inbound
if inbound := session.InboundFromContext(ctx); inbound != nil {
dnsCtx = session.ContextWithInbound(dnsCtx, inbound)
}
dnsCtx = session.ContextWithContent(dnsCtx, &session.Content{
Protocol: "https",
SkipDNSResolve: true,
})
// forced to use mux for DOH
dnsCtx = session.ContextWithMuxPrefered(dnsCtx, true)
var cancel context.CancelFunc
dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline)
defer cancel()
b, err := dns.PackMessage(r.msg)
if err != nil {
newError("failed to pack dns query").Base(err).AtError().WriteToLog()
return
}
resp, err := s.dohHTTPSContext(dnsCtx, b.Bytes())
if err != nil {
newError("failed to retrieve response").Base(err).AtError().WriteToLog()
return
}
rec, err := parseResponse(resp)
if err != nil {
newError("failed to handle DOH response").Base(err).AtError().WriteToLog()
return
}
s.updateIP(r, rec)
}(req)
}
}
func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte, error) {
body := bytes.NewBuffer(b)
req, err := http.NewRequest("POST", s.dohURL, body)
if err != nil {
return nil, err
}
req.Header.Add("Accept", "application/dns-message")
req.Header.Add("Content-Type", "application/dns-message")
resp, err := s.httpClient.Do(req.WithContext(ctx))
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
io.Copy(ioutil.Discard, resp.Body) // flush resp.Body so that the conn is reusable
return nil, fmt.Errorf("DOH server returned code %d", resp.StatusCode)
}
return ioutil.ReadAll(resp.Body)
}
func (s *DoHNameServer) findIPsForDomain(domain string, option IPOption) ([]net.IP, error) {
s.RLock()
record, found := s.ips[domain]
s.RUnlock()
if !found {
return nil, errRecordNotFound
}
var ips []net.Address
var lastErr error
if option.IPv6Enable && record.AAAA != nil && record.AAAA.RCode == dnsmessage.RCodeSuccess {
aaaa, err := record.AAAA.getIPs()
if err != nil {
lastErr = err
}
ips = append(ips, aaaa...)
}
if option.IPv4Enable && record.A != nil && record.A.RCode == dnsmessage.RCodeSuccess {
a, err := record.A.getIPs()
if err != nil {
lastErr = err
}
ips = append(ips, a...)
}
if len(ips) > 0 {
return toNetIP(ips)
}
if lastErr != nil {
return nil, lastErr
}
if (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {
return nil, dns_feature.ErrEmptyResponse
}
return nil, errRecordNotFound
}
// QueryIP implements Server.
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option IPOption) ([]net.IP, error) { // nolint: dupl
fqdn := Fqdn(domain)
ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound {
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
return ips, err
}
// ipv4 and ipv6 belong to different subscription groups
var sub4, sub6 *pubsub.Subscriber
if option.IPv4Enable {
sub4 = s.pub.Subscribe(fqdn + "4")
defer sub4.Close()
}
if option.IPv6Enable {
sub6 = s.pub.Subscribe(fqdn + "6")
defer sub6.Close()
}
done := make(chan interface{})
go func() {
if sub4 != nil {
select {
case <-sub4.Wait():
case <-ctx.Done():
}
}
if sub6 != nil {
select {
case <-sub6.Wait():
case <-ctx.Done():
}
}
close(done)
}()
s.sendQuery(ctx, fqdn, clientIP, option)
for {
ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound {
return ips, err
}
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-done:
}
}
}
v2ray-core-4.34.0/app/dns/nameserver_local.go 0000664 0000000 0000000 00000002245 13774574720 0021032 0 ustar 00root root 0000000 0000000 // +build !confonly
package dns
import (
"context"
"v2ray.com/core/common/net"
"v2ray.com/core/features/dns/localdns"
)
// LocalNameServer is an wrapper over local DNS feature.
type LocalNameServer struct {
client *localdns.Client
}
// QueryIP implements Server.
func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option IPOption) ([]net.IP, error) {
if option.IPv4Enable && option.IPv6Enable {
return s.client.LookupIP(domain)
}
if option.IPv4Enable {
return s.client.LookupIPv4(domain)
}
if option.IPv6Enable {
return s.client.LookupIPv6(domain)
}
return nil, newError("neither IPv4 nor IPv6 is enabled")
}
// Name implements Server.
func (s *LocalNameServer) Name() string {
return "localhost"
}
// NewLocalNameServer creates localdns server object for directly lookup in system DNS.
func NewLocalNameServer() *LocalNameServer {
newError("DNS: created localhost client").AtInfo().WriteToLog()
return &LocalNameServer{
client: localdns.New(),
}
}
// NewLocalDNSClient creates localdns client object for directly lookup in system DNS.
func NewLocalDNSClient() *Client {
return &Client{server: NewLocalNameServer()}
}
v2ray-core-4.34.0/app/dns/nameserver_local_test.go 0000664 0000000 0000000 00000000743 13774574720 0022072 0 ustar 00root root 0000000 0000000 package dns_test
import (
"context"
"testing"
"time"
. "v2ray.com/core/app/dns"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
)
func TestLocalNameServer(t *testing.T) {
s := NewLocalNameServer()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
ips, err := s.QueryIP(ctx, "google.com", net.IP{}, IPOption{
IPv4Enable: true,
IPv6Enable: true,
})
cancel()
common.Must(err)
if len(ips) == 0 {
t.Error("expect some ips, but got 0")
}
}
v2ray-core-4.34.0/app/dns/nameserver_quic.go 0000664 0000000 0000000 00000021276 13774574720 0020706 0 ustar 00root root 0000000 0000000 // +build !confonly
package dns
import (
"context"
"net/url"
"sync"
"sync/atomic"
"time"
"github.com/lucas-clemente/quic-go"
"golang.org/x/net/dns/dnsmessage"
"golang.org/x/net/http2"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol/dns"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal/pubsub"
"v2ray.com/core/common/task"
dns_feature "v2ray.com/core/features/dns"
"v2ray.com/core/transport/internet/tls"
)
// NextProtoDQ - During connection establishment, DNS/QUIC support is indicated
// by selecting the ALPN token "dq" in the crypto handshake.
const NextProtoDQ = "doq-i00"
const handshakeTimeout = time.Second * 8
// QUICNameServer implemented DNS over QUIC
type QUICNameServer struct {
sync.RWMutex
ips map[string]record
pub *pubsub.Service
cleanup *task.Periodic
reqID uint32
name string
destination net.Destination
session quic.Session
}
// NewQUICNameServer creates DNS-over-QUIC client object for local resolving
func NewQUICNameServer(url *url.URL) (*QUICNameServer, error) {
newError("DNS: created Local DNS-over-QUIC client for ", url.String()).AtInfo().WriteToLog()
var err error
port := net.Port(784)
if url.Port() != "" {
port, err = net.PortFromString(url.Port())
if err != nil {
return nil, err
}
}
dest := net.UDPDestination(net.DomainAddress(url.Hostname()), port)
s := &QUICNameServer{
ips: make(map[string]record),
pub: pubsub.NewService(),
name: url.String(),
destination: dest,
}
s.cleanup = &task.Periodic{
Interval: time.Minute,
Execute: s.Cleanup,
}
return s, nil
}
// Name returns client name
func (s *QUICNameServer) Name() string {
return s.name
}
// Cleanup clears expired items from cache
func (s *QUICNameServer) Cleanup() error {
now := time.Now()
s.Lock()
defer s.Unlock()
if len(s.ips) == 0 {
return newError("nothing to do. stopping...")
}
for domain, record := range s.ips {
if record.A != nil && record.A.Expire.Before(now) {
record.A = nil
}
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
record.AAAA = nil
}
if record.A == nil && record.AAAA == nil {
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog()
delete(s.ips, domain)
} else {
s.ips[domain] = record
}
}
if len(s.ips) == 0 {
s.ips = make(map[string]record)
}
return nil
}
func (s *QUICNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
elapsed := time.Since(req.start)
s.Lock()
rec := s.ips[req.domain]
updated := false
switch req.reqType {
case dnsmessage.TypeA:
if isNewer(rec.A, ipRec) {
rec.A = ipRec
updated = true
}
case dnsmessage.TypeAAAA:
addr := make([]net.Address, 0)
for _, ip := range ipRec.IP {
if len(ip.IP()) == net.IPv6len {
addr = append(addr, ip)
}
}
ipRec.IP = addr
if isNewer(rec.AAAA, ipRec) {
rec.AAAA = ipRec
updated = true
}
}
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog()
if updated {
s.ips[req.domain] = rec
}
switch req.reqType {
case dnsmessage.TypeA:
s.pub.Publish(req.domain+"4", nil)
case dnsmessage.TypeAAAA:
s.pub.Publish(req.domain+"6", nil)
}
s.Unlock()
common.Must(s.cleanup.Start())
}
func (s *QUICNameServer) newReqID() uint16 {
return uint16(atomic.AddUint32(&s.reqID, 1))
}
func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option IPOption) {
newError(s.name, " querying: ", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx))
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
var deadline time.Time
if d, ok := ctx.Deadline(); ok {
deadline = d
} else {
deadline = time.Now().Add(time.Second * 5)
}
for _, req := range reqs {
go func(r *dnsRequest) {
// generate new context for each req, using same context
// may cause reqs all aborted if any one encounter an error
dnsCtx := context.Background()
// reserve internal dns server requested Inbound
if inbound := session.InboundFromContext(ctx); inbound != nil {
dnsCtx = session.ContextWithInbound(dnsCtx, inbound)
}
dnsCtx = session.ContextWithContent(dnsCtx, &session.Content{
Protocol: "quic",
SkipDNSResolve: true,
})
var cancel context.CancelFunc
dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline)
defer cancel()
b, err := dns.PackMessage(r.msg)
if err != nil {
newError("failed to pack dns query").Base(err).AtError().WriteToLog()
return
}
conn, err := s.openStream(dnsCtx)
if err != nil {
newError("failed to open quic session").Base(err).AtError().WriteToLog()
return
}
_, err = conn.Write(b.Bytes())
if err != nil {
newError("failed to send query").Base(err).AtError().WriteToLog()
return
}
_ = conn.Close()
respBuf := buf.New()
defer respBuf.Release()
n, err := respBuf.ReadFrom(conn)
if err != nil && n == 0 {
newError("failed to read response").Base(err).AtError().WriteToLog()
return
}
rec, err := parseResponse(respBuf.Bytes())
if err != nil {
newError("failed to handle response").Base(err).AtError().WriteToLog()
return
}
s.updateIP(r, rec)
}(req)
}
}
func (s *QUICNameServer) findIPsForDomain(domain string, option IPOption) ([]net.IP, error) {
s.RLock()
record, found := s.ips[domain]
s.RUnlock()
if !found {
return nil, errRecordNotFound
}
var ips []net.Address
var lastErr error
if option.IPv6Enable && record.AAAA != nil && record.AAAA.RCode == dnsmessage.RCodeSuccess {
aaaa, err := record.AAAA.getIPs()
if err != nil {
lastErr = err
}
ips = append(ips, aaaa...)
}
if option.IPv4Enable && record.A != nil && record.A.RCode == dnsmessage.RCodeSuccess {
a, err := record.A.getIPs()
if err != nil {
lastErr = err
}
ips = append(ips, a...)
}
if len(ips) > 0 {
return toNetIP(ips)
}
if lastErr != nil {
return nil, lastErr
}
if (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {
return nil, dns_feature.ErrEmptyResponse
}
return nil, errRecordNotFound
}
// QueryIP is called from dns.Server->queryIPTimeout
func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option IPOption) ([]net.IP, error) {
fqdn := Fqdn(domain)
ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound {
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
return ips, err
}
// ipv4 and ipv6 belong to different subscription groups
var sub4, sub6 *pubsub.Subscriber
if option.IPv4Enable {
sub4 = s.pub.Subscribe(fqdn + "4")
defer sub4.Close()
}
if option.IPv6Enable {
sub6 = s.pub.Subscribe(fqdn + "6")
defer sub6.Close()
}
done := make(chan interface{})
go func() {
if sub4 != nil {
select {
case <-sub4.Wait():
case <-ctx.Done():
}
}
if sub6 != nil {
select {
case <-sub6.Wait():
case <-ctx.Done():
}
}
close(done)
}()
s.sendQuery(ctx, fqdn, clientIP, option)
for {
ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound {
return ips, err
}
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-done:
}
}
}
func isActive(s quic.Session) bool {
select {
case <-s.Context().Done():
return false
default:
return true
}
}
func (s *QUICNameServer) getSession() (quic.Session, error) {
var session quic.Session
s.RLock()
session = s.session
if session != nil && isActive(session) {
s.RUnlock()
return session, nil
}
if session != nil {
// we're recreating the session, let's create a new one
_ = session.CloseWithError(0, "")
}
s.RUnlock()
s.Lock()
defer s.Unlock()
var err error
session, err = s.openSession()
if err != nil {
// This does not look too nice, but QUIC (or maybe quic-go)
// doesn't seem stable enough.
// Maybe retransmissions aren't fully implemented in quic-go?
// Anyways, the simple solution is to make a second try when
// it fails to open the QUIC session.
session, err = s.openSession()
if err != nil {
return nil, err
}
}
s.session = session
return session, nil
}
func (s *QUICNameServer) openSession() (quic.Session, error) {
tlsConfig := tls.Config{}
quicConfig := &quic.Config{
HandshakeTimeout: handshakeTimeout,
}
session, err := quic.DialAddrContext(context.Background(), s.destination.NetAddr(), tlsConfig.GetTLSConfig(tls.WithNextProto("http/1.1", http2.NextProtoTLS, NextProtoDQ)), quicConfig)
if err != nil {
return nil, err
}
return session, nil
}
func (s *QUICNameServer) openStream(ctx context.Context) (quic.Stream, error) {
session, err := s.getSession()
if err != nil {
return nil, err
}
// open a new stream
return session.OpenStreamSync(ctx)
}
v2ray-core-4.34.0/app/dns/nameserver_quic_test.go 0000664 0000000 0000000 00000001114 13774574720 0021732 0 ustar 00root root 0000000 0000000 package dns_test
import (
"context"
"net/url"
"testing"
"time"
. "v2ray.com/core/app/dns"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
)
func TestQUICNameServer(t *testing.T) {
url, err := url.Parse("quic://dns.adguard.com")
common.Must(err)
s, err := NewQUICNameServer(url)
common.Must(err)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), IPOption{
IPv4Enable: true,
IPv6Enable: true,
})
cancel()
common.Must(err)
if len(ips) == 0 {
t.Error("expect some ips, but got 0")
}
}
v2ray-core-4.34.0/app/dns/nameserver_udp.go 0000664 0000000 0000000 00000014730 13774574720 0020532 0 ustar 00root root 0000000 0000000 // +build !confonly
package dns
import (
"context"
"strings"
"sync"
"sync/atomic"
"time"
"golang.org/x/net/dns/dnsmessage"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol/dns"
udp_proto "v2ray.com/core/common/protocol/udp"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal/pubsub"
"v2ray.com/core/common/task"
dns_feature "v2ray.com/core/features/dns"
"v2ray.com/core/features/routing"
"v2ray.com/core/transport/internet/udp"
)
// ClassicNameServer implemented traditional UDP DNS.
type ClassicNameServer struct {
sync.RWMutex
name string
address net.Destination
ips map[string]record
requests map[uint16]dnsRequest
pub *pubsub.Service
udpServer *udp.Dispatcher
cleanup *task.Periodic
reqID uint32
}
// NewClassicNameServer creates udp server object for remote resolving.
func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher) *ClassicNameServer {
// default to 53 if unspecific
if address.Port == 0 {
address.Port = net.Port(53)
}
s := &ClassicNameServer{
address: address,
ips: make(map[string]record),
requests: make(map[uint16]dnsRequest),
pub: pubsub.NewService(),
name: strings.ToUpper(address.String()),
}
s.cleanup = &task.Periodic{
Interval: time.Minute,
Execute: s.Cleanup,
}
s.udpServer = udp.NewDispatcher(dispatcher, s.HandleResponse)
newError("DNS: created UDP client inited for ", address.NetAddr()).AtInfo().WriteToLog()
return s
}
// Name implements Server.
func (s *ClassicNameServer) Name() string {
return s.name
}
// Cleanup clears expired items from cache
func (s *ClassicNameServer) Cleanup() error {
now := time.Now()
s.Lock()
defer s.Unlock()
if len(s.ips) == 0 && len(s.requests) == 0 {
return newError(s.name, " nothing to do. stopping...")
}
for domain, record := range s.ips {
if record.A != nil && record.A.Expire.Before(now) {
record.A = nil
}
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
record.AAAA = nil
}
if record.A == nil && record.AAAA == nil {
delete(s.ips, domain)
} else {
s.ips[domain] = record
}
}
if len(s.ips) == 0 {
s.ips = make(map[string]record)
}
for id, req := range s.requests {
if req.expire.Before(now) {
delete(s.requests, id)
}
}
if len(s.requests) == 0 {
s.requests = make(map[uint16]dnsRequest)
}
return nil
}
// HandleResponse handles udp response packet from remote DNS server.
func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_proto.Packet) {
ipRec, err := parseResponse(packet.Payload.Bytes())
if err != nil {
newError(s.name, " fail to parse responded DNS udp").AtError().WriteToLog()
return
}
s.Lock()
id := ipRec.ReqID
req, ok := s.requests[id]
if ok {
// remove the pending request
delete(s.requests, id)
}
s.Unlock()
if !ok {
newError(s.name, " cannot find the pending request").AtError().WriteToLog()
return
}
var rec record
switch req.reqType {
case dnsmessage.TypeA:
rec.A = ipRec
case dnsmessage.TypeAAAA:
rec.AAAA = ipRec
}
elapsed := time.Since(req.start)
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog()
if len(req.domain) > 0 && (rec.A != nil || rec.AAAA != nil) {
s.updateIP(req.domain, rec)
}
}
func (s *ClassicNameServer) updateIP(domain string, newRec record) {
s.Lock()
newError(s.name, " updating IP records for domain:", domain).AtDebug().WriteToLog()
rec := s.ips[domain]
updated := false
if isNewer(rec.A, newRec.A) {
rec.A = newRec.A
updated = true
}
if isNewer(rec.AAAA, newRec.AAAA) {
rec.AAAA = newRec.AAAA
updated = true
}
if updated {
s.ips[domain] = rec
}
if newRec.A != nil {
s.pub.Publish(domain+"4", nil)
}
if newRec.AAAA != nil {
s.pub.Publish(domain+"6", nil)
}
s.Unlock()
common.Must(s.cleanup.Start())
}
func (s *ClassicNameServer) newReqID() uint16 {
return uint16(atomic.AddUint32(&s.reqID, 1))
}
func (s *ClassicNameServer) addPendingRequest(req *dnsRequest) {
s.Lock()
defer s.Unlock()
id := req.msg.ID
req.expire = time.Now().Add(time.Second * 8)
s.requests[id] = *req
}
func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option IPOption) {
newError(s.name, " querying DNS for: ", domain).AtDebug().WriteToLog(session.ExportIDToError(ctx))
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
for _, req := range reqs {
s.addPendingRequest(req)
b, _ := dns.PackMessage(req.msg)
udpCtx := context.Background()
if inbound := session.InboundFromContext(ctx); inbound != nil {
udpCtx = session.ContextWithInbound(udpCtx, inbound)
}
udpCtx = session.ContextWithContent(udpCtx, &session.Content{
Protocol: "dns",
})
s.udpServer.Dispatch(udpCtx, s.address, b)
}
}
func (s *ClassicNameServer) findIPsForDomain(domain string, option IPOption) ([]net.IP, error) {
s.RLock()
record, found := s.ips[domain]
s.RUnlock()
if !found {
return nil, errRecordNotFound
}
var ips []net.Address
var lastErr error
if option.IPv4Enable {
a, err := record.A.getIPs()
if err != nil {
lastErr = err
}
ips = append(ips, a...)
}
if option.IPv6Enable {
aaaa, err := record.AAAA.getIPs()
if err != nil {
lastErr = err
}
ips = append(ips, aaaa...)
}
if len(ips) > 0 {
return toNetIP(ips)
}
if lastErr != nil {
return nil, lastErr
}
return nil, dns_feature.ErrEmptyResponse
}
// QueryIP implements Server.
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option IPOption) ([]net.IP, error) {
fqdn := Fqdn(domain)
ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound {
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
return ips, err
}
// ipv4 and ipv6 belong to different subscription groups
var sub4, sub6 *pubsub.Subscriber
if option.IPv4Enable {
sub4 = s.pub.Subscribe(fqdn + "4")
defer sub4.Close()
}
if option.IPv6Enable {
sub6 = s.pub.Subscribe(fqdn + "6")
defer sub6.Close()
}
done := make(chan interface{})
go func() {
if sub4 != nil {
select {
case <-sub4.Wait():
case <-ctx.Done():
}
}
if sub6 != nil {
select {
case <-sub6.Wait():
case <-ctx.Done():
}
}
close(done)
}()
s.sendQuery(ctx, fqdn, clientIP, option)
for {
ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound {
return ips, err
}
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-done:
}
}
}
v2ray-core-4.34.0/app/log/ 0000775 0000000 0000000 00000000000 13774574720 0015154 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/log/command/ 0000775 0000000 0000000 00000000000 13774574720 0016572 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/log/command/command.go 0000664 0000000 0000000 00000002332 13774574720 0020537 0 ustar 00root root 0000000 0000000 // +build !confonly
package command
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
grpc "google.golang.org/grpc"
"v2ray.com/core"
"v2ray.com/core/app/log"
"v2ray.com/core/common"
)
type LoggerServer struct {
V *core.Instance
}
// RestartLogger implements LoggerService.
func (s *LoggerServer) RestartLogger(ctx context.Context, request *RestartLoggerRequest) (*RestartLoggerResponse, error) {
logger := s.V.GetFeature((*log.Instance)(nil))
if logger == nil {
return nil, newError("unable to get logger instance")
}
if err := logger.Close(); err != nil {
return nil, newError("failed to close logger").Base(err)
}
if err := logger.Start(); err != nil {
return nil, newError("failed to start logger").Base(err)
}
return &RestartLoggerResponse{}, nil
}
func (s *LoggerServer) mustEmbedUnimplementedLoggerServiceServer() {}
type service struct {
v *core.Instance
}
func (s *service) Register(server *grpc.Server) {
RegisterLoggerServiceServer(server, &LoggerServer{
V: s.v,
})
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
s := core.MustFromContext(ctx)
return &service{v: s}, nil
}))
}
v2ray-core-4.34.0/app/log/command/command_test.go 0000664 0000000 0000000 00000001457 13774574720 0021605 0 ustar 00root root 0000000 0000000 package command_test
import (
"context"
"testing"
"v2ray.com/core"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/log"
. "v2ray.com/core/app/log/command"
"v2ray.com/core/app/proxyman"
_ "v2ray.com/core/app/proxyman/inbound"
_ "v2ray.com/core/app/proxyman/outbound"
"v2ray.com/core/common"
"v2ray.com/core/common/serial"
)
func TestLoggerRestart(t *testing.T) {
v, err := core.New(&core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{}),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.InboundConfig{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
},
})
common.Must(err)
common.Must(v.Start())
server := &LoggerServer{
V: v,
}
common.Must2(server.RestartLogger(context.Background(), &RestartLoggerRequest{}))
}
v2ray-core-4.34.0/app/log/command/config.pb.go 0000664 0000000 0000000 00000022175 13774574720 0020775 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: app/log/command/config.proto
package command
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_log_command_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_log_command_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_log_command_config_proto_rawDescGZIP(), []int{0}
}
type RestartLoggerRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *RestartLoggerRequest) Reset() {
*x = RestartLoggerRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_app_log_command_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RestartLoggerRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RestartLoggerRequest) ProtoMessage() {}
func (x *RestartLoggerRequest) ProtoReflect() protoreflect.Message {
mi := &file_app_log_command_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RestartLoggerRequest.ProtoReflect.Descriptor instead.
func (*RestartLoggerRequest) Descriptor() ([]byte, []int) {
return file_app_log_command_config_proto_rawDescGZIP(), []int{1}
}
type RestartLoggerResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *RestartLoggerResponse) Reset() {
*x = RestartLoggerResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_app_log_command_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RestartLoggerResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RestartLoggerResponse) ProtoMessage() {}
func (x *RestartLoggerResponse) ProtoReflect() protoreflect.Message {
mi := &file_app_log_command_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RestartLoggerResponse.ProtoReflect.Descriptor instead.
func (*RestartLoggerResponse) Descriptor() ([]byte, []int) {
return file_app_log_command_config_proto_rawDescGZIP(), []int{2}
}
var File_app_log_command_config_proto protoreflect.FileDescriptor
var file_app_log_command_config_proto_rawDesc = []byte{
0x0a, 0x1c, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c,
0x6f, 0x67, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x22, 0x16, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c,
0x6f, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x17, 0x0a, 0x15,
0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x87, 0x01, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x76, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x74, 0x61,
0x72, 0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x12, 0x30, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f, 0x67,
0x67, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c,
0x6f, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42,
0x5f, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
0x64, 0x50, 0x01, 0x5a, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,
0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
0x61, 0x6e, 0x64, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65,
0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4c, 0x6f, 0x67, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_log_command_config_proto_rawDescOnce sync.Once
file_app_log_command_config_proto_rawDescData = file_app_log_command_config_proto_rawDesc
)
func file_app_log_command_config_proto_rawDescGZIP() []byte {
file_app_log_command_config_proto_rawDescOnce.Do(func() {
file_app_log_command_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_log_command_config_proto_rawDescData)
})
return file_app_log_command_config_proto_rawDescData
}
var file_app_log_command_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_app_log_command_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: v2ray.core.app.log.command.Config
(*RestartLoggerRequest)(nil), // 1: v2ray.core.app.log.command.RestartLoggerRequest
(*RestartLoggerResponse)(nil), // 2: v2ray.core.app.log.command.RestartLoggerResponse
}
var file_app_log_command_config_proto_depIdxs = []int32{
1, // 0: v2ray.core.app.log.command.LoggerService.RestartLogger:input_type -> v2ray.core.app.log.command.RestartLoggerRequest
2, // 1: v2ray.core.app.log.command.LoggerService.RestartLogger:output_type -> v2ray.core.app.log.command.RestartLoggerResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_app_log_command_config_proto_init() }
func file_app_log_command_config_proto_init() {
if File_app_log_command_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_log_command_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_log_command_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RestartLoggerRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_log_command_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RestartLoggerResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_log_command_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_app_log_command_config_proto_goTypes,
DependencyIndexes: file_app_log_command_config_proto_depIdxs,
MessageInfos: file_app_log_command_config_proto_msgTypes,
}.Build()
File_app_log_command_config_proto = out.File
file_app_log_command_config_proto_rawDesc = nil
file_app_log_command_config_proto_goTypes = nil
file_app_log_command_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/app/log/command/config.proto 0000664 0000000 0000000 00000000677 13774574720 0021136 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.app.log.command;
option csharp_namespace = "V2Ray.Core.App.Log.Command";
option go_package = "v2ray.com/core/app/log/command";
option java_package = "com.v2ray.core.app.log.command";
option java_multiple_files = true;
message Config {}
message RestartLoggerRequest {}
message RestartLoggerResponse {}
service LoggerService {
rpc RestartLogger(RestartLoggerRequest) returns (RestartLoggerResponse) {}
}
v2ray-core-4.34.0/app/log/command/config_grpc.pb.go 0000664 0000000 0000000 00000007004 13774574720 0022002 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package command
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion7
// LoggerServiceClient is the client API for LoggerService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type LoggerServiceClient interface {
RestartLogger(ctx context.Context, in *RestartLoggerRequest, opts ...grpc.CallOption) (*RestartLoggerResponse, error)
}
type loggerServiceClient struct {
cc grpc.ClientConnInterface
}
func NewLoggerServiceClient(cc grpc.ClientConnInterface) LoggerServiceClient {
return &loggerServiceClient{cc}
}
func (c *loggerServiceClient) RestartLogger(ctx context.Context, in *RestartLoggerRequest, opts ...grpc.CallOption) (*RestartLoggerResponse, error) {
out := new(RestartLoggerResponse)
err := c.cc.Invoke(ctx, "/v2ray.core.app.log.command.LoggerService/RestartLogger", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// LoggerServiceServer is the server API for LoggerService service.
// All implementations must embed UnimplementedLoggerServiceServer
// for forward compatibility
type LoggerServiceServer interface {
RestartLogger(context.Context, *RestartLoggerRequest) (*RestartLoggerResponse, error)
mustEmbedUnimplementedLoggerServiceServer()
}
// UnimplementedLoggerServiceServer must be embedded to have forward compatible implementations.
type UnimplementedLoggerServiceServer struct {
}
func (UnimplementedLoggerServiceServer) RestartLogger(context.Context, *RestartLoggerRequest) (*RestartLoggerResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method RestartLogger not implemented")
}
func (UnimplementedLoggerServiceServer) mustEmbedUnimplementedLoggerServiceServer() {}
// UnsafeLoggerServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to LoggerServiceServer will
// result in compilation errors.
type UnsafeLoggerServiceServer interface {
mustEmbedUnimplementedLoggerServiceServer()
}
func RegisterLoggerServiceServer(s grpc.ServiceRegistrar, srv LoggerServiceServer) {
s.RegisterService(&_LoggerService_serviceDesc, srv)
}
func _LoggerService_RestartLogger_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RestartLoggerRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(LoggerServiceServer).RestartLogger(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.log.command.LoggerService/RestartLogger",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(LoggerServiceServer).RestartLogger(ctx, req.(*RestartLoggerRequest))
}
return interceptor(ctx, in, info, handler)
}
var _LoggerService_serviceDesc = grpc.ServiceDesc{
ServiceName: "v2ray.core.app.log.command.LoggerService",
HandlerType: (*LoggerServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "RestartLogger",
Handler: _LoggerService_RestartLogger_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "app/log/command/config.proto",
}
v2ray-core-4.34.0/app/log/command/errors.generated.go 0000664 0000000 0000000 00000000315 13774574720 0022371 0 ustar 00root root 0000000 0000000 package command
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/app/log/config.pb.go 0000664 0000000 0000000 00000022726 13774574720 0017361 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: app/log/config.proto
package log
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
log "v2ray.com/core/common/log"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type LogType int32
const (
LogType_None LogType = 0
LogType_Console LogType = 1
LogType_File LogType = 2
LogType_Event LogType = 3
)
// Enum value maps for LogType.
var (
LogType_name = map[int32]string{
0: "None",
1: "Console",
2: "File",
3: "Event",
}
LogType_value = map[string]int32{
"None": 0,
"Console": 1,
"File": 2,
"Event": 3,
}
)
func (x LogType) Enum() *LogType {
p := new(LogType)
*p = x
return p
}
func (x LogType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (LogType) Descriptor() protoreflect.EnumDescriptor {
return file_app_log_config_proto_enumTypes[0].Descriptor()
}
func (LogType) Type() protoreflect.EnumType {
return &file_app_log_config_proto_enumTypes[0]
}
func (x LogType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use LogType.Descriptor instead.
func (LogType) EnumDescriptor() ([]byte, []int) {
return file_app_log_config_proto_rawDescGZIP(), []int{0}
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ErrorLogType LogType `protobuf:"varint,1,opt,name=error_log_type,json=errorLogType,proto3,enum=v2ray.core.app.log.LogType" json:"error_log_type,omitempty"`
ErrorLogLevel log.Severity `protobuf:"varint,2,opt,name=error_log_level,json=errorLogLevel,proto3,enum=v2ray.core.common.log.Severity" json:"error_log_level,omitempty"`
ErrorLogPath string `protobuf:"bytes,3,opt,name=error_log_path,json=errorLogPath,proto3" json:"error_log_path,omitempty"`
AccessLogType LogType `protobuf:"varint,4,opt,name=access_log_type,json=accessLogType,proto3,enum=v2ray.core.app.log.LogType" json:"access_log_type,omitempty"`
AccessLogPath string `protobuf:"bytes,5,opt,name=access_log_path,json=accessLogPath,proto3" json:"access_log_path,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_log_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_log_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_log_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetErrorLogType() LogType {
if x != nil {
return x.ErrorLogType
}
return LogType_None
}
func (x *Config) GetErrorLogLevel() log.Severity {
if x != nil {
return x.ErrorLogLevel
}
return log.Severity_Unknown
}
func (x *Config) GetErrorLogPath() string {
if x != nil {
return x.ErrorLogPath
}
return ""
}
func (x *Config) GetAccessLogType() LogType {
if x != nil {
return x.AccessLogType
}
return LogType_None
}
func (x *Config) GetAccessLogPath() string {
if x != nil {
return x.AccessLogPath
}
return ""
}
var File_app_log_config_proto protoreflect.FileDescriptor
var file_app_log_config_proto_rawDesc = []byte{
0x0a, 0x14, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x1a, 0x14, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x6c, 0x6f, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x22, 0xa7, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x41, 0x0a, 0x0e, 0x65,
0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65,
0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x47,
0x0a, 0x0f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65,
0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6c, 0x6f, 0x67, 0x2e,
0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4c,
0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x72, 0x72, 0x6f, 0x72,
0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4c, 0x6f, 0x67, 0x50, 0x61, 0x74, 0x68, 0x12, 0x43, 0x0a,
0x0f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65,
0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x4c, 0x6f, 0x67, 0x54,
0x79, 0x70, 0x65, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x54, 0x79,
0x70, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x6f, 0x67,
0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x63, 0x63,
0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x50, 0x61, 0x74, 0x68, 0x2a, 0x35, 0x0a, 0x07, 0x4c, 0x6f,
0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00, 0x12,
0x0b, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04,
0x46, 0x69, 0x6c, 0x65, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x10,
0x03, 0x42, 0x47, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x50, 0x01, 0x5a, 0x16, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
0x70, 0x2f, 0x6c, 0x6f, 0x67, 0xaa, 0x02, 0x12, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f,
0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4c, 0x6f, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_app_log_config_proto_rawDescOnce sync.Once
file_app_log_config_proto_rawDescData = file_app_log_config_proto_rawDesc
)
func file_app_log_config_proto_rawDescGZIP() []byte {
file_app_log_config_proto_rawDescOnce.Do(func() {
file_app_log_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_log_config_proto_rawDescData)
})
return file_app_log_config_proto_rawDescData
}
var file_app_log_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_app_log_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_app_log_config_proto_goTypes = []interface{}{
(LogType)(0), // 0: v2ray.core.app.log.LogType
(*Config)(nil), // 1: v2ray.core.app.log.Config
(log.Severity)(0), // 2: v2ray.core.common.log.Severity
}
var file_app_log_config_proto_depIdxs = []int32{
0, // 0: v2ray.core.app.log.Config.error_log_type:type_name -> v2ray.core.app.log.LogType
2, // 1: v2ray.core.app.log.Config.error_log_level:type_name -> v2ray.core.common.log.Severity
0, // 2: v2ray.core.app.log.Config.access_log_type:type_name -> v2ray.core.app.log.LogType
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_app_log_config_proto_init() }
func file_app_log_config_proto_init() {
if File_app_log_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_log_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_log_config_proto_rawDesc,
NumEnums: 1,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_app_log_config_proto_goTypes,
DependencyIndexes: file_app_log_config_proto_depIdxs,
EnumInfos: file_app_log_config_proto_enumTypes,
MessageInfos: file_app_log_config_proto_msgTypes,
}.Build()
File_app_log_config_proto = out.File
file_app_log_config_proto_rawDesc = nil
file_app_log_config_proto_goTypes = nil
file_app_log_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/app/log/config.proto 0000664 0000000 0000000 00000001012 13774574720 0017500 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.app.log;
option csharp_namespace = "V2Ray.Core.App.Log";
option go_package = "v2ray.com/core/app/log";
option java_package = "com.v2ray.core.app.log";
option java_multiple_files = true;
import "common/log/log.proto";
enum LogType {
None = 0;
Console = 1;
File = 2;
Event = 3;
}
message Config {
LogType error_log_type = 1;
v2ray.core.common.log.Severity error_log_level = 2;
string error_log_path = 3;
LogType access_log_type = 4;
string access_log_path = 5;
}
v2ray-core-4.34.0/app/log/errors.generated.go 0000664 0000000 0000000 00000000311 13774574720 0020747 0 ustar 00root root 0000000 0000000 package log
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/app/log/log.go 0000664 0000000 0000000 00000005320 13774574720 0016264 0 ustar 00root root 0000000 0000000 // +build !confonly
package log
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"sync"
"v2ray.com/core/common"
"v2ray.com/core/common/log"
)
// Instance is a log.Handler that handles logs.
type Instance struct {
sync.RWMutex
config *Config
accessLogger log.Handler
errorLogger log.Handler
active bool
}
// New creates a new log.Instance based on the given config.
func New(ctx context.Context, config *Config) (*Instance, error) {
g := &Instance{
config: config,
active: false,
}
log.RegisterHandler(g)
// start logger instantly on inited
// other modules would log during init
if err := g.startInternal(); err != nil {
return nil, err
}
newError("Logger started").AtDebug().WriteToLog()
return g, nil
}
func (g *Instance) initAccessLogger() error {
handler, err := createHandler(g.config.AccessLogType, HandlerCreatorOptions{
Path: g.config.AccessLogPath,
})
if err != nil {
return err
}
g.accessLogger = handler
return nil
}
func (g *Instance) initErrorLogger() error {
handler, err := createHandler(g.config.ErrorLogType, HandlerCreatorOptions{
Path: g.config.ErrorLogPath,
})
if err != nil {
return err
}
g.errorLogger = handler
return nil
}
// Type implements common.HasType.
func (*Instance) Type() interface{} {
return (*Instance)(nil)
}
func (g *Instance) startInternal() error {
g.Lock()
defer g.Unlock()
if g.active {
return nil
}
g.active = true
if err := g.initAccessLogger(); err != nil {
return newError("failed to initialize access logger").Base(err).AtWarning()
}
if err := g.initErrorLogger(); err != nil {
return newError("failed to initialize error logger").Base(err).AtWarning()
}
return nil
}
// Start implements common.Runnable.Start().
func (g *Instance) Start() error {
return g.startInternal()
}
// Handle implements log.Handler.
func (g *Instance) Handle(msg log.Message) {
g.RLock()
defer g.RUnlock()
if !g.active {
return
}
switch msg := msg.(type) {
case *log.AccessMessage:
if g.accessLogger != nil {
g.accessLogger.Handle(msg)
}
case *log.GeneralMessage:
if g.errorLogger != nil && msg.Severity <= g.config.ErrorLogLevel {
g.errorLogger.Handle(msg)
}
default:
// Swallow
}
}
// Close implements common.Closable.Close().
func (g *Instance) Close() error {
newError("Logger closing").AtDebug().WriteToLog()
g.Lock()
defer g.Unlock()
if !g.active {
return nil
}
g.active = false
common.Close(g.accessLogger)
g.accessLogger = nil
common.Close(g.errorLogger)
g.errorLogger = nil
return nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
}))
}
v2ray-core-4.34.0/app/log/log_creator.go 0000664 0000000 0000000 00000002471 13774574720 0020007 0 ustar 00root root 0000000 0000000 // +build !confonly
package log
import (
"v2ray.com/core/common"
"v2ray.com/core/common/log"
)
type HandlerCreatorOptions struct {
Path string
}
type HandlerCreator func(LogType, HandlerCreatorOptions) (log.Handler, error)
var (
handlerCreatorMap = make(map[LogType]HandlerCreator)
)
func RegisterHandlerCreator(logType LogType, f HandlerCreator) error {
if f == nil {
return newError("nil HandlerCreator")
}
handlerCreatorMap[logType] = f
return nil
}
func createHandler(logType LogType, options HandlerCreatorOptions) (log.Handler, error) {
creator, found := handlerCreatorMap[logType]
if !found {
return nil, newError("unable to create log handler for ", logType)
}
return creator(logType, options)
}
func init() {
common.Must(RegisterHandlerCreator(LogType_Console, func(lt LogType, options HandlerCreatorOptions) (log.Handler, error) {
return log.NewLogger(log.CreateStdoutLogWriter()), nil
}))
common.Must(RegisterHandlerCreator(LogType_File, func(lt LogType, options HandlerCreatorOptions) (log.Handler, error) {
creator, err := log.CreateFileLogWriter(options.Path)
if err != nil {
return nil, err
}
return log.NewLogger(creator), nil
}))
common.Must(RegisterHandlerCreator(LogType_None, func(lt LogType, options HandlerCreatorOptions) (log.Handler, error) {
return nil, nil
}))
}
v2ray-core-4.34.0/app/log/log_test.go 0000664 0000000 0000000 00000002326 13774574720 0017326 0 ustar 00root root 0000000 0000000 package log_test
import (
"context"
"testing"
"github.com/golang/mock/gomock"
"v2ray.com/core/app/log"
"v2ray.com/core/common"
clog "v2ray.com/core/common/log"
"v2ray.com/core/testing/mocks"
)
func TestCustomLogHandler(t *testing.T) {
mockCtl := gomock.NewController(t)
defer mockCtl.Finish()
var loggedValue []string
mockHandler := mocks.NewLogHandler(mockCtl)
mockHandler.EXPECT().Handle(gomock.Any()).AnyTimes().DoAndReturn(func(msg clog.Message) {
loggedValue = append(loggedValue, msg.String())
})
log.RegisterHandlerCreator(log.LogType_Console, func(lt log.LogType, options log.HandlerCreatorOptions) (clog.Handler, error) {
return mockHandler, nil
})
logger, err := log.New(context.Background(), &log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
AccessLogType: log.LogType_None,
})
common.Must(err)
common.Must(logger.Start())
clog.Record(&clog.GeneralMessage{
Severity: clog.Severity_Debug,
Content: "test",
})
if len(loggedValue) < 2 {
t.Fatal("expected 2 log messages, but actually ", loggedValue)
}
if loggedValue[1] != "[Debug] test" {
t.Fatal("expected '[Debug] test', but actually ", loggedValue[1])
}
common.Must(logger.Close())
}
v2ray-core-4.34.0/app/policy/ 0000775 0000000 0000000 00000000000 13774574720 0015672 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/policy/config.go 0000664 0000000 0000000 00000004715 13774574720 0017475 0 ustar 00root root 0000000 0000000 package policy
import (
"time"
"v2ray.com/core/features/policy"
)
// Duration converts Second to time.Duration.
func (s *Second) Duration() time.Duration {
if s == nil {
return 0
}
return time.Second * time.Duration(s.Value)
}
func defaultPolicy() *Policy {
p := policy.SessionDefault()
return &Policy{
Timeout: &Policy_Timeout{
Handshake: &Second{Value: uint32(p.Timeouts.Handshake / time.Second)},
ConnectionIdle: &Second{Value: uint32(p.Timeouts.ConnectionIdle / time.Second)},
UplinkOnly: &Second{Value: uint32(p.Timeouts.UplinkOnly / time.Second)},
DownlinkOnly: &Second{Value: uint32(p.Timeouts.DownlinkOnly / time.Second)},
},
Buffer: &Policy_Buffer{
Connection: p.Buffer.PerConnection,
},
}
}
func (p *Policy_Timeout) overrideWith(another *Policy_Timeout) {
if another.Handshake != nil {
p.Handshake = &Second{Value: another.Handshake.Value}
}
if another.ConnectionIdle != nil {
p.ConnectionIdle = &Second{Value: another.ConnectionIdle.Value}
}
if another.UplinkOnly != nil {
p.UplinkOnly = &Second{Value: another.UplinkOnly.Value}
}
if another.DownlinkOnly != nil {
p.DownlinkOnly = &Second{Value: another.DownlinkOnly.Value}
}
}
func (p *Policy) overrideWith(another *Policy) {
if another.Timeout != nil {
p.Timeout.overrideWith(another.Timeout)
}
if another.Stats != nil && p.Stats == nil {
p.Stats = &Policy_Stats{}
p.Stats = another.Stats
}
if another.Buffer != nil {
p.Buffer = &Policy_Buffer{
Connection: another.Buffer.Connection,
}
}
}
// ToCorePolicy converts this Policy to policy.Session.
func (p *Policy) ToCorePolicy() policy.Session {
cp := policy.SessionDefault()
if p.Timeout != nil {
cp.Timeouts.ConnectionIdle = p.Timeout.ConnectionIdle.Duration()
cp.Timeouts.Handshake = p.Timeout.Handshake.Duration()
cp.Timeouts.DownlinkOnly = p.Timeout.DownlinkOnly.Duration()
cp.Timeouts.UplinkOnly = p.Timeout.UplinkOnly.Duration()
}
if p.Stats != nil {
cp.Stats.UserUplink = p.Stats.UserUplink
cp.Stats.UserDownlink = p.Stats.UserDownlink
}
if p.Buffer != nil {
cp.Buffer.PerConnection = p.Buffer.Connection
}
return cp
}
// ToCorePolicy converts this SystemPolicy to policy.System.
func (p *SystemPolicy) ToCorePolicy() policy.System {
return policy.System{
Stats: policy.SystemStats{
InboundUplink: p.Stats.InboundUplink,
InboundDownlink: p.Stats.InboundDownlink,
OutboundUplink: p.Stats.OutboundUplink,
OutboundDownlink: p.Stats.OutboundDownlink,
},
}
}
v2ray-core-4.34.0/app/policy/config.pb.go 0000664 0000000 0000000 00000062646 13774574720 0020104 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: app/policy/config.proto
package policy
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Second struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *Second) Reset() {
*x = Second{}
if protoimpl.UnsafeEnabled {
mi := &file_app_policy_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Second) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Second) ProtoMessage() {}
func (x *Second) ProtoReflect() protoreflect.Message {
mi := &file_app_policy_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Second.ProtoReflect.Descriptor instead.
func (*Second) Descriptor() ([]byte, []int) {
return file_app_policy_config_proto_rawDescGZIP(), []int{0}
}
func (x *Second) GetValue() uint32 {
if x != nil {
return x.Value
}
return 0
}
type Policy struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Timeout *Policy_Timeout `protobuf:"bytes,1,opt,name=timeout,proto3" json:"timeout,omitempty"`
Stats *Policy_Stats `protobuf:"bytes,2,opt,name=stats,proto3" json:"stats,omitempty"`
Buffer *Policy_Buffer `protobuf:"bytes,3,opt,name=buffer,proto3" json:"buffer,omitempty"`
}
func (x *Policy) Reset() {
*x = Policy{}
if protoimpl.UnsafeEnabled {
mi := &file_app_policy_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Policy) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Policy) ProtoMessage() {}
func (x *Policy) ProtoReflect() protoreflect.Message {
mi := &file_app_policy_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Policy.ProtoReflect.Descriptor instead.
func (*Policy) Descriptor() ([]byte, []int) {
return file_app_policy_config_proto_rawDescGZIP(), []int{1}
}
func (x *Policy) GetTimeout() *Policy_Timeout {
if x != nil {
return x.Timeout
}
return nil
}
func (x *Policy) GetStats() *Policy_Stats {
if x != nil {
return x.Stats
}
return nil
}
func (x *Policy) GetBuffer() *Policy_Buffer {
if x != nil {
return x.Buffer
}
return nil
}
type SystemPolicy struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Stats *SystemPolicy_Stats `protobuf:"bytes,1,opt,name=stats,proto3" json:"stats,omitempty"`
}
func (x *SystemPolicy) Reset() {
*x = SystemPolicy{}
if protoimpl.UnsafeEnabled {
mi := &file_app_policy_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SystemPolicy) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SystemPolicy) ProtoMessage() {}
func (x *SystemPolicy) ProtoReflect() protoreflect.Message {
mi := &file_app_policy_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SystemPolicy.ProtoReflect.Descriptor instead.
func (*SystemPolicy) Descriptor() ([]byte, []int) {
return file_app_policy_config_proto_rawDescGZIP(), []int{2}
}
func (x *SystemPolicy) GetStats() *SystemPolicy_Stats {
if x != nil {
return x.Stats
}
return nil
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Level map[uint32]*Policy `protobuf:"bytes,1,rep,name=level,proto3" json:"level,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
System *SystemPolicy `protobuf:"bytes,2,opt,name=system,proto3" json:"system,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_policy_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_policy_config_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_policy_config_proto_rawDescGZIP(), []int{3}
}
func (x *Config) GetLevel() map[uint32]*Policy {
if x != nil {
return x.Level
}
return nil
}
func (x *Config) GetSystem() *SystemPolicy {
if x != nil {
return x.System
}
return nil
}
// Timeout is a message for timeout settings in various stages, in seconds.
type Policy_Timeout struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Handshake *Second `protobuf:"bytes,1,opt,name=handshake,proto3" json:"handshake,omitempty"`
ConnectionIdle *Second `protobuf:"bytes,2,opt,name=connection_idle,json=connectionIdle,proto3" json:"connection_idle,omitempty"`
UplinkOnly *Second `protobuf:"bytes,3,opt,name=uplink_only,json=uplinkOnly,proto3" json:"uplink_only,omitempty"`
DownlinkOnly *Second `protobuf:"bytes,4,opt,name=downlink_only,json=downlinkOnly,proto3" json:"downlink_only,omitempty"`
}
func (x *Policy_Timeout) Reset() {
*x = Policy_Timeout{}
if protoimpl.UnsafeEnabled {
mi := &file_app_policy_config_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Policy_Timeout) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Policy_Timeout) ProtoMessage() {}
func (x *Policy_Timeout) ProtoReflect() protoreflect.Message {
mi := &file_app_policy_config_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Policy_Timeout.ProtoReflect.Descriptor instead.
func (*Policy_Timeout) Descriptor() ([]byte, []int) {
return file_app_policy_config_proto_rawDescGZIP(), []int{1, 0}
}
func (x *Policy_Timeout) GetHandshake() *Second {
if x != nil {
return x.Handshake
}
return nil
}
func (x *Policy_Timeout) GetConnectionIdle() *Second {
if x != nil {
return x.ConnectionIdle
}
return nil
}
func (x *Policy_Timeout) GetUplinkOnly() *Second {
if x != nil {
return x.UplinkOnly
}
return nil
}
func (x *Policy_Timeout) GetDownlinkOnly() *Second {
if x != nil {
return x.DownlinkOnly
}
return nil
}
type Policy_Stats struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
UserUplink bool `protobuf:"varint,1,opt,name=user_uplink,json=userUplink,proto3" json:"user_uplink,omitempty"`
UserDownlink bool `protobuf:"varint,2,opt,name=user_downlink,json=userDownlink,proto3" json:"user_downlink,omitempty"`
}
func (x *Policy_Stats) Reset() {
*x = Policy_Stats{}
if protoimpl.UnsafeEnabled {
mi := &file_app_policy_config_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Policy_Stats) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Policy_Stats) ProtoMessage() {}
func (x *Policy_Stats) ProtoReflect() protoreflect.Message {
mi := &file_app_policy_config_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Policy_Stats.ProtoReflect.Descriptor instead.
func (*Policy_Stats) Descriptor() ([]byte, []int) {
return file_app_policy_config_proto_rawDescGZIP(), []int{1, 1}
}
func (x *Policy_Stats) GetUserUplink() bool {
if x != nil {
return x.UserUplink
}
return false
}
func (x *Policy_Stats) GetUserDownlink() bool {
if x != nil {
return x.UserDownlink
}
return false
}
type Policy_Buffer struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Buffer size per connection, in bytes. -1 for unlimited buffer.
Connection int32 `protobuf:"varint,1,opt,name=connection,proto3" json:"connection,omitempty"`
}
func (x *Policy_Buffer) Reset() {
*x = Policy_Buffer{}
if protoimpl.UnsafeEnabled {
mi := &file_app_policy_config_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Policy_Buffer) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Policy_Buffer) ProtoMessage() {}
func (x *Policy_Buffer) ProtoReflect() protoreflect.Message {
mi := &file_app_policy_config_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Policy_Buffer.ProtoReflect.Descriptor instead.
func (*Policy_Buffer) Descriptor() ([]byte, []int) {
return file_app_policy_config_proto_rawDescGZIP(), []int{1, 2}
}
func (x *Policy_Buffer) GetConnection() int32 {
if x != nil {
return x.Connection
}
return 0
}
type SystemPolicy_Stats struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
InboundUplink bool `protobuf:"varint,1,opt,name=inbound_uplink,json=inboundUplink,proto3" json:"inbound_uplink,omitempty"`
InboundDownlink bool `protobuf:"varint,2,opt,name=inbound_downlink,json=inboundDownlink,proto3" json:"inbound_downlink,omitempty"`
OutboundUplink bool `protobuf:"varint,3,opt,name=outbound_uplink,json=outboundUplink,proto3" json:"outbound_uplink,omitempty"`
OutboundDownlink bool `protobuf:"varint,4,opt,name=outbound_downlink,json=outboundDownlink,proto3" json:"outbound_downlink,omitempty"`
}
func (x *SystemPolicy_Stats) Reset() {
*x = SystemPolicy_Stats{}
if protoimpl.UnsafeEnabled {
mi := &file_app_policy_config_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SystemPolicy_Stats) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SystemPolicy_Stats) ProtoMessage() {}
func (x *SystemPolicy_Stats) ProtoReflect() protoreflect.Message {
mi := &file_app_policy_config_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SystemPolicy_Stats.ProtoReflect.Descriptor instead.
func (*SystemPolicy_Stats) Descriptor() ([]byte, []int) {
return file_app_policy_config_proto_rawDescGZIP(), []int{2, 0}
}
func (x *SystemPolicy_Stats) GetInboundUplink() bool {
if x != nil {
return x.InboundUplink
}
return false
}
func (x *SystemPolicy_Stats) GetInboundDownlink() bool {
if x != nil {
return x.InboundDownlink
}
return false
}
func (x *SystemPolicy_Stats) GetOutboundUplink() bool {
if x != nil {
return x.OutboundUplink
}
return false
}
func (x *SystemPolicy_Stats) GetOutboundDownlink() bool {
if x != nil {
return x.OutboundDownlink
}
return false
}
var File_app_policy_config_proto protoreflect.FileDescriptor
var file_app_policy_config_proto_rawDesc = []byte{
0x0a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2f, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
0x22, 0x1e, 0x0a, 0x06, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x22, 0xd0, 0x04, 0x0a, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x3f, 0x0a, 0x07, 0x74,
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f,
0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x54, 0x69, 0x6d, 0x65,
0x6f, 0x75, 0x74, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x39, 0x0a, 0x05,
0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c,
0x69, 0x63, 0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73,
0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x12, 0x3c, 0x0a, 0x06, 0x62, 0x75, 0x66, 0x66, 0x65,
0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x52, 0x06, 0x62,
0x75, 0x66, 0x66, 0x65, 0x72, 0x1a, 0x92, 0x02, 0x0a, 0x07, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75,
0x74, 0x12, 0x3b, 0x0a, 0x09, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x63,
0x6f, 0x6e, 0x64, 0x52, 0x09, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x12, 0x46,
0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x6c,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x49, 0x64, 0x6c, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b,
0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c,
0x69, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x69,
0x6e, 0x6b, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x42, 0x0a, 0x0d, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69,
0x6e, 0x6b, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x52, 0x0c, 0x64, 0x6f,
0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4f, 0x6e, 0x6c, 0x79, 0x1a, 0x4d, 0x0a, 0x05, 0x53, 0x74,
0x61, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x75, 0x70, 0x6c, 0x69,
0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x55, 0x70,
0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x77,
0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x73, 0x65,
0x72, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x1a, 0x28, 0x0a, 0x06, 0x42, 0x75, 0x66,
0x66, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x22, 0x81, 0x02, 0x0a, 0x0c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x50, 0x6f,
0x6c, 0x69, 0x63, 0x79, 0x12, 0x3f, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x79, 0x73, 0x74,
0x65, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05,
0x73, 0x74, 0x61, 0x74, 0x73, 0x1a, 0xaf, 0x01, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12,
0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e,
0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,
0x52, 0x0f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e,
0x6b, 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x75, 0x70,
0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6f, 0x75, 0x74, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x75,
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18,
0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x44,
0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0xde, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x12, 0x3e, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x28, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,
0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x2e, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x6c, 0x65, 0x76,
0x65, 0x6c, 0x12, 0x3b, 0x0a, 0x06, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65,
0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x06, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x1a,
0x57, 0x0a, 0x0a, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
0x33, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d,
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x50, 0x01, 0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x6f, 0x6c, 0x69,
0x63, 0x79, 0xaa, 0x02, 0x15, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e,
0x41, 0x70, 0x70, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_app_policy_config_proto_rawDescOnce sync.Once
file_app_policy_config_proto_rawDescData = file_app_policy_config_proto_rawDesc
)
func file_app_policy_config_proto_rawDescGZIP() []byte {
file_app_policy_config_proto_rawDescOnce.Do(func() {
file_app_policy_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_policy_config_proto_rawDescData)
})
return file_app_policy_config_proto_rawDescData
}
var file_app_policy_config_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_app_policy_config_proto_goTypes = []interface{}{
(*Second)(nil), // 0: v2ray.core.app.policy.Second
(*Policy)(nil), // 1: v2ray.core.app.policy.Policy
(*SystemPolicy)(nil), // 2: v2ray.core.app.policy.SystemPolicy
(*Config)(nil), // 3: v2ray.core.app.policy.Config
(*Policy_Timeout)(nil), // 4: v2ray.core.app.policy.Policy.Timeout
(*Policy_Stats)(nil), // 5: v2ray.core.app.policy.Policy.Stats
(*Policy_Buffer)(nil), // 6: v2ray.core.app.policy.Policy.Buffer
(*SystemPolicy_Stats)(nil), // 7: v2ray.core.app.policy.SystemPolicy.Stats
nil, // 8: v2ray.core.app.policy.Config.LevelEntry
}
var file_app_policy_config_proto_depIdxs = []int32{
4, // 0: v2ray.core.app.policy.Policy.timeout:type_name -> v2ray.core.app.policy.Policy.Timeout
5, // 1: v2ray.core.app.policy.Policy.stats:type_name -> v2ray.core.app.policy.Policy.Stats
6, // 2: v2ray.core.app.policy.Policy.buffer:type_name -> v2ray.core.app.policy.Policy.Buffer
7, // 3: v2ray.core.app.policy.SystemPolicy.stats:type_name -> v2ray.core.app.policy.SystemPolicy.Stats
8, // 4: v2ray.core.app.policy.Config.level:type_name -> v2ray.core.app.policy.Config.LevelEntry
2, // 5: v2ray.core.app.policy.Config.system:type_name -> v2ray.core.app.policy.SystemPolicy
0, // 6: v2ray.core.app.policy.Policy.Timeout.handshake:type_name -> v2ray.core.app.policy.Second
0, // 7: v2ray.core.app.policy.Policy.Timeout.connection_idle:type_name -> v2ray.core.app.policy.Second
0, // 8: v2ray.core.app.policy.Policy.Timeout.uplink_only:type_name -> v2ray.core.app.policy.Second
0, // 9: v2ray.core.app.policy.Policy.Timeout.downlink_only:type_name -> v2ray.core.app.policy.Second
1, // 10: v2ray.core.app.policy.Config.LevelEntry.value:type_name -> v2ray.core.app.policy.Policy
11, // [11:11] is the sub-list for method output_type
11, // [11:11] is the sub-list for method input_type
11, // [11:11] is the sub-list for extension type_name
11, // [11:11] is the sub-list for extension extendee
0, // [0:11] is the sub-list for field type_name
}
func init() { file_app_policy_config_proto_init() }
func file_app_policy_config_proto_init() {
if File_app_policy_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_policy_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Second); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_policy_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Policy); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_policy_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SystemPolicy); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_policy_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_policy_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Policy_Timeout); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_policy_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Policy_Stats); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_policy_config_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Policy_Buffer); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_policy_config_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SystemPolicy_Stats); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_policy_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 9,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_app_policy_config_proto_goTypes,
DependencyIndexes: file_app_policy_config_proto_depIdxs,
MessageInfos: file_app_policy_config_proto_msgTypes,
}.Build()
File_app_policy_config_proto = out.File
file_app_policy_config_proto_rawDesc = nil
file_app_policy_config_proto_goTypes = nil
file_app_policy_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/app/policy/config.proto 0000664 0000000 0000000 00000002026 13774574720 0020224 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.app.policy;
option csharp_namespace = "V2Ray.Core.App.Policy";
option go_package = "v2ray.com/core/app/policy";
option java_package = "com.v2ray.core.app.policy";
option java_multiple_files = true;
message Second {
uint32 value = 1;
}
message Policy {
// Timeout is a message for timeout settings in various stages, in seconds.
message Timeout {
Second handshake = 1;
Second connection_idle = 2;
Second uplink_only = 3;
Second downlink_only = 4;
}
message Stats {
bool user_uplink = 1;
bool user_downlink = 2;
}
message Buffer {
// Buffer size per connection, in bytes. -1 for unlimited buffer.
int32 connection = 1;
}
Timeout timeout = 1;
Stats stats = 2;
Buffer buffer = 3;
}
message SystemPolicy {
message Stats {
bool inbound_uplink = 1;
bool inbound_downlink = 2;
bool outbound_uplink = 3;
bool outbound_downlink = 4;
}
Stats stats = 1;
}
message Config {
map level = 1;
SystemPolicy system = 2;
}
v2ray-core-4.34.0/app/policy/errors.generated.go 0000664 0000000 0000000 00000000314 13774574720 0021470 0 ustar 00root root 0000000 0000000 package policy
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/app/policy/manager.go 0000664 0000000 0000000 00000002603 13774574720 0017634 0 ustar 00root root 0000000 0000000 package policy
import (
"context"
"v2ray.com/core/common"
"v2ray.com/core/features/policy"
)
// Instance is an instance of Policy manager.
type Instance struct {
levels map[uint32]*Policy
system *SystemPolicy
}
// New creates new Policy manager instance.
func New(ctx context.Context, config *Config) (*Instance, error) {
m := &Instance{
levels: make(map[uint32]*Policy),
system: config.System,
}
if len(config.Level) > 0 {
for lv, p := range config.Level {
pp := defaultPolicy()
pp.overrideWith(p)
m.levels[lv] = pp
}
}
return m, nil
}
// Type implements common.HasType.
func (*Instance) Type() interface{} {
return policy.ManagerType()
}
// ForLevel implements policy.Manager.
func (m *Instance) ForLevel(level uint32) policy.Session {
if p, ok := m.levels[level]; ok {
return p.ToCorePolicy()
}
return policy.SessionDefault()
}
// ForSystem implements policy.Manager.
func (m *Instance) ForSystem() policy.System {
if m.system == nil {
return policy.System{}
}
return m.system.ToCorePolicy()
}
// Start implements common.Runnable.Start().
func (m *Instance) Start() error {
return nil
}
// Close implements common.Closable.Close().
func (m *Instance) Close() error {
return nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
}))
}
v2ray-core-4.34.0/app/policy/manager_test.go 0000664 0000000 0000000 00000001702 13774574720 0020672 0 ustar 00root root 0000000 0000000 package policy_test
import (
"context"
"testing"
"time"
. "v2ray.com/core/app/policy"
"v2ray.com/core/common"
"v2ray.com/core/features/policy"
)
func TestPolicy(t *testing.T) {
manager, err := New(context.Background(), &Config{
Level: map[uint32]*Policy{
0: {
Timeout: &Policy_Timeout{
Handshake: &Second{
Value: 2,
},
},
},
},
})
common.Must(err)
pDefault := policy.SessionDefault()
{
p := manager.ForLevel(0)
if p.Timeouts.Handshake != 2*time.Second {
t.Error("expect 2 sec timeout, but got ", p.Timeouts.Handshake)
}
if p.Timeouts.ConnectionIdle != pDefault.Timeouts.ConnectionIdle {
t.Error("expect ", pDefault.Timeouts.ConnectionIdle, " sec timeout, but got ", p.Timeouts.ConnectionIdle)
}
}
{
p := manager.ForLevel(1)
if p.Timeouts.Handshake != pDefault.Timeouts.Handshake {
t.Error("expect ", pDefault.Timeouts.Handshake, " sec timeout, but got ", p.Timeouts.Handshake)
}
}
}
v2ray-core-4.34.0/app/policy/policy.go 0000664 0000000 0000000 00000000215 13774574720 0017516 0 ustar 00root root 0000000 0000000 // Package policy is an implementation of policy.Manager feature.
package policy
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/app/proxyman/ 0000775 0000000 0000000 00000000000 13774574720 0016250 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/proxyman/command/ 0000775 0000000 0000000 00000000000 13774574720 0017666 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/proxyman/command/command.go 0000664 0000000 0000000 00000010376 13774574720 0021642 0 ustar 00root root 0000000 0000000 // +build !confonly
package command
import (
"context"
grpc "google.golang.org/grpc"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/features/inbound"
"v2ray.com/core/features/outbound"
"v2ray.com/core/proxy"
)
// InboundOperation is the interface for operations that applies to inbound handlers.
type InboundOperation interface {
// ApplyInbound applies this operation to the given inbound handler.
ApplyInbound(context.Context, inbound.Handler) error
}
// OutboundOperation is the interface for operations that applies to outbound handlers.
type OutboundOperation interface {
// ApplyOutbound applies this operation to the given outbound handler.
ApplyOutbound(context.Context, outbound.Handler) error
}
func getInbound(handler inbound.Handler) (proxy.Inbound, error) {
gi, ok := handler.(proxy.GetInbound)
if !ok {
return nil, newError("can't get inbound proxy from handler.")
}
return gi.GetInbound(), nil
}
// ApplyInbound implements InboundOperation.
func (op *AddUserOperation) ApplyInbound(ctx context.Context, handler inbound.Handler) error {
p, err := getInbound(handler)
if err != nil {
return err
}
um, ok := p.(proxy.UserManager)
if !ok {
return newError("proxy is not a UserManager")
}
mUser, err := op.User.ToMemoryUser()
if err != nil {
return newError("failed to parse user").Base(err)
}
return um.AddUser(ctx, mUser)
}
// ApplyInbound implements InboundOperation.
func (op *RemoveUserOperation) ApplyInbound(ctx context.Context, handler inbound.Handler) error {
p, err := getInbound(handler)
if err != nil {
return err
}
um, ok := p.(proxy.UserManager)
if !ok {
return newError("proxy is not a UserManager")
}
return um.RemoveUser(ctx, op.Email)
}
type handlerServer struct {
s *core.Instance
ihm inbound.Manager
ohm outbound.Manager
}
func (s *handlerServer) AddInbound(ctx context.Context, request *AddInboundRequest) (*AddInboundResponse, error) {
if err := core.AddInboundHandler(s.s, request.Inbound); err != nil {
return nil, err
}
return &AddInboundResponse{}, nil
}
func (s *handlerServer) RemoveInbound(ctx context.Context, request *RemoveInboundRequest) (*RemoveInboundResponse, error) {
return &RemoveInboundResponse{}, s.ihm.RemoveHandler(ctx, request.Tag)
}
func (s *handlerServer) AlterInbound(ctx context.Context, request *AlterInboundRequest) (*AlterInboundResponse, error) {
rawOperation, err := request.Operation.GetInstance()
if err != nil {
return nil, newError("unknown operation").Base(err)
}
operation, ok := rawOperation.(InboundOperation)
if !ok {
return nil, newError("not an inbound operation")
}
handler, err := s.ihm.GetHandler(ctx, request.Tag)
if err != nil {
return nil, newError("failed to get handler: ", request.Tag).Base(err)
}
return &AlterInboundResponse{}, operation.ApplyInbound(ctx, handler)
}
func (s *handlerServer) AddOutbound(ctx context.Context, request *AddOutboundRequest) (*AddOutboundResponse, error) {
if err := core.AddOutboundHandler(s.s, request.Outbound); err != nil {
return nil, err
}
return &AddOutboundResponse{}, nil
}
func (s *handlerServer) RemoveOutbound(ctx context.Context, request *RemoveOutboundRequest) (*RemoveOutboundResponse, error) {
return &RemoveOutboundResponse{}, s.ohm.RemoveHandler(ctx, request.Tag)
}
func (s *handlerServer) AlterOutbound(ctx context.Context, request *AlterOutboundRequest) (*AlterOutboundResponse, error) {
rawOperation, err := request.Operation.GetInstance()
if err != nil {
return nil, newError("unknown operation").Base(err)
}
operation, ok := rawOperation.(OutboundOperation)
if !ok {
return nil, newError("not an outbound operation")
}
handler := s.ohm.GetHandler(request.Tag)
return &AlterOutboundResponse{}, operation.ApplyOutbound(ctx, handler)
}
func (s *handlerServer) mustEmbedUnimplementedHandlerServiceServer() {}
type service struct {
v *core.Instance
}
func (s *service) Register(server *grpc.Server) {
hs := &handlerServer{
s: s.v,
}
common.Must(s.v.RequireFeatures(func(im inbound.Manager, om outbound.Manager) {
hs.ihm = im
hs.ohm = om
}))
RegisterHandlerServiceServer(server, hs)
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
s := core.MustFromContext(ctx)
return &service{v: s}, nil
}))
}
v2ray-core-4.34.0/app/proxyman/command/command.pb.go 0000664 0000000 0000000 00000116651 13774574720 0022245 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: app/proxyman/command/command.proto
package command
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
core "v2ray.com/core"
protocol "v2ray.com/core/common/protocol"
serial "v2ray.com/core/common/serial"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type AddUserOperation struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
User *protocol.User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"`
}
func (x *AddUserOperation) Reset() {
*x = AddUserOperation{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AddUserOperation) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AddUserOperation) ProtoMessage() {}
func (x *AddUserOperation) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AddUserOperation.ProtoReflect.Descriptor instead.
func (*AddUserOperation) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{0}
}
func (x *AddUserOperation) GetUser() *protocol.User {
if x != nil {
return x.User
}
return nil
}
type RemoveUserOperation struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"`
}
func (x *RemoveUserOperation) Reset() {
*x = RemoveUserOperation{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RemoveUserOperation) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RemoveUserOperation) ProtoMessage() {}
func (x *RemoveUserOperation) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RemoveUserOperation.ProtoReflect.Descriptor instead.
func (*RemoveUserOperation) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{1}
}
func (x *RemoveUserOperation) GetEmail() string {
if x != nil {
return x.Email
}
return ""
}
type AddInboundRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Inbound *core.InboundHandlerConfig `protobuf:"bytes,1,opt,name=inbound,proto3" json:"inbound,omitempty"`
}
func (x *AddInboundRequest) Reset() {
*x = AddInboundRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AddInboundRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AddInboundRequest) ProtoMessage() {}
func (x *AddInboundRequest) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AddInboundRequest.ProtoReflect.Descriptor instead.
func (*AddInboundRequest) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{2}
}
func (x *AddInboundRequest) GetInbound() *core.InboundHandlerConfig {
if x != nil {
return x.Inbound
}
return nil
}
type AddInboundResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *AddInboundResponse) Reset() {
*x = AddInboundResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AddInboundResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AddInboundResponse) ProtoMessage() {}
func (x *AddInboundResponse) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AddInboundResponse.ProtoReflect.Descriptor instead.
func (*AddInboundResponse) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{3}
}
type RemoveInboundRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
}
func (x *RemoveInboundRequest) Reset() {
*x = RemoveInboundRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RemoveInboundRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RemoveInboundRequest) ProtoMessage() {}
func (x *RemoveInboundRequest) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RemoveInboundRequest.ProtoReflect.Descriptor instead.
func (*RemoveInboundRequest) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{4}
}
func (x *RemoveInboundRequest) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
type RemoveInboundResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *RemoveInboundResponse) Reset() {
*x = RemoveInboundResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RemoveInboundResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RemoveInboundResponse) ProtoMessage() {}
func (x *RemoveInboundResponse) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RemoveInboundResponse.ProtoReflect.Descriptor instead.
func (*RemoveInboundResponse) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{5}
}
type AlterInboundRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
Operation *serial.TypedMessage `protobuf:"bytes,2,opt,name=operation,proto3" json:"operation,omitempty"`
}
func (x *AlterInboundRequest) Reset() {
*x = AlterInboundRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AlterInboundRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AlterInboundRequest) ProtoMessage() {}
func (x *AlterInboundRequest) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AlterInboundRequest.ProtoReflect.Descriptor instead.
func (*AlterInboundRequest) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{6}
}
func (x *AlterInboundRequest) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
func (x *AlterInboundRequest) GetOperation() *serial.TypedMessage {
if x != nil {
return x.Operation
}
return nil
}
type AlterInboundResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *AlterInboundResponse) Reset() {
*x = AlterInboundResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AlterInboundResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AlterInboundResponse) ProtoMessage() {}
func (x *AlterInboundResponse) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AlterInboundResponse.ProtoReflect.Descriptor instead.
func (*AlterInboundResponse) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{7}
}
type AddOutboundRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Outbound *core.OutboundHandlerConfig `protobuf:"bytes,1,opt,name=outbound,proto3" json:"outbound,omitempty"`
}
func (x *AddOutboundRequest) Reset() {
*x = AddOutboundRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AddOutboundRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AddOutboundRequest) ProtoMessage() {}
func (x *AddOutboundRequest) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AddOutboundRequest.ProtoReflect.Descriptor instead.
func (*AddOutboundRequest) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{8}
}
func (x *AddOutboundRequest) GetOutbound() *core.OutboundHandlerConfig {
if x != nil {
return x.Outbound
}
return nil
}
type AddOutboundResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *AddOutboundResponse) Reset() {
*x = AddOutboundResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AddOutboundResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AddOutboundResponse) ProtoMessage() {}
func (x *AddOutboundResponse) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AddOutboundResponse.ProtoReflect.Descriptor instead.
func (*AddOutboundResponse) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{9}
}
type RemoveOutboundRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
}
func (x *RemoveOutboundRequest) Reset() {
*x = RemoveOutboundRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RemoveOutboundRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RemoveOutboundRequest) ProtoMessage() {}
func (x *RemoveOutboundRequest) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RemoveOutboundRequest.ProtoReflect.Descriptor instead.
func (*RemoveOutboundRequest) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{10}
}
func (x *RemoveOutboundRequest) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
type RemoveOutboundResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *RemoveOutboundResponse) Reset() {
*x = RemoveOutboundResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RemoveOutboundResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RemoveOutboundResponse) ProtoMessage() {}
func (x *RemoveOutboundResponse) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RemoveOutboundResponse.ProtoReflect.Descriptor instead.
func (*RemoveOutboundResponse) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{11}
}
type AlterOutboundRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
Operation *serial.TypedMessage `protobuf:"bytes,2,opt,name=operation,proto3" json:"operation,omitempty"`
}
func (x *AlterOutboundRequest) Reset() {
*x = AlterOutboundRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AlterOutboundRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AlterOutboundRequest) ProtoMessage() {}
func (x *AlterOutboundRequest) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AlterOutboundRequest.ProtoReflect.Descriptor instead.
func (*AlterOutboundRequest) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{12}
}
func (x *AlterOutboundRequest) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
func (x *AlterOutboundRequest) GetOperation() *serial.TypedMessage {
if x != nil {
return x.Operation
}
return nil
}
type AlterOutboundResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *AlterOutboundResponse) Reset() {
*x = AlterOutboundResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AlterOutboundResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AlterOutboundResponse) ProtoMessage() {}
func (x *AlterOutboundResponse) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AlterOutboundResponse.ProtoReflect.Descriptor instead.
func (*AlterOutboundResponse) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{13}
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{14}
}
var File_app_proxyman_command_command_proto protoreflect.FileDescriptor
var file_app_proxyman_command_command_proto_rawDesc = []byte{
0x0a, 0x22, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f, 0x63,
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,
0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x22, 0x48, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x4f, 0x70, 0x65,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x2b, 0x0a, 0x13,
0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x4f, 0x0a, 0x11, 0x41, 0x64, 0x64,
0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a,
0x0a, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x14, 0x0a, 0x12, 0x41, 0x64,
0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x28, 0x0a, 0x14, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x17, 0x0a, 0x15, 0x52, 0x65,
0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x6d, 0x0a, 0x13, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x44, 0x0a, 0x09,
0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64,
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x22, 0x16, 0x0a, 0x14, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75,
0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x53, 0x0a, 0x12, 0x41, 0x64,
0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x3d, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x22,
0x15, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61,
0x67, 0x22, 0x18, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4f, 0x75, 0x74, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6e, 0x0a, 0x14, 0x41,
0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x44, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72,
0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x17, 0x0a, 0x15, 0x41,
0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0x90,
0x06, 0x0a, 0x0e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x12, 0x77, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12,
0x32, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
0x64, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x80, 0x01, 0x0a, 0x0d, 0x52,
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x35, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52,
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7d, 0x0a,
0x0c, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x34, 0x2e,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75,
0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7a, 0x0a, 0x0b,
0x41, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x33, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64,
0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x34, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x83, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x6d,
0x6f, 0x76, 0x65, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x36, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65,
0x6d, 0x6f, 0x76, 0x65, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4f, 0x75, 0x74, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x80,
0x01, 0x0a, 0x0d, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x12, 0x35, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
0x6e, 0x64, 0x2e, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x4f,
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x00, 0x42, 0x6e, 0x0a, 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x23, 0x76, 0x32, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa,
0x02, 0x1f, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70,
0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_proxyman_command_command_proto_rawDescOnce sync.Once
file_app_proxyman_command_command_proto_rawDescData = file_app_proxyman_command_command_proto_rawDesc
)
func file_app_proxyman_command_command_proto_rawDescGZIP() []byte {
file_app_proxyman_command_command_proto_rawDescOnce.Do(func() {
file_app_proxyman_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_proxyman_command_command_proto_rawDescData)
})
return file_app_proxyman_command_command_proto_rawDescData
}
var file_app_proxyman_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
var file_app_proxyman_command_command_proto_goTypes = []interface{}{
(*AddUserOperation)(nil), // 0: v2ray.core.app.proxyman.command.AddUserOperation
(*RemoveUserOperation)(nil), // 1: v2ray.core.app.proxyman.command.RemoveUserOperation
(*AddInboundRequest)(nil), // 2: v2ray.core.app.proxyman.command.AddInboundRequest
(*AddInboundResponse)(nil), // 3: v2ray.core.app.proxyman.command.AddInboundResponse
(*RemoveInboundRequest)(nil), // 4: v2ray.core.app.proxyman.command.RemoveInboundRequest
(*RemoveInboundResponse)(nil), // 5: v2ray.core.app.proxyman.command.RemoveInboundResponse
(*AlterInboundRequest)(nil), // 6: v2ray.core.app.proxyman.command.AlterInboundRequest
(*AlterInboundResponse)(nil), // 7: v2ray.core.app.proxyman.command.AlterInboundResponse
(*AddOutboundRequest)(nil), // 8: v2ray.core.app.proxyman.command.AddOutboundRequest
(*AddOutboundResponse)(nil), // 9: v2ray.core.app.proxyman.command.AddOutboundResponse
(*RemoveOutboundRequest)(nil), // 10: v2ray.core.app.proxyman.command.RemoveOutboundRequest
(*RemoveOutboundResponse)(nil), // 11: v2ray.core.app.proxyman.command.RemoveOutboundResponse
(*AlterOutboundRequest)(nil), // 12: v2ray.core.app.proxyman.command.AlterOutboundRequest
(*AlterOutboundResponse)(nil), // 13: v2ray.core.app.proxyman.command.AlterOutboundResponse
(*Config)(nil), // 14: v2ray.core.app.proxyman.command.Config
(*protocol.User)(nil), // 15: v2ray.core.common.protocol.User
(*core.InboundHandlerConfig)(nil), // 16: v2ray.core.InboundHandlerConfig
(*serial.TypedMessage)(nil), // 17: v2ray.core.common.serial.TypedMessage
(*core.OutboundHandlerConfig)(nil), // 18: v2ray.core.OutboundHandlerConfig
}
var file_app_proxyman_command_command_proto_depIdxs = []int32{
15, // 0: v2ray.core.app.proxyman.command.AddUserOperation.user:type_name -> v2ray.core.common.protocol.User
16, // 1: v2ray.core.app.proxyman.command.AddInboundRequest.inbound:type_name -> v2ray.core.InboundHandlerConfig
17, // 2: v2ray.core.app.proxyman.command.AlterInboundRequest.operation:type_name -> v2ray.core.common.serial.TypedMessage
18, // 3: v2ray.core.app.proxyman.command.AddOutboundRequest.outbound:type_name -> v2ray.core.OutboundHandlerConfig
17, // 4: v2ray.core.app.proxyman.command.AlterOutboundRequest.operation:type_name -> v2ray.core.common.serial.TypedMessage
2, // 5: v2ray.core.app.proxyman.command.HandlerService.AddInbound:input_type -> v2ray.core.app.proxyman.command.AddInboundRequest
4, // 6: v2ray.core.app.proxyman.command.HandlerService.RemoveInbound:input_type -> v2ray.core.app.proxyman.command.RemoveInboundRequest
6, // 7: v2ray.core.app.proxyman.command.HandlerService.AlterInbound:input_type -> v2ray.core.app.proxyman.command.AlterInboundRequest
8, // 8: v2ray.core.app.proxyman.command.HandlerService.AddOutbound:input_type -> v2ray.core.app.proxyman.command.AddOutboundRequest
10, // 9: v2ray.core.app.proxyman.command.HandlerService.RemoveOutbound:input_type -> v2ray.core.app.proxyman.command.RemoveOutboundRequest
12, // 10: v2ray.core.app.proxyman.command.HandlerService.AlterOutbound:input_type -> v2ray.core.app.proxyman.command.AlterOutboundRequest
3, // 11: v2ray.core.app.proxyman.command.HandlerService.AddInbound:output_type -> v2ray.core.app.proxyman.command.AddInboundResponse
5, // 12: v2ray.core.app.proxyman.command.HandlerService.RemoveInbound:output_type -> v2ray.core.app.proxyman.command.RemoveInboundResponse
7, // 13: v2ray.core.app.proxyman.command.HandlerService.AlterInbound:output_type -> v2ray.core.app.proxyman.command.AlterInboundResponse
9, // 14: v2ray.core.app.proxyman.command.HandlerService.AddOutbound:output_type -> v2ray.core.app.proxyman.command.AddOutboundResponse
11, // 15: v2ray.core.app.proxyman.command.HandlerService.RemoveOutbound:output_type -> v2ray.core.app.proxyman.command.RemoveOutboundResponse
13, // 16: v2ray.core.app.proxyman.command.HandlerService.AlterOutbound:output_type -> v2ray.core.app.proxyman.command.AlterOutboundResponse
11, // [11:17] is the sub-list for method output_type
5, // [5:11] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_app_proxyman_command_command_proto_init() }
func file_app_proxyman_command_command_proto_init() {
if File_app_proxyman_command_command_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_proxyman_command_command_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AddUserOperation); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_command_command_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RemoveUserOperation); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_command_command_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AddInboundRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_command_command_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AddInboundResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_command_command_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RemoveInboundRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_command_command_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RemoveInboundResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_command_command_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AlterInboundRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_command_command_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AlterInboundResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_command_command_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AddOutboundRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_command_command_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AddOutboundResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_command_command_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RemoveOutboundRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_command_command_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RemoveOutboundResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_command_command_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AlterOutboundRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_command_command_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AlterOutboundResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_command_command_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_proxyman_command_command_proto_rawDesc,
NumEnums: 0,
NumMessages: 15,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_app_proxyman_command_command_proto_goTypes,
DependencyIndexes: file_app_proxyman_command_command_proto_depIdxs,
MessageInfos: file_app_proxyman_command_command_proto_msgTypes,
}.Build()
File_app_proxyman_command_command_proto = out.File
file_app_proxyman_command_command_proto_rawDesc = nil
file_app_proxyman_command_command_proto_goTypes = nil
file_app_proxyman_command_command_proto_depIdxs = nil
}
v2ray-core-4.34.0/app/proxyman/command/command.proto 0000664 0000000 0000000 00000003210 13774574720 0022365 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.app.proxyman.command;
option csharp_namespace = "V2Ray.Core.App.Proxyman.Command";
option go_package = "v2ray.com/core/app/proxyman/command";
option java_package = "com.v2ray.core.app.proxyman.command";
option java_multiple_files = true;
import "common/protocol/user.proto";
import "common/serial/typed_message.proto";
import "config.proto";
message AddUserOperation {
v2ray.core.common.protocol.User user = 1;
}
message RemoveUserOperation {
string email = 1;
}
message AddInboundRequest {
core.InboundHandlerConfig inbound = 1;
}
message AddInboundResponse {}
message RemoveInboundRequest {
string tag = 1;
}
message RemoveInboundResponse {}
message AlterInboundRequest {
string tag = 1;
v2ray.core.common.serial.TypedMessage operation = 2;
}
message AlterInboundResponse {}
message AddOutboundRequest {
core.OutboundHandlerConfig outbound = 1;
}
message AddOutboundResponse {}
message RemoveOutboundRequest {
string tag = 1;
}
message RemoveOutboundResponse {}
message AlterOutboundRequest {
string tag = 1;
v2ray.core.common.serial.TypedMessage operation = 2;
}
message AlterOutboundResponse {}
service HandlerService {
rpc AddInbound(AddInboundRequest) returns (AddInboundResponse) {}
rpc RemoveInbound(RemoveInboundRequest) returns (RemoveInboundResponse) {}
rpc AlterInbound(AlterInboundRequest) returns (AlterInboundResponse) {}
rpc AddOutbound(AddOutboundRequest) returns (AddOutboundResponse) {}
rpc RemoveOutbound(RemoveOutboundRequest) returns (RemoveOutboundResponse) {}
rpc AlterOutbound(AlterOutboundRequest) returns (AlterOutboundResponse) {}
}
message Config {}
v2ray-core-4.34.0/app/proxyman/command/command_grpc.pb.go 0000664 0000000 0000000 00000026131 13774574720 0023251 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package command
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion7
// HandlerServiceClient is the client API for HandlerService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type HandlerServiceClient interface {
AddInbound(ctx context.Context, in *AddInboundRequest, opts ...grpc.CallOption) (*AddInboundResponse, error)
RemoveInbound(ctx context.Context, in *RemoveInboundRequest, opts ...grpc.CallOption) (*RemoveInboundResponse, error)
AlterInbound(ctx context.Context, in *AlterInboundRequest, opts ...grpc.CallOption) (*AlterInboundResponse, error)
AddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error)
RemoveOutbound(ctx context.Context, in *RemoveOutboundRequest, opts ...grpc.CallOption) (*RemoveOutboundResponse, error)
AlterOutbound(ctx context.Context, in *AlterOutboundRequest, opts ...grpc.CallOption) (*AlterOutboundResponse, error)
}
type handlerServiceClient struct {
cc grpc.ClientConnInterface
}
func NewHandlerServiceClient(cc grpc.ClientConnInterface) HandlerServiceClient {
return &handlerServiceClient{cc}
}
func (c *handlerServiceClient) AddInbound(ctx context.Context, in *AddInboundRequest, opts ...grpc.CallOption) (*AddInboundResponse, error) {
out := new(AddInboundResponse)
err := c.cc.Invoke(ctx, "/v2ray.core.app.proxyman.command.HandlerService/AddInbound", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *handlerServiceClient) RemoveInbound(ctx context.Context, in *RemoveInboundRequest, opts ...grpc.CallOption) (*RemoveInboundResponse, error) {
out := new(RemoveInboundResponse)
err := c.cc.Invoke(ctx, "/v2ray.core.app.proxyman.command.HandlerService/RemoveInbound", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *handlerServiceClient) AlterInbound(ctx context.Context, in *AlterInboundRequest, opts ...grpc.CallOption) (*AlterInboundResponse, error) {
out := new(AlterInboundResponse)
err := c.cc.Invoke(ctx, "/v2ray.core.app.proxyman.command.HandlerService/AlterInbound", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *handlerServiceClient) AddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error) {
out := new(AddOutboundResponse)
err := c.cc.Invoke(ctx, "/v2ray.core.app.proxyman.command.HandlerService/AddOutbound", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *handlerServiceClient) RemoveOutbound(ctx context.Context, in *RemoveOutboundRequest, opts ...grpc.CallOption) (*RemoveOutboundResponse, error) {
out := new(RemoveOutboundResponse)
err := c.cc.Invoke(ctx, "/v2ray.core.app.proxyman.command.HandlerService/RemoveOutbound", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *handlerServiceClient) AlterOutbound(ctx context.Context, in *AlterOutboundRequest, opts ...grpc.CallOption) (*AlterOutboundResponse, error) {
out := new(AlterOutboundResponse)
err := c.cc.Invoke(ctx, "/v2ray.core.app.proxyman.command.HandlerService/AlterOutbound", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// HandlerServiceServer is the server API for HandlerService service.
// All implementations must embed UnimplementedHandlerServiceServer
// for forward compatibility
type HandlerServiceServer interface {
AddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error)
RemoveInbound(context.Context, *RemoveInboundRequest) (*RemoveInboundResponse, error)
AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error)
AddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error)
RemoveOutbound(context.Context, *RemoveOutboundRequest) (*RemoveOutboundResponse, error)
AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error)
mustEmbedUnimplementedHandlerServiceServer()
}
// UnimplementedHandlerServiceServer must be embedded to have forward compatible implementations.
type UnimplementedHandlerServiceServer struct {
}
func (UnimplementedHandlerServiceServer) AddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddInbound not implemented")
}
func (UnimplementedHandlerServiceServer) RemoveInbound(context.Context, *RemoveInboundRequest) (*RemoveInboundResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method RemoveInbound not implemented")
}
func (UnimplementedHandlerServiceServer) AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AlterInbound not implemented")
}
func (UnimplementedHandlerServiceServer) AddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddOutbound not implemented")
}
func (UnimplementedHandlerServiceServer) RemoveOutbound(context.Context, *RemoveOutboundRequest) (*RemoveOutboundResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method RemoveOutbound not implemented")
}
func (UnimplementedHandlerServiceServer) AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AlterOutbound not implemented")
}
func (UnimplementedHandlerServiceServer) mustEmbedUnimplementedHandlerServiceServer() {}
// UnsafeHandlerServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to HandlerServiceServer will
// result in compilation errors.
type UnsafeHandlerServiceServer interface {
mustEmbedUnimplementedHandlerServiceServer()
}
func RegisterHandlerServiceServer(s grpc.ServiceRegistrar, srv HandlerServiceServer) {
s.RegisterService(&_HandlerService_serviceDesc, srv)
}
func _HandlerService_AddInbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddInboundRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HandlerServiceServer).AddInbound(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.proxyman.command.HandlerService/AddInbound",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).AddInbound(ctx, req.(*AddInboundRequest))
}
return interceptor(ctx, in, info, handler)
}
func _HandlerService_RemoveInbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RemoveInboundRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HandlerServiceServer).RemoveInbound(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.proxyman.command.HandlerService/RemoveInbound",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).RemoveInbound(ctx, req.(*RemoveInboundRequest))
}
return interceptor(ctx, in, info, handler)
}
func _HandlerService_AlterInbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AlterInboundRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HandlerServiceServer).AlterInbound(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.proxyman.command.HandlerService/AlterInbound",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).AlterInbound(ctx, req.(*AlterInboundRequest))
}
return interceptor(ctx, in, info, handler)
}
func _HandlerService_AddOutbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddOutboundRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HandlerServiceServer).AddOutbound(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.proxyman.command.HandlerService/AddOutbound",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).AddOutbound(ctx, req.(*AddOutboundRequest))
}
return interceptor(ctx, in, info, handler)
}
func _HandlerService_RemoveOutbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RemoveOutboundRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HandlerServiceServer).RemoveOutbound(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.proxyman.command.HandlerService/RemoveOutbound",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).RemoveOutbound(ctx, req.(*RemoveOutboundRequest))
}
return interceptor(ctx, in, info, handler)
}
func _HandlerService_AlterOutbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AlterOutboundRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HandlerServiceServer).AlterOutbound(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.proxyman.command.HandlerService/AlterOutbound",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).AlterOutbound(ctx, req.(*AlterOutboundRequest))
}
return interceptor(ctx, in, info, handler)
}
var _HandlerService_serviceDesc = grpc.ServiceDesc{
ServiceName: "v2ray.core.app.proxyman.command.HandlerService",
HandlerType: (*HandlerServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "AddInbound",
Handler: _HandlerService_AddInbound_Handler,
},
{
MethodName: "RemoveInbound",
Handler: _HandlerService_RemoveInbound_Handler,
},
{
MethodName: "AlterInbound",
Handler: _HandlerService_AlterInbound_Handler,
},
{
MethodName: "AddOutbound",
Handler: _HandlerService_AddOutbound_Handler,
},
{
MethodName: "RemoveOutbound",
Handler: _HandlerService_RemoveOutbound_Handler,
},
{
MethodName: "AlterOutbound",
Handler: _HandlerService_AlterOutbound_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "app/proxyman/command/command.proto",
}
v2ray-core-4.34.0/app/proxyman/command/doc.go 0000664 0000000 0000000 00000000114 13774574720 0020756 0 ustar 00root root 0000000 0000000 package command
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/app/proxyman/command/errors.generated.go 0000664 0000000 0000000 00000000315 13774574720 0023465 0 ustar 00root root 0000000 0000000 package command
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/app/proxyman/config.go 0000664 0000000 0000000 00000001366 13774574720 0020052 0 ustar 00root root 0000000 0000000 package proxyman
func (s *AllocationStrategy) GetConcurrencyValue() uint32 {
if s == nil || s.Concurrency == nil {
return 3
}
return s.Concurrency.Value
}
func (s *AllocationStrategy) GetRefreshValue() uint32 {
if s == nil || s.Refresh == nil {
return 5
}
return s.Refresh.Value
}
func (c *ReceiverConfig) GetEffectiveSniffingSettings() *SniffingConfig {
if c.SniffingSettings != nil {
return c.SniffingSettings
}
if len(c.DomainOverride) > 0 {
var p []string
for _, kd := range c.DomainOverride {
switch kd {
case KnownProtocols_HTTP:
p = append(p, "http")
case KnownProtocols_TLS:
p = append(p, "tls")
}
}
return &SniffingConfig{
Enabled: true,
DestinationOverride: p,
}
}
return nil
}
v2ray-core-4.34.0/app/proxyman/config.pb.go 0000664 0000000 0000000 00000121557 13774574720 0020457 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: app/proxyman/config.proto
package proxyman
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
net "v2ray.com/core/common/net"
serial "v2ray.com/core/common/serial"
internet "v2ray.com/core/transport/internet"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type KnownProtocols int32
const (
KnownProtocols_HTTP KnownProtocols = 0
KnownProtocols_TLS KnownProtocols = 1
)
// Enum value maps for KnownProtocols.
var (
KnownProtocols_name = map[int32]string{
0: "HTTP",
1: "TLS",
}
KnownProtocols_value = map[string]int32{
"HTTP": 0,
"TLS": 1,
}
)
func (x KnownProtocols) Enum() *KnownProtocols {
p := new(KnownProtocols)
*p = x
return p
}
func (x KnownProtocols) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (KnownProtocols) Descriptor() protoreflect.EnumDescriptor {
return file_app_proxyman_config_proto_enumTypes[0].Descriptor()
}
func (KnownProtocols) Type() protoreflect.EnumType {
return &file_app_proxyman_config_proto_enumTypes[0]
}
func (x KnownProtocols) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use KnownProtocols.Descriptor instead.
func (KnownProtocols) EnumDescriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{0}
}
type AllocationStrategy_Type int32
const (
// Always allocate all connection handlers.
AllocationStrategy_Always AllocationStrategy_Type = 0
// Randomly allocate specific range of handlers.
AllocationStrategy_Random AllocationStrategy_Type = 1
// External. Not supported yet.
AllocationStrategy_External AllocationStrategy_Type = 2
)
// Enum value maps for AllocationStrategy_Type.
var (
AllocationStrategy_Type_name = map[int32]string{
0: "Always",
1: "Random",
2: "External",
}
AllocationStrategy_Type_value = map[string]int32{
"Always": 0,
"Random": 1,
"External": 2,
}
)
func (x AllocationStrategy_Type) Enum() *AllocationStrategy_Type {
p := new(AllocationStrategy_Type)
*p = x
return p
}
func (x AllocationStrategy_Type) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (AllocationStrategy_Type) Descriptor() protoreflect.EnumDescriptor {
return file_app_proxyman_config_proto_enumTypes[1].Descriptor()
}
func (AllocationStrategy_Type) Type() protoreflect.EnumType {
return &file_app_proxyman_config_proto_enumTypes[1]
}
func (x AllocationStrategy_Type) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use AllocationStrategy_Type.Descriptor instead.
func (AllocationStrategy_Type) EnumDescriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 0}
}
type InboundConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *InboundConfig) Reset() {
*x = InboundConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *InboundConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*InboundConfig) ProtoMessage() {}
func (x *InboundConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use InboundConfig.ProtoReflect.Descriptor instead.
func (*InboundConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{0}
}
type AllocationStrategy struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type AllocationStrategy_Type `protobuf:"varint,1,opt,name=type,proto3,enum=v2ray.core.app.proxyman.AllocationStrategy_Type" json:"type,omitempty"`
// Number of handlers (ports) running in parallel.
// Default value is 3 if unset.
Concurrency *AllocationStrategy_AllocationStrategyConcurrency `protobuf:"bytes,2,opt,name=concurrency,proto3" json:"concurrency,omitempty"`
// Number of minutes before a handler is regenerated.
// Default value is 5 if unset.
Refresh *AllocationStrategy_AllocationStrategyRefresh `protobuf:"bytes,3,opt,name=refresh,proto3" json:"refresh,omitempty"`
}
func (x *AllocationStrategy) Reset() {
*x = AllocationStrategy{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AllocationStrategy) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AllocationStrategy) ProtoMessage() {}
func (x *AllocationStrategy) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AllocationStrategy.ProtoReflect.Descriptor instead.
func (*AllocationStrategy) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1}
}
func (x *AllocationStrategy) GetType() AllocationStrategy_Type {
if x != nil {
return x.Type
}
return AllocationStrategy_Always
}
func (x *AllocationStrategy) GetConcurrency() *AllocationStrategy_AllocationStrategyConcurrency {
if x != nil {
return x.Concurrency
}
return nil
}
func (x *AllocationStrategy) GetRefresh() *AllocationStrategy_AllocationStrategyRefresh {
if x != nil {
return x.Refresh
}
return nil
}
type SniffingConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Whether or not to enable content sniffing on an inbound connection.
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
// Override target destination if sniff'ed protocol is in the given list.
// Supported values are "http", "tls".
DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
}
func (x *SniffingConfig) Reset() {
*x = SniffingConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SniffingConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SniffingConfig) ProtoMessage() {}
func (x *SniffingConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SniffingConfig.ProtoReflect.Descriptor instead.
func (*SniffingConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{2}
}
func (x *SniffingConfig) GetEnabled() bool {
if x != nil {
return x.Enabled
}
return false
}
func (x *SniffingConfig) GetDestinationOverride() []string {
if x != nil {
return x.DestinationOverride
}
return nil
}
type ReceiverConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// PortRange specifies the ports which the Receiver should listen on.
PortRange *net.PortRange `protobuf:"bytes,1,opt,name=port_range,json=portRange,proto3" json:"port_range,omitempty"`
// Listen specifies the IP address that the Receiver should listen on.
Listen *net.IPOrDomain `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"`
AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy,proto3" json:"allocation_strategy,omitempty"`
StreamSettings *internet.StreamConfig `protobuf:"bytes,4,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
ReceiveOriginalDestination bool `protobuf:"varint,5,opt,name=receive_original_destination,json=receiveOriginalDestination,proto3" json:"receive_original_destination,omitempty"`
// Override domains for the given protocol.
// Deprecated. Use sniffing_settings.
//
// Deprecated: Do not use.
DomainOverride []KnownProtocols `protobuf:"varint,7,rep,packed,name=domain_override,json=domainOverride,proto3,enum=v2ray.core.app.proxyman.KnownProtocols" json:"domain_override,omitempty"`
SniffingSettings *SniffingConfig `protobuf:"bytes,8,opt,name=sniffing_settings,json=sniffingSettings,proto3" json:"sniffing_settings,omitempty"`
}
func (x *ReceiverConfig) Reset() {
*x = ReceiverConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReceiverConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReceiverConfig) ProtoMessage() {}
func (x *ReceiverConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReceiverConfig.ProtoReflect.Descriptor instead.
func (*ReceiverConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{3}
}
func (x *ReceiverConfig) GetPortRange() *net.PortRange {
if x != nil {
return x.PortRange
}
return nil
}
func (x *ReceiverConfig) GetListen() *net.IPOrDomain {
if x != nil {
return x.Listen
}
return nil
}
func (x *ReceiverConfig) GetAllocationStrategy() *AllocationStrategy {
if x != nil {
return x.AllocationStrategy
}
return nil
}
func (x *ReceiverConfig) GetStreamSettings() *internet.StreamConfig {
if x != nil {
return x.StreamSettings
}
return nil
}
func (x *ReceiverConfig) GetReceiveOriginalDestination() bool {
if x != nil {
return x.ReceiveOriginalDestination
}
return false
}
// Deprecated: Do not use.
func (x *ReceiverConfig) GetDomainOverride() []KnownProtocols {
if x != nil {
return x.DomainOverride
}
return nil
}
func (x *ReceiverConfig) GetSniffingSettings() *SniffingConfig {
if x != nil {
return x.SniffingSettings
}
return nil
}
type InboundHandlerConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
ReceiverSettings *serial.TypedMessage `protobuf:"bytes,2,opt,name=receiver_settings,json=receiverSettings,proto3" json:"receiver_settings,omitempty"`
ProxySettings *serial.TypedMessage `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"`
}
func (x *InboundHandlerConfig) Reset() {
*x = InboundHandlerConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_config_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *InboundHandlerConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*InboundHandlerConfig) ProtoMessage() {}
func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use InboundHandlerConfig.ProtoReflect.Descriptor instead.
func (*InboundHandlerConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{4}
}
func (x *InboundHandlerConfig) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
func (x *InboundHandlerConfig) GetReceiverSettings() *serial.TypedMessage {
if x != nil {
return x.ReceiverSettings
}
return nil
}
func (x *InboundHandlerConfig) GetProxySettings() *serial.TypedMessage {
if x != nil {
return x.ProxySettings
}
return nil
}
type OutboundConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *OutboundConfig) Reset() {
*x = OutboundConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_config_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *OutboundConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OutboundConfig) ProtoMessage() {}
func (x *OutboundConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OutboundConfig.ProtoReflect.Descriptor instead.
func (*OutboundConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{5}
}
type SenderConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Send traffic through the given IP. Only IP is allowed.
Via *net.IPOrDomain `protobuf:"bytes,1,opt,name=via,proto3" json:"via,omitempty"`
StreamSettings *internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
ProxySettings *internet.ProxyConfig `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"`
MultiplexSettings *MultiplexingConfig `protobuf:"bytes,4,opt,name=multiplex_settings,json=multiplexSettings,proto3" json:"multiplex_settings,omitempty"`
}
func (x *SenderConfig) Reset() {
*x = SenderConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_config_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SenderConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SenderConfig) ProtoMessage() {}
func (x *SenderConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SenderConfig.ProtoReflect.Descriptor instead.
func (*SenderConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{6}
}
func (x *SenderConfig) GetVia() *net.IPOrDomain {
if x != nil {
return x.Via
}
return nil
}
func (x *SenderConfig) GetStreamSettings() *internet.StreamConfig {
if x != nil {
return x.StreamSettings
}
return nil
}
func (x *SenderConfig) GetProxySettings() *internet.ProxyConfig {
if x != nil {
return x.ProxySettings
}
return nil
}
func (x *SenderConfig) GetMultiplexSettings() *MultiplexingConfig {
if x != nil {
return x.MultiplexSettings
}
return nil
}
type MultiplexingConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Whether or not Mux is enabled.
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
// Max number of concurrent connections that one Mux connection can handle.
Concurrency uint32 `protobuf:"varint,2,opt,name=concurrency,proto3" json:"concurrency,omitempty"`
}
func (x *MultiplexingConfig) Reset() {
*x = MultiplexingConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_config_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiplexingConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiplexingConfig) ProtoMessage() {}
func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiplexingConfig.ProtoReflect.Descriptor instead.
func (*MultiplexingConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{7}
}
func (x *MultiplexingConfig) GetEnabled() bool {
if x != nil {
return x.Enabled
}
return false
}
func (x *MultiplexingConfig) GetConcurrency() uint32 {
if x != nil {
return x.Concurrency
}
return 0
}
type AllocationStrategy_AllocationStrategyConcurrency struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *AllocationStrategy_AllocationStrategyConcurrency) Reset() {
*x = AllocationStrategy_AllocationStrategyConcurrency{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_config_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AllocationStrategy_AllocationStrategyConcurrency) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AllocationStrategy_AllocationStrategyConcurrency) ProtoMessage() {}
func (x *AllocationStrategy_AllocationStrategyConcurrency) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AllocationStrategy_AllocationStrategyConcurrency.ProtoReflect.Descriptor instead.
func (*AllocationStrategy_AllocationStrategyConcurrency) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 0}
}
func (x *AllocationStrategy_AllocationStrategyConcurrency) GetValue() uint32 {
if x != nil {
return x.Value
}
return 0
}
type AllocationStrategy_AllocationStrategyRefresh struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *AllocationStrategy_AllocationStrategyRefresh) Reset() {
*x = AllocationStrategy_AllocationStrategyRefresh{}
if protoimpl.UnsafeEnabled {
mi := &file_app_proxyman_config_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AllocationStrategy_AllocationStrategyRefresh) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AllocationStrategy_AllocationStrategyRefresh) ProtoMessage() {}
func (x *AllocationStrategy_AllocationStrategyRefresh) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AllocationStrategy_AllocationStrategyRefresh.ProtoReflect.Descriptor instead.
func (*AllocationStrategy_AllocationStrategyRefresh) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 1}
}
func (x *AllocationStrategy_AllocationStrategyRefresh) GetValue() uint32 {
if x != nil {
return x.Value
}
return 0
}
var File_app_proxyman_config_proto protoreflect.FileDescriptor
var file_app_proxyman_config_proto_rawDesc = []byte{
0x0a, 0x19, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,
0x79, 0x6d, 0x61, 0x6e, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74,
0x2f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73,
0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x0f, 0x0a, 0x0d, 0x49, 0x6e, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xc0, 0x03, 0x0a, 0x12, 0x41,
0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
0x79, 0x12, 0x44, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x30, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x54, 0x79, 0x70,
0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x6b, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75,
0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x49, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63,
0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72,
0x65, 0x6e, 0x63, 0x79, 0x12, 0x5f, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e,
0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
0x67, 0x79, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72,
0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x07, 0x72, 0x65,
0x66, 0x72, 0x65, 0x73, 0x68, 0x1a, 0x35, 0x0a, 0x1d, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63, 0x75,
0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x31, 0x0a, 0x19,
0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
0x67, 0x79, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,
0x2c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79,
0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12,
0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0x5d, 0x0a,
0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73,
0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x22, 0xb4, 0x04, 0x0a,
0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x3f, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74,
0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65,
0x12, 0x39, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d,
0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x5c, 0x0a, 0x13, 0x61,
0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d,
0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72,
0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x54, 0x0a, 0x0f, 0x73, 0x74, 0x72,
0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,
0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69,
0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72,
0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x12, 0x54, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72,
0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,
0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,
0x6f, 0x6c, 0x73, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f,
0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66,
0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x27, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e, 0x69,
0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e, 0x69,
0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04, 0x08,
0x06, 0x10, 0x07, 0x22, 0xcc, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48,
0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03,
0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x53,
0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65,
0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x52, 0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69,
0x6e, 0x67, 0x73, 0x12, 0x4d, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74,
0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x22, 0xc8, 0x02, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x33, 0x0a, 0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x54, 0x0a, 0x0f, 0x73, 0x74,
0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x12, 0x51, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69,
0x6e, 0x67, 0x73, 0x12, 0x5a, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78,
0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70,
0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75,
0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22,
0x50, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12,
0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63,
0x79, 0x2a, 0x23, 0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,
0x6f, 0x6c, 0x73, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a,
0x03, 0x54, 0x4c, 0x53, 0x10, 0x01, 0x42, 0x56, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x1b, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78,
0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x17, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72,
0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_proxyman_config_proto_rawDescOnce sync.Once
file_app_proxyman_config_proto_rawDescData = file_app_proxyman_config_proto_rawDesc
)
func file_app_proxyman_config_proto_rawDescGZIP() []byte {
file_app_proxyman_config_proto_rawDescOnce.Do(func() {
file_app_proxyman_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_proxyman_config_proto_rawDescData)
})
return file_app_proxyman_config_proto_rawDescData
}
var file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_app_proxyman_config_proto_goTypes = []interface{}{
(KnownProtocols)(0), // 0: v2ray.core.app.proxyman.KnownProtocols
(AllocationStrategy_Type)(0), // 1: v2ray.core.app.proxyman.AllocationStrategy.Type
(*InboundConfig)(nil), // 2: v2ray.core.app.proxyman.InboundConfig
(*AllocationStrategy)(nil), // 3: v2ray.core.app.proxyman.AllocationStrategy
(*SniffingConfig)(nil), // 4: v2ray.core.app.proxyman.SniffingConfig
(*ReceiverConfig)(nil), // 5: v2ray.core.app.proxyman.ReceiverConfig
(*InboundHandlerConfig)(nil), // 6: v2ray.core.app.proxyman.InboundHandlerConfig
(*OutboundConfig)(nil), // 7: v2ray.core.app.proxyman.OutboundConfig
(*SenderConfig)(nil), // 8: v2ray.core.app.proxyman.SenderConfig
(*MultiplexingConfig)(nil), // 9: v2ray.core.app.proxyman.MultiplexingConfig
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 10: v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 11: v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
(*net.PortRange)(nil), // 12: v2ray.core.common.net.PortRange
(*net.IPOrDomain)(nil), // 13: v2ray.core.common.net.IPOrDomain
(*internet.StreamConfig)(nil), // 14: v2ray.core.transport.internet.StreamConfig
(*serial.TypedMessage)(nil), // 15: v2ray.core.common.serial.TypedMessage
(*internet.ProxyConfig)(nil), // 16: v2ray.core.transport.internet.ProxyConfig
}
var file_app_proxyman_config_proto_depIdxs = []int32{
1, // 0: v2ray.core.app.proxyman.AllocationStrategy.type:type_name -> v2ray.core.app.proxyman.AllocationStrategy.Type
10, // 1: v2ray.core.app.proxyman.AllocationStrategy.concurrency:type_name -> v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
11, // 2: v2ray.core.app.proxyman.AllocationStrategy.refresh:type_name -> v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
12, // 3: v2ray.core.app.proxyman.ReceiverConfig.port_range:type_name -> v2ray.core.common.net.PortRange
13, // 4: v2ray.core.app.proxyman.ReceiverConfig.listen:type_name -> v2ray.core.common.net.IPOrDomain
3, // 5: v2ray.core.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> v2ray.core.app.proxyman.AllocationStrategy
14, // 6: v2ray.core.app.proxyman.ReceiverConfig.stream_settings:type_name -> v2ray.core.transport.internet.StreamConfig
0, // 7: v2ray.core.app.proxyman.ReceiverConfig.domain_override:type_name -> v2ray.core.app.proxyman.KnownProtocols
4, // 8: v2ray.core.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> v2ray.core.app.proxyman.SniffingConfig
15, // 9: v2ray.core.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> v2ray.core.common.serial.TypedMessage
15, // 10: v2ray.core.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> v2ray.core.common.serial.TypedMessage
13, // 11: v2ray.core.app.proxyman.SenderConfig.via:type_name -> v2ray.core.common.net.IPOrDomain
14, // 12: v2ray.core.app.proxyman.SenderConfig.stream_settings:type_name -> v2ray.core.transport.internet.StreamConfig
16, // 13: v2ray.core.app.proxyman.SenderConfig.proxy_settings:type_name -> v2ray.core.transport.internet.ProxyConfig
9, // 14: v2ray.core.app.proxyman.SenderConfig.multiplex_settings:type_name -> v2ray.core.app.proxyman.MultiplexingConfig
15, // [15:15] is the sub-list for method output_type
15, // [15:15] is the sub-list for method input_type
15, // [15:15] is the sub-list for extension type_name
15, // [15:15] is the sub-list for extension extendee
0, // [0:15] is the sub-list for field type_name
}
func init() { file_app_proxyman_config_proto_init() }
func file_app_proxyman_config_proto_init() {
if File_app_proxyman_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_proxyman_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*InboundConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AllocationStrategy); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SniffingConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReceiverConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*InboundHandlerConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*OutboundConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_config_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SenderConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_config_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*MultiplexingConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_config_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AllocationStrategy_AllocationStrategyConcurrency); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_proxyman_config_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AllocationStrategy_AllocationStrategyRefresh); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_proxyman_config_proto_rawDesc,
NumEnums: 2,
NumMessages: 10,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_app_proxyman_config_proto_goTypes,
DependencyIndexes: file_app_proxyman_config_proto_depIdxs,
EnumInfos: file_app_proxyman_config_proto_enumTypes,
MessageInfos: file_app_proxyman_config_proto_msgTypes,
}.Build()
File_app_proxyman_config_proto = out.File
file_app_proxyman_config_proto_rawDesc = nil
file_app_proxyman_config_proto_goTypes = nil
file_app_proxyman_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/app/proxyman/config.proto 0000664 0000000 0000000 00000005271 13774574720 0020607 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.app.proxyman;
option csharp_namespace = "V2Ray.Core.App.Proxyman";
option go_package = "v2ray.com/core/app/proxyman";
option java_package = "com.v2ray.core.app.proxyman";
option java_multiple_files = true;
import "common/net/address.proto";
import "common/net/port.proto";
import "transport/internet/config.proto";
import "common/serial/typed_message.proto";
message InboundConfig {}
message AllocationStrategy {
enum Type {
// Always allocate all connection handlers.
Always = 0;
// Randomly allocate specific range of handlers.
Random = 1;
// External. Not supported yet.
External = 2;
}
Type type = 1;
message AllocationStrategyConcurrency {
uint32 value = 1;
}
// Number of handlers (ports) running in parallel.
// Default value is 3 if unset.
AllocationStrategyConcurrency concurrency = 2;
message AllocationStrategyRefresh {
uint32 value = 1;
}
// Number of minutes before a handler is regenerated.
// Default value is 5 if unset.
AllocationStrategyRefresh refresh = 3;
}
enum KnownProtocols {
HTTP = 0;
TLS = 1;
}
message SniffingConfig {
// Whether or not to enable content sniffing on an inbound connection.
bool enabled = 1;
// Override target destination if sniff'ed protocol is in the given list.
// Supported values are "http", "tls".
repeated string destination_override = 2;
}
message ReceiverConfig {
// PortRange specifies the ports which the Receiver should listen on.
v2ray.core.common.net.PortRange port_range = 1;
// Listen specifies the IP address that the Receiver should listen on.
v2ray.core.common.net.IPOrDomain listen = 2;
AllocationStrategy allocation_strategy = 3;
v2ray.core.transport.internet.StreamConfig stream_settings = 4;
bool receive_original_destination = 5;
reserved 6;
// Override domains for the given protocol.
// Deprecated. Use sniffing_settings.
repeated KnownProtocols domain_override = 7 [deprecated = true];
SniffingConfig sniffing_settings = 8;
}
message InboundHandlerConfig {
string tag = 1;
v2ray.core.common.serial.TypedMessage receiver_settings = 2;
v2ray.core.common.serial.TypedMessage proxy_settings = 3;
}
message OutboundConfig {}
message SenderConfig {
// Send traffic through the given IP. Only IP is allowed.
v2ray.core.common.net.IPOrDomain via = 1;
v2ray.core.transport.internet.StreamConfig stream_settings = 2;
v2ray.core.transport.internet.ProxyConfig proxy_settings = 3;
MultiplexingConfig multiplex_settings = 4;
}
message MultiplexingConfig {
// Whether or not Mux is enabled.
bool enabled = 1;
// Max number of concurrent connections that one Mux connection can handle.
uint32 concurrency = 2;
}
v2ray-core-4.34.0/app/proxyman/inbound/ 0000775 0000000 0000000 00000000000 13774574720 0017706 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/proxyman/inbound/always.go 0000664 0000000 0000000 00000011606 13774574720 0021541 0 ustar 00root root 0000000 0000000 package inbound
import (
"context"
"v2ray.com/core"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common"
"v2ray.com/core/common/dice"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/mux"
"v2ray.com/core/common/net"
"v2ray.com/core/features/policy"
"v2ray.com/core/features/stats"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/internet"
)
func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {
var uplinkCounter stats.Counter
var downlinkCounter stats.Counter
policy := v.GetFeature(policy.ManagerType()).(policy.Manager)
if len(tag) > 0 && policy.ForSystem().Stats.InboundUplink {
statsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)
name := "inbound>>>" + tag + ">>>traffic>>>uplink"
c, _ := stats.GetOrRegisterCounter(statsManager, name)
if c != nil {
uplinkCounter = c
}
}
if len(tag) > 0 && policy.ForSystem().Stats.InboundDownlink {
statsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)
name := "inbound>>>" + tag + ">>>traffic>>>downlink"
c, _ := stats.GetOrRegisterCounter(statsManager, name)
if c != nil {
downlinkCounter = c
}
}
return uplinkCounter, downlinkCounter
}
type AlwaysOnInboundHandler struct {
proxy proxy.Inbound
workers []worker
mux *mux.Server
tag string
}
func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*AlwaysOnInboundHandler, error) {
rawProxy, err := common.CreateObject(ctx, proxyConfig)
if err != nil {
return nil, err
}
p, ok := rawProxy.(proxy.Inbound)
if !ok {
return nil, newError("not an inbound proxy.")
}
h := &AlwaysOnInboundHandler{
proxy: p,
mux: mux.NewServer(ctx),
tag: tag,
}
uplinkCounter, downlinkCounter := getStatCounter(core.MustFromContext(ctx), tag)
nl := p.Network()
pr := receiverConfig.PortRange
address := receiverConfig.Listen.AsAddress()
if address == nil {
address = net.AnyIP
}
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
if err != nil {
return nil, newError("failed to parse stream config").Base(err).AtWarning()
}
if receiverConfig.ReceiveOriginalDestination {
if mss.SocketSettings == nil {
mss.SocketSettings = &internet.SocketConfig{}
}
if mss.SocketSettings.Tproxy == internet.SocketConfig_Off {
mss.SocketSettings.Tproxy = internet.SocketConfig_Redirect
}
mss.SocketSettings.ReceiveOriginalDestAddress = true
}
if pr == nil {
if net.HasNetwork(nl, net.Network_UNIX) {
newError("creating unix domain socket worker on ", address).AtDebug().WriteToLog()
worker := &dsWorker{
address: address,
proxy: p,
stream: mss,
tag: tag,
dispatcher: h.mux,
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter,
ctx: ctx,
}
h.workers = append(h.workers, worker)
}
}
if pr != nil {
for port := pr.From; port <= pr.To; port++ {
if net.HasNetwork(nl, net.Network_TCP) {
newError("creating stream worker on ", address, ":", port).AtDebug().WriteToLog()
worker := &tcpWorker{
address: address,
port: net.Port(port),
proxy: p,
stream: mss,
recvOrigDest: receiverConfig.ReceiveOriginalDestination,
tag: tag,
dispatcher: h.mux,
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter,
ctx: ctx,
}
h.workers = append(h.workers, worker)
}
if net.HasNetwork(nl, net.Network_UDP) {
worker := &udpWorker{
tag: tag,
proxy: p,
address: address,
port: net.Port(port),
dispatcher: h.mux,
uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter,
stream: mss,
}
h.workers = append(h.workers, worker)
}
}
}
return h, nil
}
// Start implements common.Runnable.
func (h *AlwaysOnInboundHandler) Start() error {
for _, worker := range h.workers {
if err := worker.Start(); err != nil {
return err
}
}
return nil
}
// Close implements common.Closable.
func (h *AlwaysOnInboundHandler) Close() error {
var errs []error
for _, worker := range h.workers {
errs = append(errs, worker.Close())
}
errs = append(errs, h.mux.Close())
if err := errors.Combine(errs...); err != nil {
return newError("failed to close all resources").Base(err)
}
return nil
}
func (h *AlwaysOnInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {
if len(h.workers) == 0 {
return nil, 0, 0
}
w := h.workers[dice.Roll(len(h.workers))]
return w.Proxy(), w.Port(), 9999
}
func (h *AlwaysOnInboundHandler) Tag() string {
return h.tag
}
func (h *AlwaysOnInboundHandler) GetInbound() proxy.Inbound {
return h.proxy
}
v2ray-core-4.34.0/app/proxyman/inbound/dynamic.go 0000664 0000000 0000000 00000012242 13774574720 0021662 0 ustar 00root root 0000000 0000000 package inbound
import (
"context"
"sync"
"time"
"v2ray.com/core"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common/dice"
"v2ray.com/core/common/mux"
"v2ray.com/core/common/net"
"v2ray.com/core/common/task"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/internet"
)
type DynamicInboundHandler struct {
tag string
v *core.Instance
proxyConfig interface{}
receiverConfig *proxyman.ReceiverConfig
streamSettings *internet.MemoryStreamConfig
portMutex sync.Mutex
portsInUse map[net.Port]bool
workerMutex sync.RWMutex
worker []worker
lastRefresh time.Time
mux *mux.Server
task *task.Periodic
ctx context.Context
}
func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*DynamicInboundHandler, error) {
v := core.MustFromContext(ctx)
h := &DynamicInboundHandler{
tag: tag,
proxyConfig: proxyConfig,
receiverConfig: receiverConfig,
portsInUse: make(map[net.Port]bool),
mux: mux.NewServer(ctx),
v: v,
ctx: ctx,
}
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
if err != nil {
return nil, newError("failed to parse stream settings").Base(err).AtWarning()
}
if receiverConfig.ReceiveOriginalDestination {
if mss.SocketSettings == nil {
mss.SocketSettings = &internet.SocketConfig{}
}
if mss.SocketSettings.Tproxy == internet.SocketConfig_Off {
mss.SocketSettings.Tproxy = internet.SocketConfig_Redirect
}
mss.SocketSettings.ReceiveOriginalDestAddress = true
}
h.streamSettings = mss
h.task = &task.Periodic{
Interval: time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()),
Execute: h.refresh,
}
return h, nil
}
func (h *DynamicInboundHandler) allocatePort() net.Port {
from := int(h.receiverConfig.PortRange.From)
delta := int(h.receiverConfig.PortRange.To) - from + 1
h.portMutex.Lock()
defer h.portMutex.Unlock()
for {
r := dice.Roll(delta)
port := net.Port(from + r)
_, used := h.portsInUse[port]
if !used {
h.portsInUse[port] = true
return port
}
}
}
func (h *DynamicInboundHandler) closeWorkers(workers []worker) {
ports2Del := make([]net.Port, len(workers))
for idx, worker := range workers {
ports2Del[idx] = worker.Port()
if err := worker.Close(); err != nil {
newError("failed to close worker").Base(err).WriteToLog()
}
}
h.portMutex.Lock()
for _, port := range ports2Del {
delete(h.portsInUse, port)
}
h.portMutex.Unlock()
}
func (h *DynamicInboundHandler) refresh() error {
h.lastRefresh = time.Now()
timeout := time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()) * 2
concurrency := h.receiverConfig.AllocationStrategy.GetConcurrencyValue()
workers := make([]worker, 0, concurrency)
address := h.receiverConfig.Listen.AsAddress()
if address == nil {
address = net.AnyIP
}
uplinkCounter, downlinkCounter := getStatCounter(h.v, h.tag)
for i := uint32(0); i < concurrency; i++ {
port := h.allocatePort()
rawProxy, err := core.CreateObject(h.v, h.proxyConfig)
if err != nil {
newError("failed to create proxy instance").Base(err).AtWarning().WriteToLog()
continue
}
p := rawProxy.(proxy.Inbound)
nl := p.Network()
if net.HasNetwork(nl, net.Network_TCP) {
worker := &tcpWorker{
tag: h.tag,
address: address,
port: port,
proxy: p,
stream: h.streamSettings,
recvOrigDest: h.receiverConfig.ReceiveOriginalDestination,
dispatcher: h.mux,
sniffingConfig: h.receiverConfig.GetEffectiveSniffingSettings(),
uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter,
ctx: h.ctx,
}
if err := worker.Start(); err != nil {
newError("failed to create TCP worker").Base(err).AtWarning().WriteToLog()
continue
}
workers = append(workers, worker)
}
if net.HasNetwork(nl, net.Network_UDP) {
worker := &udpWorker{
tag: h.tag,
proxy: p,
address: address,
port: port,
dispatcher: h.mux,
uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter,
stream: h.streamSettings,
}
if err := worker.Start(); err != nil {
newError("failed to create UDP worker").Base(err).AtWarning().WriteToLog()
continue
}
workers = append(workers, worker)
}
}
h.workerMutex.Lock()
h.worker = workers
h.workerMutex.Unlock()
time.AfterFunc(timeout, func() {
h.closeWorkers(workers)
})
return nil
}
func (h *DynamicInboundHandler) Start() error {
return h.task.Start()
}
func (h *DynamicInboundHandler) Close() error {
return h.task.Close()
}
func (h *DynamicInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {
h.workerMutex.RLock()
defer h.workerMutex.RUnlock()
if len(h.worker) == 0 {
return nil, 0, 0
}
w := h.worker[dice.Roll(len(h.worker))]
expire := h.receiverConfig.AllocationStrategy.GetRefreshValue() - uint32(time.Since(h.lastRefresh)/time.Minute)
return w.Proxy(), w.Port(), int(expire)
}
func (h *DynamicInboundHandler) Tag() string {
return h.tag
}
v2ray-core-4.34.0/app/proxyman/inbound/errors.generated.go 0000664 0000000 0000000 00000000315 13774574720 0023505 0 ustar 00root root 0000000 0000000 package inbound
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/app/proxyman/inbound/inbound.go 0000664 0000000 0000000 00000010705 13774574720 0021676 0 ustar 00root root 0000000 0000000 package inbound
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"sync"
"v2ray.com/core"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common"
"v2ray.com/core/common/serial"
"v2ray.com/core/common/session"
"v2ray.com/core/features/inbound"
)
// Manager is to manage all inbound handlers.
type Manager struct {
access sync.RWMutex
untaggedHandler []inbound.Handler
taggedHandlers map[string]inbound.Handler
running bool
}
// New returns a new Manager for inbound handlers.
func New(ctx context.Context, config *proxyman.InboundConfig) (*Manager, error) {
m := &Manager{
taggedHandlers: make(map[string]inbound.Handler),
}
return m, nil
}
// Type implements common.HasType.
func (*Manager) Type() interface{} {
return inbound.ManagerType()
}
// AddHandler implements inbound.Manager.
func (m *Manager) AddHandler(ctx context.Context, handler inbound.Handler) error {
m.access.Lock()
defer m.access.Unlock()
tag := handler.Tag()
if len(tag) > 0 {
m.taggedHandlers[tag] = handler
} else {
m.untaggedHandler = append(m.untaggedHandler, handler)
}
if m.running {
return handler.Start()
}
return nil
}
// GetHandler implements inbound.Manager.
func (m *Manager) GetHandler(ctx context.Context, tag string) (inbound.Handler, error) {
m.access.RLock()
defer m.access.RUnlock()
handler, found := m.taggedHandlers[tag]
if !found {
return nil, newError("handler not found: ", tag)
}
return handler, nil
}
// RemoveHandler implements inbound.Manager.
func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
if tag == "" {
return common.ErrNoClue
}
m.access.Lock()
defer m.access.Unlock()
if handler, found := m.taggedHandlers[tag]; found {
if err := handler.Close(); err != nil {
newError("failed to close handler ", tag).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))
}
delete(m.taggedHandlers, tag)
return nil
}
return common.ErrNoClue
}
// Start implements common.Runnable.
func (m *Manager) Start() error {
m.access.Lock()
defer m.access.Unlock()
m.running = true
for _, handler := range m.taggedHandlers {
if err := handler.Start(); err != nil {
return err
}
}
for _, handler := range m.untaggedHandler {
if err := handler.Start(); err != nil {
return err
}
}
return nil
}
// Close implements common.Closable.
func (m *Manager) Close() error {
m.access.Lock()
defer m.access.Unlock()
m.running = false
var errors []interface{}
for _, handler := range m.taggedHandlers {
if err := handler.Close(); err != nil {
errors = append(errors, err)
}
}
for _, handler := range m.untaggedHandler {
if err := handler.Close(); err != nil {
errors = append(errors, err)
}
}
if len(errors) > 0 {
return newError("failed to close all handlers").Base(newError(serial.Concat(errors...)))
}
return nil
}
// NewHandler creates a new inbound.Handler based on the given config.
func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound.Handler, error) {
rawReceiverSettings, err := config.ReceiverSettings.GetInstance()
if err != nil {
return nil, err
}
proxySettings, err := config.ProxySettings.GetInstance()
if err != nil {
return nil, err
}
tag := config.Tag
receiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig)
if !ok {
return nil, newError("not a ReceiverConfig").AtError()
}
streamSettings := receiverSettings.StreamSettings
if streamSettings != nil && streamSettings.SocketSettings != nil {
ctx = session.ContextWithSockopt(ctx, &session.Sockopt{
Mark: streamSettings.SocketSettings.Mark,
})
}
allocStrategy := receiverSettings.AllocationStrategy
if allocStrategy == nil || allocStrategy.Type == proxyman.AllocationStrategy_Always {
return NewAlwaysOnInboundHandler(ctx, tag, receiverSettings, proxySettings)
}
if allocStrategy.Type == proxyman.AllocationStrategy_Random {
return NewDynamicInboundHandler(ctx, tag, receiverSettings, proxySettings)
}
return nil, newError("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).AtError()
}
func init() {
common.Must(common.RegisterConfig((*proxyman.InboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*proxyman.InboundConfig))
}))
common.Must(common.RegisterConfig((*core.InboundHandlerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewHandler(ctx, config.(*core.InboundHandlerConfig))
}))
}
v2ray-core-4.34.0/app/proxyman/inbound/worker.go 0000664 0000000 0000000 00000026065 13774574720 0021557 0 ustar 00root root 0000000 0000000 package inbound
import (
"context"
"sync"
"sync/atomic"
"time"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/serial"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal/done"
"v2ray.com/core/common/task"
"v2ray.com/core/features/routing"
"v2ray.com/core/features/stats"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/tcp"
"v2ray.com/core/transport/internet/udp"
"v2ray.com/core/transport/pipe"
)
type worker interface {
Start() error
Close() error
Port() net.Port
Proxy() proxy.Inbound
}
type tcpWorker struct {
address net.Address
port net.Port
proxy proxy.Inbound
stream *internet.MemoryStreamConfig
recvOrigDest bool
tag string
dispatcher routing.Dispatcher
sniffingConfig *proxyman.SniffingConfig
uplinkCounter stats.Counter
downlinkCounter stats.Counter
hub internet.Listener
ctx context.Context
}
func getTProxyType(s *internet.MemoryStreamConfig) internet.SocketConfig_TProxyMode {
if s == nil || s.SocketSettings == nil {
return internet.SocketConfig_Off
}
return s.SocketSettings.Tproxy
}
func (w *tcpWorker) callback(conn internet.Connection) {
ctx, cancel := context.WithCancel(w.ctx)
sid := session.NewID()
ctx = session.ContextWithID(ctx, sid)
if w.recvOrigDest {
var dest net.Destination
switch getTProxyType(w.stream) {
case internet.SocketConfig_Redirect:
d, err := tcp.GetOriginalDestination(conn)
if err != nil {
newError("failed to get original destination").Base(err).WriteToLog(session.ExportIDToError(ctx))
} else {
dest = d
}
case internet.SocketConfig_TProxy:
dest = net.DestinationFromAddr(conn.LocalAddr())
}
if dest.IsValid() {
ctx = session.ContextWithOutbound(ctx, &session.Outbound{
Target: dest,
})
}
}
ctx = session.ContextWithInbound(ctx, &session.Inbound{
Source: net.DestinationFromAddr(conn.RemoteAddr()),
Gateway: net.TCPDestination(w.address, w.port),
Tag: w.tag,
})
content := new(session.Content)
if w.sniffingConfig != nil {
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
}
ctx = session.ContextWithContent(ctx, content)
if w.uplinkCounter != nil || w.downlinkCounter != nil {
conn = &internet.StatCouterConnection{
Connection: conn,
ReadCounter: w.uplinkCounter,
WriteCounter: w.downlinkCounter,
}
}
if err := w.proxy.Process(ctx, net.Network_TCP, conn, w.dispatcher); err != nil {
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
cancel()
if err := conn.Close(); err != nil {
newError("failed to close connection").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
}
func (w *tcpWorker) Proxy() proxy.Inbound {
return w.proxy
}
func (w *tcpWorker) Start() error {
ctx := context.Background()
hub, err := internet.ListenTCP(ctx, w.address, w.port, w.stream, func(conn internet.Connection) {
go w.callback(conn)
})
if err != nil {
return newError("failed to listen TCP on ", w.port).AtWarning().Base(err)
}
w.hub = hub
return nil
}
func (w *tcpWorker) Close() error {
var errors []interface{}
if w.hub != nil {
if err := common.Close(w.hub); err != nil {
errors = append(errors, err)
}
if err := common.Close(w.proxy); err != nil {
errors = append(errors, err)
}
}
if len(errors) > 0 {
return newError("failed to close all resources").Base(newError(serial.Concat(errors...)))
}
return nil
}
func (w *tcpWorker) Port() net.Port {
return w.port
}
type udpConn struct {
lastActivityTime int64 // in seconds
reader buf.Reader
writer buf.Writer
output func([]byte) (int, error)
remote net.Addr
local net.Addr
done *done.Instance
uplink stats.Counter
downlink stats.Counter
}
func (c *udpConn) updateActivity() {
atomic.StoreInt64(&c.lastActivityTime, time.Now().Unix())
}
// ReadMultiBuffer implements buf.Reader
func (c *udpConn) ReadMultiBuffer() (buf.MultiBuffer, error) {
mb, err := c.reader.ReadMultiBuffer()
if err != nil {
return nil, err
}
c.updateActivity()
if c.uplink != nil {
c.uplink.Add(int64(mb.Len()))
}
return mb, nil
}
func (c *udpConn) Read(buf []byte) (int, error) {
panic("not implemented")
}
// Write implements io.Writer.
func (c *udpConn) Write(buf []byte) (int, error) {
n, err := c.output(buf)
if c.downlink != nil {
c.downlink.Add(int64(n))
}
if err == nil {
c.updateActivity()
}
return n, err
}
func (c *udpConn) Close() error {
common.Must(c.done.Close())
common.Must(common.Close(c.writer))
return nil
}
func (c *udpConn) RemoteAddr() net.Addr {
return c.remote
}
func (c *udpConn) LocalAddr() net.Addr {
return c.local
}
func (*udpConn) SetDeadline(time.Time) error {
return nil
}
func (*udpConn) SetReadDeadline(time.Time) error {
return nil
}
func (*udpConn) SetWriteDeadline(time.Time) error {
return nil
}
type connID struct {
src net.Destination
dest net.Destination
}
type udpWorker struct {
sync.RWMutex
proxy proxy.Inbound
hub *udp.Hub
address net.Address
port net.Port
tag string
stream *internet.MemoryStreamConfig
dispatcher routing.Dispatcher
uplinkCounter stats.Counter
downlinkCounter stats.Counter
checker *task.Periodic
activeConn map[connID]*udpConn
}
func (w *udpWorker) getConnection(id connID) (*udpConn, bool) {
w.Lock()
defer w.Unlock()
if conn, found := w.activeConn[id]; found && !conn.done.Done() {
return conn, true
}
pReader, pWriter := pipe.New(pipe.DiscardOverflow(), pipe.WithSizeLimit(16*1024))
conn := &udpConn{
reader: pReader,
writer: pWriter,
output: func(b []byte) (int, error) {
return w.hub.WriteTo(b, id.src)
},
remote: &net.UDPAddr{
IP: id.src.Address.IP(),
Port: int(id.src.Port),
},
local: &net.UDPAddr{
IP: w.address.IP(),
Port: int(w.port),
},
done: done.New(),
uplink: w.uplinkCounter,
downlink: w.downlinkCounter,
}
w.activeConn[id] = conn
conn.updateActivity()
return conn, false
}
func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest net.Destination) {
id := connID{
src: source,
}
if originalDest.IsValid() {
id.dest = originalDest
}
conn, existing := w.getConnection(id)
// payload will be discarded in pipe is full.
conn.writer.WriteMultiBuffer(buf.MultiBuffer{b})
if !existing {
common.Must(w.checker.Start())
go func() {
ctx := context.Background()
sid := session.NewID()
ctx = session.ContextWithID(ctx, sid)
if originalDest.IsValid() {
ctx = session.ContextWithOutbound(ctx, &session.Outbound{
Target: originalDest,
})
}
ctx = session.ContextWithInbound(ctx, &session.Inbound{
Source: source,
Gateway: net.UDPDestination(w.address, w.port),
Tag: w.tag,
})
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
conn.Close()
w.removeConn(id)
}()
}
}
func (w *udpWorker) removeConn(id connID) {
w.Lock()
delete(w.activeConn, id)
w.Unlock()
}
func (w *udpWorker) handlePackets() {
receive := w.hub.Receive()
for payload := range receive {
w.callback(payload.Payload, payload.Source, payload.Target)
}
}
func (w *udpWorker) clean() error {
nowSec := time.Now().Unix()
w.Lock()
defer w.Unlock()
if len(w.activeConn) == 0 {
return newError("no more connections. stopping...")
}
for addr, conn := range w.activeConn {
if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 8 { // TODO Timeout too small
delete(w.activeConn, addr)
conn.Close()
}
}
if len(w.activeConn) == 0 {
w.activeConn = make(map[connID]*udpConn, 16)
}
return nil
}
func (w *udpWorker) Start() error {
w.activeConn = make(map[connID]*udpConn, 16)
ctx := context.Background()
h, err := udp.ListenUDP(ctx, w.address, w.port, w.stream, udp.HubCapacity(256))
if err != nil {
return err
}
w.checker = &task.Periodic{
Interval: time.Second * 16,
Execute: w.clean,
}
w.hub = h
go w.handlePackets()
return nil
}
func (w *udpWorker) Close() error {
w.Lock()
defer w.Unlock()
var errors []interface{}
if w.hub != nil {
if err := w.hub.Close(); err != nil {
errors = append(errors, err)
}
}
if w.checker != nil {
if err := w.checker.Close(); err != nil {
errors = append(errors, err)
}
}
if err := common.Close(w.proxy); err != nil {
errors = append(errors, err)
}
if len(errors) > 0 {
return newError("failed to close all resources").Base(newError(serial.Concat(errors...)))
}
return nil
}
func (w *udpWorker) Port() net.Port {
return w.port
}
func (w *udpWorker) Proxy() proxy.Inbound {
return w.proxy
}
type dsWorker struct {
address net.Address
proxy proxy.Inbound
stream *internet.MemoryStreamConfig
tag string
dispatcher routing.Dispatcher
sniffingConfig *proxyman.SniffingConfig
uplinkCounter stats.Counter
downlinkCounter stats.Counter
hub internet.Listener
ctx context.Context
}
func (w *dsWorker) callback(conn internet.Connection) {
ctx, cancel := context.WithCancel(w.ctx)
sid := session.NewID()
ctx = session.ContextWithID(ctx, sid)
ctx = session.ContextWithInbound(ctx, &session.Inbound{
Source: net.DestinationFromAddr(conn.RemoteAddr()),
Gateway: net.UnixDestination(w.address),
Tag: w.tag,
})
content := new(session.Content)
if w.sniffingConfig != nil {
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
}
ctx = session.ContextWithContent(ctx, content)
if w.uplinkCounter != nil || w.downlinkCounter != nil {
conn = &internet.StatCouterConnection{
Connection: conn,
ReadCounter: w.uplinkCounter,
WriteCounter: w.downlinkCounter,
}
}
if err := w.proxy.Process(ctx, net.Network_UNIX, conn, w.dispatcher); err != nil {
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
cancel()
if err := conn.Close(); err != nil {
newError("failed to close connection").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
}
func (w *dsWorker) Proxy() proxy.Inbound {
return w.proxy
}
func (w *dsWorker) Port() net.Port {
return net.Port(0)
}
func (w *dsWorker) Start() error {
ctx := context.Background()
hub, err := internet.ListenUnix(ctx, w.address, w.stream, func(conn internet.Connection) {
go w.callback(conn)
})
if err != nil {
return newError("failed to listen Unix Domain Socket on ", w.address).AtWarning().Base(err)
}
w.hub = hub
return nil
}
func (w *dsWorker) Close() error {
var errors []interface{}
if w.hub != nil {
if err := common.Close(w.hub); err != nil {
errors = append(errors, err)
}
if err := common.Close(w.proxy); err != nil {
errors = append(errors, err)
}
}
if len(errors) > 0 {
return newError("failed to close all resources").Base(newError(serial.Concat(errors...)))
}
return nil
}
v2ray-core-4.34.0/app/proxyman/outbound/ 0000775 0000000 0000000 00000000000 13774574720 0020107 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/proxyman/outbound/errors.generated.go 0000664 0000000 0000000 00000000316 13774574720 0023707 0 ustar 00root root 0000000 0000000 package outbound
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/app/proxyman/outbound/handler.go 0000664 0000000 0000000 00000015257 13774574720 0022065 0 ustar 00root root 0000000 0000000 package outbound
import (
"context"
"v2ray.com/core"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common"
"v2ray.com/core/common/mux"
"v2ray.com/core/common/net"
"v2ray.com/core/common/session"
"v2ray.com/core/features/outbound"
"v2ray.com/core/features/policy"
"v2ray.com/core/features/stats"
"v2ray.com/core/proxy"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/tls"
"v2ray.com/core/transport/pipe"
)
func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {
var uplinkCounter stats.Counter
var downlinkCounter stats.Counter
policy := v.GetFeature(policy.ManagerType()).(policy.Manager)
if len(tag) > 0 && policy.ForSystem().Stats.OutboundUplink {
statsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)
name := "outbound>>>" + tag + ">>>traffic>>>uplink"
c, _ := stats.GetOrRegisterCounter(statsManager, name)
if c != nil {
uplinkCounter = c
}
}
if len(tag) > 0 && policy.ForSystem().Stats.OutboundDownlink {
statsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)
name := "outbound>>>" + tag + ">>>traffic>>>downlink"
c, _ := stats.GetOrRegisterCounter(statsManager, name)
if c != nil {
downlinkCounter = c
}
}
return uplinkCounter, downlinkCounter
}
// Handler is an implements of outbound.Handler.
type Handler struct {
tag string
senderSettings *proxyman.SenderConfig
streamSettings *internet.MemoryStreamConfig
proxy proxy.Outbound
outboundManager outbound.Manager
mux *mux.ClientManager
uplinkCounter stats.Counter
downlinkCounter stats.Counter
}
// NewHandler create a new Handler based on the given configuration.
func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbound.Handler, error) {
v := core.MustFromContext(ctx)
uplinkCounter, downlinkCounter := getStatCounter(v, config.Tag)
h := &Handler{
tag: config.Tag,
outboundManager: v.GetFeature(outbound.ManagerType()).(outbound.Manager),
uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter,
}
if config.SenderSettings != nil {
senderSettings, err := config.SenderSettings.GetInstance()
if err != nil {
return nil, err
}
switch s := senderSettings.(type) {
case *proxyman.SenderConfig:
h.senderSettings = s
mss, err := internet.ToMemoryStreamConfig(s.StreamSettings)
if err != nil {
return nil, newError("failed to parse stream settings").Base(err).AtWarning()
}
h.streamSettings = mss
default:
return nil, newError("settings is not SenderConfig")
}
}
proxyConfig, err := config.ProxySettings.GetInstance()
if err != nil {
return nil, err
}
rawProxyHandler, err := common.CreateObject(ctx, proxyConfig)
if err != nil {
return nil, err
}
proxyHandler, ok := rawProxyHandler.(proxy.Outbound)
if !ok {
return nil, newError("not an outbound handler")
}
if h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil {
config := h.senderSettings.MultiplexSettings
if config.Concurrency < 1 || config.Concurrency > 1024 {
return nil, newError("invalid mux concurrency: ", config.Concurrency).AtWarning()
}
h.mux = &mux.ClientManager{
Enabled: h.senderSettings.MultiplexSettings.Enabled,
Picker: &mux.IncrementalWorkerPicker{
Factory: &mux.DialingWorkerFactory{
Proxy: proxyHandler,
Dialer: h,
Strategy: mux.ClientStrategy{
MaxConcurrency: config.Concurrency,
MaxConnection: 128,
},
},
},
}
}
h.proxy = proxyHandler
return h, nil
}
// Tag implements outbound.Handler.
func (h *Handler) Tag() string {
return h.tag
}
// Dispatch implements proxy.Outbound.Dispatch.
func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
if h.mux != nil && (h.mux.Enabled || session.MuxPreferedFromContext(ctx)) {
if err := h.mux.Dispatch(ctx, link); err != nil {
newError("failed to process mux outbound traffic").Base(err).WriteToLog(session.ExportIDToError(ctx))
common.Interrupt(link.Writer)
}
} else {
if err := h.proxy.Process(ctx, link, h); err != nil {
// Ensure outbound ray is properly closed.
newError("failed to process outbound traffic").Base(err).WriteToLog(session.ExportIDToError(ctx))
common.Interrupt(link.Writer)
} else {
common.Must(common.Close(link.Writer))
}
common.Interrupt(link.Reader)
}
}
// Address implements internet.Dialer.
func (h *Handler) Address() net.Address {
if h.senderSettings == nil || h.senderSettings.Via == nil {
return nil
}
return h.senderSettings.Via.AsAddress()
}
// Dial implements internet.Dialer.
func (h *Handler) Dial(ctx context.Context, dest net.Destination) (internet.Connection, error) {
if h.senderSettings != nil {
if h.senderSettings.ProxySettings.HasTag() {
tag := h.senderSettings.ProxySettings.Tag
handler := h.outboundManager.GetHandler(tag)
if handler != nil {
newError("proxying to ", tag, " for dest ", dest).AtDebug().WriteToLog(session.ExportIDToError(ctx))
ctx = session.ContextWithOutbound(ctx, &session.Outbound{
Target: dest,
})
opts := pipe.OptionsFromContext(ctx)
uplinkReader, uplinkWriter := pipe.New(opts...)
downlinkReader, downlinkWriter := pipe.New(opts...)
go handler.Dispatch(ctx, &transport.Link{Reader: uplinkReader, Writer: downlinkWriter})
conn := net.NewConnection(net.ConnectionInputMulti(uplinkWriter), net.ConnectionOutputMulti(downlinkReader))
if config := tls.ConfigFromStreamSettings(h.streamSettings); config != nil {
tlsConfig := config.GetTLSConfig(tls.WithDestination(dest))
conn = tls.Client(conn, tlsConfig)
}
return h.getStatCouterConnection(conn), nil
}
newError("failed to get outbound handler with tag: ", tag).AtWarning().WriteToLog(session.ExportIDToError(ctx))
}
if h.senderSettings.Via != nil {
outbound := session.OutboundFromContext(ctx)
if outbound == nil {
outbound = new(session.Outbound)
ctx = session.ContextWithOutbound(ctx, outbound)
}
outbound.Gateway = h.senderSettings.Via.AsAddress()
}
}
conn, err := internet.Dial(ctx, dest, h.streamSettings)
return h.getStatCouterConnection(conn), err
}
func (h *Handler) getStatCouterConnection(conn internet.Connection) internet.Connection {
if h.uplinkCounter != nil || h.downlinkCounter != nil {
return &internet.StatCouterConnection{
Connection: conn,
ReadCounter: h.downlinkCounter,
WriteCounter: h.uplinkCounter,
}
}
return conn
}
// GetOutbound implements proxy.GetOutbound.
func (h *Handler) GetOutbound() proxy.Outbound {
return h.proxy
}
// Start implements common.Runnable.
func (h *Handler) Start() error {
return nil
}
// Close implements common.Closable.
func (h *Handler) Close() error {
common.Close(h.mux)
return nil
}
v2ray-core-4.34.0/app/proxyman/outbound/handler_test.go 0000664 0000000 0000000 00000004144 13774574720 0023115 0 ustar 00root root 0000000 0000000 package outbound_test
import (
"context"
"testing"
"v2ray.com/core"
"v2ray.com/core/app/policy"
. "v2ray.com/core/app/proxyman/outbound"
"v2ray.com/core/app/stats"
"v2ray.com/core/common/net"
"v2ray.com/core/common/serial"
"v2ray.com/core/features/outbound"
"v2ray.com/core/proxy/freedom"
"v2ray.com/core/transport/internet"
)
func TestInterfaces(t *testing.T) {
_ = (outbound.Handler)(new(Handler))
_ = (outbound.Manager)(new(Manager))
}
const v2rayKey core.V2rayKey = 1
func TestOutboundWithoutStatCounter(t *testing.T) {
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&stats.Config{}),
serial.ToTypedMessage(&policy.Config{
System: &policy.SystemPolicy{
Stats: &policy.SystemPolicy_Stats{
InboundUplink: true,
},
},
}),
},
}
v, _ := core.New(config)
v.AddFeature((outbound.Manager)(new(Manager)))
ctx := context.WithValue(context.Background(), v2rayKey, v)
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
Tag: "tag",
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
})
conn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146))
_, ok := conn.(*internet.StatCouterConnection)
if ok {
t.Errorf("Expected conn to not be StatCouterConnection")
}
}
func TestOutboundWithStatCounter(t *testing.T) {
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&stats.Config{}),
serial.ToTypedMessage(&policy.Config{
System: &policy.SystemPolicy{
Stats: &policy.SystemPolicy_Stats{
OutboundUplink: true,
OutboundDownlink: true,
},
},
}),
},
}
v, _ := core.New(config)
v.AddFeature((outbound.Manager)(new(Manager)))
ctx := context.WithValue(context.Background(), v2rayKey, v)
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
Tag: "tag",
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
})
conn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146))
_, ok := conn.(*internet.StatCouterConnection)
if !ok {
t.Errorf("Expected conn to be StatCouterConnection")
}
}
v2ray-core-4.34.0/app/proxyman/outbound/outbound.go 0000664 0000000 0000000 00000006771 13774574720 0022310 0 ustar 00root root 0000000 0000000 package outbound
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"strings"
"sync"
"v2ray.com/core"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
"v2ray.com/core/features/outbound"
)
// Manager is to manage all outbound handlers.
type Manager struct {
access sync.RWMutex
defaultHandler outbound.Handler
taggedHandler map[string]outbound.Handler
untaggedHandlers []outbound.Handler
running bool
}
// New creates a new Manager.
func New(ctx context.Context, config *proxyman.OutboundConfig) (*Manager, error) {
m := &Manager{
taggedHandler: make(map[string]outbound.Handler),
}
return m, nil
}
// Type implements common.HasType.
func (m *Manager) Type() interface{} {
return outbound.ManagerType()
}
// Start implements core.Feature
func (m *Manager) Start() error {
m.access.Lock()
defer m.access.Unlock()
m.running = true
for _, h := range m.taggedHandler {
if err := h.Start(); err != nil {
return err
}
}
for _, h := range m.untaggedHandlers {
if err := h.Start(); err != nil {
return err
}
}
return nil
}
// Close implements core.Feature
func (m *Manager) Close() error {
m.access.Lock()
defer m.access.Unlock()
m.running = false
var errs []error
for _, h := range m.taggedHandler {
errs = append(errs, h.Close())
}
for _, h := range m.untaggedHandlers {
errs = append(errs, h.Close())
}
return errors.Combine(errs...)
}
// GetDefaultHandler implements outbound.Manager.
func (m *Manager) GetDefaultHandler() outbound.Handler {
m.access.RLock()
defer m.access.RUnlock()
if m.defaultHandler == nil {
return nil
}
return m.defaultHandler
}
// GetHandler implements outbound.Manager.
func (m *Manager) GetHandler(tag string) outbound.Handler {
m.access.RLock()
defer m.access.RUnlock()
if handler, found := m.taggedHandler[tag]; found {
return handler
}
return nil
}
// AddHandler implements outbound.Manager.
func (m *Manager) AddHandler(ctx context.Context, handler outbound.Handler) error {
m.access.Lock()
defer m.access.Unlock()
if m.defaultHandler == nil {
m.defaultHandler = handler
}
tag := handler.Tag()
if len(tag) > 0 {
m.taggedHandler[tag] = handler
} else {
m.untaggedHandlers = append(m.untaggedHandlers, handler)
}
if m.running {
return handler.Start()
}
return nil
}
// RemoveHandler implements outbound.Manager.
func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
if tag == "" {
return common.ErrNoClue
}
m.access.Lock()
defer m.access.Unlock()
delete(m.taggedHandler, tag)
if m.defaultHandler != nil && m.defaultHandler.Tag() == tag {
m.defaultHandler = nil
}
return nil
}
// Select implements outbound.HandlerSelector.
func (m *Manager) Select(selectors []string) []string {
m.access.RLock()
defer m.access.RUnlock()
tags := make([]string, 0, len(selectors))
for tag := range m.taggedHandler {
match := false
for _, selector := range selectors {
if strings.HasPrefix(tag, selector) {
match = true
break
}
}
if match {
tags = append(tags, tag)
}
}
return tags
}
func init() {
common.Must(common.RegisterConfig((*proxyman.OutboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*proxyman.OutboundConfig))
}))
common.Must(common.RegisterConfig((*core.OutboundHandlerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewHandler(ctx, config.(*core.OutboundHandlerConfig))
}))
}
v2ray-core-4.34.0/app/reverse/ 0000775 0000000 0000000 00000000000 13774574720 0016046 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/reverse/bridge.go 0000664 0000000 0000000 00000007741 13774574720 0017642 0 ustar 00root root 0000000 0000000 // +build !confonly
package reverse
import (
"context"
"time"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/mux"
"v2ray.com/core/common/net"
"v2ray.com/core/common/session"
"v2ray.com/core/common/task"
"v2ray.com/core/features/routing"
"v2ray.com/core/transport"
"v2ray.com/core/transport/pipe"
)
// Bridge is a component in reverse proxy, that relays connections from Portal to local address.
type Bridge struct {
dispatcher routing.Dispatcher
tag string
domain string
workers []*BridgeWorker
monitorTask *task.Periodic
}
// NewBridge creates a new Bridge instance.
func NewBridge(config *BridgeConfig, dispatcher routing.Dispatcher) (*Bridge, error) {
if config.Tag == "" {
return nil, newError("bridge tag is empty")
}
if config.Domain == "" {
return nil, newError("bridge domain is empty")
}
b := &Bridge{
dispatcher: dispatcher,
tag: config.Tag,
domain: config.Domain,
}
b.monitorTask = &task.Periodic{
Execute: b.monitor,
Interval: time.Second * 2,
}
return b, nil
}
func (b *Bridge) cleanup() {
var activeWorkers []*BridgeWorker
for _, w := range b.workers {
if w.IsActive() {
activeWorkers = append(activeWorkers, w)
}
}
if len(activeWorkers) != len(b.workers) {
b.workers = activeWorkers
}
}
func (b *Bridge) monitor() error {
b.cleanup()
var numConnections uint32
var numWorker uint32
for _, w := range b.workers {
if w.IsActive() {
numConnections += w.Connections()
numWorker++
}
}
if numWorker == 0 || numConnections/numWorker > 16 {
worker, err := NewBridgeWorker(b.domain, b.tag, b.dispatcher)
if err != nil {
newError("failed to create bridge worker").Base(err).AtWarning().WriteToLog()
return nil
}
b.workers = append(b.workers, worker)
}
return nil
}
func (b *Bridge) Start() error {
return b.monitorTask.Start()
}
func (b *Bridge) Close() error {
return b.monitorTask.Close()
}
type BridgeWorker struct {
tag string
worker *mux.ServerWorker
dispatcher routing.Dispatcher
state Control_State
}
func NewBridgeWorker(domain string, tag string, d routing.Dispatcher) (*BridgeWorker, error) {
ctx := context.Background()
ctx = session.ContextWithInbound(ctx, &session.Inbound{
Tag: tag,
})
link, err := d.Dispatch(ctx, net.Destination{
Network: net.Network_TCP,
Address: net.DomainAddress(domain),
Port: 0,
})
if err != nil {
return nil, err
}
w := &BridgeWorker{
dispatcher: d,
tag: tag,
}
worker, err := mux.NewServerWorker(context.Background(), w, link)
if err != nil {
return nil, err
}
w.worker = worker
return w, nil
}
func (w *BridgeWorker) Type() interface{} {
return routing.DispatcherType()
}
func (w *BridgeWorker) Start() error {
return nil
}
func (w *BridgeWorker) Close() error {
return nil
}
func (w *BridgeWorker) IsActive() bool {
return w.state == Control_ACTIVE && !w.worker.Closed()
}
func (w *BridgeWorker) Connections() uint32 {
return w.worker.ActiveConnections()
}
func (w *BridgeWorker) handleInternalConn(link transport.Link) {
go func() {
reader := link.Reader
for {
mb, err := reader.ReadMultiBuffer()
if err != nil {
break
}
for _, b := range mb {
var ctl Control
if err := proto.Unmarshal(b.Bytes(), &ctl); err != nil {
newError("failed to parse proto message").Base(err).WriteToLog()
break
}
if ctl.State != w.state {
w.state = ctl.State
}
}
}
}()
}
func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {
if !isInternalDomain(dest) {
ctx = session.ContextWithInbound(ctx, &session.Inbound{
Tag: w.tag,
})
return w.dispatcher.Dispatch(ctx, dest)
}
opt := []pipe.Option{pipe.WithSizeLimit(16 * 1024)}
uplinkReader, uplinkWriter := pipe.New(opt...)
downlinkReader, downlinkWriter := pipe.New(opt...)
w.handleInternalConn(transport.Link{
Reader: downlinkReader,
Writer: uplinkWriter,
})
return &transport.Link{
Reader: uplinkReader,
Writer: downlinkWriter,
}, nil
}
v2ray-core-4.34.0/app/reverse/config.go 0000664 0000000 0000000 00000000365 13774574720 0017646 0 ustar 00root root 0000000 0000000 // +build !confonly
package reverse
import (
"crypto/rand"
"io"
"v2ray.com/core/common/dice"
)
func (c *Control) FillInRandom() {
randomLength := dice.Roll(64)
c.Random = make([]byte, randomLength)
io.ReadFull(rand.Reader, c.Random)
}
v2ray-core-4.34.0/app/reverse/config.pb.go 0000664 0000000 0000000 00000033717 13774574720 0020255 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: app/reverse/config.proto
package reverse
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Control_State int32
const (
Control_ACTIVE Control_State = 0
Control_DRAIN Control_State = 1
)
// Enum value maps for Control_State.
var (
Control_State_name = map[int32]string{
0: "ACTIVE",
1: "DRAIN",
}
Control_State_value = map[string]int32{
"ACTIVE": 0,
"DRAIN": 1,
}
)
func (x Control_State) Enum() *Control_State {
p := new(Control_State)
*p = x
return p
}
func (x Control_State) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Control_State) Descriptor() protoreflect.EnumDescriptor {
return file_app_reverse_config_proto_enumTypes[0].Descriptor()
}
func (Control_State) Type() protoreflect.EnumType {
return &file_app_reverse_config_proto_enumTypes[0]
}
func (x Control_State) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Control_State.Descriptor instead.
func (Control_State) EnumDescriptor() ([]byte, []int) {
return file_app_reverse_config_proto_rawDescGZIP(), []int{0, 0}
}
type Control struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
State Control_State `protobuf:"varint,1,opt,name=state,proto3,enum=v2ray.core.app.reverse.Control_State" json:"state,omitempty"`
Random []byte `protobuf:"bytes,99,opt,name=random,proto3" json:"random,omitempty"`
}
func (x *Control) Reset() {
*x = Control{}
if protoimpl.UnsafeEnabled {
mi := &file_app_reverse_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Control) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Control) ProtoMessage() {}
func (x *Control) ProtoReflect() protoreflect.Message {
mi := &file_app_reverse_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Control.ProtoReflect.Descriptor instead.
func (*Control) Descriptor() ([]byte, []int) {
return file_app_reverse_config_proto_rawDescGZIP(), []int{0}
}
func (x *Control) GetState() Control_State {
if x != nil {
return x.State
}
return Control_ACTIVE
}
func (x *Control) GetRandom() []byte {
if x != nil {
return x.Random
}
return nil
}
type BridgeConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
}
func (x *BridgeConfig) Reset() {
*x = BridgeConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_app_reverse_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BridgeConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BridgeConfig) ProtoMessage() {}
func (x *BridgeConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_reverse_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BridgeConfig.ProtoReflect.Descriptor instead.
func (*BridgeConfig) Descriptor() ([]byte, []int) {
return file_app_reverse_config_proto_rawDescGZIP(), []int{1}
}
func (x *BridgeConfig) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
func (x *BridgeConfig) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
type PortalConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
}
func (x *PortalConfig) Reset() {
*x = PortalConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_app_reverse_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PortalConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PortalConfig) ProtoMessage() {}
func (x *PortalConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_reverse_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PortalConfig.ProtoReflect.Descriptor instead.
func (*PortalConfig) Descriptor() ([]byte, []int) {
return file_app_reverse_config_proto_rawDescGZIP(), []int{2}
}
func (x *PortalConfig) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
func (x *PortalConfig) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
BridgeConfig []*BridgeConfig `protobuf:"bytes,1,rep,name=bridge_config,json=bridgeConfig,proto3" json:"bridge_config,omitempty"`
PortalConfig []*PortalConfig `protobuf:"bytes,2,rep,name=portal_config,json=portalConfig,proto3" json:"portal_config,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_reverse_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_reverse_config_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_reverse_config_proto_rawDescGZIP(), []int{3}
}
func (x *Config) GetBridgeConfig() []*BridgeConfig {
if x != nil {
return x.BridgeConfig
}
return nil
}
func (x *Config) GetPortalConfig() []*PortalConfig {
if x != nil {
return x.PortalConfig
}
return nil
}
var File_app_reverse_config_proto protoreflect.FileDescriptor
var file_app_reverse_config_proto_rawDesc = []byte{
0x0a, 0x18, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x2f, 0x63, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x76, 0x32, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x65, 0x76, 0x65, 0x72,
0x73, 0x65, 0x22, 0x7e, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x3b, 0x0a,
0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x65,
0x76, 0x65, 0x72, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x74,
0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x61,
0x6e, 0x64, 0x6f, 0x6d, 0x18, 0x63, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x61, 0x6e, 0x64,
0x6f, 0x6d, 0x22, 0x1e, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x41,
0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x52, 0x41, 0x49, 0x4e,
0x10, 0x01, 0x22, 0x38, 0x0a, 0x0c, 0x42, 0x72, 0x69, 0x64, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x74, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x38, 0x0a, 0x0c,
0x50, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03,
0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x16,
0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x9e, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x12, 0x49, 0x0a, 0x0d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73,
0x65, 0x2e, 0x42, 0x72, 0x69, 0x64, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0c,
0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x49, 0x0a, 0x0d,
0x70, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x2e, 0x50, 0x6f, 0x72,
0x74, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0c, 0x70, 0x6f, 0x72, 0x74, 0x61,
0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x57, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x50, 0x01, 0x5a, 0x1a, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x65,
0x76, 0x65, 0x72, 0x73, 0x65, 0xaa, 0x02, 0x18, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f,
0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_reverse_config_proto_rawDescOnce sync.Once
file_app_reverse_config_proto_rawDescData = file_app_reverse_config_proto_rawDesc
)
func file_app_reverse_config_proto_rawDescGZIP() []byte {
file_app_reverse_config_proto_rawDescOnce.Do(func() {
file_app_reverse_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_reverse_config_proto_rawDescData)
})
return file_app_reverse_config_proto_rawDescData
}
var file_app_reverse_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_app_reverse_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_app_reverse_config_proto_goTypes = []interface{}{
(Control_State)(0), // 0: v2ray.core.app.reverse.Control.State
(*Control)(nil), // 1: v2ray.core.app.reverse.Control
(*BridgeConfig)(nil), // 2: v2ray.core.app.reverse.BridgeConfig
(*PortalConfig)(nil), // 3: v2ray.core.app.reverse.PortalConfig
(*Config)(nil), // 4: v2ray.core.app.reverse.Config
}
var file_app_reverse_config_proto_depIdxs = []int32{
0, // 0: v2ray.core.app.reverse.Control.state:type_name -> v2ray.core.app.reverse.Control.State
2, // 1: v2ray.core.app.reverse.Config.bridge_config:type_name -> v2ray.core.app.reverse.BridgeConfig
3, // 2: v2ray.core.app.reverse.Config.portal_config:type_name -> v2ray.core.app.reverse.PortalConfig
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_app_reverse_config_proto_init() }
func file_app_reverse_config_proto_init() {
if File_app_reverse_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_reverse_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Control); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_reverse_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BridgeConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_reverse_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PortalConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_reverse_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_reverse_config_proto_rawDesc,
NumEnums: 1,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_app_reverse_config_proto_goTypes,
DependencyIndexes: file_app_reverse_config_proto_depIdxs,
EnumInfos: file_app_reverse_config_proto_enumTypes,
MessageInfos: file_app_reverse_config_proto_msgTypes,
}.Build()
File_app_reverse_config_proto = out.File
file_app_reverse_config_proto_rawDesc = nil
file_app_reverse_config_proto_goTypes = nil
file_app_reverse_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/app/reverse/config.proto 0000664 0000000 0000000 00000001121 13774574720 0020373 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.app.reverse;
option csharp_namespace = "V2Ray.Core.Proxy.Reverse";
option go_package = "v2ray.com/core/app/reverse";
option java_package = "com.v2ray.core.proxy.reverse";
option java_multiple_files = true;
message Control {
enum State {
ACTIVE = 0;
DRAIN = 1;
}
State state = 1;
bytes random = 99;
}
message BridgeConfig {
string tag = 1;
string domain = 2;
}
message PortalConfig {
string tag = 1;
string domain = 2;
}
message Config {
repeated BridgeConfig bridge_config = 1;
repeated PortalConfig portal_config = 2;
}
v2ray-core-4.34.0/app/reverse/errors.generated.go 0000664 0000000 0000000 00000000315 13774574720 0021645 0 ustar 00root root 0000000 0000000 package reverse
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/app/reverse/portal.go 0000664 0000000 0000000 00000012471 13774574720 0017703 0 ustar 00root root 0000000 0000000 // +build !confonly
package reverse
import (
"context"
"sync"
"time"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/mux"
"v2ray.com/core/common/net"
"v2ray.com/core/common/session"
"v2ray.com/core/common/task"
"v2ray.com/core/features/outbound"
"v2ray.com/core/transport"
"v2ray.com/core/transport/pipe"
)
type Portal struct {
ohm outbound.Manager
tag string
domain string
picker *StaticMuxPicker
client *mux.ClientManager
}
func NewPortal(config *PortalConfig, ohm outbound.Manager) (*Portal, error) {
if config.Tag == "" {
return nil, newError("portal tag is empty")
}
if config.Domain == "" {
return nil, newError("portal domain is empty")
}
picker, err := NewStaticMuxPicker()
if err != nil {
return nil, err
}
return &Portal{
ohm: ohm,
tag: config.Tag,
domain: config.Domain,
picker: picker,
client: &mux.ClientManager{
Picker: picker,
},
}, nil
}
func (p *Portal) Start() error {
return p.ohm.AddHandler(context.Background(), &Outbound{
portal: p,
tag: p.tag,
})
}
func (p *Portal) Close() error {
return p.ohm.RemoveHandler(context.Background(), p.tag)
}
func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) error {
outboundMeta := session.OutboundFromContext(ctx)
if outboundMeta == nil {
return newError("outbound metadata not found").AtError()
}
if isDomain(outboundMeta.Target, p.domain) {
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
if err != nil {
return newError("failed to create mux client worker").Base(err).AtWarning()
}
worker, err := NewPortalWorker(muxClient)
if err != nil {
return newError("failed to create portal worker").Base(err)
}
p.picker.AddWorker(worker)
return nil
}
return p.client.Dispatch(ctx, link)
}
type Outbound struct {
portal *Portal
tag string
}
func (o *Outbound) Tag() string {
return o.tag
}
func (o *Outbound) Dispatch(ctx context.Context, link *transport.Link) {
if err := o.portal.HandleConnection(ctx, link); err != nil {
newError("failed to process reverse connection").Base(err).WriteToLog(session.ExportIDToError(ctx))
common.Interrupt(link.Writer)
}
}
func (o *Outbound) Start() error {
return nil
}
func (o *Outbound) Close() error {
return nil
}
type StaticMuxPicker struct {
access sync.Mutex
workers []*PortalWorker
cTask *task.Periodic
}
func NewStaticMuxPicker() (*StaticMuxPicker, error) {
p := &StaticMuxPicker{}
p.cTask = &task.Periodic{
Execute: p.cleanup,
Interval: time.Second * 30,
}
p.cTask.Start()
return p, nil
}
func (p *StaticMuxPicker) cleanup() error {
p.access.Lock()
defer p.access.Unlock()
var activeWorkers []*PortalWorker
for _, w := range p.workers {
if !w.Closed() {
activeWorkers = append(activeWorkers, w)
}
}
if len(activeWorkers) != len(p.workers) {
p.workers = activeWorkers
}
return nil
}
func (p *StaticMuxPicker) PickAvailable() (*mux.ClientWorker, error) {
p.access.Lock()
defer p.access.Unlock()
if len(p.workers) == 0 {
return nil, newError("empty worker list")
}
var minIdx int = -1
var minConn uint32 = 9999
for i, w := range p.workers {
if w.draining {
continue
}
if w.client.ActiveConnections() < minConn {
minConn = w.client.ActiveConnections()
minIdx = i
}
}
if minIdx == -1 {
for i, w := range p.workers {
if w.IsFull() {
continue
}
if w.client.ActiveConnections() < minConn {
minConn = w.client.ActiveConnections()
minIdx = i
}
}
}
if minIdx != -1 {
return p.workers[minIdx].client, nil
}
return nil, newError("no mux client worker available")
}
func (p *StaticMuxPicker) AddWorker(worker *PortalWorker) {
p.access.Lock()
defer p.access.Unlock()
p.workers = append(p.workers, worker)
}
type PortalWorker struct {
client *mux.ClientWorker
control *task.Periodic
writer buf.Writer
reader buf.Reader
draining bool
}
func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
opt := []pipe.Option{pipe.WithSizeLimit(16 * 1024)}
uplinkReader, uplinkWriter := pipe.New(opt...)
downlinkReader, downlinkWriter := pipe.New(opt...)
ctx := context.Background()
ctx = session.ContextWithOutbound(ctx, &session.Outbound{
Target: net.UDPDestination(net.DomainAddress(internalDomain), 0),
})
f := client.Dispatch(ctx, &transport.Link{
Reader: uplinkReader,
Writer: downlinkWriter,
})
if !f {
return nil, newError("unable to dispatch control connection")
}
w := &PortalWorker{
client: client,
reader: downlinkReader,
writer: uplinkWriter,
}
w.control = &task.Periodic{
Execute: w.heartbeat,
Interval: time.Second * 2,
}
w.control.Start()
return w, nil
}
func (w *PortalWorker) heartbeat() error {
if w.client.Closed() {
return newError("client worker stopped")
}
if w.draining || w.writer == nil {
return newError("already disposed")
}
msg := &Control{}
msg.FillInRandom()
if w.client.TotalConnections() > 256 {
w.draining = true
msg.State = Control_DRAIN
defer func() {
common.Close(w.writer)
common.Interrupt(w.reader)
w.writer = nil
}()
}
b, err := proto.Marshal(msg)
common.Must(err)
mb := buf.MergeBytes(nil, b)
return w.writer.WriteMultiBuffer(mb)
}
func (w *PortalWorker) IsFull() bool {
return w.client.IsFull()
}
func (w *PortalWorker) Closed() bool {
return w.client.Closed()
}
v2ray-core-4.34.0/app/reverse/portal_test.go 0000664 0000000 0000000 00000000566 13774574720 0020744 0 ustar 00root root 0000000 0000000 package reverse_test
import (
"testing"
"v2ray.com/core/app/reverse"
"v2ray.com/core/common"
)
func TestStaticPickerEmpty(t *testing.T) {
picker, err := reverse.NewStaticMuxPicker()
common.Must(err)
worker, err := picker.PickAvailable()
if err == nil {
t.Error("expected error, but nil")
}
if worker != nil {
t.Error("expected nil worker, but not nil")
}
}
v2ray-core-4.34.0/app/reverse/reverse.go 0000664 0000000 0000000 00000003623 13774574720 0020054 0 ustar 00root root 0000000 0000000 // +build !confonly
package reverse
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/net"
"v2ray.com/core/features/outbound"
"v2ray.com/core/features/routing"
)
const (
internalDomain = "reverse.internal.v2ray.com"
)
func isDomain(dest net.Destination, domain string) bool {
return dest.Address.Family().IsDomain() && dest.Address.Domain() == domain
}
func isInternalDomain(dest net.Destination) bool {
return isDomain(dest, internalDomain)
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
r := new(Reverse)
if err := core.RequireFeatures(ctx, func(d routing.Dispatcher, om outbound.Manager) error {
return r.Init(config.(*Config), d, om)
}); err != nil {
return nil, err
}
return r, nil
}))
}
type Reverse struct {
bridges []*Bridge
portals []*Portal
}
func (r *Reverse) Init(config *Config, d routing.Dispatcher, ohm outbound.Manager) error {
for _, bConfig := range config.BridgeConfig {
b, err := NewBridge(bConfig, d)
if err != nil {
return err
}
r.bridges = append(r.bridges, b)
}
for _, pConfig := range config.PortalConfig {
p, err := NewPortal(pConfig, ohm)
if err != nil {
return err
}
r.portals = append(r.portals, p)
}
return nil
}
func (r *Reverse) Type() interface{} {
return (*Reverse)(nil)
}
func (r *Reverse) Start() error {
for _, b := range r.bridges {
if err := b.Start(); err != nil {
return err
}
}
for _, p := range r.portals {
if err := p.Start(); err != nil {
return err
}
}
return nil
}
func (r *Reverse) Close() error {
var errs []error
for _, b := range r.bridges {
errs = append(errs, b.Close())
}
for _, p := range r.portals {
errs = append(errs, p.Close())
}
return errors.Combine(errs...)
}
v2ray-core-4.34.0/app/router/ 0000775 0000000 0000000 00000000000 13774574720 0015713 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/router/balancing.go 0000664 0000000 0000000 00000001571 13774574720 0020164 0 ustar 00root root 0000000 0000000 // +build !confonly
package router
import (
"v2ray.com/core/common/dice"
"v2ray.com/core/features/outbound"
)
type BalancingStrategy interface {
PickOutbound([]string) string
}
type RandomStrategy struct {
}
func (s *RandomStrategy) PickOutbound(tags []string) string {
n := len(tags)
if n == 0 {
panic("0 tags")
}
return tags[dice.Roll(n)]
}
type Balancer struct {
selectors []string
strategy BalancingStrategy
ohm outbound.Manager
}
func (b *Balancer) PickOutbound() (string, error) {
hs, ok := b.ohm.(outbound.HandlerSelector)
if !ok {
return "", newError("outbound.Manager is not a HandlerSelector")
}
tags := hs.Select(b.selectors)
if len(tags) == 0 {
return "", newError("no available outbounds selected")
}
tag := b.strategy.PickOutbound(tags)
if tag == "" {
return "", newError("balancing strategy returns empty tag")
}
return tag, nil
}
v2ray-core-4.34.0/app/router/command/ 0000775 0000000 0000000 00000000000 13774574720 0017331 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/router/command/command.go 0000664 0000000 0000000 00000005057 13774574720 0021305 0 ustar 00root root 0000000 0000000 // +build !confonly
package command
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"time"
"google.golang.org/grpc"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/features/routing"
"v2ray.com/core/features/stats"
)
// routingServer is an implementation of RoutingService.
type routingServer struct {
router routing.Router
routingStats stats.Channel
}
// NewRoutingServer creates a statistics service with statistics manager.
func NewRoutingServer(router routing.Router, routingStats stats.Channel) RoutingServiceServer {
return &routingServer{
router: router,
routingStats: routingStats,
}
}
func (s *routingServer) TestRoute(ctx context.Context, request *TestRouteRequest) (*RoutingContext, error) {
if request.RoutingContext == nil {
return nil, newError("Invalid routing request.")
}
route, err := s.router.PickRoute(AsRoutingContext(request.RoutingContext))
if err != nil {
return nil, err
}
if request.PublishResult && s.routingStats != nil {
ctx, _ := context.WithTimeout(context.Background(), 4*time.Second) // nolint: govet
s.routingStats.Publish(ctx, route)
}
return AsProtobufMessage(request.FieldSelectors)(route), nil
}
func (s *routingServer) SubscribeRoutingStats(request *SubscribeRoutingStatsRequest, stream RoutingService_SubscribeRoutingStatsServer) error {
if s.routingStats == nil {
return newError("Routing statistics not enabled.")
}
genMessage := AsProtobufMessage(request.FieldSelectors)
subscriber, err := stats.SubscribeRunnableChannel(s.routingStats)
if err != nil {
return err
}
defer stats.UnsubscribeClosableChannel(s.routingStats, subscriber)
for {
select {
case value, ok := <-subscriber:
if !ok {
return newError("Upstream closed the subscriber channel.")
}
route, ok := value.(routing.Route)
if !ok {
return newError("Upstream sent malformed statistics.")
}
err := stream.Send(genMessage(route))
if err != nil {
return err
}
case <-stream.Context().Done():
return stream.Context().Err()
}
}
}
func (s *routingServer) mustEmbedUnimplementedRoutingServiceServer() {}
type service struct {
v *core.Instance
}
func (s *service) Register(server *grpc.Server) {
common.Must(s.v.RequireFeatures(func(router routing.Router, stats stats.Manager) {
RegisterRoutingServiceServer(server, NewRoutingServer(router, nil))
}))
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
s := core.MustFromContext(ctx)
return &service{v: s}, nil
}))
}
v2ray-core-4.34.0/app/router/command/command.pb.go 0000664 0000000 0000000 00000054161 13774574720 0021705 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: app/router/command/command.proto
package command
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
net "v2ray.com/core/common/net"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// RoutingContext is the context with information relative to routing process.
// It conforms to the structure of v2ray.core.features.routing.Context and
// v2ray.core.features.routing.Route.
type RoutingContext struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
InboundTag string `protobuf:"bytes,1,opt,name=InboundTag,proto3" json:"InboundTag,omitempty"`
Network net.Network `protobuf:"varint,2,opt,name=Network,proto3,enum=v2ray.core.common.net.Network" json:"Network,omitempty"`
SourceIPs [][]byte `protobuf:"bytes,3,rep,name=SourceIPs,proto3" json:"SourceIPs,omitempty"`
TargetIPs [][]byte `protobuf:"bytes,4,rep,name=TargetIPs,proto3" json:"TargetIPs,omitempty"`
SourcePort uint32 `protobuf:"varint,5,opt,name=SourcePort,proto3" json:"SourcePort,omitempty"`
TargetPort uint32 `protobuf:"varint,6,opt,name=TargetPort,proto3" json:"TargetPort,omitempty"`
TargetDomain string `protobuf:"bytes,7,opt,name=TargetDomain,proto3" json:"TargetDomain,omitempty"`
Protocol string `protobuf:"bytes,8,opt,name=Protocol,proto3" json:"Protocol,omitempty"`
User string `protobuf:"bytes,9,opt,name=User,proto3" json:"User,omitempty"`
Attributes map[string]string `protobuf:"bytes,10,rep,name=Attributes,proto3" json:"Attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
OutboundGroupTags []string `protobuf:"bytes,11,rep,name=OutboundGroupTags,proto3" json:"OutboundGroupTags,omitempty"`
OutboundTag string `protobuf:"bytes,12,opt,name=OutboundTag,proto3" json:"OutboundTag,omitempty"`
}
func (x *RoutingContext) Reset() {
*x = RoutingContext{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_command_command_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RoutingContext) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RoutingContext) ProtoMessage() {}
func (x *RoutingContext) ProtoReflect() protoreflect.Message {
mi := &file_app_router_command_command_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RoutingContext.ProtoReflect.Descriptor instead.
func (*RoutingContext) Descriptor() ([]byte, []int) {
return file_app_router_command_command_proto_rawDescGZIP(), []int{0}
}
func (x *RoutingContext) GetInboundTag() string {
if x != nil {
return x.InboundTag
}
return ""
}
func (x *RoutingContext) GetNetwork() net.Network {
if x != nil {
return x.Network
}
return net.Network_Unknown
}
func (x *RoutingContext) GetSourceIPs() [][]byte {
if x != nil {
return x.SourceIPs
}
return nil
}
func (x *RoutingContext) GetTargetIPs() [][]byte {
if x != nil {
return x.TargetIPs
}
return nil
}
func (x *RoutingContext) GetSourcePort() uint32 {
if x != nil {
return x.SourcePort
}
return 0
}
func (x *RoutingContext) GetTargetPort() uint32 {
if x != nil {
return x.TargetPort
}
return 0
}
func (x *RoutingContext) GetTargetDomain() string {
if x != nil {
return x.TargetDomain
}
return ""
}
func (x *RoutingContext) GetProtocol() string {
if x != nil {
return x.Protocol
}
return ""
}
func (x *RoutingContext) GetUser() string {
if x != nil {
return x.User
}
return ""
}
func (x *RoutingContext) GetAttributes() map[string]string {
if x != nil {
return x.Attributes
}
return nil
}
func (x *RoutingContext) GetOutboundGroupTags() []string {
if x != nil {
return x.OutboundGroupTags
}
return nil
}
func (x *RoutingContext) GetOutboundTag() string {
if x != nil {
return x.OutboundTag
}
return ""
}
// SubscribeRoutingStatsRequest subscribes to routing statistics channel if
// opened by v2ray-core.
// * FieldSelectors selects a subset of fields in routing statistics to return.
// Valid selectors:
// - inbound: Selects connection's inbound tag.
// - network: Selects connection's network.
// - ip: Equivalent as "ip_source" and "ip_target", selects both source and
// target IP.
// - port: Equivalent as "port_source" and "port_target", selects both source
// and target port.
// - domain: Selects target domain.
// - protocol: Select connection's protocol.
// - user: Select connection's inbound user email.
// - attributes: Select connection's additional attributes.
// - outbound: Equivalent as "outbound" and "outbound_group", select both
// outbound tag and outbound group tags.
// * If FieldSelectors is left empty, all fields will be returned.
type SubscribeRoutingStatsRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
FieldSelectors []string `protobuf:"bytes,1,rep,name=FieldSelectors,proto3" json:"FieldSelectors,omitempty"`
}
func (x *SubscribeRoutingStatsRequest) Reset() {
*x = SubscribeRoutingStatsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_command_command_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SubscribeRoutingStatsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SubscribeRoutingStatsRequest) ProtoMessage() {}
func (x *SubscribeRoutingStatsRequest) ProtoReflect() protoreflect.Message {
mi := &file_app_router_command_command_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SubscribeRoutingStatsRequest.ProtoReflect.Descriptor instead.
func (*SubscribeRoutingStatsRequest) Descriptor() ([]byte, []int) {
return file_app_router_command_command_proto_rawDescGZIP(), []int{1}
}
func (x *SubscribeRoutingStatsRequest) GetFieldSelectors() []string {
if x != nil {
return x.FieldSelectors
}
return nil
}
// TestRouteRequest manually tests a routing result according to the routing
// context message.
// * RoutingContext is the routing message without outbound information.
// * FieldSelectors selects the fields to return in the routing result. All
// fields are returned if left empty.
// * PublishResult broadcasts the routing result to routing statistics channel
// if set true.
type TestRouteRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
RoutingContext *RoutingContext `protobuf:"bytes,1,opt,name=RoutingContext,proto3" json:"RoutingContext,omitempty"`
FieldSelectors []string `protobuf:"bytes,2,rep,name=FieldSelectors,proto3" json:"FieldSelectors,omitempty"`
PublishResult bool `protobuf:"varint,3,opt,name=PublishResult,proto3" json:"PublishResult,omitempty"`
}
func (x *TestRouteRequest) Reset() {
*x = TestRouteRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_command_command_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TestRouteRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TestRouteRequest) ProtoMessage() {}
func (x *TestRouteRequest) ProtoReflect() protoreflect.Message {
mi := &file_app_router_command_command_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TestRouteRequest.ProtoReflect.Descriptor instead.
func (*TestRouteRequest) Descriptor() ([]byte, []int) {
return file_app_router_command_command_proto_rawDescGZIP(), []int{2}
}
func (x *TestRouteRequest) GetRoutingContext() *RoutingContext {
if x != nil {
return x.RoutingContext
}
return nil
}
func (x *TestRouteRequest) GetFieldSelectors() []string {
if x != nil {
return x.FieldSelectors
}
return nil
}
func (x *TestRouteRequest) GetPublishResult() bool {
if x != nil {
return x.PublishResult
}
return false
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_command_command_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_router_command_command_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_router_command_command_proto_rawDescGZIP(), []int{3}
}
var File_app_router_command_command_proto protoreflect.FileDescriptor
var file_app_router_command_command_proto_rawDesc = []byte{
0x0a, 0x20, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d,
0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x12, 0x1d, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
0x64, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65,
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa8, 0x04, 0x0a, 0x0e,
0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x1e,
0x0a, 0x0a, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0a, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x38,
0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52,
0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x6f, 0x75, 0x72,
0x63, 0x65, 0x49, 0x50, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x53, 0x6f, 0x75,
0x72, 0x63, 0x65, 0x49, 0x50, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
0x49, 0x50, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x54, 0x61, 0x72, 0x67, 0x65,
0x74, 0x49, 0x50, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f,
0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65,
0x50, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x50, 0x6f,
0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
0x50, 0x6f, 0x72, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x54, 0x61, 0x72, 0x67,
0x65, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x5d, 0x0a, 0x0a, 0x41, 0x74, 0x74, 0x72,
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75,
0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x72,
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x41, 0x74, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x4f, 0x75, 0x74, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x18, 0x0b, 0x20, 0x03,
0x28, 0x09, 0x52, 0x11, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x47, 0x72, 0x6f, 0x75,
0x70, 0x54, 0x61, 0x67, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e,
0x64, 0x54, 0x61, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x75, 0x74, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69,
0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x46, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72,
0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53,
0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e,
0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xb7,
0x01, 0x0a, 0x10, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x55, 0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f,
0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74,
0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0e, 0x52, 0x6f, 0x75, 0x74,
0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69,
0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03,
0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f,
0x72, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73,
0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69,
0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x32, 0x89, 0x02, 0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x87, 0x01, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72,
0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12,
0x3b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67,
0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75,
0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00, 0x30, 0x01, 0x12,
0x6d, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x2f, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x54, 0x65, 0x73,
0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f,
0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00, 0x42, 0x68,
0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x21, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x1d, 0x56, 0x32, 0x52, 0x61, 0x79,
0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72,
0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_router_command_command_proto_rawDescOnce sync.Once
file_app_router_command_command_proto_rawDescData = file_app_router_command_command_proto_rawDesc
)
func file_app_router_command_command_proto_rawDescGZIP() []byte {
file_app_router_command_command_proto_rawDescOnce.Do(func() {
file_app_router_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_router_command_command_proto_rawDescData)
})
return file_app_router_command_command_proto_rawDescData
}
var file_app_router_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_app_router_command_command_proto_goTypes = []interface{}{
(*RoutingContext)(nil), // 0: v2ray.core.app.router.command.RoutingContext
(*SubscribeRoutingStatsRequest)(nil), // 1: v2ray.core.app.router.command.SubscribeRoutingStatsRequest
(*TestRouteRequest)(nil), // 2: v2ray.core.app.router.command.TestRouteRequest
(*Config)(nil), // 3: v2ray.core.app.router.command.Config
nil, // 4: v2ray.core.app.router.command.RoutingContext.AttributesEntry
(net.Network)(0), // 5: v2ray.core.common.net.Network
}
var file_app_router_command_command_proto_depIdxs = []int32{
5, // 0: v2ray.core.app.router.command.RoutingContext.Network:type_name -> v2ray.core.common.net.Network
4, // 1: v2ray.core.app.router.command.RoutingContext.Attributes:type_name -> v2ray.core.app.router.command.RoutingContext.AttributesEntry
0, // 2: v2ray.core.app.router.command.TestRouteRequest.RoutingContext:type_name -> v2ray.core.app.router.command.RoutingContext
1, // 3: v2ray.core.app.router.command.RoutingService.SubscribeRoutingStats:input_type -> v2ray.core.app.router.command.SubscribeRoutingStatsRequest
2, // 4: v2ray.core.app.router.command.RoutingService.TestRoute:input_type -> v2ray.core.app.router.command.TestRouteRequest
0, // 5: v2ray.core.app.router.command.RoutingService.SubscribeRoutingStats:output_type -> v2ray.core.app.router.command.RoutingContext
0, // 6: v2ray.core.app.router.command.RoutingService.TestRoute:output_type -> v2ray.core.app.router.command.RoutingContext
5, // [5:7] is the sub-list for method output_type
3, // [3:5] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_app_router_command_command_proto_init() }
func file_app_router_command_command_proto_init() {
if File_app_router_command_command_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_router_command_command_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RoutingContext); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_router_command_command_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SubscribeRoutingStatsRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_router_command_command_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TestRouteRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_router_command_command_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_router_command_command_proto_rawDesc,
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_app_router_command_command_proto_goTypes,
DependencyIndexes: file_app_router_command_command_proto_depIdxs,
MessageInfos: file_app_router_command_command_proto_msgTypes,
}.Build()
File_app_router_command_command_proto = out.File
file_app_router_command_command_proto_rawDesc = nil
file_app_router_command_command_proto_goTypes = nil
file_app_router_command_command_proto_depIdxs = nil
}
v2ray-core-4.34.0/app/router/command/command.proto 0000664 0000000 0000000 00000004767 13774574720 0022052 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.app.router.command;
option csharp_namespace = "V2Ray.Core.App.Router.Command";
option go_package = "v2ray.com/core/app/router/command";
option java_package = "com.v2ray.core.app.router.command";
option java_multiple_files = true;
import "common/net/network.proto";
// RoutingContext is the context with information relative to routing process.
// It conforms to the structure of v2ray.core.features.routing.Context and
// v2ray.core.features.routing.Route.
message RoutingContext {
string InboundTag = 1;
v2ray.core.common.net.Network Network = 2;
repeated bytes SourceIPs = 3;
repeated bytes TargetIPs = 4;
uint32 SourcePort = 5;
uint32 TargetPort = 6;
string TargetDomain = 7;
string Protocol = 8;
string User = 9;
map Attributes = 10;
repeated string OutboundGroupTags = 11;
string OutboundTag = 12;
}
// SubscribeRoutingStatsRequest subscribes to routing statistics channel if
// opened by v2ray-core.
// * FieldSelectors selects a subset of fields in routing statistics to return.
// Valid selectors:
// - inbound: Selects connection's inbound tag.
// - network: Selects connection's network.
// - ip: Equivalent as "ip_source" and "ip_target", selects both source and
// target IP.
// - port: Equivalent as "port_source" and "port_target", selects both source
// and target port.
// - domain: Selects target domain.
// - protocol: Select connection's protocol.
// - user: Select connection's inbound user email.
// - attributes: Select connection's additional attributes.
// - outbound: Equivalent as "outbound" and "outbound_group", select both
// outbound tag and outbound group tags.
// * If FieldSelectors is left empty, all fields will be returned.
message SubscribeRoutingStatsRequest {
repeated string FieldSelectors = 1;
}
// TestRouteRequest manually tests a routing result according to the routing
// context message.
// * RoutingContext is the routing message without outbound information.
// * FieldSelectors selects the fields to return in the routing result. All
// fields are returned if left empty.
// * PublishResult broadcasts the routing result to routing statistics channel
// if set true.
message TestRouteRequest {
RoutingContext RoutingContext = 1;
repeated string FieldSelectors = 2;
bool PublishResult = 3;
}
service RoutingService {
rpc SubscribeRoutingStats(SubscribeRoutingStatsRequest)
returns (stream RoutingContext) {}
rpc TestRoute(TestRouteRequest) returns (RoutingContext) {}
}
message Config {}
v2ray-core-4.34.0/app/router/command/command_grpc.pb.go 0000664 0000000 0000000 00000013240 13774574720 0022711 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package command
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion7
// RoutingServiceClient is the client API for RoutingService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type RoutingServiceClient interface {
SubscribeRoutingStats(ctx context.Context, in *SubscribeRoutingStatsRequest, opts ...grpc.CallOption) (RoutingService_SubscribeRoutingStatsClient, error)
TestRoute(ctx context.Context, in *TestRouteRequest, opts ...grpc.CallOption) (*RoutingContext, error)
}
type routingServiceClient struct {
cc grpc.ClientConnInterface
}
func NewRoutingServiceClient(cc grpc.ClientConnInterface) RoutingServiceClient {
return &routingServiceClient{cc}
}
func (c *routingServiceClient) SubscribeRoutingStats(ctx context.Context, in *SubscribeRoutingStatsRequest, opts ...grpc.CallOption) (RoutingService_SubscribeRoutingStatsClient, error) {
stream, err := c.cc.NewStream(ctx, &_RoutingService_serviceDesc.Streams[0], "/v2ray.core.app.router.command.RoutingService/SubscribeRoutingStats", opts...)
if err != nil {
return nil, err
}
x := &routingServiceSubscribeRoutingStatsClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type RoutingService_SubscribeRoutingStatsClient interface {
Recv() (*RoutingContext, error)
grpc.ClientStream
}
type routingServiceSubscribeRoutingStatsClient struct {
grpc.ClientStream
}
func (x *routingServiceSubscribeRoutingStatsClient) Recv() (*RoutingContext, error) {
m := new(RoutingContext)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *routingServiceClient) TestRoute(ctx context.Context, in *TestRouteRequest, opts ...grpc.CallOption) (*RoutingContext, error) {
out := new(RoutingContext)
err := c.cc.Invoke(ctx, "/v2ray.core.app.router.command.RoutingService/TestRoute", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// RoutingServiceServer is the server API for RoutingService service.
// All implementations must embed UnimplementedRoutingServiceServer
// for forward compatibility
type RoutingServiceServer interface {
SubscribeRoutingStats(*SubscribeRoutingStatsRequest, RoutingService_SubscribeRoutingStatsServer) error
TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error)
mustEmbedUnimplementedRoutingServiceServer()
}
// UnimplementedRoutingServiceServer must be embedded to have forward compatible implementations.
type UnimplementedRoutingServiceServer struct {
}
func (UnimplementedRoutingServiceServer) SubscribeRoutingStats(*SubscribeRoutingStatsRequest, RoutingService_SubscribeRoutingStatsServer) error {
return status.Errorf(codes.Unimplemented, "method SubscribeRoutingStats not implemented")
}
func (UnimplementedRoutingServiceServer) TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error) {
return nil, status.Errorf(codes.Unimplemented, "method TestRoute not implemented")
}
func (UnimplementedRoutingServiceServer) mustEmbedUnimplementedRoutingServiceServer() {}
// UnsafeRoutingServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to RoutingServiceServer will
// result in compilation errors.
type UnsafeRoutingServiceServer interface {
mustEmbedUnimplementedRoutingServiceServer()
}
func RegisterRoutingServiceServer(s grpc.ServiceRegistrar, srv RoutingServiceServer) {
s.RegisterService(&_RoutingService_serviceDesc, srv)
}
func _RoutingService_SubscribeRoutingStats_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(SubscribeRoutingStatsRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(RoutingServiceServer).SubscribeRoutingStats(m, &routingServiceSubscribeRoutingStatsServer{stream})
}
type RoutingService_SubscribeRoutingStatsServer interface {
Send(*RoutingContext) error
grpc.ServerStream
}
type routingServiceSubscribeRoutingStatsServer struct {
grpc.ServerStream
}
func (x *routingServiceSubscribeRoutingStatsServer) Send(m *RoutingContext) error {
return x.ServerStream.SendMsg(m)
}
func _RoutingService_TestRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(TestRouteRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RoutingServiceServer).TestRoute(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.router.command.RoutingService/TestRoute",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RoutingServiceServer).TestRoute(ctx, req.(*TestRouteRequest))
}
return interceptor(ctx, in, info, handler)
}
var _RoutingService_serviceDesc = grpc.ServiceDesc{
ServiceName: "v2ray.core.app.router.command.RoutingService",
HandlerType: (*RoutingServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "TestRoute",
Handler: _RoutingService_TestRoute_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "SubscribeRoutingStats",
Handler: _RoutingService_SubscribeRoutingStats_Handler,
ServerStreams: true,
},
},
Metadata: "app/router/command/command.proto",
}
v2ray-core-4.34.0/app/router/command/command_test.go 0000664 0000000 0000000 00000023676 13774574720 0022353 0 ustar 00root root 0000000 0000000 package command_test
import (
"context"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"google.golang.org/grpc"
"google.golang.org/grpc/test/bufconn"
"v2ray.com/core/app/router"
. "v2ray.com/core/app/router/command"
"v2ray.com/core/app/stats"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/features/routing"
"v2ray.com/core/testing/mocks"
)
func TestServiceSubscribeRoutingStats(t *testing.T) {
c := stats.NewChannel(&stats.ChannelConfig{
SubscriberLimit: 1,
BufferSize: 0,
Blocking: true,
})
common.Must(c.Start())
defer c.Close()
lis := bufconn.Listen(1024 * 1024)
bufDialer := func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}
testCases := []*RoutingContext{
{InboundTag: "in", OutboundTag: "out"},
{TargetIPs: [][]byte{{1, 2, 3, 4}}, TargetPort: 8080, OutboundTag: "out"},
{TargetDomain: "example.com", TargetPort: 443, OutboundTag: "out"},
{SourcePort: 9999, TargetPort: 9999, OutboundTag: "out"},
{Network: net.Network_UDP, OutboundGroupTags: []string{"outergroup", "innergroup"}, OutboundTag: "out"},
{Protocol: "bittorrent", OutboundTag: "blocked"},
{User: "example@v2fly.org", OutboundTag: "out"},
{SourceIPs: [][]byte{{127, 0, 0, 1}}, Attributes: map[string]string{"attr": "value"}, OutboundTag: "out"},
}
errCh := make(chan error)
nextPub := make(chan struct{})
// Server goroutine
go func() {
server := grpc.NewServer()
RegisterRoutingServiceServer(server, NewRoutingServer(nil, c))
errCh <- server.Serve(lis)
}()
// Publisher goroutine
go func() {
publishTestCases := func() error {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
for { // Wait until there's one subscriber in routing stats channel
if len(c.Subscribers()) > 0 {
break
}
if ctx.Err() != nil {
return ctx.Err()
}
}
for _, tc := range testCases {
c.Publish(context.Background(), AsRoutingRoute(tc))
time.Sleep(time.Millisecond)
}
return nil
}
if err := publishTestCases(); err != nil {
errCh <- err
}
// Wait for next round of publishing
<-nextPub
if err := publishTestCases(); err != nil {
errCh <- err
}
}()
// Client goroutine
go func() {
defer lis.Close()
conn, err := grpc.DialContext(context.Background(), "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
if err != nil {
errCh <- err
return
}
defer conn.Close()
client := NewRoutingServiceClient(conn)
// Test retrieving all fields
testRetrievingAllFields := func() error {
streamCtx, streamClose := context.WithCancel(context.Background())
// Test the unsubscription of stream works well
defer func() {
streamClose()
timeOutCtx, timeout := context.WithTimeout(context.Background(), time.Second)
defer timeout()
for { // Wait until there's no subscriber in routing stats channel
if len(c.Subscribers()) == 0 {
break
}
if timeOutCtx.Err() != nil {
t.Error("unexpected subscribers not decreased in channel", timeOutCtx.Err())
}
}
}()
stream, err := client.SubscribeRoutingStats(streamCtx, &SubscribeRoutingStatsRequest{})
if err != nil {
return err
}
for _, tc := range testCases {
msg, err := stream.Recv()
if err != nil {
return err
}
if r := cmp.Diff(msg, tc, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
}
}
// Test that double subscription will fail
errStream, err := client.SubscribeRoutingStats(context.Background(), &SubscribeRoutingStatsRequest{
FieldSelectors: []string{"ip", "port", "domain", "outbound"},
})
if err != nil {
return err
}
if _, err := errStream.Recv(); err == nil {
t.Error("unexpected successful subscription")
}
return nil
}
// Test retrieving only a subset of fields
testRetrievingSubsetOfFields := func() error {
streamCtx, streamClose := context.WithCancel(context.Background())
defer streamClose()
stream, err := client.SubscribeRoutingStats(streamCtx, &SubscribeRoutingStatsRequest{
FieldSelectors: []string{"ip", "port", "domain", "outbound"},
})
if err != nil {
return err
}
// Send nextPub signal to start next round of publishing
close(nextPub)
for _, tc := range testCases {
msg, err := stream.Recv()
if err != nil {
return err
}
stat := &RoutingContext{ // Only a subset of stats is retrieved
SourceIPs: tc.SourceIPs,
TargetIPs: tc.TargetIPs,
SourcePort: tc.SourcePort,
TargetPort: tc.TargetPort,
TargetDomain: tc.TargetDomain,
OutboundGroupTags: tc.OutboundGroupTags,
OutboundTag: tc.OutboundTag,
}
if r := cmp.Diff(msg, stat, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
}
}
return nil
}
if err := testRetrievingAllFields(); err != nil {
errCh <- err
}
if err := testRetrievingSubsetOfFields(); err != nil {
errCh <- err
}
errCh <- nil // Client passed all tests successfully
}()
// Wait for goroutines to complete
select {
case <-time.After(2 * time.Second):
t.Fatal("Test timeout after 2s")
case err := <-errCh:
if err != nil {
t.Fatal(err)
}
}
}
func TestSerivceTestRoute(t *testing.T) {
c := stats.NewChannel(&stats.ChannelConfig{
SubscriberLimit: 1,
BufferSize: 16,
Blocking: true,
})
common.Must(c.Start())
defer c.Close()
r := new(router.Router)
mockCtl := gomock.NewController(t)
defer mockCtl.Finish()
common.Must(r.Init(&router.Config{
Rule: []*router.RoutingRule{
{
InboundTag: []string{"in"},
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
},
{
Protocol: []string{"bittorrent"},
TargetTag: &router.RoutingRule_Tag{Tag: "blocked"},
},
{
PortList: &net.PortList{Range: []*net.PortRange{{From: 8080, To: 8080}}},
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
},
{
SourcePortList: &net.PortList{Range: []*net.PortRange{{From: 9999, To: 9999}}},
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
},
{
Domain: []*router.Domain{{Type: router.Domain_Domain, Value: "com"}},
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
},
{
SourceGeoip: []*router.GeoIP{{CountryCode: "private", Cidr: []*router.CIDR{{Ip: []byte{127, 0, 0, 0}, Prefix: 8}}}},
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
},
{
UserEmail: []string{"example@v2fly.org"},
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
},
{
Networks: []net.Network{net.Network_UDP, net.Network_TCP},
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
},
},
}, mocks.NewDNSClient(mockCtl), mocks.NewOutboundManager(mockCtl)))
lis := bufconn.Listen(1024 * 1024)
bufDialer := func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}
errCh := make(chan error)
// Server goroutine
go func() {
server := grpc.NewServer()
RegisterRoutingServiceServer(server, NewRoutingServer(r, c))
errCh <- server.Serve(lis)
}()
// Client goroutine
go func() {
defer lis.Close()
conn, err := grpc.DialContext(context.Background(), "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
if err != nil {
errCh <- err
}
defer conn.Close()
client := NewRoutingServiceClient(conn)
testCases := []*RoutingContext{
{InboundTag: "in", OutboundTag: "out"},
{TargetIPs: [][]byte{{1, 2, 3, 4}}, TargetPort: 8080, OutboundTag: "out"},
{TargetDomain: "example.com", TargetPort: 443, OutboundTag: "out"},
{SourcePort: 9999, TargetPort: 9999, OutboundTag: "out"},
{Network: net.Network_UDP, Protocol: "bittorrent", OutboundTag: "blocked"},
{User: "example@v2fly.org", OutboundTag: "out"},
{SourceIPs: [][]byte{{127, 0, 0, 1}}, Attributes: map[string]string{"attr": "value"}, OutboundTag: "out"},
}
// Test simple TestRoute
testSimple := func() error {
for _, tc := range testCases {
route, err := client.TestRoute(context.Background(), &TestRouteRequest{RoutingContext: tc})
if err != nil {
return err
}
if r := cmp.Diff(route, tc, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
}
}
return nil
}
// Test TestRoute with special options
testOptions := func() error {
sub, err := c.Subscribe()
if err != nil {
return err
}
for _, tc := range testCases {
route, err := client.TestRoute(context.Background(), &TestRouteRequest{
RoutingContext: tc,
FieldSelectors: []string{"ip", "port", "domain", "outbound"},
PublishResult: true,
})
if err != nil {
return err
}
stat := &RoutingContext{ // Only a subset of stats is retrieved
SourceIPs: tc.SourceIPs,
TargetIPs: tc.TargetIPs,
SourcePort: tc.SourcePort,
TargetPort: tc.TargetPort,
TargetDomain: tc.TargetDomain,
OutboundGroupTags: tc.OutboundGroupTags,
OutboundTag: tc.OutboundTag,
}
if r := cmp.Diff(route, stat, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
}
select { // Check that routing result has been published to statistics channel
case msg, received := <-sub:
if route, ok := msg.(routing.Route); received && ok {
if r := cmp.Diff(AsProtobufMessage(nil)(route), tc, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
}
} else {
t.Error("unexpected failure in receiving published routing result for testcase", tc)
}
case <-time.After(100 * time.Millisecond):
t.Error("unexpected failure in receiving published routing result", tc)
}
}
return nil
}
if err := testSimple(); err != nil {
errCh <- err
}
if err := testOptions(); err != nil {
errCh <- err
}
errCh <- nil // Client passed all tests successfully
}()
// Wait for goroutines to complete
select {
case <-time.After(2 * time.Second):
t.Fatal("Test timeout after 2s")
case err := <-errCh:
if err != nil {
t.Fatal(err)
}
}
}
v2ray-core-4.34.0/app/router/command/config.go 0000664 0000000 0000000 00000007116 13774574720 0021132 0 ustar 00root root 0000000 0000000 package command
import (
"strings"
"v2ray.com/core/common/net"
"v2ray.com/core/features/routing"
)
// routingContext is an wrapper of protobuf RoutingContext as implementation of routing.Context and routing.Route.
type routingContext struct {
*RoutingContext
}
func (c routingContext) GetSourceIPs() []net.IP {
return mapBytesToIPs(c.RoutingContext.GetSourceIPs())
}
func (c routingContext) GetSourcePort() net.Port {
return net.Port(c.RoutingContext.GetSourcePort())
}
func (c routingContext) GetTargetIPs() []net.IP {
return mapBytesToIPs(c.RoutingContext.GetTargetIPs())
}
func (c routingContext) GetTargetPort() net.Port {
return net.Port(c.RoutingContext.GetTargetPort())
}
// GetSkipDNSResolve is a mock implementation here to match the interface,
// SkipDNSResolve is set from dns module, no use if coming from a protobuf object?
// TODO: please confirm @Vigilans
func (c routingContext) GetSkipDNSResolve() bool {
return false
}
// AsRoutingContext converts a protobuf RoutingContext into an implementation of routing.Context.
func AsRoutingContext(r *RoutingContext) routing.Context {
return routingContext{r}
}
// AsRoutingRoute converts a protobuf RoutingContext into an implementation of routing.Route.
func AsRoutingRoute(r *RoutingContext) routing.Route {
return routingContext{r}
}
var fieldMap = map[string]func(*RoutingContext, routing.Route){
"inbound": func(s *RoutingContext, r routing.Route) { s.InboundTag = r.GetInboundTag() },
"network": func(s *RoutingContext, r routing.Route) { s.Network = r.GetNetwork() },
"ip_source": func(s *RoutingContext, r routing.Route) { s.SourceIPs = mapIPsToBytes(r.GetSourceIPs()) },
"ip_target": func(s *RoutingContext, r routing.Route) { s.TargetIPs = mapIPsToBytes(r.GetTargetIPs()) },
"port_source": func(s *RoutingContext, r routing.Route) { s.SourcePort = uint32(r.GetSourcePort()) },
"port_target": func(s *RoutingContext, r routing.Route) { s.TargetPort = uint32(r.GetTargetPort()) },
"domain": func(s *RoutingContext, r routing.Route) { s.TargetDomain = r.GetTargetDomain() },
"protocol": func(s *RoutingContext, r routing.Route) { s.Protocol = r.GetProtocol() },
"user": func(s *RoutingContext, r routing.Route) { s.User = r.GetUser() },
"attributes": func(s *RoutingContext, r routing.Route) { s.Attributes = r.GetAttributes() },
"outbound_group": func(s *RoutingContext, r routing.Route) { s.OutboundGroupTags = r.GetOutboundGroupTags() },
"outbound": func(s *RoutingContext, r routing.Route) { s.OutboundTag = r.GetOutboundTag() },
}
// AsProtobufMessage takes selectors of fields and returns a function to convert routing.Route to protobuf RoutingContext.
func AsProtobufMessage(fieldSelectors []string) func(routing.Route) *RoutingContext {
initializers := []func(*RoutingContext, routing.Route){}
for field, init := range fieldMap {
if len(fieldSelectors) == 0 { // If selectors not set, retrieve all fields
initializers = append(initializers, init)
continue
}
for _, selector := range fieldSelectors {
if strings.HasPrefix(field, selector) {
initializers = append(initializers, init)
break
}
}
}
return func(ctx routing.Route) *RoutingContext {
message := new(RoutingContext)
for _, init := range initializers {
init(message, ctx)
}
return message
}
}
func mapBytesToIPs(bytes [][]byte) []net.IP {
var ips []net.IP
for _, rawIP := range bytes {
ips = append(ips, net.IP(rawIP))
}
return ips
}
func mapIPsToBytes(ips []net.IP) [][]byte {
var bytes [][]byte
for _, ip := range ips {
bytes = append(bytes, []byte(ip))
}
return bytes
}
v2ray-core-4.34.0/app/router/command/errors.generated.go 0000664 0000000 0000000 00000000315 13774574720 0023130 0 ustar 00root root 0000000 0000000 package command
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/app/router/condition.go 0000664 0000000 0000000 00000014520 13774574720 0020232 0 ustar 00root root 0000000 0000000 // +build !confonly
package router
import (
"strings"
"go.starlark.net/starlark"
"go.starlark.net/syntax"
"v2ray.com/core/common/net"
"v2ray.com/core/common/strmatcher"
"v2ray.com/core/features/routing"
)
type Condition interface {
Apply(ctx routing.Context) bool
}
type ConditionChan []Condition
func NewConditionChan() *ConditionChan {
var condChan ConditionChan = make([]Condition, 0, 8)
return &condChan
}
func (v *ConditionChan) Add(cond Condition) *ConditionChan {
*v = append(*v, cond)
return v
}
// Apply applies all conditions registered in this chan.
func (v *ConditionChan) Apply(ctx routing.Context) bool {
for _, cond := range *v {
if !cond.Apply(ctx) {
return false
}
}
return true
}
func (v *ConditionChan) Len() int {
return len(*v)
}
var matcherTypeMap = map[Domain_Type]strmatcher.Type{
Domain_Plain: strmatcher.Substr,
Domain_Regex: strmatcher.Regex,
Domain_Domain: strmatcher.Domain,
Domain_Full: strmatcher.Full,
}
func domainToMatcher(domain *Domain) (strmatcher.Matcher, error) {
matcherType, f := matcherTypeMap[domain.Type]
if !f {
return nil, newError("unsupported domain type", domain.Type)
}
matcher, err := matcherType.New(domain.Value)
if err != nil {
return nil, newError("failed to create domain matcher").Base(err)
}
return matcher, nil
}
type DomainMatcher struct {
matchers strmatcher.IndexMatcher
}
func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
g := new(strmatcher.MatcherGroup)
for _, d := range domains {
m, err := domainToMatcher(d)
if err != nil {
return nil, err
}
g.Add(m)
}
return &DomainMatcher{
matchers: g,
}, nil
}
func (m *DomainMatcher) ApplyDomain(domain string) bool {
return len(m.matchers.Match(domain)) > 0
}
// Apply implements Condition.
func (m *DomainMatcher) Apply(ctx routing.Context) bool {
domain := ctx.GetTargetDomain()
if len(domain) == 0 {
return false
}
return m.ApplyDomain(domain)
}
type MultiGeoIPMatcher struct {
matchers []*GeoIPMatcher
onSource bool
}
func NewMultiGeoIPMatcher(geoips []*GeoIP, onSource bool) (*MultiGeoIPMatcher, error) {
var matchers []*GeoIPMatcher
for _, geoip := range geoips {
matcher, err := globalGeoIPContainer.Add(geoip)
if err != nil {
return nil, err
}
matchers = append(matchers, matcher)
}
matcher := &MultiGeoIPMatcher{
matchers: matchers,
onSource: onSource,
}
return matcher, nil
}
// Apply implements Condition.
func (m *MultiGeoIPMatcher) Apply(ctx routing.Context) bool {
var ips []net.IP
if m.onSource {
ips = ctx.GetSourceIPs()
} else {
ips = ctx.GetTargetIPs()
}
for _, ip := range ips {
for _, matcher := range m.matchers {
if matcher.Match(ip) {
return true
}
}
}
return false
}
type PortMatcher struct {
port net.MemoryPortList
onSource bool
}
// NewPortMatcher create a new port matcher that can match source or destination port
func NewPortMatcher(list *net.PortList, onSource bool) *PortMatcher {
return &PortMatcher{
port: net.PortListFromProto(list),
onSource: onSource,
}
}
// Apply implements Condition.
func (v *PortMatcher) Apply(ctx routing.Context) bool {
if v.onSource {
return v.port.Contains(ctx.GetSourcePort())
}
return v.port.Contains(ctx.GetTargetPort())
}
type NetworkMatcher struct {
list [8]bool
}
func NewNetworkMatcher(network []net.Network) NetworkMatcher {
var matcher NetworkMatcher
for _, n := range network {
matcher.list[int(n)] = true
}
return matcher
}
// Apply implements Condition.
func (v NetworkMatcher) Apply(ctx routing.Context) bool {
return v.list[int(ctx.GetNetwork())]
}
type UserMatcher struct {
user []string
}
func NewUserMatcher(users []string) *UserMatcher {
usersCopy := make([]string, 0, len(users))
for _, user := range users {
if len(user) > 0 {
usersCopy = append(usersCopy, user)
}
}
return &UserMatcher{
user: usersCopy,
}
}
// Apply implements Condition.
func (v *UserMatcher) Apply(ctx routing.Context) bool {
user := ctx.GetUser()
if len(user) == 0 {
return false
}
for _, u := range v.user {
if u == user {
return true
}
}
return false
}
type InboundTagMatcher struct {
tags []string
}
func NewInboundTagMatcher(tags []string) *InboundTagMatcher {
tagsCopy := make([]string, 0, len(tags))
for _, tag := range tags {
if len(tag) > 0 {
tagsCopy = append(tagsCopy, tag)
}
}
return &InboundTagMatcher{
tags: tagsCopy,
}
}
// Apply implements Condition.
func (v *InboundTagMatcher) Apply(ctx routing.Context) bool {
tag := ctx.GetInboundTag()
if len(tag) == 0 {
return false
}
for _, t := range v.tags {
if t == tag {
return true
}
}
return false
}
type ProtocolMatcher struct {
protocols []string
}
func NewProtocolMatcher(protocols []string) *ProtocolMatcher {
pCopy := make([]string, 0, len(protocols))
for _, p := range protocols {
if len(p) > 0 {
pCopy = append(pCopy, p)
}
}
return &ProtocolMatcher{
protocols: pCopy,
}
}
// Apply implements Condition.
func (m *ProtocolMatcher) Apply(ctx routing.Context) bool {
protocol := ctx.GetProtocol()
if len(protocol) == 0 {
return false
}
for _, p := range m.protocols {
if strings.HasPrefix(protocol, p) {
return true
}
}
return false
}
type AttributeMatcher struct {
program *starlark.Program
}
func NewAttributeMatcher(code string) (*AttributeMatcher, error) {
starFile, err := syntax.Parse("attr.star", "satisfied=("+code+")", 0)
if err != nil {
return nil, newError("attr rule").Base(err)
}
p, err := starlark.FileProgram(starFile, func(name string) bool {
return name == "attrs"
})
if err != nil {
return nil, err
}
return &AttributeMatcher{
program: p,
}, nil
}
// Match implements attributes matching.
func (m *AttributeMatcher) Match(attrs map[string]string) bool {
attrsDict := new(starlark.Dict)
for key, value := range attrs {
attrsDict.SetKey(starlark.String(key), starlark.String(value))
}
predefined := make(starlark.StringDict)
predefined["attrs"] = attrsDict
thread := &starlark.Thread{
Name: "matcher",
}
results, err := m.program.Init(thread, predefined)
if err != nil {
newError("attr matcher").Base(err).WriteToLog()
}
satisfied := results["satisfied"]
return satisfied != nil && bool(satisfied.Truth())
}
// Apply implements Condition.
func (m *AttributeMatcher) Apply(ctx routing.Context) bool {
attributes := ctx.GetAttributes()
if attributes == nil {
return false
}
return m.Match(attributes)
}
v2ray-core-4.34.0/app/router/condition_geoip.go 0000664 0000000 0000000 00000007057 13774574720 0021424 0 ustar 00root root 0000000 0000000 // +build !confonly
package router
import (
"encoding/binary"
"sort"
"v2ray.com/core/common/net"
)
type ipv6 struct {
a uint64
b uint64
}
type GeoIPMatcher struct {
countryCode string
ip4 []uint32
prefix4 []uint8
ip6 []ipv6
prefix6 []uint8
}
func normalize4(ip uint32, prefix uint8) uint32 {
return (ip >> (32 - prefix)) << (32 - prefix)
}
func normalize6(ip ipv6, prefix uint8) ipv6 {
if prefix <= 64 {
ip.a = (ip.a >> (64 - prefix)) << (64 - prefix)
ip.b = 0
} else {
ip.b = (ip.b >> (128 - prefix)) << (128 - prefix)
}
return ip
}
func (m *GeoIPMatcher) Init(cidrs []*CIDR) error {
ip4Count := 0
ip6Count := 0
for _, cidr := range cidrs {
ip := cidr.Ip
switch len(ip) {
case 4:
ip4Count++
case 16:
ip6Count++
default:
return newError("unexpect ip length: ", len(ip))
}
}
cidrList := CIDRList(cidrs)
sort.Sort(&cidrList)
m.ip4 = make([]uint32, 0, ip4Count)
m.prefix4 = make([]uint8, 0, ip4Count)
m.ip6 = make([]ipv6, 0, ip6Count)
m.prefix6 = make([]uint8, 0, ip6Count)
for _, cidr := range cidrs {
ip := cidr.Ip
prefix := uint8(cidr.Prefix)
switch len(ip) {
case 4:
m.ip4 = append(m.ip4, normalize4(binary.BigEndian.Uint32(ip), prefix))
m.prefix4 = append(m.prefix4, prefix)
case 16:
ip6 := ipv6{
a: binary.BigEndian.Uint64(ip[0:8]),
b: binary.BigEndian.Uint64(ip[8:16]),
}
ip6 = normalize6(ip6, prefix)
m.ip6 = append(m.ip6, ip6)
m.prefix6 = append(m.prefix6, prefix)
}
}
return nil
}
func (m *GeoIPMatcher) match4(ip uint32) bool {
if len(m.ip4) == 0 {
return false
}
if ip < m.ip4[0] {
return false
}
size := uint32(len(m.ip4))
l := uint32(0)
r := size
for l < r {
x := ((l + r) >> 1)
if ip < m.ip4[x] {
r = x
continue
}
nip := normalize4(ip, m.prefix4[x])
if nip == m.ip4[x] {
return true
}
l = x + 1
}
return l > 0 && normalize4(ip, m.prefix4[l-1]) == m.ip4[l-1]
}
func less6(a ipv6, b ipv6) bool {
return a.a < b.a || (a.a == b.a && a.b < b.b)
}
func (m *GeoIPMatcher) match6(ip ipv6) bool {
if len(m.ip6) == 0 {
return false
}
if less6(ip, m.ip6[0]) {
return false
}
size := uint32(len(m.ip6))
l := uint32(0)
r := size
for l < r {
x := (l + r) / 2
if less6(ip, m.ip6[x]) {
r = x
continue
}
if normalize6(ip, m.prefix6[x]) == m.ip6[x] {
return true
}
l = x + 1
}
return l > 0 && normalize6(ip, m.prefix6[l-1]) == m.ip6[l-1]
}
// Match returns true if the given ip is included by the GeoIP.
func (m *GeoIPMatcher) Match(ip net.IP) bool {
switch len(ip) {
case 4:
return m.match4(binary.BigEndian.Uint32(ip))
case 16:
return m.match6(ipv6{
a: binary.BigEndian.Uint64(ip[0:8]),
b: binary.BigEndian.Uint64(ip[8:16]),
})
default:
return false
}
}
// GeoIPMatcherContainer is a container for GeoIPMatchers. It keeps unique copies of GeoIPMatcher by country code.
type GeoIPMatcherContainer struct {
matchers []*GeoIPMatcher
}
// Add adds a new GeoIP set into the container.
// If the country code of GeoIP is not empty, GeoIPMatcherContainer will try to find an existing one, instead of adding a new one.
func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
if len(geoip.CountryCode) > 0 {
for _, m := range c.matchers {
if m.countryCode == geoip.CountryCode {
return m, nil
}
}
}
m := &GeoIPMatcher{
countryCode: geoip.CountryCode,
}
if err := m.Init(geoip.Cidr); err != nil {
return nil, err
}
if len(geoip.CountryCode) > 0 {
c.matchers = append(c.matchers, m)
}
return m, nil
}
var (
globalGeoIPContainer GeoIPMatcherContainer
)
v2ray-core-4.34.0/app/router/condition_geoip_test.go 0000664 0000000 0000000 00000010443 13774574720 0022454 0 ustar 00root root 0000000 0000000 package router_test
import (
"os"
"path/filepath"
"testing"
"github.com/golang/protobuf/proto"
"v2ray.com/core/app/router"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/common/platform"
"v2ray.com/core/common/platform/filesystem"
)
func init() {
wd, err := os.Getwd()
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")))
}
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")))
}
}
func TestGeoIPMatcherContainer(t *testing.T) {
container := &router.GeoIPMatcherContainer{}
m1, err := container.Add(&router.GeoIP{
CountryCode: "CN",
})
common.Must(err)
m2, err := container.Add(&router.GeoIP{
CountryCode: "US",
})
common.Must(err)
m3, err := container.Add(&router.GeoIP{
CountryCode: "CN",
})
common.Must(err)
if m1 != m3 {
t.Error("expect same matcher for same geoip, but not")
}
if m1 == m2 {
t.Error("expect different matcher for different geoip, but actually same")
}
}
func TestGeoIPMatcher(t *testing.T) {
cidrList := router.CIDRList{
{Ip: []byte{0, 0, 0, 0}, Prefix: 8},
{Ip: []byte{10, 0, 0, 0}, Prefix: 8},
{Ip: []byte{100, 64, 0, 0}, Prefix: 10},
{Ip: []byte{127, 0, 0, 0}, Prefix: 8},
{Ip: []byte{169, 254, 0, 0}, Prefix: 16},
{Ip: []byte{172, 16, 0, 0}, Prefix: 12},
{Ip: []byte{192, 0, 0, 0}, Prefix: 24},
{Ip: []byte{192, 0, 2, 0}, Prefix: 24},
{Ip: []byte{192, 168, 0, 0}, Prefix: 16},
{Ip: []byte{192, 18, 0, 0}, Prefix: 15},
{Ip: []byte{198, 51, 100, 0}, Prefix: 24},
{Ip: []byte{203, 0, 113, 0}, Prefix: 24},
{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
{Ip: []byte{91, 108, 4, 0}, Prefix: 16},
}
matcher := &router.GeoIPMatcher{}
common.Must(matcher.Init(cidrList))
testCases := []struct {
Input string
Output bool
}{
{
Input: "192.168.1.1",
Output: true,
},
{
Input: "192.0.0.0",
Output: true,
},
{
Input: "192.0.1.0",
Output: false,
}, {
Input: "0.1.0.0",
Output: true,
},
{
Input: "1.0.0.1",
Output: false,
},
{
Input: "8.8.8.7",
Output: false,
},
{
Input: "8.8.8.8",
Output: true,
},
{
Input: "2001:cdba::3257:9652",
Output: false,
},
{
Input: "91.108.255.254",
Output: true,
},
}
for _, testCase := range testCases {
ip := net.ParseAddress(testCase.Input).IP()
actual := matcher.Match(ip)
if actual != testCase.Output {
t.Error("expect input", testCase.Input, "to be", testCase.Output, ", but actually", actual)
}
}
}
func TestGeoIPMatcher4CN(t *testing.T) {
ips, err := loadGeoIP("CN")
common.Must(err)
matcher := &router.GeoIPMatcher{}
common.Must(matcher.Init(ips))
if matcher.Match([]byte{8, 8, 8, 8}) {
t.Error("expect CN geoip doesn't contain 8.8.8.8, but actually does")
}
}
func TestGeoIPMatcher6US(t *testing.T) {
ips, err := loadGeoIP("US")
common.Must(err)
matcher := &router.GeoIPMatcher{}
common.Must(matcher.Init(ips))
if !matcher.Match(net.ParseAddress("2001:4860:4860::8888").IP()) {
t.Error("expect US geoip contain 2001:4860:4860::8888, but actually not")
}
}
func loadGeoIP(country string) ([]*router.CIDR, error) {
geoipBytes, err := filesystem.ReadAsset("geoip.dat")
if err != nil {
return nil, err
}
var geoipList router.GeoIPList
if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil {
return nil, err
}
for _, geoip := range geoipList.Entry {
if geoip.CountryCode == country {
return geoip.Cidr, nil
}
}
panic("country not found: " + country)
}
func BenchmarkGeoIPMatcher4CN(b *testing.B) {
ips, err := loadGeoIP("CN")
common.Must(err)
matcher := &router.GeoIPMatcher{}
common.Must(matcher.Init(ips))
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = matcher.Match([]byte{8, 8, 8, 8})
}
}
func BenchmarkGeoIPMatcher6US(b *testing.B) {
ips, err := loadGeoIP("US")
common.Must(err)
matcher := &router.GeoIPMatcher{}
common.Must(matcher.Init(ips))
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = matcher.Match(net.ParseAddress("2001:4860:4860::8888").IP())
}
}
v2ray-core-4.34.0/app/router/condition_test.go 0000664 0000000 0000000 00000023752 13774574720 0021300 0 ustar 00root root 0000000 0000000 package router_test
import (
"os"
"path/filepath"
"strconv"
"testing"
"github.com/golang/protobuf/proto"
. "v2ray.com/core/app/router"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/net"
"v2ray.com/core/common/platform"
"v2ray.com/core/common/platform/filesystem"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/protocol/http"
"v2ray.com/core/common/session"
"v2ray.com/core/features/routing"
routing_session "v2ray.com/core/features/routing/session"
)
func init() {
wd, err := os.Getwd()
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")))
}
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")))
}
}
func withBackground() routing.Context {
return &routing_session.Context{}
}
func withOutbound(outbound *session.Outbound) routing.Context {
return &routing_session.Context{Outbound: outbound}
}
func withInbound(inbound *session.Inbound) routing.Context {
return &routing_session.Context{Inbound: inbound}
}
func withContent(content *session.Content) routing.Context {
return &routing_session.Context{Content: content}
}
func TestRoutingRule(t *testing.T) {
type ruleTest struct {
input routing.Context
output bool
}
cases := []struct {
rule *RoutingRule
test []ruleTest
}{
{
rule: &RoutingRule{
Domain: []*Domain{
{
Value: "v2ray.com",
Type: Domain_Plain,
},
{
Value: "google.com",
Type: Domain_Domain,
},
{
Value: "^facebook\\.com$",
Type: Domain_Regex,
},
},
},
test: []ruleTest{
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.com"), 80)}),
output: true,
},
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("www.v2ray.com.www"), 80)}),
output: true,
},
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.co"), 80)}),
output: false,
},
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("www.google.com"), 80)}),
output: true,
},
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("facebook.com"), 80)}),
output: true,
},
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("www.facebook.com"), 80)}),
output: false,
},
{
input: withBackground(),
output: false,
},
},
},
{
rule: &RoutingRule{
Cidr: []*CIDR{
{
Ip: []byte{8, 8, 8, 8},
Prefix: 32,
},
{
Ip: []byte{8, 8, 8, 8},
Prefix: 32,
},
{
Ip: net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334").IP(),
Prefix: 128,
},
},
},
test: []ruleTest{
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)}),
output: true,
},
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.4.4"), 80)}),
output: false,
},
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334"), 80)}),
output: true,
},
{
input: withBackground(),
output: false,
},
},
},
{
rule: &RoutingRule{
Geoip: []*GeoIP{
{
Cidr: []*CIDR{
{
Ip: []byte{8, 8, 8, 8},
Prefix: 32,
},
{
Ip: []byte{8, 8, 8, 8},
Prefix: 32,
},
{
Ip: net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334").IP(),
Prefix: 128,
},
},
},
},
},
test: []ruleTest{
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)}),
output: true,
},
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.4.4"), 80)}),
output: false,
},
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334"), 80)}),
output: true,
},
{
input: withBackground(),
output: false,
},
},
},
{
rule: &RoutingRule{
SourceCidr: []*CIDR{
{
Ip: []byte{192, 168, 0, 0},
Prefix: 16,
},
},
},
test: []ruleTest{
{
input: withInbound(&session.Inbound{Source: net.TCPDestination(net.ParseAddress("192.168.0.1"), 80)}),
output: true,
},
{
input: withInbound(&session.Inbound{Source: net.TCPDestination(net.ParseAddress("10.0.0.1"), 80)}),
output: false,
},
},
},
{
rule: &RoutingRule{
UserEmail: []string{
"admin@v2ray.com",
},
},
test: []ruleTest{
{
input: withInbound(&session.Inbound{User: &protocol.MemoryUser{Email: "admin@v2ray.com"}}),
output: true,
},
{
input: withInbound(&session.Inbound{User: &protocol.MemoryUser{Email: "love@v2ray.com"}}),
output: false,
},
{
input: withBackground(),
output: false,
},
},
},
{
rule: &RoutingRule{
Protocol: []string{"http"},
},
test: []ruleTest{
{
input: withContent(&session.Content{Protocol: (&http.SniffHeader{}).Protocol()}),
output: true,
},
},
},
{
rule: &RoutingRule{
InboundTag: []string{"test", "test1"},
},
test: []ruleTest{
{
input: withInbound(&session.Inbound{Tag: "test"}),
output: true,
},
{
input: withInbound(&session.Inbound{Tag: "test2"}),
output: false,
},
},
},
{
rule: &RoutingRule{
PortList: &net.PortList{
Range: []*net.PortRange{
{From: 443, To: 443},
{From: 1000, To: 1100},
},
},
},
test: []ruleTest{
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 443)}),
output: true,
},
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 1100)}),
output: true,
},
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 1005)}),
output: true,
},
{
input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 53)}),
output: false,
},
},
},
{
rule: &RoutingRule{
SourcePortList: &net.PortList{
Range: []*net.PortRange{
{From: 123, To: 123},
{From: 9993, To: 9999},
},
},
},
test: []ruleTest{
{
input: withInbound(&session.Inbound{Source: net.UDPDestination(net.LocalHostIP, 123)}),
output: true,
},
{
input: withInbound(&session.Inbound{Source: net.UDPDestination(net.LocalHostIP, 9999)}),
output: true,
},
{
input: withInbound(&session.Inbound{Source: net.UDPDestination(net.LocalHostIP, 9994)}),
output: true,
},
{
input: withInbound(&session.Inbound{Source: net.UDPDestination(net.LocalHostIP, 53)}),
output: false,
},
},
},
{
rule: &RoutingRule{
Protocol: []string{"http"},
Attributes: "attrs[':path'].startswith('/test')",
},
test: []ruleTest{
{
input: withContent(&session.Content{Protocol: "http/1.1", Attributes: map[string]string{":path": "/test/1"}}),
output: true,
},
},
},
}
for _, test := range cases {
cond, err := test.rule.BuildCondition()
common.Must(err)
for _, subtest := range test.test {
actual := cond.Apply(subtest.input)
if actual != subtest.output {
t.Error("test case failed: ", subtest.input, " expected ", subtest.output, " but got ", actual)
}
}
}
}
func loadGeoSite(country string) ([]*Domain, error) {
geositeBytes, err := filesystem.ReadAsset("geosite.dat")
if err != nil {
return nil, err
}
var geositeList GeoSiteList
if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil {
return nil, err
}
for _, site := range geositeList.Entry {
if site.CountryCode == country {
return site.Domain, nil
}
}
return nil, errors.New("country not found: " + country)
}
func TestChinaSites(t *testing.T) {
domains, err := loadGeoSite("CN")
common.Must(err)
matcher, err := NewDomainMatcher(domains)
common.Must(err)
type TestCase struct {
Domain string
Output bool
}
testCases := []TestCase{
{
Domain: "163.com",
Output: true,
},
{
Domain: "163.com",
Output: true,
},
{
Domain: "164.com",
Output: false,
},
{
Domain: "164.com",
Output: false,
},
}
for i := 0; i < 1024; i++ {
testCases = append(testCases, TestCase{Domain: strconv.Itoa(i) + ".not-exists.com", Output: false})
}
for _, testCase := range testCases {
r := matcher.ApplyDomain(testCase.Domain)
if r != testCase.Output {
t.Error("expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r)
}
}
}
func BenchmarkMultiGeoIPMatcher(b *testing.B) {
var geoips []*GeoIP
{
ips, err := loadGeoIP("CN")
common.Must(err)
geoips = append(geoips, &GeoIP{
CountryCode: "CN",
Cidr: ips,
})
}
{
ips, err := loadGeoIP("JP")
common.Must(err)
geoips = append(geoips, &GeoIP{
CountryCode: "JP",
Cidr: ips,
})
}
{
ips, err := loadGeoIP("CA")
common.Must(err)
geoips = append(geoips, &GeoIP{
CountryCode: "CA",
Cidr: ips,
})
}
{
ips, err := loadGeoIP("US")
common.Must(err)
geoips = append(geoips, &GeoIP{
CountryCode: "US",
Cidr: ips,
})
}
matcher, err := NewMultiGeoIPMatcher(geoips, false)
common.Must(err)
ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)})
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = matcher.Apply(ctx)
}
}
v2ray-core-4.34.0/app/router/config.go 0000664 0000000 0000000 00000006165 13774574720 0017517 0 ustar 00root root 0000000 0000000 // +build !confonly
package router
import (
"v2ray.com/core/common/net"
"v2ray.com/core/features/outbound"
"v2ray.com/core/features/routing"
)
// CIDRList is an alias of []*CIDR to provide sort.Interface.
type CIDRList []*CIDR
// Len implements sort.Interface.
func (l *CIDRList) Len() int {
return len(*l)
}
// Less implements sort.Interface.
func (l *CIDRList) Less(i int, j int) bool {
ci := (*l)[i]
cj := (*l)[j]
if len(ci.Ip) < len(cj.Ip) {
return true
}
if len(ci.Ip) > len(cj.Ip) {
return false
}
for k := 0; k < len(ci.Ip); k++ {
if ci.Ip[k] < cj.Ip[k] {
return true
}
if ci.Ip[k] > cj.Ip[k] {
return false
}
}
return ci.Prefix < cj.Prefix
}
// Swap implements sort.Interface.
func (l *CIDRList) Swap(i int, j int) {
(*l)[i], (*l)[j] = (*l)[j], (*l)[i]
}
type Rule struct {
Tag string
Balancer *Balancer
Condition Condition
}
func (r *Rule) GetTag() (string, error) {
if r.Balancer != nil {
return r.Balancer.PickOutbound()
}
return r.Tag, nil
}
// Apply checks rule matching of current routing context.
func (r *Rule) Apply(ctx routing.Context) bool {
return r.Condition.Apply(ctx)
}
func (rr *RoutingRule) BuildCondition() (Condition, error) {
conds := NewConditionChan()
if len(rr.Domain) > 0 {
matcher, err := NewDomainMatcher(rr.Domain)
if err != nil {
return nil, newError("failed to build domain condition").Base(err)
}
conds.Add(matcher)
}
if len(rr.UserEmail) > 0 {
conds.Add(NewUserMatcher(rr.UserEmail))
}
if len(rr.InboundTag) > 0 {
conds.Add(NewInboundTagMatcher(rr.InboundTag))
}
if rr.PortList != nil {
conds.Add(NewPortMatcher(rr.PortList, false))
} else if rr.PortRange != nil {
conds.Add(NewPortMatcher(&net.PortList{Range: []*net.PortRange{rr.PortRange}}, false))
}
if rr.SourcePortList != nil {
conds.Add(NewPortMatcher(rr.SourcePortList, true))
}
if len(rr.Networks) > 0 {
conds.Add(NewNetworkMatcher(rr.Networks))
} else if rr.NetworkList != nil {
conds.Add(NewNetworkMatcher(rr.NetworkList.Network))
}
if len(rr.Geoip) > 0 {
cond, err := NewMultiGeoIPMatcher(rr.Geoip, false)
if err != nil {
return nil, err
}
conds.Add(cond)
} else if len(rr.Cidr) > 0 {
cond, err := NewMultiGeoIPMatcher([]*GeoIP{{Cidr: rr.Cidr}}, false)
if err != nil {
return nil, err
}
conds.Add(cond)
}
if len(rr.SourceGeoip) > 0 {
cond, err := NewMultiGeoIPMatcher(rr.SourceGeoip, true)
if err != nil {
return nil, err
}
conds.Add(cond)
} else if len(rr.SourceCidr) > 0 {
cond, err := NewMultiGeoIPMatcher([]*GeoIP{{Cidr: rr.SourceCidr}}, true)
if err != nil {
return nil, err
}
conds.Add(cond)
}
if len(rr.Protocol) > 0 {
conds.Add(NewProtocolMatcher(rr.Protocol))
}
if len(rr.Attributes) > 0 {
cond, err := NewAttributeMatcher(rr.Attributes)
if err != nil {
return nil, err
}
conds.Add(cond)
}
if conds.Len() == 0 {
return nil, newError("this rule has no effective fields").AtWarning()
}
return conds, nil
}
func (br *BalancingRule) Build(ohm outbound.Manager) (*Balancer, error) {
return &Balancer{
selectors: br.OutboundSelector,
strategy: &RandomStrategy{},
ohm: ohm,
}, nil
}
v2ray-core-4.34.0/app/router/config.pb.go 0000664 0000000 0000000 00000125557 13774574720 0020126 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: app/router/config.proto
package router
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
net "v2ray.com/core/common/net"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// Type of domain value.
type Domain_Type int32
const (
// The value is used as is.
Domain_Plain Domain_Type = 0
// The value is used as a regular expression.
Domain_Regex Domain_Type = 1
// The value is a root domain.
Domain_Domain Domain_Type = 2
// The value is a domain.
Domain_Full Domain_Type = 3
)
// Enum value maps for Domain_Type.
var (
Domain_Type_name = map[int32]string{
0: "Plain",
1: "Regex",
2: "Domain",
3: "Full",
}
Domain_Type_value = map[string]int32{
"Plain": 0,
"Regex": 1,
"Domain": 2,
"Full": 3,
}
)
func (x Domain_Type) Enum() *Domain_Type {
p := new(Domain_Type)
*p = x
return p
}
func (x Domain_Type) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Domain_Type) Descriptor() protoreflect.EnumDescriptor {
return file_app_router_config_proto_enumTypes[0].Descriptor()
}
func (Domain_Type) Type() protoreflect.EnumType {
return &file_app_router_config_proto_enumTypes[0]
}
func (x Domain_Type) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Domain_Type.Descriptor instead.
func (Domain_Type) EnumDescriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{0, 0}
}
type Config_DomainStrategy int32
const (
// Use domain as is.
Config_AsIs Config_DomainStrategy = 0
// Always resolve IP for domains.
Config_UseIp Config_DomainStrategy = 1
// Resolve to IP if the domain doesn't match any rules.
Config_IpIfNonMatch Config_DomainStrategy = 2
// Resolve to IP if any rule requires IP matching.
Config_IpOnDemand Config_DomainStrategy = 3
)
// Enum value maps for Config_DomainStrategy.
var (
Config_DomainStrategy_name = map[int32]string{
0: "AsIs",
1: "UseIp",
2: "IpIfNonMatch",
3: "IpOnDemand",
}
Config_DomainStrategy_value = map[string]int32{
"AsIs": 0,
"UseIp": 1,
"IpIfNonMatch": 2,
"IpOnDemand": 3,
}
)
func (x Config_DomainStrategy) Enum() *Config_DomainStrategy {
p := new(Config_DomainStrategy)
*p = x
return p
}
func (x Config_DomainStrategy) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Config_DomainStrategy) Descriptor() protoreflect.EnumDescriptor {
return file_app_router_config_proto_enumTypes[1].Descriptor()
}
func (Config_DomainStrategy) Type() protoreflect.EnumType {
return &file_app_router_config_proto_enumTypes[1]
}
func (x Config_DomainStrategy) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Config_DomainStrategy.Descriptor instead.
func (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{8, 0}
}
// Domain for routing decision.
type Domain struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Domain matching type.
Type Domain_Type `protobuf:"varint,1,opt,name=type,proto3,enum=v2ray.core.app.router.Domain_Type" json:"type,omitempty"`
// Domain value.
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
// Attributes of this domain. May be used for filtering.
Attribute []*Domain_Attribute `protobuf:"bytes,3,rep,name=attribute,proto3" json:"attribute,omitempty"`
}
func (x *Domain) Reset() {
*x = Domain{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Domain) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Domain) ProtoMessage() {}
func (x *Domain) ProtoReflect() protoreflect.Message {
mi := &file_app_router_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Domain.ProtoReflect.Descriptor instead.
func (*Domain) Descriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{0}
}
func (x *Domain) GetType() Domain_Type {
if x != nil {
return x.Type
}
return Domain_Plain
}
func (x *Domain) GetValue() string {
if x != nil {
return x.Value
}
return ""
}
func (x *Domain) GetAttribute() []*Domain_Attribute {
if x != nil {
return x.Attribute
}
return nil
}
// IP for routing decision, in CIDR form.
type CIDR struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// IP address, should be either 4 or 16 bytes.
Ip []byte `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"`
// Number of leading ones in the network mask.
Prefix uint32 `protobuf:"varint,2,opt,name=prefix,proto3" json:"prefix,omitempty"`
}
func (x *CIDR) Reset() {
*x = CIDR{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CIDR) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CIDR) ProtoMessage() {}
func (x *CIDR) ProtoReflect() protoreflect.Message {
mi := &file_app_router_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CIDR.ProtoReflect.Descriptor instead.
func (*CIDR) Descriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{1}
}
func (x *CIDR) GetIp() []byte {
if x != nil {
return x.Ip
}
return nil
}
func (x *CIDR) GetPrefix() uint32 {
if x != nil {
return x.Prefix
}
return 0
}
type GeoIP struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
CountryCode string `protobuf:"bytes,1,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"`
Cidr []*CIDR `protobuf:"bytes,2,rep,name=cidr,proto3" json:"cidr,omitempty"`
}
func (x *GeoIP) Reset() {
*x = GeoIP{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GeoIP) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GeoIP) ProtoMessage() {}
func (x *GeoIP) ProtoReflect() protoreflect.Message {
mi := &file_app_router_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GeoIP.ProtoReflect.Descriptor instead.
func (*GeoIP) Descriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{2}
}
func (x *GeoIP) GetCountryCode() string {
if x != nil {
return x.CountryCode
}
return ""
}
func (x *GeoIP) GetCidr() []*CIDR {
if x != nil {
return x.Cidr
}
return nil
}
type GeoIPList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Entry []*GeoIP `protobuf:"bytes,1,rep,name=entry,proto3" json:"entry,omitempty"`
}
func (x *GeoIPList) Reset() {
*x = GeoIPList{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GeoIPList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GeoIPList) ProtoMessage() {}
func (x *GeoIPList) ProtoReflect() protoreflect.Message {
mi := &file_app_router_config_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GeoIPList.ProtoReflect.Descriptor instead.
func (*GeoIPList) Descriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{3}
}
func (x *GeoIPList) GetEntry() []*GeoIP {
if x != nil {
return x.Entry
}
return nil
}
type GeoSite struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
CountryCode string `protobuf:"bytes,1,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"`
Domain []*Domain `protobuf:"bytes,2,rep,name=domain,proto3" json:"domain,omitempty"`
}
func (x *GeoSite) Reset() {
*x = GeoSite{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_config_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GeoSite) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GeoSite) ProtoMessage() {}
func (x *GeoSite) ProtoReflect() protoreflect.Message {
mi := &file_app_router_config_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GeoSite.ProtoReflect.Descriptor instead.
func (*GeoSite) Descriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{4}
}
func (x *GeoSite) GetCountryCode() string {
if x != nil {
return x.CountryCode
}
return ""
}
func (x *GeoSite) GetDomain() []*Domain {
if x != nil {
return x.Domain
}
return nil
}
type GeoSiteList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Entry []*GeoSite `protobuf:"bytes,1,rep,name=entry,proto3" json:"entry,omitempty"`
}
func (x *GeoSiteList) Reset() {
*x = GeoSiteList{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_config_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GeoSiteList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GeoSiteList) ProtoMessage() {}
func (x *GeoSiteList) ProtoReflect() protoreflect.Message {
mi := &file_app_router_config_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GeoSiteList.ProtoReflect.Descriptor instead.
func (*GeoSiteList) Descriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{5}
}
func (x *GeoSiteList) GetEntry() []*GeoSite {
if x != nil {
return x.Entry
}
return nil
}
type RoutingRule struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Types that are assignable to TargetTag:
// *RoutingRule_Tag
// *RoutingRule_BalancingTag
TargetTag isRoutingRule_TargetTag `protobuf_oneof:"target_tag"`
// List of domains for target domain matching.
Domain []*Domain `protobuf:"bytes,2,rep,name=domain,proto3" json:"domain,omitempty"`
// List of CIDRs for target IP address matching.
// Deprecated. Use geoip below.
//
// Deprecated: Do not use.
Cidr []*CIDR `protobuf:"bytes,3,rep,name=cidr,proto3" json:"cidr,omitempty"`
// List of GeoIPs for target IP address matching. If this entry exists, the
// cidr above will have no effect. GeoIP fields with the same country code are
// supposed to contain exactly same content. They will be merged during
// runtime. For customized GeoIPs, please leave country code empty.
Geoip []*GeoIP `protobuf:"bytes,10,rep,name=geoip,proto3" json:"geoip,omitempty"`
// A range of port [from, to]. If the destination port is in this range, this
// rule takes effect. Deprecated. Use port_list.
//
// Deprecated: Do not use.
PortRange *net.PortRange `protobuf:"bytes,4,opt,name=port_range,json=portRange,proto3" json:"port_range,omitempty"`
// List of ports.
PortList *net.PortList `protobuf:"bytes,14,opt,name=port_list,json=portList,proto3" json:"port_list,omitempty"`
// List of networks. Deprecated. Use networks.
//
// Deprecated: Do not use.
NetworkList *net.NetworkList `protobuf:"bytes,5,opt,name=network_list,json=networkList,proto3" json:"network_list,omitempty"`
// List of networks for matching.
Networks []net.Network `protobuf:"varint,13,rep,packed,name=networks,proto3,enum=v2ray.core.common.net.Network" json:"networks,omitempty"`
// List of CIDRs for source IP address matching.
//
// Deprecated: Do not use.
SourceCidr []*CIDR `protobuf:"bytes,6,rep,name=source_cidr,json=sourceCidr,proto3" json:"source_cidr,omitempty"`
// List of GeoIPs for source IP address matching. If this entry exists, the
// source_cidr above will have no effect.
SourceGeoip []*GeoIP `protobuf:"bytes,11,rep,name=source_geoip,json=sourceGeoip,proto3" json:"source_geoip,omitempty"`
// List of ports for source port matching.
SourcePortList *net.PortList `protobuf:"bytes,16,opt,name=source_port_list,json=sourcePortList,proto3" json:"source_port_list,omitempty"`
UserEmail []string `protobuf:"bytes,7,rep,name=user_email,json=userEmail,proto3" json:"user_email,omitempty"`
InboundTag []string `protobuf:"bytes,8,rep,name=inbound_tag,json=inboundTag,proto3" json:"inbound_tag,omitempty"`
Protocol []string `protobuf:"bytes,9,rep,name=protocol,proto3" json:"protocol,omitempty"`
Attributes string `protobuf:"bytes,15,opt,name=attributes,proto3" json:"attributes,omitempty"`
}
func (x *RoutingRule) Reset() {
*x = RoutingRule{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_config_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RoutingRule) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RoutingRule) ProtoMessage() {}
func (x *RoutingRule) ProtoReflect() protoreflect.Message {
mi := &file_app_router_config_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RoutingRule.ProtoReflect.Descriptor instead.
func (*RoutingRule) Descriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{6}
}
func (m *RoutingRule) GetTargetTag() isRoutingRule_TargetTag {
if m != nil {
return m.TargetTag
}
return nil
}
func (x *RoutingRule) GetTag() string {
if x, ok := x.GetTargetTag().(*RoutingRule_Tag); ok {
return x.Tag
}
return ""
}
func (x *RoutingRule) GetBalancingTag() string {
if x, ok := x.GetTargetTag().(*RoutingRule_BalancingTag); ok {
return x.BalancingTag
}
return ""
}
func (x *RoutingRule) GetDomain() []*Domain {
if x != nil {
return x.Domain
}
return nil
}
// Deprecated: Do not use.
func (x *RoutingRule) GetCidr() []*CIDR {
if x != nil {
return x.Cidr
}
return nil
}
func (x *RoutingRule) GetGeoip() []*GeoIP {
if x != nil {
return x.Geoip
}
return nil
}
// Deprecated: Do not use.
func (x *RoutingRule) GetPortRange() *net.PortRange {
if x != nil {
return x.PortRange
}
return nil
}
func (x *RoutingRule) GetPortList() *net.PortList {
if x != nil {
return x.PortList
}
return nil
}
// Deprecated: Do not use.
func (x *RoutingRule) GetNetworkList() *net.NetworkList {
if x != nil {
return x.NetworkList
}
return nil
}
func (x *RoutingRule) GetNetworks() []net.Network {
if x != nil {
return x.Networks
}
return nil
}
// Deprecated: Do not use.
func (x *RoutingRule) GetSourceCidr() []*CIDR {
if x != nil {
return x.SourceCidr
}
return nil
}
func (x *RoutingRule) GetSourceGeoip() []*GeoIP {
if x != nil {
return x.SourceGeoip
}
return nil
}
func (x *RoutingRule) GetSourcePortList() *net.PortList {
if x != nil {
return x.SourcePortList
}
return nil
}
func (x *RoutingRule) GetUserEmail() []string {
if x != nil {
return x.UserEmail
}
return nil
}
func (x *RoutingRule) GetInboundTag() []string {
if x != nil {
return x.InboundTag
}
return nil
}
func (x *RoutingRule) GetProtocol() []string {
if x != nil {
return x.Protocol
}
return nil
}
func (x *RoutingRule) GetAttributes() string {
if x != nil {
return x.Attributes
}
return ""
}
type isRoutingRule_TargetTag interface {
isRoutingRule_TargetTag()
}
type RoutingRule_Tag struct {
// Tag of outbound that this rule is pointing to.
Tag string `protobuf:"bytes,1,opt,name=tag,proto3,oneof"`
}
type RoutingRule_BalancingTag struct {
// Tag of routing balancer.
BalancingTag string `protobuf:"bytes,12,opt,name=balancing_tag,json=balancingTag,proto3,oneof"`
}
func (*RoutingRule_Tag) isRoutingRule_TargetTag() {}
func (*RoutingRule_BalancingTag) isRoutingRule_TargetTag() {}
type BalancingRule struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
OutboundSelector []string `protobuf:"bytes,2,rep,name=outbound_selector,json=outboundSelector,proto3" json:"outbound_selector,omitempty"`
}
func (x *BalancingRule) Reset() {
*x = BalancingRule{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_config_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BalancingRule) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BalancingRule) ProtoMessage() {}
func (x *BalancingRule) ProtoReflect() protoreflect.Message {
mi := &file_app_router_config_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BalancingRule.ProtoReflect.Descriptor instead.
func (*BalancingRule) Descriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{7}
}
func (x *BalancingRule) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
func (x *BalancingRule) GetOutboundSelector() []string {
if x != nil {
return x.OutboundSelector
}
return nil
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
DomainStrategy Config_DomainStrategy `protobuf:"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=v2ray.core.app.router.Config_DomainStrategy" json:"domain_strategy,omitempty"`
Rule []*RoutingRule `protobuf:"bytes,2,rep,name=rule,proto3" json:"rule,omitempty"`
BalancingRule []*BalancingRule `protobuf:"bytes,3,rep,name=balancing_rule,json=balancingRule,proto3" json:"balancing_rule,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_config_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_router_config_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{8}
}
func (x *Config) GetDomainStrategy() Config_DomainStrategy {
if x != nil {
return x.DomainStrategy
}
return Config_AsIs
}
func (x *Config) GetRule() []*RoutingRule {
if x != nil {
return x.Rule
}
return nil
}
func (x *Config) GetBalancingRule() []*BalancingRule {
if x != nil {
return x.BalancingRule
}
return nil
}
type Domain_Attribute struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
// Types that are assignable to TypedValue:
// *Domain_Attribute_BoolValue
// *Domain_Attribute_IntValue
TypedValue isDomain_Attribute_TypedValue `protobuf_oneof:"typed_value"`
}
func (x *Domain_Attribute) Reset() {
*x = Domain_Attribute{}
if protoimpl.UnsafeEnabled {
mi := &file_app_router_config_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Domain_Attribute) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Domain_Attribute) ProtoMessage() {}
func (x *Domain_Attribute) ProtoReflect() protoreflect.Message {
mi := &file_app_router_config_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Domain_Attribute.ProtoReflect.Descriptor instead.
func (*Domain_Attribute) Descriptor() ([]byte, []int) {
return file_app_router_config_proto_rawDescGZIP(), []int{0, 0}
}
func (x *Domain_Attribute) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
func (m *Domain_Attribute) GetTypedValue() isDomain_Attribute_TypedValue {
if m != nil {
return m.TypedValue
}
return nil
}
func (x *Domain_Attribute) GetBoolValue() bool {
if x, ok := x.GetTypedValue().(*Domain_Attribute_BoolValue); ok {
return x.BoolValue
}
return false
}
func (x *Domain_Attribute) GetIntValue() int64 {
if x, ok := x.GetTypedValue().(*Domain_Attribute_IntValue); ok {
return x.IntValue
}
return 0
}
type isDomain_Attribute_TypedValue interface {
isDomain_Attribute_TypedValue()
}
type Domain_Attribute_BoolValue struct {
BoolValue bool `protobuf:"varint,2,opt,name=bool_value,json=boolValue,proto3,oneof"`
}
type Domain_Attribute_IntValue struct {
IntValue int64 `protobuf:"varint,3,opt,name=int_value,json=intValue,proto3,oneof"`
}
func (*Domain_Attribute_BoolValue) isDomain_Attribute_TypedValue() {}
func (*Domain_Attribute_IntValue) isDomain_Attribute_TypedValue() {}
var File_app_router_config_proto protoreflect.FileDescriptor
var file_app_router_config_proto_rawDesc = []byte{
0x0a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
0x1a, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f,
0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x22, 0xbf, 0x02, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x36, 0x0a, 0x04,
0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04,
0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x45, 0x0a, 0x09, 0x61, 0x74,
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x41, 0x74, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
0x65, 0x1a, 0x6c, 0x0a, 0x09, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x10,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
0x12, 0x1f, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75,
0x65, 0x12, 0x1d, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03,
0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65,
0x42, 0x0d, 0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,
0x32, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x6c, 0x61, 0x69, 0x6e,
0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x01, 0x12, 0x0a, 0x0a,
0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c,
0x6c, 0x10, 0x03, 0x22, 0x2e, 0x0a, 0x04, 0x43, 0x49, 0x44, 0x52, 0x12, 0x0e, 0x0a, 0x02, 0x69,
0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x70,
0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65,
0x66, 0x69, 0x78, 0x22, 0x5b, 0x0a, 0x05, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x12, 0x21, 0x0a, 0x0c,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12,
0x2f, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72,
0x22, 0x3f, 0x0a, 0x09, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x32, 0x0a,
0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72,
0x79, 0x22, 0x63, 0x0a, 0x07, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12,
0x35, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x1d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x43, 0x0a, 0x0b, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74,
0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f,
0x53, 0x69, 0x74, 0x65, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xca, 0x06, 0x0a, 0x0b,
0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x03, 0x74,
0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12,
0x25, 0x0a, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67,
0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63,
0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x12, 0x35, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x33, 0x0a,
0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x42, 0x02, 0x18, 0x01, 0x52, 0x04, 0x63, 0x69,
0x64, 0x72, 0x12, 0x32, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0a, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x1c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52,
0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x43, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72,
0x61, 0x6e, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e,
0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x02, 0x18, 0x01,
0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x09, 0x70,
0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f,
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52,
0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x49, 0x0a, 0x0c, 0x6e, 0x65, 0x74,
0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x22, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c,
0x69, 0x73, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
0x4c, 0x69, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73,
0x18, 0x0d, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e,
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73,
0x12, 0x40, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18,
0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49,
0x44, 0x52, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x69,
0x64, 0x72, 0x12, 0x3f, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, 0x65, 0x6f,
0x69, 0x70, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x65,
0x6f, 0x69, 0x70, 0x12, 0x49, 0x0a, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x6f,
0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0e,
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1d,
0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x07, 0x20, 0x03,
0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1f, 0x0a,
0x0b, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x08, 0x20, 0x03,
0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x1a,
0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09,
0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x74,
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x74, 0x61,
0x72, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x22, 0x4e, 0x0a, 0x0d, 0x42, 0x61, 0x6c, 0x61,
0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b, 0x0a, 0x11, 0x6f,
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72,
0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0xad, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x12, 0x55, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74,
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61,
0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61,
0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x36, 0x0a, 0x04, 0x72, 0x75,
0x6c, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x75,
0x6c, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f,
0x72, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
0x65, 0x72, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65,
0x52, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x22,
0x47, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
0x79, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49, 0x73, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x55,
0x73, 0x65, 0x49, 0x70, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x70, 0x49, 0x66, 0x4e, 0x6f,
0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x70, 0x4f, 0x6e,
0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x10, 0x03, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
0x6f, 0x75, 0x74, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74,
0x65, 0x72, 0xaa, 0x02, 0x15, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e,
0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_app_router_config_proto_rawDescOnce sync.Once
file_app_router_config_proto_rawDescData = file_app_router_config_proto_rawDesc
)
func file_app_router_config_proto_rawDescGZIP() []byte {
file_app_router_config_proto_rawDescOnce.Do(func() {
file_app_router_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_router_config_proto_rawDescData)
})
return file_app_router_config_proto_rawDescData
}
var file_app_router_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_app_router_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_app_router_config_proto_goTypes = []interface{}{
(Domain_Type)(0), // 0: v2ray.core.app.router.Domain.Type
(Config_DomainStrategy)(0), // 1: v2ray.core.app.router.Config.DomainStrategy
(*Domain)(nil), // 2: v2ray.core.app.router.Domain
(*CIDR)(nil), // 3: v2ray.core.app.router.CIDR
(*GeoIP)(nil), // 4: v2ray.core.app.router.GeoIP
(*GeoIPList)(nil), // 5: v2ray.core.app.router.GeoIPList
(*GeoSite)(nil), // 6: v2ray.core.app.router.GeoSite
(*GeoSiteList)(nil), // 7: v2ray.core.app.router.GeoSiteList
(*RoutingRule)(nil), // 8: v2ray.core.app.router.RoutingRule
(*BalancingRule)(nil), // 9: v2ray.core.app.router.BalancingRule
(*Config)(nil), // 10: v2ray.core.app.router.Config
(*Domain_Attribute)(nil), // 11: v2ray.core.app.router.Domain.Attribute
(*net.PortRange)(nil), // 12: v2ray.core.common.net.PortRange
(*net.PortList)(nil), // 13: v2ray.core.common.net.PortList
(*net.NetworkList)(nil), // 14: v2ray.core.common.net.NetworkList
(net.Network)(0), // 15: v2ray.core.common.net.Network
}
var file_app_router_config_proto_depIdxs = []int32{
0, // 0: v2ray.core.app.router.Domain.type:type_name -> v2ray.core.app.router.Domain.Type
11, // 1: v2ray.core.app.router.Domain.attribute:type_name -> v2ray.core.app.router.Domain.Attribute
3, // 2: v2ray.core.app.router.GeoIP.cidr:type_name -> v2ray.core.app.router.CIDR
4, // 3: v2ray.core.app.router.GeoIPList.entry:type_name -> v2ray.core.app.router.GeoIP
2, // 4: v2ray.core.app.router.GeoSite.domain:type_name -> v2ray.core.app.router.Domain
6, // 5: v2ray.core.app.router.GeoSiteList.entry:type_name -> v2ray.core.app.router.GeoSite
2, // 6: v2ray.core.app.router.RoutingRule.domain:type_name -> v2ray.core.app.router.Domain
3, // 7: v2ray.core.app.router.RoutingRule.cidr:type_name -> v2ray.core.app.router.CIDR
4, // 8: v2ray.core.app.router.RoutingRule.geoip:type_name -> v2ray.core.app.router.GeoIP
12, // 9: v2ray.core.app.router.RoutingRule.port_range:type_name -> v2ray.core.common.net.PortRange
13, // 10: v2ray.core.app.router.RoutingRule.port_list:type_name -> v2ray.core.common.net.PortList
14, // 11: v2ray.core.app.router.RoutingRule.network_list:type_name -> v2ray.core.common.net.NetworkList
15, // 12: v2ray.core.app.router.RoutingRule.networks:type_name -> v2ray.core.common.net.Network
3, // 13: v2ray.core.app.router.RoutingRule.source_cidr:type_name -> v2ray.core.app.router.CIDR
4, // 14: v2ray.core.app.router.RoutingRule.source_geoip:type_name -> v2ray.core.app.router.GeoIP
13, // 15: v2ray.core.app.router.RoutingRule.source_port_list:type_name -> v2ray.core.common.net.PortList
1, // 16: v2ray.core.app.router.Config.domain_strategy:type_name -> v2ray.core.app.router.Config.DomainStrategy
8, // 17: v2ray.core.app.router.Config.rule:type_name -> v2ray.core.app.router.RoutingRule
9, // 18: v2ray.core.app.router.Config.balancing_rule:type_name -> v2ray.core.app.router.BalancingRule
19, // [19:19] is the sub-list for method output_type
19, // [19:19] is the sub-list for method input_type
19, // [19:19] is the sub-list for extension type_name
19, // [19:19] is the sub-list for extension extendee
0, // [0:19] is the sub-list for field type_name
}
func init() { file_app_router_config_proto_init() }
func file_app_router_config_proto_init() {
if File_app_router_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_router_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Domain); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_router_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CIDR); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_router_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GeoIP); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_router_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GeoIPList); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_router_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GeoSite); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_router_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GeoSiteList); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_router_config_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RoutingRule); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_router_config_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BalancingRule); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_router_config_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_router_config_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Domain_Attribute); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_app_router_config_proto_msgTypes[6].OneofWrappers = []interface{}{
(*RoutingRule_Tag)(nil),
(*RoutingRule_BalancingTag)(nil),
}
file_app_router_config_proto_msgTypes[9].OneofWrappers = []interface{}{
(*Domain_Attribute_BoolValue)(nil),
(*Domain_Attribute_IntValue)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_router_config_proto_rawDesc,
NumEnums: 2,
NumMessages: 10,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_app_router_config_proto_goTypes,
DependencyIndexes: file_app_router_config_proto_depIdxs,
EnumInfos: file_app_router_config_proto_enumTypes,
MessageInfos: file_app_router_config_proto_msgTypes,
}.Build()
File_app_router_config_proto = out.File
file_app_router_config_proto_rawDesc = nil
file_app_router_config_proto_goTypes = nil
file_app_router_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/app/router/config.proto 0000664 0000000 0000000 00000007011 13774574720 0020244 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.app.router;
option csharp_namespace = "V2Ray.Core.App.Router";
option go_package = "v2ray.com/core/app/router";
option java_package = "com.v2ray.core.app.router";
option java_multiple_files = true;
import "common/net/port.proto";
import "common/net/network.proto";
// Domain for routing decision.
message Domain {
// Type of domain value.
enum Type {
// The value is used as is.
Plain = 0;
// The value is used as a regular expression.
Regex = 1;
// The value is a root domain.
Domain = 2;
// The value is a domain.
Full = 3;
}
// Domain matching type.
Type type = 1;
// Domain value.
string value = 2;
message Attribute {
string key = 1;
oneof typed_value {
bool bool_value = 2;
int64 int_value = 3;
}
}
// Attributes of this domain. May be used for filtering.
repeated Attribute attribute = 3;
}
// IP for routing decision, in CIDR form.
message CIDR {
// IP address, should be either 4 or 16 bytes.
bytes ip = 1;
// Number of leading ones in the network mask.
uint32 prefix = 2;
}
message GeoIP {
string country_code = 1;
repeated CIDR cidr = 2;
}
message GeoIPList {
repeated GeoIP entry = 1;
}
message GeoSite {
string country_code = 1;
repeated Domain domain = 2;
}
message GeoSiteList {
repeated GeoSite entry = 1;
}
message RoutingRule {
oneof target_tag {
// Tag of outbound that this rule is pointing to.
string tag = 1;
// Tag of routing balancer.
string balancing_tag = 12;
}
// List of domains for target domain matching.
repeated Domain domain = 2;
// List of CIDRs for target IP address matching.
// Deprecated. Use geoip below.
repeated CIDR cidr = 3 [deprecated = true];
// List of GeoIPs for target IP address matching. If this entry exists, the
// cidr above will have no effect. GeoIP fields with the same country code are
// supposed to contain exactly same content. They will be merged during
// runtime. For customized GeoIPs, please leave country code empty.
repeated GeoIP geoip = 10;
// A range of port [from, to]. If the destination port is in this range, this
// rule takes effect. Deprecated. Use port_list.
v2ray.core.common.net.PortRange port_range = 4 [deprecated = true];
// List of ports.
v2ray.core.common.net.PortList port_list = 14;
// List of networks. Deprecated. Use networks.
v2ray.core.common.net.NetworkList network_list = 5 [deprecated = true];
// List of networks for matching.
repeated v2ray.core.common.net.Network networks = 13;
// List of CIDRs for source IP address matching.
repeated CIDR source_cidr = 6 [deprecated = true];
// List of GeoIPs for source IP address matching. If this entry exists, the
// source_cidr above will have no effect.
repeated GeoIP source_geoip = 11;
// List of ports for source port matching.
v2ray.core.common.net.PortList source_port_list = 16;
repeated string user_email = 7;
repeated string inbound_tag = 8;
repeated string protocol = 9;
string attributes = 15;
}
message BalancingRule {
string tag = 1;
repeated string outbound_selector = 2;
}
message Config {
enum DomainStrategy {
// Use domain as is.
AsIs = 0;
// Always resolve IP for domains.
UseIp = 1;
// Resolve to IP if the domain doesn't match any rules.
IpIfNonMatch = 2;
// Resolve to IP if any rule requires IP matching.
IpOnDemand = 3;
}
DomainStrategy domain_strategy = 1;
repeated RoutingRule rule = 2;
repeated BalancingRule balancing_rule = 3;
}
v2ray-core-4.34.0/app/router/errors.generated.go 0000664 0000000 0000000 00000000314 13774574720 0021511 0 ustar 00root root 0000000 0000000 package router
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/app/router/router.go 0000664 0000000 0000000 00000006710 13774574720 0017566 0 ustar 00root root 0000000 0000000 // +build !confonly
package router
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/features/dns"
"v2ray.com/core/features/outbound"
"v2ray.com/core/features/routing"
routing_dns "v2ray.com/core/features/routing/dns"
)
// Router is an implementation of routing.Router.
type Router struct {
domainStrategy Config_DomainStrategy
rules []*Rule
balancers map[string]*Balancer
dns dns.Client
}
// Route is an implementation of routing.Route.
type Route struct {
routing.Context
outboundGroupTags []string
outboundTag string
}
// Init initializes the Router.
func (r *Router) Init(config *Config, d dns.Client, ohm outbound.Manager) error {
r.domainStrategy = config.DomainStrategy
r.dns = d
r.balancers = make(map[string]*Balancer, len(config.BalancingRule))
for _, rule := range config.BalancingRule {
balancer, err := rule.Build(ohm)
if err != nil {
return err
}
r.balancers[rule.Tag] = balancer
}
r.rules = make([]*Rule, 0, len(config.Rule))
for _, rule := range config.Rule {
cond, err := rule.BuildCondition()
if err != nil {
return err
}
rr := &Rule{
Condition: cond,
Tag: rule.GetTag(),
}
btag := rule.GetBalancingTag()
if len(btag) > 0 {
brule, found := r.balancers[btag]
if !found {
return newError("balancer ", btag, " not found")
}
rr.Balancer = brule
}
r.rules = append(r.rules, rr)
}
return nil
}
// PickRoute implements routing.Router.
func (r *Router) PickRoute(ctx routing.Context) (routing.Route, error) {
rule, ctx, err := r.pickRouteInternal(ctx)
if err != nil {
return nil, err
}
tag, err := rule.GetTag()
if err != nil {
return nil, err
}
return &Route{Context: ctx, outboundTag: tag}, nil
}
func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context, error) {
// SkipDNSResolve is set from DNS module.
// the DOH remote server maybe a domain name,
// this prevents cycle resolving dead loop
skipDNSResolve := ctx.GetSkipDNSResolve()
if r.domainStrategy == Config_IpOnDemand && !skipDNSResolve {
ctx = routing_dns.ContextWithDNSClient(ctx, r.dns)
}
for _, rule := range r.rules {
if rule.Apply(ctx) {
return rule, ctx, nil
}
}
if r.domainStrategy != Config_IpIfNonMatch || len(ctx.GetTargetDomain()) == 0 || skipDNSResolve {
return nil, ctx, common.ErrNoClue
}
ctx = routing_dns.ContextWithDNSClient(ctx, r.dns)
// Try applying rules again if we have IPs.
for _, rule := range r.rules {
if rule.Apply(ctx) {
return rule, ctx, nil
}
}
return nil, ctx, common.ErrNoClue
}
// Start implements common.Runnable.
func (*Router) Start() error {
return nil
}
// Close implements common.Closable.
func (*Router) Close() error {
return nil
}
// Type implement common.HasType.
func (*Router) Type() interface{} {
return routing.RouterType()
}
// GetOutboundGroupTags implements routing.Route.
func (r *Route) GetOutboundGroupTags() []string {
return r.outboundGroupTags
}
// GetOutboundTag implements routing.Route.
func (r *Route) GetOutboundTag() string {
return r.outboundTag
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
r := new(Router)
if err := core.RequireFeatures(ctx, func(d dns.Client, ohm outbound.Manager) error {
return r.Init(config.(*Config), d, ohm)
}); err != nil {
return nil, err
}
return r, nil
}))
}
v2ray-core-4.34.0/app/router/router_test.go 0000664 0000000 0000000 00000011547 13774574720 0020631 0 ustar 00root root 0000000 0000000 package router_test
import (
"context"
"testing"
"github.com/golang/mock/gomock"
. "v2ray.com/core/app/router"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/common/session"
"v2ray.com/core/features/outbound"
routing_session "v2ray.com/core/features/routing/session"
"v2ray.com/core/testing/mocks"
)
type mockOutboundManager struct {
outbound.Manager
outbound.HandlerSelector
}
func TestSimpleRouter(t *testing.T) {
config := &Config{
Rule: []*RoutingRule{
{
TargetTag: &RoutingRule_Tag{
Tag: "test",
},
Networks: []net.Network{net.Network_TCP},
},
},
}
mockCtl := gomock.NewController(t)
defer mockCtl.Finish()
mockDNS := mocks.NewDNSClient(mockCtl)
mockOhm := mocks.NewOutboundManager(mockCtl)
mockHs := mocks.NewOutboundHandlerSelector(mockCtl)
r := new(Router)
common.Must(r.Init(config, mockDNS, &mockOutboundManager{
Manager: mockOhm,
HandlerSelector: mockHs,
}))
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.com"), 80)})
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
common.Must(err)
if tag := route.GetOutboundTag(); tag != "test" {
t.Error("expect tag 'test', bug actually ", tag)
}
}
func TestSimpleBalancer(t *testing.T) {
config := &Config{
Rule: []*RoutingRule{
{
TargetTag: &RoutingRule_BalancingTag{
BalancingTag: "balance",
},
Networks: []net.Network{net.Network_TCP},
},
},
BalancingRule: []*BalancingRule{
{
Tag: "balance",
OutboundSelector: []string{"test-"},
},
},
}
mockCtl := gomock.NewController(t)
defer mockCtl.Finish()
mockDNS := mocks.NewDNSClient(mockCtl)
mockOhm := mocks.NewOutboundManager(mockCtl)
mockHs := mocks.NewOutboundHandlerSelector(mockCtl)
mockHs.EXPECT().Select(gomock.Eq([]string{"test-"})).Return([]string{"test"})
r := new(Router)
common.Must(r.Init(config, mockDNS, &mockOutboundManager{
Manager: mockOhm,
HandlerSelector: mockHs,
}))
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.com"), 80)})
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
common.Must(err)
if tag := route.GetOutboundTag(); tag != "test" {
t.Error("expect tag 'test', bug actually ", tag)
}
}
func TestIPOnDemand(t *testing.T) {
config := &Config{
DomainStrategy: Config_IpOnDemand,
Rule: []*RoutingRule{
{
TargetTag: &RoutingRule_Tag{
Tag: "test",
},
Cidr: []*CIDR{
{
Ip: []byte{192, 168, 0, 0},
Prefix: 16,
},
},
},
},
}
mockCtl := gomock.NewController(t)
defer mockCtl.Finish()
mockDNS := mocks.NewDNSClient(mockCtl)
mockDNS.EXPECT().LookupIP(gomock.Eq("v2ray.com")).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
r := new(Router)
common.Must(r.Init(config, mockDNS, nil))
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.com"), 80)})
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
common.Must(err)
if tag := route.GetOutboundTag(); tag != "test" {
t.Error("expect tag 'test', bug actually ", tag)
}
}
func TestIPIfNonMatchDomain(t *testing.T) {
config := &Config{
DomainStrategy: Config_IpIfNonMatch,
Rule: []*RoutingRule{
{
TargetTag: &RoutingRule_Tag{
Tag: "test",
},
Cidr: []*CIDR{
{
Ip: []byte{192, 168, 0, 0},
Prefix: 16,
},
},
},
},
}
mockCtl := gomock.NewController(t)
defer mockCtl.Finish()
mockDNS := mocks.NewDNSClient(mockCtl)
mockDNS.EXPECT().LookupIP(gomock.Eq("v2ray.com")).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
r := new(Router)
common.Must(r.Init(config, mockDNS, nil))
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.com"), 80)})
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
common.Must(err)
if tag := route.GetOutboundTag(); tag != "test" {
t.Error("expect tag 'test', bug actually ", tag)
}
}
func TestIPIfNonMatchIP(t *testing.T) {
config := &Config{
DomainStrategy: Config_IpIfNonMatch,
Rule: []*RoutingRule{
{
TargetTag: &RoutingRule_Tag{
Tag: "test",
},
Cidr: []*CIDR{
{
Ip: []byte{127, 0, 0, 0},
Prefix: 8,
},
},
},
},
}
mockCtl := gomock.NewController(t)
defer mockCtl.Finish()
mockDNS := mocks.NewDNSClient(mockCtl)
r := new(Router)
common.Must(r.Init(config, mockDNS, nil))
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 80)})
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
common.Must(err)
if tag := route.GetOutboundTag(); tag != "test" {
t.Error("expect tag 'test', bug actually ", tag)
}
}
v2ray-core-4.34.0/app/stats/ 0000775 0000000 0000000 00000000000 13774574720 0015531 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/stats/channel.go 0000664 0000000 0000000 00000010205 13774574720 0017466 0 ustar 00root root 0000000 0000000 // +build !confonly
package stats
import (
"context"
"sync"
"v2ray.com/core/common"
)
// Channel is an implementation of stats.Channel.
type Channel struct {
channel chan channelMessage
subscribers []chan interface{}
// Synchronization components
access sync.RWMutex
closed chan struct{}
// Channel options
blocking bool // Set blocking state if channel buffer reaches limit
bufferSize int // Set to 0 as no buffering
subsLimit int // Set to 0 as no subscriber limit
}
// NewChannel creates an instance of Statistics Channel.
func NewChannel(config *ChannelConfig) *Channel {
return &Channel{
channel: make(chan channelMessage, config.BufferSize),
subsLimit: int(config.SubscriberLimit),
bufferSize: int(config.BufferSize),
blocking: config.Blocking,
}
}
// Subscribers implements stats.Channel.
func (c *Channel) Subscribers() []chan interface{} {
c.access.RLock()
defer c.access.RUnlock()
return c.subscribers
}
// Subscribe implements stats.Channel.
func (c *Channel) Subscribe() (chan interface{}, error) {
c.access.Lock()
defer c.access.Unlock()
if c.subsLimit > 0 && len(c.subscribers) >= c.subsLimit {
return nil, newError("Number of subscribers has reached limit")
}
subscriber := make(chan interface{}, c.bufferSize)
c.subscribers = append(c.subscribers, subscriber)
return subscriber, nil
}
// Unsubscribe implements stats.Channel.
func (c *Channel) Unsubscribe(subscriber chan interface{}) error {
c.access.Lock()
defer c.access.Unlock()
for i, s := range c.subscribers {
if s == subscriber {
// Copy to new memory block to prevent modifying original data
subscribers := make([]chan interface{}, len(c.subscribers)-1)
copy(subscribers[:i], c.subscribers[:i])
copy(subscribers[i:], c.subscribers[i+1:])
c.subscribers = subscribers
}
}
return nil
}
// Publish implements stats.Channel.
func (c *Channel) Publish(ctx context.Context, msg interface{}) {
select { // Early exit if channel closed
case <-c.closed:
return
default:
pub := channelMessage{context: ctx, message: msg}
if c.blocking {
pub.publish(c.channel)
} else {
pub.publishNonBlocking(c.channel)
}
}
}
// Running returns whether the channel is running.
func (c *Channel) Running() bool {
select {
case <-c.closed: // Channel closed
default: // Channel running or not initialized
if c.closed != nil { // Channel initialized
return true
}
}
return false
}
// Start implements common.Runnable.
func (c *Channel) Start() error {
c.access.Lock()
defer c.access.Unlock()
if !c.Running() {
c.closed = make(chan struct{}) // Reset close signal
go func() {
for {
select {
case pub := <-c.channel: // Published message received
for _, sub := range c.Subscribers() { // Concurrency-safe subscribers retrievement
if c.blocking {
pub.broadcast(sub)
} else {
pub.broadcastNonBlocking(sub)
}
}
case <-c.closed: // Channel closed
for _, sub := range c.Subscribers() { // Remove all subscribers
common.Must(c.Unsubscribe(sub))
close(sub)
}
return
}
}
}()
}
return nil
}
// Close implements common.Closable.
func (c *Channel) Close() error {
c.access.Lock()
defer c.access.Unlock()
if c.Running() {
close(c.closed) // Send closed signal
}
return nil
}
// channelMessage is the published message with guaranteed delivery.
// message is discarded only when the context is early cancelled.
type channelMessage struct {
context context.Context
message interface{}
}
func (c channelMessage) publish(publisher chan channelMessage) {
select {
case publisher <- c:
case <-c.context.Done():
}
}
func (c channelMessage) publishNonBlocking(publisher chan channelMessage) {
select {
case publisher <- c:
default: // Create another goroutine to keep sending message
go c.publish(publisher)
}
}
func (c channelMessage) broadcast(subscriber chan interface{}) {
select {
case subscriber <- c.message:
case <-c.context.Done():
}
}
func (c channelMessage) broadcastNonBlocking(subscriber chan interface{}) {
select {
case subscriber <- c.message:
default: // Create another goroutine to keep sending message
go c.broadcast(subscriber)
}
}
v2ray-core-4.34.0/app/stats/channel_test.go 0000664 0000000 0000000 00000022721 13774574720 0020533 0 ustar 00root root 0000000 0000000 package stats_test
import (
"context"
"fmt"
"testing"
"time"
. "v2ray.com/core/app/stats"
"v2ray.com/core/common"
"v2ray.com/core/features/stats"
)
func TestStatsChannel(t *testing.T) {
// At most 2 subscribers could be registered
c := NewChannel(&ChannelConfig{SubscriberLimit: 2, Blocking: true})
a, err := stats.SubscribeRunnableChannel(c)
common.Must(err)
if !c.Running() {
t.Fatal("unexpected failure in running channel after first subscription")
}
b, err := c.Subscribe()
common.Must(err)
// Test that third subscriber is forbidden
_, err = c.Subscribe()
if err == nil {
t.Fatal("unexpected successful subscription")
}
t.Log("expected error: ", err)
stopCh := make(chan struct{})
errCh := make(chan string)
go func() {
c.Publish(context.Background(), 1)
c.Publish(context.Background(), 2)
c.Publish(context.Background(), "3")
c.Publish(context.Background(), []int{4})
stopCh <- struct{}{}
}()
go func() {
if v, ok := (<-a).(int); !ok || v != 1 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", 1)
}
if v, ok := (<-a).(int); !ok || v != 2 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", 2)
}
if v, ok := (<-a).(string); !ok || v != "3" {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", "3")
}
if v, ok := (<-a).([]int); !ok || v[0] != 4 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", []int{4})
}
stopCh <- struct{}{}
}()
go func() {
if v, ok := (<-b).(int); !ok || v != 1 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", 1)
}
if v, ok := (<-b).(int); !ok || v != 2 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", 2)
}
if v, ok := (<-b).(string); !ok || v != "3" {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", "3")
}
if v, ok := (<-b).([]int); !ok || v[0] != 4 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", []int{4})
}
stopCh <- struct{}{}
}()
timeout := time.After(2 * time.Second)
for i := 0; i < 3; i++ {
select {
case <-timeout:
t.Fatal("Test timeout after 2s")
case e := <-errCh:
t.Fatal(e)
case <-stopCh:
}
}
// Test the unsubscription of channel
common.Must(c.Unsubscribe(b))
// Test the last subscriber will close channel with `UnsubscribeClosableChannel`
common.Must(stats.UnsubscribeClosableChannel(c, a))
if c.Running() {
t.Fatal("unexpected running channel after unsubscribing the last subscriber")
}
}
func TestStatsChannelUnsubcribe(t *testing.T) {
c := NewChannel(&ChannelConfig{Blocking: true})
common.Must(c.Start())
defer c.Close()
a, err := c.Subscribe()
common.Must(err)
defer c.Unsubscribe(a)
b, err := c.Subscribe()
common.Must(err)
pauseCh := make(chan struct{})
stopCh := make(chan struct{})
errCh := make(chan string)
{
var aSet, bSet bool
for _, s := range c.Subscribers() {
if s == a {
aSet = true
}
if s == b {
bSet = true
}
}
if !(aSet && bSet) {
t.Fatal("unexpected subscribers: ", c.Subscribers())
}
}
go func() { // Blocking publish
c.Publish(context.Background(), 1)
<-pauseCh // Wait for `b` goroutine to resume sending message
c.Publish(context.Background(), 2)
}()
go func() {
if v, ok := (<-a).(int); !ok || v != 1 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", 1)
}
if v, ok := (<-a).(int); !ok || v != 2 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", 2)
}
}()
go func() {
if v, ok := (<-b).(int); !ok || v != 1 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", 1)
}
// Unsubscribe `b` while publishing is paused
c.Unsubscribe(b)
{ // Test `b` is not in subscribers
var aSet, bSet bool
for _, s := range c.Subscribers() {
if s == a {
aSet = true
}
if s == b {
bSet = true
}
}
if !(aSet && !bSet) {
errCh <- fmt.Sprint("unexpected subscribers: ", c.Subscribers())
}
}
// Resume publishing progress
close(pauseCh)
// Test `b` is neither closed nor able to receive any data
select {
case v, ok := <-b:
if ok {
errCh <- fmt.Sprint("unexpected data received: ", v)
} else {
errCh <- fmt.Sprint("unexpected closed channel: ", b)
}
default:
}
close(stopCh)
}()
select {
case <-time.After(2 * time.Second):
t.Fatal("Test timeout after 2s")
case e := <-errCh:
t.Fatal(e)
case <-stopCh:
}
}
func TestStatsChannelBlocking(t *testing.T) {
// Do not use buffer so as to create blocking scenario
c := NewChannel(&ChannelConfig{BufferSize: 0, Blocking: true})
common.Must(c.Start())
defer c.Close()
a, err := c.Subscribe()
common.Must(err)
defer c.Unsubscribe(a)
pauseCh := make(chan struct{})
stopCh := make(chan struct{})
errCh := make(chan string)
ctx, cancel := context.WithCancel(context.Background())
// Test blocking channel publishing
go func() {
// Dummy messsage with no subscriber receiving, will block broadcasting goroutine
c.Publish(context.Background(), nil)
<-pauseCh
// Publishing should be blocked here, for last message was not cleared and buffer was full
c.Publish(context.Background(), nil)
pauseCh <- struct{}{}
// Publishing should still be blocked here
c.Publish(ctx, nil)
// Check publishing is done because context is canceled
select {
case <-ctx.Done():
if ctx.Err() != context.Canceled {
errCh <- fmt.Sprint("unexpected error: ", ctx.Err())
}
default:
errCh <- "unexpected non-blocked publishing"
}
close(stopCh)
}()
go func() {
pauseCh <- struct{}{}
select {
case <-pauseCh:
errCh <- "unexpected non-blocked publishing"
case <-time.After(100 * time.Millisecond):
}
// Receive first published message
<-a
select {
case <-pauseCh:
case <-time.After(100 * time.Millisecond):
errCh <- "unexpected blocking publishing"
}
// Manually cancel the context to end publishing
cancel()
}()
select {
case <-time.After(2 * time.Second):
t.Fatal("Test timeout after 2s")
case e := <-errCh:
t.Fatal(e)
case <-stopCh:
}
}
func TestStatsChannelNonBlocking(t *testing.T) {
// Do not use buffer so as to create blocking scenario
c := NewChannel(&ChannelConfig{BufferSize: 0, Blocking: false})
common.Must(c.Start())
defer c.Close()
a, err := c.Subscribe()
common.Must(err)
defer c.Unsubscribe(a)
pauseCh := make(chan struct{})
stopCh := make(chan struct{})
errCh := make(chan string)
ctx, cancel := context.WithCancel(context.Background())
// Test blocking channel publishing
go func() {
c.Publish(context.Background(), nil)
c.Publish(context.Background(), nil)
pauseCh <- struct{}{}
<-pauseCh
c.Publish(ctx, nil)
c.Publish(ctx, nil)
// Check publishing is done because context is canceled
select {
case <-ctx.Done():
if ctx.Err() != context.Canceled {
errCh <- fmt.Sprint("unexpected error: ", ctx.Err())
}
case <-time.After(100 * time.Millisecond):
errCh <- "unexpected non-cancelled publishing"
}
}()
go func() {
// Check publishing won't block even if there is no subscriber receiving message
select {
case <-pauseCh:
case <-time.After(100 * time.Millisecond):
errCh <- "unexpected blocking publishing"
}
// Receive first and second published message
<-a
<-a
pauseCh <- struct{}{}
// Manually cancel the context to end publishing
cancel()
// Check third and forth published message is cancelled and cannot receive
<-time.After(100 * time.Millisecond)
select {
case <-a:
errCh <- "unexpected non-cancelled publishing"
default:
}
select {
case <-a:
errCh <- "unexpected non-cancelled publishing"
default:
}
close(stopCh)
}()
select {
case <-time.After(2 * time.Second):
t.Fatal("Test timeout after 2s")
case e := <-errCh:
t.Fatal(e)
case <-stopCh:
}
}
func TestStatsChannelConcurrency(t *testing.T) {
// Do not use buffer so as to create blocking scenario
c := NewChannel(&ChannelConfig{BufferSize: 0, Blocking: true})
common.Must(c.Start())
defer c.Close()
a, err := c.Subscribe()
common.Must(err)
defer c.Unsubscribe(a)
b, err := c.Subscribe()
common.Must(err)
defer c.Unsubscribe(b)
stopCh := make(chan struct{})
errCh := make(chan string)
go func() { // Blocking publish
c.Publish(context.Background(), 1)
c.Publish(context.Background(), 2)
}()
go func() {
if v, ok := (<-a).(int); !ok || v != 1 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", 1)
}
if v, ok := (<-a).(int); !ok || v != 2 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", 2)
}
}()
go func() {
// Block `b` for a time so as to ensure source channel is trying to send message to `b`.
<-time.After(25 * time.Millisecond)
// This causes concurrency scenario: unsubscribe `b` while trying to send message to it
c.Unsubscribe(b)
// Test `b` is not closed and can still receive data 1:
// Because unsubscribe won't affect the ongoing process of sending message.
select {
case v, ok := <-b:
if v1, ok1 := v.(int); !(ok && ok1 && v1 == 1) {
errCh <- fmt.Sprint("unexpected failure in receiving data: ", 1)
}
default:
errCh <- fmt.Sprint("unexpected block from receiving data: ", 1)
}
// Test `b` is not closed but cannot receive data 2:
// Because in a new round of messaging, `b` has been unsubscribed.
select {
case v, ok := <-b:
if ok {
errCh <- fmt.Sprint("unexpected receiving: ", v)
} else {
errCh <- "unexpected closing of channel"
}
default:
}
close(stopCh)
}()
select {
case <-time.After(2 * time.Second):
t.Fatal("Test timeout after 2s")
case e := <-errCh:
t.Fatal(e)
case <-stopCh:
}
}
v2ray-core-4.34.0/app/stats/command/ 0000775 0000000 0000000 00000000000 13774574720 0017147 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/app/stats/command/command.go 0000664 0000000 0000000 00000005422 13774574720 0021117 0 ustar 00root root 0000000 0000000 // +build !confonly
package command
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"runtime"
"time"
grpc "google.golang.org/grpc"
"v2ray.com/core"
"v2ray.com/core/app/stats"
"v2ray.com/core/common"
"v2ray.com/core/common/strmatcher"
feature_stats "v2ray.com/core/features/stats"
)
// statsServer is an implementation of StatsService.
type statsServer struct {
stats feature_stats.Manager
startTime time.Time
}
func NewStatsServer(manager feature_stats.Manager) StatsServiceServer {
return &statsServer{
stats: manager,
startTime: time.Now(),
}
}
func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {
c := s.stats.GetCounter(request.Name)
if c == nil {
return nil, newError(request.Name, " not found.")
}
var value int64
if request.Reset_ {
value = c.Set(0)
} else {
value = c.Value()
}
return &GetStatsResponse{
Stat: &Stat{
Name: request.Name,
Value: value,
},
}, nil
}
func (s *statsServer) QueryStats(ctx context.Context, request *QueryStatsRequest) (*QueryStatsResponse, error) {
matcher, err := strmatcher.Substr.New(request.Pattern)
if err != nil {
return nil, err
}
response := &QueryStatsResponse{}
manager, ok := s.stats.(*stats.Manager)
if !ok {
return nil, newError("QueryStats only works its own stats.Manager.")
}
manager.VisitCounters(func(name string, c feature_stats.Counter) bool {
if matcher.Match(name) {
var value int64
if request.Reset_ {
value = c.Set(0)
} else {
value = c.Value()
}
response.Stat = append(response.Stat, &Stat{
Name: name,
Value: value,
})
}
return true
})
return response, nil
}
func (s *statsServer) GetSysStats(ctx context.Context, request *SysStatsRequest) (*SysStatsResponse, error) {
var rtm runtime.MemStats
runtime.ReadMemStats(&rtm)
uptime := time.Since(s.startTime)
response := &SysStatsResponse{
Uptime: uint32(uptime.Seconds()),
NumGoroutine: uint32(runtime.NumGoroutine()),
Alloc: rtm.Alloc,
TotalAlloc: rtm.TotalAlloc,
Sys: rtm.Sys,
Mallocs: rtm.Mallocs,
Frees: rtm.Frees,
LiveObjects: rtm.Mallocs - rtm.Frees,
NumGC: rtm.NumGC,
PauseTotalNs: rtm.PauseTotalNs,
}
return response, nil
}
func (s *statsServer) mustEmbedUnimplementedStatsServiceServer() {}
type service struct {
statsManager feature_stats.Manager
}
func (s *service) Register(server *grpc.Server) {
RegisterStatsServiceServer(server, NewStatsServer(s.statsManager))
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
s := new(service)
core.RequireFeatures(ctx, func(sm feature_stats.Manager) {
s.statsManager = sm
})
return s, nil
}))
}
v2ray-core-4.34.0/app/stats/command/command.pb.go 0000664 0000000 0000000 00000061476 13774574720 0021532 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: app/stats/command/command.proto
package command
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type GetStatsRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Name of the stat counter.
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
// Whether or not to reset the counter to fetching its value.
Reset_ bool `protobuf:"varint,2,opt,name=reset,proto3" json:"reset,omitempty"`
}
func (x *GetStatsRequest) Reset() {
*x = GetStatsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_app_stats_command_command_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetStatsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetStatsRequest) ProtoMessage() {}
func (x *GetStatsRequest) ProtoReflect() protoreflect.Message {
mi := &file_app_stats_command_command_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetStatsRequest.ProtoReflect.Descriptor instead.
func (*GetStatsRequest) Descriptor() ([]byte, []int) {
return file_app_stats_command_command_proto_rawDescGZIP(), []int{0}
}
func (x *GetStatsRequest) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *GetStatsRequest) GetReset_() bool {
if x != nil {
return x.Reset_
}
return false
}
type Stat struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *Stat) Reset() {
*x = Stat{}
if protoimpl.UnsafeEnabled {
mi := &file_app_stats_command_command_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Stat) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Stat) ProtoMessage() {}
func (x *Stat) ProtoReflect() protoreflect.Message {
mi := &file_app_stats_command_command_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Stat.ProtoReflect.Descriptor instead.
func (*Stat) Descriptor() ([]byte, []int) {
return file_app_stats_command_command_proto_rawDescGZIP(), []int{1}
}
func (x *Stat) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *Stat) GetValue() int64 {
if x != nil {
return x.Value
}
return 0
}
type GetStatsResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Stat *Stat `protobuf:"bytes,1,opt,name=stat,proto3" json:"stat,omitempty"`
}
func (x *GetStatsResponse) Reset() {
*x = GetStatsResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_app_stats_command_command_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetStatsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetStatsResponse) ProtoMessage() {}
func (x *GetStatsResponse) ProtoReflect() protoreflect.Message {
mi := &file_app_stats_command_command_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetStatsResponse.ProtoReflect.Descriptor instead.
func (*GetStatsResponse) Descriptor() ([]byte, []int) {
return file_app_stats_command_command_proto_rawDescGZIP(), []int{2}
}
func (x *GetStatsResponse) GetStat() *Stat {
if x != nil {
return x.Stat
}
return nil
}
type QueryStatsRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Pattern string `protobuf:"bytes,1,opt,name=pattern,proto3" json:"pattern,omitempty"`
Reset_ bool `protobuf:"varint,2,opt,name=reset,proto3" json:"reset,omitempty"`
}
func (x *QueryStatsRequest) Reset() {
*x = QueryStatsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_app_stats_command_command_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *QueryStatsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*QueryStatsRequest) ProtoMessage() {}
func (x *QueryStatsRequest) ProtoReflect() protoreflect.Message {
mi := &file_app_stats_command_command_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use QueryStatsRequest.ProtoReflect.Descriptor instead.
func (*QueryStatsRequest) Descriptor() ([]byte, []int) {
return file_app_stats_command_command_proto_rawDescGZIP(), []int{3}
}
func (x *QueryStatsRequest) GetPattern() string {
if x != nil {
return x.Pattern
}
return ""
}
func (x *QueryStatsRequest) GetReset_() bool {
if x != nil {
return x.Reset_
}
return false
}
type QueryStatsResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Stat []*Stat `protobuf:"bytes,1,rep,name=stat,proto3" json:"stat,omitempty"`
}
func (x *QueryStatsResponse) Reset() {
*x = QueryStatsResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_app_stats_command_command_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *QueryStatsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*QueryStatsResponse) ProtoMessage() {}
func (x *QueryStatsResponse) ProtoReflect() protoreflect.Message {
mi := &file_app_stats_command_command_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use QueryStatsResponse.ProtoReflect.Descriptor instead.
func (*QueryStatsResponse) Descriptor() ([]byte, []int) {
return file_app_stats_command_command_proto_rawDescGZIP(), []int{4}
}
func (x *QueryStatsResponse) GetStat() []*Stat {
if x != nil {
return x.Stat
}
return nil
}
type SysStatsRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *SysStatsRequest) Reset() {
*x = SysStatsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_app_stats_command_command_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SysStatsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SysStatsRequest) ProtoMessage() {}
func (x *SysStatsRequest) ProtoReflect() protoreflect.Message {
mi := &file_app_stats_command_command_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SysStatsRequest.ProtoReflect.Descriptor instead.
func (*SysStatsRequest) Descriptor() ([]byte, []int) {
return file_app_stats_command_command_proto_rawDescGZIP(), []int{5}
}
type SysStatsResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
NumGoroutine uint32 `protobuf:"varint,1,opt,name=NumGoroutine,proto3" json:"NumGoroutine,omitempty"`
NumGC uint32 `protobuf:"varint,2,opt,name=NumGC,proto3" json:"NumGC,omitempty"`
Alloc uint64 `protobuf:"varint,3,opt,name=Alloc,proto3" json:"Alloc,omitempty"`
TotalAlloc uint64 `protobuf:"varint,4,opt,name=TotalAlloc,proto3" json:"TotalAlloc,omitempty"`
Sys uint64 `protobuf:"varint,5,opt,name=Sys,proto3" json:"Sys,omitempty"`
Mallocs uint64 `protobuf:"varint,6,opt,name=Mallocs,proto3" json:"Mallocs,omitempty"`
Frees uint64 `protobuf:"varint,7,opt,name=Frees,proto3" json:"Frees,omitempty"`
LiveObjects uint64 `protobuf:"varint,8,opt,name=LiveObjects,proto3" json:"LiveObjects,omitempty"`
PauseTotalNs uint64 `protobuf:"varint,9,opt,name=PauseTotalNs,proto3" json:"PauseTotalNs,omitempty"`
Uptime uint32 `protobuf:"varint,10,opt,name=Uptime,proto3" json:"Uptime,omitempty"`
}
func (x *SysStatsResponse) Reset() {
*x = SysStatsResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_app_stats_command_command_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SysStatsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SysStatsResponse) ProtoMessage() {}
func (x *SysStatsResponse) ProtoReflect() protoreflect.Message {
mi := &file_app_stats_command_command_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SysStatsResponse.ProtoReflect.Descriptor instead.
func (*SysStatsResponse) Descriptor() ([]byte, []int) {
return file_app_stats_command_command_proto_rawDescGZIP(), []int{6}
}
func (x *SysStatsResponse) GetNumGoroutine() uint32 {
if x != nil {
return x.NumGoroutine
}
return 0
}
func (x *SysStatsResponse) GetNumGC() uint32 {
if x != nil {
return x.NumGC
}
return 0
}
func (x *SysStatsResponse) GetAlloc() uint64 {
if x != nil {
return x.Alloc
}
return 0
}
func (x *SysStatsResponse) GetTotalAlloc() uint64 {
if x != nil {
return x.TotalAlloc
}
return 0
}
func (x *SysStatsResponse) GetSys() uint64 {
if x != nil {
return x.Sys
}
return 0
}
func (x *SysStatsResponse) GetMallocs() uint64 {
if x != nil {
return x.Mallocs
}
return 0
}
func (x *SysStatsResponse) GetFrees() uint64 {
if x != nil {
return x.Frees
}
return 0
}
func (x *SysStatsResponse) GetLiveObjects() uint64 {
if x != nil {
return x.LiveObjects
}
return 0
}
func (x *SysStatsResponse) GetPauseTotalNs() uint64 {
if x != nil {
return x.PauseTotalNs
}
return 0
}
func (x *SysStatsResponse) GetUptime() uint32 {
if x != nil {
return x.Uptime
}
return 0
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_stats_command_command_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_stats_command_command_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_stats_command_command_proto_rawDescGZIP(), []int{7}
}
var File_app_stats_command_command_proto protoreflect.FileDescriptor
var file_app_stats_command_command_proto_rawDesc = []byte{
0x0a, 0x1f, 0x61, 0x70, 0x70, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x1c, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22,
0x3b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x73, 0x65, 0x74, 0x18,
0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, 0x73, 0x65, 0x74, 0x22, 0x30, 0x0a, 0x04,
0x53, 0x74, 0x61, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4a,
0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x73, 0x74, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x22, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
0x53, 0x74, 0x61, 0x74, 0x52, 0x04, 0x73, 0x74, 0x61, 0x74, 0x22, 0x43, 0x0a, 0x11, 0x51, 0x75,
0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x73,
0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, 0x73, 0x65, 0x74, 0x22,
0x4c, 0x0a, 0x12, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x73, 0x74, 0x61, 0x74, 0x18, 0x01, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
0x6e, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x52, 0x04, 0x73, 0x74, 0x61, 0x74, 0x22, 0x11, 0x0a,
0x0f, 0x53, 0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x22, 0xa2, 0x02, 0x0a, 0x10, 0x53, 0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x4e, 0x75, 0x6d, 0x47, 0x6f, 0x72, 0x6f,
0x75, 0x74, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x4e, 0x75, 0x6d,
0x47, 0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4e, 0x75, 0x6d,
0x47, 0x43, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4e, 0x75, 0x6d, 0x47, 0x43, 0x12,
0x14, 0x0a, 0x05, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05,
0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x12, 0x1e, 0x0a, 0x0a, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c,
0x6c, 0x6f, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x54, 0x6f, 0x74, 0x61, 0x6c,
0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x12, 0x10, 0x0a, 0x03, 0x53, 0x79, 0x73, 0x18, 0x05, 0x20, 0x01,
0x28, 0x04, 0x52, 0x03, 0x53, 0x79, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x61, 0x6c, 0x6c, 0x6f,
0x63, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x4d, 0x61, 0x6c, 0x6c, 0x6f, 0x63,
0x73, 0x12, 0x14, 0x0a, 0x05, 0x46, 0x72, 0x65, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04,
0x52, 0x05, 0x46, 0x72, 0x65, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4c, 0x69, 0x76, 0x65, 0x4f,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x4c, 0x69,
0x76, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x50, 0x61, 0x75,
0x73, 0x65, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4e, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52,
0x0c, 0x50, 0x61, 0x75, 0x73, 0x65, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4e, 0x73, 0x12, 0x16, 0x0a,
0x06, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x55,
0x70, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32,
0xde, 0x02, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x12, 0x6b, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x2d, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74,
0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53,
0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61,
0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74,
0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x71, 0x0a,
0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x2f, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61,
0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79,
0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74,
0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x51, 0x75, 0x65, 0x72,
0x79, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
0x12, 0x6e, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12,
0x2d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53,
0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e,
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53, 0x79,
0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
0x42, 0x65, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x20, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73,
0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x1c, 0x56, 0x32, 0x52, 0x61, 0x79,
0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x2e,
0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_stats_command_command_proto_rawDescOnce sync.Once
file_app_stats_command_command_proto_rawDescData = file_app_stats_command_command_proto_rawDesc
)
func file_app_stats_command_command_proto_rawDescGZIP() []byte {
file_app_stats_command_command_proto_rawDescOnce.Do(func() {
file_app_stats_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_stats_command_command_proto_rawDescData)
})
return file_app_stats_command_command_proto_rawDescData
}
var file_app_stats_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_app_stats_command_command_proto_goTypes = []interface{}{
(*GetStatsRequest)(nil), // 0: v2ray.core.app.stats.command.GetStatsRequest
(*Stat)(nil), // 1: v2ray.core.app.stats.command.Stat
(*GetStatsResponse)(nil), // 2: v2ray.core.app.stats.command.GetStatsResponse
(*QueryStatsRequest)(nil), // 3: v2ray.core.app.stats.command.QueryStatsRequest
(*QueryStatsResponse)(nil), // 4: v2ray.core.app.stats.command.QueryStatsResponse
(*SysStatsRequest)(nil), // 5: v2ray.core.app.stats.command.SysStatsRequest
(*SysStatsResponse)(nil), // 6: v2ray.core.app.stats.command.SysStatsResponse
(*Config)(nil), // 7: v2ray.core.app.stats.command.Config
}
var file_app_stats_command_command_proto_depIdxs = []int32{
1, // 0: v2ray.core.app.stats.command.GetStatsResponse.stat:type_name -> v2ray.core.app.stats.command.Stat
1, // 1: v2ray.core.app.stats.command.QueryStatsResponse.stat:type_name -> v2ray.core.app.stats.command.Stat
0, // 2: v2ray.core.app.stats.command.StatsService.GetStats:input_type -> v2ray.core.app.stats.command.GetStatsRequest
3, // 3: v2ray.core.app.stats.command.StatsService.QueryStats:input_type -> v2ray.core.app.stats.command.QueryStatsRequest
5, // 4: v2ray.core.app.stats.command.StatsService.GetSysStats:input_type -> v2ray.core.app.stats.command.SysStatsRequest
2, // 5: v2ray.core.app.stats.command.StatsService.GetStats:output_type -> v2ray.core.app.stats.command.GetStatsResponse
4, // 6: v2ray.core.app.stats.command.StatsService.QueryStats:output_type -> v2ray.core.app.stats.command.QueryStatsResponse
6, // 7: v2ray.core.app.stats.command.StatsService.GetSysStats:output_type -> v2ray.core.app.stats.command.SysStatsResponse
5, // [5:8] is the sub-list for method output_type
2, // [2:5] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_app_stats_command_command_proto_init() }
func file_app_stats_command_command_proto_init() {
if File_app_stats_command_command_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_stats_command_command_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetStatsRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_stats_command_command_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Stat); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_stats_command_command_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetStatsResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_stats_command_command_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*QueryStatsRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_stats_command_command_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*QueryStatsResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_stats_command_command_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SysStatsRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_stats_command_command_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SysStatsResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_stats_command_command_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_stats_command_command_proto_rawDesc,
NumEnums: 0,
NumMessages: 8,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_app_stats_command_command_proto_goTypes,
DependencyIndexes: file_app_stats_command_command_proto_depIdxs,
MessageInfos: file_app_stats_command_command_proto_msgTypes,
}.Build()
File_app_stats_command_command_proto = out.File
file_app_stats_command_command_proto_rawDesc = nil
file_app_stats_command_command_proto_goTypes = nil
file_app_stats_command_command_proto_depIdxs = nil
}
v2ray-core-4.34.0/app/stats/command/command.proto 0000664 0000000 0000000 00000002237 13774574720 0021656 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.app.stats.command;
option csharp_namespace = "V2Ray.Core.App.Stats.Command";
option go_package = "v2ray.com/core/app/stats/command";
option java_package = "com.v2ray.core.app.stats.command";
option java_multiple_files = true;
message GetStatsRequest {
// Name of the stat counter.
string name = 1;
// Whether or not to reset the counter to fetching its value.
bool reset = 2;
}
message Stat {
string name = 1;
int64 value = 2;
}
message GetStatsResponse {
Stat stat = 1;
}
message QueryStatsRequest {
string pattern = 1;
bool reset = 2;
}
message QueryStatsResponse {
repeated Stat stat = 1;
}
message SysStatsRequest {}
message SysStatsResponse {
uint32 NumGoroutine = 1;
uint32 NumGC = 2;
uint64 Alloc = 3;
uint64 TotalAlloc = 4;
uint64 Sys = 5;
uint64 Mallocs = 6;
uint64 Frees = 7;
uint64 LiveObjects = 8;
uint64 PauseTotalNs = 9;
uint32 Uptime = 10;
}
service StatsService {
rpc GetStats(GetStatsRequest) returns (GetStatsResponse) {}
rpc QueryStats(QueryStatsRequest) returns (QueryStatsResponse) {}
rpc GetSysStats(SysStatsRequest) returns (SysStatsResponse) {}
}
message Config {}
v2ray-core-4.34.0/app/stats/command/command_grpc.pb.go 0000664 0000000 0000000 00000014362 13774574720 0022535 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package command
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion7
// StatsServiceClient is the client API for StatsService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type StatsServiceClient interface {
GetStats(ctx context.Context, in *GetStatsRequest, opts ...grpc.CallOption) (*GetStatsResponse, error)
QueryStats(ctx context.Context, in *QueryStatsRequest, opts ...grpc.CallOption) (*QueryStatsResponse, error)
GetSysStats(ctx context.Context, in *SysStatsRequest, opts ...grpc.CallOption) (*SysStatsResponse, error)
}
type statsServiceClient struct {
cc grpc.ClientConnInterface
}
func NewStatsServiceClient(cc grpc.ClientConnInterface) StatsServiceClient {
return &statsServiceClient{cc}
}
func (c *statsServiceClient) GetStats(ctx context.Context, in *GetStatsRequest, opts ...grpc.CallOption) (*GetStatsResponse, error) {
out := new(GetStatsResponse)
err := c.cc.Invoke(ctx, "/v2ray.core.app.stats.command.StatsService/GetStats", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *statsServiceClient) QueryStats(ctx context.Context, in *QueryStatsRequest, opts ...grpc.CallOption) (*QueryStatsResponse, error) {
out := new(QueryStatsResponse)
err := c.cc.Invoke(ctx, "/v2ray.core.app.stats.command.StatsService/QueryStats", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *statsServiceClient) GetSysStats(ctx context.Context, in *SysStatsRequest, opts ...grpc.CallOption) (*SysStatsResponse, error) {
out := new(SysStatsResponse)
err := c.cc.Invoke(ctx, "/v2ray.core.app.stats.command.StatsService/GetSysStats", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// StatsServiceServer is the server API for StatsService service.
// All implementations must embed UnimplementedStatsServiceServer
// for forward compatibility
type StatsServiceServer interface {
GetStats(context.Context, *GetStatsRequest) (*GetStatsResponse, error)
QueryStats(context.Context, *QueryStatsRequest) (*QueryStatsResponse, error)
GetSysStats(context.Context, *SysStatsRequest) (*SysStatsResponse, error)
mustEmbedUnimplementedStatsServiceServer()
}
// UnimplementedStatsServiceServer must be embedded to have forward compatible implementations.
type UnimplementedStatsServiceServer struct {
}
func (UnimplementedStatsServiceServer) GetStats(context.Context, *GetStatsRequest) (*GetStatsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetStats not implemented")
}
func (UnimplementedStatsServiceServer) QueryStats(context.Context, *QueryStatsRequest) (*QueryStatsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method QueryStats not implemented")
}
func (UnimplementedStatsServiceServer) GetSysStats(context.Context, *SysStatsRequest) (*SysStatsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetSysStats not implemented")
}
func (UnimplementedStatsServiceServer) mustEmbedUnimplementedStatsServiceServer() {}
// UnsafeStatsServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to StatsServiceServer will
// result in compilation errors.
type UnsafeStatsServiceServer interface {
mustEmbedUnimplementedStatsServiceServer()
}
func RegisterStatsServiceServer(s grpc.ServiceRegistrar, srv StatsServiceServer) {
s.RegisterService(&_StatsService_serviceDesc, srv)
}
func _StatsService_GetStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetStatsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StatsServiceServer).GetStats(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.stats.command.StatsService/GetStats",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StatsServiceServer).GetStats(ctx, req.(*GetStatsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _StatsService_QueryStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(QueryStatsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StatsServiceServer).QueryStats(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.stats.command.StatsService/QueryStats",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StatsServiceServer).QueryStats(ctx, req.(*QueryStatsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _StatsService_GetSysStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SysStatsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StatsServiceServer).GetSysStats(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.stats.command.StatsService/GetSysStats",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StatsServiceServer).GetSysStats(ctx, req.(*SysStatsRequest))
}
return interceptor(ctx, in, info, handler)
}
var _StatsService_serviceDesc = grpc.ServiceDesc{
ServiceName: "v2ray.core.app.stats.command.StatsService",
HandlerType: (*StatsServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetStats",
Handler: _StatsService_GetStats_Handler,
},
{
MethodName: "QueryStats",
Handler: _StatsService_QueryStats_Handler,
},
{
MethodName: "GetSysStats",
Handler: _StatsService_GetSysStats_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "app/stats/command/command.proto",
}
v2ray-core-4.34.0/app/stats/command/command_test.go 0000664 0000000 0000000 00000003463 13774574720 0022161 0 ustar 00root root 0000000 0000000 package command_test
import (
"context"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"v2ray.com/core/app/stats"
. "v2ray.com/core/app/stats/command"
"v2ray.com/core/common"
)
func TestGetStats(t *testing.T) {
m, err := stats.NewManager(context.Background(), &stats.Config{})
common.Must(err)
sc, err := m.RegisterCounter("test_counter")
common.Must(err)
sc.Set(1)
s := NewStatsServer(m)
testCases := []struct {
name string
reset bool
value int64
err bool
}{
{
name: "counterNotExist",
err: true,
},
{
name: "test_counter",
reset: true,
value: 1,
},
{
name: "test_counter",
value: 0,
},
}
for _, tc := range testCases {
resp, err := s.GetStats(context.Background(), &GetStatsRequest{
Name: tc.name,
Reset_: tc.reset,
})
if tc.err {
if err == nil {
t.Error("nil error: ", tc.name)
}
} else {
common.Must(err)
if r := cmp.Diff(resp.Stat, &Stat{Name: tc.name, Value: tc.value}, cmpopts.IgnoreUnexported(Stat{})); r != "" {
t.Error(r)
}
}
}
}
func TestQueryStats(t *testing.T) {
m, err := stats.NewManager(context.Background(), &stats.Config{})
common.Must(err)
sc1, err := m.RegisterCounter("test_counter")
common.Must(err)
sc1.Set(1)
sc2, err := m.RegisterCounter("test_counter_2")
common.Must(err)
sc2.Set(2)
sc3, err := m.RegisterCounter("test_counter_3")
common.Must(err)
sc3.Set(3)
s := NewStatsServer(m)
resp, err := s.QueryStats(context.Background(), &QueryStatsRequest{
Pattern: "counter_",
})
common.Must(err)
if r := cmp.Diff(resp.Stat, []*Stat{
{Name: "test_counter_2", Value: 2},
{Name: "test_counter_3", Value: 3},
}, cmpopts.SortSlices(func(s1, s2 *Stat) bool { return s1.Name < s2.Name }),
cmpopts.IgnoreUnexported(Stat{})); r != "" {
t.Error(r)
}
}
v2ray-core-4.34.0/app/stats/command/errors.generated.go 0000664 0000000 0000000 00000000315 13774574720 0022746 0 ustar 00root root 0000000 0000000 package command
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/app/stats/config.pb.go 0000664 0000000 0000000 00000016304 13774574720 0017731 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: app/stats/config.proto
package stats
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_stats_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_stats_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_stats_config_proto_rawDescGZIP(), []int{0}
}
type ChannelConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Blocking bool `protobuf:"varint,1,opt,name=Blocking,proto3" json:"Blocking,omitempty"`
SubscriberLimit int32 `protobuf:"varint,2,opt,name=SubscriberLimit,proto3" json:"SubscriberLimit,omitempty"`
BufferSize int32 `protobuf:"varint,3,opt,name=BufferSize,proto3" json:"BufferSize,omitempty"`
}
func (x *ChannelConfig) Reset() {
*x = ChannelConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_app_stats_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ChannelConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ChannelConfig) ProtoMessage() {}
func (x *ChannelConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_stats_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ChannelConfig.ProtoReflect.Descriptor instead.
func (*ChannelConfig) Descriptor() ([]byte, []int) {
return file_app_stats_config_proto_rawDescGZIP(), []int{1}
}
func (x *ChannelConfig) GetBlocking() bool {
if x != nil {
return x.Blocking
}
return false
}
func (x *ChannelConfig) GetSubscriberLimit() int32 {
if x != nil {
return x.SubscriberLimit
}
return 0
}
func (x *ChannelConfig) GetBufferSize() int32 {
if x != nil {
return x.BufferSize
}
return 0
}
var File_app_stats_config_proto protoreflect.FileDescriptor
var file_app_stats_config_proto_rawDesc = []byte{
0x0a, 0x16, 0x61, 0x70, 0x70, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x22, 0x08,
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x75, 0x0a, 0x0d, 0x43, 0x68, 0x61, 0x6e,
0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x6c, 0x6f,
0x63, 0x6b, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x42, 0x6c, 0x6f,
0x63, 0x6b, 0x69, 0x6e, 0x67, 0x12, 0x28, 0x0a, 0x0f, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
0x62, 0x65, 0x72, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f,
0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12,
0x1e, 0x0a, 0x0a, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0a, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x42,
0x4d, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x50, 0x01, 0x5a, 0x18, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
0x70, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0xaa, 0x02, 0x14, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,
0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_stats_config_proto_rawDescOnce sync.Once
file_app_stats_config_proto_rawDescData = file_app_stats_config_proto_rawDesc
)
func file_app_stats_config_proto_rawDescGZIP() []byte {
file_app_stats_config_proto_rawDescOnce.Do(func() {
file_app_stats_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_stats_config_proto_rawDescData)
})
return file_app_stats_config_proto_rawDescData
}
var file_app_stats_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_app_stats_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: v2ray.core.app.stats.Config
(*ChannelConfig)(nil), // 1: v2ray.core.app.stats.ChannelConfig
}
var file_app_stats_config_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_app_stats_config_proto_init() }
func file_app_stats_config_proto_init() {
if File_app_stats_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_stats_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_stats_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ChannelConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_stats_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_app_stats_config_proto_goTypes,
DependencyIndexes: file_app_stats_config_proto_depIdxs,
MessageInfos: file_app_stats_config_proto_msgTypes,
}.Build()
File_app_stats_config_proto = out.File
file_app_stats_config_proto_rawDesc = nil
file_app_stats_config_proto_goTypes = nil
file_app_stats_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/app/stats/config.proto 0000664 0000000 0000000 00000000541 13774574720 0020063 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.app.stats;
option csharp_namespace = "V2Ray.Core.App.Stats";
option go_package = "v2ray.com/core/app/stats";
option java_package = "com.v2ray.core.app.stats";
option java_multiple_files = true;
message Config {}
message ChannelConfig {
bool Blocking = 1;
int32 SubscriberLimit = 2;
int32 BufferSize = 3;
}
v2ray-core-4.34.0/app/stats/counter.go 0000664 0000000 0000000 00000000763 13774574720 0017545 0 ustar 00root root 0000000 0000000 // +build !confonly
package stats
import "sync/atomic"
// Counter is an implementation of stats.Counter.
type Counter struct {
value int64
}
// Value implements stats.Counter.
func (c *Counter) Value() int64 {
return atomic.LoadInt64(&c.value)
}
// Set implements stats.Counter.
func (c *Counter) Set(newValue int64) int64 {
return atomic.SwapInt64(&c.value, newValue)
}
// Add implements stats.Counter.
func (c *Counter) Add(delta int64) int64 {
return atomic.AddInt64(&c.value, delta)
}
v2ray-core-4.34.0/app/stats/counter_test.go 0000664 0000000 0000000 00000001167 13774574720 0020603 0 ustar 00root root 0000000 0000000 package stats_test
import (
"context"
"testing"
. "v2ray.com/core/app/stats"
"v2ray.com/core/common"
"v2ray.com/core/features/stats"
)
func TestStatsCounter(t *testing.T) {
raw, err := common.CreateObject(context.Background(), &Config{})
common.Must(err)
m := raw.(stats.Manager)
c, err := m.RegisterCounter("test.counter")
common.Must(err)
if v := c.Add(1); v != 1 {
t.Fatal("unpexcted Add(1) return: ", v, ", wanted ", 1)
}
if v := c.Set(0); v != 1 {
t.Fatal("unexpected Set(0) return: ", v, ", wanted ", 1)
}
if v := c.Value(); v != 0 {
t.Fatal("unexpected Value() return: ", v, ", wanted ", 0)
}
}
v2ray-core-4.34.0/app/stats/errors.generated.go 0000664 0000000 0000000 00000000313 13774574720 0021326 0 ustar 00root root 0000000 0000000 package stats
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/app/stats/stats.go 0000664 0000000 0000000 00000007417 13774574720 0017227 0 ustar 00root root 0000000 0000000 // +build !confonly
package stats
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"sync"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
"v2ray.com/core/features/stats"
)
// Manager is an implementation of stats.Manager.
type Manager struct {
access sync.RWMutex
counters map[string]*Counter
channels map[string]*Channel
running bool
}
// NewManager creates an instance of Statistics Manager.
func NewManager(ctx context.Context, config *Config) (*Manager, error) {
m := &Manager{
counters: make(map[string]*Counter),
channels: make(map[string]*Channel),
}
return m, nil
}
// Type implements common.HasType.
func (*Manager) Type() interface{} {
return stats.ManagerType()
}
// RegisterCounter implements stats.Manager.
func (m *Manager) RegisterCounter(name string) (stats.Counter, error) {
m.access.Lock()
defer m.access.Unlock()
if _, found := m.counters[name]; found {
return nil, newError("Counter ", name, " already registered.")
}
newError("create new counter ", name).AtDebug().WriteToLog()
c := new(Counter)
m.counters[name] = c
return c, nil
}
// UnregisterCounter implements stats.Manager.
func (m *Manager) UnregisterCounter(name string) error {
m.access.Lock()
defer m.access.Unlock()
if _, found := m.counters[name]; found {
newError("remove counter ", name).AtDebug().WriteToLog()
delete(m.counters, name)
}
return nil
}
// GetCounter implements stats.Manager.
func (m *Manager) GetCounter(name string) stats.Counter {
m.access.RLock()
defer m.access.RUnlock()
if c, found := m.counters[name]; found {
return c
}
return nil
}
// VisitCounters calls visitor function on all managed counters.
func (m *Manager) VisitCounters(visitor func(string, stats.Counter) bool) {
m.access.RLock()
defer m.access.RUnlock()
for name, c := range m.counters {
if !visitor(name, c) {
break
}
}
}
// RegisterChannel implements stats.Manager.
func (m *Manager) RegisterChannel(name string) (stats.Channel, error) {
m.access.Lock()
defer m.access.Unlock()
if _, found := m.channels[name]; found {
return nil, newError("Channel ", name, " already registered.")
}
newError("create new channel ", name).AtDebug().WriteToLog()
c := NewChannel(&ChannelConfig{BufferSize: 64, Blocking: false})
m.channels[name] = c
if m.running {
return c, c.Start()
}
return c, nil
}
// UnregisterChannel implements stats.Manager.
func (m *Manager) UnregisterChannel(name string) error {
m.access.Lock()
defer m.access.Unlock()
if c, found := m.channels[name]; found {
newError("remove channel ", name).AtDebug().WriteToLog()
delete(m.channels, name)
return c.Close()
}
return nil
}
// GetChannel implements stats.Manager.
func (m *Manager) GetChannel(name string) stats.Channel {
m.access.RLock()
defer m.access.RUnlock()
if c, found := m.channels[name]; found {
return c
}
return nil
}
// Start implements common.Runnable.
func (m *Manager) Start() error {
m.access.Lock()
defer m.access.Unlock()
m.running = true
errs := []error{}
for _, channel := range m.channels {
if err := channel.Start(); err != nil {
errs = append(errs, err)
}
}
if len(errs) != 0 {
return errors.Combine(errs...)
}
return nil
}
// Close implement common.Closable.
func (m *Manager) Close() error {
m.access.Lock()
defer m.access.Unlock()
m.running = false
errs := []error{}
for name, channel := range m.channels {
newError("remove channel ", name).AtDebug().WriteToLog()
delete(m.channels, name)
if err := channel.Close(); err != nil {
errs = append(errs, err)
}
}
if len(errs) != 0 {
return errors.Combine(errs...)
}
return nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewManager(ctx, config.(*Config))
}))
}
v2ray-core-4.34.0/app/stats/stats_test.go 0000664 0000000 0000000 00000003663 13774574720 0020265 0 ustar 00root root 0000000 0000000 package stats_test
import (
"context"
"testing"
"time"
. "v2ray.com/core/app/stats"
"v2ray.com/core/common"
"v2ray.com/core/features/stats"
)
func TestInterface(t *testing.T) {
_ = (stats.Manager)(new(Manager))
}
func TestStatsChannelRunnable(t *testing.T) {
raw, err := common.CreateObject(context.Background(), &Config{})
common.Must(err)
m := raw.(stats.Manager)
ch1, err := m.RegisterChannel("test.channel.1")
c1 := ch1.(*Channel)
common.Must(err)
if c1.Running() {
t.Fatalf("unexpected running channel: test.channel.%d", 1)
}
common.Must(m.Start())
if !c1.Running() {
t.Fatalf("unexpected non-running channel: test.channel.%d", 1)
}
ch2, err := m.RegisterChannel("test.channel.2")
c2 := ch2.(*Channel)
common.Must(err)
if !c2.Running() {
t.Fatalf("unexpected non-running channel: test.channel.%d", 2)
}
s1, err := c1.Subscribe()
common.Must(err)
common.Must(c1.Close())
if c1.Running() {
t.Fatalf("unexpected running channel: test.channel.%d", 1)
}
select { // Check all subscribers in closed channel are closed
case _, ok := <-s1:
if ok {
t.Fatalf("unexpected non-closed subscriber in channel: test.channel.%d", 1)
}
case <-time.After(500 * time.Millisecond):
t.Fatalf("unexpected non-closed subscriber in channel: test.channel.%d", 1)
}
if len(c1.Subscribers()) != 0 { // Check subscribers in closed channel are emptied
t.Fatalf("unexpected non-empty subscribers in channel: test.channel.%d", 1)
}
common.Must(m.Close())
if c2.Running() {
t.Fatalf("unexpected running channel: test.channel.%d", 2)
}
ch3, err := m.RegisterChannel("test.channel.3")
c3 := ch3.(*Channel)
common.Must(err)
if c3.Running() {
t.Fatalf("unexpected running channel: test.channel.%d", 3)
}
common.Must(c3.Start())
common.Must(m.UnregisterChannel("test.channel.3"))
if c3.Running() { // Test that unregistering will close the channel.
t.Fatalf("unexpected running channel: test.channel.%d", 3)
}
}
v2ray-core-4.34.0/common/ 0000775 0000000 0000000 00000000000 13774574720 0015103 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/antireplay/ 0000775 0000000 0000000 00000000000 13774574720 0017253 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/antireplay/replayfilter.go 0000664 0000000 0000000 00000002452 13774574720 0022307 0 ustar 00root root 0000000 0000000 package antireplay
import (
"sync"
"time"
cuckoo "github.com/seiflotfy/cuckoofilter"
)
const replayFilterCapacity = 100000
// ReplayFilter check for replay attacks.
type ReplayFilter struct {
lock sync.Mutex
poolA *cuckoo.Filter
poolB *cuckoo.Filter
poolSwap bool
lastSwap int64
interval int64
}
// NewReplayFilter create a new filter with specifying the expiration time interval in seconds.
func NewReplayFilter(interval int64) *ReplayFilter {
filter := &ReplayFilter{}
filter.interval = interval
return filter
}
// Interval in second for expiration time for duplicate records.
func (filter *ReplayFilter) Interval() int64 {
return filter.interval
}
// Check determine if there are duplicate records.
func (filter *ReplayFilter) Check(sum []byte) bool {
filter.lock.Lock()
defer filter.lock.Unlock()
now := time.Now().Unix()
if filter.lastSwap == 0 {
filter.lastSwap = now
filter.poolA = cuckoo.NewFilter(replayFilterCapacity)
filter.poolB = cuckoo.NewFilter(replayFilterCapacity)
}
elapsed := now - filter.lastSwap
if elapsed >= filter.Interval() {
if filter.poolSwap {
filter.poolA.Reset()
} else {
filter.poolB.Reset()
}
filter.poolSwap = !filter.poolSwap
filter.lastSwap = now
}
return filter.poolA.InsertUnique(sum) && filter.poolB.InsertUnique(sum)
}
v2ray-core-4.34.0/common/bitmask/ 0000775 0000000 0000000 00000000000 13774574720 0016535 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/bitmask/byte.go 0000664 0000000 0000000 00000000476 13774574720 0020036 0 ustar 00root root 0000000 0000000 package bitmask
// Byte is a bitmask in byte.
type Byte byte
// Has returns true if this bitmask contains another bitmask.
func (b Byte) Has(bb Byte) bool {
return (b & bb) != 0
}
func (b *Byte) Set(bb Byte) {
*b |= bb
}
func (b *Byte) Clear(bb Byte) {
*b &= ^bb
}
func (b *Byte) Toggle(bb Byte) {
*b ^= bb
}
v2ray-core-4.34.0/common/bitmask/byte_test.go 0000664 0000000 0000000 00000001264 13774574720 0021071 0 ustar 00root root 0000000 0000000 package bitmask_test
import (
"testing"
. "v2ray.com/core/common/bitmask"
)
func TestBitmaskByte(t *testing.T) {
b := Byte(0)
b.Set(Byte(1))
if !b.Has(1) {
t.Fatal("expected ", b, " to contain 1, but actually not")
}
b.Set(Byte(2))
if !b.Has(2) {
t.Fatal("expected ", b, " to contain 2, but actually not")
}
if !b.Has(1) {
t.Fatal("expected ", b, " to contain 1, but actually not")
}
b.Clear(Byte(1))
if !b.Has(2) {
t.Fatal("expected ", b, " to contain 2, but actually not")
}
if b.Has(1) {
t.Fatal("expected ", b, " to not contain 1, but actually did")
}
b.Toggle(Byte(2))
if b.Has(2) {
t.Fatal("expected ", b, " to not contain 2, but actually did")
}
}
v2ray-core-4.34.0/common/buf/ 0000775 0000000 0000000 00000000000 13774574720 0015657 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/buf/buf.go 0000664 0000000 0000000 00000000262 13774574720 0016762 0 ustar 00root root 0000000 0000000 // Package buf provides a light-weight memory allocation mechanism.
package buf // import "v2ray.com/core/common/buf"
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/common/buf/buffer.go 0000664 0000000 0000000 00000010663 13774574720 0017465 0 ustar 00root root 0000000 0000000 package buf
import (
"io"
"v2ray.com/core/common/bytespool"
)
const (
// Size of a regular buffer.
Size = 2048
)
var pool = bytespool.GetPool(Size)
// Buffer is a recyclable allocation of a byte array. Buffer.Release() recycles
// the buffer into an internal buffer pool, in order to recreate a buffer more
// quickly.
type Buffer struct {
v []byte
start int32
end int32
}
// New creates a Buffer with 0 length and 2K capacity.
func New() *Buffer {
return &Buffer{
v: pool.Get().([]byte),
}
}
// StackNew creates a new Buffer object on stack.
// This method is for buffers that is released in the same function.
func StackNew() Buffer {
return Buffer{
v: pool.Get().([]byte),
}
}
// Release recycles the buffer into an internal buffer pool.
func (b *Buffer) Release() {
if b == nil || b.v == nil {
return
}
p := b.v
b.v = nil
b.Clear()
pool.Put(p) // nolint: staticcheck
}
// Clear clears the content of the buffer, results an empty buffer with
// Len() = 0.
func (b *Buffer) Clear() {
b.start = 0
b.end = 0
}
// Byte returns the bytes at index.
func (b *Buffer) Byte(index int32) byte {
return b.v[b.start+index]
}
// SetByte sets the byte value at index.
func (b *Buffer) SetByte(index int32, value byte) {
b.v[b.start+index] = value
}
// Bytes returns the content bytes of this Buffer.
func (b *Buffer) Bytes() []byte {
return b.v[b.start:b.end]
}
// Extend increases the buffer size by n bytes, and returns the extended part.
// It panics if result size is larger than buf.Size.
func (b *Buffer) Extend(n int32) []byte {
end := b.end + n
if end > int32(len(b.v)) {
panic("extending out of bound")
}
ext := b.v[b.end:end]
b.end = end
return ext
}
// BytesRange returns a slice of this buffer with given from and to boundary.
func (b *Buffer) BytesRange(from, to int32) []byte {
if from < 0 {
from += b.Len()
}
if to < 0 {
to += b.Len()
}
return b.v[b.start+from : b.start+to]
}
// BytesFrom returns a slice of this Buffer starting from the given position.
func (b *Buffer) BytesFrom(from int32) []byte {
if from < 0 {
from += b.Len()
}
return b.v[b.start+from : b.end]
}
// BytesTo returns a slice of this Buffer from start to the given position.
func (b *Buffer) BytesTo(to int32) []byte {
if to < 0 {
to += b.Len()
}
return b.v[b.start : b.start+to]
}
// Resize cuts the buffer at the given position.
func (b *Buffer) Resize(from, to int32) {
if from < 0 {
from += b.Len()
}
if to < 0 {
to += b.Len()
}
if to < from {
panic("Invalid slice")
}
b.end = b.start + to
b.start += from
}
// Advance cuts the buffer at the given position.
func (b *Buffer) Advance(from int32) {
if from < 0 {
from += b.Len()
}
b.start += from
}
// Len returns the length of the buffer content.
func (b *Buffer) Len() int32 {
if b == nil {
return 0
}
return b.end - b.start
}
// IsEmpty returns true if the buffer is empty.
func (b *Buffer) IsEmpty() bool {
return b.Len() == 0
}
// IsFull returns true if the buffer has no more room to grow.
func (b *Buffer) IsFull() bool {
return b != nil && b.end == int32(len(b.v))
}
// Write implements Write method in io.Writer.
func (b *Buffer) Write(data []byte) (int, error) {
nBytes := copy(b.v[b.end:], data)
b.end += int32(nBytes)
return nBytes, nil
}
// WriteByte writes a single byte into the buffer.
func (b *Buffer) WriteByte(v byte) error {
if b.IsFull() {
return newError("buffer full")
}
b.v[b.end] = v
b.end++
return nil
}
// WriteString implements io.StringWriter.
func (b *Buffer) WriteString(s string) (int, error) {
return b.Write([]byte(s))
}
// Read implements io.Reader.Read().
func (b *Buffer) Read(data []byte) (int, error) {
if b.Len() == 0 {
return 0, io.EOF
}
nBytes := copy(data, b.v[b.start:b.end])
if int32(nBytes) == b.Len() {
b.Clear()
} else {
b.start += int32(nBytes)
}
return nBytes, nil
}
// ReadFrom implements io.ReaderFrom.
func (b *Buffer) ReadFrom(reader io.Reader) (int64, error) {
n, err := reader.Read(b.v[b.end:])
b.end += int32(n)
return int64(n), err
}
// ReadFullFrom reads exact size of bytes from given reader, or until error occurs.
func (b *Buffer) ReadFullFrom(reader io.Reader, size int32) (int64, error) {
end := b.end + size
if end > int32(len(b.v)) {
v := end
return 0, newError("out of bound: ", v)
}
n, err := io.ReadFull(reader, b.v[b.end:end])
b.end += int32(n)
return int64(n), err
}
// String returns the string form of this Buffer.
func (b *Buffer) String() string {
return string(b.Bytes())
}
v2ray-core-4.34.0/common/buf/buffer_test.go 0000664 0000000 0000000 00000010561 13774574720 0020521 0 ustar 00root root 0000000 0000000 package buf_test
import (
"bytes"
"crypto/rand"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
. "v2ray.com/core/common/buf"
)
func TestBufferClear(t *testing.T) {
buffer := New()
defer buffer.Release()
payload := "Bytes"
buffer.Write([]byte(payload))
if diff := cmp.Diff(buffer.Bytes(), []byte(payload)); diff != "" {
t.Error(diff)
}
buffer.Clear()
if buffer.Len() != 0 {
t.Error("expect 0 length, but got ", buffer.Len())
}
}
func TestBufferIsEmpty(t *testing.T) {
buffer := New()
defer buffer.Release()
if buffer.IsEmpty() != true {
t.Error("expect empty buffer, but not")
}
}
func TestBufferString(t *testing.T) {
buffer := New()
defer buffer.Release()
const payload = "Test String"
common.Must2(buffer.WriteString(payload))
if buffer.String() != payload {
t.Error("expect buffer content as ", payload, " but actually ", buffer.String())
}
}
func TestBufferByte(t *testing.T) {
{
buffer := New()
common.Must(buffer.WriteByte('m'))
if buffer.String() != "m" {
t.Error("expect buffer content as ", "m", " but actually ", buffer.String())
}
buffer.Release()
}
{
buffer := StackNew()
common.Must(buffer.WriteByte('n'))
if buffer.String() != "n" {
t.Error("expect buffer content as ", "n", " but actually ", buffer.String())
}
buffer.Release()
}
{
buffer := StackNew()
common.Must2(buffer.WriteString("HELLOWORLD"))
if b := buffer.Byte(5); b != 'W' {
t.Error("unexpected byte ", b)
}
buffer.SetByte(5, 'M')
if buffer.String() != "HELLOMORLD" {
t.Error("expect buffer content as ", "n", " but actually ", buffer.String())
}
buffer.Release()
}
}
func TestBufferResize(t *testing.T) {
buffer := New()
defer buffer.Release()
const payload = "Test String"
common.Must2(buffer.WriteString(payload))
if buffer.String() != payload {
t.Error("expect buffer content as ", payload, " but actually ", buffer.String())
}
buffer.Resize(-6, -3)
if l := buffer.Len(); int(l) != 3 {
t.Error("len error ", l)
}
if s := buffer.String(); s != "Str" {
t.Error("unexpect buffer ", s)
}
buffer.Resize(int32(len(payload)), 200)
if l := buffer.Len(); int(l) != 200-len(payload) {
t.Error("len error ", l)
}
}
func TestBufferSlice(t *testing.T) {
{
b := New()
common.Must2(b.Write([]byte("abcd")))
bytes := b.BytesFrom(-2)
if diff := cmp.Diff(bytes, []byte{'c', 'd'}); diff != "" {
t.Error(diff)
}
}
{
b := New()
common.Must2(b.Write([]byte("abcd")))
bytes := b.BytesTo(-2)
if diff := cmp.Diff(bytes, []byte{'a', 'b'}); diff != "" {
t.Error(diff)
}
}
{
b := New()
common.Must2(b.Write([]byte("abcd")))
bytes := b.BytesRange(-3, -1)
if diff := cmp.Diff(bytes, []byte{'b', 'c'}); diff != "" {
t.Error(diff)
}
}
}
func TestBufferReadFullFrom(t *testing.T) {
payload := make([]byte, 1024)
common.Must2(rand.Read(payload))
reader := bytes.NewReader(payload)
b := New()
n, err := b.ReadFullFrom(reader, 1024)
common.Must(err)
if n != 1024 {
t.Error("expect reading 1024 bytes, but actually ", n)
}
if diff := cmp.Diff(payload, b.Bytes()); diff != "" {
t.Error(diff)
}
}
func BenchmarkNewBuffer(b *testing.B) {
for i := 0; i < b.N; i++ {
buffer := New()
buffer.Release()
}
}
func BenchmarkNewBufferStack(b *testing.B) {
for i := 0; i < b.N; i++ {
buffer := StackNew()
buffer.Release()
}
}
func BenchmarkWrite2(b *testing.B) {
buffer := New()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = buffer.Write([]byte{'a', 'b'})
buffer.Clear()
}
}
func BenchmarkWrite8(b *testing.B) {
buffer := New()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = buffer.Write([]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'})
buffer.Clear()
}
}
func BenchmarkWrite32(b *testing.B) {
buffer := New()
payload := make([]byte, 32)
rand.Read(payload)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = buffer.Write(payload)
buffer.Clear()
}
}
func BenchmarkWriteByte2(b *testing.B) {
buffer := New()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = buffer.WriteByte('a')
_ = buffer.WriteByte('b')
buffer.Clear()
}
}
func BenchmarkWriteByte8(b *testing.B) {
buffer := New()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = buffer.WriteByte('a')
_ = buffer.WriteByte('b')
_ = buffer.WriteByte('c')
_ = buffer.WriteByte('d')
_ = buffer.WriteByte('e')
_ = buffer.WriteByte('f')
_ = buffer.WriteByte('g')
_ = buffer.WriteByte('h')
buffer.Clear()
}
}
v2ray-core-4.34.0/common/buf/copy.go 0000664 0000000 0000000 00000005115 13774574720 0017162 0 ustar 00root root 0000000 0000000 package buf
import (
"io"
"time"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/signal"
)
type dataHandler func(MultiBuffer)
type copyHandler struct {
onData []dataHandler
}
// SizeCounter is for counting bytes copied by Copy().
type SizeCounter struct {
Size int64
}
// CopyOption is an option for copying data.
type CopyOption func(*copyHandler)
// UpdateActivity is a CopyOption to update activity on each data copy operation.
func UpdateActivity(timer signal.ActivityUpdater) CopyOption {
return func(handler *copyHandler) {
handler.onData = append(handler.onData, func(MultiBuffer) {
timer.Update()
})
}
}
// CountSize is a CopyOption that sums the total size of data copied into the given SizeCounter.
func CountSize(sc *SizeCounter) CopyOption {
return func(handler *copyHandler) {
handler.onData = append(handler.onData, func(b MultiBuffer) {
sc.Size += int64(b.Len())
})
}
}
type readError struct {
error
}
func (e readError) Error() string {
return e.error.Error()
}
func (e readError) Inner() error {
return e.error
}
// IsReadError returns true if the error in Copy() comes from reading.
func IsReadError(err error) bool {
_, ok := err.(readError)
return ok
}
type writeError struct {
error
}
func (e writeError) Error() string {
return e.error.Error()
}
func (e writeError) Inner() error {
return e.error
}
// IsWriteError returns true if the error in Copy() comes from writing.
func IsWriteError(err error) bool {
_, ok := err.(writeError)
return ok
}
func copyInternal(reader Reader, writer Writer, handler *copyHandler) error {
for {
buffer, err := reader.ReadMultiBuffer()
if !buffer.IsEmpty() {
for _, handler := range handler.onData {
handler(buffer)
}
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
return writeError{werr}
}
}
if err != nil {
return readError{err}
}
}
}
// Copy dumps all payload from reader to writer or stops when an error occurs. It returns nil when EOF.
func Copy(reader Reader, writer Writer, options ...CopyOption) error {
var handler copyHandler
for _, option := range options {
option(&handler)
}
err := copyInternal(reader, writer, &handler)
if err != nil && errors.Cause(err) != io.EOF {
return err
}
return nil
}
var ErrNotTimeoutReader = newError("not a TimeoutReader")
func CopyOnceTimeout(reader Reader, writer Writer, timeout time.Duration) error {
timeoutReader, ok := reader.(TimeoutReader)
if !ok {
return ErrNotTimeoutReader
}
mb, err := timeoutReader.ReadMultiBufferTimeout(timeout)
if err != nil {
return err
}
return writer.WriteMultiBuffer(mb)
}
v2ray-core-4.34.0/common/buf/copy_test.go 0000664 0000000 0000000 00000002717 13774574720 0020226 0 ustar 00root root 0000000 0000000 package buf_test
import (
"crypto/rand"
"io"
"testing"
"github.com/golang/mock/gomock"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
"v2ray.com/core/testing/mocks"
)
func TestReadError(t *testing.T) {
mockCtl := gomock.NewController(t)
defer mockCtl.Finish()
mockReader := mocks.NewReader(mockCtl)
mockReader.EXPECT().Read(gomock.Any()).Return(0, errors.New("error"))
err := buf.Copy(buf.NewReader(mockReader), buf.Discard)
if err == nil {
t.Fatal("expected error, but nil")
}
if !buf.IsReadError(err) {
t.Error("expected to be ReadError, but not")
}
if err.Error() != "error" {
t.Fatal("unexpected error message: ", err.Error())
}
}
func TestWriteError(t *testing.T) {
mockCtl := gomock.NewController(t)
defer mockCtl.Finish()
mockWriter := mocks.NewWriter(mockCtl)
mockWriter.EXPECT().Write(gomock.Any()).Return(0, errors.New("error"))
err := buf.Copy(buf.NewReader(rand.Reader), buf.NewWriter(mockWriter))
if err == nil {
t.Fatal("expected error, but nil")
}
if !buf.IsWriteError(err) {
t.Error("expected to be WriteError, but not")
}
if err.Error() != "error" {
t.Fatal("unexpected error message: ", err.Error())
}
}
type TestReader struct{}
func (TestReader) Read(b []byte) (int, error) {
return len(b), nil
}
func BenchmarkCopy(b *testing.B) {
reader := buf.NewReader(io.LimitReader(TestReader{}, 10240))
writer := buf.Discard
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = buf.Copy(reader, writer)
}
}
v2ray-core-4.34.0/common/buf/data/ 0000775 0000000 0000000 00000000000 13774574720 0016570 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/buf/data/test_MultiBufferReadAllToByte.dat 0000664 0000000 0000000 00000004417 13774574720 0025127 0 ustar 00root root 0000000 0000000
???8+?$??I????+??????+?+++?IO7$ZD88ZDMD8OZ$7II7+++++++++++++
+??7++???I????????+?+++?+I?IZI$OND7ODDDDDD7Z$IZI++++++++++++
???I????????????~,...~?++I?777$DD8O8DDD88O$O7$7I++++++++++?+
???????????????.,::~...,+?I77ZZD8ZDNDDDDD8ZZ7$$7+++++++?+?+?
??????????????.,,:~~~==,I?7$$ZOD8ODNDD8DDZ$87777++?+++?????+
?????????I?=...:~~~~=~=+I?$$ZODD88ND8N8DDOZOZ77?????++??????
???II?????.,,,:==~~===I?IIZ$O$88ODD8ODNDDDOO$7$??I?++?++++??
???I????+..,,~=+???+?????7OOZZ8O$$778DDDDDO87I$I++++++++????
I??????..,,:~=??????+=,~?ZZZ$$I??II$DDDDD8Z8I~,+=?II$777IIII
II???,.,,::~??I?I?....,,~==I?+===+?$ODN8DD$O=,......+?????II
I?I?..,,:~~????,...,,::::~~~~~~~~=+$88ODD88=~,,,.......IIIII
II,..,,:~~I?:..,,,::::~~~~~~~~~~~~~+IOZ87?~~~::::,,,,...=?II
I,...,:::....,:::::::~~~~~~~~~~~~~~~=++=~~~~~~~~~~~:::,,,?II
,,,,~....,,,::::::::::::::~~~~~~~~~~~~~~~~~~~~~~~~~~~::,,,??
:~:...,,,:::::::::::::::::::~~~~~~~~~~~~~~~~~~~~~~~~~~::,,II
:::::::::::::::::::~+++::::::~~~~~~~~~~~~~~~~~~~~~~~~::::,,7
::::::::::::::~IIII?????:::::::~~~~~~~~~~~~~~~~~~~~~::::::,I
:,,,,,,,:+ZIIIIIIIIIIIII:::~::~~~~~~~~~~~~~~~~~~~~=~::::::::
7I777IIZI7ZIIIIIIIIIIII7?:~~~~~~~~~~~~~~~~~~~~~~~~~=~:::::::
$$$77$7Z77$7I77IIII7III$$:~~~~~~~~~~~~~~~~~~~~~~~=II~:::::::
$$$8$Z7$7$Z777777777777Z7~:~~~~~~~~~~~~~~~~~~~~~~$777::::::,
ZOZOZOZZ$7$$ZZ$8DDDZ777$$=~~~~~~~~~~~~~~~~~~~~~~~$$$7~:::::,
OOZOOOZZOOZO$ZZZ$O$$$$7ZZ$~~~~~~~~~~~~~~~~~~~~~~~ZZ$ZZ:::::,
O88OOOOO8ODOZZZZZOOZ8OOOOO:~~~~~~~~~~~~~~~~~~~~~ZOZZZZ~:::::
8888O8OODZ8ZOZOZZOOZOOOOOZ:::~~~~~~~~~~~~~~~~~~~,Z$ZOOO:::::
Z88O88D8Z88ZZOOZZOZ$$Z$$OZ:::~~~~~~~~~~~~~~~~~~~,,ZOOOOO::::
888D88OODD8DNDNDNNDDDD88OI:::::~~~~~~~~~~~~~~~~~.,:8ZO8O::::
D8D88DO88ZOOZOO8DDDNOZ$$O8~::::~~~~~~~~~~~~~===~..,88O8OO:::
8OD8O8OODO$D8DO88DO8O8888O~~::~~::~~~~~~~~~~~===...:8OOOZ~::
:..................,~,..~,~~:~:~~~~~~~~~~~~~~===...,+.....~~
.........................~~~:~~~~~~~~~~~~~~~~~==:..,......:~
.Made with love.........,~~~~~~~~:~~~~::~~~~~~~==..,,......:
........................~~~~~~~~~~~~~~:~~~~~~~~===,.,......~
...................,,..~~~~~~~~~~~~~~~~~~~~~~~~~==~,,.......
..................,,::~~~~~~~~~~~~~~~~~~~~~~~~~====~.,....,.
....................:~~~~~~~~~~~~~~~~~~~~~~~~~~~~==~:......,
......................,~================,.==~~~=~===~,......
.Thank you for your support.....................:~=,,,,,,,..
v2ray-core-4.34.0/common/buf/errors.generated.go 0000664 0000000 0000000 00000000311 13774574720 0021452 0 ustar 00root root 0000000 0000000 package buf
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/common/buf/io.go 0000664 0000000 0000000 00000004636 13774574720 0016626 0 ustar 00root root 0000000 0000000 package buf
import (
"io"
"net"
"os"
"syscall"
"time"
)
// Reader extends io.Reader with MultiBuffer.
type Reader interface {
// ReadMultiBuffer reads content from underlying reader, and put it into a MultiBuffer.
ReadMultiBuffer() (MultiBuffer, error)
}
// ErrReadTimeout is an error that happens with IO timeout.
var ErrReadTimeout = newError("IO timeout")
// TimeoutReader is a reader that returns error if Read() operation takes longer than the given timeout.
type TimeoutReader interface {
ReadMultiBufferTimeout(time.Duration) (MultiBuffer, error)
}
// Writer extends io.Writer with MultiBuffer.
type Writer interface {
// WriteMultiBuffer writes a MultiBuffer into underlying writer.
WriteMultiBuffer(MultiBuffer) error
}
// WriteAllBytes ensures all bytes are written into the given writer.
func WriteAllBytes(writer io.Writer, payload []byte) error {
for len(payload) > 0 {
n, err := writer.Write(payload)
if err != nil {
return err
}
payload = payload[n:]
}
return nil
}
func isPacketReader(reader io.Reader) bool {
_, ok := reader.(net.PacketConn)
return ok
}
// NewReader creates a new Reader.
// The Reader instance doesn't take the ownership of reader.
func NewReader(reader io.Reader) Reader {
if mr, ok := reader.(Reader); ok {
return mr
}
if isPacketReader(reader) {
return &PacketReader{
Reader: reader,
}
}
_, isFile := reader.(*os.File)
if !isFile && useReadv {
if sc, ok := reader.(syscall.Conn); ok {
rawConn, err := sc.SyscallConn()
if err != nil {
newError("failed to get sysconn").Base(err).WriteToLog()
} else {
return NewReadVReader(reader, rawConn)
}
}
}
return &SingleReader{
Reader: reader,
}
}
// NewPacketReader creates a new PacketReader based on the given reader.
func NewPacketReader(reader io.Reader) Reader {
if mr, ok := reader.(Reader); ok {
return mr
}
return &PacketReader{
Reader: reader,
}
}
func isPacketWriter(writer io.Writer) bool {
if _, ok := writer.(net.PacketConn); ok {
return true
}
// If the writer doesn't implement syscall.Conn, it is probably not a TCP connection.
if _, ok := writer.(syscall.Conn); !ok {
return true
}
return false
}
// NewWriter creates a new Writer.
func NewWriter(writer io.Writer) Writer {
if mw, ok := writer.(Writer); ok {
return mw
}
if isPacketWriter(writer) {
return &SequentialWriter{
Writer: writer,
}
}
return &BufferToBytesWriter{
Writer: writer,
}
}
v2ray-core-4.34.0/common/buf/io_test.go 0000664 0000000 0000000 00000001717 13774574720 0017662 0 ustar 00root root 0000000 0000000 package buf_test
import (
"crypto/tls"
"io"
"testing"
. "v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/testing/servers/tcp"
)
func TestWriterCreation(t *testing.T) {
tcpServer := tcp.Server{}
dest, err := tcpServer.Start()
if err != nil {
t.Fatal("failed to start tcp server: ", err)
}
defer tcpServer.Close()
conn, err := net.Dial("tcp", dest.NetAddr())
if err != nil {
t.Fatal("failed to dial a TCP connection: ", err)
}
defer conn.Close()
{
writer := NewWriter(conn)
if _, ok := writer.(*BufferToBytesWriter); !ok {
t.Fatal("writer is not a BufferToBytesWriter")
}
writer2 := NewWriter(writer.(io.Writer))
if writer2 != writer {
t.Fatal("writer is not reused")
}
}
tlsConn := tls.Client(conn, &tls.Config{
InsecureSkipVerify: true,
})
defer tlsConn.Close()
{
writer := NewWriter(tlsConn)
if _, ok := writer.(*SequentialWriter); !ok {
t.Fatal("writer is not a SequentialWriter")
}
}
}
v2ray-core-4.34.0/common/buf/multi_buffer.go 0000664 0000000 0000000 00000014366 13774574720 0020703 0 ustar 00root root 0000000 0000000 package buf
import (
"io"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/serial"
)
// ReadAllToBytes reads all content from the reader into a byte array, until EOF.
func ReadAllToBytes(reader io.Reader) ([]byte, error) {
mb, err := ReadFrom(reader)
if err != nil {
return nil, err
}
if mb.Len() == 0 {
return nil, nil
}
b := make([]byte, mb.Len())
mb, _ = SplitBytes(mb, b)
ReleaseMulti(mb)
return b, nil
}
// MultiBuffer is a list of Buffers. The order of Buffer matters.
type MultiBuffer []*Buffer
// MergeMulti merges content from src to dest, and returns the new address of dest and src
func MergeMulti(dest MultiBuffer, src MultiBuffer) (MultiBuffer, MultiBuffer) {
dest = append(dest, src...)
for idx := range src {
src[idx] = nil
}
return dest, src[:0]
}
// MergeBytes merges the given bytes into MultiBuffer and return the new address of the merged MultiBuffer.
func MergeBytes(dest MultiBuffer, src []byte) MultiBuffer {
n := len(dest)
if n > 0 && !(dest)[n-1].IsFull() {
nBytes, _ := (dest)[n-1].Write(src)
src = src[nBytes:]
}
for len(src) > 0 {
b := New()
nBytes, _ := b.Write(src)
src = src[nBytes:]
dest = append(dest, b)
}
return dest
}
// ReleaseMulti release all content of the MultiBuffer, and returns an empty MultiBuffer.
func ReleaseMulti(mb MultiBuffer) MultiBuffer {
for i := range mb {
mb[i].Release()
mb[i] = nil
}
return mb[:0]
}
// Copy copied the beginning part of the MultiBuffer into the given byte array.
func (mb MultiBuffer) Copy(b []byte) int {
total := 0
for _, bb := range mb {
nBytes := copy(b[total:], bb.Bytes())
total += nBytes
if int32(nBytes) < bb.Len() {
break
}
}
return total
}
// ReadFrom reads all content from reader until EOF.
func ReadFrom(reader io.Reader) (MultiBuffer, error) {
mb := make(MultiBuffer, 0, 16)
for {
b := New()
_, err := b.ReadFullFrom(reader, Size)
if b.IsEmpty() {
b.Release()
} else {
mb = append(mb, b)
}
if err != nil {
if errors.Cause(err) == io.EOF || errors.Cause(err) == io.ErrUnexpectedEOF {
return mb, nil
}
return mb, err
}
}
}
// SplitBytes splits the given amount of bytes from the beginning of the MultiBuffer.
// It returns the new address of MultiBuffer leftover, and number of bytes written into the input byte slice.
func SplitBytes(mb MultiBuffer, b []byte) (MultiBuffer, int) {
totalBytes := 0
endIndex := -1
for i := range mb {
pBuffer := mb[i]
nBytes, _ := pBuffer.Read(b)
totalBytes += nBytes
b = b[nBytes:]
if !pBuffer.IsEmpty() {
endIndex = i
break
}
pBuffer.Release()
mb[i] = nil
}
if endIndex == -1 {
mb = mb[:0]
} else {
mb = mb[endIndex:]
}
return mb, totalBytes
}
// SplitFirstBytes splits the first buffer from MultiBuffer, and then copy its content into the given slice.
func SplitFirstBytes(mb MultiBuffer, p []byte) (MultiBuffer, int) {
mb, b := SplitFirst(mb)
if b == nil {
return mb, 0
}
n := copy(p, b.Bytes())
b.Release()
return mb, n
}
// Compact returns another MultiBuffer by merging all content of the given one together.
func Compact(mb MultiBuffer) MultiBuffer {
if len(mb) == 0 {
return mb
}
mb2 := make(MultiBuffer, 0, len(mb))
last := mb[0]
for i := 1; i < len(mb); i++ {
curr := mb[i]
if last.Len()+curr.Len() > Size {
mb2 = append(mb2, last)
last = curr
} else {
common.Must2(last.ReadFrom(curr))
curr.Release()
}
}
mb2 = append(mb2, last)
return mb2
}
// SplitFirst splits the first Buffer from the beginning of the MultiBuffer.
func SplitFirst(mb MultiBuffer) (MultiBuffer, *Buffer) {
if len(mb) == 0 {
return mb, nil
}
b := mb[0]
mb[0] = nil
mb = mb[1:]
return mb, b
}
// SplitSize splits the beginning of the MultiBuffer into another one, for at most size bytes.
func SplitSize(mb MultiBuffer, size int32) (MultiBuffer, MultiBuffer) {
if len(mb) == 0 {
return mb, nil
}
if mb[0].Len() > size {
b := New()
copy(b.Extend(size), mb[0].BytesTo(size))
mb[0].Advance(size)
return mb, MultiBuffer{b}
}
totalBytes := int32(0)
var r MultiBuffer
endIndex := -1
for i := range mb {
if totalBytes+mb[i].Len() > size {
endIndex = i
break
}
totalBytes += mb[i].Len()
r = append(r, mb[i])
mb[i] = nil
}
if endIndex == -1 {
// To reuse mb array
mb = mb[:0]
} else {
mb = mb[endIndex:]
}
return mb, r
}
// WriteMultiBuffer writes all buffers from the MultiBuffer to the Writer one by one, and return error if any, with leftover MultiBuffer.
func WriteMultiBuffer(writer io.Writer, mb MultiBuffer) (MultiBuffer, error) {
for {
mb2, b := SplitFirst(mb)
mb = mb2
if b == nil {
break
}
_, err := writer.Write(b.Bytes())
b.Release()
if err != nil {
return mb, err
}
}
return nil, nil
}
// Len returns the total number of bytes in the MultiBuffer.
func (mb MultiBuffer) Len() int32 {
if mb == nil {
return 0
}
size := int32(0)
for _, b := range mb {
size += b.Len()
}
return size
}
// IsEmpty return true if the MultiBuffer has no content.
func (mb MultiBuffer) IsEmpty() bool {
for _, b := range mb {
if !b.IsEmpty() {
return false
}
}
return true
}
// String returns the content of the MultiBuffer in string.
func (mb MultiBuffer) String() string {
v := make([]interface{}, len(mb))
for i, b := range mb {
v[i] = b
}
return serial.Concat(v...)
}
// MultiBufferContainer is a ReadWriteCloser wrapper over MultiBuffer.
type MultiBufferContainer struct {
MultiBuffer
}
// Read implements io.Reader.
func (c *MultiBufferContainer) Read(b []byte) (int, error) {
if c.MultiBuffer.IsEmpty() {
return 0, io.EOF
}
mb, nBytes := SplitBytes(c.MultiBuffer, b)
c.MultiBuffer = mb
return nBytes, nil
}
// ReadMultiBuffer implements Reader.
func (c *MultiBufferContainer) ReadMultiBuffer() (MultiBuffer, error) {
mb := c.MultiBuffer
c.MultiBuffer = nil
return mb, nil
}
// Write implements io.Writer.
func (c *MultiBufferContainer) Write(b []byte) (int, error) {
c.MultiBuffer = MergeBytes(c.MultiBuffer, b)
return len(b), nil
}
// WriteMultiBuffer implement Writer.
func (c *MultiBufferContainer) WriteMultiBuffer(b MultiBuffer) error {
mb, _ := MergeMulti(c.MultiBuffer, b)
c.MultiBuffer = mb
return nil
}
// Close implement io.Closer.
func (c *MultiBufferContainer) Close() error {
c.MultiBuffer = ReleaseMulti(c.MultiBuffer)
return nil
}
v2ray-core-4.34.0/common/buf/multi_buffer_test.go 0000664 0000000 0000000 00000007307 13774574720 0021737 0 ustar 00root root 0000000 0000000 package buf_test
import (
"bytes"
"crypto/rand"
"io"
"io/ioutil"
"os"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
. "v2ray.com/core/common/buf"
)
func TestMultiBufferRead(t *testing.T) {
b1 := New()
common.Must2(b1.WriteString("ab"))
b2 := New()
common.Must2(b2.WriteString("cd"))
mb := MultiBuffer{b1, b2}
bs := make([]byte, 32)
_, nBytes := SplitBytes(mb, bs)
if nBytes != 4 {
t.Error("expect 4 bytes split, but got ", nBytes)
}
if r := cmp.Diff(bs[:nBytes], []byte("abcd")); r != "" {
t.Error(r)
}
}
func TestMultiBufferAppend(t *testing.T) {
var mb MultiBuffer
b := New()
common.Must2(b.WriteString("ab"))
mb = append(mb, b)
if mb.Len() != 2 {
t.Error("expected length 2, but got ", mb.Len())
}
}
func TestMultiBufferSliceBySizeLarge(t *testing.T) {
lb := make([]byte, 8*1024)
common.Must2(io.ReadFull(rand.Reader, lb))
mb := MergeBytes(nil, lb)
mb, mb2 := SplitSize(mb, 1024)
if mb2.Len() != 1024 {
t.Error("expect length 1024, but got ", mb2.Len())
}
if mb.Len() != 7*1024 {
t.Error("expect length 7*1024, but got ", mb.Len())
}
mb, mb3 := SplitSize(mb, 7*1024)
if mb3.Len() != 7*1024 {
t.Error("expect length 7*1024, but got", mb.Len())
}
if !mb.IsEmpty() {
t.Error("expect empty buffer, but got ", mb.Len())
}
}
func TestMultiBufferSplitFirst(t *testing.T) {
b1 := New()
b1.WriteString("b1")
b2 := New()
b2.WriteString("b2")
b3 := New()
b3.WriteString("b3")
var mb MultiBuffer
mb = append(mb, b1, b2, b3)
mb, c1 := SplitFirst(mb)
if diff := cmp.Diff(b1.String(), c1.String()); diff != "" {
t.Error(diff)
}
mb, c2 := SplitFirst(mb)
if diff := cmp.Diff(b2.String(), c2.String()); diff != "" {
t.Error(diff)
}
mb, c3 := SplitFirst(mb)
if diff := cmp.Diff(b3.String(), c3.String()); diff != "" {
t.Error(diff)
}
if !mb.IsEmpty() {
t.Error("expect empty buffer, but got ", mb.String())
}
}
func TestMultiBufferReadAllToByte(t *testing.T) {
{
lb := make([]byte, 8*1024)
common.Must2(io.ReadFull(rand.Reader, lb))
rd := bytes.NewBuffer(lb)
b, err := ReadAllToBytes(rd)
common.Must(err)
if l := len(b); l != 8*1024 {
t.Error("unexpceted length from ReadAllToBytes", l)
}
}
{
const dat = "data/test_MultiBufferReadAllToByte.dat"
f, err := os.Open(dat)
common.Must(err)
buf2, err := ReadAllToBytes(f)
common.Must(err)
f.Close()
cnt, err := ioutil.ReadFile(dat)
common.Must(err)
if d := cmp.Diff(buf2, cnt); d != "" {
t.Error("fail to read from file: ", d)
}
}
}
func TestMultiBufferCopy(t *testing.T) {
lb := make([]byte, 8*1024)
common.Must2(io.ReadFull(rand.Reader, lb))
reader := bytes.NewBuffer(lb)
mb, err := ReadFrom(reader)
common.Must(err)
lbdst := make([]byte, 8*1024)
mb.Copy(lbdst)
if d := cmp.Diff(lb, lbdst); d != "" {
t.Error("unexpceted different from MultiBufferCopy ", d)
}
}
func TestSplitFirstBytes(t *testing.T) {
a := New()
common.Must2(a.WriteString("ab"))
b := New()
common.Must2(b.WriteString("bc"))
mb := MultiBuffer{a, b}
o := make([]byte, 2)
_, cnt := SplitFirstBytes(mb, o)
if cnt != 2 {
t.Error("unexpected cnt from SplitFirstBytes ", cnt)
}
if d := cmp.Diff(string(o), "ab"); d != "" {
t.Error("unexpected splited result from SplitFirstBytes ", d)
}
}
func TestCompact(t *testing.T) {
a := New()
common.Must2(a.WriteString("ab"))
b := New()
common.Must2(b.WriteString("bc"))
mb := MultiBuffer{a, b}
cmb := Compact(mb)
if w := cmb.String(); w != "abbc" {
t.Error("unexpected Compact result ", w)
}
}
func BenchmarkSplitBytes(b *testing.B) {
var mb MultiBuffer
raw := make([]byte, Size)
b.ResetTimer()
for i := 0; i < b.N; i++ {
buffer := StackNew()
buffer.Extend(Size)
mb = append(mb, &buffer)
mb, _ = SplitBytes(mb, raw)
}
}
v2ray-core-4.34.0/common/buf/reader.go 0000664 0000000 0000000 00000007325 13774574720 0017457 0 ustar 00root root 0000000 0000000 package buf
import (
"io"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
)
func readOneUDP(r io.Reader) (*Buffer, error) {
b := New()
for i := 0; i < 64; i++ {
_, err := b.ReadFrom(r)
if !b.IsEmpty() {
return b, nil
}
if err != nil {
b.Release()
return nil, err
}
}
b.Release()
return nil, newError("Reader returns too many empty payloads.")
}
// ReadBuffer reads a Buffer from the given reader.
func ReadBuffer(r io.Reader) (*Buffer, error) {
b := New()
n, err := b.ReadFrom(r)
if n > 0 {
return b, err
}
b.Release()
return nil, err
}
// BufferedReader is a Reader that keeps its internal buffer.
type BufferedReader struct {
// Reader is the underlying reader to be read from
Reader Reader
// Buffer is the internal buffer to be read from first
Buffer MultiBuffer
// Spliter is a function to read bytes from MultiBuffer
Spliter func(MultiBuffer, []byte) (MultiBuffer, int)
}
// BufferedBytes returns the number of bytes that is cached in this reader.
func (r *BufferedReader) BufferedBytes() int32 {
return r.Buffer.Len()
}
// ReadByte implements io.ByteReader.
func (r *BufferedReader) ReadByte() (byte, error) {
var b [1]byte
_, err := r.Read(b[:])
return b[0], err
}
// Read implements io.Reader. It reads from internal buffer first (if available) and then reads from the underlying reader.
func (r *BufferedReader) Read(b []byte) (int, error) {
spliter := r.Spliter
if spliter == nil {
spliter = SplitBytes
}
if !r.Buffer.IsEmpty() {
buffer, nBytes := spliter(r.Buffer, b)
r.Buffer = buffer
if r.Buffer.IsEmpty() {
r.Buffer = nil
}
return nBytes, nil
}
mb, err := r.Reader.ReadMultiBuffer()
if err != nil {
return 0, err
}
mb, nBytes := spliter(mb, b)
if !mb.IsEmpty() {
r.Buffer = mb
}
return nBytes, nil
}
// ReadMultiBuffer implements Reader.
func (r *BufferedReader) ReadMultiBuffer() (MultiBuffer, error) {
if !r.Buffer.IsEmpty() {
mb := r.Buffer
r.Buffer = nil
return mb, nil
}
return r.Reader.ReadMultiBuffer()
}
// ReadAtMost returns a MultiBuffer with at most size.
func (r *BufferedReader) ReadAtMost(size int32) (MultiBuffer, error) {
if r.Buffer.IsEmpty() {
mb, err := r.Reader.ReadMultiBuffer()
if mb.IsEmpty() && err != nil {
return nil, err
}
r.Buffer = mb
}
rb, mb := SplitSize(r.Buffer, size)
r.Buffer = rb
if r.Buffer.IsEmpty() {
r.Buffer = nil
}
return mb, nil
}
func (r *BufferedReader) writeToInternal(writer io.Writer) (int64, error) {
mbWriter := NewWriter(writer)
var sc SizeCounter
if r.Buffer != nil {
sc.Size = int64(r.Buffer.Len())
if err := mbWriter.WriteMultiBuffer(r.Buffer); err != nil {
return 0, err
}
r.Buffer = nil
}
err := Copy(r.Reader, mbWriter, CountSize(&sc))
return sc.Size, err
}
// WriteTo implements io.WriterTo.
func (r *BufferedReader) WriteTo(writer io.Writer) (int64, error) {
nBytes, err := r.writeToInternal(writer)
if errors.Cause(err) == io.EOF {
return nBytes, nil
}
return nBytes, err
}
// Interrupt implements common.Interruptible.
func (r *BufferedReader) Interrupt() {
common.Interrupt(r.Reader)
}
// Close implements io.Closer.
func (r *BufferedReader) Close() error {
return common.Close(r.Reader)
}
// SingleReader is a Reader that read one Buffer every time.
type SingleReader struct {
io.Reader
}
// ReadMultiBuffer implements Reader.
func (r *SingleReader) ReadMultiBuffer() (MultiBuffer, error) {
b, err := ReadBuffer(r.Reader)
return MultiBuffer{b}, err
}
// PacketReader is a Reader that read one Buffer every time.
type PacketReader struct {
io.Reader
}
// ReadMultiBuffer implements Reader.
func (r *PacketReader) ReadMultiBuffer() (MultiBuffer, error) {
b, err := readOneUDP(r.Reader)
if err != nil {
return nil, err
}
return MultiBuffer{b}, nil
}
v2ray-core-4.34.0/common/buf/reader_test.go 0000664 0000000 0000000 00000005547 13774574720 0020522 0 ustar 00root root 0000000 0000000 package buf_test
import (
"bytes"
"io"
"strings"
"testing"
"v2ray.com/core/common"
. "v2ray.com/core/common/buf"
"v2ray.com/core/transport/pipe"
)
func TestBytesReaderWriteTo(t *testing.T) {
pReader, pWriter := pipe.New(pipe.WithSizeLimit(1024))
reader := &BufferedReader{Reader: pReader}
b1 := New()
b1.WriteString("abc")
b2 := New()
b2.WriteString("efg")
common.Must(pWriter.WriteMultiBuffer(MultiBuffer{b1, b2}))
pWriter.Close()
pReader2, pWriter2 := pipe.New(pipe.WithSizeLimit(1024))
writer := NewBufferedWriter(pWriter2)
writer.SetBuffered(false)
nBytes, err := io.Copy(writer, reader)
common.Must(err)
if nBytes != 6 {
t.Error("copy: ", nBytes)
}
mb, err := pReader2.ReadMultiBuffer()
common.Must(err)
if s := mb.String(); s != "abcefg" {
t.Error("content: ", s)
}
}
func TestBytesReaderMultiBuffer(t *testing.T) {
pReader, pWriter := pipe.New(pipe.WithSizeLimit(1024))
reader := &BufferedReader{Reader: pReader}
b1 := New()
b1.WriteString("abc")
b2 := New()
b2.WriteString("efg")
common.Must(pWriter.WriteMultiBuffer(MultiBuffer{b1, b2}))
pWriter.Close()
mbReader := NewReader(reader)
mb, err := mbReader.ReadMultiBuffer()
common.Must(err)
if s := mb.String(); s != "abcefg" {
t.Error("content: ", s)
}
}
func TestReadByte(t *testing.T) {
sr := strings.NewReader("abcd")
reader := &BufferedReader{
Reader: NewReader(sr),
}
b, err := reader.ReadByte()
common.Must(err)
if b != 'a' {
t.Error("unexpected byte: ", b, " want a")
}
if reader.BufferedBytes() != 3 { // 3 bytes left in buffer
t.Error("unexpected buffered Bytes: ", reader.BufferedBytes())
}
nBytes, err := reader.WriteTo(DiscardBytes)
common.Must(err)
if nBytes != 3 {
t.Error("unexpect bytes written: ", nBytes)
}
}
func TestReadBuffer(t *testing.T) {
{
sr := strings.NewReader("abcd")
buf, err := ReadBuffer(sr)
common.Must(err)
if s := buf.String(); s != "abcd" {
t.Error("unexpected str: ", s, " want abcd")
}
buf.Release()
}
}
func TestReadAtMost(t *testing.T) {
sr := strings.NewReader("abcd")
reader := &BufferedReader{
Reader: NewReader(sr),
}
mb, err := reader.ReadAtMost(3)
common.Must(err)
if s := mb.String(); s != "abc" {
t.Error("unexpected read result: ", s)
}
nBytes, err := reader.WriteTo(DiscardBytes)
common.Must(err)
if nBytes != 1 {
t.Error("unexpect bytes written: ", nBytes)
}
}
func TestPacketReader_ReadMultiBuffer(t *testing.T) {
const alpha = "abcefg"
buf := bytes.NewBufferString(alpha)
reader := &PacketReader{buf}
mb, err := reader.ReadMultiBuffer()
common.Must(err)
if s := mb.String(); s != alpha {
t.Error("content: ", s)
}
}
func TestReaderInterface(t *testing.T) {
_ = (io.Reader)(new(ReadVReader))
_ = (Reader)(new(ReadVReader))
_ = (Reader)(new(BufferedReader))
_ = (io.Reader)(new(BufferedReader))
_ = (io.ByteReader)(new(BufferedReader))
_ = (io.WriterTo)(new(BufferedReader))
}
v2ray-core-4.34.0/common/buf/readv_posix.go 0000664 0000000 0000000 00000001467 13774574720 0020541 0 ustar 00root root 0000000 0000000 // +build !windows
// +build !wasm
// +build !illumos
package buf
import (
"syscall"
"unsafe"
)
type posixReader struct {
iovecs []syscall.Iovec
}
func (r *posixReader) Init(bs []*Buffer) {
iovecs := r.iovecs
if iovecs == nil {
iovecs = make([]syscall.Iovec, 0, len(bs))
}
for idx, b := range bs {
iovecs = append(iovecs, syscall.Iovec{
Base: &(b.v[0]),
})
iovecs[idx].SetLen(int(Size))
}
r.iovecs = iovecs
}
func (r *posixReader) Read(fd uintptr) int32 {
n, _, e := syscall.Syscall(syscall.SYS_READV, fd, uintptr(unsafe.Pointer(&r.iovecs[0])), uintptr(len(r.iovecs)))
if e != 0 {
return -1
}
return int32(n)
}
func (r *posixReader) Clear() {
for idx := range r.iovecs {
r.iovecs[idx].Base = nil
}
r.iovecs = r.iovecs[:0]
}
func newMultiReader() multiReader {
return &posixReader{}
}
v2ray-core-4.34.0/common/buf/readv_reader.go 0000664 0000000 0000000 00000005014 13774574720 0020631 0 ustar 00root root 0000000 0000000 // +build !wasm
package buf
import (
"io"
"runtime"
"syscall"
"v2ray.com/core/common/platform"
)
type allocStrategy struct {
current uint32
}
func (s *allocStrategy) Current() uint32 {
return s.current
}
func (s *allocStrategy) Adjust(n uint32) {
if n >= s.current {
s.current *= 4
} else {
s.current = n
}
if s.current > 32 {
s.current = 32
}
if s.current == 0 {
s.current = 1
}
}
func (s *allocStrategy) Alloc() []*Buffer {
bs := make([]*Buffer, s.current)
for i := range bs {
bs[i] = New()
}
return bs
}
type multiReader interface {
Init([]*Buffer)
Read(fd uintptr) int32
Clear()
}
// ReadVReader is a Reader that uses readv(2) syscall to read data.
type ReadVReader struct {
io.Reader
rawConn syscall.RawConn
mr multiReader
alloc allocStrategy
}
// NewReadVReader creates a new ReadVReader.
func NewReadVReader(reader io.Reader, rawConn syscall.RawConn) *ReadVReader {
return &ReadVReader{
Reader: reader,
rawConn: rawConn,
alloc: allocStrategy{
current: 1,
},
mr: newMultiReader(),
}
}
func (r *ReadVReader) readMulti() (MultiBuffer, error) {
bs := r.alloc.Alloc()
r.mr.Init(bs)
var nBytes int32
err := r.rawConn.Read(func(fd uintptr) bool {
n := r.mr.Read(fd)
if n < 0 {
return false
}
nBytes = n
return true
})
r.mr.Clear()
if err != nil {
ReleaseMulti(MultiBuffer(bs))
return nil, err
}
if nBytes == 0 {
ReleaseMulti(MultiBuffer(bs))
return nil, io.EOF
}
nBuf := 0
for nBuf < len(bs) {
if nBytes <= 0 {
break
}
end := nBytes
if end > Size {
end = Size
}
bs[nBuf].end = end
nBytes -= end
nBuf++
}
for i := nBuf; i < len(bs); i++ {
bs[i].Release()
bs[i] = nil
}
return MultiBuffer(bs[:nBuf]), nil
}
// ReadMultiBuffer implements Reader.
func (r *ReadVReader) ReadMultiBuffer() (MultiBuffer, error) {
if r.alloc.Current() == 1 {
b, err := ReadBuffer(r.Reader)
if b.IsFull() {
r.alloc.Adjust(1)
}
return MultiBuffer{b}, err
}
mb, err := r.readMulti()
if err != nil {
return nil, err
}
r.alloc.Adjust(uint32(len(mb)))
return mb, nil
}
var useReadv = false
func init() {
const defaultFlagValue = "NOT_DEFINED_AT_ALL"
value := platform.NewEnvFlag("v2ray.buf.readv").GetValue(func() string { return defaultFlagValue })
switch value {
case defaultFlagValue, "auto":
if (runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "s390x") && (runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows") {
useReadv = true
}
case "enable":
useReadv = true
}
}
v2ray-core-4.34.0/common/buf/readv_reader_wasm.go 0000664 0000000 0000000 00000000266 13774574720 0021664 0 ustar 00root root 0000000 0000000 // +build wasm
package buf
import (
"io"
"syscall"
)
const useReadv = false
func NewReadVReader(reader io.Reader, rawConn syscall.RawConn) Reader {
panic("not implemented")
}
v2ray-core-4.34.0/common/buf/readv_test.go 0000664 0000000 0000000 00000002350 13774574720 0020346 0 ustar 00root root 0000000 0000000 // +build !wasm
package buf_test
import (
"crypto/rand"
"net"
"testing"
"github.com/google/go-cmp/cmp"
"golang.org/x/sync/errgroup"
"v2ray.com/core/common"
. "v2ray.com/core/common/buf"
"v2ray.com/core/testing/servers/tcp"
)
func TestReadvReader(t *testing.T) {
tcpServer := &tcp.Server{
MsgProcessor: func(b []byte) []byte {
return b
},
}
dest, err := tcpServer.Start()
common.Must(err)
defer tcpServer.Close()
conn, err := net.Dial("tcp", dest.NetAddr())
common.Must(err)
defer conn.Close()
const size = 8192
data := make([]byte, 8192)
common.Must2(rand.Read(data))
var errg errgroup.Group
errg.Go(func() error {
writer := NewWriter(conn)
mb := MergeBytes(nil, data)
return writer.WriteMultiBuffer(mb)
})
defer func() {
if err := errg.Wait(); err != nil {
t.Error(err)
}
}()
rawConn, err := conn.(*net.TCPConn).SyscallConn()
common.Must(err)
reader := NewReadVReader(conn, rawConn)
var rmb MultiBuffer
for {
mb, err := reader.ReadMultiBuffer()
if err != nil {
t.Fatal("unexpected error: ", err)
}
rmb, _ = MergeMulti(rmb, mb)
if rmb.Len() == size {
break
}
}
rdata := make([]byte, size)
SplitBytes(rmb, rdata)
if r := cmp.Diff(data, rdata); r != "" {
t.Fatal(r)
}
}
v2ray-core-4.34.0/common/buf/readv_unix.go 0000664 0000000 0000000 00000001036 13774574720 0020352 0 ustar 00root root 0000000 0000000 // +build illumos
package buf
import "golang.org/x/sys/unix"
type unixReader struct {
iovs [][]byte
}
func (r *unixReader) Init(bs []*Buffer) {
iovs := r.iovs
if iovs == nil {
iovs = make([][]byte, 0, len(bs))
}
for _, b := range bs {
iovs = append(iovs, b.v)
}
r.iovs = iovs
}
func (r *unixReader) Read(fd uintptr) int32 {
n, e := unix.Readv(int(fd), r.iovs)
if e != nil {
return -1
}
return int32(n)
}
func (r *unixReader) Clear() {
r.iovs = r.iovs[:0]
}
func newMultiReader() multiReader {
return &unixReader{}
}
v2ray-core-4.34.0/common/buf/readv_windows.go 0000664 0000000 0000000 00000001335 13774574720 0021063 0 ustar 00root root 0000000 0000000 package buf
import (
"syscall"
)
type windowsReader struct {
bufs []syscall.WSABuf
}
func (r *windowsReader) Init(bs []*Buffer) {
if r.bufs == nil {
r.bufs = make([]syscall.WSABuf, 0, len(bs))
}
for _, b := range bs {
r.bufs = append(r.bufs, syscall.WSABuf{Len: uint32(Size), Buf: &b.v[0]})
}
}
func (r *windowsReader) Clear() {
for idx := range r.bufs {
r.bufs[idx].Buf = nil
}
r.bufs = r.bufs[:0]
}
func (r *windowsReader) Read(fd uintptr) int32 {
var nBytes uint32
var flags uint32
err := syscall.WSARecv(syscall.Handle(fd), &r.bufs[0], uint32(len(r.bufs)), &nBytes, &flags, nil, nil)
if err != nil {
return -1
}
return int32(nBytes)
}
func newMultiReader() multiReader {
return new(windowsReader)
}
v2ray-core-4.34.0/common/buf/writer.go 0000664 0000000 0000000 00000011605 13774574720 0017525 0 ustar 00root root 0000000 0000000 package buf
import (
"io"
"net"
"sync"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
)
// BufferToBytesWriter is a Writer that writes alloc.Buffer into underlying writer.
type BufferToBytesWriter struct {
io.Writer
cache [][]byte
}
// WriteMultiBuffer implements Writer. This method takes ownership of the given buffer.
func (w *BufferToBytesWriter) WriteMultiBuffer(mb MultiBuffer) error {
defer ReleaseMulti(mb)
size := mb.Len()
if size == 0 {
return nil
}
if len(mb) == 1 {
return WriteAllBytes(w.Writer, mb[0].Bytes())
}
if cap(w.cache) < len(mb) {
w.cache = make([][]byte, 0, len(mb))
}
bs := w.cache
for _, b := range mb {
bs = append(bs, b.Bytes())
}
defer func() {
for idx := range bs {
bs[idx] = nil
}
}()
nb := net.Buffers(bs)
for size > 0 {
n, err := nb.WriteTo(w.Writer)
if err != nil {
return err
}
size -= int32(n)
}
return nil
}
// ReadFrom implements io.ReaderFrom.
func (w *BufferToBytesWriter) ReadFrom(reader io.Reader) (int64, error) {
var sc SizeCounter
err := Copy(NewReader(reader), w, CountSize(&sc))
return sc.Size, err
}
// BufferedWriter is a Writer with internal buffer.
type BufferedWriter struct {
sync.Mutex
writer Writer
buffer *Buffer
buffered bool
}
// NewBufferedWriter creates a new BufferedWriter.
func NewBufferedWriter(writer Writer) *BufferedWriter {
return &BufferedWriter{
writer: writer,
buffer: New(),
buffered: true,
}
}
// WriteByte implements io.ByteWriter.
func (w *BufferedWriter) WriteByte(c byte) error {
return common.Error2(w.Write([]byte{c}))
}
// Write implements io.Writer.
func (w *BufferedWriter) Write(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
w.Lock()
defer w.Unlock()
if !w.buffered {
if writer, ok := w.writer.(io.Writer); ok {
return writer.Write(b)
}
}
totalBytes := 0
for len(b) > 0 {
if w.buffer == nil {
w.buffer = New()
}
nBytes, err := w.buffer.Write(b)
totalBytes += nBytes
if err != nil {
return totalBytes, err
}
if !w.buffered || w.buffer.IsFull() {
if err := w.flushInternal(); err != nil {
return totalBytes, err
}
}
b = b[nBytes:]
}
return totalBytes, nil
}
// WriteMultiBuffer implements Writer. It takes ownership of the given MultiBuffer.
func (w *BufferedWriter) WriteMultiBuffer(b MultiBuffer) error {
if b.IsEmpty() {
return nil
}
w.Lock()
defer w.Unlock()
if !w.buffered {
return w.writer.WriteMultiBuffer(b)
}
reader := MultiBufferContainer{
MultiBuffer: b,
}
defer reader.Close()
for !reader.MultiBuffer.IsEmpty() {
if w.buffer == nil {
w.buffer = New()
}
common.Must2(w.buffer.ReadFrom(&reader))
if w.buffer.IsFull() {
if err := w.flushInternal(); err != nil {
return err
}
}
}
return nil
}
// Flush flushes buffered content into underlying writer.
func (w *BufferedWriter) Flush() error {
w.Lock()
defer w.Unlock()
return w.flushInternal()
}
func (w *BufferedWriter) flushInternal() error {
if w.buffer.IsEmpty() {
return nil
}
b := w.buffer
w.buffer = nil
if writer, ok := w.writer.(io.Writer); ok {
err := WriteAllBytes(writer, b.Bytes())
b.Release()
return err
}
return w.writer.WriteMultiBuffer(MultiBuffer{b})
}
// SetBuffered sets whether the internal buffer is used. If set to false, Flush() will be called to clear the buffer.
func (w *BufferedWriter) SetBuffered(f bool) error {
w.Lock()
defer w.Unlock()
w.buffered = f
if !f {
return w.flushInternal()
}
return nil
}
// ReadFrom implements io.ReaderFrom.
func (w *BufferedWriter) ReadFrom(reader io.Reader) (int64, error) {
if err := w.SetBuffered(false); err != nil {
return 0, err
}
var sc SizeCounter
err := Copy(NewReader(reader), w, CountSize(&sc))
return sc.Size, err
}
// Close implements io.Closable.
func (w *BufferedWriter) Close() error {
if err := w.Flush(); err != nil {
return err
}
return common.Close(w.writer)
}
// SequentialWriter is a Writer that writes MultiBuffer sequentially into the underlying io.Writer.
type SequentialWriter struct {
io.Writer
}
// WriteMultiBuffer implements Writer.
func (w *SequentialWriter) WriteMultiBuffer(mb MultiBuffer) error {
mb, err := WriteMultiBuffer(w.Writer, mb)
ReleaseMulti(mb)
return err
}
type noOpWriter byte
func (noOpWriter) WriteMultiBuffer(b MultiBuffer) error {
ReleaseMulti(b)
return nil
}
func (noOpWriter) Write(b []byte) (int, error) {
return len(b), nil
}
func (noOpWriter) ReadFrom(reader io.Reader) (int64, error) {
b := New()
defer b.Release()
totalBytes := int64(0)
for {
b.Clear()
_, err := b.ReadFrom(reader)
totalBytes += int64(b.Len())
if err != nil {
if errors.Cause(err) == io.EOF {
return totalBytes, nil
}
return totalBytes, err
}
}
}
var (
// Discard is a Writer that swallows all contents written in.
Discard Writer = noOpWriter(0)
// DiscardBytes is an io.Writer that swallows all contents written in.
DiscardBytes io.Writer = noOpWriter(0)
)
v2ray-core-4.34.0/common/buf/writer_test.go 0000664 0000000 0000000 00000004415 13774574720 0020565 0 ustar 00root root 0000000 0000000 package buf_test
import (
"bufio"
"bytes"
"crypto/rand"
"io"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
. "v2ray.com/core/common/buf"
"v2ray.com/core/transport/pipe"
)
func TestWriter(t *testing.T) {
lb := New()
common.Must2(lb.ReadFrom(rand.Reader))
expectedBytes := append([]byte(nil), lb.Bytes()...)
writeBuffer := bytes.NewBuffer(make([]byte, 0, 1024*1024))
writer := NewBufferedWriter(NewWriter(writeBuffer))
writer.SetBuffered(false)
common.Must(writer.WriteMultiBuffer(MultiBuffer{lb}))
common.Must(writer.Flush())
if r := cmp.Diff(expectedBytes, writeBuffer.Bytes()); r != "" {
t.Error(r)
}
}
func TestBytesWriterReadFrom(t *testing.T) {
const size = 50000
pReader, pWriter := pipe.New(pipe.WithSizeLimit(size))
reader := bufio.NewReader(io.LimitReader(rand.Reader, size))
writer := NewBufferedWriter(pWriter)
writer.SetBuffered(false)
nBytes, err := reader.WriteTo(writer)
if nBytes != size {
t.Fatal("unexpected size of bytes written: ", nBytes)
}
if err != nil {
t.Fatal("expect success, but actually error: ", err.Error())
}
mb, err := pReader.ReadMultiBuffer()
common.Must(err)
if mb.Len() != size {
t.Fatal("unexpected size read: ", mb.Len())
}
}
func TestDiscardBytes(t *testing.T) {
b := New()
common.Must2(b.ReadFullFrom(rand.Reader, Size))
nBytes, err := io.Copy(DiscardBytes, b)
common.Must(err)
if nBytes != Size {
t.Error("copy size: ", nBytes)
}
}
func TestDiscardBytesMultiBuffer(t *testing.T) {
const size = 10240*1024 + 1
buffer := bytes.NewBuffer(make([]byte, 0, size))
common.Must2(buffer.ReadFrom(io.LimitReader(rand.Reader, size)))
r := NewReader(buffer)
nBytes, err := io.Copy(DiscardBytes, &BufferedReader{Reader: r})
common.Must(err)
if nBytes != size {
t.Error("copy size: ", nBytes)
}
}
func TestWriterInterface(t *testing.T) {
{
var writer interface{} = (*BufferToBytesWriter)(nil)
switch writer.(type) {
case Writer, io.Writer, io.ReaderFrom:
default:
t.Error("BufferToBytesWriter is not Writer, io.Writer or io.ReaderFrom")
}
}
{
var writer interface{} = (*BufferedWriter)(nil)
switch writer.(type) {
case Writer, io.Writer, io.ReaderFrom, io.ByteWriter:
default:
t.Error("BufferedWriter is not Writer, io.Writer, io.ReaderFrom or io.ByteWriter")
}
}
}
v2ray-core-4.34.0/common/bytespool/ 0000775 0000000 0000000 00000000000 13774574720 0017123 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/bytespool/pool.go 0000664 0000000 0000000 00000002766 13774574720 0020436 0 ustar 00root root 0000000 0000000 package bytespool
import "sync"
func createAllocFunc(size int32) func() interface{} {
return func() interface{} {
return make([]byte, size)
}
}
// The following parameters controls the size of buffer pools.
// There are numPools pools. Starting from 2k size, the size of each pool is sizeMulti of the previous one.
// Package buf is guaranteed to not use buffers larger than the largest pool.
// Other packets may use larger buffers.
const (
numPools = 4
sizeMulti = 4
)
var (
pool [numPools]sync.Pool
poolSize [numPools]int32
)
func init() {
size := int32(2048)
for i := 0; i < numPools; i++ {
pool[i] = sync.Pool{
New: createAllocFunc(size),
}
poolSize[i] = size
size *= sizeMulti
}
}
// GetPool returns a sync.Pool that generates bytes array with at least the given size.
// It may return nil if no such pool exists.
//
// v2ray:api:stable
func GetPool(size int32) *sync.Pool {
for idx, ps := range poolSize {
if size <= ps {
return &pool[idx]
}
}
return nil
}
// Alloc returns a byte slice with at least the given size. Minimum size of returned slice is 2048.
//
// v2ray:api:stable
func Alloc(size int32) []byte {
pool := GetPool(size)
if pool != nil {
return pool.Get().([]byte)
}
return make([]byte, size)
}
// Free puts a byte slice into the internal pool.
//
// v2ray:api:stable
func Free(b []byte) {
size := int32(cap(b))
b = b[0:cap(b)]
for i := numPools - 1; i >= 0; i-- {
if size >= poolSize[i] {
pool[i].Put(b) // nolint: staticcheck
return
}
}
}
v2ray-core-4.34.0/common/cmdarg/ 0000775 0000000 0000000 00000000000 13774574720 0016340 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/cmdarg/cmdarg.go 0000664 0000000 0000000 00000000452 13774574720 0020125 0 ustar 00root root 0000000 0000000 package cmdarg
import "strings"
// Arg is used by flag to accept multiple argument.
type Arg []string
func (c *Arg) String() string {
return strings.Join([]string(*c), " ")
}
// Set is the method flag package calls
func (c *Arg) Set(value string) error {
*c = append(*c, value)
return nil
}
v2ray-core-4.34.0/common/common.go 0000664 0000000 0000000 00000010532 13774574720 0016723 0 ustar 00root root 0000000 0000000 // Package common contains common utilities that are shared among other packages.
// See each sub-package for detail.
package common
import (
"fmt"
"go/build"
"io/ioutil"
"os"
"path/filepath"
"strings"
"v2ray.com/core/common/errors"
)
//go:generate go run v2ray.com/core/common/errors/errorgen
var (
// ErrNoClue is for the situation that existing information is not enough to make a decision. For example, Router may return this error when there is no suitable route.
ErrNoClue = errors.New("not enough information for making a decision")
)
// Must panics if err is not nil.
func Must(err error) {
if err != nil {
panic(err)
}
}
// Must2 panics if the second parameter is not nil, otherwise returns the first parameter.
func Must2(v interface{}, err error) interface{} {
Must(err)
return v
}
// Error2 returns the err from the 2nd parameter.
func Error2(v interface{}, err error) error {
return err
}
// envFile returns the name of the Go environment configuration file.
// Copy from https://github.com/golang/go/blob/c4f2a9788a7be04daf931ac54382fbe2cb754938/src/cmd/go/internal/cfg/cfg.go#L150-L166
func envFile() (string, error) {
if file := os.Getenv("GOENV"); file != "" {
if file == "off" {
return "", fmt.Errorf("GOENV=off")
}
return file, nil
}
dir, err := os.UserConfigDir()
if err != nil {
return "", err
}
if dir == "" {
return "", fmt.Errorf("missing user-config dir")
}
return filepath.Join(dir, "go", "env"), nil
}
// GetRuntimeEnv returns the value of runtime environment variable,
// that is set by running following command: `go env -w key=value`.
func GetRuntimeEnv(key string) (string, error) {
file, err := envFile()
if err != nil {
return "", err
}
if file == "" {
return "", fmt.Errorf("missing runtime env file")
}
var data []byte
var runtimeEnv string
data, readErr := ioutil.ReadFile(file)
if readErr != nil {
return "", readErr
}
envStrings := strings.Split(string(data), "\n")
for _, envItem := range envStrings {
envItem = strings.TrimSuffix(envItem, "\r")
envKeyValue := strings.Split(envItem, "=")
if strings.EqualFold(strings.TrimSpace(envKeyValue[0]), key) {
runtimeEnv = strings.TrimSpace(envKeyValue[1])
}
}
return runtimeEnv, nil
}
// GetGOBIN returns GOBIN environment variable as a string. It will NOT be empty.
func GetGOBIN() string {
// The one set by user explicitly by `export GOBIN=/path` or `env GOBIN=/path command`
GOBIN := os.Getenv("GOBIN")
if GOBIN == "" {
var err error
// The one set by user by running `go env -w GOBIN=/path`
GOBIN, err = GetRuntimeEnv("GOBIN")
if err != nil {
// The default one that Golang uses
return filepath.Join(build.Default.GOPATH, "bin")
}
if GOBIN == "" {
return filepath.Join(build.Default.GOPATH, "bin")
}
return GOBIN
}
return GOBIN
}
// GetGOPATH returns GOPATH environment variable as a string. It will NOT be empty.
func GetGOPATH() string {
// The one set by user explicitly by `export GOPATH=/path` or `env GOPATH=/path command`
GOPATH := os.Getenv("GOPATH")
if GOPATH == "" {
var err error
// The one set by user by running `go env -w GOPATH=/path`
GOPATH, err = GetRuntimeEnv("GOPATH")
if err != nil {
// The default one that Golang uses
return build.Default.GOPATH
}
if GOPATH == "" {
return build.Default.GOPATH
}
return GOPATH
}
return GOPATH
}
// GetModuleName returns the value of module in `go.mod` file.
func GetModuleName(pathToProjectRoot string) (string, error) {
var moduleName string
loopPath := pathToProjectRoot
for {
if idx := strings.LastIndex(loopPath, string(filepath.Separator)); idx >= 0 {
gomodPath := filepath.Join(loopPath, "go.mod")
gomodBytes, err := ioutil.ReadFile(gomodPath)
if err != nil {
loopPath = loopPath[:idx]
continue
}
gomodContent := string(gomodBytes)
moduleIdx := strings.Index(gomodContent, "module ")
newLineIdx := strings.Index(gomodContent, "\n")
if moduleIdx >= 0 {
if newLineIdx >= 0 {
moduleName = strings.TrimSpace(gomodContent[moduleIdx+6 : newLineIdx])
moduleName = strings.TrimSuffix(moduleName, "\r")
} else {
moduleName = strings.TrimSpace(gomodContent[moduleIdx+6:])
}
return moduleName, nil
}
return "", fmt.Errorf("can not get module path in `%s`", gomodPath)
}
break
}
return moduleName, fmt.Errorf("no `go.mod` file in every parent directory of `%s`", pathToProjectRoot)
}
v2ray-core-4.34.0/common/common_test.go 0000664 0000000 0000000 00000001423 13774574720 0017761 0 ustar 00root root 0000000 0000000 package common_test
import (
"errors"
"testing"
. "v2ray.com/core/common"
)
func TestMust(t *testing.T) {
hasPanic := func(f func()) (ret bool) {
defer func() {
if r := recover(); r != nil {
ret = true
}
}()
f()
return false
}
testCases := []struct {
Input func()
Panic bool
}{
{
Panic: true,
Input: func() { Must(func() error { return errors.New("test error") }()) },
},
{
Panic: true,
Input: func() { Must2(func() (int, error) { return 0, errors.New("test error") }()) },
},
{
Panic: false,
Input: func() { Must(func() error { return nil }()) },
},
}
for idx, test := range testCases {
if hasPanic(test.Input) != test.Panic {
t.Error("test case #", idx, " expect panic ", test.Panic, " but actually not")
}
}
}
v2ray-core-4.34.0/common/crypto/ 0000775 0000000 0000000 00000000000 13774574720 0016423 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/crypto/aes.go 0000664 0000000 0000000 00000002350 13774574720 0017522 0 ustar 00root root 0000000 0000000 package crypto
import (
"crypto/aes"
"crypto/cipher"
"v2ray.com/core/common"
)
// NewAesDecryptionStream creates a new AES encryption stream based on given key and IV.
// Caller must ensure the length of key and IV is either 16, 24 or 32 bytes.
func NewAesDecryptionStream(key []byte, iv []byte) cipher.Stream {
return NewAesStreamMethod(key, iv, cipher.NewCFBDecrypter)
}
// NewAesEncryptionStream creates a new AES description stream based on given key and IV.
// Caller must ensure the length of key and IV is either 16, 24 or 32 bytes.
func NewAesEncryptionStream(key []byte, iv []byte) cipher.Stream {
return NewAesStreamMethod(key, iv, cipher.NewCFBEncrypter)
}
func NewAesStreamMethod(key []byte, iv []byte, f func(cipher.Block, []byte) cipher.Stream) cipher.Stream {
aesBlock, err := aes.NewCipher(key)
common.Must(err)
return f(aesBlock, iv)
}
// NewAesCTRStream creates a stream cipher based on AES-CTR.
func NewAesCTRStream(key []byte, iv []byte) cipher.Stream {
return NewAesStreamMethod(key, iv, cipher.NewCTR)
}
// NewAesGcm creates a AEAD cipher based on AES-GCM.
func NewAesGcm(key []byte) cipher.AEAD {
block, err := aes.NewCipher(key)
common.Must(err)
aead, err := cipher.NewGCM(block)
common.Must(err)
return aead
}
v2ray-core-4.34.0/common/crypto/auth.go 0000664 0000000 0000000 00000017537 13774574720 0017730 0 ustar 00root root 0000000 0000000 package crypto
import (
"crypto/cipher"
"io"
"math/rand"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/bytespool"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/protocol"
)
type BytesGenerator func() []byte
func GenerateEmptyBytes() BytesGenerator {
var b [1]byte
return func() []byte {
return b[:0]
}
}
func GenerateStaticBytes(content []byte) BytesGenerator {
return func() []byte {
return content
}
}
func GenerateIncreasingNonce(nonce []byte) BytesGenerator {
c := append([]byte(nil), nonce...)
return func() []byte {
for i := range c {
c[i]++
if c[i] != 0 {
break
}
}
return c
}
}
func GenerateInitialAEADNonce() BytesGenerator {
return GenerateIncreasingNonce([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})
}
type Authenticator interface {
NonceSize() int
Overhead() int
Open(dst, cipherText []byte) ([]byte, error)
Seal(dst, plainText []byte) ([]byte, error)
}
type AEADAuthenticator struct {
cipher.AEAD
NonceGenerator BytesGenerator
AdditionalDataGenerator BytesGenerator
}
func (v *AEADAuthenticator) Open(dst, cipherText []byte) ([]byte, error) {
iv := v.NonceGenerator()
if len(iv) != v.AEAD.NonceSize() {
return nil, newError("invalid AEAD nonce size: ", len(iv))
}
var additionalData []byte
if v.AdditionalDataGenerator != nil {
additionalData = v.AdditionalDataGenerator()
}
return v.AEAD.Open(dst, iv, cipherText, additionalData)
}
func (v *AEADAuthenticator) Seal(dst, plainText []byte) ([]byte, error) {
iv := v.NonceGenerator()
if len(iv) != v.AEAD.NonceSize() {
return nil, newError("invalid AEAD nonce size: ", len(iv))
}
var additionalData []byte
if v.AdditionalDataGenerator != nil {
additionalData = v.AdditionalDataGenerator()
}
return v.AEAD.Seal(dst, iv, plainText, additionalData), nil
}
type AuthenticationReader struct {
auth Authenticator
reader *buf.BufferedReader
sizeParser ChunkSizeDecoder
sizeBytes []byte
transferType protocol.TransferType
padding PaddingLengthGenerator
size uint16
paddingLen uint16
hasSize bool
done bool
}
func NewAuthenticationReader(auth Authenticator, sizeParser ChunkSizeDecoder, reader io.Reader, transferType protocol.TransferType, paddingLen PaddingLengthGenerator) *AuthenticationReader {
r := &AuthenticationReader{
auth: auth,
sizeParser: sizeParser,
transferType: transferType,
padding: paddingLen,
sizeBytes: make([]byte, sizeParser.SizeBytes()),
}
if breader, ok := reader.(*buf.BufferedReader); ok {
r.reader = breader
} else {
r.reader = &buf.BufferedReader{Reader: buf.NewReader(reader)}
}
return r
}
func (r *AuthenticationReader) readSize() (uint16, uint16, error) {
if r.hasSize {
r.hasSize = false
return r.size, r.paddingLen, nil
}
if _, err := io.ReadFull(r.reader, r.sizeBytes); err != nil {
return 0, 0, err
}
var padding uint16
if r.padding != nil {
padding = r.padding.NextPaddingLen()
}
size, err := r.sizeParser.Decode(r.sizeBytes)
return size, padding, err
}
var errSoft = newError("waiting for more data")
func (r *AuthenticationReader) readBuffer(size int32, padding int32) (*buf.Buffer, error) {
b := buf.New()
if _, err := b.ReadFullFrom(r.reader, size); err != nil {
b.Release()
return nil, err
}
size -= padding
rb, err := r.auth.Open(b.BytesTo(0), b.BytesTo(size))
if err != nil {
b.Release()
return nil, err
}
b.Resize(0, int32(len(rb)))
return b, nil
}
func (r *AuthenticationReader) readInternal(soft bool, mb *buf.MultiBuffer) error {
if soft && r.reader.BufferedBytes() < r.sizeParser.SizeBytes() {
return errSoft
}
if r.done {
return io.EOF
}
size, padding, err := r.readSize()
if err != nil {
return err
}
if size == uint16(r.auth.Overhead())+padding {
r.done = true
return io.EOF
}
if soft && int32(size) > r.reader.BufferedBytes() {
r.size = size
r.paddingLen = padding
r.hasSize = true
return errSoft
}
if size <= buf.Size {
b, err := r.readBuffer(int32(size), int32(padding))
if err != nil {
return nil
}
*mb = append(*mb, b)
return nil
}
payload := bytespool.Alloc(int32(size))
defer bytespool.Free(payload)
if _, err := io.ReadFull(r.reader, payload[:size]); err != nil {
return err
}
size -= padding
rb, err := r.auth.Open(payload[:0], payload[:size])
if err != nil {
return err
}
*mb = buf.MergeBytes(*mb, rb)
return nil
}
func (r *AuthenticationReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
const readSize = 16
mb := make(buf.MultiBuffer, 0, readSize)
if err := r.readInternal(false, &mb); err != nil {
buf.ReleaseMulti(mb)
return nil, err
}
for i := 1; i < readSize; i++ {
err := r.readInternal(true, &mb)
if err == errSoft || err == io.EOF {
break
}
if err != nil {
buf.ReleaseMulti(mb)
return nil, err
}
}
return mb, nil
}
type AuthenticationWriter struct {
auth Authenticator
writer buf.Writer
sizeParser ChunkSizeEncoder
transferType protocol.TransferType
padding PaddingLengthGenerator
}
func NewAuthenticationWriter(auth Authenticator, sizeParser ChunkSizeEncoder, writer io.Writer, transferType protocol.TransferType, padding PaddingLengthGenerator) *AuthenticationWriter {
w := &AuthenticationWriter{
auth: auth,
writer: buf.NewWriter(writer),
sizeParser: sizeParser,
transferType: transferType,
}
if padding != nil {
w.padding = padding
}
return w
}
func (w *AuthenticationWriter) seal(b []byte) (*buf.Buffer, error) {
encryptedSize := int32(len(b) + w.auth.Overhead())
var paddingSize int32
if w.padding != nil {
paddingSize = int32(w.padding.NextPaddingLen())
}
sizeBytes := w.sizeParser.SizeBytes()
totalSize := sizeBytes + encryptedSize + paddingSize
if totalSize > buf.Size {
return nil, newError("size too large: ", totalSize)
}
eb := buf.New()
w.sizeParser.Encode(uint16(encryptedSize+paddingSize), eb.Extend(sizeBytes))
if _, err := w.auth.Seal(eb.Extend(encryptedSize)[:0], b); err != nil {
eb.Release()
return nil, err
}
if paddingSize > 0 {
// With size of the chunk and padding length encrypted, the content of padding doesn't matter much.
paddingBytes := eb.Extend(paddingSize)
common.Must2(rand.Read(paddingBytes))
}
return eb, nil
}
func (w *AuthenticationWriter) writeStream(mb buf.MultiBuffer) error {
defer buf.ReleaseMulti(mb)
var maxPadding int32
if w.padding != nil {
maxPadding = int32(w.padding.MaxPaddingLen())
}
payloadSize := buf.Size - int32(w.auth.Overhead()) - w.sizeParser.SizeBytes() - maxPadding
if len(mb)+10 > 64*1024*1024 {
return errors.New("value too large")
}
sliceSize := len(mb) + 10
mb2Write := make(buf.MultiBuffer, 0, sliceSize)
temp := buf.New()
defer temp.Release()
rawBytes := temp.Extend(payloadSize)
for {
nb, nBytes := buf.SplitBytes(mb, rawBytes)
mb = nb
eb, err := w.seal(rawBytes[:nBytes])
if err != nil {
buf.ReleaseMulti(mb2Write)
return err
}
mb2Write = append(mb2Write, eb)
if mb.IsEmpty() {
break
}
}
return w.writer.WriteMultiBuffer(mb2Write)
}
func (w *AuthenticationWriter) writePacket(mb buf.MultiBuffer) error {
defer buf.ReleaseMulti(mb)
if len(mb)+1 > 64*1024*1024 {
return errors.New("value too large")
}
sliceSize := len(mb) + 1
mb2Write := make(buf.MultiBuffer, 0, sliceSize)
for _, b := range mb {
if b.IsEmpty() {
continue
}
eb, err := w.seal(b.Bytes())
if err != nil {
continue
}
mb2Write = append(mb2Write, eb)
}
if mb2Write.IsEmpty() {
return nil
}
return w.writer.WriteMultiBuffer(mb2Write)
}
// WriteMultiBuffer implements buf.Writer.
func (w *AuthenticationWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
if mb.IsEmpty() {
eb, err := w.seal([]byte{})
common.Must(err)
return w.writer.WriteMultiBuffer(buf.MultiBuffer{eb})
}
if w.transferType == protocol.TransferTypeStream {
return w.writeStream(mb)
}
return w.writePacket(mb)
}
v2ray-core-4.34.0/common/crypto/auth_test.go 0000664 0000000 0000000 00000006413 13774574720 0020756 0 ustar 00root root 0000000 0000000 package crypto_test
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
. "v2ray.com/core/common/crypto"
"v2ray.com/core/common/protocol"
)
func TestAuthenticationReaderWriter(t *testing.T) {
key := make([]byte, 16)
rand.Read(key)
block, err := aes.NewCipher(key)
common.Must(err)
aead, err := cipher.NewGCM(block)
common.Must(err)
const payloadSize = 1024 * 80
rawPayload := make([]byte, payloadSize)
rand.Read(rawPayload)
payload := buf.MergeBytes(nil, rawPayload)
cache := bytes.NewBuffer(nil)
iv := make([]byte, 12)
rand.Read(iv)
writer := NewAuthenticationWriter(&AEADAuthenticator{
AEAD: aead,
NonceGenerator: GenerateStaticBytes(iv),
AdditionalDataGenerator: GenerateEmptyBytes(),
}, PlainChunkSizeParser{}, cache, protocol.TransferTypeStream, nil)
common.Must(writer.WriteMultiBuffer(payload))
if cache.Len() <= 1024*80 {
t.Error("cache len: ", cache.Len())
}
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{}))
reader := NewAuthenticationReader(&AEADAuthenticator{
AEAD: aead,
NonceGenerator: GenerateStaticBytes(iv),
AdditionalDataGenerator: GenerateEmptyBytes(),
}, PlainChunkSizeParser{}, cache, protocol.TransferTypeStream, nil)
var mb buf.MultiBuffer
for mb.Len() < payloadSize {
mb2, err := reader.ReadMultiBuffer()
common.Must(err)
mb, _ = buf.MergeMulti(mb, mb2)
}
if mb.Len() != payloadSize {
t.Error("mb len: ", mb.Len())
}
mbContent := make([]byte, payloadSize)
buf.SplitBytes(mb, mbContent)
if r := cmp.Diff(mbContent, rawPayload); r != "" {
t.Error(r)
}
_, err = reader.ReadMultiBuffer()
if err != io.EOF {
t.Error("error: ", err)
}
}
func TestAuthenticationReaderWriterPacket(t *testing.T) {
key := make([]byte, 16)
common.Must2(rand.Read(key))
block, err := aes.NewCipher(key)
common.Must(err)
aead, err := cipher.NewGCM(block)
common.Must(err)
cache := buf.New()
iv := make([]byte, 12)
rand.Read(iv)
writer := NewAuthenticationWriter(&AEADAuthenticator{
AEAD: aead,
NonceGenerator: GenerateStaticBytes(iv),
AdditionalDataGenerator: GenerateEmptyBytes(),
}, PlainChunkSizeParser{}, cache, protocol.TransferTypePacket, nil)
var payload buf.MultiBuffer
pb1 := buf.New()
pb1.Write([]byte("abcd"))
payload = append(payload, pb1)
pb2 := buf.New()
pb2.Write([]byte("efgh"))
payload = append(payload, pb2)
common.Must(writer.WriteMultiBuffer(payload))
if cache.Len() == 0 {
t.Error("cache len: ", cache.Len())
}
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{}))
reader := NewAuthenticationReader(&AEADAuthenticator{
AEAD: aead,
NonceGenerator: GenerateStaticBytes(iv),
AdditionalDataGenerator: GenerateEmptyBytes(),
}, PlainChunkSizeParser{}, cache, protocol.TransferTypePacket, nil)
mb, err := reader.ReadMultiBuffer()
common.Must(err)
mb, b1 := buf.SplitFirst(mb)
if b1.String() != "abcd" {
t.Error("b1: ", b1.String())
}
mb, b2 := buf.SplitFirst(mb)
if b2.String() != "efgh" {
t.Error("b2: ", b2.String())
}
if !mb.IsEmpty() {
t.Error("not empty")
}
_, err = reader.ReadMultiBuffer()
if err != io.EOF {
t.Error("error: ", err)
}
}
v2ray-core-4.34.0/common/crypto/benchmark_test.go 0000664 0000000 0000000 00000001723 13774574720 0021746 0 ustar 00root root 0000000 0000000 package crypto_test
import (
"crypto/cipher"
"testing"
. "v2ray.com/core/common/crypto"
)
const benchSize = 1024 * 1024
func benchmarkStream(b *testing.B, c cipher.Stream) {
b.SetBytes(benchSize)
input := make([]byte, benchSize)
output := make([]byte, benchSize)
b.ResetTimer()
for i := 0; i < b.N; i++ {
c.XORKeyStream(output, input)
}
}
func BenchmarkChaCha20(b *testing.B) {
key := make([]byte, 32)
nonce := make([]byte, 8)
c := NewChaCha20Stream(key, nonce)
benchmarkStream(b, c)
}
func BenchmarkChaCha20IETF(b *testing.B) {
key := make([]byte, 32)
nonce := make([]byte, 12)
c := NewChaCha20Stream(key, nonce)
benchmarkStream(b, c)
}
func BenchmarkAESEncryption(b *testing.B) {
key := make([]byte, 32)
iv := make([]byte, 16)
c := NewAesEncryptionStream(key, iv)
benchmarkStream(b, c)
}
func BenchmarkAESDecryption(b *testing.B) {
key := make([]byte, 32)
iv := make([]byte, 16)
c := NewAesDecryptionStream(key, iv)
benchmarkStream(b, c)
}
v2ray-core-4.34.0/common/crypto/chacha20.go 0000664 0000000 0000000 00000000612 13774574720 0020322 0 ustar 00root root 0000000 0000000 package crypto
import (
"crypto/cipher"
"v2ray.com/core/common/crypto/internal"
)
// NewChaCha20Stream creates a new Chacha20 encryption/descryption stream based on give key and IV.
// Caller must ensure the length of key is 32 bytes, and length of IV is either 8 or 12 bytes.
func NewChaCha20Stream(key []byte, iv []byte) cipher.Stream {
return internal.NewChaCha20Stream(key, iv, 20)
}
v2ray-core-4.34.0/common/crypto/chacha20_test.go 0000664 0000000 0000000 00000004427 13774574720 0021371 0 ustar 00root root 0000000 0000000 package crypto_test
import (
"crypto/rand"
"encoding/hex"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
. "v2ray.com/core/common/crypto"
)
func mustDecodeHex(s string) []byte {
b, err := hex.DecodeString(s)
common.Must(err)
return b
}
func TestChaCha20Stream(t *testing.T) {
var cases = []struct {
key []byte
iv []byte
output []byte
}{
{
key: mustDecodeHex("0000000000000000000000000000000000000000000000000000000000000000"),
iv: mustDecodeHex("0000000000000000"),
output: mustDecodeHex("76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7" +
"da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586" +
"9f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32ee7aed" +
"29b721769ce64e43d57133b074d839d531ed1f28510afb45ace10a1f4b794d6f"),
},
{
key: mustDecodeHex("5555555555555555555555555555555555555555555555555555555555555555"),
iv: mustDecodeHex("5555555555555555"),
output: mustDecodeHex("bea9411aa453c5434a5ae8c92862f564396855a9ea6e22d6d3b50ae1b3663311" +
"a4a3606c671d605ce16c3aece8e61ea145c59775017bee2fa6f88afc758069f7" +
"e0b8f676e644216f4d2a3422d7fa36c6c4931aca950e9da42788e6d0b6d1cd83" +
"8ef652e97b145b14871eae6c6804c7004db5ac2fce4c68c726d004b10fcaba86"),
},
{
key: mustDecodeHex("0000000000000000000000000000000000000000000000000000000000000000"),
iv: mustDecodeHex("000000000000000000000000"),
output: mustDecodeHex("76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586"),
},
}
for _, c := range cases {
s := NewChaCha20Stream(c.key, c.iv)
input := make([]byte, len(c.output))
actualOutout := make([]byte, len(c.output))
s.XORKeyStream(actualOutout, input)
if r := cmp.Diff(c.output, actualOutout); r != "" {
t.Fatal(r)
}
}
}
func TestChaCha20Decoding(t *testing.T) {
key := make([]byte, 32)
common.Must2(rand.Read(key))
iv := make([]byte, 8)
common.Must2(rand.Read(iv))
stream := NewChaCha20Stream(key, iv)
payload := make([]byte, 1024)
common.Must2(rand.Read(payload))
x := make([]byte, len(payload))
stream.XORKeyStream(x, payload)
stream2 := NewChaCha20Stream(key, iv)
stream2.XORKeyStream(x, x)
if r := cmp.Diff(x, payload); r != "" {
t.Fatal(r)
}
}
v2ray-core-4.34.0/common/crypto/chunk.go 0000664 0000000 0000000 00000007113 13774574720 0020064 0 ustar 00root root 0000000 0000000 package crypto
import (
"encoding/binary"
"io"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
)
// ChunkSizeDecoder is a utility class to decode size value from bytes.
type ChunkSizeDecoder interface {
SizeBytes() int32
Decode([]byte) (uint16, error)
}
// ChunkSizeEncoder is a utility class to encode size value into bytes.
type ChunkSizeEncoder interface {
SizeBytes() int32
Encode(uint16, []byte) []byte
}
type PaddingLengthGenerator interface {
MaxPaddingLen() uint16
NextPaddingLen() uint16
}
type PlainChunkSizeParser struct{}
func (PlainChunkSizeParser) SizeBytes() int32 {
return 2
}
func (PlainChunkSizeParser) Encode(size uint16, b []byte) []byte {
binary.BigEndian.PutUint16(b, size)
return b[:2]
}
func (PlainChunkSizeParser) Decode(b []byte) (uint16, error) {
return binary.BigEndian.Uint16(b), nil
}
type AEADChunkSizeParser struct {
Auth *AEADAuthenticator
}
func (p *AEADChunkSizeParser) SizeBytes() int32 {
return 2 + int32(p.Auth.Overhead())
}
func (p *AEADChunkSizeParser) Encode(size uint16, b []byte) []byte {
binary.BigEndian.PutUint16(b, size-uint16(p.Auth.Overhead()))
b, err := p.Auth.Seal(b[:0], b[:2])
common.Must(err)
return b
}
func (p *AEADChunkSizeParser) Decode(b []byte) (uint16, error) {
b, err := p.Auth.Open(b[:0], b)
if err != nil {
return 0, err
}
return binary.BigEndian.Uint16(b) + uint16(p.Auth.Overhead()), nil
}
type ChunkStreamReader struct {
sizeDecoder ChunkSizeDecoder
reader *buf.BufferedReader
buffer []byte
leftOverSize int32
maxNumChunk uint32
numChunk uint32
}
func NewChunkStreamReader(sizeDecoder ChunkSizeDecoder, reader io.Reader) *ChunkStreamReader {
return NewChunkStreamReaderWithChunkCount(sizeDecoder, reader, 0)
}
func NewChunkStreamReaderWithChunkCount(sizeDecoder ChunkSizeDecoder, reader io.Reader, maxNumChunk uint32) *ChunkStreamReader {
r := &ChunkStreamReader{
sizeDecoder: sizeDecoder,
buffer: make([]byte, sizeDecoder.SizeBytes()),
maxNumChunk: maxNumChunk,
}
if breader, ok := reader.(*buf.BufferedReader); ok {
r.reader = breader
} else {
r.reader = &buf.BufferedReader{Reader: buf.NewReader(reader)}
}
return r
}
func (r *ChunkStreamReader) readSize() (uint16, error) {
if _, err := io.ReadFull(r.reader, r.buffer); err != nil {
return 0, err
}
return r.sizeDecoder.Decode(r.buffer)
}
func (r *ChunkStreamReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
size := r.leftOverSize
if size == 0 {
r.numChunk++
if r.maxNumChunk > 0 && r.numChunk > r.maxNumChunk {
return nil, io.EOF
}
nextSize, err := r.readSize()
if err != nil {
return nil, err
}
if nextSize == 0 {
return nil, io.EOF
}
size = int32(nextSize)
}
r.leftOverSize = size
mb, err := r.reader.ReadAtMost(size)
if !mb.IsEmpty() {
r.leftOverSize -= mb.Len()
return mb, nil
}
return nil, err
}
type ChunkStreamWriter struct {
sizeEncoder ChunkSizeEncoder
writer buf.Writer
}
func NewChunkStreamWriter(sizeEncoder ChunkSizeEncoder, writer io.Writer) *ChunkStreamWriter {
return &ChunkStreamWriter{
sizeEncoder: sizeEncoder,
writer: buf.NewWriter(writer),
}
}
func (w *ChunkStreamWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
const sliceSize = 8192
mbLen := mb.Len()
mb2Write := make(buf.MultiBuffer, 0, mbLen/buf.Size+mbLen/sliceSize+2)
for {
mb2, slice := buf.SplitSize(mb, sliceSize)
mb = mb2
b := buf.New()
w.sizeEncoder.Encode(uint16(slice.Len()), b.Extend(w.sizeEncoder.SizeBytes()))
mb2Write = append(mb2Write, b)
mb2Write = append(mb2Write, slice...)
if mb.IsEmpty() {
break
}
}
return w.writer.WriteMultiBuffer(mb2Write)
}
v2ray-core-4.34.0/common/crypto/chunk_test.go 0000664 0000000 0000000 00000002003 13774574720 0021114 0 ustar 00root root 0000000 0000000 package crypto_test
import (
"bytes"
"io"
"testing"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
. "v2ray.com/core/common/crypto"
)
func TestChunkStreamIO(t *testing.T) {
cache := bytes.NewBuffer(make([]byte, 0, 8192))
writer := NewChunkStreamWriter(PlainChunkSizeParser{}, cache)
reader := NewChunkStreamReader(PlainChunkSizeParser{}, cache)
b := buf.New()
b.WriteString("abcd")
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{b}))
b = buf.New()
b.WriteString("efg")
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{b}))
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{}))
if cache.Len() != 13 {
t.Fatalf("Cache length is %d, want 13", cache.Len())
}
mb, err := reader.ReadMultiBuffer()
common.Must(err)
if s := mb.String(); s != "abcd" {
t.Error("content: ", s)
}
mb, err = reader.ReadMultiBuffer()
common.Must(err)
if s := mb.String(); s != "efg" {
t.Error("content: ", s)
}
_, err = reader.ReadMultiBuffer()
if err != io.EOF {
t.Error("error: ", err)
}
}
v2ray-core-4.34.0/common/crypto/crypto.go 0000664 0000000 0000000 00000000262 13774574720 0020272 0 ustar 00root root 0000000 0000000 // Package crypto provides common crypto libraries for V2Ray.
package crypto // import "v2ray.com/core/common/crypto"
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/common/crypto/errors.generated.go 0000664 0000000 0000000 00000000314 13774574720 0022221 0 ustar 00root root 0000000 0000000 package crypto
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/common/crypto/internal/ 0000775 0000000 0000000 00000000000 13774574720 0020237 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/crypto/internal/chacha.go 0000664 0000000 0000000 00000003626 13774574720 0022004 0 ustar 00root root 0000000 0000000 package internal
//go:generate go run chacha_core_gen.go
import (
"encoding/binary"
)
const (
wordSize = 4 // the size of ChaCha20's words
stateSize = 16 // the size of ChaCha20's state, in words
blockSize = stateSize * wordSize // the size of ChaCha20's block, in bytes
)
type ChaCha20Stream struct {
state [stateSize]uint32 // the state as an array of 16 32-bit words
block [blockSize]byte // the keystream as an array of 64 bytes
offset int // the offset of used bytes in block
rounds int
}
func NewChaCha20Stream(key []byte, nonce []byte, rounds int) *ChaCha20Stream {
s := new(ChaCha20Stream)
// the magic constants for 256-bit keys
s.state[0] = 0x61707865
s.state[1] = 0x3320646e
s.state[2] = 0x79622d32
s.state[3] = 0x6b206574
for i := 0; i < 8; i++ {
s.state[i+4] = binary.LittleEndian.Uint32(key[i*4 : i*4+4])
}
switch len(nonce) {
case 8:
s.state[14] = binary.LittleEndian.Uint32(nonce[0:])
s.state[15] = binary.LittleEndian.Uint32(nonce[4:])
case 12:
s.state[13] = binary.LittleEndian.Uint32(nonce[0:4])
s.state[14] = binary.LittleEndian.Uint32(nonce[4:8])
s.state[15] = binary.LittleEndian.Uint32(nonce[8:12])
default:
panic("bad nonce length")
}
s.rounds = rounds
ChaCha20Block(&s.state, s.block[:], s.rounds)
return s
}
func (s *ChaCha20Stream) XORKeyStream(dst, src []byte) {
// Stride over the input in 64-byte blocks, minus the amount of keystream
// previously used. This will produce best results when processing blocks
// of a size evenly divisible by 64.
i := 0
max := len(src)
for i < max {
gap := blockSize - s.offset
limit := i + gap
if limit > max {
limit = max
}
o := s.offset
for j := i; j < limit; j++ {
dst[j] = src[j] ^ s.block[o]
o++
}
i += gap
s.offset = o
if o == blockSize {
s.offset = 0
s.state[12]++
ChaCha20Block(&s.state, s.block[:], s.rounds)
}
}
}
v2ray-core-4.34.0/common/crypto/internal/chacha_core.generated.go 0000664 0000000 0000000 00000006127 13774574720 0024750 0 ustar 00root root 0000000 0000000 package internal
import "encoding/binary"
func ChaCha20Block(s *[16]uint32, out []byte, rounds int) {
var x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 = s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15]
for i := 0; i < rounds; i += 2 {
var x uint32
x0 += x4
x = x12 ^ x0
x12 = (x << 16) | (x >> (32 - 16))
x8 += x12
x = x4 ^ x8
x4 = (x << 12) | (x >> (32 - 12))
x0 += x4
x = x12 ^ x0
x12 = (x << 8) | (x >> (32 - 8))
x8 += x12
x = x4 ^ x8
x4 = (x << 7) | (x >> (32 - 7))
x1 += x5
x = x13 ^ x1
x13 = (x << 16) | (x >> (32 - 16))
x9 += x13
x = x5 ^ x9
x5 = (x << 12) | (x >> (32 - 12))
x1 += x5
x = x13 ^ x1
x13 = (x << 8) | (x >> (32 - 8))
x9 += x13
x = x5 ^ x9
x5 = (x << 7) | (x >> (32 - 7))
x2 += x6
x = x14 ^ x2
x14 = (x << 16) | (x >> (32 - 16))
x10 += x14
x = x6 ^ x10
x6 = (x << 12) | (x >> (32 - 12))
x2 += x6
x = x14 ^ x2
x14 = (x << 8) | (x >> (32 - 8))
x10 += x14
x = x6 ^ x10
x6 = (x << 7) | (x >> (32 - 7))
x3 += x7
x = x15 ^ x3
x15 = (x << 16) | (x >> (32 - 16))
x11 += x15
x = x7 ^ x11
x7 = (x << 12) | (x >> (32 - 12))
x3 += x7
x = x15 ^ x3
x15 = (x << 8) | (x >> (32 - 8))
x11 += x15
x = x7 ^ x11
x7 = (x << 7) | (x >> (32 - 7))
x0 += x5
x = x15 ^ x0
x15 = (x << 16) | (x >> (32 - 16))
x10 += x15
x = x5 ^ x10
x5 = (x << 12) | (x >> (32 - 12))
x0 += x5
x = x15 ^ x0
x15 = (x << 8) | (x >> (32 - 8))
x10 += x15
x = x5 ^ x10
x5 = (x << 7) | (x >> (32 - 7))
x1 += x6
x = x12 ^ x1
x12 = (x << 16) | (x >> (32 - 16))
x11 += x12
x = x6 ^ x11
x6 = (x << 12) | (x >> (32 - 12))
x1 += x6
x = x12 ^ x1
x12 = (x << 8) | (x >> (32 - 8))
x11 += x12
x = x6 ^ x11
x6 = (x << 7) | (x >> (32 - 7))
x2 += x7
x = x13 ^ x2
x13 = (x << 16) | (x >> (32 - 16))
x8 += x13
x = x7 ^ x8
x7 = (x << 12) | (x >> (32 - 12))
x2 += x7
x = x13 ^ x2
x13 = (x << 8) | (x >> (32 - 8))
x8 += x13
x = x7 ^ x8
x7 = (x << 7) | (x >> (32 - 7))
x3 += x4
x = x14 ^ x3
x14 = (x << 16) | (x >> (32 - 16))
x9 += x14
x = x4 ^ x9
x4 = (x << 12) | (x >> (32 - 12))
x3 += x4
x = x14 ^ x3
x14 = (x << 8) | (x >> (32 - 8))
x9 += x14
x = x4 ^ x9
x4 = (x << 7) | (x >> (32 - 7))
}
binary.LittleEndian.PutUint32(out[0:4], s[0]+x0)
binary.LittleEndian.PutUint32(out[4:8], s[1]+x1)
binary.LittleEndian.PutUint32(out[8:12], s[2]+x2)
binary.LittleEndian.PutUint32(out[12:16], s[3]+x3)
binary.LittleEndian.PutUint32(out[16:20], s[4]+x4)
binary.LittleEndian.PutUint32(out[20:24], s[5]+x5)
binary.LittleEndian.PutUint32(out[24:28], s[6]+x6)
binary.LittleEndian.PutUint32(out[28:32], s[7]+x7)
binary.LittleEndian.PutUint32(out[32:36], s[8]+x8)
binary.LittleEndian.PutUint32(out[36:40], s[9]+x9)
binary.LittleEndian.PutUint32(out[40:44], s[10]+x10)
binary.LittleEndian.PutUint32(out[44:48], s[11]+x11)
binary.LittleEndian.PutUint32(out[48:52], s[12]+x12)
binary.LittleEndian.PutUint32(out[52:56], s[13]+x13)
binary.LittleEndian.PutUint32(out[56:60], s[14]+x14)
binary.LittleEndian.PutUint32(out[60:64], s[15]+x15)
}
v2ray-core-4.34.0/common/crypto/internal/chacha_core_gen.go 0000664 0000000 0000000 00000003423 13774574720 0023640 0 ustar 00root root 0000000 0000000 // +build generate
package main
import (
"fmt"
"log"
"os"
)
func writeQuarterRound(file *os.File, a, b, c, d int) {
add := "x%d+=x%d\n"
xor := "x=x%d^x%d\n"
rotate := "x%d=(x << %d) | (x >> (32 - %d))\n"
fmt.Fprintf(file, add, a, b)
fmt.Fprintf(file, xor, d, a)
fmt.Fprintf(file, rotate, d, 16, 16)
fmt.Fprintf(file, add, c, d)
fmt.Fprintf(file, xor, b, c)
fmt.Fprintf(file, rotate, b, 12, 12)
fmt.Fprintf(file, add, a, b)
fmt.Fprintf(file, xor, d, a)
fmt.Fprintf(file, rotate, d, 8, 8)
fmt.Fprintf(file, add, c, d)
fmt.Fprintf(file, xor, b, c)
fmt.Fprintf(file, rotate, b, 7, 7)
}
func writeChacha20Block(file *os.File) {
fmt.Fprintln(file, `
func ChaCha20Block(s *[16]uint32, out []byte, rounds int) {
var x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15 = s[0],s[1],s[2],s[3],s[4],s[5],s[6],s[7],s[8],s[9],s[10],s[11],s[12],s[13],s[14],s[15]
for i := 0; i < rounds; i+=2 {
var x uint32
`)
writeQuarterRound(file, 0, 4, 8, 12)
writeQuarterRound(file, 1, 5, 9, 13)
writeQuarterRound(file, 2, 6, 10, 14)
writeQuarterRound(file, 3, 7, 11, 15)
writeQuarterRound(file, 0, 5, 10, 15)
writeQuarterRound(file, 1, 6, 11, 12)
writeQuarterRound(file, 2, 7, 8, 13)
writeQuarterRound(file, 3, 4, 9, 14)
fmt.Fprintln(file, "}")
for i := 0; i < 16; i++ {
fmt.Fprintf(file, "binary.LittleEndian.PutUint32(out[%d:%d], s[%d]+x%d)\n", i*4, i*4+4, i, i)
}
fmt.Fprintln(file, "}")
fmt.Fprintln(file)
}
func main() {
file, err := os.OpenFile("chacha_core.generated.go", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
if err != nil {
log.Fatalf("Failed to generate chacha_core.go: %v", err)
}
defer file.Close()
fmt.Fprintln(file, "package internal")
fmt.Fprintln(file)
fmt.Fprintln(file, "import \"encoding/binary\"")
fmt.Fprintln(file)
writeChacha20Block(file)
}
v2ray-core-4.34.0/common/crypto/io.go 0000664 0000000 0000000 00000002505 13774574720 0017363 0 ustar 00root root 0000000 0000000 package crypto
import (
"crypto/cipher"
"io"
"v2ray.com/core/common/buf"
)
type CryptionReader struct {
stream cipher.Stream
reader io.Reader
}
func NewCryptionReader(stream cipher.Stream, reader io.Reader) *CryptionReader {
return &CryptionReader{
stream: stream,
reader: reader,
}
}
func (r *CryptionReader) Read(data []byte) (int, error) {
nBytes, err := r.reader.Read(data)
if nBytes > 0 {
r.stream.XORKeyStream(data[:nBytes], data[:nBytes])
}
return nBytes, err
}
var (
_ buf.Writer = (*CryptionWriter)(nil)
)
type CryptionWriter struct {
stream cipher.Stream
writer io.Writer
bufWriter buf.Writer
}
// NewCryptionWriter creates a new CryptionWriter.
func NewCryptionWriter(stream cipher.Stream, writer io.Writer) *CryptionWriter {
return &CryptionWriter{
stream: stream,
writer: writer,
bufWriter: buf.NewWriter(writer),
}
}
// Write implements io.Writer.Write().
func (w *CryptionWriter) Write(data []byte) (int, error) {
w.stream.XORKeyStream(data, data)
if err := buf.WriteAllBytes(w.writer, data); err != nil {
return 0, err
}
return len(data), nil
}
// WriteMultiBuffer implements buf.Writer.
func (w *CryptionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
for _, b := range mb {
w.stream.XORKeyStream(b.Bytes(), b.Bytes())
}
return w.bufWriter.WriteMultiBuffer(mb)
}
v2ray-core-4.34.0/common/dice/ 0000775 0000000 0000000 00000000000 13774574720 0016007 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/dice/dice.go 0000664 0000000 0000000 00000002041 13774574720 0017237 0 ustar 00root root 0000000 0000000 // Package dice contains common functions to generate random number.
// It also initialize math/rand with the time in seconds at launch time.
package dice // import "v2ray.com/core/common/dice"
import (
"math/rand"
"time"
)
// Roll returns a non-negative number between 0 (inclusive) and n (exclusive).
func Roll(n int) int {
if n == 1 {
return 0
}
return rand.Intn(n)
}
// Roll returns a non-negative number between 0 (inclusive) and n (exclusive).
func RollDeterministic(n int, seed int64) int {
if n == 1 {
return 0
}
return rand.New(rand.NewSource(seed)).Intn(n)
}
// RollUint16 returns a random uint16 value.
func RollUint16() uint16 {
return uint16(rand.Int63() >> 47)
}
func RollUint64() uint64 {
return rand.Uint64()
}
func NewDeterministicDice(seed int64) *DeterministicDice {
return &DeterministicDice{rand.New(rand.NewSource(seed))}
}
type DeterministicDice struct {
*rand.Rand
}
func (dd *DeterministicDice) Roll(n int) int {
if n == 1 {
return 0
}
return dd.Intn(n)
}
func init() {
rand.Seed(time.Now().Unix())
}
v2ray-core-4.34.0/common/dice/dice_test.go 0000664 0000000 0000000 00000001327 13774574720 0020304 0 ustar 00root root 0000000 0000000 package dice_test
import (
"math/rand"
"testing"
. "v2ray.com/core/common/dice"
)
func BenchmarkRoll1(b *testing.B) {
for i := 0; i < b.N; i++ {
Roll(1)
}
}
func BenchmarkRoll20(b *testing.B) {
for i := 0; i < b.N; i++ {
Roll(20)
}
}
func BenchmarkIntn1(b *testing.B) {
for i := 0; i < b.N; i++ {
rand.Intn(1)
}
}
func BenchmarkIntn20(b *testing.B) {
for i := 0; i < b.N; i++ {
rand.Intn(20)
}
}
func BenchmarkInt63(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = uint16(rand.Int63() >> 47)
}
}
func BenchmarkInt31(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = uint16(rand.Int31() >> 15)
}
}
func BenchmarkIntn(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = uint16(rand.Intn(65536))
}
}
v2ray-core-4.34.0/common/errors.generated.go 0000664 0000000 0000000 00000000314 13774574720 0020701 0 ustar 00root root 0000000 0000000 package common
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/common/errors/ 0000775 0000000 0000000 00000000000 13774574720 0016417 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/errors/errorgen/ 0000775 0000000 0000000 00000000000 13774574720 0020242 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/errors/errorgen/main.go 0000664 0000000 0000000 00000002024 13774574720 0021513 0 ustar 00root root 0000000 0000000 package main
import (
"fmt"
"log"
"os"
"path/filepath"
"v2ray.com/core/common"
)
func main() {
pwd, err := os.Getwd()
if err != nil {
fmt.Println("can not get current working directory")
os.Exit(1)
}
pkg := filepath.Base(pwd)
if pkg == "v2ray-core" {
pkg = "core"
}
moduleName, gmnErr := common.GetModuleName(pwd)
if gmnErr != nil {
fmt.Println("can not get module path", gmnErr)
os.Exit(1)
}
file, err := os.OpenFile("errors.generated.go", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
if err != nil {
log.Fatalf("Failed to generate errors.generated.go: %v", err)
os.Exit(1)
}
defer file.Close()
fmt.Fprintln(file, "package", pkg)
fmt.Fprintln(file, "")
fmt.Fprintln(file, "import \""+moduleName+"/common/errors\"")
fmt.Fprintln(file, "")
fmt.Fprintln(file, "type errPathObjHolder struct{}")
fmt.Fprintln(file, "")
fmt.Fprintln(file, "func newError(values ...interface{}) *errors.Error {")
fmt.Fprintln(file, " return errors.New(values...).WithPathObj(errPathObjHolder{})")
fmt.Fprintln(file, "}")
}
v2ray-core-4.34.0/common/errors/errors.go 0000664 0000000 0000000 00000007244 13774574720 0020271 0 ustar 00root root 0000000 0000000 // Package errors is a drop-in replacement for Golang lib 'errors'.
package errors // import "v2ray.com/core/common/errors"
import (
"os"
"reflect"
"strings"
"v2ray.com/core/common/log"
"v2ray.com/core/common/serial"
)
type hasInnerError interface {
// Inner returns the underlying error of this one.
Inner() error
}
type hasSeverity interface {
Severity() log.Severity
}
// Error is an error object with underlying error.
type Error struct {
pathObj interface{}
prefix []interface{}
message []interface{}
inner error
severity log.Severity
}
func (err *Error) WithPathObj(obj interface{}) *Error {
err.pathObj = obj
return err
}
func (err *Error) pkgPath() string {
if err.pathObj == nil {
return ""
}
return reflect.TypeOf(err.pathObj).PkgPath()
}
// Error implements error.Error().
func (err *Error) Error() string {
builder := strings.Builder{}
for _, prefix := range err.prefix {
builder.WriteByte('[')
builder.WriteString(serial.ToString(prefix))
builder.WriteString("] ")
}
path := err.pkgPath()
if len(path) > 0 {
builder.WriteString(path)
builder.WriteString(": ")
}
msg := serial.Concat(err.message...)
builder.WriteString(msg)
if err.inner != nil {
builder.WriteString(" > ")
builder.WriteString(err.inner.Error())
}
return builder.String()
}
// Inner implements hasInnerError.Inner()
func (err *Error) Inner() error {
if err.inner == nil {
return nil
}
return err.inner
}
func (err *Error) Base(e error) *Error {
err.inner = e
return err
}
func (err *Error) atSeverity(s log.Severity) *Error {
err.severity = s
return err
}
func (err *Error) Severity() log.Severity {
if err.inner == nil {
return err.severity
}
if s, ok := err.inner.(hasSeverity); ok {
as := s.Severity()
if as < err.severity {
return as
}
}
return err.severity
}
// AtDebug sets the severity to debug.
func (err *Error) AtDebug() *Error {
return err.atSeverity(log.Severity_Debug)
}
// AtInfo sets the severity to info.
func (err *Error) AtInfo() *Error {
return err.atSeverity(log.Severity_Info)
}
// AtWarning sets the severity to warning.
func (err *Error) AtWarning() *Error {
return err.atSeverity(log.Severity_Warning)
}
// AtError sets the severity to error.
func (err *Error) AtError() *Error {
return err.atSeverity(log.Severity_Error)
}
// String returns the string representation of this error.
func (err *Error) String() string {
return err.Error()
}
// WriteToLog writes current error into log.
func (err *Error) WriteToLog(opts ...ExportOption) {
var holder ExportOptionHolder
for _, opt := range opts {
opt(&holder)
}
if holder.SessionID > 0 {
err.prefix = append(err.prefix, holder.SessionID)
}
log.Record(&log.GeneralMessage{
Severity: GetSeverity(err),
Content: err,
})
}
type ExportOptionHolder struct {
SessionID uint32
}
type ExportOption func(*ExportOptionHolder)
// New returns a new error object with message formed from given arguments.
func New(msg ...interface{}) *Error {
return &Error{
message: msg,
severity: log.Severity_Info,
}
}
// Cause returns the root cause of this error.
func Cause(err error) error {
if err == nil {
return nil
}
L:
for {
switch inner := err.(type) {
case hasInnerError:
if inner.Inner() == nil {
break L
}
err = inner.Inner()
case *os.PathError:
if inner.Err == nil {
break L
}
err = inner.Err
case *os.SyscallError:
if inner.Err == nil {
break L
}
err = inner.Err
default:
break L
}
}
return err
}
// GetSeverity returns the actual severity of the error, including inner errors.
func GetSeverity(err error) log.Severity {
if s, ok := err.(hasSeverity); ok {
return s.Severity()
}
return log.Severity_Info
}
v2ray-core-4.34.0/common/errors/errors_test.go 0000664 0000000 0000000 00000002336 13774574720 0021325 0 ustar 00root root 0000000 0000000 package errors_test
import (
"io"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
. "v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
)
func TestError(t *testing.T) {
err := New("TestError")
if v := GetSeverity(err); v != log.Severity_Info {
t.Error("severity: ", v)
}
err = New("TestError2").Base(io.EOF)
if v := GetSeverity(err); v != log.Severity_Info {
t.Error("severity: ", v)
}
err = New("TestError3").Base(io.EOF).AtWarning()
if v := GetSeverity(err); v != log.Severity_Warning {
t.Error("severity: ", v)
}
err = New("TestError4").Base(io.EOF).AtWarning()
err = New("TestError5").Base(err)
if v := GetSeverity(err); v != log.Severity_Warning {
t.Error("severity: ", v)
}
if v := err.Error(); !strings.Contains(v, "EOF") {
t.Error("error: ", v)
}
}
type e struct{}
func TestErrorMessage(t *testing.T) {
data := []struct {
err error
msg string
}{
{
err: New("a").Base(New("b")).WithPathObj(e{}),
msg: "v2ray.com/core/common/errors_test: a > b",
},
{
err: New("a").Base(New("b").WithPathObj(e{})),
msg: "a > v2ray.com/core/common/errors_test: b",
},
}
for _, d := range data {
if diff := cmp.Diff(d.msg, d.err.Error()); diff != "" {
t.Error(diff)
}
}
}
v2ray-core-4.34.0/common/errors/multi_error.go 0000664 0000000 0000000 00000000711 13774574720 0021310 0 ustar 00root root 0000000 0000000 package errors
import (
"strings"
)
type multiError []error
func (e multiError) Error() string {
var r strings.Builder
r.WriteString("multierr: ")
for _, err := range e {
r.WriteString(err.Error())
r.WriteString(" | ")
}
return r.String()
}
func Combine(maybeError ...error) error {
var errs multiError
for _, err := range maybeError {
if err != nil {
errs = append(errs, err)
}
}
if len(errs) == 0 {
return nil
}
return errs
}
v2ray-core-4.34.0/common/interfaces.go 0000664 0000000 0000000 00000003176 13774574720 0017564 0 ustar 00root root 0000000 0000000 package common
import "v2ray.com/core/common/errors"
// Closable is the interface for objects that can release its resources.
//
// v2ray:api:beta
type Closable interface {
// Close release all resources used by this object, including goroutines.
Close() error
}
// Interruptible is an interface for objects that can be stopped before its completion.
//
// v2ray:api:beta
type Interruptible interface {
Interrupt()
}
// Close closes the obj if it is a Closable.
//
// v2ray:api:beta
func Close(obj interface{}) error {
if c, ok := obj.(Closable); ok {
return c.Close()
}
return nil
}
// Interrupt calls Interrupt() if object implements Interruptible interface, or Close() if the object implements Closable interface.
//
// v2ray:api:beta
func Interrupt(obj interface{}) error {
if c, ok := obj.(Interruptible); ok {
c.Interrupt()
return nil
}
return Close(obj)
}
// Runnable is the interface for objects that can start to work and stop on demand.
type Runnable interface {
// Start starts the runnable object. Upon the method returning nil, the object begins to function properly.
Start() error
Closable
}
// HasType is the interface for objects that knows its type.
type HasType interface {
// Type returns the type of the object.
// Usually it returns (*Type)(nil) of the object.
Type() interface{}
}
// ChainedClosable is a Closable that consists of multiple Closable objects.
type ChainedClosable []Closable
// Close implements Closable.
func (cc ChainedClosable) Close() error {
var errs []error
for _, c := range cc {
if err := c.Close(); err != nil {
errs = append(errs, err)
}
}
return errors.Combine(errs...)
}
v2ray-core-4.34.0/common/log/ 0000775 0000000 0000000 00000000000 13774574720 0015664 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/log/access.go 0000664 0000000 0000000 00000002516 13774574720 0017460 0 ustar 00root root 0000000 0000000 package log
import (
"context"
"strings"
"v2ray.com/core/common/serial"
)
type logKey int
const (
accessMessageKey logKey = iota
)
type AccessStatus string
const (
AccessAccepted = AccessStatus("accepted")
AccessRejected = AccessStatus("rejected")
)
type AccessMessage struct {
From interface{}
To interface{}
Status AccessStatus
Reason interface{}
Email string
Detour string
}
func (m *AccessMessage) String() string {
builder := strings.Builder{}
builder.WriteString(serial.ToString(m.From))
builder.WriteByte(' ')
builder.WriteString(string(m.Status))
builder.WriteByte(' ')
builder.WriteString(serial.ToString(m.To))
if len(m.Detour) > 0 {
builder.WriteString(" [")
builder.WriteString(m.Detour)
builder.WriteByte(']')
}
if reason := serial.ToString(m.Reason); len(reason) > 0 {
builder.WriteString(" ")
builder.WriteString(reason)
}
if len(m.Email) > 0 {
builder.WriteString(" email: ")
builder.WriteString(m.Email)
}
return builder.String()
}
func ContextWithAccessMessage(ctx context.Context, accessMessage *AccessMessage) context.Context {
return context.WithValue(ctx, accessMessageKey, accessMessage)
}
func AccessMessageFromContext(ctx context.Context) *AccessMessage {
if accessMessage, ok := ctx.Value(accessMessageKey).(*AccessMessage); ok {
return accessMessage
}
return nil
}
v2ray-core-4.34.0/common/log/log.go 0000664 0000000 0000000 00000002306 13774574720 0016775 0 ustar 00root root 0000000 0000000 package log // import "v2ray.com/core/common/log"
import (
"sync"
"v2ray.com/core/common/serial"
)
// Message is the interface for all log messages.
type Message interface {
String() string
}
// Handler is the interface for log handler.
type Handler interface {
Handle(msg Message)
}
// GeneralMessage is a general log message that can contain all kind of content.
type GeneralMessage struct {
Severity Severity
Content interface{}
}
// String implements Message.
func (m *GeneralMessage) String() string {
return serial.Concat("[", m.Severity, "] ", m.Content)
}
// Record writes a message into log stream.
func Record(msg Message) {
logHandler.Handle(msg)
}
var (
logHandler syncHandler
)
// RegisterHandler register a new handler as current log handler. Previous registered handler will be discarded.
func RegisterHandler(handler Handler) {
if handler == nil {
panic("Log handler is nil")
}
logHandler.Set(handler)
}
type syncHandler struct {
sync.RWMutex
Handler
}
func (h *syncHandler) Handle(msg Message) {
h.RLock()
defer h.RUnlock()
if h.Handler != nil {
h.Handler.Handle(msg)
}
}
func (h *syncHandler) Set(handler Handler) {
h.Lock()
defer h.Unlock()
h.Handler = handler
}
v2ray-core-4.34.0/common/log/log.pb.go 0000664 0000000 0000000 00000011443 13774574720 0017377 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: common/log/log.proto
package log
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Severity int32
const (
Severity_Unknown Severity = 0
Severity_Error Severity = 1
Severity_Warning Severity = 2
Severity_Info Severity = 3
Severity_Debug Severity = 4
)
// Enum value maps for Severity.
var (
Severity_name = map[int32]string{
0: "Unknown",
1: "Error",
2: "Warning",
3: "Info",
4: "Debug",
}
Severity_value = map[string]int32{
"Unknown": 0,
"Error": 1,
"Warning": 2,
"Info": 3,
"Debug": 4,
}
)
func (x Severity) Enum() *Severity {
p := new(Severity)
*p = x
return p
}
func (x Severity) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Severity) Descriptor() protoreflect.EnumDescriptor {
return file_common_log_log_proto_enumTypes[0].Descriptor()
}
func (Severity) Type() protoreflect.EnumType {
return &file_common_log_log_proto_enumTypes[0]
}
func (x Severity) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Severity.Descriptor instead.
func (Severity) EnumDescriptor() ([]byte, []int) {
return file_common_log_log_proto_rawDescGZIP(), []int{0}
}
var File_common_log_log_proto protoreflect.FileDescriptor
var file_common_log_log_proto_rawDesc = []byte{
0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x6c, 0x6f, 0x67,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6c, 0x6f, 0x67, 0x2a, 0x44, 0x0a,
0x08, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b,
0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10,
0x01, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x10, 0x02, 0x12, 0x08,
0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x65, 0x62, 0x75,
0x67, 0x10, 0x04, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6c, 0x6f, 0x67,
0x50, 0x01, 0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f,
0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6c, 0x6f, 0x67, 0xaa, 0x02, 0x15,
0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_common_log_log_proto_rawDescOnce sync.Once
file_common_log_log_proto_rawDescData = file_common_log_log_proto_rawDesc
)
func file_common_log_log_proto_rawDescGZIP() []byte {
file_common_log_log_proto_rawDescOnce.Do(func() {
file_common_log_log_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_log_log_proto_rawDescData)
})
return file_common_log_log_proto_rawDescData
}
var file_common_log_log_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_common_log_log_proto_goTypes = []interface{}{
(Severity)(0), // 0: v2ray.core.common.log.Severity
}
var file_common_log_log_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_common_log_log_proto_init() }
func file_common_log_log_proto_init() {
if File_common_log_log_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_log_log_proto_rawDesc,
NumEnums: 1,
NumMessages: 0,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_log_log_proto_goTypes,
DependencyIndexes: file_common_log_log_proto_depIdxs,
EnumInfos: file_common_log_log_proto_enumTypes,
}.Build()
File_common_log_log_proto = out.File
file_common_log_log_proto_rawDesc = nil
file_common_log_log_proto_goTypes = nil
file_common_log_log_proto_depIdxs = nil
}
v2ray-core-4.34.0/common/log/log.proto 0000664 0000000 0000000 00000000504 13774574720 0017531 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.common.log;
option csharp_namespace = "V2Ray.Core.Common.Log";
option go_package = "v2ray.com/core/common/log";
option java_package = "com.v2ray.core.common.log";
option java_multiple_files = true;
enum Severity {
Unknown = 0;
Error = 1;
Warning = 2;
Info = 3;
Debug = 4;
}
v2ray-core-4.34.0/common/log/log_test.go 0000664 0000000 0000000 00000001040 13774574720 0020026 0 ustar 00root root 0000000 0000000 package log_test
import (
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
)
type testLogger struct {
value string
}
func (l *testLogger) Handle(msg log.Message) {
l.value = msg.String()
}
func TestLogRecord(t *testing.T) {
var logger testLogger
log.RegisterHandler(&logger)
ip := "8.8.8.8"
log.Record(&log.GeneralMessage{
Severity: log.Severity_Error,
Content: net.ParseAddress(ip),
})
if diff := cmp.Diff("[Error] "+ip, logger.value); diff != "" {
t.Error(diff)
}
}
v2ray-core-4.34.0/common/log/logger.go 0000664 0000000 0000000 00000005627 13774574720 0017504 0 ustar 00root root 0000000 0000000 package log
import (
"io"
"log"
"os"
"time"
"v2ray.com/core/common/platform"
"v2ray.com/core/common/signal/done"
"v2ray.com/core/common/signal/semaphore"
)
// Writer is the interface for writing logs.
type Writer interface {
Write(string) error
io.Closer
}
// WriterCreator is a function to create LogWriters.
type WriterCreator func() Writer
type generalLogger struct {
creator WriterCreator
buffer chan Message
access *semaphore.Instance
done *done.Instance
}
// NewLogger returns a generic log handler that can handle all type of messages.
func NewLogger(logWriterCreator WriterCreator) Handler {
return &generalLogger{
creator: logWriterCreator,
buffer: make(chan Message, 16),
access: semaphore.New(1),
done: done.New(),
}
}
func (l *generalLogger) run() {
defer l.access.Signal()
dataWritten := false
ticker := time.NewTicker(time.Minute)
defer ticker.Stop()
logger := l.creator()
if logger == nil {
return
}
defer logger.Close()
for {
select {
case <-l.done.Wait():
return
case msg := <-l.buffer:
logger.Write(msg.String() + platform.LineSeparator())
dataWritten = true
case <-ticker.C:
if !dataWritten {
return
}
dataWritten = false
}
}
}
func (l *generalLogger) Handle(msg Message) {
select {
case l.buffer <- msg:
default:
}
select {
case <-l.access.Wait():
go l.run()
default:
}
}
func (l *generalLogger) Close() error {
return l.done.Close()
}
type consoleLogWriter struct {
logger *log.Logger
}
func (w *consoleLogWriter) Write(s string) error {
w.logger.Print(s)
return nil
}
func (w *consoleLogWriter) Close() error {
return nil
}
type fileLogWriter struct {
file *os.File
logger *log.Logger
}
func (w *fileLogWriter) Write(s string) error {
w.logger.Print(s)
return nil
}
func (w *fileLogWriter) Close() error {
return w.file.Close()
}
// CreateStdoutLogWriter returns a LogWriterCreator that creates LogWriter for stdout.
func CreateStdoutLogWriter() WriterCreator {
return func() Writer {
return &consoleLogWriter{
logger: log.New(os.Stdout, "", log.Ldate|log.Ltime),
}
}
}
// CreateStderrLogWriter returns a LogWriterCreator that creates LogWriter for stderr.
func CreateStderrLogWriter() WriterCreator {
return func() Writer {
return &consoleLogWriter{
logger: log.New(os.Stderr, "", log.Ldate|log.Ltime),
}
}
}
// CreateFileLogWriter returns a LogWriterCreator that creates LogWriter for the given file.
func CreateFileLogWriter(path string) (WriterCreator, error) {
file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
return nil, err
}
file.Close()
return func() Writer {
file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
return nil
}
return &fileLogWriter{
file: file,
logger: log.New(file, "", log.Ldate|log.Ltime),
}
}, nil
}
func init() {
RegisterHandler(NewLogger(CreateStdoutLogWriter()))
}
v2ray-core-4.34.0/common/log/logger_test.go 0000664 0000000 0000000 00000001363 13774574720 0020534 0 ustar 00root root 0000000 0000000 package log_test
import (
"io/ioutil"
"os"
"strings"
"testing"
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
. "v2ray.com/core/common/log"
)
func TestFileLogger(t *testing.T) {
f, err := ioutil.TempFile("", "vtest")
common.Must(err)
path := f.Name()
common.Must(f.Close())
creator, err := CreateFileLogWriter(path)
common.Must(err)
handler := NewLogger(creator)
handler.Handle(&GeneralMessage{Content: "Test Log"})
time.Sleep(2 * time.Second)
common.Must(common.Close(handler))
f, err = os.Open(path)
common.Must(err)
defer f.Close()
b, err := buf.ReadAllToBytes(f)
common.Must(err)
if !strings.Contains(string(b), "Test Log") {
t.Fatal("Expect log text contains 'Test Log', but actually: ", string(b))
}
}
v2ray-core-4.34.0/common/mux/ 0000775 0000000 0000000 00000000000 13774574720 0015714 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/mux/client.go 0000664 0000000 0000000 00000022246 13774574720 0017527 0 ustar 00root root 0000000 0000000 package mux
import (
"context"
"io"
"sync"
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal/done"
"v2ray.com/core/common/task"
"v2ray.com/core/proxy"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/pipe"
)
type ClientManager struct {
Enabled bool // wheather mux is enabled from user config
Picker WorkerPicker
}
func (m *ClientManager) Dispatch(ctx context.Context, link *transport.Link) error {
for i := 0; i < 16; i++ {
worker, err := m.Picker.PickAvailable()
if err != nil {
return err
}
if worker.Dispatch(ctx, link) {
return nil
}
}
return newError("unable to find an available mux client").AtWarning()
}
type WorkerPicker interface {
PickAvailable() (*ClientWorker, error)
}
type IncrementalWorkerPicker struct {
Factory ClientWorkerFactory
access sync.Mutex
workers []*ClientWorker
cleanupTask *task.Periodic
}
func (p *IncrementalWorkerPicker) cleanupFunc() error {
p.access.Lock()
defer p.access.Unlock()
if len(p.workers) == 0 {
return newError("no worker")
}
p.cleanup()
return nil
}
func (p *IncrementalWorkerPicker) cleanup() {
var activeWorkers []*ClientWorker
for _, w := range p.workers {
if !w.Closed() {
activeWorkers = append(activeWorkers, w)
}
}
p.workers = activeWorkers
}
func (p *IncrementalWorkerPicker) findAvailable() int {
for idx, w := range p.workers {
if !w.IsFull() {
return idx
}
}
return -1
}
func (p *IncrementalWorkerPicker) pickInternal() (*ClientWorker, bool, error) {
p.access.Lock()
defer p.access.Unlock()
idx := p.findAvailable()
if idx >= 0 {
n := len(p.workers)
if n > 1 && idx != n-1 {
p.workers[n-1], p.workers[idx] = p.workers[idx], p.workers[n-1]
}
return p.workers[idx], false, nil
}
p.cleanup()
worker, err := p.Factory.Create()
if err != nil {
return nil, false, err
}
p.workers = append(p.workers, worker)
if p.cleanupTask == nil {
p.cleanupTask = &task.Periodic{
Interval: time.Second * 30,
Execute: p.cleanupFunc,
}
}
return worker, true, nil
}
func (p *IncrementalWorkerPicker) PickAvailable() (*ClientWorker, error) {
worker, start, err := p.pickInternal()
if start {
common.Must(p.cleanupTask.Start())
}
return worker, err
}
type ClientWorkerFactory interface {
Create() (*ClientWorker, error)
}
type DialingWorkerFactory struct {
Proxy proxy.Outbound
Dialer internet.Dialer
Strategy ClientStrategy
}
func (f *DialingWorkerFactory) Create() (*ClientWorker, error) {
opts := []pipe.Option{pipe.WithSizeLimit(64 * 1024)}
uplinkReader, upLinkWriter := pipe.New(opts...)
downlinkReader, downlinkWriter := pipe.New(opts...)
c, err := NewClientWorker(transport.Link{
Reader: downlinkReader,
Writer: upLinkWriter,
}, f.Strategy)
if err != nil {
return nil, err
}
go func(p proxy.Outbound, d internet.Dialer, c common.Closable) {
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{
Target: net.TCPDestination(muxCoolAddress, muxCoolPort),
})
ctx, cancel := context.WithCancel(ctx)
if err := p.Process(ctx, &transport.Link{Reader: uplinkReader, Writer: downlinkWriter}, d); err != nil {
errors.New("failed to handler mux client connection").Base(err).WriteToLog()
}
common.Must(c.Close())
cancel()
}(f.Proxy, f.Dialer, c.done)
return c, nil
}
type ClientStrategy struct {
MaxConcurrency uint32
MaxConnection uint32
}
type ClientWorker struct {
sessionManager *SessionManager
link transport.Link
done *done.Instance
strategy ClientStrategy
}
var muxCoolAddress = net.DomainAddress("v1.mux.cool")
var muxCoolPort = net.Port(9527)
// NewClientWorker creates a new mux.Client.
func NewClientWorker(stream transport.Link, s ClientStrategy) (*ClientWorker, error) {
c := &ClientWorker{
sessionManager: NewSessionManager(),
link: stream,
done: done.New(),
strategy: s,
}
go c.fetchOutput()
go c.monitor()
return c, nil
}
func (m *ClientWorker) TotalConnections() uint32 {
return uint32(m.sessionManager.Count())
}
func (m *ClientWorker) ActiveConnections() uint32 {
return uint32(m.sessionManager.Size())
}
// Closed returns true if this Client is closed.
func (m *ClientWorker) Closed() bool {
return m.done.Done()
}
func (m *ClientWorker) monitor() {
timer := time.NewTicker(time.Second * 16)
defer timer.Stop()
for {
select {
case <-m.done.Wait():
m.sessionManager.Close()
common.Close(m.link.Writer)
common.Interrupt(m.link.Reader)
return
case <-timer.C:
size := m.sessionManager.Size()
if size == 0 && m.sessionManager.CloseIfNoSession() {
common.Must(m.done.Close())
}
}
}
}
func writeFirstPayload(reader buf.Reader, writer *Writer) error {
err := buf.CopyOnceTimeout(reader, writer, time.Millisecond*100)
if err == buf.ErrNotTimeoutReader || err == buf.ErrReadTimeout {
return writer.WriteMultiBuffer(buf.MultiBuffer{})
}
if err != nil {
return err
}
return nil
}
func fetchInput(ctx context.Context, s *Session, output buf.Writer) {
dest := session.OutboundFromContext(ctx).Target
transferType := protocol.TransferTypeStream
if dest.Network == net.Network_UDP {
transferType = protocol.TransferTypePacket
}
s.transferType = transferType
writer := NewWriter(s.ID, dest, output, transferType)
defer s.Close()
defer writer.Close()
newError("dispatching request to ", dest).WriteToLog(session.ExportIDToError(ctx))
if err := writeFirstPayload(s.input, writer); err != nil {
newError("failed to write first payload").Base(err).WriteToLog(session.ExportIDToError(ctx))
writer.hasError = true
common.Interrupt(s.input)
return
}
if err := buf.Copy(s.input, writer); err != nil {
newError("failed to fetch all input").Base(err).WriteToLog(session.ExportIDToError(ctx))
writer.hasError = true
common.Interrupt(s.input)
return
}
}
func (m *ClientWorker) IsClosing() bool {
sm := m.sessionManager
if m.strategy.MaxConnection > 0 && sm.Count() >= int(m.strategy.MaxConnection) {
return true
}
return false
}
func (m *ClientWorker) IsFull() bool {
if m.IsClosing() || m.Closed() {
return true
}
sm := m.sessionManager
if m.strategy.MaxConcurrency > 0 && sm.Size() >= int(m.strategy.MaxConcurrency) {
return true
}
return false
}
func (m *ClientWorker) Dispatch(ctx context.Context, link *transport.Link) bool {
if m.IsFull() || m.Closed() {
return false
}
sm := m.sessionManager
s := sm.Allocate()
if s == nil {
return false
}
s.input = link.Reader
s.output = link.Writer
go fetchInput(ctx, s, m.link.Writer)
return true
}
func (m *ClientWorker) handleStatueKeepAlive(meta *FrameMetadata, reader *buf.BufferedReader) error {
if meta.Option.Has(OptionData) {
return buf.Copy(NewStreamReader(reader), buf.Discard)
}
return nil
}
func (m *ClientWorker) handleStatusNew(meta *FrameMetadata, reader *buf.BufferedReader) error {
if meta.Option.Has(OptionData) {
return buf.Copy(NewStreamReader(reader), buf.Discard)
}
return nil
}
func (m *ClientWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.BufferedReader) error {
if !meta.Option.Has(OptionData) {
return nil
}
s, found := m.sessionManager.Get(meta.SessionID)
if !found {
// Notify remote peer to close this session.
closingWriter := NewResponseWriter(meta.SessionID, m.link.Writer, protocol.TransferTypeStream)
closingWriter.Close()
return buf.Copy(NewStreamReader(reader), buf.Discard)
}
rr := s.NewReader(reader)
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()
// Notify remote peer to close this session.
closingWriter := NewResponseWriter(meta.SessionID, m.link.Writer, protocol.TransferTypeStream)
closingWriter.Close()
drainErr := buf.Copy(rr, buf.Discard)
common.Interrupt(s.input)
s.Close()
return drainErr
}
return err
}
func (m *ClientWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.BufferedReader) error {
if s, found := m.sessionManager.Get(meta.SessionID); found {
if meta.Option.Has(OptionError) {
common.Interrupt(s.input)
common.Interrupt(s.output)
}
s.Close()
}
if meta.Option.Has(OptionData) {
return buf.Copy(NewStreamReader(reader), buf.Discard)
}
return nil
}
func (m *ClientWorker) fetchOutput() {
defer func() {
common.Must(m.done.Close())
}()
reader := &buf.BufferedReader{Reader: m.link.Reader}
var meta FrameMetadata
for {
err := meta.Unmarshal(reader)
if err != nil {
if errors.Cause(err) != io.EOF {
newError("failed to read metadata").Base(err).WriteToLog()
}
break
}
switch meta.SessionStatus {
case SessionStatusKeepAlive:
err = m.handleStatueKeepAlive(&meta, reader)
case SessionStatusEnd:
err = m.handleStatusEnd(&meta, reader)
case SessionStatusNew:
err = m.handleStatusNew(&meta, reader)
case SessionStatusKeep:
err = m.handleStatusKeep(&meta, reader)
default:
status := meta.SessionStatus
newError("unknown status: ", status).AtError().WriteToLog()
return
}
if err != nil {
newError("failed to process data").Base(err).WriteToLog()
return
}
}
}
v2ray-core-4.34.0/common/mux/client_test.go 0000664 0000000 0000000 00000005275 13774574720 0020571 0 ustar 00root root 0000000 0000000 package mux_test
import (
"context"
"testing"
"time"
"github.com/golang/mock/gomock"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/mux"
"v2ray.com/core/common/net"
"v2ray.com/core/common/session"
"v2ray.com/core/testing/mocks"
"v2ray.com/core/transport"
"v2ray.com/core/transport/pipe"
)
func TestIncrementalPickerFailure(t *testing.T) {
mockCtl := gomock.NewController(t)
defer mockCtl.Finish()
mockWorkerFactory := mocks.NewMuxClientWorkerFactory(mockCtl)
mockWorkerFactory.EXPECT().Create().Return(nil, errors.New("test"))
picker := mux.IncrementalWorkerPicker{
Factory: mockWorkerFactory,
}
_, err := picker.PickAvailable()
if err == nil {
t.Error("expected error, but nil")
}
}
func TestClientWorkerEOF(t *testing.T) {
reader, writer := pipe.New(pipe.WithoutSizeLimit())
common.Must(writer.Close())
worker, err := mux.NewClientWorker(transport.Link{Reader: reader, Writer: writer}, mux.ClientStrategy{})
common.Must(err)
time.Sleep(time.Millisecond * 500)
f := worker.Dispatch(context.Background(), nil)
if f {
t.Error("expected failed dispatching, but actually not")
}
}
func TestClientWorkerClose(t *testing.T) {
mockCtl := gomock.NewController(t)
defer mockCtl.Finish()
r1, w1 := pipe.New(pipe.WithoutSizeLimit())
worker1, err := mux.NewClientWorker(transport.Link{
Reader: r1,
Writer: w1,
}, mux.ClientStrategy{
MaxConcurrency: 4,
MaxConnection: 4,
})
common.Must(err)
r2, w2 := pipe.New(pipe.WithoutSizeLimit())
worker2, err := mux.NewClientWorker(transport.Link{
Reader: r2,
Writer: w2,
}, mux.ClientStrategy{
MaxConcurrency: 4,
MaxConnection: 4,
})
common.Must(err)
factory := mocks.NewMuxClientWorkerFactory(mockCtl)
gomock.InOrder(
factory.EXPECT().Create().Return(worker1, nil),
factory.EXPECT().Create().Return(worker2, nil),
)
picker := &mux.IncrementalWorkerPicker{
Factory: factory,
}
manager := &mux.ClientManager{
Picker: picker,
}
tr1, tw1 := pipe.New(pipe.WithoutSizeLimit())
ctx1 := session.ContextWithOutbound(context.Background(), &session.Outbound{
Target: net.TCPDestination(net.DomainAddress("www.v2ray.com"), 80),
})
common.Must(manager.Dispatch(ctx1, &transport.Link{
Reader: tr1,
Writer: tw1,
}))
defer tw1.Close()
common.Must(w1.Close())
time.Sleep(time.Millisecond * 500)
if !worker1.Closed() {
t.Error("worker1 is not finished")
}
tr2, tw2 := pipe.New(pipe.WithoutSizeLimit())
ctx2 := session.ContextWithOutbound(context.Background(), &session.Outbound{
Target: net.TCPDestination(net.DomainAddress("www.v2ray.com"), 80),
})
common.Must(manager.Dispatch(ctx2, &transport.Link{
Reader: tr2,
Writer: tw2,
}))
defer tw2.Close()
common.Must(w2.Close())
}
v2ray-core-4.34.0/common/mux/errors.generated.go 0000664 0000000 0000000 00000000311 13774574720 0021507 0 ustar 00root root 0000000 0000000 package mux
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/common/mux/frame.go 0000664 0000000 0000000 00000006441 13774574720 0017342 0 ustar 00root root 0000000 0000000 package mux
import (
"encoding/binary"
"io"
"v2ray.com/core/common"
"v2ray.com/core/common/bitmask"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
)
type SessionStatus byte
const (
SessionStatusNew SessionStatus = 0x01
SessionStatusKeep SessionStatus = 0x02
SessionStatusEnd SessionStatus = 0x03
SessionStatusKeepAlive SessionStatus = 0x04
)
const (
OptionData bitmask.Byte = 0x01
OptionError bitmask.Byte = 0x02
)
type TargetNetwork byte
const (
TargetNetworkTCP TargetNetwork = 0x01
TargetNetworkUDP TargetNetwork = 0x02
)
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(),
)
/*
Frame format
2 bytes - length
2 bytes - session id
1 bytes - status
1 bytes - option
1 byte - network
2 bytes - port
n bytes - address
*/
type FrameMetadata struct {
Target net.Destination
SessionID uint16
Option bitmask.Byte
SessionStatus SessionStatus
}
func (f FrameMetadata) WriteTo(b *buf.Buffer) error {
lenBytes := b.Extend(2)
len0 := b.Len()
sessionBytes := b.Extend(2)
binary.BigEndian.PutUint16(sessionBytes, f.SessionID)
common.Must(b.WriteByte(byte(f.SessionStatus)))
common.Must(b.WriteByte(byte(f.Option)))
if f.SessionStatus == SessionStatusNew {
switch f.Target.Network {
case net.Network_TCP:
common.Must(b.WriteByte(byte(TargetNetworkTCP)))
case net.Network_UDP:
common.Must(b.WriteByte(byte(TargetNetworkUDP)))
}
if err := addrParser.WriteAddressPort(b, f.Target.Address, f.Target.Port); err != nil {
return err
}
}
len1 := b.Len()
binary.BigEndian.PutUint16(lenBytes, uint16(len1-len0))
return nil
}
// Unmarshal reads FrameMetadata from the given reader.
func (f *FrameMetadata) Unmarshal(reader io.Reader) error {
metaLen, err := serial.ReadUint16(reader)
if err != nil {
return err
}
if metaLen > 512 {
return newError("invalid metalen ", metaLen).AtError()
}
b := buf.New()
defer b.Release()
if _, err := b.ReadFullFrom(reader, int32(metaLen)); err != nil {
return err
}
return f.UnmarshalFromBuffer(b)
}
// UnmarshalFromBuffer reads a FrameMetadata from the given buffer.
// Visible for testing only.
func (f *FrameMetadata) UnmarshalFromBuffer(b *buf.Buffer) error {
if b.Len() < 4 {
return newError("insufficient buffer: ", b.Len())
}
f.SessionID = binary.BigEndian.Uint16(b.BytesTo(2))
f.SessionStatus = SessionStatus(b.Byte(2))
f.Option = bitmask.Byte(b.Byte(3))
f.Target.Network = net.Network_Unknown
if f.SessionStatus == SessionStatusNew {
if b.Len() < 8 {
return newError("insufficient buffer: ", b.Len())
}
network := TargetNetwork(b.Byte(4))
b.Advance(5)
addr, port, err := addrParser.ReadAddressPort(nil, b)
if err != nil {
return newError("failed to parse address and port").Base(err)
}
switch network {
case TargetNetworkTCP:
f.Target = net.TCPDestination(addr, port)
case TargetNetworkUDP:
f.Target = net.UDPDestination(addr, port)
default:
return newError("unknown network type: ", network)
}
}
return nil
}
v2ray-core-4.34.0/common/mux/frame_test.go 0000664 0000000 0000000 00000000772 13774574720 0020402 0 ustar 00root root 0000000 0000000 package mux_test
import (
"testing"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/mux"
"v2ray.com/core/common/net"
)
func BenchmarkFrameWrite(b *testing.B) {
frame := mux.FrameMetadata{
Target: net.TCPDestination(net.DomainAddress("www.v2ray.com"), net.Port(80)),
SessionID: 1,
SessionStatus: mux.SessionStatusNew,
}
writer := buf.New()
defer writer.Release()
for i := 0; i < b.N; i++ {
common.Must(frame.WriteTo(writer))
writer.Clear()
}
}
v2ray-core-4.34.0/common/mux/mux.go 0000664 0000000 0000000 00000000110 13774574720 0017044 0 ustar 00root root 0000000 0000000 package mux
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/common/mux/mux_test.go 0000664 0000000 0000000 00000010067 13774574720 0020117 0 ustar 00root root 0000000 0000000 package mux_test
import (
"io"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
. "v2ray.com/core/common/mux"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/transport/pipe"
)
func readAll(reader buf.Reader) (buf.MultiBuffer, error) {
var mb buf.MultiBuffer
for {
b, err := reader.ReadMultiBuffer()
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
mb = append(mb, b...)
}
return mb, nil
}
func TestReaderWriter(t *testing.T) {
pReader, pWriter := pipe.New(pipe.WithSizeLimit(1024))
dest := net.TCPDestination(net.DomainAddress("v2ray.com"), 80)
writer := NewWriter(1, dest, pWriter, protocol.TransferTypeStream)
dest2 := net.TCPDestination(net.LocalHostIP, 443)
writer2 := NewWriter(2, dest2, pWriter, protocol.TransferTypeStream)
dest3 := net.TCPDestination(net.LocalHostIPv6, 18374)
writer3 := NewWriter(3, dest3, pWriter, protocol.TransferTypeStream)
writePayload := func(writer *Writer, payload ...byte) error {
b := buf.New()
b.Write(payload)
return writer.WriteMultiBuffer(buf.MultiBuffer{b})
}
common.Must(writePayload(writer, 'a', 'b', 'c', 'd'))
common.Must(writePayload(writer2))
common.Must(writePayload(writer, 'e', 'f', 'g', 'h'))
common.Must(writePayload(writer3, 'x'))
writer.Close()
writer3.Close()
common.Must(writePayload(writer2, 'y'))
writer2.Close()
bytesReader := &buf.BufferedReader{Reader: pReader}
{
var meta FrameMetadata
common.Must(meta.Unmarshal(bytesReader))
if r := cmp.Diff(meta, FrameMetadata{
SessionID: 1,
SessionStatus: SessionStatusNew,
Target: dest,
Option: OptionData,
}); r != "" {
t.Error("metadata: ", r)
}
data, err := readAll(NewStreamReader(bytesReader))
common.Must(err)
if s := data.String(); s != "abcd" {
t.Error("data: ", s)
}
}
{
var meta FrameMetadata
common.Must(meta.Unmarshal(bytesReader))
if r := cmp.Diff(meta, FrameMetadata{
SessionStatus: SessionStatusNew,
SessionID: 2,
Option: 0,
Target: dest2,
}); r != "" {
t.Error("meta: ", r)
}
}
{
var meta FrameMetadata
common.Must(meta.Unmarshal(bytesReader))
if r := cmp.Diff(meta, FrameMetadata{
SessionID: 1,
SessionStatus: SessionStatusKeep,
Option: 1,
}); r != "" {
t.Error("meta: ", r)
}
data, err := readAll(NewStreamReader(bytesReader))
common.Must(err)
if s := data.String(); s != "efgh" {
t.Error("data: ", s)
}
}
{
var meta FrameMetadata
common.Must(meta.Unmarshal(bytesReader))
if r := cmp.Diff(meta, FrameMetadata{
SessionID: 3,
SessionStatus: SessionStatusNew,
Option: 1,
Target: dest3,
}); r != "" {
t.Error("meta: ", r)
}
data, err := readAll(NewStreamReader(bytesReader))
common.Must(err)
if s := data.String(); s != "x" {
t.Error("data: ", s)
}
}
{
var meta FrameMetadata
common.Must(meta.Unmarshal(bytesReader))
if r := cmp.Diff(meta, FrameMetadata{
SessionID: 1,
SessionStatus: SessionStatusEnd,
Option: 0,
}); r != "" {
t.Error("meta: ", r)
}
}
{
var meta FrameMetadata
common.Must(meta.Unmarshal(bytesReader))
if r := cmp.Diff(meta, FrameMetadata{
SessionID: 3,
SessionStatus: SessionStatusEnd,
Option: 0,
}); r != "" {
t.Error("meta: ", r)
}
}
{
var meta FrameMetadata
common.Must(meta.Unmarshal(bytesReader))
if r := cmp.Diff(meta, FrameMetadata{
SessionID: 2,
SessionStatus: SessionStatusKeep,
Option: 1,
}); r != "" {
t.Error("meta: ", r)
}
data, err := readAll(NewStreamReader(bytesReader))
common.Must(err)
if s := data.String(); s != "y" {
t.Error("data: ", s)
}
}
{
var meta FrameMetadata
common.Must(meta.Unmarshal(bytesReader))
if r := cmp.Diff(meta, FrameMetadata{
SessionID: 2,
SessionStatus: SessionStatusEnd,
Option: 0,
}); r != "" {
t.Error("meta: ", r)
}
}
pWriter.Close()
{
var meta FrameMetadata
err := meta.Unmarshal(bytesReader)
if err == nil {
t.Error("nil error")
}
}
}
v2ray-core-4.34.0/common/mux/reader.go 0000664 0000000 0000000 00000002130 13774574720 0017501 0 ustar 00root root 0000000 0000000 package mux
import (
"io"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/crypto"
"v2ray.com/core/common/serial"
)
// PacketReader is an io.Reader that reads whole chunk of Mux frames every time.
type PacketReader struct {
reader io.Reader
eof bool
}
// NewPacketReader creates a new PacketReader.
func NewPacketReader(reader io.Reader) *PacketReader {
return &PacketReader{
reader: reader,
eof: false,
}
}
// ReadMultiBuffer implements buf.Reader.
func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
if r.eof {
return nil, io.EOF
}
size, err := serial.ReadUint16(r.reader)
if err != nil {
return nil, err
}
if size > buf.Size {
return nil, newError("packet size too large: ", size)
}
b := buf.New()
if _, err := b.ReadFullFrom(r.reader, int32(size)); err != nil {
b.Release()
return nil, err
}
r.eof = true
return buf.MultiBuffer{b}, nil
}
// NewStreamReader creates a new StreamReader.
func NewStreamReader(reader *buf.BufferedReader) buf.Reader {
return crypto.NewChunkStreamReaderWithChunkCount(crypto.PlainChunkSizeParser{}, reader, 1)
}
v2ray-core-4.34.0/common/mux/server.go 0000664 0000000 0000000 00000014345 13774574720 0017560 0 ustar 00root root 0000000 0000000 package mux
import (
"context"
"io"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/session"
"v2ray.com/core/features/routing"
"v2ray.com/core/transport"
"v2ray.com/core/transport/pipe"
)
type Server struct {
dispatcher routing.Dispatcher
}
// NewServer creates a new mux.Server.
func NewServer(ctx context.Context) *Server {
s := &Server{}
core.RequireFeatures(ctx, func(d routing.Dispatcher) {
s.dispatcher = d
})
return s
}
// Type implements common.HasType.
func (s *Server) Type() interface{} {
return s.dispatcher.Type()
}
// Dispatch implements routing.Dispatcher
func (s *Server) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {
if dest.Address != muxCoolAddress {
return s.dispatcher.Dispatch(ctx, dest)
}
opts := pipe.OptionsFromContext(ctx)
uplinkReader, uplinkWriter := pipe.New(opts...)
downlinkReader, downlinkWriter := pipe.New(opts...)
_, err := NewServerWorker(ctx, s.dispatcher, &transport.Link{
Reader: uplinkReader,
Writer: downlinkWriter,
})
if err != nil {
return nil, err
}
return &transport.Link{Reader: downlinkReader, Writer: uplinkWriter}, nil
}
// Start implements common.Runnable.
func (s *Server) Start() error {
return nil
}
// Close implements common.Closable.
func (s *Server) Close() error {
return nil
}
type ServerWorker struct {
dispatcher routing.Dispatcher
link *transport.Link
sessionManager *SessionManager
}
func NewServerWorker(ctx context.Context, d routing.Dispatcher, link *transport.Link) (*ServerWorker, error) {
worker := &ServerWorker{
dispatcher: d,
link: link,
sessionManager: NewSessionManager(),
}
go worker.run(ctx)
return worker, nil
}
func handle(ctx context.Context, s *Session, output buf.Writer) {
writer := NewResponseWriter(s.ID, output, s.transferType)
if err := buf.Copy(s.input, writer); err != nil {
newError("session ", s.ID, " ends.").Base(err).WriteToLog(session.ExportIDToError(ctx))
writer.hasError = true
}
writer.Close()
s.Close()
}
func (w *ServerWorker) ActiveConnections() uint32 {
return uint32(w.sessionManager.Size())
}
func (w *ServerWorker) Closed() bool {
return w.sessionManager.Closed()
}
func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.BufferedReader) error {
if meta.Option.Has(OptionData) {
return buf.Copy(NewStreamReader(reader), buf.Discard)
}
return nil
}
func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata, reader *buf.BufferedReader) error {
newError("received request for ", meta.Target).WriteToLog(session.ExportIDToError(ctx))
{
msg := &log.AccessMessage{
To: meta.Target,
Status: log.AccessAccepted,
Reason: "",
}
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() {
msg.From = inbound.Source
msg.Email = inbound.User.Email
}
ctx = log.ContextWithAccessMessage(ctx, msg)
}
link, err := w.dispatcher.Dispatch(ctx, meta.Target)
if err != nil {
if meta.Option.Has(OptionData) {
buf.Copy(NewStreamReader(reader), buf.Discard)
}
return newError("failed to dispatch request.").Base(err)
}
s := &Session{
input: link.Reader,
output: link.Writer,
parent: w.sessionManager,
ID: meta.SessionID,
transferType: protocol.TransferTypeStream,
}
if meta.Target.Network == net.Network_UDP {
s.transferType = protocol.TransferTypePacket
}
w.sessionManager.Add(s)
go handle(ctx, s, w.link.Writer)
if !meta.Option.Has(OptionData) {
return nil
}
rr := s.NewReader(reader)
if err := buf.Copy(rr, s.output); err != nil {
buf.Copy(rr, buf.Discard)
common.Interrupt(s.input)
return s.Close()
}
return nil
}
func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.BufferedReader) error {
if !meta.Option.Has(OptionData) {
return nil
}
s, found := w.sessionManager.Get(meta.SessionID)
if !found {
// Notify remote peer to close this session.
closingWriter := NewResponseWriter(meta.SessionID, w.link.Writer, protocol.TransferTypeStream)
closingWriter.Close()
return buf.Copy(NewStreamReader(reader), buf.Discard)
}
rr := s.NewReader(reader)
err := buf.Copy(rr, s.output)
if err != nil && buf.IsWriteError(err) {
newError("failed to write to downstream writer. closing session ", s.ID).Base(err).WriteToLog()
// Notify remote peer to close this session.
closingWriter := NewResponseWriter(meta.SessionID, w.link.Writer, protocol.TransferTypeStream)
closingWriter.Close()
drainErr := buf.Copy(rr, buf.Discard)
common.Interrupt(s.input)
s.Close()
return drainErr
}
return err
}
func (w *ServerWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.BufferedReader) error {
if s, found := w.sessionManager.Get(meta.SessionID); found {
if meta.Option.Has(OptionError) {
common.Interrupt(s.input)
common.Interrupt(s.output)
}
s.Close()
}
if meta.Option.Has(OptionData) {
return buf.Copy(NewStreamReader(reader), buf.Discard)
}
return nil
}
func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedReader) error {
var meta FrameMetadata
err := meta.Unmarshal(reader)
if err != nil {
return newError("failed to read metadata").Base(err)
}
switch meta.SessionStatus {
case SessionStatusKeepAlive:
err = w.handleStatusKeepAlive(&meta, reader)
case SessionStatusEnd:
err = w.handleStatusEnd(&meta, reader)
case SessionStatusNew:
err = w.handleStatusNew(ctx, &meta, reader)
case SessionStatusKeep:
err = w.handleStatusKeep(&meta, reader)
default:
status := meta.SessionStatus
return newError("unknown status: ", status).AtError()
}
if err != nil {
return newError("failed to process data").Base(err)
}
return nil
}
func (w *ServerWorker) run(ctx context.Context) {
input := w.link.Reader
reader := &buf.BufferedReader{Reader: input}
defer w.sessionManager.Close()
for {
select {
case <-ctx.Done():
return
default:
err := w.handleFrame(ctx, reader)
if err != nil {
if errors.Cause(err) != io.EOF {
newError("unexpected EOF").Base(err).WriteToLog(session.ExportIDToError(ctx))
common.Interrupt(input)
}
return
}
}
}
}
v2ray-core-4.34.0/common/mux/session.go 0000664 0000000 0000000 00000004646 13774574720 0017740 0 ustar 00root root 0000000 0000000 package mux
import (
"sync"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/protocol"
)
type SessionManager struct {
sync.RWMutex
sessions map[uint16]*Session
count uint16
closed bool
}
func NewSessionManager() *SessionManager {
return &SessionManager{
count: 0,
sessions: make(map[uint16]*Session, 16),
}
}
func (m *SessionManager) Closed() bool {
m.RLock()
defer m.RUnlock()
return m.closed
}
func (m *SessionManager) Size() int {
m.RLock()
defer m.RUnlock()
return len(m.sessions)
}
func (m *SessionManager) Count() int {
m.RLock()
defer m.RUnlock()
return int(m.count)
}
func (m *SessionManager) Allocate() *Session {
m.Lock()
defer m.Unlock()
if m.closed {
return nil
}
m.count++
s := &Session{
ID: m.count,
parent: m,
}
m.sessions[s.ID] = s
return s
}
func (m *SessionManager) Add(s *Session) {
m.Lock()
defer m.Unlock()
if m.closed {
return
}
m.count++
m.sessions[s.ID] = s
}
func (m *SessionManager) Remove(id uint16) {
m.Lock()
defer m.Unlock()
if m.closed {
return
}
delete(m.sessions, id)
if len(m.sessions) == 0 {
m.sessions = make(map[uint16]*Session, 16)
}
}
func (m *SessionManager) Get(id uint16) (*Session, bool) {
m.RLock()
defer m.RUnlock()
if m.closed {
return nil, false
}
s, found := m.sessions[id]
return s, found
}
func (m *SessionManager) CloseIfNoSession() bool {
m.Lock()
defer m.Unlock()
if m.closed {
return true
}
if len(m.sessions) != 0 {
return false
}
m.closed = true
return true
}
func (m *SessionManager) Close() error {
m.Lock()
defer m.Unlock()
if m.closed {
return nil
}
m.closed = true
for _, s := range m.sessions {
common.Close(s.input)
common.Close(s.output)
}
m.sessions = nil
return nil
}
// Session represents a client connection in a Mux connection.
type Session struct {
input buf.Reader
output buf.Writer
parent *SessionManager
ID uint16
transferType protocol.TransferType
}
// Close closes all resources associated with this session.
func (s *Session) Close() error {
common.Close(s.output)
common.Close(s.input)
s.parent.Remove(s.ID)
return nil
}
// NewReader creates a buf.Reader based on the transfer type of this Session.
func (s *Session) NewReader(reader *buf.BufferedReader) buf.Reader {
if s.transferType == protocol.TransferTypeStream {
return NewStreamReader(reader)
}
return NewPacketReader(reader)
}
v2ray-core-4.34.0/common/mux/session_test.go 0000664 0000000 0000000 00000001342 13774574720 0020765 0 ustar 00root root 0000000 0000000 package mux_test
import (
"testing"
. "v2ray.com/core/common/mux"
)
func TestSessionManagerAdd(t *testing.T) {
m := NewSessionManager()
s := m.Allocate()
if s.ID != 1 {
t.Error("id: ", s.ID)
}
if m.Size() != 1 {
t.Error("size: ", m.Size())
}
s = m.Allocate()
if s.ID != 2 {
t.Error("id: ", s.ID)
}
if m.Size() != 2 {
t.Error("size: ", m.Size())
}
s = &Session{
ID: 4,
}
m.Add(s)
if s.ID != 4 {
t.Error("id: ", s.ID)
}
if m.Size() != 3 {
t.Error("size: ", m.Size())
}
}
func TestSessionManagerClose(t *testing.T) {
m := NewSessionManager()
s := m.Allocate()
if m.CloseIfNoSession() {
t.Error("able to close")
}
m.Remove(s.ID)
if !m.CloseIfNoSession() {
t.Error("not able to close")
}
}
v2ray-core-4.34.0/common/mux/writer.go 0000664 0000000 0000000 00000005402 13774574720 0017560 0 ustar 00root root 0000000 0000000 package mux
import (
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
)
type Writer struct {
dest net.Destination
writer buf.Writer
id uint16
followup bool
hasError bool
transferType protocol.TransferType
}
func NewWriter(id uint16, dest net.Destination, writer buf.Writer, transferType protocol.TransferType) *Writer {
return &Writer{
id: id,
dest: dest,
writer: writer,
followup: false,
transferType: transferType,
}
}
func NewResponseWriter(id uint16, writer buf.Writer, transferType protocol.TransferType) *Writer {
return &Writer{
id: id,
writer: writer,
followup: true,
transferType: transferType,
}
}
func (w *Writer) getNextFrameMeta() FrameMetadata {
meta := FrameMetadata{
SessionID: w.id,
Target: w.dest,
}
if w.followup {
meta.SessionStatus = SessionStatusKeep
} else {
w.followup = true
meta.SessionStatus = SessionStatusNew
}
return meta
}
func (w *Writer) writeMetaOnly() error {
meta := w.getNextFrameMeta()
b := buf.New()
if err := meta.WriteTo(b); err != nil {
return err
}
return w.writer.WriteMultiBuffer(buf.MultiBuffer{b})
}
func writeMetaWithFrame(writer buf.Writer, meta FrameMetadata, data buf.MultiBuffer) error {
frame := buf.New()
if err := meta.WriteTo(frame); err != nil {
return err
}
if _, err := serial.WriteUint16(frame, uint16(data.Len())); err != nil {
return err
}
if len(data)+1 > 64*1024*1024 {
return errors.New("value too large")
}
sliceSize := len(data) + 1
mb2 := make(buf.MultiBuffer, 0, sliceSize)
mb2 = append(mb2, frame)
mb2 = append(mb2, data...)
return writer.WriteMultiBuffer(mb2)
}
func (w *Writer) writeData(mb buf.MultiBuffer) error {
meta := w.getNextFrameMeta()
meta.Option.Set(OptionData)
return writeMetaWithFrame(w.writer, meta, mb)
}
// WriteMultiBuffer implements buf.Writer.
func (w *Writer) WriteMultiBuffer(mb buf.MultiBuffer) error {
defer buf.ReleaseMulti(mb)
if mb.IsEmpty() {
return w.writeMetaOnly()
}
for !mb.IsEmpty() {
var chunk buf.MultiBuffer
if w.transferType == protocol.TransferTypeStream {
mb, chunk = buf.SplitSize(mb, 8*1024)
} else {
mb2, b := buf.SplitFirst(mb)
mb = mb2
chunk = buf.MultiBuffer{b}
}
if err := w.writeData(chunk); err != nil {
return err
}
}
return nil
}
// Close implements common.Closable.
func (w *Writer) Close() error {
meta := FrameMetadata{
SessionID: w.id,
SessionStatus: SessionStatusEnd,
}
if w.hasError {
meta.Option.Set(OptionError)
}
frame := buf.New()
common.Must(meta.WriteTo(frame))
w.writer.WriteMultiBuffer(buf.MultiBuffer{frame})
return nil
}
v2ray-core-4.34.0/common/net/ 0000775 0000000 0000000 00000000000 13774574720 0015671 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/net/address.go 0000664 0000000 0000000 00000011776 13774574720 0017661 0 ustar 00root root 0000000 0000000 package net
import (
"bytes"
"net"
"strings"
)
var (
// LocalHostIP is a constant value for localhost IP in IPv4.
LocalHostIP = IPAddress([]byte{127, 0, 0, 1})
// AnyIP is a constant value for any IP in IPv4.
AnyIP = IPAddress([]byte{0, 0, 0, 0})
// LocalHostDomain is a constant value for localhost domain.
LocalHostDomain = DomainAddress("localhost")
// LocalHostIPv6 is a constant value for localhost IP in IPv6.
LocalHostIPv6 = IPAddress([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
// AnyIPv6 is a constant value for any IP in IPv6.
AnyIPv6 = IPAddress([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
)
// AddressFamily is the type of address.
type AddressFamily byte
const (
// AddressFamilyIPv4 represents address as IPv4
AddressFamilyIPv4 = AddressFamily(0)
// AddressFamilyIPv6 represents address as IPv6
AddressFamilyIPv6 = AddressFamily(1)
// AddressFamilyDomain represents address as Domain
AddressFamilyDomain = AddressFamily(2)
)
// IsIPv4 returns true if current AddressFamily is IPv4.
func (af AddressFamily) IsIPv4() bool {
return af == AddressFamilyIPv4
}
// IsIPv6 returns true if current AddressFamily is IPv6.
func (af AddressFamily) IsIPv6() bool {
return af == AddressFamilyIPv6
}
// IsIP returns true if current AddressFamily is IPv6 or IPv4.
func (af AddressFamily) IsIP() bool {
return af == AddressFamilyIPv4 || af == AddressFamilyIPv6
}
// IsDomain returns true if current AddressFamily is Domain.
func (af AddressFamily) IsDomain() bool {
return af == AddressFamilyDomain
}
// Address represents a network address to be communicated with. It may be an IP address or domain
// address, not both. This interface doesn't resolve IP address for a given domain.
type Address interface {
IP() net.IP // IP of this Address
Domain() string // Domain of this Address
Family() AddressFamily
String() string // String representation of this Address
}
func isAlphaNum(c byte) bool {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
}
// ParseAddress parses a string into an Address. The return value will be an IPAddress when
// the string is in the form of IPv4 or IPv6 address, or a DomainAddress otherwise.
func ParseAddress(addr string) Address {
// Handle IPv6 address in form as "[2001:4860:0:2001::68]"
lenAddr := len(addr)
if lenAddr > 0 && addr[0] == '[' && addr[lenAddr-1] == ']' {
addr = addr[1 : lenAddr-1]
lenAddr -= 2
}
if lenAddr > 0 && (!isAlphaNum(addr[0]) || !isAlphaNum(addr[len(addr)-1])) {
addr = strings.TrimSpace(addr)
}
ip := net.ParseIP(addr)
if ip != nil {
return IPAddress(ip)
}
return DomainAddress(addr)
}
var bytes0 = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
// IPAddress creates an Address with given IP.
func IPAddress(ip []byte) Address {
switch len(ip) {
case net.IPv4len:
var addr ipv4Address = [4]byte{ip[0], ip[1], ip[2], ip[3]}
return addr
case net.IPv6len:
if bytes.Equal(ip[:10], bytes0) && ip[10] == 0xff && ip[11] == 0xff {
return IPAddress(ip[12:16])
}
var addr ipv6Address = [16]byte{
ip[0], ip[1], ip[2], ip[3],
ip[4], ip[5], ip[6], ip[7],
ip[8], ip[9], ip[10], ip[11],
ip[12], ip[13], ip[14], ip[15],
}
return addr
default:
newError("invalid IP format: ", ip).AtError().WriteToLog()
return nil
}
}
// DomainAddress creates an Address with given domain.
func DomainAddress(domain string) Address {
return domainAddress(domain)
}
type ipv4Address [4]byte
func (a ipv4Address) IP() net.IP {
return net.IP(a[:])
}
func (ipv4Address) Domain() string {
panic("Calling Domain() on an IPv4Address.")
}
func (ipv4Address) Family() AddressFamily {
return AddressFamilyIPv4
}
func (a ipv4Address) String() string {
return a.IP().String()
}
type ipv6Address [16]byte
func (a ipv6Address) IP() net.IP {
return net.IP(a[:])
}
func (ipv6Address) Domain() string {
panic("Calling Domain() on an IPv6Address.")
}
func (ipv6Address) Family() AddressFamily {
return AddressFamilyIPv6
}
func (a ipv6Address) String() string {
return "[" + a.IP().String() + "]"
}
type domainAddress string
func (domainAddress) IP() net.IP {
panic("Calling IP() on a DomainAddress.")
}
func (a domainAddress) Domain() string {
return string(a)
}
func (domainAddress) Family() AddressFamily {
return AddressFamilyDomain
}
func (a domainAddress) String() string {
return a.Domain()
}
// AsAddress translates IPOrDomain to Address.
func (d *IPOrDomain) AsAddress() Address {
if d == nil {
return nil
}
switch addr := d.Address.(type) {
case *IPOrDomain_Ip:
return IPAddress(addr.Ip)
case *IPOrDomain_Domain:
return DomainAddress(addr.Domain)
}
panic("Common|Net: Invalid address.")
}
// NewIPOrDomain translates Address to IPOrDomain
func NewIPOrDomain(addr Address) *IPOrDomain {
switch addr.Family() {
case AddressFamilyDomain:
return &IPOrDomain{
Address: &IPOrDomain_Domain{
Domain: addr.Domain(),
},
}
case AddressFamilyIPv4, AddressFamilyIPv6:
return &IPOrDomain{
Address: &IPOrDomain_Ip{
Ip: addr.IP(),
},
}
default:
panic("Unknown Address type.")
}
}
v2ray-core-4.34.0/common/net/address.pb.go 0000664 0000000 0000000 00000014262 13774574720 0020252 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: common/net/address.proto
package net
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// Address of a network host. It may be either an IP address or a domain
// address.
type IPOrDomain struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Types that are assignable to Address:
// *IPOrDomain_Ip
// *IPOrDomain_Domain
Address isIPOrDomain_Address `protobuf_oneof:"address"`
}
func (x *IPOrDomain) Reset() {
*x = IPOrDomain{}
if protoimpl.UnsafeEnabled {
mi := &file_common_net_address_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *IPOrDomain) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*IPOrDomain) ProtoMessage() {}
func (x *IPOrDomain) ProtoReflect() protoreflect.Message {
mi := &file_common_net_address_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use IPOrDomain.ProtoReflect.Descriptor instead.
func (*IPOrDomain) Descriptor() ([]byte, []int) {
return file_common_net_address_proto_rawDescGZIP(), []int{0}
}
func (m *IPOrDomain) GetAddress() isIPOrDomain_Address {
if m != nil {
return m.Address
}
return nil
}
func (x *IPOrDomain) GetIp() []byte {
if x, ok := x.GetAddress().(*IPOrDomain_Ip); ok {
return x.Ip
}
return nil
}
func (x *IPOrDomain) GetDomain() string {
if x, ok := x.GetAddress().(*IPOrDomain_Domain); ok {
return x.Domain
}
return ""
}
type isIPOrDomain_Address interface {
isIPOrDomain_Address()
}
type IPOrDomain_Ip struct {
// IP address. Must by either 4 or 16 bytes.
Ip []byte `protobuf:"bytes,1,opt,name=ip,proto3,oneof"`
}
type IPOrDomain_Domain struct {
// Domain address.
Domain string `protobuf:"bytes,2,opt,name=domain,proto3,oneof"`
}
func (*IPOrDomain_Ip) isIPOrDomain_Address() {}
func (*IPOrDomain_Domain) isIPOrDomain_Address() {}
var File_common_net_address_proto protoreflect.FileDescriptor
var file_common_net_address_proto_rawDesc = []byte{
0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
0x74, 0x22, 0x43, 0x0a, 0x0a, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12,
0x10, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x02, 0x69,
0x70, 0x12, 0x18, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x48, 0x00, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x61,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74,
0xaa, 0x02, 0x15, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_common_net_address_proto_rawDescOnce sync.Once
file_common_net_address_proto_rawDescData = file_common_net_address_proto_rawDesc
)
func file_common_net_address_proto_rawDescGZIP() []byte {
file_common_net_address_proto_rawDescOnce.Do(func() {
file_common_net_address_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_net_address_proto_rawDescData)
})
return file_common_net_address_proto_rawDescData
}
var file_common_net_address_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_common_net_address_proto_goTypes = []interface{}{
(*IPOrDomain)(nil), // 0: v2ray.core.common.net.IPOrDomain
}
var file_common_net_address_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_common_net_address_proto_init() }
func file_common_net_address_proto_init() {
if File_common_net_address_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_net_address_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*IPOrDomain); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_common_net_address_proto_msgTypes[0].OneofWrappers = []interface{}{
(*IPOrDomain_Ip)(nil),
(*IPOrDomain_Domain)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_net_address_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_net_address_proto_goTypes,
DependencyIndexes: file_common_net_address_proto_depIdxs,
MessageInfos: file_common_net_address_proto_msgTypes,
}.Build()
File_common_net_address_proto = out.File
file_common_net_address_proto_rawDesc = nil
file_common_net_address_proto_goTypes = nil
file_common_net_address_proto_depIdxs = nil
}
v2ray-core-4.34.0/common/net/address.proto 0000664 0000000 0000000 00000000742 13774574720 0020406 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.common.net;
option csharp_namespace = "V2Ray.Core.Common.Net";
option go_package = "v2ray.com/core/common/net";
option java_package = "com.v2ray.core.common.net";
option java_multiple_files = true;
// Address of a network host. It may be either an IP address or a domain
// address.
message IPOrDomain {
oneof address {
// IP address. Must by either 4 or 16 bytes.
bytes ip = 1;
// Domain address.
string domain = 2;
}
}
v2ray-core-4.34.0/common/net/address_test.go 0000664 0000000 0000000 00000010553 13774574720 0020710 0 ustar 00root root 0000000 0000000 package net_test
import (
"net"
"testing"
"github.com/google/go-cmp/cmp"
. "v2ray.com/core/common/net"
)
func TestAddressProperty(t *testing.T) {
type addrProprty struct {
IP []byte
Domain string
Family AddressFamily
String string
}
testCases := []struct {
Input Address
Output addrProprty
}{
{
Input: IPAddress([]byte{byte(1), byte(2), byte(3), byte(4)}),
Output: addrProprty{
IP: []byte{byte(1), byte(2), byte(3), byte(4)},
Family: AddressFamilyIPv4,
String: "1.2.3.4",
},
},
{
Input: IPAddress([]byte{
byte(1), byte(2), byte(3), byte(4),
byte(1), byte(2), byte(3), byte(4),
byte(1), byte(2), byte(3), byte(4),
byte(1), byte(2), byte(3), byte(4),
}),
Output: addrProprty{
IP: []byte{
byte(1), byte(2), byte(3), byte(4),
byte(1), byte(2), byte(3), byte(4),
byte(1), byte(2), byte(3), byte(4),
byte(1), byte(2), byte(3), byte(4),
},
Family: AddressFamilyIPv6,
String: "[102:304:102:304:102:304:102:304]",
},
},
{
Input: IPAddress([]byte{
byte(0), byte(0), byte(0), byte(0),
byte(0), byte(0), byte(0), byte(0),
byte(0), byte(0), byte(255), byte(255),
byte(1), byte(2), byte(3), byte(4),
}),
Output: addrProprty{
IP: []byte{byte(1), byte(2), byte(3), byte(4)},
Family: AddressFamilyIPv4,
String: "1.2.3.4",
},
},
{
Input: DomainAddress("v2ray.com"),
Output: addrProprty{
Domain: "v2ray.com",
Family: AddressFamilyDomain,
String: "v2ray.com",
},
},
{
Input: IPAddress(net.IPv4(1, 2, 3, 4)),
Output: addrProprty{
IP: []byte{byte(1), byte(2), byte(3), byte(4)},
Family: AddressFamilyIPv4,
String: "1.2.3.4",
},
},
{
Input: ParseAddress("[2001:4860:0:2001::68]"),
Output: addrProprty{
IP: []byte{0x20, 0x01, 0x48, 0x60, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68},
Family: AddressFamilyIPv6,
String: "[2001:4860:0:2001::68]",
},
},
{
Input: ParseAddress("::0"),
Output: addrProprty{
IP: AnyIPv6.IP(),
Family: AddressFamilyIPv6,
String: "[::]",
},
},
{
Input: ParseAddress("[::ffff:123.151.71.143]"),
Output: addrProprty{
IP: []byte{123, 151, 71, 143},
Family: AddressFamilyIPv4,
String: "123.151.71.143",
},
},
{
Input: NewIPOrDomain(ParseAddress("v2ray.com")).AsAddress(),
Output: addrProprty{
Domain: "v2ray.com",
Family: AddressFamilyDomain,
String: "v2ray.com",
},
},
{
Input: NewIPOrDomain(ParseAddress("8.8.8.8")).AsAddress(),
Output: addrProprty{
IP: []byte{8, 8, 8, 8},
Family: AddressFamilyIPv4,
String: "8.8.8.8",
},
},
{
Input: NewIPOrDomain(ParseAddress("[2001:4860:0:2001::68]")).AsAddress(),
Output: addrProprty{
IP: []byte{0x20, 0x01, 0x48, 0x60, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68},
Family: AddressFamilyIPv6,
String: "[2001:4860:0:2001::68]",
},
},
}
for _, testCase := range testCases {
actual := addrProprty{
Family: testCase.Input.Family(),
String: testCase.Input.String(),
}
if testCase.Input.Family().IsIP() {
actual.IP = testCase.Input.IP()
} else {
actual.Domain = testCase.Input.Domain()
}
if r := cmp.Diff(actual, testCase.Output); r != "" {
t.Error("for input: ", testCase.Input, ":", r)
}
}
}
func TestInvalidAddressConvertion(t *testing.T) {
panics := func(f func()) (ret bool) {
defer func() {
if r := recover(); r != nil {
ret = true
}
}()
f()
return false
}
testCases := []func(){
func() { ParseAddress("8.8.8.8").Domain() },
func() { ParseAddress("2001:4860:0:2001::68").Domain() },
func() { ParseAddress("v2ray.com").IP() },
}
for idx, testCase := range testCases {
if !panics(testCase) {
t.Error("case ", idx, " failed")
}
}
}
func BenchmarkParseAddressIPv4(b *testing.B) {
for i := 0; i < b.N; i++ {
addr := ParseAddress("8.8.8.8")
if addr.Family() != AddressFamilyIPv4 {
panic("not ipv4")
}
}
}
func BenchmarkParseAddressIPv6(b *testing.B) {
for i := 0; i < b.N; i++ {
addr := ParseAddress("2001:4860:0:2001::68")
if addr.Family() != AddressFamilyIPv6 {
panic("not ipv6")
}
}
}
func BenchmarkParseAddressDomain(b *testing.B) {
for i := 0; i < b.N; i++ {
addr := ParseAddress("v2ray.com")
if addr.Family() != AddressFamilyDomain {
panic("not domain")
}
}
}
v2ray-core-4.34.0/common/net/connection.go 0000664 0000000 0000000 00000006445 13774574720 0020370 0 ustar 00root root 0000000 0000000 // +build !confonly
package net
import (
"io"
"net"
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/signal/done"
)
type ConnectionOption func(*connection)
func ConnectionLocalAddr(a net.Addr) ConnectionOption {
return func(c *connection) {
c.local = a
}
}
func ConnectionRemoteAddr(a net.Addr) ConnectionOption {
return func(c *connection) {
c.remote = a
}
}
func ConnectionInput(writer io.Writer) ConnectionOption {
return func(c *connection) {
c.writer = buf.NewWriter(writer)
}
}
func ConnectionInputMulti(writer buf.Writer) ConnectionOption {
return func(c *connection) {
c.writer = writer
}
}
func ConnectionOutput(reader io.Reader) ConnectionOption {
return func(c *connection) {
c.reader = &buf.BufferedReader{Reader: buf.NewReader(reader)}
}
}
func ConnectionOutputMulti(reader buf.Reader) ConnectionOption {
return func(c *connection) {
c.reader = &buf.BufferedReader{Reader: reader}
}
}
func ConnectionOutputMultiUDP(reader buf.Reader) ConnectionOption {
return func(c *connection) {
c.reader = &buf.BufferedReader{
Reader: reader,
Spliter: buf.SplitFirstBytes,
}
}
}
func ConnectionOnClose(n io.Closer) ConnectionOption {
return func(c *connection) {
c.onClose = n
}
}
func NewConnection(opts ...ConnectionOption) net.Conn {
c := &connection{
done: done.New(),
local: &net.TCPAddr{
IP: []byte{0, 0, 0, 0},
Port: 0,
},
remote: &net.TCPAddr{
IP: []byte{0, 0, 0, 0},
Port: 0,
},
}
for _, opt := range opts {
opt(c)
}
return c
}
type connection struct {
reader *buf.BufferedReader
writer buf.Writer
done *done.Instance
onClose io.Closer
local Addr
remote Addr
}
func (c *connection) Read(b []byte) (int, error) {
return c.reader.Read(b)
}
// ReadMultiBuffer implements buf.Reader.
func (c *connection) ReadMultiBuffer() (buf.MultiBuffer, error) {
return c.reader.ReadMultiBuffer()
}
// Write implements net.Conn.Write().
func (c *connection) Write(b []byte) (int, error) {
if c.done.Done() {
return 0, io.ErrClosedPipe
}
if len(b)/buf.Size+1 > 64*1024*1024 {
return 0, errors.New("value too large")
}
l := len(b)
sliceSize := l/buf.Size + 1
mb := make(buf.MultiBuffer, 0, sliceSize)
mb = buf.MergeBytes(mb, b)
return l, c.writer.WriteMultiBuffer(mb)
}
func (c *connection) WriteMultiBuffer(mb buf.MultiBuffer) error {
if c.done.Done() {
buf.ReleaseMulti(mb)
return io.ErrClosedPipe
}
return c.writer.WriteMultiBuffer(mb)
}
// Close implements net.Conn.Close().
func (c *connection) Close() error {
common.Must(c.done.Close())
common.Interrupt(c.reader)
common.Close(c.writer)
if c.onClose != nil {
return c.onClose.Close()
}
return nil
}
// LocalAddr implements net.Conn.LocalAddr().
func (c *connection) LocalAddr() net.Addr {
return c.local
}
// RemoteAddr implements net.Conn.RemoteAddr().
func (c *connection) RemoteAddr() net.Addr {
return c.remote
}
// SetDeadline implements net.Conn.SetDeadline().
func (c *connection) SetDeadline(t time.Time) error {
return nil
}
// SetReadDeadline implements net.Conn.SetReadDeadline().
func (c *connection) SetReadDeadline(t time.Time) error {
return nil
}
// SetWriteDeadline implements net.Conn.SetWriteDeadline().
func (c *connection) SetWriteDeadline(t time.Time) error {
return nil
}
v2ray-core-4.34.0/common/net/destination.go 0000664 0000000 0000000 00000005623 13774574720 0020547 0 ustar 00root root 0000000 0000000 package net
import (
"net"
"strings"
)
// Destination represents a network destination including address and protocol (tcp / udp).
type Destination struct {
Address Address
Port Port
Network Network
}
// DestinationFromAddr generates a Destination from a net address.
func DestinationFromAddr(addr net.Addr) Destination {
switch addr := addr.(type) {
case *net.TCPAddr:
return TCPDestination(IPAddress(addr.IP), Port(addr.Port))
case *net.UDPAddr:
return UDPDestination(IPAddress(addr.IP), Port(addr.Port))
case *net.UnixAddr:
return UnixDestination(DomainAddress(addr.Name))
default:
panic("Net: Unknown address type.")
}
}
// ParseDestination converts a destination from its string presentation.
func ParseDestination(dest string) (Destination, error) {
d := Destination{
Address: AnyIP,
Port: Port(0),
}
switch {
case strings.HasPrefix(dest, "tcp:"):
d.Network = Network_TCP
dest = dest[4:]
case strings.HasPrefix(dest, "udp:"):
d.Network = Network_UDP
dest = dest[4:]
case strings.HasPrefix(dest, "unix:"):
d = UnixDestination(DomainAddress(dest[5:]))
return d, nil
}
hstr, pstr, err := SplitHostPort(dest)
if err != nil {
return d, err
}
if len(hstr) > 0 {
d.Address = ParseAddress(hstr)
}
if len(pstr) > 0 {
port, err := PortFromString(pstr)
if err != nil {
return d, err
}
d.Port = port
}
return d, nil
}
// TCPDestination creates a TCP destination with given address
func TCPDestination(address Address, port Port) Destination {
return Destination{
Network: Network_TCP,
Address: address,
Port: port,
}
}
// UDPDestination creates a UDP destination with given address
func UDPDestination(address Address, port Port) Destination {
return Destination{
Network: Network_UDP,
Address: address,
Port: port,
}
}
// UnixDestination creates a Unix destination with given address
func UnixDestination(address Address) Destination {
return Destination{
Network: Network_UNIX,
Address: address,
}
}
// NetAddr returns the network address in this Destination in string form.
func (d Destination) NetAddr() string {
addr := ""
if d.Network == Network_TCP || d.Network == Network_UDP {
addr = d.Address.String() + ":" + d.Port.String()
} else if d.Network == Network_UNIX {
addr = d.Address.String()
}
return addr
}
// String returns the strings form of this Destination.
func (d Destination) String() string {
prefix := "unknown:"
switch d.Network {
case Network_TCP:
prefix = "tcp:"
case Network_UDP:
prefix = "udp:"
case Network_UNIX:
prefix = "unix:"
}
return prefix + d.NetAddr()
}
// IsValid returns true if this Destination is valid.
func (d Destination) IsValid() bool {
return d.Network != Network_Unknown
}
// AsDestination converts current Endpoint into Destination.
func (p *Endpoint) AsDestination() Destination {
return Destination{
Network: p.Network,
Address: p.Address.AsAddress(),
Port: Port(p.Port),
}
}
v2ray-core-4.34.0/common/net/destination.pb.go 0000664 0000000 0000000 00000015733 13774574720 0021152 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: common/net/destination.proto
package net
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// Endpoint of a network connection.
type Endpoint struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Network Network `protobuf:"varint,1,opt,name=network,proto3,enum=v2ray.core.common.net.Network" json:"network,omitempty"`
Address *IPOrDomain `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"`
Port uint32 `protobuf:"varint,3,opt,name=port,proto3" json:"port,omitempty"`
}
func (x *Endpoint) Reset() {
*x = Endpoint{}
if protoimpl.UnsafeEnabled {
mi := &file_common_net_destination_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Endpoint) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Endpoint) ProtoMessage() {}
func (x *Endpoint) ProtoReflect() protoreflect.Message {
mi := &file_common_net_destination_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Endpoint.ProtoReflect.Descriptor instead.
func (*Endpoint) Descriptor() ([]byte, []int) {
return file_common_net_destination_proto_rawDescGZIP(), []int{0}
}
func (x *Endpoint) GetNetwork() Network {
if x != nil {
return x.Network
}
return Network_Unknown
}
func (x *Endpoint) GetAddress() *IPOrDomain {
if x != nil {
return x.Address
}
return nil
}
func (x *Endpoint) GetPort() uint32 {
if x != nil {
return x.Port
}
return 0
}
var File_common_net_destination_proto protoreflect.FileDescriptor
var file_common_net_destination_proto_rawDesc = []byte{
0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x65, 0x73,
0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65,
0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x95, 0x01, 0x0a, 0x08, 0x45, 0x6e,
0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e,
0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
0x12, 0x3b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a,
0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72,
0x74, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x50, 0x01,
0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65,
0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x15, 0x56, 0x32,
0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x4e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_common_net_destination_proto_rawDescOnce sync.Once
file_common_net_destination_proto_rawDescData = file_common_net_destination_proto_rawDesc
)
func file_common_net_destination_proto_rawDescGZIP() []byte {
file_common_net_destination_proto_rawDescOnce.Do(func() {
file_common_net_destination_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_net_destination_proto_rawDescData)
})
return file_common_net_destination_proto_rawDescData
}
var file_common_net_destination_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_common_net_destination_proto_goTypes = []interface{}{
(*Endpoint)(nil), // 0: v2ray.core.common.net.Endpoint
(Network)(0), // 1: v2ray.core.common.net.Network
(*IPOrDomain)(nil), // 2: v2ray.core.common.net.IPOrDomain
}
var file_common_net_destination_proto_depIdxs = []int32{
1, // 0: v2ray.core.common.net.Endpoint.network:type_name -> v2ray.core.common.net.Network
2, // 1: v2ray.core.common.net.Endpoint.address:type_name -> v2ray.core.common.net.IPOrDomain
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_common_net_destination_proto_init() }
func file_common_net_destination_proto_init() {
if File_common_net_destination_proto != nil {
return
}
file_common_net_network_proto_init()
file_common_net_address_proto_init()
if !protoimpl.UnsafeEnabled {
file_common_net_destination_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Endpoint); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_net_destination_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_net_destination_proto_goTypes,
DependencyIndexes: file_common_net_destination_proto_depIdxs,
MessageInfos: file_common_net_destination_proto_msgTypes,
}.Build()
File_common_net_destination_proto = out.File
file_common_net_destination_proto_rawDesc = nil
file_common_net_destination_proto_goTypes = nil
file_common_net_destination_proto_depIdxs = nil
}
v2ray-core-4.34.0/common/net/destination.proto 0000664 0000000 0000000 00000000663 13774574720 0021304 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.common.net;
option csharp_namespace = "V2Ray.Core.Common.Net";
option go_package = "v2ray.com/core/common/net";
option java_package = "com.v2ray.core.common.net";
option java_multiple_files = true;
import "common/net/network.proto";
import "common/net/address.proto";
// Endpoint of a network connection.
message Endpoint {
Network network = 1;
IPOrDomain address = 2;
uint32 port = 3;
}
v2ray-core-4.34.0/common/net/destination_test.go 0000664 0000000 0000000 00000004715 13774574720 0021607 0 ustar 00root root 0000000 0000000 package net_test
import (
"testing"
"github.com/google/go-cmp/cmp"
. "v2ray.com/core/common/net"
)
func TestDestinationProperty(t *testing.T) {
testCases := []struct {
Input Destination
Network Network
String string
NetString string
}{
{
Input: TCPDestination(IPAddress([]byte{1, 2, 3, 4}), 80),
Network: Network_TCP,
String: "tcp:1.2.3.4:80",
NetString: "1.2.3.4:80",
},
{
Input: UDPDestination(IPAddress([]byte{0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88}), 53),
Network: Network_UDP,
String: "udp:[2001:4860:4860::8888]:53",
NetString: "[2001:4860:4860::8888]:53",
},
{
Input: UnixDestination(DomainAddress("/tmp/test.sock")),
Network: Network_UNIX,
String: "unix:/tmp/test.sock",
NetString: "/tmp/test.sock",
},
}
for _, testCase := range testCases {
dest := testCase.Input
if r := cmp.Diff(dest.Network, testCase.Network); r != "" {
t.Error("unexpected Network in ", dest.String(), ": ", r)
}
if r := cmp.Diff(dest.String(), testCase.String); r != "" {
t.Error(r)
}
if r := cmp.Diff(dest.NetAddr(), testCase.NetString); r != "" {
t.Error(r)
}
}
}
func TestDestinationParse(t *testing.T) {
cases := []struct {
Input string
Output Destination
Error bool
}{
{
Input: "tcp:127.0.0.1:80",
Output: TCPDestination(LocalHostIP, Port(80)),
},
{
Input: "udp:8.8.8.8:53",
Output: UDPDestination(IPAddress([]byte{8, 8, 8, 8}), Port(53)),
},
{
Input: "unix:/tmp/test.sock",
Output: UnixDestination(DomainAddress("/tmp/test.sock")),
},
{
Input: "8.8.8.8:53",
Output: Destination{
Address: IPAddress([]byte{8, 8, 8, 8}),
Port: Port(53),
},
},
{
Input: ":53",
Output: Destination{
Address: AnyIP,
Port: Port(53),
},
},
{
Input: "8.8.8.8",
Error: true,
},
{
Input: "8.8.8.8:http",
Error: true,
},
{
Input: "/tmp/test.sock",
Error: true,
},
}
for _, testcase := range cases {
d, err := ParseDestination(testcase.Input)
if !testcase.Error {
if err != nil {
t.Error("for test case: ", testcase.Input, " expected no error, but got ", err)
}
if d != testcase.Output {
t.Error("for test case: ", testcase.Input, " expected output: ", testcase.Output.String(), " but got ", d.String())
}
} else if err == nil {
t.Error("for test case: ", testcase.Input, " expected error, but got nil")
}
}
}
v2ray-core-4.34.0/common/net/errors.generated.go 0000664 0000000 0000000 00000000311 13774574720 0021464 0 ustar 00root root 0000000 0000000 package net
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/common/net/net.go 0000664 0000000 0000000 00000000317 13774574720 0017007 0 ustar 00root root 0000000 0000000 // Package net is a drop-in replacement to Golang's net package, with some more functionalities.
package net // import "v2ray.com/core/common/net"
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/common/net/network.go 0000664 0000000 0000000 00000000647 13774574720 0017720 0 ustar 00root root 0000000 0000000 package net
func (n Network) SystemString() string {
switch n {
case Network_TCP:
return "tcp"
case Network_UDP:
return "udp"
case Network_UNIX:
return "unix"
default:
return "unknown"
}
}
// HasNetwork returns true if the network list has a certain network.
func HasNetwork(list []Network, network Network) bool {
for _, value := range list {
if value == network {
return true
}
}
return false
}
v2ray-core-4.34.0/common/net/network.pb.go 0000664 0000000 0000000 00000016232 13774574720 0020315 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: common/net/network.proto
package net
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Network int32
const (
Network_Unknown Network = 0
// Deprecated: Do not use.
Network_RawTCP Network = 1
Network_TCP Network = 2
Network_UDP Network = 3
Network_UNIX Network = 4
)
// Enum value maps for Network.
var (
Network_name = map[int32]string{
0: "Unknown",
1: "RawTCP",
2: "TCP",
3: "UDP",
4: "UNIX",
}
Network_value = map[string]int32{
"Unknown": 0,
"RawTCP": 1,
"TCP": 2,
"UDP": 3,
"UNIX": 4,
}
)
func (x Network) Enum() *Network {
p := new(Network)
*p = x
return p
}
func (x Network) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Network) Descriptor() protoreflect.EnumDescriptor {
return file_common_net_network_proto_enumTypes[0].Descriptor()
}
func (Network) Type() protoreflect.EnumType {
return &file_common_net_network_proto_enumTypes[0]
}
func (x Network) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Network.Descriptor instead.
func (Network) EnumDescriptor() ([]byte, []int) {
return file_common_net_network_proto_rawDescGZIP(), []int{0}
}
// NetworkList is a list of Networks.
type NetworkList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Network []Network `protobuf:"varint,1,rep,packed,name=network,proto3,enum=v2ray.core.common.net.Network" json:"network,omitempty"`
}
func (x *NetworkList) Reset() {
*x = NetworkList{}
if protoimpl.UnsafeEnabled {
mi := &file_common_net_network_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *NetworkList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NetworkList) ProtoMessage() {}
func (x *NetworkList) ProtoReflect() protoreflect.Message {
mi := &file_common_net_network_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NetworkList.ProtoReflect.Descriptor instead.
func (*NetworkList) Descriptor() ([]byte, []int) {
return file_common_net_network_proto_rawDescGZIP(), []int{0}
}
func (x *NetworkList) GetNetwork() []Network {
if x != nil {
return x.Network
}
return nil
}
var File_common_net_network_proto protoreflect.FileDescriptor
var file_common_net_network_proto_rawDesc = []byte{
0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74,
0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
0x74, 0x22, 0x47, 0x0a, 0x0b, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69, 0x73, 0x74,
0x12, 0x38, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x03, 0x28,
0x0e, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72,
0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2a, 0x42, 0x0a, 0x07, 0x4e, 0x65,
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e,
0x10, 0x00, 0x12, 0x0e, 0x0a, 0x06, 0x52, 0x61, 0x77, 0x54, 0x43, 0x50, 0x10, 0x01, 0x1a, 0x02,
0x08, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x55,
0x44, 0x50, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x4e, 0x49, 0x58, 0x10, 0x04, 0x42, 0x50,
0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x19, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x15, 0x56, 0x32, 0x52, 0x61, 0x79,
0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_common_net_network_proto_rawDescOnce sync.Once
file_common_net_network_proto_rawDescData = file_common_net_network_proto_rawDesc
)
func file_common_net_network_proto_rawDescGZIP() []byte {
file_common_net_network_proto_rawDescOnce.Do(func() {
file_common_net_network_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_net_network_proto_rawDescData)
})
return file_common_net_network_proto_rawDescData
}
var file_common_net_network_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_common_net_network_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_common_net_network_proto_goTypes = []interface{}{
(Network)(0), // 0: v2ray.core.common.net.Network
(*NetworkList)(nil), // 1: v2ray.core.common.net.NetworkList
}
var file_common_net_network_proto_depIdxs = []int32{
0, // 0: v2ray.core.common.net.NetworkList.network:type_name -> v2ray.core.common.net.Network
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_common_net_network_proto_init() }
func file_common_net_network_proto_init() {
if File_common_net_network_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_net_network_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NetworkList); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_net_network_proto_rawDesc,
NumEnums: 1,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_net_network_proto_goTypes,
DependencyIndexes: file_common_net_network_proto_depIdxs,
EnumInfos: file_common_net_network_proto_enumTypes,
MessageInfos: file_common_net_network_proto_msgTypes,
}.Build()
File_common_net_network_proto = out.File
file_common_net_network_proto_rawDesc = nil
file_common_net_network_proto_goTypes = nil
file_common_net_network_proto_depIdxs = nil
}
v2ray-core-4.34.0/common/net/network.proto 0000664 0000000 0000000 00000000660 13774574720 0020451 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.common.net;
option csharp_namespace = "V2Ray.Core.Common.Net";
option go_package = "v2ray.com/core/common/net";
option java_package = "com.v2ray.core.common.net";
option java_multiple_files = true;
enum Network {
Unknown = 0;
RawTCP = 1 [deprecated = true];
TCP = 2;
UDP = 3;
UNIX = 4;
}
// NetworkList is a list of Networks.
message NetworkList { repeated Network network = 1; }
v2ray-core-4.34.0/common/net/port.go 0000664 0000000 0000000 00000004430 13774574720 0017205 0 ustar 00root root 0000000 0000000 package net
import (
"encoding/binary"
"strconv"
)
// Port represents a network port in TCP and UDP protocol.
type Port uint16
// PortFromBytes converts a byte array to a Port, assuming bytes are in big endian order.
// @unsafe Caller must ensure that the byte array has at least 2 elements.
func PortFromBytes(port []byte) Port {
return Port(binary.BigEndian.Uint16(port))
}
// PortFromInt converts an integer to a Port.
// @error when the integer is not positive or larger then 65535
func PortFromInt(val uint32) (Port, error) {
if val > 65535 {
return Port(0), newError("invalid port range: ", val)
}
return Port(val), nil
}
// PortFromString converts a string to a Port.
// @error when the string is not an integer or the integral value is a not a valid Port.
func PortFromString(s string) (Port, error) {
val, err := strconv.ParseUint(s, 10, 32)
if err != nil {
return Port(0), newError("invalid port range: ", s)
}
return PortFromInt(uint32(val))
}
// Value return the corresponding uint16 value of a Port.
func (p Port) Value() uint16 {
return uint16(p)
}
// String returns the string presentation of a Port.
func (p Port) String() string {
return strconv.Itoa(int(p))
}
// FromPort returns the beginning port of this PortRange.
func (p *PortRange) FromPort() Port {
return Port(p.From)
}
// ToPort returns the end port of this PortRange.
func (p *PortRange) ToPort() Port {
return Port(p.To)
}
// Contains returns true if the given port is within the range of a PortRange.
func (p *PortRange) Contains(port Port) bool {
return p.FromPort() <= port && port <= p.ToPort()
}
// SinglePortRange returns a PortRange contains a single port.
func SinglePortRange(p Port) *PortRange {
return &PortRange{
From: uint32(p),
To: uint32(p),
}
}
type MemoryPortRange struct {
From Port
To Port
}
func (r MemoryPortRange) Contains(port Port) bool {
return r.From <= port && port <= r.To
}
type MemoryPortList []MemoryPortRange
func PortListFromProto(l *PortList) MemoryPortList {
mpl := make(MemoryPortList, 0, len(l.Range))
for _, r := range l.Range {
mpl = append(mpl, MemoryPortRange{From: Port(r.From), To: Port(r.To)})
}
return mpl
}
func (mpl MemoryPortList) Contains(port Port) bool {
for _, pr := range mpl {
if pr.Contains(port) {
return true
}
}
return false
}
v2ray-core-4.34.0/common/net/port.pb.go 0000664 0000000 0000000 00000016336 13774574720 0017615 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: common/net/port.proto
package net
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// PortRange represents a range of ports.
type PortRange struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The port that this range starts from.
From uint32 `protobuf:"varint,1,opt,name=From,proto3" json:"From,omitempty"`
// The port that this range ends with (inclusive).
To uint32 `protobuf:"varint,2,opt,name=To,proto3" json:"To,omitempty"`
}
func (x *PortRange) Reset() {
*x = PortRange{}
if protoimpl.UnsafeEnabled {
mi := &file_common_net_port_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PortRange) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PortRange) ProtoMessage() {}
func (x *PortRange) ProtoReflect() protoreflect.Message {
mi := &file_common_net_port_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PortRange.ProtoReflect.Descriptor instead.
func (*PortRange) Descriptor() ([]byte, []int) {
return file_common_net_port_proto_rawDescGZIP(), []int{0}
}
func (x *PortRange) GetFrom() uint32 {
if x != nil {
return x.From
}
return 0
}
func (x *PortRange) GetTo() uint32 {
if x != nil {
return x.To
}
return 0
}
// PortList is a list of ports.
type PortList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Range []*PortRange `protobuf:"bytes,1,rep,name=range,proto3" json:"range,omitempty"`
}
func (x *PortList) Reset() {
*x = PortList{}
if protoimpl.UnsafeEnabled {
mi := &file_common_net_port_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PortList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PortList) ProtoMessage() {}
func (x *PortList) ProtoReflect() protoreflect.Message {
mi := &file_common_net_port_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PortList.ProtoReflect.Descriptor instead.
func (*PortList) Descriptor() ([]byte, []int) {
return file_common_net_port_proto_rawDescGZIP(), []int{1}
}
func (x *PortList) GetRange() []*PortRange {
if x != nil {
return x.Range
}
return nil
}
var File_common_net_port_proto protoreflect.FileDescriptor
var file_common_net_port_proto_rawDesc = []byte{
0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x22, 0x2f,
0x0a, 0x09, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x46,
0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x46, 0x72, 0x6f, 0x6d, 0x12,
0x0e, 0x0a, 0x02, 0x54, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x54, 0x6f, 0x22,
0x42, 0x0a, 0x08, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x36, 0x0a, 0x05, 0x72,
0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e,
0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x05, 0x72, 0x61,
0x6e, 0x67, 0x65, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,
0x50, 0x01, 0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f,
0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x15,
0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2e, 0x4e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_common_net_port_proto_rawDescOnce sync.Once
file_common_net_port_proto_rawDescData = file_common_net_port_proto_rawDesc
)
func file_common_net_port_proto_rawDescGZIP() []byte {
file_common_net_port_proto_rawDescOnce.Do(func() {
file_common_net_port_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_net_port_proto_rawDescData)
})
return file_common_net_port_proto_rawDescData
}
var file_common_net_port_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_common_net_port_proto_goTypes = []interface{}{
(*PortRange)(nil), // 0: v2ray.core.common.net.PortRange
(*PortList)(nil), // 1: v2ray.core.common.net.PortList
}
var file_common_net_port_proto_depIdxs = []int32{
0, // 0: v2ray.core.common.net.PortList.range:type_name -> v2ray.core.common.net.PortRange
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_common_net_port_proto_init() }
func file_common_net_port_proto_init() {
if File_common_net_port_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_net_port_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PortRange); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_common_net_port_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PortList); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_net_port_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_net_port_proto_goTypes,
DependencyIndexes: file_common_net_port_proto_depIdxs,
MessageInfos: file_common_net_port_proto_msgTypes,
}.Build()
File_common_net_port_proto = out.File
file_common_net_port_proto_rawDesc = nil
file_common_net_port_proto_goTypes = nil
file_common_net_port_proto_depIdxs = nil
}
v2ray-core-4.34.0/common/net/port.proto 0000664 0000000 0000000 00000001010 13774574720 0017732 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.common.net;
option csharp_namespace = "V2Ray.Core.Common.Net";
option go_package = "v2ray.com/core/common/net";
option java_package = "com.v2ray.core.common.net";
option java_multiple_files = true;
// PortRange represents a range of ports.
message PortRange {
// The port that this range starts from.
uint32 From = 1;
// The port that this range ends with (inclusive).
uint32 To = 2;
}
// PortList is a list of ports.
message PortList {
repeated PortRange range = 1;
}
v2ray-core-4.34.0/common/net/port_test.go 0000664 0000000 0000000 00000000424 13774574720 0020243 0 ustar 00root root 0000000 0000000 package net_test
import (
"testing"
. "v2ray.com/core/common/net"
)
func TestPortRangeContains(t *testing.T) {
portRange := &PortRange{
From: 53,
To: 53,
}
if !portRange.Contains(Port(53)) {
t.Error("expected port range containing 53, but actually not")
}
}
v2ray-core-4.34.0/common/net/system.go 0000664 0000000 0000000 00000002265 13774574720 0017551 0 ustar 00root root 0000000 0000000 package net
import "net"
// DialTCP is an alias of net.DialTCP.
var DialTCP = net.DialTCP
var DialUDP = net.DialUDP
var DialUnix = net.DialUnix
var Dial = net.Dial
type ListenConfig = net.ListenConfig
var Listen = net.Listen
var ListenTCP = net.ListenTCP
var ListenUDP = net.ListenUDP
var ListenUnix = net.ListenUnix
var LookupIP = net.LookupIP
var FileConn = net.FileConn
// ParseIP is an alias of net.ParseIP
var ParseIP = net.ParseIP
var SplitHostPort = net.SplitHostPort
var CIDRMask = net.CIDRMask
type Addr = net.Addr
type Conn = net.Conn
type PacketConn = net.PacketConn
type TCPAddr = net.TCPAddr
type TCPConn = net.TCPConn
type UDPAddr = net.UDPAddr
type UDPConn = net.UDPConn
type UnixAddr = net.UnixAddr
type UnixConn = net.UnixConn
// IP is an alias for net.IP.
type IP = net.IP
type IPMask = net.IPMask
type IPNet = net.IPNet
const IPv4len = net.IPv4len
const IPv6len = net.IPv6len
type Error = net.Error
type AddrError = net.AddrError
type Dialer = net.Dialer
type Listener = net.Listener
type TCPListener = net.TCPListener
type UnixListener = net.UnixListener
var ResolveUnixAddr = net.ResolveUnixAddr
var ResolveUDPAddr = net.ResolveUDPAddr
type Resolver = net.Resolver
v2ray-core-4.34.0/common/peer/ 0000775 0000000 0000000 00000000000 13774574720 0016036 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/peer/latency.go 0000664 0000000 0000000 00000000662 13774574720 0020030 0 ustar 00root root 0000000 0000000 package peer
import (
"sync"
)
type Latency interface {
Value() uint64
}
type HasLatency interface {
ConnectionLatency() Latency
HandshakeLatency() Latency
}
type AverageLatency struct {
access sync.Mutex
value uint64
}
func (al *AverageLatency) Update(newValue uint64) {
al.access.Lock()
defer al.access.Unlock()
al.value = (al.value + newValue*2) / 3
}
func (al *AverageLatency) Value() uint64 {
return al.value
}
v2ray-core-4.34.0/common/peer/peer.go 0000664 0000000 0000000 00000000015 13774574720 0017314 0 ustar 00root root 0000000 0000000 package peer
v2ray-core-4.34.0/common/platform/ 0000775 0000000 0000000 00000000000 13774574720 0016727 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/platform/ctlcmd/ 0000775 0000000 0000000 00000000000 13774574720 0020175 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/platform/ctlcmd/attr_other.go 0000664 0000000 0000000 00000000161 13774574720 0022675 0 ustar 00root root 0000000 0000000 // +build !windows
package ctlcmd
import "syscall"
func getSysProcAttr() *syscall.SysProcAttr {
return nil
}
v2ray-core-4.34.0/common/platform/ctlcmd/attr_windows.go 0000664 0000000 0000000 00000000231 13774574720 0023244 0 ustar 00root root 0000000 0000000 // +build windows
package ctlcmd
import "syscall"
func getSysProcAttr() *syscall.SysProcAttr {
return &syscall.SysProcAttr{
HideWindow: true,
}
}
v2ray-core-4.34.0/common/platform/ctlcmd/ctlcmd.go 0000664 0000000 0000000 00000002213 13774574720 0021770 0 ustar 00root root 0000000 0000000 package ctlcmd
import (
"io"
"os"
"os/exec"
"strings"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/platform"
)
//go:generate go run v2ray.com/core/common/errors/errorgen
func Run(args []string, input io.Reader) (buf.MultiBuffer, error) {
v2ctl := platform.GetToolLocation("v2ctl")
if _, err := os.Stat(v2ctl); err != nil {
return nil, newError("v2ctl doesn't exist").Base(err)
}
var errBuffer buf.MultiBufferContainer
var outBuffer buf.MultiBufferContainer
cmd := exec.Command(v2ctl, args...)
cmd.Stderr = &errBuffer
cmd.Stdout = &outBuffer
cmd.SysProcAttr = getSysProcAttr()
if input != nil {
cmd.Stdin = input
}
if err := cmd.Start(); err != nil {
return nil, newError("failed to start v2ctl").Base(err)
}
if err := cmd.Wait(); err != nil {
msg := "failed to execute v2ctl"
if errBuffer.Len() > 0 {
msg += ": \n" + strings.TrimSpace(errBuffer.MultiBuffer.String())
}
return nil, newError(msg).Base(err)
}
// log stderr, info message
if !errBuffer.IsEmpty() {
newError(" \n", strings.TrimSpace(errBuffer.MultiBuffer.String())).AtInfo().WriteToLog()
}
return outBuffer.MultiBuffer, nil
}
v2ray-core-4.34.0/common/platform/ctlcmd/errors.generated.go 0000664 0000000 0000000 00000000314 13774574720 0023773 0 ustar 00root root 0000000 0000000 package ctlcmd
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/common/platform/filesystem/ 0000775 0000000 0000000 00000000000 13774574720 0021113 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/platform/filesystem/file.go 0000664 0000000 0000000 00000001451 13774574720 0022362 0 ustar 00root root 0000000 0000000 package filesystem
import (
"io"
"os"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/platform"
)
type FileReaderFunc func(path string) (io.ReadCloser, error)
var NewFileReader FileReaderFunc = func(path string) (io.ReadCloser, error) {
return os.Open(path)
}
func ReadFile(path string) ([]byte, error) {
reader, err := NewFileReader(path)
if err != nil {
return nil, err
}
defer reader.Close()
return buf.ReadAllToBytes(reader)
}
func ReadAsset(file string) ([]byte, error) {
return ReadFile(platform.GetAssetLocation(file))
}
func CopyFile(dst string, src string) error {
bytes, err := ReadFile(src)
if err != nil {
return err
}
f, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer f.Close()
_, err = f.Write(bytes)
return err
}
v2ray-core-4.34.0/common/platform/others.go 0000664 0000000 0000000 00000001660 13774574720 0020565 0 ustar 00root root 0000000 0000000 // +build !windows
package platform
import (
"os"
"path/filepath"
)
func ExpandEnv(s string) string {
return os.ExpandEnv(s)
}
func LineSeparator() string {
return "\n"
}
func GetToolLocation(file string) string {
const name = "v2ray.location.tool"
toolPath := EnvFlag{Name: name, AltName: NormalizeEnvName(name)}.GetValue(getExecutableDir)
return filepath.Join(toolPath, file)
}
// GetAssetLocation search for `file` in certain locations
func GetAssetLocation(file string) string {
const name = "v2ray.location.asset"
assetPath := NewEnvFlag(name).GetValue(getExecutableDir)
defPath := filepath.Join(assetPath, file)
for _, p := range []string{
defPath,
filepath.Join("/usr/local/share/v2ray/", file),
filepath.Join("/usr/share/v2ray/", file),
} {
if _, err := os.Stat(p); os.IsNotExist(err) {
continue
}
// asset found
return p
}
// asset not found, let the caller throw out the error
return defPath
}
v2ray-core-4.34.0/common/platform/platform.go 0000664 0000000 0000000 00000003362 13774574720 0021106 0 ustar 00root root 0000000 0000000 package platform // import "v2ray.com/core/common/platform"
import (
"os"
"path/filepath"
"strconv"
"strings"
)
type EnvFlag struct {
Name string
AltName string
}
func NewEnvFlag(name string) EnvFlag {
return EnvFlag{
Name: name,
AltName: NormalizeEnvName(name),
}
}
func (f EnvFlag) GetValue(defaultValue func() string) string {
if v, found := os.LookupEnv(f.Name); found {
return v
}
if len(f.AltName) > 0 {
if v, found := os.LookupEnv(f.AltName); found {
return v
}
}
return defaultValue()
}
func (f EnvFlag) GetValueAsInt(defaultValue int) int {
useDefaultValue := false
s := f.GetValue(func() string {
useDefaultValue = true
return ""
})
if useDefaultValue {
return defaultValue
}
v, err := strconv.ParseInt(s, 10, 32)
if err != nil {
return defaultValue
}
return int(v)
}
func NormalizeEnvName(name string) string {
return strings.ReplaceAll(strings.ToUpper(strings.TrimSpace(name)), ".", "_")
}
func getExecutableDir() string {
exec, err := os.Executable()
if err != nil {
return ""
}
return filepath.Dir(exec)
}
func getExecutableSubDir(dir string) func() string {
return func() string {
return filepath.Join(getExecutableDir(), dir)
}
}
func GetPluginDirectory() string {
const name = "v2ray.location.plugin"
pluginDir := NewEnvFlag(name).GetValue(getExecutableSubDir("plugins"))
return pluginDir
}
func GetConfigurationPath() string {
const name = "v2ray.location.config"
configPath := NewEnvFlag(name).GetValue(getExecutableDir)
return filepath.Join(configPath, "config.json")
}
// GetConfDirPath reads "v2ray.location.confdir"
func GetConfDirPath() string {
const name = "v2ray.location.confdir"
configPath := NewEnvFlag(name).GetValue(func() string { return "" })
return configPath
}
v2ray-core-4.34.0/common/platform/platform_test.go 0000664 0000000 0000000 00000002205 13774574720 0022140 0 ustar 00root root 0000000 0000000 package platform_test
import (
"os"
"path/filepath"
"runtime"
"testing"
"v2ray.com/core/common"
. "v2ray.com/core/common/platform"
)
func TestNormalizeEnvName(t *testing.T) {
cases := []struct {
input string
output string
}{
{
input: "a",
output: "A",
},
{
input: "a.a",
output: "A_A",
},
{
input: "A.A.B",
output: "A_A_B",
},
}
for _, test := range cases {
if v := NormalizeEnvName(test.input); v != test.output {
t.Error("unexpected output: ", v, " want ", test.output)
}
}
}
func TestEnvFlag(t *testing.T) {
if v := (EnvFlag{
Name: "xxxxx.y",
}.GetValueAsInt(10)); v != 10 {
t.Error("env value: ", v)
}
}
func TestGetAssetLocation(t *testing.T) {
exec, err := os.Executable()
common.Must(err)
loc := GetAssetLocation("t")
if filepath.Dir(loc) != filepath.Dir(exec) {
t.Error("asset dir: ", loc, " not in ", exec)
}
os.Setenv("v2ray.location.asset", "/v2ray")
if runtime.GOOS == "windows" {
if v := GetAssetLocation("t"); v != "\\v2ray\\t" {
t.Error("asset loc: ", v)
}
} else {
if v := GetAssetLocation("t"); v != "/v2ray/t" {
t.Error("asset loc: ", v)
}
}
}
v2ray-core-4.34.0/common/platform/windows.go 0000664 0000000 0000000 00000001160 13774574720 0020746 0 ustar 00root root 0000000 0000000 // +build windows
package platform
import "path/filepath"
func ExpandEnv(s string) string {
// TODO
return s
}
func LineSeparator() string {
return "\r\n"
}
func GetToolLocation(file string) string {
const name = "v2ray.location.tool"
toolPath := EnvFlag{Name: name, AltName: NormalizeEnvName(name)}.GetValue(getExecutableDir)
return filepath.Join(toolPath, file+".exe")
}
// GetAssetLocation search for `file` in the excutable dir
func GetAssetLocation(file string) string {
const name = "v2ray.location.asset"
assetPath := NewEnvFlag(name).GetValue(getExecutableDir)
return filepath.Join(assetPath, file)
}
v2ray-core-4.34.0/common/protocol/ 0000775 0000000 0000000 00000000000 13774574720 0016744 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/protocol/account.go 0000664 0000000 0000000 00000000357 13774574720 0020734 0 ustar 00root root 0000000 0000000 package protocol
// Account is a user identity used for authentication.
type Account interface {
Equals(Account) bool
}
// AsAccount is an object can be converted into account.
type AsAccount interface {
AsAccount() (Account, error)
}
v2ray-core-4.34.0/common/protocol/address.go 0000664 0000000 0000000 00000013344 13774574720 0020725 0 ustar 00root root 0000000 0000000 package protocol
import (
"io"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/serial"
)
type AddressOption func(*option)
func PortThenAddress() AddressOption {
return func(p *option) {
p.portFirst = true
}
}
func AddressFamilyByte(b byte, f net.AddressFamily) AddressOption {
if b >= 16 {
panic("address family byte too big")
}
return func(p *option) {
p.addrTypeMap[b] = f
p.addrByteMap[f] = b
}
}
type AddressTypeParser func(byte) byte
func WithAddressTypeParser(atp AddressTypeParser) AddressOption {
return func(p *option) {
p.typeParser = atp
}
}
type AddressSerializer interface {
ReadAddressPort(buffer *buf.Buffer, input io.Reader) (net.Address, net.Port, error)
WriteAddressPort(writer io.Writer, addr net.Address, port net.Port) error
}
const afInvalid = 255
type option struct {
addrTypeMap [16]net.AddressFamily
addrByteMap [16]byte
portFirst bool
typeParser AddressTypeParser
}
// NewAddressParser creates a new AddressParser
func NewAddressParser(options ...AddressOption) AddressSerializer {
var o option
for i := range o.addrByteMap {
o.addrByteMap[i] = afInvalid
}
for i := range o.addrTypeMap {
o.addrTypeMap[i] = net.AddressFamily(afInvalid)
}
for _, opt := range options {
opt(&o)
}
ap := &addressParser{
addrByteMap: o.addrByteMap,
addrTypeMap: o.addrTypeMap,
}
if o.typeParser != nil {
ap.typeParser = o.typeParser
}
if o.portFirst {
return portFirstAddressParser{ap: ap}
}
return portLastAddressParser{ap: ap}
}
type portFirstAddressParser struct {
ap *addressParser
}
func (p portFirstAddressParser) ReadAddressPort(buffer *buf.Buffer, input io.Reader) (net.Address, net.Port, error) {
if buffer == nil {
buffer = buf.New()
defer buffer.Release()
}
port, err := readPort(buffer, input)
if err != nil {
return nil, 0, err
}
addr, err := p.ap.readAddress(buffer, input)
if err != nil {
return nil, 0, err
}
return addr, port, nil
}
func (p portFirstAddressParser) WriteAddressPort(writer io.Writer, addr net.Address, port net.Port) error {
if err := writePort(writer, port); err != nil {
return err
}
return p.ap.writeAddress(writer, addr)
}
type portLastAddressParser struct {
ap *addressParser
}
func (p portLastAddressParser) ReadAddressPort(buffer *buf.Buffer, input io.Reader) (net.Address, net.Port, error) {
if buffer == nil {
buffer = buf.New()
defer buffer.Release()
}
addr, err := p.ap.readAddress(buffer, input)
if err != nil {
return nil, 0, err
}
port, err := readPort(buffer, input)
if err != nil {
return nil, 0, err
}
return addr, port, nil
}
func (p portLastAddressParser) WriteAddressPort(writer io.Writer, addr net.Address, port net.Port) error {
if err := p.ap.writeAddress(writer, addr); err != nil {
return err
}
return writePort(writer, port)
}
func readPort(b *buf.Buffer, reader io.Reader) (net.Port, error) {
if _, err := b.ReadFullFrom(reader, 2); err != nil {
return 0, err
}
return net.PortFromBytes(b.BytesFrom(-2)), nil
}
func writePort(writer io.Writer, port net.Port) error {
return common.Error2(serial.WriteUint16(writer, port.Value()))
}
func maybeIPPrefix(b byte) bool {
return b == '[' || (b >= '0' && b <= '9')
}
func isValidDomain(d string) bool {
for _, c := range d {
if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '-' || c == '.' || c == '_') {
return false
}
}
return true
}
type addressParser struct {
addrTypeMap [16]net.AddressFamily
addrByteMap [16]byte
typeParser AddressTypeParser
}
func (p *addressParser) readAddress(b *buf.Buffer, reader io.Reader) (net.Address, error) {
if _, err := b.ReadFullFrom(reader, 1); err != nil {
return nil, err
}
addrType := b.Byte(b.Len() - 1)
if p.typeParser != nil {
addrType = p.typeParser(addrType)
}
if addrType >= 16 {
return nil, newError("unknown address type: ", addrType)
}
addrFamily := p.addrTypeMap[addrType]
if addrFamily == net.AddressFamily(afInvalid) {
return nil, newError("unknown address type: ", addrType)
}
switch addrFamily {
case net.AddressFamilyIPv4:
if _, err := b.ReadFullFrom(reader, 4); err != nil {
return nil, err
}
return net.IPAddress(b.BytesFrom(-4)), nil
case net.AddressFamilyIPv6:
if _, err := b.ReadFullFrom(reader, 16); err != nil {
return nil, err
}
return net.IPAddress(b.BytesFrom(-16)), nil
case net.AddressFamilyDomain:
if _, err := b.ReadFullFrom(reader, 1); err != nil {
return nil, err
}
domainLength := int32(b.Byte(b.Len() - 1))
if _, err := b.ReadFullFrom(reader, domainLength); err != nil {
return nil, err
}
domain := string(b.BytesFrom(-domainLength))
if maybeIPPrefix(domain[0]) {
addr := net.ParseAddress(domain)
if addr.Family().IsIP() {
return addr, nil
}
}
if !isValidDomain(domain) {
return nil, newError("invalid domain name: ", domain)
}
return net.DomainAddress(domain), nil
default:
panic("impossible case")
}
}
func (p *addressParser) writeAddress(writer io.Writer, address net.Address) error {
tb := p.addrByteMap[address.Family()]
if tb == afInvalid {
return newError("unknown address family", address.Family())
}
switch address.Family() {
case net.AddressFamilyIPv4, net.AddressFamilyIPv6:
if _, err := writer.Write([]byte{tb}); err != nil {
return err
}
if _, err := writer.Write(address.IP()); err != nil {
return err
}
case net.AddressFamilyDomain:
domain := address.Domain()
if isDomainTooLong(domain) {
return newError("Super long domain is not supported: ", domain)
}
if _, err := writer.Write([]byte{tb, byte(len(domain))}); err != nil {
return err
}
if _, err := writer.Write([]byte(domain)); err != nil {
return err
}
default:
panic("Unknown family type.")
}
return nil
}
v2ray-core-4.34.0/common/protocol/address_test.go 0000664 0000000 0000000 00000013753 13774574720 0021770 0 ustar 00root root 0000000 0000000 package protocol_test
import (
"bytes"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
. "v2ray.com/core/common/protocol"
)
func TestAddressReading(t *testing.T) {
data := []struct {
Options []AddressOption
Input []byte
Address net.Address
Port net.Port
Error bool
}{
{
Options: []AddressOption{},
Input: []byte{},
Error: true,
},
{
Options: []AddressOption{},
Input: []byte{0, 0, 0, 0, 0},
Error: true,
},
{
Options: []AddressOption{AddressFamilyByte(0x01, net.AddressFamilyIPv4)},
Input: []byte{1, 0, 0, 0, 0, 0, 53},
Address: net.IPAddress([]byte{0, 0, 0, 0}),
Port: net.Port(53),
},
{
Options: []AddressOption{AddressFamilyByte(0x01, net.AddressFamilyIPv4), PortThenAddress()},
Input: []byte{0, 53, 1, 0, 0, 0, 0},
Address: net.IPAddress([]byte{0, 0, 0, 0}),
Port: net.Port(53),
},
{
Options: []AddressOption{AddressFamilyByte(0x01, net.AddressFamilyIPv4)},
Input: []byte{1, 0, 0, 0, 0},
Error: true,
},
{
Options: []AddressOption{AddressFamilyByte(0x04, net.AddressFamilyIPv6)},
Input: []byte{4, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 0, 80},
Address: net.IPAddress([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}),
Port: net.Port(80),
},
{
Options: []AddressOption{AddressFamilyByte(0x03, net.AddressFamilyDomain)},
Input: []byte{3, 9, 118, 50, 114, 97, 121, 46, 99, 111, 109, 0, 80},
Address: net.DomainAddress("v2ray.com"),
Port: net.Port(80),
},
{
Options: []AddressOption{AddressFamilyByte(0x03, net.AddressFamilyDomain)},
Input: []byte{3, 9, 118, 50, 114, 97, 121, 46, 99, 111, 109, 0},
Error: true,
},
{
Options: []AddressOption{AddressFamilyByte(0x03, net.AddressFamilyDomain)},
Input: []byte{3, 7, 56, 46, 56, 46, 56, 46, 56, 0, 80},
Address: net.ParseAddress("8.8.8.8"),
Port: net.Port(80),
},
{
Options: []AddressOption{AddressFamilyByte(0x03, net.AddressFamilyDomain)},
Input: []byte{3, 7, 10, 46, 56, 46, 56, 46, 56, 0, 80},
Error: true,
},
{
Options: []AddressOption{AddressFamilyByte(0x03, net.AddressFamilyDomain)},
Input: append(append([]byte{3, 24}, []byte("2a00:1450:4007:816::200e")...), 0, 80),
Address: net.ParseAddress("2a00:1450:4007:816::200e"),
Port: net.Port(80),
},
}
for _, tc := range data {
b := buf.New()
parser := NewAddressParser(tc.Options...)
addr, port, err := parser.ReadAddressPort(b, bytes.NewReader(tc.Input))
b.Release()
if tc.Error {
if err == nil {
t.Errorf("Expect error but not: %v", tc)
}
} else {
if err != nil {
t.Errorf("Expect no error but: %s %v", err.Error(), tc)
}
if addr != tc.Address {
t.Error("Got address ", addr.String(), " want ", tc.Address.String())
}
if tc.Port != port {
t.Error("Got port ", port, " want ", tc.Port)
}
}
}
}
func TestAddressWriting(t *testing.T) {
data := []struct {
Options []AddressOption
Address net.Address
Port net.Port
Bytes []byte
Error bool
}{
{
Options: []AddressOption{AddressFamilyByte(0x01, net.AddressFamilyIPv4)},
Address: net.LocalHostIP,
Port: net.Port(80),
Bytes: []byte{1, 127, 0, 0, 1, 0, 80},
},
}
for _, tc := range data {
parser := NewAddressParser(tc.Options...)
b := buf.New()
err := parser.WriteAddressPort(b, tc.Address, tc.Port)
if tc.Error {
if err == nil {
t.Error("Expect error but nil")
}
} else {
common.Must(err)
if diff := cmp.Diff(tc.Bytes, b.Bytes()); diff != "" {
t.Error(err)
}
}
}
}
func BenchmarkAddressReadingIPv4(b *testing.B) {
parser := NewAddressParser(AddressFamilyByte(0x01, net.AddressFamilyIPv4))
cache := buf.New()
defer cache.Release()
payload := buf.New()
defer payload.Release()
raw := []byte{1, 0, 0, 0, 0, 0, 53}
payload.Write(raw)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _, err := parser.ReadAddressPort(cache, payload)
common.Must(err)
cache.Clear()
payload.Clear()
payload.Extend(int32(len(raw)))
}
}
func BenchmarkAddressReadingIPv6(b *testing.B) {
parser := NewAddressParser(AddressFamilyByte(0x04, net.AddressFamilyIPv6))
cache := buf.New()
defer cache.Release()
payload := buf.New()
defer payload.Release()
raw := []byte{4, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 0, 80}
payload.Write(raw)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _, err := parser.ReadAddressPort(cache, payload)
common.Must(err)
cache.Clear()
payload.Clear()
payload.Extend(int32(len(raw)))
}
}
func BenchmarkAddressReadingDomain(b *testing.B) {
parser := NewAddressParser(AddressFamilyByte(0x03, net.AddressFamilyDomain))
cache := buf.New()
defer cache.Release()
payload := buf.New()
defer payload.Release()
raw := []byte{3, 9, 118, 50, 114, 97, 121, 46, 99, 111, 109, 0, 80}
payload.Write(raw)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _, err := parser.ReadAddressPort(cache, payload)
common.Must(err)
cache.Clear()
payload.Clear()
payload.Extend(int32(len(raw)))
}
}
func BenchmarkAddressWritingIPv4(b *testing.B) {
parser := NewAddressParser(AddressFamilyByte(0x01, net.AddressFamilyIPv4))
writer := buf.New()
defer writer.Release()
b.ResetTimer()
for i := 0; i < b.N; i++ {
common.Must(parser.WriteAddressPort(writer, net.LocalHostIP, net.Port(80)))
writer.Clear()
}
}
func BenchmarkAddressWritingIPv6(b *testing.B) {
parser := NewAddressParser(AddressFamilyByte(0x04, net.AddressFamilyIPv6))
writer := buf.New()
defer writer.Release()
b.ResetTimer()
for i := 0; i < b.N; i++ {
common.Must(parser.WriteAddressPort(writer, net.LocalHostIPv6, net.Port(80)))
writer.Clear()
}
}
func BenchmarkAddressWritingDomain(b *testing.B) {
parser := NewAddressParser(AddressFamilyByte(0x02, net.AddressFamilyDomain))
writer := buf.New()
defer writer.Release()
b.ResetTimer()
for i := 0; i < b.N; i++ {
common.Must(parser.WriteAddressPort(writer, net.DomainAddress("www.v2ray.com"), net.Port(80)))
writer.Clear()
}
}
v2ray-core-4.34.0/common/protocol/bittorrent/ 0000775 0000000 0000000 00000000000 13774574720 0021140 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/protocol/bittorrent/bittorrent.go 0000664 0000000 0000000 00000000777 13774574720 0023676 0 ustar 00root root 0000000 0000000 package bittorrent
import (
"errors"
"v2ray.com/core/common"
)
type SniffHeader struct {
}
func (h *SniffHeader) Protocol() string {
return "bittorrent"
}
func (h *SniffHeader) Domain() string {
return ""
}
var errNotBittorrent = errors.New("not bittorrent header")
func SniffBittorrent(b []byte) (*SniffHeader, error) {
if len(b) < 20 {
return nil, common.ErrNoClue
}
if b[0] == 19 && string(b[1:20]) == "BitTorrent protocol" {
return &SniffHeader{}, nil
}
return nil, errNotBittorrent
}
v2ray-core-4.34.0/common/protocol/context.go 0000664 0000000 0000000 00000000633 13774574720 0020761 0 ustar 00root root 0000000 0000000 package protocol
import (
"context"
)
type key int
const (
requestKey key = iota
)
func ContextWithRequestHeader(ctx context.Context, request *RequestHeader) context.Context {
return context.WithValue(ctx, requestKey, request)
}
func RequestHeaderFromContext(ctx context.Context) *RequestHeader {
request := ctx.Value(requestKey)
if request == nil {
return nil
}
return request.(*RequestHeader)
}
v2ray-core-4.34.0/common/protocol/dns/ 0000775 0000000 0000000 00000000000 13774574720 0017530 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/protocol/dns/errors.generated.go 0000664 0000000 0000000 00000000311 13774574720 0023323 0 ustar 00root root 0000000 0000000 package dns
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/common/protocol/dns/io.go 0000664 0000000 0000000 00000004777 13774574720 0020505 0 ustar 00root root 0000000 0000000 package dns
import (
"encoding/binary"
"sync"
"golang.org/x/net/dns/dnsmessage"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/serial"
)
func PackMessage(msg *dnsmessage.Message) (*buf.Buffer, error) {
buffer := buf.New()
rawBytes := buffer.Extend(buf.Size)
packed, err := msg.AppendPack(rawBytes[:0])
if err != nil {
buffer.Release()
return nil, err
}
buffer.Resize(0, int32(len(packed)))
return buffer, nil
}
type MessageReader interface {
ReadMessage() (*buf.Buffer, error)
}
type UDPReader struct {
buf.Reader
access sync.Mutex
cache buf.MultiBuffer
}
func (r *UDPReader) readCache() *buf.Buffer {
r.access.Lock()
defer r.access.Unlock()
mb, b := buf.SplitFirst(r.cache)
r.cache = mb
return b
}
func (r *UDPReader) refill() error {
mb, err := r.Reader.ReadMultiBuffer()
if err != nil {
return err
}
r.access.Lock()
r.cache = mb
r.access.Unlock()
return nil
}
// ReadMessage implements MessageReader.
func (r *UDPReader) ReadMessage() (*buf.Buffer, error) {
for {
b := r.readCache()
if b != nil {
return b, nil
}
if err := r.refill(); err != nil {
return nil, err
}
}
}
// Close implements common.Closable.
func (r *UDPReader) Close() error {
defer func() {
r.access.Lock()
buf.ReleaseMulti(r.cache)
r.cache = nil
r.access.Unlock()
}()
return common.Close(r.Reader)
}
type TCPReader struct {
reader *buf.BufferedReader
}
func NewTCPReader(reader buf.Reader) *TCPReader {
return &TCPReader{
reader: &buf.BufferedReader{
Reader: reader,
},
}
}
func (r *TCPReader) ReadMessage() (*buf.Buffer, error) {
size, err := serial.ReadUint16(r.reader)
if err != nil {
return nil, err
}
if size > buf.Size {
return nil, newError("message size too large: ", size)
}
b := buf.New()
if _, err := b.ReadFullFrom(r.reader, int32(size)); err != nil {
return nil, err
}
return b, nil
}
func (r *TCPReader) Interrupt() {
common.Interrupt(r.reader)
}
func (r *TCPReader) Close() error {
return common.Close(r.reader)
}
type MessageWriter interface {
WriteMessage(msg *buf.Buffer) error
}
type UDPWriter struct {
buf.Writer
}
func (w *UDPWriter) WriteMessage(b *buf.Buffer) error {
return w.WriteMultiBuffer(buf.MultiBuffer{b})
}
type TCPWriter struct {
buf.Writer
}
func (w *TCPWriter) WriteMessage(b *buf.Buffer) error {
if b.IsEmpty() {
return nil
}
mb := make(buf.MultiBuffer, 0, 2)
size := buf.New()
binary.BigEndian.PutUint16(size.Extend(2), uint16(b.Len()))
mb = append(mb, size, b)
return w.WriteMultiBuffer(mb)
}
v2ray-core-4.34.0/common/protocol/errors.generated.go 0000664 0000000 0000000 00000000316 13774574720 0022544 0 ustar 00root root 0000000 0000000 package protocol
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/common/protocol/headers.go 0000664 0000000 0000000 00000004031 13774574720 0020704 0 ustar 00root root 0000000 0000000 package protocol
import (
"runtime"
"v2ray.com/core/common/bitmask"
"v2ray.com/core/common/net"
"v2ray.com/core/common/uuid"
)
// RequestCommand is a custom command in a proxy request.
type RequestCommand byte
const (
RequestCommandTCP = RequestCommand(0x01)
RequestCommandUDP = RequestCommand(0x02)
RequestCommandMux = RequestCommand(0x03)
)
func (c RequestCommand) TransferType() TransferType {
switch c {
case RequestCommandTCP, RequestCommandMux:
return TransferTypeStream
case RequestCommandUDP:
return TransferTypePacket
default:
return TransferTypeStream
}
}
const (
// RequestOptionChunkStream indicates request payload is chunked. Each chunk consists of length, authentication and payload.
RequestOptionChunkStream bitmask.Byte = 0x01
// RequestOptionConnectionReuse indicates client side expects to reuse the connection.
RequestOptionConnectionReuse bitmask.Byte = 0x02
RequestOptionChunkMasking bitmask.Byte = 0x04
RequestOptionGlobalPadding bitmask.Byte = 0x08
)
type RequestHeader struct {
Version byte
Command RequestCommand
Option bitmask.Byte
Security SecurityType
Port net.Port
Address net.Address
User *MemoryUser
}
func (h *RequestHeader) Destination() net.Destination {
if h.Command == RequestCommandUDP {
return net.UDPDestination(h.Address, h.Port)
}
return net.TCPDestination(h.Address, h.Port)
}
const (
ResponseOptionConnectionReuse bitmask.Byte = 0x01
)
type ResponseCommand interface{}
type ResponseHeader struct {
Option bitmask.Byte
Command ResponseCommand
}
type CommandSwitchAccount struct {
Host net.Address
Port net.Port
ID uuid.UUID
Level uint32
AlterIds uint16
ValidMin byte
}
func (sc *SecurityConfig) GetSecurityType() SecurityType {
if sc == nil || sc.Type == SecurityType_AUTO {
if runtime.GOARCH == "amd64" || runtime.GOARCH == "s390x" || runtime.GOARCH == "arm64" {
return SecurityType_AES128_GCM
}
return SecurityType_CHACHA20_POLY1305
}
return sc.Type
}
func isDomainTooLong(domain string) bool {
return len(domain) > 256
}
v2ray-core-4.34.0/common/protocol/headers.pb.go 0000664 0000000 0000000 00000020043 13774574720 0021305 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: common/protocol/headers.proto
package protocol
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type SecurityType int32
const (
SecurityType_UNKNOWN SecurityType = 0
SecurityType_LEGACY SecurityType = 1
SecurityType_AUTO SecurityType = 2
SecurityType_AES128_GCM SecurityType = 3
SecurityType_CHACHA20_POLY1305 SecurityType = 4
SecurityType_NONE SecurityType = 5
)
// Enum value maps for SecurityType.
var (
SecurityType_name = map[int32]string{
0: "UNKNOWN",
1: "LEGACY",
2: "AUTO",
3: "AES128_GCM",
4: "CHACHA20_POLY1305",
5: "NONE",
}
SecurityType_value = map[string]int32{
"UNKNOWN": 0,
"LEGACY": 1,
"AUTO": 2,
"AES128_GCM": 3,
"CHACHA20_POLY1305": 4,
"NONE": 5,
}
)
func (x SecurityType) Enum() *SecurityType {
p := new(SecurityType)
*p = x
return p
}
func (x SecurityType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (SecurityType) Descriptor() protoreflect.EnumDescriptor {
return file_common_protocol_headers_proto_enumTypes[0].Descriptor()
}
func (SecurityType) Type() protoreflect.EnumType {
return &file_common_protocol_headers_proto_enumTypes[0]
}
func (x SecurityType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use SecurityType.Descriptor instead.
func (SecurityType) EnumDescriptor() ([]byte, []int) {
return file_common_protocol_headers_proto_rawDescGZIP(), []int{0}
}
type SecurityConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type SecurityType `protobuf:"varint,1,opt,name=type,proto3,enum=v2ray.core.common.protocol.SecurityType" json:"type,omitempty"`
}
func (x *SecurityConfig) Reset() {
*x = SecurityConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_common_protocol_headers_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SecurityConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SecurityConfig) ProtoMessage() {}
func (x *SecurityConfig) ProtoReflect() protoreflect.Message {
mi := &file_common_protocol_headers_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SecurityConfig.ProtoReflect.Descriptor instead.
func (*SecurityConfig) Descriptor() ([]byte, []int) {
return file_common_protocol_headers_proto_rawDescGZIP(), []int{0}
}
func (x *SecurityConfig) GetType() SecurityType {
if x != nil {
return x.Type
}
return SecurityType_UNKNOWN
}
var File_common_protocol_headers_proto protoreflect.FileDescriptor
var file_common_protocol_headers_proto_rawDesc = []byte{
0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22, 0x4e, 0x0a, 0x0e, 0x53,
0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a,
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 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, 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,
0x5f, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x50, 0x01, 0x5a, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,
0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65,
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 (
file_common_protocol_headers_proto_rawDescOnce sync.Once
file_common_protocol_headers_proto_rawDescData = file_common_protocol_headers_proto_rawDesc
)
func file_common_protocol_headers_proto_rawDescGZIP() []byte {
file_common_protocol_headers_proto_rawDescOnce.Do(func() {
file_common_protocol_headers_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_protocol_headers_proto_rawDescData)
})
return file_common_protocol_headers_proto_rawDescData
}
var file_common_protocol_headers_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_common_protocol_headers_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_common_protocol_headers_proto_goTypes = []interface{}{
(SecurityType)(0), // 0: v2ray.core.common.protocol.SecurityType
(*SecurityConfig)(nil), // 1: v2ray.core.common.protocol.SecurityConfig
}
var file_common_protocol_headers_proto_depIdxs = []int32{
0, // 0: v2ray.core.common.protocol.SecurityConfig.type:type_name -> v2ray.core.common.protocol.SecurityType
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_common_protocol_headers_proto_init() }
func file_common_protocol_headers_proto_init() {
if File_common_protocol_headers_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_protocol_headers_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SecurityConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_protocol_headers_proto_rawDesc,
NumEnums: 1,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_protocol_headers_proto_goTypes,
DependencyIndexes: file_common_protocol_headers_proto_depIdxs,
EnumInfos: file_common_protocol_headers_proto_enumTypes,
MessageInfos: file_common_protocol_headers_proto_msgTypes,
}.Build()
File_common_protocol_headers_proto = out.File
file_common_protocol_headers_proto_rawDesc = nil
file_common_protocol_headers_proto_goTypes = nil
file_common_protocol_headers_proto_depIdxs = nil
}
v2ray-core-4.34.0/common/protocol/headers.proto 0000664 0000000 0000000 00000000655 13774574720 0021452 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.common.protocol;
option csharp_namespace = "V2Ray.Core.Common.Protocol";
option go_package = "v2ray.com/core/common/protocol";
option java_package = "com.v2ray.core.common.protocol";
option java_multiple_files = true;
enum SecurityType {
UNKNOWN = 0;
LEGACY = 1;
AUTO = 2;
AES128_GCM = 3;
CHACHA20_POLY1305 = 4;
NONE = 5;
}
message SecurityConfig {
SecurityType type = 1;
}
v2ray-core-4.34.0/common/protocol/http/ 0000775 0000000 0000000 00000000000 13774574720 0017723 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/protocol/http/headers.go 0000664 0000000 0000000 00000003511 13774574720 0021665 0 ustar 00root root 0000000 0000000 package http
import (
"net/http"
"strconv"
"strings"
"v2ray.com/core/common/net"
)
// ParseXForwardedFor parses X-Forwarded-For header in http headers, and return the IP list in it.
func ParseXForwardedFor(header http.Header) []net.Address {
xff := header.Get("X-Forwarded-For")
if xff == "" {
return nil
}
list := strings.Split(xff, ",")
addrs := make([]net.Address, 0, len(list))
for _, proxy := range list {
addrs = append(addrs, net.ParseAddress(proxy))
}
return addrs
}
// RemoveHopByHopHeaders remove hop by hop headers in http header list.
func RemoveHopByHopHeaders(header http.Header) {
// Strip hop-by-hop header based on RFC:
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
// https://www.mnot.net/blog/2011/07/11/what_proxies_must_do
header.Del("Proxy-Connection")
header.Del("Proxy-Authenticate")
header.Del("Proxy-Authorization")
header.Del("TE")
header.Del("Trailers")
header.Del("Transfer-Encoding")
header.Del("Upgrade")
connections := header.Get("Connection")
header.Del("Connection")
if connections == "" {
return
}
for _, h := range strings.Split(connections, ",") {
header.Del(strings.TrimSpace(h))
}
}
// ParseHost splits host and port from a raw string. Default port is used when raw string doesn't contain port.
func ParseHost(rawHost string, defaultPort net.Port) (net.Destination, error) {
port := defaultPort
host, rawPort, err := net.SplitHostPort(rawHost)
if err != nil {
if addrError, ok := err.(*net.AddrError); ok && strings.Contains(addrError.Err, "missing port") {
host = rawHost
} else {
return net.Destination{}, err
}
} else if len(rawPort) > 0 {
intPort, err := strconv.ParseUint(rawPort, 0, 16)
if err != nil {
return net.Destination{}, err
}
port = net.Port(intPort)
}
return net.TCPDestination(net.ParseAddress(host), port), nil
}
v2ray-core-4.34.0/common/protocol/http/headers_test.go 0000664 0000000 0000000 00000005245 13774574720 0022732 0 ustar 00root root 0000000 0000000 package http_test
import (
"bufio"
"net/http"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
. "v2ray.com/core/common/protocol/http"
)
func TestParseXForwardedFor(t *testing.T) {
header := http.Header{}
header.Add("X-Forwarded-For", "129.78.138.66, 129.78.64.103")
addrs := ParseXForwardedFor(header)
if r := cmp.Diff(addrs, []net.Address{net.ParseAddress("129.78.138.66"), net.ParseAddress("129.78.64.103")}); r != "" {
t.Error(r)
}
}
func TestHopByHopHeadersRemoving(t *testing.T) {
rawRequest := `GET /pkg/net/http/ HTTP/1.1
Host: golang.org
Connection: keep-alive,Foo, Bar
Foo: foo
Bar: bar
Proxy-Connection: keep-alive
Proxy-Authenticate: abc
Accept-Encoding: gzip
Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7
Cache-Control: no-cache
Accept-Language: de,en;q=0.7,en-us;q=0.3
`
b := bufio.NewReader(strings.NewReader(rawRequest))
req, err := http.ReadRequest(b)
common.Must(err)
headers := []struct {
Key string
Value string
}{
{
Key: "Foo",
Value: "foo",
},
{
Key: "Bar",
Value: "bar",
},
{
Key: "Connection",
Value: "keep-alive,Foo, Bar",
},
{
Key: "Proxy-Connection",
Value: "keep-alive",
},
{
Key: "Proxy-Authenticate",
Value: "abc",
},
}
for _, header := range headers {
if v := req.Header.Get(header.Key); v != header.Value {
t.Error("header ", header.Key, " = ", v, " want ", header.Value)
}
}
RemoveHopByHopHeaders(req.Header)
for _, header := range []string{"Connection", "Foo", "Bar", "Proxy-Connection", "Proxy-Authenticate"} {
if v := req.Header.Get(header); v != "" {
t.Error("header ", header, " = ", v)
}
}
}
func TestParseHost(t *testing.T) {
testCases := []struct {
RawHost string
DefaultPort net.Port
Destination net.Destination
Error bool
}{
{
RawHost: "v2ray.com:80",
DefaultPort: 443,
Destination: net.TCPDestination(net.DomainAddress("v2ray.com"), 80),
},
{
RawHost: "tls.v2ray.com",
DefaultPort: 443,
Destination: net.TCPDestination(net.DomainAddress("tls.v2ray.com"), 443),
},
{
RawHost: "[2401:1bc0:51f0:ec08::1]:80",
DefaultPort: 443,
Destination: net.TCPDestination(net.ParseAddress("[2401:1bc0:51f0:ec08::1]"), 80),
},
}
for _, testCase := range testCases {
dest, err := ParseHost(testCase.RawHost, testCase.DefaultPort)
if testCase.Error {
if err == nil {
t.Error("for test case: ", testCase.RawHost, " expected error, but actually nil")
}
} else {
if dest != testCase.Destination {
t.Error("for test case: ", testCase.RawHost, " expected host: ", testCase.Destination.String(), " but got ", dest.String())
}
}
}
}
v2ray-core-4.34.0/common/protocol/http/sniff.go 0000664 0000000 0000000 00000003041 13774574720 0021355 0 ustar 00root root 0000000 0000000 package http
import (
"bytes"
"errors"
"strings"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
)
type version byte
const (
HTTP1 version = iota
HTTP2
)
type SniffHeader struct {
version version
host string
}
func (h *SniffHeader) Protocol() string {
switch h.version {
case HTTP1:
return "http1"
case HTTP2:
return "http2"
default:
return "unknown"
}
}
func (h *SniffHeader) Domain() string {
return h.host
}
var (
methods = [...]string{"get", "post", "head", "put", "delete", "options", "connect"}
errNotHTTPMethod = errors.New("not an HTTP method")
)
func beginWithHTTPMethod(b []byte) error {
for _, m := range &methods {
if len(b) >= len(m) && strings.EqualFold(string(b[:len(m)]), m) {
return nil
}
if len(b) < len(m) {
return common.ErrNoClue
}
}
return errNotHTTPMethod
}
func SniffHTTP(b []byte) (*SniffHeader, error) {
if err := beginWithHTTPMethod(b); err != nil {
return nil, err
}
sh := &SniffHeader{
version: HTTP1,
}
headers := bytes.Split(b, []byte{'\n'})
for i := 1; i < len(headers); i++ {
header := headers[i]
if len(header) == 0 {
break
}
parts := bytes.SplitN(header, []byte{':'}, 2)
if len(parts) != 2 {
continue
}
key := strings.ToLower(string(parts[0]))
if key == "host" {
rawHost := strings.ToLower(string(bytes.TrimSpace(parts[1])))
dest, err := ParseHost(rawHost, net.Port(80))
if err != nil {
return nil, err
}
sh.host = dest.Address.String()
}
}
if len(sh.host) > 0 {
return sh, nil
}
return nil, common.ErrNoClue
}
v2ray-core-4.34.0/common/protocol/http/sniff_test.go 0000664 0000000 0000000 00000005717 13774574720 0022430 0 ustar 00root root 0000000 0000000 package http_test
import (
"testing"
. "v2ray.com/core/common/protocol/http"
)
func TestHTTPHeaders(t *testing.T) {
cases := []struct {
input string
domain string
err bool
}{
{
input: `GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1
Host: net.tutsplus.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120
Pragma: no-cache
Cache-Control: no-cache`,
domain: "net.tutsplus.com",
},
{
input: `POST /foo.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost/test.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
first_name=John&last_name=Doe&action=Submit`,
domain: "localhost",
},
{
input: `X /foo.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost/test.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
first_name=John&last_name=Doe&action=Submit`,
domain: "",
err: true,
},
{
input: `GET /foo.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost/test.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
Host: localhost
first_name=John&last_name=Doe&action=Submit`,
domain: "",
err: true,
},
{
input: `GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1`,
domain: "",
err: true,
},
}
for _, test := range cases {
header, err := SniffHTTP([]byte(test.input))
if test.err {
if err == nil {
t.Errorf("Expect error but nil, in test: %v", test)
}
} else {
if err != nil {
t.Errorf("Expect no error but actually %s in test %v", err.Error(), test)
}
if header.Domain() != test.domain {
t.Error("expected domain ", test.domain, " but got ", header.Domain())
}
}
}
}
v2ray-core-4.34.0/common/protocol/id.go 0000664 0000000 0000000 00000003142 13774574720 0017667 0 ustar 00root root 0000000 0000000 package protocol
import (
"crypto/hmac"
"crypto/md5"
"hash"
"v2ray.com/core/common"
"v2ray.com/core/common/uuid"
)
const (
IDBytesLen = 16
)
type IDHash func(key []byte) hash.Hash
func DefaultIDHash(key []byte) hash.Hash {
return hmac.New(md5.New, key)
}
// The ID of en entity, in the form of a UUID.
type ID struct {
uuid uuid.UUID
cmdKey [IDBytesLen]byte
}
// Equals returns true if this ID equals to the other one.
func (id *ID) Equals(another *ID) bool {
return id.uuid.Equals(&(another.uuid))
}
func (id *ID) Bytes() []byte {
return id.uuid.Bytes()
}
func (id *ID) String() string {
return id.uuid.String()
}
func (id *ID) UUID() uuid.UUID {
return id.uuid
}
func (id ID) CmdKey() []byte {
return id.cmdKey[:]
}
// NewID returns an ID with given UUID.
func NewID(uuid uuid.UUID) *ID {
id := &ID{uuid: uuid}
md5hash := md5.New()
common.Must2(md5hash.Write(uuid.Bytes()))
common.Must2(md5hash.Write([]byte("c48619fe-8f02-49e0-b9e9-edf763e17e21")))
md5hash.Sum(id.cmdKey[:0])
return id
}
func nextID(u *uuid.UUID) uuid.UUID {
md5hash := md5.New()
common.Must2(md5hash.Write(u.Bytes()))
common.Must2(md5hash.Write([]byte("16167dc8-16b6-4e6d-b8bb-65dd68113a81")))
var newid uuid.UUID
for {
md5hash.Sum(newid[:0])
if !newid.Equals(u) {
return newid
}
common.Must2(md5hash.Write([]byte("533eff8a-4113-4b10-b5ce-0f5d76b98cd2")))
}
}
func NewAlterIDs(primary *ID, alterIDCount uint16) []*ID {
alterIDs := make([]*ID, alterIDCount)
prevID := primary.UUID()
for idx := range alterIDs {
newid := nextID(&prevID)
alterIDs[idx] = NewID(newid)
prevID = newid
}
return alterIDs
}
v2ray-core-4.34.0/common/protocol/id_test.go 0000664 0000000 0000000 00000000562 13774574720 0020731 0 ustar 00root root 0000000 0000000 package protocol_test
import (
"testing"
. "v2ray.com/core/common/protocol"
"v2ray.com/core/common/uuid"
)
func TestIdEquals(t *testing.T) {
id1 := NewID(uuid.New())
id2 := NewID(id1.UUID())
if !id1.Equals(id2) {
t.Error("expected id1 to equal id2, but actually not")
}
if id1.String() != id2.String() {
t.Error(id1.String(), " != ", id2.String())
}
}
v2ray-core-4.34.0/common/protocol/payload.go 0000664 0000000 0000000 00000000411 13774574720 0020720 0 ustar 00root root 0000000 0000000 package protocol
type TransferType byte
const (
TransferTypeStream TransferType = 0
TransferTypePacket TransferType = 1
)
type AddressType byte
const (
AddressTypeIPv4 AddressType = 1
AddressTypeDomain AddressType = 2
AddressTypeIPv6 AddressType = 3
)
v2ray-core-4.34.0/common/protocol/protocol.go 0000664 0000000 0000000 00000000170 13774574720 0021132 0 ustar 00root root 0000000 0000000 package protocol // import "v2ray.com/core/common/protocol"
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/common/protocol/server_picker.go 0000664 0000000 0000000 00000002637 13774574720 0022146 0 ustar 00root root 0000000 0000000 package protocol
import (
"sync"
)
type ServerList struct {
sync.RWMutex
servers []*ServerSpec
}
func NewServerList() *ServerList {
return &ServerList{}
}
func (sl *ServerList) AddServer(server *ServerSpec) {
sl.Lock()
defer sl.Unlock()
sl.servers = append(sl.servers, server)
}
func (sl *ServerList) Size() uint32 {
sl.RLock()
defer sl.RUnlock()
return uint32(len(sl.servers))
}
func (sl *ServerList) GetServer(idx uint32) *ServerSpec {
sl.Lock()
defer sl.Unlock()
for {
if idx >= uint32(len(sl.servers)) {
return nil
}
server := sl.servers[idx]
if !server.IsValid() {
sl.removeServer(idx)
continue
}
return server
}
}
func (sl *ServerList) removeServer(idx uint32) {
n := len(sl.servers)
sl.servers[idx] = sl.servers[n-1]
sl.servers = sl.servers[:n-1]
}
type ServerPicker interface {
PickServer() *ServerSpec
}
type RoundRobinServerPicker struct {
sync.Mutex
serverlist *ServerList
nextIndex uint32
}
func NewRoundRobinServerPicker(serverlist *ServerList) *RoundRobinServerPicker {
return &RoundRobinServerPicker{
serverlist: serverlist,
nextIndex: 0,
}
}
func (p *RoundRobinServerPicker) PickServer() *ServerSpec {
p.Lock()
defer p.Unlock()
next := p.nextIndex
server := p.serverlist.GetServer(next)
if server == nil {
next = 0
server = p.serverlist.GetServer(0)
}
next++
if next >= p.serverlist.Size() {
next = 0
}
p.nextIndex = next
return server
}
v2ray-core-4.34.0/common/protocol/server_picker_test.go 0000664 0000000 0000000 00000003757 13774574720 0023211 0 ustar 00root root 0000000 0000000 package protocol_test
import (
"testing"
"time"
"v2ray.com/core/common/net"
. "v2ray.com/core/common/protocol"
)
func TestServerList(t *testing.T) {
list := NewServerList()
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(1)), AlwaysValid()))
if list.Size() != 1 {
t.Error("list size: ", list.Size())
}
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(2)), BeforeTime(time.Now().Add(time.Second))))
if list.Size() != 2 {
t.Error("list.size: ", list.Size())
}
server := list.GetServer(1)
if server.Destination().Port != 2 {
t.Error("server: ", server.Destination())
}
time.Sleep(2 * time.Second)
server = list.GetServer(1)
if server != nil {
t.Error("server: ", server)
}
server = list.GetServer(0)
if server.Destination().Port != 1 {
t.Error("server: ", server.Destination())
}
}
func TestServerPicker(t *testing.T) {
list := NewServerList()
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(1)), AlwaysValid()))
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(2)), BeforeTime(time.Now().Add(time.Second))))
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(3)), BeforeTime(time.Now().Add(time.Second))))
picker := NewRoundRobinServerPicker(list)
server := picker.PickServer()
if server.Destination().Port != 1 {
t.Error("server: ", server.Destination())
}
server = picker.PickServer()
if server.Destination().Port != 2 {
t.Error("server: ", server.Destination())
}
server = picker.PickServer()
if server.Destination().Port != 3 {
t.Error("server: ", server.Destination())
}
server = picker.PickServer()
if server.Destination().Port != 1 {
t.Error("server: ", server.Destination())
}
time.Sleep(2 * time.Second)
server = picker.PickServer()
if server.Destination().Port != 1 {
t.Error("server: ", server.Destination())
}
server = picker.PickServer()
if server.Destination().Port != 1 {
t.Error("server: ", server.Destination())
}
}
v2ray-core-4.34.0/common/protocol/server_spec.go 0000664 0000000 0000000 00000004135 13774574720 0021616 0 ustar 00root root 0000000 0000000 package protocol
import (
"sync"
"time"
"v2ray.com/core/common/dice"
"v2ray.com/core/common/net"
)
type ValidationStrategy interface {
IsValid() bool
Invalidate()
}
type alwaysValidStrategy struct{}
func AlwaysValid() ValidationStrategy {
return alwaysValidStrategy{}
}
func (alwaysValidStrategy) IsValid() bool {
return true
}
func (alwaysValidStrategy) Invalidate() {}
type timeoutValidStrategy struct {
until time.Time
}
func BeforeTime(t time.Time) ValidationStrategy {
return &timeoutValidStrategy{
until: t,
}
}
func (s *timeoutValidStrategy) IsValid() bool {
return s.until.After(time.Now())
}
func (s *timeoutValidStrategy) Invalidate() {
s.until = time.Time{}
}
type ServerSpec struct {
sync.RWMutex
dest net.Destination
users []*MemoryUser
valid ValidationStrategy
}
func NewServerSpec(dest net.Destination, valid ValidationStrategy, users ...*MemoryUser) *ServerSpec {
return &ServerSpec{
dest: dest,
users: users,
valid: valid,
}
}
func NewServerSpecFromPB(spec *ServerEndpoint) (*ServerSpec, error) {
dest := net.TCPDestination(spec.Address.AsAddress(), net.Port(spec.Port))
mUsers := make([]*MemoryUser, len(spec.User))
for idx, u := range spec.User {
mUser, err := u.ToMemoryUser()
if err != nil {
return nil, err
}
mUsers[idx] = mUser
}
return NewServerSpec(dest, AlwaysValid(), mUsers...), nil
}
func (s *ServerSpec) Destination() net.Destination {
return s.dest
}
func (s *ServerSpec) HasUser(user *MemoryUser) bool {
s.RLock()
defer s.RUnlock()
for _, u := range s.users {
if u.Account.Equals(user.Account) {
return true
}
}
return false
}
func (s *ServerSpec) AddUser(user *MemoryUser) {
if s.HasUser(user) {
return
}
s.Lock()
defer s.Unlock()
s.users = append(s.users, user)
}
func (s *ServerSpec) PickUser() *MemoryUser {
s.RLock()
defer s.RUnlock()
userCount := len(s.users)
switch userCount {
case 0:
return nil
case 1:
return s.users[0]
default:
return s.users[dice.Roll(userCount)]
}
}
func (s *ServerSpec) IsValid() bool {
return s.valid.IsValid()
}
func (s *ServerSpec) Invalidate() {
s.valid.Invalidate()
}
v2ray-core-4.34.0/common/protocol/server_spec.pb.go 0000664 0000000 0000000 00000016503 13774574720 0022220 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: common/protocol/server_spec.proto
package protocol
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
net "v2ray.com/core/common/net"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type ServerEndpoint struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
User []*User `protobuf:"bytes,3,rep,name=user,proto3" json:"user,omitempty"`
}
func (x *ServerEndpoint) Reset() {
*x = ServerEndpoint{}
if protoimpl.UnsafeEnabled {
mi := &file_common_protocol_server_spec_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServerEndpoint) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServerEndpoint) ProtoMessage() {}
func (x *ServerEndpoint) ProtoReflect() protoreflect.Message {
mi := &file_common_protocol_server_spec_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServerEndpoint.ProtoReflect.Descriptor instead.
func (*ServerEndpoint) Descriptor() ([]byte, []int) {
return file_common_protocol_server_spec_proto_rawDescGZIP(), []int{0}
}
func (x *ServerEndpoint) GetAddress() *net.IPOrDomain {
if x != nil {
return x.Address
}
return nil
}
func (x *ServerEndpoint) GetPort() uint32 {
if x != nil {
return x.Port
}
return 0
}
func (x *ServerEndpoint) GetUser() []*User {
if x != nil {
return x.User
}
return nil
}
var File_common_protocol_server_spec_proto protoreflect.FileDescriptor
var file_common_protocol_server_spec_proto_rawDesc = []byte{
0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x1a,
0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x97, 0x01, 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x07, 0x61, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x34, 0x0a, 0x04, 0x75, 0x73, 0x65,
0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x42,
0x5f, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x50, 0x01, 0x5a, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,
0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65,
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 (
file_common_protocol_server_spec_proto_rawDescOnce sync.Once
file_common_protocol_server_spec_proto_rawDescData = file_common_protocol_server_spec_proto_rawDesc
)
func file_common_protocol_server_spec_proto_rawDescGZIP() []byte {
file_common_protocol_server_spec_proto_rawDescOnce.Do(func() {
file_common_protocol_server_spec_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_protocol_server_spec_proto_rawDescData)
})
return file_common_protocol_server_spec_proto_rawDescData
}
var file_common_protocol_server_spec_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_common_protocol_server_spec_proto_goTypes = []interface{}{
(*ServerEndpoint)(nil), // 0: v2ray.core.common.protocol.ServerEndpoint
(*net.IPOrDomain)(nil), // 1: v2ray.core.common.net.IPOrDomain
(*User)(nil), // 2: v2ray.core.common.protocol.User
}
var file_common_protocol_server_spec_proto_depIdxs = []int32{
1, // 0: v2ray.core.common.protocol.ServerEndpoint.address:type_name -> v2ray.core.common.net.IPOrDomain
2, // 1: v2ray.core.common.protocol.ServerEndpoint.user:type_name -> v2ray.core.common.protocol.User
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_common_protocol_server_spec_proto_init() }
func file_common_protocol_server_spec_proto_init() {
if File_common_protocol_server_spec_proto != nil {
return
}
file_common_protocol_user_proto_init()
if !protoimpl.UnsafeEnabled {
file_common_protocol_server_spec_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ServerEndpoint); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_protocol_server_spec_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_protocol_server_spec_proto_goTypes,
DependencyIndexes: file_common_protocol_server_spec_proto_depIdxs,
MessageInfos: file_common_protocol_server_spec_proto_msgTypes,
}.Build()
File_common_protocol_server_spec_proto = out.File
file_common_protocol_server_spec_proto_rawDesc = nil
file_common_protocol_server_spec_proto_goTypes = nil
file_common_protocol_server_spec_proto_depIdxs = nil
}
v2ray-core-4.34.0/common/protocol/server_spec.proto 0000664 0000000 0000000 00000000736 13774574720 0022357 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.common.protocol;
option csharp_namespace = "V2Ray.Core.Common.Protocol";
option go_package = "v2ray.com/core/common/protocol";
option java_package = "com.v2ray.core.common.protocol";
option java_multiple_files = true;
import "common/net/address.proto";
import "common/protocol/user.proto";
message ServerEndpoint {
v2ray.core.common.net.IPOrDomain address = 1;
uint32 port = 2;
repeated v2ray.core.common.protocol.User user = 3;
}
v2ray-core-4.34.0/common/protocol/server_spec_test.go 0000664 0000000 0000000 00000003552 13774574720 0022657 0 ustar 00root root 0000000 0000000 package protocol_test
import (
"strings"
"testing"
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
. "v2ray.com/core/common/protocol"
"v2ray.com/core/common/uuid"
"v2ray.com/core/proxy/vmess"
)
func TestAlwaysValidStrategy(t *testing.T) {
strategy := AlwaysValid()
if !strategy.IsValid() {
t.Error("strategy not valid")
}
strategy.Invalidate()
if !strategy.IsValid() {
t.Error("strategy not valid")
}
}
func TestTimeoutValidStrategy(t *testing.T) {
strategy := BeforeTime(time.Now().Add(2 * time.Second))
if !strategy.IsValid() {
t.Error("strategy not valid")
}
time.Sleep(3 * time.Second)
if strategy.IsValid() {
t.Error("strategy is valid")
}
strategy = BeforeTime(time.Now().Add(2 * time.Second))
strategy.Invalidate()
if strategy.IsValid() {
t.Error("strategy is valid")
}
}
func TestUserInServerSpec(t *testing.T) {
uuid1 := uuid.New()
uuid2 := uuid.New()
toAccount := func(a *vmess.Account) Account {
account, err := a.AsAccount()
common.Must(err)
return account
}
spec := NewServerSpec(net.Destination{}, AlwaysValid(), &MemoryUser{
Email: "test1@v2ray.com",
Account: toAccount(&vmess.Account{Id: uuid1.String()}),
})
if spec.HasUser(&MemoryUser{
Email: "test1@v2ray.com",
Account: toAccount(&vmess.Account{Id: uuid2.String()}),
}) {
t.Error("has user: ", uuid2)
}
spec.AddUser(&MemoryUser{Email: "test2@v2ray.com"})
if !spec.HasUser(&MemoryUser{
Email: "test1@v2ray.com",
Account: toAccount(&vmess.Account{Id: uuid1.String()}),
}) {
t.Error("not having user: ", uuid1)
}
}
func TestPickUser(t *testing.T) {
spec := NewServerSpec(net.Destination{}, AlwaysValid(), &MemoryUser{Email: "test1@v2ray.com"}, &MemoryUser{Email: "test2@v2ray.com"}, &MemoryUser{Email: "test3@v2ray.com"})
user := spec.PickUser()
if !strings.HasSuffix(user.Email, "@v2ray.com") {
t.Error("user: ", user.Email)
}
}
v2ray-core-4.34.0/common/protocol/time.go 0000664 0000000 0000000 00000000610 13774574720 0020226 0 ustar 00root root 0000000 0000000 package protocol
import (
"time"
"v2ray.com/core/common/dice"
)
type Timestamp int64
type TimestampGenerator func() Timestamp
func NowTime() Timestamp {
return Timestamp(time.Now().Unix())
}
func NewTimestampGenerator(base Timestamp, delta int) TimestampGenerator {
return func() Timestamp {
rangeInDelta := dice.Roll(delta*2) - delta
return base + Timestamp(rangeInDelta)
}
}
v2ray-core-4.34.0/common/protocol/time_test.go 0000664 0000000 0000000 00000000700 13774574720 0021265 0 ustar 00root root 0000000 0000000 package protocol_test
import (
"testing"
"time"
. "v2ray.com/core/common/protocol"
)
func TestGenerateRandomInt64InRange(t *testing.T) {
base := time.Now().Unix()
delta := 100
generator := NewTimestampGenerator(Timestamp(base), delta)
for i := 0; i < 100; i++ {
val := int64(generator())
if val > base+int64(delta) || val < base-int64(delta) {
t.Error(val, " not between ", base-int64(delta), " and ", base+int64(delta))
}
}
}
v2ray-core-4.34.0/common/protocol/tls/ 0000775 0000000 0000000 00000000000 13774574720 0017546 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/protocol/tls/cert/ 0000775 0000000 0000000 00000000000 13774574720 0020503 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/protocol/tls/cert/.gitignore 0000664 0000000 0000000 00000000005 13774574720 0022466 0 ustar 00root root 0000000 0000000 *.pem v2ray-core-4.34.0/common/protocol/tls/cert/cert.go 0000664 0000000 0000000 00000010452 13774574720 0021771 0 ustar 00root root 0000000 0000000 package cert
import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"math/big"
"time"
"v2ray.com/core/common"
)
//go:generate go run v2ray.com/core/common/errors/errorgen
type Certificate struct {
// Cerificate in ASN.1 DER format
Certificate []byte
// Private key in ASN.1 DER format
PrivateKey []byte
}
func ParseCertificate(certPEM []byte, keyPEM []byte) (*Certificate, error) {
certBlock, _ := pem.Decode(certPEM)
if certBlock == nil {
return nil, newError("failed to decode certificate")
}
keyBlock, _ := pem.Decode(keyPEM)
if keyBlock == nil {
return nil, newError("failed to decode key")
}
return &Certificate{
Certificate: certBlock.Bytes,
PrivateKey: keyBlock.Bytes,
}, nil
}
func (c *Certificate) ToPEM() ([]byte, []byte) {
return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: c.Certificate}),
pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: c.PrivateKey})
}
type Option func(*x509.Certificate)
func Authority(isCA bool) Option {
return func(cert *x509.Certificate) {
cert.IsCA = isCA
}
}
func NotBefore(t time.Time) Option {
return func(c *x509.Certificate) {
c.NotBefore = t
}
}
func NotAfter(t time.Time) Option {
return func(c *x509.Certificate) {
c.NotAfter = t
}
}
func DNSNames(names ...string) Option {
return func(c *x509.Certificate) {
c.DNSNames = names
}
}
func CommonName(name string) Option {
return func(c *x509.Certificate) {
c.Subject.CommonName = name
}
}
func KeyUsage(usage x509.KeyUsage) Option {
return func(c *x509.Certificate) {
c.KeyUsage = usage
}
}
func Organization(org string) Option {
return func(c *x509.Certificate) {
c.Subject.Organization = []string{org}
}
}
func MustGenerate(parent *Certificate, opts ...Option) *Certificate {
cert, err := Generate(parent, opts...)
common.Must(err)
return cert
}
func publicKey(priv interface{}) interface{} {
switch k := priv.(type) {
case *rsa.PrivateKey:
return &k.PublicKey
case *ecdsa.PrivateKey:
return &k.PublicKey
case ed25519.PrivateKey:
return k.Public().(ed25519.PublicKey)
default:
return nil
}
}
func Generate(parent *Certificate, opts ...Option) (*Certificate, error) {
var (
pKey interface{}
parentKey interface{}
err error
)
// higher signing performance than RSA2048
selfKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, newError("failed to generate self private key").Base(err)
}
parentKey = selfKey
if parent != nil {
if _, e := asn1.Unmarshal(parent.PrivateKey, &ecPrivateKey{}); e == nil {
pKey, err = x509.ParseECPrivateKey(parent.PrivateKey)
} else if _, e := asn1.Unmarshal(parent.PrivateKey, &pkcs8{}); e == nil {
pKey, err = x509.ParsePKCS8PrivateKey(parent.PrivateKey)
} else if _, e := asn1.Unmarshal(parent.PrivateKey, &pkcs1PrivateKey{}); e == nil {
pKey, err = x509.ParsePKCS1PrivateKey(parent.PrivateKey)
}
if err != nil {
return nil, newError("failed to parse parent private key").Base(err)
}
parentKey = pKey
}
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, newError("failed to generate serial number").Base(err)
}
template := &x509.Certificate{
SerialNumber: serialNumber,
NotBefore: time.Now().Add(time.Hour * -1),
NotAfter: time.Now().Add(time.Hour),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
for _, opt := range opts {
opt(template)
}
parentCert := template
if parent != nil {
pCert, err := x509.ParseCertificate(parent.Certificate)
if err != nil {
return nil, newError("failed to parse parent certificate").Base(err)
}
parentCert = pCert
}
derBytes, err := x509.CreateCertificate(rand.Reader, template, parentCert, publicKey(selfKey), parentKey)
if err != nil {
return nil, newError("failed to create certificate").Base(err)
}
privateKey, err := x509.MarshalPKCS8PrivateKey(selfKey)
if err != nil {
return nil, newError("Unable to marshal private key").Base(err)
}
return &Certificate{
Certificate: derBytes,
PrivateKey: privateKey,
}, nil
}
v2ray-core-4.34.0/common/protocol/tls/cert/cert_test.go 0000664 0000000 0000000 00000004027 13774574720 0023031 0 ustar 00root root 0000000 0000000 package cert
import (
"context"
"crypto/x509"
"encoding/json"
"os"
"strings"
"testing"
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/task"
)
func TestGenerate(t *testing.T) {
err := generate(nil, true, true, "ca")
if err != nil {
t.Fatal(err)
}
}
func generate(domainNames []string, isCA bool, jsonOutput bool, fileOutput string) error {
commonName := "V2Ray Root CA"
organization := "V2Ray Inc"
expire := time.Hour * 3
var opts []Option
if isCA {
opts = append(opts, Authority(isCA))
opts = append(opts, KeyUsage(x509.KeyUsageCertSign|x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature))
}
opts = append(opts, NotAfter(time.Now().Add(expire)))
opts = append(opts, CommonName(commonName))
if len(domainNames) > 0 {
opts = append(opts, DNSNames(domainNames...))
}
opts = append(opts, Organization(organization))
cert, err := Generate(nil, opts...)
if err != nil {
return newError("failed to generate TLS certificate").Base(err)
}
if jsonOutput {
printJSON(cert)
}
if len(fileOutput) > 0 {
if err := printFile(cert, fileOutput); err != nil {
return err
}
}
return nil
}
type jsonCert struct {
Certificate []string `json:"certificate"`
Key []string `json:"key"`
}
func printJSON(certificate *Certificate) {
certPEM, keyPEM := certificate.ToPEM()
jCert := &jsonCert{
Certificate: strings.Split(strings.TrimSpace(string(certPEM)), "\n"),
Key: strings.Split(strings.TrimSpace(string(keyPEM)), "\n"),
}
content, err := json.MarshalIndent(jCert, "", " ")
common.Must(err)
os.Stdout.Write(content)
os.Stdout.WriteString("\n")
}
func printFile(certificate *Certificate, name string) error {
certPEM, keyPEM := certificate.ToPEM()
return task.Run(context.Background(), func() error {
return writeFile(certPEM, name+"_cert.pem")
}, func() error {
return writeFile(keyPEM, name+"_key.pem")
})
}
func writeFile(content []byte, name string) error {
f, err := os.Create(name)
if err != nil {
return err
}
defer f.Close()
return common.Error2(f.Write(content))
}
v2ray-core-4.34.0/common/protocol/tls/cert/errors.generated.go 0000664 0000000 0000000 00000000312 13774574720 0024277 0 ustar 00root root 0000000 0000000 package cert
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/common/protocol/tls/cert/privateKey.go 0000664 0000000 0000000 00000001653 13774574720 0023162 0 ustar 00root root 0000000 0000000 package cert
import (
"crypto/x509/pkix"
"encoding/asn1"
"math/big"
)
type ecPrivateKey struct {
Version int
PrivateKey []byte
NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"`
PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"`
}
type pkcs8 struct {
Version int
Algo pkix.AlgorithmIdentifier
PrivateKey []byte
// optional attributes omitted.
}
type pkcs1AdditionalRSAPrime struct {
Prime *big.Int
// We ignore these values because rsa will calculate them.
Exp *big.Int
Coeff *big.Int
}
type pkcs1PrivateKey struct {
Version int
N *big.Int
E int
D *big.Int
P *big.Int
Q *big.Int
// We ignore these values, if present, because rsa will calculate them.
Dp *big.Int `asn1:"optional"`
Dq *big.Int `asn1:"optional"`
Qinv *big.Int `asn1:"optional"`
AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional,omitempty"`
}
v2ray-core-4.34.0/common/protocol/tls/sniff.go 0000664 0000000 0000000 00000006152 13774574720 0021206 0 ustar 00root root 0000000 0000000 package tls
import (
"encoding/binary"
"errors"
"strings"
"v2ray.com/core/common"
)
type SniffHeader struct {
domain string
}
func (h *SniffHeader) Protocol() string {
return "tls"
}
func (h *SniffHeader) Domain() string {
return h.domain
}
var errNotTLS = errors.New("not TLS header")
var errNotClientHello = errors.New("not client hello")
func IsValidTLSVersion(major, minor byte) bool {
return major == 3
}
// ReadClientHello returns server name (if any) from TLS client hello message.
// https://github.com/golang/go/blob/master/src/crypto/tls/handshake_messages.go#L300
func ReadClientHello(data []byte, h *SniffHeader) error {
if len(data) < 42 {
return common.ErrNoClue
}
sessionIDLen := int(data[38])
if sessionIDLen > 32 || len(data) < 39+sessionIDLen {
return common.ErrNoClue
}
data = data[39+sessionIDLen:]
if len(data) < 2 {
return common.ErrNoClue
}
// cipherSuiteLen is the number of bytes of cipher suite numbers. Since
// they are uint16s, the number must be even.
cipherSuiteLen := int(data[0])<<8 | int(data[1])
if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen {
return errNotClientHello
}
data = data[2+cipherSuiteLen:]
if len(data) < 1 {
return common.ErrNoClue
}
compressionMethodsLen := int(data[0])
if len(data) < 1+compressionMethodsLen {
return common.ErrNoClue
}
data = data[1+compressionMethodsLen:]
if len(data) == 0 {
return errNotClientHello
}
if len(data) < 2 {
return errNotClientHello
}
extensionsLength := int(data[0])<<8 | int(data[1])
data = data[2:]
if extensionsLength != len(data) {
return errNotClientHello
}
for len(data) != 0 {
if len(data) < 4 {
return errNotClientHello
}
extension := uint16(data[0])<<8 | uint16(data[1])
length := int(data[2])<<8 | int(data[3])
data = data[4:]
if len(data) < length {
return errNotClientHello
}
if extension == 0x00 { /* extensionServerName */
d := data[:length]
if len(d) < 2 {
return errNotClientHello
}
namesLen := int(d[0])<<8 | int(d[1])
d = d[2:]
if len(d) != namesLen {
return errNotClientHello
}
for len(d) > 0 {
if len(d) < 3 {
return errNotClientHello
}
nameType := d[0]
nameLen := int(d[1])<<8 | int(d[2])
d = d[3:]
if len(d) < nameLen {
return errNotClientHello
}
if nameType == 0 {
serverName := string(d[:nameLen])
// An SNI value may not include a
// trailing dot. See
// https://tools.ietf.org/html/rfc6066#section-3.
if strings.HasSuffix(serverName, ".") {
return errNotClientHello
}
h.domain = serverName
return nil
}
d = d[nameLen:]
}
}
data = data[length:]
}
return errNotTLS
}
func SniffTLS(b []byte) (*SniffHeader, error) {
if len(b) < 5 {
return nil, common.ErrNoClue
}
if b[0] != 0x16 /* TLS Handshake */ {
return nil, errNotTLS
}
if !IsValidTLSVersion(b[1], b[2]) {
return nil, errNotTLS
}
headerLen := int(binary.BigEndian.Uint16(b[3:5]))
if 5+headerLen > len(b) {
return nil, common.ErrNoClue
}
h := &SniffHeader{}
err := ReadClientHello(b[5:5+headerLen], h)
if err == nil {
return h, nil
}
return nil, err
}
v2ray-core-4.34.0/common/protocol/tls/sniff_test.go 0000664 0000000 0000000 00000015546 13774574720 0022254 0 ustar 00root root 0000000 0000000 package tls_test
import (
"testing"
. "v2ray.com/core/common/protocol/tls"
)
func TestTLSHeaders(t *testing.T) {
cases := []struct {
input []byte
domain string
err bool
}{
{
input: []byte{
0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00,
0xc4, 0x03, 0x03, 0x1a, 0xac, 0xb2, 0xa8, 0xfe,
0xb4, 0x96, 0x04, 0x5b, 0xca, 0xf7, 0xc1, 0xf4,
0x2e, 0x53, 0x24, 0x6e, 0x34, 0x0c, 0x58, 0x36,
0x71, 0x97, 0x59, 0xe9, 0x41, 0x66, 0xe2, 0x43,
0xa0, 0x13, 0xb6, 0x00, 0x00, 0x20, 0x1a, 0x1a,
0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30,
0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0x14, 0xcc, 0x13,
0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d,
0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00,
0x00, 0x7b, 0xba, 0xba, 0x00, 0x00, 0xff, 0x01,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00,
0x14, 0x00, 0x00, 0x11, 0x63, 0x2e, 0x73, 0x2d,
0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66,
0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x17, 0x00,
0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00,
0x14, 0x00, 0x12, 0x04, 0x03, 0x08, 0x04, 0x04,
0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x08,
0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x05, 0x00,
0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x0c,
0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70,
0x2f, 0x31, 0x2e, 0x31, 0x00, 0x0b, 0x00, 0x02,
0x01, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08,
0xaa, 0xaa, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
0xaa, 0xaa, 0x00, 0x01, 0x00,
},
domain: "c.s-microsoft.com",
err: false,
},
{
input: []byte{
0x16, 0x03, 0x01, 0x00, 0xee, 0x01, 0x00, 0x00,
0xea, 0x03, 0x03, 0xe7, 0x91, 0x9e, 0x93, 0xca,
0x78, 0x1b, 0x3c, 0xe0, 0x65, 0x25, 0x58, 0xb5,
0x93, 0xe1, 0x0f, 0x85, 0xec, 0x9a, 0x66, 0x8e,
0x61, 0x82, 0x88, 0xc8, 0xfc, 0xae, 0x1e, 0xca,
0xd7, 0xa5, 0x63, 0x20, 0xbd, 0x1c, 0x00, 0x00,
0x8b, 0xee, 0x09, 0xe3, 0x47, 0x6a, 0x0e, 0x74,
0xb0, 0xbc, 0xa3, 0x02, 0xa7, 0x35, 0xe8, 0x85,
0x70, 0x7c, 0x7a, 0xf0, 0x00, 0xdf, 0x4a, 0xea,
0x87, 0x01, 0x14, 0x91, 0x00, 0x20, 0xea, 0xea,
0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30,
0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0x14, 0xcc, 0x13,
0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d,
0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00,
0x00, 0x81, 0x9a, 0x9a, 0x00, 0x00, 0xff, 0x01,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00,
0x16, 0x00, 0x00, 0x13, 0x77, 0x77, 0x77, 0x30,
0x37, 0x2e, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x74,
0x61, 0x6c, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x00,
0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x0d, 0x00, 0x14, 0x00, 0x12, 0x04, 0x03, 0x08,
0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05,
0x01, 0x08, 0x06, 0x06, 0x01, 0x02, 0x01, 0x00,
0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0e,
0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74,
0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, 0x75, 0x50,
0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x9a, 0x9a,
0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x8a, 0x8a,
0x00, 0x01, 0x00,
},
domain: "www07.clicktale.net",
err: false,
},
{
input: []byte{
0x16, 0x03, 0x01, 0x00, 0xe6, 0x01, 0x00, 0x00, 0xe2, 0x03, 0x03, 0x81, 0x47, 0xc1,
0x66, 0xd5, 0x1b, 0xfa, 0x4b, 0xb5, 0xe0, 0x2a, 0xe1, 0xa7, 0x87, 0x13, 0x1d, 0x11, 0xaa, 0xc6,
0xce, 0xfc, 0x7f, 0xab, 0x94, 0xc8, 0x62, 0xad, 0xc8, 0xab, 0x0c, 0xdd, 0xcb, 0x20, 0x6f, 0x9d,
0x07, 0xf1, 0x95, 0x3e, 0x99, 0xd8, 0xf3, 0x6d, 0x97, 0xee, 0x19, 0x0b, 0x06, 0x1b, 0xf4, 0x84,
0x0b, 0xb6, 0x8f, 0xcc, 0xde, 0xe2, 0xd0, 0x2d, 0x6b, 0x0c, 0x1f, 0x52, 0x53, 0x13, 0x00, 0x08,
0x13, 0x02, 0x13, 0x03, 0x13, 0x01, 0x00, 0xff, 0x01, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x0c,
0x00, 0x0a, 0x00, 0x00, 0x07, 0x64, 0x6f, 0x67, 0x66, 0x69, 0x73, 0x68, 0x00, 0x0b, 0x00, 0x04,
0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x1e,
0x00, 0x19, 0x00, 0x18, 0x00, 0x23, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00,
0x00, 0x0d, 0x00, 0x1e, 0x00, 0x1c, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x07, 0x08, 0x08,
0x08, 0x09, 0x08, 0x0a, 0x08, 0x0b, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01,
0x06, 0x01, 0x00, 0x2b, 0x00, 0x07, 0x06, 0x7f, 0x1c, 0x7f, 0x1b, 0x7f, 0x1a, 0x00, 0x2d, 0x00,
0x02, 0x01, 0x01, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x2f, 0x35, 0x0c,
0xb6, 0x90, 0x0a, 0xb7, 0xd5, 0xc4, 0x1b, 0x2f, 0x60, 0xaa, 0x56, 0x7b, 0x3f, 0x71, 0xc8, 0x01,
0x7e, 0x86, 0xd3, 0xb7, 0x0c, 0x29, 0x1a, 0x9e, 0x5b, 0x38, 0x3f, 0x01, 0x72,
},
domain: "dogfish",
err: false,
},
{
input: []byte{
0x16, 0x03, 0x01, 0x01, 0x03, 0x01, 0x00, 0x00,
0xff, 0x03, 0x03, 0x3d, 0x89, 0x52, 0x9e, 0xee,
0xbe, 0x17, 0x63, 0x75, 0xef, 0x29, 0xbd, 0x14,
0x6a, 0x49, 0xe0, 0x2c, 0x37, 0x57, 0x71, 0x62,
0x82, 0x44, 0x94, 0x8f, 0x6e, 0x94, 0x08, 0x45,
0x7f, 0xdb, 0xc1, 0x00, 0x00, 0x3e, 0xc0, 0x2c,
0xc0, 0x30, 0x00, 0x9f, 0xcc, 0xa9, 0xcc, 0xa8,
0xcc, 0xaa, 0xc0, 0x2b, 0xc0, 0x2f, 0x00, 0x9e,
0xc0, 0x24, 0xc0, 0x28, 0x00, 0x6b, 0xc0, 0x23,
0xc0, 0x27, 0x00, 0x67, 0xc0, 0x0a, 0xc0, 0x14,
0x00, 0x39, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x33,
0x00, 0x9d, 0x00, 0x9c, 0x13, 0x02, 0x13, 0x03,
0x13, 0x01, 0x00, 0x3d, 0x00, 0x3c, 0x00, 0x35,
0x00, 0x2f, 0x00, 0xff, 0x01, 0x00, 0x00, 0x98,
0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x00,
0x0b, 0x31, 0x30, 0x2e, 0x34, 0x32, 0x2e, 0x30,
0x2e, 0x32, 0x34, 0x33, 0x00, 0x0b, 0x00, 0x04,
0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x0a,
0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x19,
0x00, 0x18, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d,
0x00, 0x20, 0x00, 0x1e, 0x04, 0x03, 0x05, 0x03,
0x06, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06,
0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03,
0x02, 0x01, 0x02, 0x02, 0x04, 0x02, 0x05, 0x02,
0x06, 0x02, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17,
0x00, 0x00, 0x00, 0x2b, 0x00, 0x09, 0x08, 0x7f,
0x14, 0x03, 0x03, 0x03, 0x02, 0x03, 0x01, 0x00,
0x2d, 0x00, 0x03, 0x02, 0x01, 0x00, 0x00, 0x28,
0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20,
0x13, 0x7c, 0x6e, 0x97, 0xc4, 0xfd, 0x09, 0x2e,
0x70, 0x2f, 0x73, 0x5a, 0x9b, 0x57, 0x4d, 0x5f,
0x2b, 0x73, 0x2c, 0xa5, 0x4a, 0x98, 0x40, 0x3d,
0x75, 0x6e, 0xb4, 0x76, 0xf9, 0x48, 0x8f, 0x36,
},
domain: "10.42.0.243",
err: false,
},
}
for _, test := range cases {
header, err := SniffTLS(test.input)
if test.err {
if err == nil {
t.Errorf("Exepct error but nil in test %v", test)
}
} else {
if err != nil {
t.Errorf("Expect no error but actually %s in test %v", err.Error(), test)
}
if header.Domain() != test.domain {
t.Error("expect domain ", test.domain, " but got ", header.Domain())
}
}
}
}
v2ray-core-4.34.0/common/protocol/udp/ 0000775 0000000 0000000 00000000000 13774574720 0017534 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/protocol/udp/packet.go 0000664 0000000 0000000 00000000375 13774574720 0021337 0 ustar 00root root 0000000 0000000 package udp
import (
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
)
// Packet is a UDP packet together with its source and destination address.
type Packet struct {
Payload *buf.Buffer
Source net.Destination
Target net.Destination
}
v2ray-core-4.34.0/common/protocol/udp/udp.go 0000664 0000000 0000000 00000000014 13774574720 0020646 0 ustar 00root root 0000000 0000000 package udp
v2ray-core-4.34.0/common/protocol/user.go 0000664 0000000 0000000 00000001575 13774574720 0020261 0 ustar 00root root 0000000 0000000 package protocol
func (u *User) GetTypedAccount() (Account, error) {
if u.GetAccount() == nil {
return nil, newError("Account missing").AtWarning()
}
rawAccount, err := u.Account.GetInstance()
if err != nil {
return nil, err
}
if asAccount, ok := rawAccount.(AsAccount); ok {
return asAccount.AsAccount()
}
if account, ok := rawAccount.(Account); ok {
return account, nil
}
return nil, newError("Unknown account type: ", u.Account.Type)
}
func (u *User) ToMemoryUser() (*MemoryUser, error) {
account, err := u.GetTypedAccount()
if err != nil {
return nil, err
}
return &MemoryUser{
Account: account,
Email: u.Email,
Level: u.Level,
}, nil
}
// MemoryUser is a parsed form of User, to reduce number of parsing of Account proto.
type MemoryUser struct {
// Account is the parsed account of the protocol.
Account Account
Email string
Level uint32
}
v2ray-core-4.34.0/common/protocol/user.pb.go 0000664 0000000 0000000 00000015110 13774574720 0020647 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: common/protocol/user.proto
package protocol
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
serial "v2ray.com/core/common/serial"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// User is a generic user for all procotols.
type User struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Level uint32 `protobuf:"varint,1,opt,name=level,proto3" json:"level,omitempty"`
Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"`
// Protocol specific account information. Must be the account proto in one of
// the proxies.
Account *serial.TypedMessage `protobuf:"bytes,3,opt,name=account,proto3" json:"account,omitempty"`
}
func (x *User) Reset() {
*x = User{}
if protoimpl.UnsafeEnabled {
mi := &file_common_protocol_user_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *User) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*User) ProtoMessage() {}
func (x *User) ProtoReflect() protoreflect.Message {
mi := &file_common_protocol_user_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use User.ProtoReflect.Descriptor instead.
func (*User) Descriptor() ([]byte, []int) {
return file_common_protocol_user_proto_rawDescGZIP(), []int{0}
}
func (x *User) GetLevel() uint32 {
if x != nil {
return x.Level
}
return 0
}
func (x *User) GetEmail() string {
if x != nil {
return x.Email
}
return ""
}
func (x *User) GetAccount() *serial.TypedMessage {
if x != nil {
return x.Account
}
return nil
}
var File_common_protocol_user_proto protoreflect.FileDescriptor
var file_common_protocol_user_proto_rawDesc = []byte{
0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x74, 0x0a, 0x04, 0x55,
0x73, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0d, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61,
0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12,
0x40, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65,
0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x42, 0x5f, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x50, 0x01, 0x5a, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f,
0x72, 0x65, 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 (
file_common_protocol_user_proto_rawDescOnce sync.Once
file_common_protocol_user_proto_rawDescData = file_common_protocol_user_proto_rawDesc
)
func file_common_protocol_user_proto_rawDescGZIP() []byte {
file_common_protocol_user_proto_rawDescOnce.Do(func() {
file_common_protocol_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_protocol_user_proto_rawDescData)
})
return file_common_protocol_user_proto_rawDescData
}
var file_common_protocol_user_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_common_protocol_user_proto_goTypes = []interface{}{
(*User)(nil), // 0: v2ray.core.common.protocol.User
(*serial.TypedMessage)(nil), // 1: v2ray.core.common.serial.TypedMessage
}
var file_common_protocol_user_proto_depIdxs = []int32{
1, // 0: v2ray.core.common.protocol.User.account:type_name -> v2ray.core.common.serial.TypedMessage
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_common_protocol_user_proto_init() }
func file_common_protocol_user_proto_init() {
if File_common_protocol_user_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_protocol_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*User); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_protocol_user_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_protocol_user_proto_goTypes,
DependencyIndexes: file_common_protocol_user_proto_depIdxs,
MessageInfos: file_common_protocol_user_proto_msgTypes,
}.Build()
File_common_protocol_user_proto = out.File
file_common_protocol_user_proto_rawDesc = nil
file_common_protocol_user_proto_goTypes = nil
file_common_protocol_user_proto_depIdxs = nil
}
v2ray-core-4.34.0/common/protocol/user.proto 0000664 0000000 0000000 00000001055 13774574720 0021010 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.common.protocol;
option csharp_namespace = "V2Ray.Core.Common.Protocol";
option go_package = "v2ray.com/core/common/protocol";
option java_package = "com.v2ray.core.common.protocol";
option java_multiple_files = true;
import "common/serial/typed_message.proto";
// User is a generic user for all procotols.
message User {
uint32 level = 1;
string email = 2;
// Protocol specific account information. Must be the account proto in one of
// the proxies.
v2ray.core.common.serial.TypedMessage account = 3;
}
v2ray-core-4.34.0/common/retry/ 0000775 0000000 0000000 00000000000 13774574720 0016250 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/retry/errors.generated.go 0000664 0000000 0000000 00000000313 13774574720 0022045 0 ustar 00root root 0000000 0000000 package retry
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/common/retry/retry.go 0000664 0000000 0000000 00000002646 13774574720 0017754 0 ustar 00root root 0000000 0000000 package retry // import "v2ray.com/core/common/retry"
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"time"
)
var (
ErrRetryFailed = newError("all retry attempts failed")
)
// Strategy is a way to retry on a specific function.
type Strategy interface {
// On performs a retry on a specific function, until it doesn't return any error.
On(func() error) error
}
type retryer struct {
totalAttempt int
nextDelay func() uint32
}
// On implements Strategy.On.
func (r *retryer) On(method func() error) error {
attempt := 0
accumulatedError := make([]error, 0, r.totalAttempt)
for attempt < r.totalAttempt {
err := method()
if err == nil {
return nil
}
numErrors := len(accumulatedError)
if numErrors == 0 || err.Error() != accumulatedError[numErrors-1].Error() {
accumulatedError = append(accumulatedError, err)
}
delay := r.nextDelay()
time.Sleep(time.Duration(delay) * time.Millisecond)
attempt++
}
return newError(accumulatedError).Base(ErrRetryFailed)
}
// Timed returns a retry strategy with fixed interval.
func Timed(attempts int, delay uint32) Strategy {
return &retryer{
totalAttempt: attempts,
nextDelay: func() uint32 {
return delay
},
}
}
func ExponentialBackoff(attempts int, delay uint32) Strategy {
nextDelay := uint32(0)
return &retryer{
totalAttempt: attempts,
nextDelay: func() uint32 {
r := nextDelay
nextDelay += delay
return r
},
}
}
v2ray-core-4.34.0/common/retry/retry_test.go 0000664 0000000 0000000 00000003512 13774574720 0021004 0 ustar 00root root 0000000 0000000 package retry_test
import (
"testing"
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
. "v2ray.com/core/common/retry"
)
var (
errorTestOnly = errors.New("this is a fake error")
)
func TestNoRetry(t *testing.T) {
startTime := time.Now().Unix()
err := Timed(10, 100000).On(func() error {
return nil
})
endTime := time.Now().Unix()
common.Must(err)
if endTime < startTime {
t.Error("endTime < startTime: ", startTime, " -> ", endTime)
}
}
func TestRetryOnce(t *testing.T) {
startTime := time.Now()
called := 0
err := Timed(10, 1000).On(func() error {
if called == 0 {
called++
return errorTestOnly
}
return nil
})
duration := time.Since(startTime)
common.Must(err)
if v := int64(duration / time.Millisecond); v < 900 {
t.Error("duration: ", v)
}
}
func TestRetryMultiple(t *testing.T) {
startTime := time.Now()
called := 0
err := Timed(10, 1000).On(func() error {
if called < 5 {
called++
return errorTestOnly
}
return nil
})
duration := time.Since(startTime)
common.Must(err)
if v := int64(duration / time.Millisecond); v < 4900 {
t.Error("duration: ", v)
}
}
func TestRetryExhausted(t *testing.T) {
startTime := time.Now()
called := 0
err := Timed(2, 1000).On(func() error {
called++
return errorTestOnly
})
duration := time.Since(startTime)
if errors.Cause(err) != ErrRetryFailed {
t.Error("cause: ", err)
}
if v := int64(duration / time.Millisecond); v < 1900 {
t.Error("duration: ", v)
}
}
func TestExponentialBackoff(t *testing.T) {
startTime := time.Now()
called := 0
err := ExponentialBackoff(10, 100).On(func() error {
called++
return errorTestOnly
})
duration := time.Since(startTime)
if errors.Cause(err) != ErrRetryFailed {
t.Error("cause: ", err)
}
if v := int64(duration / time.Millisecond); v < 4000 {
t.Error("duration: ", v)
}
}
v2ray-core-4.34.0/common/serial/ 0000775 0000000 0000000 00000000000 13774574720 0016362 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/serial/serial.go 0000664 0000000 0000000 00000001337 13774574720 0020174 0 ustar 00root root 0000000 0000000 package serial
import (
"encoding/binary"
"io"
)
// ReadUint16 reads first two bytes from the reader, and then coverts them to an uint16 value.
func ReadUint16(reader io.Reader) (uint16, error) {
var b [2]byte
if _, err := io.ReadFull(reader, b[:]); err != nil {
return 0, err
}
return binary.BigEndian.Uint16(b[:]), nil
}
// WriteUint16 writes an uint16 value into writer.
func WriteUint16(writer io.Writer, value uint16) (int, error) {
var b [2]byte
binary.BigEndian.PutUint16(b[:], value)
return writer.Write(b[:])
}
// WriteUint64 writes an uint64 value into writer.
func WriteUint64(writer io.Writer, value uint64) (int, error) {
var b [8]byte
binary.BigEndian.PutUint64(b[:], value)
return writer.Write(b[:])
}
v2ray-core-4.34.0/common/serial/serial_test.go 0000664 0000000 0000000 00000003154 13774574720 0021232 0 ustar 00root root 0000000 0000000 package serial_test
import (
"bytes"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/serial"
)
func TestUint16Serial(t *testing.T) {
b := buf.New()
defer b.Release()
n, err := serial.WriteUint16(b, 10)
common.Must(err)
if n != 2 {
t.Error("expect 2 bytes writtng, but actually ", n)
}
if diff := cmp.Diff(b.Bytes(), []byte{0, 10}); diff != "" {
t.Error(diff)
}
}
func TestUint64Serial(t *testing.T) {
b := buf.New()
defer b.Release()
n, err := serial.WriteUint64(b, 10)
common.Must(err)
if n != 8 {
t.Error("expect 8 bytes writtng, but actually ", n)
}
if diff := cmp.Diff(b.Bytes(), []byte{0, 0, 0, 0, 0, 0, 0, 10}); diff != "" {
t.Error(diff)
}
}
func TestReadUint16(t *testing.T) {
testCases := []struct {
Input []byte
Output uint16
}{
{
Input: []byte{0, 1},
Output: 1,
},
}
for _, testCase := range testCases {
v, err := serial.ReadUint16(bytes.NewReader(testCase.Input))
common.Must(err)
if v != testCase.Output {
t.Error("for input ", testCase.Input, " expect output ", testCase.Output, " but got ", v)
}
}
}
func BenchmarkReadUint16(b *testing.B) {
reader := buf.New()
defer reader.Release()
common.Must2(reader.Write([]byte{0, 1}))
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := serial.ReadUint16(reader)
common.Must(err)
reader.Clear()
reader.Extend(2)
}
}
func BenchmarkWriteUint64(b *testing.B) {
writer := buf.New()
defer writer.Release()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := serial.WriteUint64(writer, 8)
common.Must(err)
writer.Clear()
}
}
v2ray-core-4.34.0/common/serial/string.go 0000664 0000000 0000000 00000001140 13774574720 0020213 0 ustar 00root root 0000000 0000000 package serial
import (
"fmt"
"strings"
)
// ToString serialize an arbitrary value into string.
func ToString(v interface{}) string {
if v == nil {
return ""
}
switch value := v.(type) {
case string:
return value
case *string:
return *value
case fmt.Stringer:
return value.String()
case error:
return value.Error()
default:
return fmt.Sprintf("%+v", value)
}
}
// Concat concatenates all input into a single string.
func Concat(v ...interface{}) string {
builder := strings.Builder{}
for _, value := range v {
builder.WriteString(ToString(value))
}
return builder.String()
}
v2ray-core-4.34.0/common/serial/string_test.go 0000664 0000000 0000000 00000002017 13774574720 0021256 0 ustar 00root root 0000000 0000000 package serial_test
import (
"errors"
"testing"
"github.com/google/go-cmp/cmp"
. "v2ray.com/core/common/serial"
)
func TestToString(t *testing.T) {
s := "a"
data := []struct {
Value interface{}
String string
}{
{Value: s, String: s},
{Value: &s, String: s},
{Value: errors.New("t"), String: "t"},
{Value: []byte{'b', 'c'}, String: "[98 99]"},
}
for _, c := range data {
if r := cmp.Diff(ToString(c.Value), c.String); r != "" {
t.Error(r)
}
}
}
func TestConcat(t *testing.T) {
testCases := []struct {
Input []interface{}
Output string
}{
{
Input: []interface{}{
"a", "b",
},
Output: "ab",
},
}
for _, testCase := range testCases {
actual := Concat(testCase.Input...)
if actual != testCase.Output {
t.Error("Unexpected output: ", actual, " but want: ", testCase.Output)
}
}
}
func BenchmarkConcat(b *testing.B) {
input := []interface{}{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"}
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = Concat(input...)
}
}
v2ray-core-4.34.0/common/serial/typed_message.go 0000664 0000000 0000000 00000002271 13774574720 0021544 0 ustar 00root root 0000000 0000000 package serial
import (
"errors"
"reflect"
"github.com/golang/protobuf/proto"
)
// ToTypedMessage converts a proto Message into TypedMessage.
func ToTypedMessage(message proto.Message) *TypedMessage {
if message == nil {
return nil
}
settings, _ := proto.Marshal(message)
return &TypedMessage{
Type: GetMessageType(message),
Value: settings,
}
}
// GetMessageType returns the name of this proto Message.
func GetMessageType(message proto.Message) string {
return proto.MessageName(message)
}
// GetInstance creates a new instance of the message with messageType.
func GetInstance(messageType string) (interface{}, error) {
mType := proto.MessageType(messageType)
if mType == nil || mType.Elem() == nil {
return nil, errors.New("Serial: Unknown type: " + messageType)
}
return reflect.New(mType.Elem()).Interface(), nil
}
// GetInstance converts current TypedMessage into a proto Message.
func (v *TypedMessage) GetInstance() (proto.Message, error) {
instance, err := GetInstance(v.Type)
if err != nil {
return nil, err
}
protoMessage := instance.(proto.Message)
if err := proto.Unmarshal(v.Value, protoMessage); err != nil {
return nil, err
}
return protoMessage, nil
}
v2ray-core-4.34.0/common/serial/typed_message.pb.go 0000664 0000000 0000000 00000013625 13774574720 0022151 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: common/serial/typed_message.proto
package serial
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// TypedMessage is a serialized proto message along with its type name.
type TypedMessage struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The name of the message type, retrieved from protobuf API.
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
// Serialized proto message.
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *TypedMessage) Reset() {
*x = TypedMessage{}
if protoimpl.UnsafeEnabled {
mi := &file_common_serial_typed_message_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TypedMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TypedMessage) ProtoMessage() {}
func (x *TypedMessage) ProtoReflect() protoreflect.Message {
mi := &file_common_serial_typed_message_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TypedMessage.ProtoReflect.Descriptor instead.
func (*TypedMessage) Descriptor() ([]byte, []int) {
return file_common_serial_typed_message_proto_rawDescGZIP(), []int{0}
}
func (x *TypedMessage) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *TypedMessage) GetValue() []byte {
if x != nil {
return x.Value
}
return nil
}
var File_common_serial_typed_message_proto protoreflect.FileDescriptor
var file_common_serial_typed_message_proto_rawDesc = []byte{
0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,
0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x18, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x22, 0x38, 0x0a,
0x0c, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a,
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70,
0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x59, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x50, 0x01, 0x5a, 0x1c, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0xaa, 0x02, 0x18, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,
0x43, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_common_serial_typed_message_proto_rawDescOnce sync.Once
file_common_serial_typed_message_proto_rawDescData = file_common_serial_typed_message_proto_rawDesc
)
func file_common_serial_typed_message_proto_rawDescGZIP() []byte {
file_common_serial_typed_message_proto_rawDescOnce.Do(func() {
file_common_serial_typed_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_serial_typed_message_proto_rawDescData)
})
return file_common_serial_typed_message_proto_rawDescData
}
var file_common_serial_typed_message_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_common_serial_typed_message_proto_goTypes = []interface{}{
(*TypedMessage)(nil), // 0: v2ray.core.common.serial.TypedMessage
}
var file_common_serial_typed_message_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_common_serial_typed_message_proto_init() }
func file_common_serial_typed_message_proto_init() {
if File_common_serial_typed_message_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_serial_typed_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TypedMessage); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_serial_typed_message_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_serial_typed_message_proto_goTypes,
DependencyIndexes: file_common_serial_typed_message_proto_depIdxs,
MessageInfos: file_common_serial_typed_message_proto_msgTypes,
}.Build()
File_common_serial_typed_message_proto = out.File
file_common_serial_typed_message_proto_rawDesc = nil
file_common_serial_typed_message_proto_goTypes = nil
file_common_serial_typed_message_proto_depIdxs = nil
}
v2ray-core-4.34.0/common/serial/typed_message.proto 0000664 0000000 0000000 00000000740 13774574720 0022301 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.common.serial;
option csharp_namespace = "V2Ray.Core.Common.Serial";
option go_package = "v2ray.com/core/common/serial";
option java_package = "com.v2ray.core.common.serial";
option java_multiple_files = true;
// TypedMessage is a serialized proto message along with its type name.
message TypedMessage {
// The name of the message type, retrieved from protobuf API.
string type = 1;
// Serialized proto message.
bytes value = 2;
}
v2ray-core-4.34.0/common/serial/typed_message_test.go 0000664 0000000 0000000 00000000635 13774574720 0022605 0 ustar 00root root 0000000 0000000 package serial_test
import (
"testing"
. "v2ray.com/core/common/serial"
)
func TestGetInstance(t *testing.T) {
p, err := GetInstance("")
if p != nil {
t.Error("expected nil instance, but got ", p)
}
if err == nil {
t.Error("expect non-nil error, but got nil")
}
}
func TestConvertingNilMessage(t *testing.T) {
x := ToTypedMessage(nil)
if x != nil {
t.Error("expect nil, but actually not")
}
}
v2ray-core-4.34.0/common/session/ 0000775 0000000 0000000 00000000000 13774574720 0016566 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/session/context.go 0000664 0000000 0000000 00000004475 13774574720 0020613 0 ustar 00root root 0000000 0000000 package session
import "context"
type sessionKey int
const (
idSessionKey sessionKey = iota
inboundSessionKey
outboundSessionKey
contentSessionKey
muxPreferedSessionKey
sockoptSessionKey
)
// ContextWithID returns a new context with the given ID.
func ContextWithID(ctx context.Context, id ID) context.Context {
return context.WithValue(ctx, idSessionKey, id)
}
// IDFromContext returns ID in this context, or 0 if not contained.
func IDFromContext(ctx context.Context) ID {
if id, ok := ctx.Value(idSessionKey).(ID); ok {
return id
}
return 0
}
func ContextWithInbound(ctx context.Context, inbound *Inbound) context.Context {
return context.WithValue(ctx, inboundSessionKey, inbound)
}
func InboundFromContext(ctx context.Context) *Inbound {
if inbound, ok := ctx.Value(inboundSessionKey).(*Inbound); ok {
return inbound
}
return nil
}
func ContextWithOutbound(ctx context.Context, outbound *Outbound) context.Context {
return context.WithValue(ctx, outboundSessionKey, outbound)
}
func OutboundFromContext(ctx context.Context) *Outbound {
if outbound, ok := ctx.Value(outboundSessionKey).(*Outbound); ok {
return outbound
}
return nil
}
func ContextWithContent(ctx context.Context, content *Content) context.Context {
return context.WithValue(ctx, contentSessionKey, content)
}
func ContentFromContext(ctx context.Context) *Content {
if content, ok := ctx.Value(contentSessionKey).(*Content); ok {
return content
}
return nil
}
// ContextWithMuxPrefered returns a new context with the given bool
func ContextWithMuxPrefered(ctx context.Context, forced bool) context.Context {
return context.WithValue(ctx, muxPreferedSessionKey, forced)
}
// MuxPreferedFromContext returns value in this context, or false if not contained.
func MuxPreferedFromContext(ctx context.Context) bool {
if val, ok := ctx.Value(muxPreferedSessionKey).(bool); ok {
return val
}
return false
}
// ContextWithSockopt returns a new context with Socket configs included
func ContextWithSockopt(ctx context.Context, s *Sockopt) context.Context {
return context.WithValue(ctx, sockoptSessionKey, s)
}
// SockoptFromContext returns Socket configs in this context, or nil if not contained.
func SockoptFromContext(ctx context.Context) *Sockopt {
if sockopt, ok := ctx.Value(sockoptSessionKey).(*Sockopt); ok {
return sockopt
}
return nil
}
v2ray-core-4.34.0/common/session/session.go 0000664 0000000 0000000 00000004452 13774574720 0020605 0 ustar 00root root 0000000 0000000 // Package session provides functions for sessions of incoming requests.
package session // import "v2ray.com/core/common/session"
import (
"context"
"math/rand"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
)
// ID of a session.
type ID uint32
// NewID generates a new ID. The generated ID is high likely to be unique, but not cryptographically secure.
// The generated ID will never be 0.
func NewID() ID {
for {
id := ID(rand.Uint32())
if id != 0 {
return id
}
}
}
// ExportIDToError transfers session.ID into an error object, for logging purpose.
// This can be used with error.WriteToLog().
func ExportIDToError(ctx context.Context) errors.ExportOption {
id := IDFromContext(ctx)
return func(h *errors.ExportOptionHolder) {
h.SessionID = uint32(id)
}
}
// Inbound is the metadata of an inbound connection.
type Inbound struct {
// Source address of the inbound connection.
Source net.Destination
// Getaway address
Gateway net.Destination
// Tag of the inbound proxy that handles the connection.
Tag string
// User is the user that authencates for the inbound. May be nil if the protocol allows anounymous traffic.
User *protocol.MemoryUser
}
// Outbound is the metadata of an outbound connection.
type Outbound struct {
// Target address of the outbound connection.
Target net.Destination
// Gateway address
Gateway net.Address
}
// SniffingRequest controls the behavior of content sniffing.
type SniffingRequest struct {
OverrideDestinationForProtocol []string
Enabled bool
}
// Content is the metadata of the connection content.
type Content struct {
// Protocol of current content.
Protocol string
SniffingRequest SniffingRequest
Attributes map[string]string
SkipDNSResolve bool
}
// Sockopt is the settings for socket connection.
type Sockopt struct {
// Mark of the socket connection.
Mark int32
}
// SetAttribute attachs additional string attributes to content.
func (c *Content) SetAttribute(name string, value string) {
if c.Attributes == nil {
c.Attributes = make(map[string]string)
}
c.Attributes[name] = value
}
// Attribute retrieves additional string attributes from content.
func (c *Content) Attribute(name string) string {
if c.Attributes == nil {
return ""
}
return c.Attributes[name]
}
v2ray-core-4.34.0/common/signal/ 0000775 0000000 0000000 00000000000 13774574720 0016360 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/signal/done/ 0000775 0000000 0000000 00000000000 13774574720 0017305 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/signal/done/done.go 0000664 0000000 0000000 00000001476 13774574720 0020571 0 ustar 00root root 0000000 0000000 package done
import (
"sync"
)
// Instance is a utility for notifications of something being done.
type Instance struct {
access sync.Mutex
c chan struct{}
closed bool
}
// New returns a new Done.
func New() *Instance {
return &Instance{
c: make(chan struct{}),
}
}
// Done returns true if Close() is called.
func (d *Instance) Done() bool {
select {
case <-d.Wait():
return true
default:
return false
}
}
// Wait returns a channel for waiting for done.
func (d *Instance) Wait() <-chan struct{} {
return d.c
}
// Close marks this Done 'done'. This method may be called multiple times. All calls after first call will have no effect on its status.
func (d *Instance) Close() error {
d.access.Lock()
defer d.access.Unlock()
if d.closed {
return nil
}
d.closed = true
close(d.c)
return nil
}
v2ray-core-4.34.0/common/signal/notifier.go 0000664 0000000 0000000 00000001200 13774574720 0020517 0 ustar 00root root 0000000 0000000 package signal
// Notifier is a utility for notifying changes. The change producer may notify changes multiple time, and the consumer may get notified asynchronously.
type Notifier struct {
c chan struct{}
}
// NewNotifier creates a new Notifier.
func NewNotifier() *Notifier {
return &Notifier{
c: make(chan struct{}, 1),
}
}
// Signal signals a change, usually by producer. This method never blocks.
func (n *Notifier) Signal() {
select {
case n.c <- struct{}{}:
default:
}
}
// Wait returns a channel for waiting for changes. The returned channel never gets closed.
func (n *Notifier) Wait() <-chan struct{} {
return n.c
}
v2ray-core-4.34.0/common/signal/notifier_test.go 0000664 0000000 0000000 00000000327 13774574720 0021567 0 ustar 00root root 0000000 0000000 package signal_test
import (
"testing"
. "v2ray.com/core/common/signal"
)
func TestNotifierSignal(t *testing.T) {
n := NewNotifier()
w := n.Wait()
n.Signal()
select {
case <-w:
default:
t.Fail()
}
}
v2ray-core-4.34.0/common/signal/pubsub/ 0000775 0000000 0000000 00000000000 13774574720 0017660 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/signal/pubsub/pubsub.go 0000664 0000000 0000000 00000003405 13774574720 0021511 0 ustar 00root root 0000000 0000000 package pubsub
import (
"errors"
"sync"
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/signal/done"
"v2ray.com/core/common/task"
)
type Subscriber struct {
buffer chan interface{}
done *done.Instance
}
func (s *Subscriber) push(msg interface{}) {
select {
case s.buffer <- msg:
default:
}
}
func (s *Subscriber) Wait() <-chan interface{} {
return s.buffer
}
func (s *Subscriber) Close() error {
return s.done.Close()
}
func (s *Subscriber) IsClosed() bool {
return s.done.Done()
}
type Service struct {
sync.RWMutex
subs map[string][]*Subscriber
ctask *task.Periodic
}
func NewService() *Service {
s := &Service{
subs: make(map[string][]*Subscriber),
}
s.ctask = &task.Periodic{
Execute: s.Cleanup,
Interval: time.Second * 30,
}
return s
}
// Cleanup cleans up internal caches of subscribers.
// Visible for testing only.
func (s *Service) Cleanup() error {
s.Lock()
defer s.Unlock()
if len(s.subs) == 0 {
return errors.New("nothing to do")
}
for name, subs := range s.subs {
newSub := make([]*Subscriber, 0, len(s.subs))
for _, sub := range subs {
if !sub.IsClosed() {
newSub = append(newSub, sub)
}
}
if len(newSub) == 0 {
delete(s.subs, name)
} else {
s.subs[name] = newSub
}
}
if len(s.subs) == 0 {
s.subs = make(map[string][]*Subscriber)
}
return nil
}
func (s *Service) Subscribe(name string) *Subscriber {
sub := &Subscriber{
buffer: make(chan interface{}, 16),
done: done.New(),
}
s.Lock()
subs := append(s.subs[name], sub)
s.subs[name] = subs
s.Unlock()
common.Must(s.ctask.Start())
return sub
}
func (s *Service) Publish(name string, message interface{}) {
s.RLock()
defer s.RUnlock()
for _, sub := range s.subs[name] {
if !sub.IsClosed() {
sub.push(message)
}
}
}
v2ray-core-4.34.0/common/signal/pubsub/pubsub_test.go 0000664 0000000 0000000 00000000701 13774574720 0022544 0 ustar 00root root 0000000 0000000 package pubsub_test
import (
"testing"
. "v2ray.com/core/common/signal/pubsub"
)
func TestPubsub(t *testing.T) {
service := NewService()
sub := service.Subscribe("a")
service.Publish("a", 1)
select {
case v := <-sub.Wait():
if v != 1 {
t.Error("expected subscribed value 1, but got ", v)
}
default:
t.Fail()
}
sub.Close()
service.Publish("a", 2)
select {
case <-sub.Wait():
t.Fail()
default:
}
service.Cleanup()
}
v2ray-core-4.34.0/common/signal/semaphore/ 0000775 0000000 0000000 00000000000 13774574720 0020343 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/signal/semaphore/semaphore.go 0000664 0000000 0000000 00000001012 13774574720 0022647 0 ustar 00root root 0000000 0000000 package semaphore
// Instance is an implementation of semaphore.
type Instance struct {
token chan struct{}
}
// New create a new Semaphore with n permits.
func New(n int) *Instance {
s := &Instance{
token: make(chan struct{}, n),
}
for i := 0; i < n; i++ {
s.token <- struct{}{}
}
return s
}
// Wait returns a channel for acquiring a permit.
func (s *Instance) Wait() <-chan struct{} {
return s.token
}
// Signal releases a permit into the semaphore.
func (s *Instance) Signal() {
s.token <- struct{}{}
}
v2ray-core-4.34.0/common/signal/timer.go 0000664 0000000 0000000 00000002335 13774574720 0020032 0 ustar 00root root 0000000 0000000 package signal
import (
"context"
"sync"
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/task"
)
type ActivityUpdater interface {
Update()
}
type ActivityTimer struct {
sync.RWMutex
updated chan struct{}
checkTask *task.Periodic
onTimeout func()
}
func (t *ActivityTimer) Update() {
select {
case t.updated <- struct{}{}:
default:
}
}
func (t *ActivityTimer) check() error {
select {
case <-t.updated:
default:
t.finish()
}
return nil
}
func (t *ActivityTimer) finish() {
t.Lock()
defer t.Unlock()
if t.onTimeout != nil {
t.onTimeout()
t.onTimeout = nil
}
if t.checkTask != nil {
t.checkTask.Close()
t.checkTask = nil
}
}
func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
if timeout == 0 {
t.finish()
return
}
checkTask := &task.Periodic{
Interval: timeout,
Execute: t.check,
}
t.Lock()
if t.checkTask != nil {
t.checkTask.Close()
}
t.checkTask = checkTask
t.Unlock()
t.Update()
common.Must(checkTask.Start())
}
func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
timer := &ActivityTimer{
updated: make(chan struct{}, 1),
onTimeout: cancel,
}
timer.SetTimeout(timeout)
return timer
}
v2ray-core-4.34.0/common/signal/timer_test.go 0000664 0000000 0000000 00000002603 13774574720 0021067 0 ustar 00root root 0000000 0000000 package signal_test
import (
"context"
"runtime"
"testing"
"time"
. "v2ray.com/core/common/signal"
)
func TestActivityTimer(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
timer := CancelAfterInactivity(ctx, cancel, time.Second*4)
time.Sleep(time.Second * 6)
if ctx.Err() == nil {
t.Error("expected some error, but got nil")
}
runtime.KeepAlive(timer)
}
func TestActivityTimerUpdate(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
timer := CancelAfterInactivity(ctx, cancel, time.Second*10)
time.Sleep(time.Second * 3)
if ctx.Err() != nil {
t.Error("expected nil, but got ", ctx.Err().Error())
}
timer.SetTimeout(time.Second * 1)
time.Sleep(time.Second * 2)
if ctx.Err() == nil {
t.Error("expcted some error, but got nil")
}
runtime.KeepAlive(timer)
}
func TestActivityTimerNonBlocking(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
timer := CancelAfterInactivity(ctx, cancel, 0)
time.Sleep(time.Second * 1)
select {
case <-ctx.Done():
default:
t.Error("context not done")
}
timer.SetTimeout(0)
timer.SetTimeout(1)
timer.SetTimeout(2)
}
func TestActivityTimerZeroTimeout(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
timer := CancelAfterInactivity(ctx, cancel, 0)
select {
case <-ctx.Done():
default:
t.Error("context not done")
}
runtime.KeepAlive(timer)
}
v2ray-core-4.34.0/common/strmatcher/ 0000775 0000000 0000000 00000000000 13774574720 0017257 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/strmatcher/benchmark_test.go 0000664 0000000 0000000 00000001541 13774574720 0022600 0 ustar 00root root 0000000 0000000 package strmatcher_test
import (
"strconv"
"testing"
"v2ray.com/core/common"
. "v2ray.com/core/common/strmatcher"
)
func BenchmarkDomainMatcherGroup(b *testing.B) {
g := new(DomainMatcherGroup)
for i := 1; i <= 1024; i++ {
g.Add(strconv.Itoa(i)+".v2ray.com", uint32(i))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = g.Match("0.v2ray.com")
}
}
func BenchmarkFullMatcherGroup(b *testing.B) {
g := new(FullMatcherGroup)
for i := 1; i <= 1024; i++ {
g.Add(strconv.Itoa(i)+".v2ray.com", uint32(i))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = g.Match("0.v2ray.com")
}
}
func BenchmarkMarchGroup(b *testing.B) {
g := new(MatcherGroup)
for i := 1; i <= 1024; i++ {
m, err := Domain.New(strconv.Itoa(i) + ".v2ray.com")
common.Must(err)
g.Add(m)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = g.Match("0.v2ray.com")
}
}
v2ray-core-4.34.0/common/strmatcher/domain_matcher.go 0000664 0000000 0000000 00000003414 13774574720 0022562 0 ustar 00root root 0000000 0000000 package strmatcher
import "strings"
func breakDomain(domain string) []string {
return strings.Split(domain, ".")
}
type node struct {
values []uint32
sub map[string]*node
}
// DomainMatcherGroup is a IndexMatcher for a large set of Domain matchers.
// Visible for testing only.
type DomainMatcherGroup struct {
root *node
}
func (g *DomainMatcherGroup) Add(domain string, value uint32) {
if g.root == nil {
g.root = new(node)
}
current := g.root
parts := breakDomain(domain)
for i := len(parts) - 1; i >= 0; i-- {
part := parts[i]
if current.sub == nil {
current.sub = make(map[string]*node)
}
next := current.sub[part]
if next == nil {
next = new(node)
current.sub[part] = next
}
current = next
}
current.values = append(current.values, value)
}
func (g *DomainMatcherGroup) addMatcher(m domainMatcher, value uint32) {
g.Add(string(m), value)
}
func (g *DomainMatcherGroup) Match(domain string) []uint32 {
if domain == "" {
return nil
}
current := g.root
if current == nil {
return nil
}
nextPart := func(idx int) int {
for i := idx - 1; i >= 0; i-- {
if domain[i] == '.' {
return i
}
}
return -1
}
matches := [][]uint32{}
idx := len(domain)
for {
if idx == -1 || current.sub == nil {
break
}
nidx := nextPart(idx)
part := domain[nidx+1 : idx]
next := current.sub[part]
if next == nil {
break
}
current = next
idx = nidx
if len(current.values) > 0 {
matches = append(matches, current.values)
}
}
switch len(matches) {
case 0:
return nil
case 1:
return matches[0]
default:
result := []uint32{}
for idx := range matches {
// Insert reversely, the subdomain that matches further ranks higher
result = append(result, matches[len(matches)-1-idx]...)
}
return result
}
}
v2ray-core-4.34.0/common/strmatcher/domain_matcher_test.go 0000664 0000000 0000000 00000002366 13774574720 0023626 0 ustar 00root root 0000000 0000000 package strmatcher_test
import (
"reflect"
"testing"
. "v2ray.com/core/common/strmatcher"
)
func TestDomainMatcherGroup(t *testing.T) {
g := new(DomainMatcherGroup)
g.Add("v2ray.com", 1)
g.Add("google.com", 2)
g.Add("x.a.com", 3)
g.Add("a.b.com", 4)
g.Add("c.a.b.com", 5)
g.Add("x.y.com", 4)
g.Add("x.y.com", 6)
testCases := []struct {
Domain string
Result []uint32
}{
{
Domain: "x.v2ray.com",
Result: []uint32{1},
},
{
Domain: "y.com",
Result: nil,
},
{
Domain: "a.b.com",
Result: []uint32{4},
},
{ // Matches [c.a.b.com, a.b.com]
Domain: "c.a.b.com",
Result: []uint32{5, 4},
},
{
Domain: "c.a..b.com",
Result: nil,
},
{
Domain: ".com",
Result: nil,
},
{
Domain: "com",
Result: nil,
},
{
Domain: "",
Result: nil,
},
{
Domain: "x.y.com",
Result: []uint32{4, 6},
},
}
for _, testCase := range testCases {
r := g.Match(testCase.Domain)
if !reflect.DeepEqual(r, testCase.Result) {
t.Error("Failed to match domain: ", testCase.Domain, ", expect ", testCase.Result, ", but got ", r)
}
}
}
func TestEmptyDomainMatcherGroup(t *testing.T) {
g := new(DomainMatcherGroup)
r := g.Match("v2ray.com")
if len(r) != 0 {
t.Error("Expect [], but ", r)
}
}
v2ray-core-4.34.0/common/strmatcher/full_matcher.go 0000664 0000000 0000000 00000000756 13774574720 0022263 0 ustar 00root root 0000000 0000000 package strmatcher
type FullMatcherGroup struct {
matchers map[string][]uint32
}
func (g *FullMatcherGroup) Add(domain string, value uint32) {
if g.matchers == nil {
g.matchers = make(map[string][]uint32)
}
g.matchers[domain] = append(g.matchers[domain], value)
}
func (g *FullMatcherGroup) addMatcher(m fullMatcher, value uint32) {
g.Add(string(m), value)
}
func (g *FullMatcherGroup) Match(str string) []uint32 {
if g.matchers == nil {
return nil
}
return g.matchers[str]
}
v2ray-core-4.34.0/common/strmatcher/full_matcher_test.go 0000664 0000000 0000000 00000001574 13774574720 0023321 0 ustar 00root root 0000000 0000000 package strmatcher_test
import (
"reflect"
"testing"
. "v2ray.com/core/common/strmatcher"
)
func TestFullMatcherGroup(t *testing.T) {
g := new(FullMatcherGroup)
g.Add("v2ray.com", 1)
g.Add("google.com", 2)
g.Add("x.a.com", 3)
g.Add("x.y.com", 4)
g.Add("x.y.com", 6)
testCases := []struct {
Domain string
Result []uint32
}{
{
Domain: "v2ray.com",
Result: []uint32{1},
},
{
Domain: "y.com",
Result: nil,
},
{
Domain: "x.y.com",
Result: []uint32{4, 6},
},
}
for _, testCase := range testCases {
r := g.Match(testCase.Domain)
if !reflect.DeepEqual(r, testCase.Result) {
t.Error("Failed to match domain: ", testCase.Domain, ", expect ", testCase.Result, ", but got ", r)
}
}
}
func TestEmptyFullMatcherGroup(t *testing.T) {
g := new(FullMatcherGroup)
r := g.Match("v2ray.com")
if len(r) != 0 {
t.Error("Expect [], but ", r)
}
}
v2ray-core-4.34.0/common/strmatcher/matchers.go 0000664 0000000 0000000 00000001627 13774574720 0021422 0 ustar 00root root 0000000 0000000 package strmatcher
import (
"regexp"
"strings"
)
type fullMatcher string
func (m fullMatcher) Match(s string) bool {
return string(m) == s
}
func (m fullMatcher) String() string {
return "full:" + string(m)
}
type substrMatcher string
func (m substrMatcher) Match(s string) bool {
return strings.Contains(s, string(m))
}
func (m substrMatcher) String() string {
return "keyword:" + string(m)
}
type domainMatcher string
func (m domainMatcher) Match(s string) bool {
pattern := string(m)
if !strings.HasSuffix(s, pattern) {
return false
}
return len(s) == len(pattern) || s[len(s)-len(pattern)-1] == '.'
}
func (m domainMatcher) String() string {
return "domain:" + string(m)
}
type regexMatcher struct {
pattern *regexp.Regexp
}
func (m *regexMatcher) Match(s string) bool {
return m.pattern.MatchString(s)
}
func (m *regexMatcher) String() string {
return "regexp:" + m.pattern.String()
}
v2ray-core-4.34.0/common/strmatcher/matchers_test.go 0000664 0000000 0000000 00000002334 13774574720 0022455 0 ustar 00root root 0000000 0000000 package strmatcher_test
import (
"testing"
"v2ray.com/core/common"
. "v2ray.com/core/common/strmatcher"
)
func TestMatcher(t *testing.T) {
cases := []struct {
pattern string
mType Type
input string
output bool
}{
{
pattern: "v2ray.com",
mType: Domain,
input: "www.v2ray.com",
output: true,
},
{
pattern: "v2ray.com",
mType: Domain,
input: "v2ray.com",
output: true,
},
{
pattern: "v2ray.com",
mType: Domain,
input: "www.v3ray.com",
output: false,
},
{
pattern: "v2ray.com",
mType: Domain,
input: "2ray.com",
output: false,
},
{
pattern: "v2ray.com",
mType: Domain,
input: "xv2ray.com",
output: false,
},
{
pattern: "v2ray.com",
mType: Full,
input: "v2ray.com",
output: true,
},
{
pattern: "v2ray.com",
mType: Full,
input: "xv2ray.com",
output: false,
},
{
pattern: "v2ray.com",
mType: Regex,
input: "v2rayxcom",
output: true,
},
}
for _, test := range cases {
matcher, err := test.mType.New(test.pattern)
common.Must(err)
if m := matcher.Match(test.input); m != test.output {
t.Error("unexpected output: ", m, " for test case ", test)
}
}
}
v2ray-core-4.34.0/common/strmatcher/strmatcher.go 0000664 0000000 0000000 00000005073 13774574720 0021767 0 ustar 00root root 0000000 0000000 package strmatcher
import (
"regexp"
)
// Matcher is the interface to determine a string matches a pattern.
type Matcher interface {
// Match returns true if the given string matches a predefined pattern.
Match(string) bool
String() string
}
// Type is the type of the matcher.
type Type byte
const (
// Full is the type of matcher that the input string must exactly equal to the pattern.
Full Type = iota
// Substr is the type of matcher that the input string must contain the pattern as a sub-string.
Substr
// Domain is the type of matcher that the input string must be a sub-domain or itself of the pattern.
Domain
// Regex is the type of matcher that the input string must matches the regular-expression pattern.
Regex
)
// New creates a new Matcher based on the given pattern.
func (t Type) New(pattern string) (Matcher, error) {
switch t {
case Full:
return fullMatcher(pattern), nil
case Substr:
return substrMatcher(pattern), nil
case Domain:
return domainMatcher(pattern), nil
case Regex:
r, err := regexp.Compile(pattern)
if err != nil {
return nil, err
}
return ®exMatcher{
pattern: r,
}, nil
default:
panic("Unknown type")
}
}
// IndexMatcher is the interface for matching with a group of matchers.
type IndexMatcher interface {
// Match returns the index of a matcher that matches the input. It returns empty array if no such matcher exists.
Match(input string) []uint32
}
type matcherEntry struct {
m Matcher
id uint32
}
// MatcherGroup is an implementation of IndexMatcher.
// Empty initialization works.
type MatcherGroup struct {
count uint32
fullMatcher FullMatcherGroup
domainMatcher DomainMatcherGroup
otherMatchers []matcherEntry
}
// Add adds a new Matcher into the MatcherGroup, and returns its index. The index will never be 0.
func (g *MatcherGroup) Add(m Matcher) uint32 {
g.count++
c := g.count
switch tm := m.(type) {
case fullMatcher:
g.fullMatcher.addMatcher(tm, c)
case domainMatcher:
g.domainMatcher.addMatcher(tm, c)
default:
g.otherMatchers = append(g.otherMatchers, matcherEntry{
m: m,
id: c,
})
}
return c
}
// Match implements IndexMatcher.Match.
func (g *MatcherGroup) Match(pattern string) []uint32 {
result := []uint32{}
result = append(result, g.fullMatcher.Match(pattern)...)
result = append(result, g.domainMatcher.Match(pattern)...)
for _, e := range g.otherMatchers {
if e.m.Match(pattern) {
result = append(result, e.id)
}
}
return result
}
// Size returns the number of matchers in the MatcherGroup.
func (g *MatcherGroup) Size() uint32 {
return g.count
}
v2ray-core-4.34.0/common/strmatcher/strmatcher_test.go 0000664 0000000 0000000 00000003060 13774574720 0023020 0 ustar 00root root 0000000 0000000 package strmatcher_test
import (
"reflect"
"testing"
"v2ray.com/core/common"
. "v2ray.com/core/common/strmatcher"
)
// See https://github.com/v2fly/v2ray-core/issues/92#issuecomment-673238489
func TestMatcherGroup(t *testing.T) {
rules := []struct {
Type Type
Domain string
}{
{
Type: Regex,
Domain: "apis\\.us$",
},
{
Type: Substr,
Domain: "apis",
},
{
Type: Domain,
Domain: "googleapis.com",
},
{
Type: Domain,
Domain: "com",
},
{
Type: Full,
Domain: "www.baidu.com",
},
{
Type: Substr,
Domain: "apis",
},
{
Type: Domain,
Domain: "googleapis.com",
},
{
Type: Full,
Domain: "fonts.googleapis.com",
},
{
Type: Full,
Domain: "www.baidu.com",
},
{
Type: Domain,
Domain: "example.com",
},
}
cases := []struct {
Input string
Output []uint32
}{
{
Input: "www.baidu.com",
Output: []uint32{5, 9, 4},
},
{
Input: "fonts.googleapis.com",
Output: []uint32{8, 3, 7, 4, 2, 6},
},
{
Input: "example.googleapis.com",
Output: []uint32{3, 7, 4, 2, 6},
},
{
Input: "testapis.us",
Output: []uint32{1, 2, 6},
},
{
Input: "example.com",
Output: []uint32{10, 4},
},
}
matcherGroup := &MatcherGroup{}
for _, rule := range rules {
matcher, err := rule.Type.New(rule.Domain)
common.Must(err)
matcherGroup.Add(matcher)
}
for _, test := range cases {
if m := matcherGroup.Match(test.Input); !reflect.DeepEqual(m, test.Output) {
t.Error("unexpected output: ", m, " for test case ", test)
}
}
}
v2ray-core-4.34.0/common/task/ 0000775 0000000 0000000 00000000000 13774574720 0016045 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/task/common.go 0000664 0000000 0000000 00000000265 13774574720 0017667 0 ustar 00root root 0000000 0000000 package task
import "v2ray.com/core/common"
// Close returns a func() that closes v.
func Close(v interface{}) func() error {
return func() error {
return common.Close(v)
}
}
v2ray-core-4.34.0/common/task/periodic.go 0000664 0000000 0000000 00000002360 13774574720 0020173 0 ustar 00root root 0000000 0000000 package task
import (
"sync"
"time"
)
// Periodic is a task that runs periodically.
type Periodic struct {
// Interval of the task being run
Interval time.Duration
// Execute is the task function
Execute func() error
access sync.Mutex
timer *time.Timer
running bool
}
func (t *Periodic) hasClosed() bool {
t.access.Lock()
defer t.access.Unlock()
return !t.running
}
func (t *Periodic) checkedExecute() error {
if t.hasClosed() {
return nil
}
if err := t.Execute(); err != nil {
t.access.Lock()
t.running = false
t.access.Unlock()
return err
}
t.access.Lock()
defer t.access.Unlock()
if !t.running {
return nil
}
t.timer = time.AfterFunc(t.Interval, func() {
t.checkedExecute()
})
return nil
}
// Start implements common.Runnable.
func (t *Periodic) Start() error {
t.access.Lock()
if t.running {
t.access.Unlock()
return nil
}
t.running = true
t.access.Unlock()
if err := t.checkedExecute(); err != nil {
t.access.Lock()
t.running = false
t.access.Unlock()
return err
}
return nil
}
// Close implements common.Closable.
func (t *Periodic) Close() error {
t.access.Lock()
defer t.access.Unlock()
t.running = false
if t.timer != nil {
t.timer.Stop()
t.timer = nil
}
return nil
}
v2ray-core-4.34.0/common/task/periodic_test.go 0000664 0000000 0000000 00000001206 13774574720 0021230 0 ustar 00root root 0000000 0000000 package task_test
import (
"testing"
"time"
"v2ray.com/core/common"
. "v2ray.com/core/common/task"
)
func TestPeriodicTaskStop(t *testing.T) {
value := 0
task := &Periodic{
Interval: time.Second * 2,
Execute: func() error {
value++
return nil
},
}
common.Must(task.Start())
time.Sleep(time.Second * 5)
common.Must(task.Close())
if value != 3 {
t.Fatal("expected 3, but got ", value)
}
time.Sleep(time.Second * 4)
if value != 3 {
t.Fatal("expected 3, but got ", value)
}
common.Must(task.Start())
time.Sleep(time.Second * 3)
if value != 5 {
t.Fatal("Expected 5, but ", value)
}
common.Must(task.Close())
}
v2ray-core-4.34.0/common/task/task.go 0000664 0000000 0000000 00000001552 13774574720 0017341 0 ustar 00root root 0000000 0000000 package task
import (
"context"
"v2ray.com/core/common/signal/semaphore"
)
// OnSuccess executes g() after f() returns nil.
func OnSuccess(f func() error, g func() error) func() error {
return func() error {
if err := f(); err != nil {
return err
}
return g()
}
}
// Run executes a list of tasks in parallel, returns the first error encountered or nil if all tasks pass.
func Run(ctx context.Context, tasks ...func() error) error {
n := len(tasks)
s := semaphore.New(n)
done := make(chan error, 1)
for _, task := range tasks {
<-s.Wait()
go func(f func() error) {
err := f()
if err == nil {
s.Signal()
return
}
select {
case done <- err:
default:
}
}(task)
}
for i := 0; i < n; i++ {
select {
case err := <-done:
return err
case <-ctx.Done():
return ctx.Err()
case <-s.Wait():
}
}
return nil
}
v2ray-core-4.34.0/common/task/task_test.go 0000664 0000000 0000000 00000002455 13774574720 0020403 0 ustar 00root root 0000000 0000000 package task_test
import (
"context"
"errors"
"strings"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
. "v2ray.com/core/common/task"
)
func TestExecuteParallel(t *testing.T) {
err := Run(context.Background(),
func() error {
time.Sleep(time.Millisecond * 200)
return errors.New("test")
}, func() error {
time.Sleep(time.Millisecond * 500)
return errors.New("test2")
})
if r := cmp.Diff(err.Error(), "test"); r != "" {
t.Error(r)
}
}
func TestExecuteParallelContextCancel(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
err := Run(ctx, func() error {
time.Sleep(time.Millisecond * 2000)
return errors.New("test")
}, func() error {
time.Sleep(time.Millisecond * 5000)
return errors.New("test2")
}, func() error {
cancel()
return nil
})
errStr := err.Error()
if !strings.Contains(errStr, "canceled") {
t.Error("expected error string to contain 'canceled', but actually not: ", errStr)
}
}
func BenchmarkExecuteOne(b *testing.B) {
noop := func() error {
return nil
}
for i := 0; i < b.N; i++ {
common.Must(Run(context.Background(), noop))
}
}
func BenchmarkExecuteTwo(b *testing.B) {
noop := func() error {
return nil
}
for i := 0; i < b.N; i++ {
common.Must(Run(context.Background(), noop, noop))
}
}
v2ray-core-4.34.0/common/type.go 0000664 0000000 0000000 00000002075 13774574720 0016417 0 ustar 00root root 0000000 0000000 package common
import (
"context"
"reflect"
)
// ConfigCreator is a function to create an object by a config.
type ConfigCreator func(ctx context.Context, config interface{}) (interface{}, error)
var (
typeCreatorRegistry = make(map[reflect.Type]ConfigCreator)
)
// RegisterConfig registers a global config creator. The config can be nil but must have a type.
func RegisterConfig(config interface{}, configCreator ConfigCreator) error {
configType := reflect.TypeOf(config)
if _, found := typeCreatorRegistry[configType]; found {
return newError(configType.Name() + " is already registered").AtError()
}
typeCreatorRegistry[configType] = configCreator
return nil
}
// CreateObject creates an object by its config. The config type must be registered through RegisterConfig().
func CreateObject(ctx context.Context, config interface{}) (interface{}, error) {
configType := reflect.TypeOf(config)
creator, found := typeCreatorRegistry[configType]
if !found {
return nil, newError(configType.String() + " is not registered").AtError()
}
return creator(ctx, config)
}
v2ray-core-4.34.0/common/type_test.go 0000664 0000000 0000000 00000001425 13774574720 0017454 0 ustar 00root root 0000000 0000000 package common_test
import (
"context"
"testing"
. "v2ray.com/core/common"
)
type TConfig struct {
value int
}
type YConfig struct {
value string
}
func TestObjectCreation(t *testing.T) {
var f = func(ctx context.Context, t interface{}) (interface{}, error) {
return func() int {
return t.(*TConfig).value
}, nil
}
Must(RegisterConfig((*TConfig)(nil), f))
err := RegisterConfig((*TConfig)(nil), f)
if err == nil {
t.Error("expect non-nil error, but got nil")
}
g, err := CreateObject(context.Background(), &TConfig{value: 2})
Must(err)
if v := g.(func() int)(); v != 2 {
t.Error("expect return value 2, but got ", v)
}
_, err = CreateObject(context.Background(), &YConfig{value: "T"})
if err == nil {
t.Error("expect non-nil error, but got nil")
}
}
v2ray-core-4.34.0/common/uuid/ 0000775 0000000 0000000 00000000000 13774574720 0016051 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/common/uuid/uuid.go 0000664 0000000 0000000 00000003427 13774574720 0017354 0 ustar 00root root 0000000 0000000 package uuid // import "v2ray.com/core/common/uuid"
import (
"bytes"
"crypto/rand"
"encoding/hex"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
)
var (
byteGroups = []int{8, 4, 4, 4, 12}
)
type UUID [16]byte
// String returns the string representation of this UUID.
func (u *UUID) String() string {
bytes := u.Bytes()
result := hex.EncodeToString(bytes[0 : byteGroups[0]/2])
start := byteGroups[0] / 2
for i := 1; i < len(byteGroups); i++ {
nBytes := byteGroups[i] / 2
result += "-"
result += hex.EncodeToString(bytes[start : start+nBytes])
start += nBytes
}
return result
}
// Bytes returns the bytes representation of this UUID.
func (u *UUID) Bytes() []byte {
return u[:]
}
// Equals returns true if this UUID equals another UUID by value.
func (u *UUID) Equals(another *UUID) bool {
if u == nil && another == nil {
return true
}
if u == nil || another == nil {
return false
}
return bytes.Equal(u.Bytes(), another.Bytes())
}
// New creates a UUID with random value.
func New() UUID {
var uuid UUID
common.Must2(rand.Read(uuid.Bytes()))
return uuid
}
// ParseBytes converts a UUID in byte form to object.
func ParseBytes(b []byte) (UUID, error) {
var uuid UUID
if len(b) != 16 {
return uuid, errors.New("invalid UUID: ", b)
}
copy(uuid[:], b)
return uuid, nil
}
// ParseString converts a UUID in string form to object.
func ParseString(str string) (UUID, error) {
var uuid UUID
text := []byte(str)
if len(text) < 32 {
return uuid, errors.New("invalid UUID: ", str)
}
b := uuid.Bytes()
for _, byteGroup := range byteGroups {
if text[0] == '-' {
text = text[1:]
}
if _, err := hex.Decode(b[:byteGroup/2], text[:byteGroup]); err != nil {
return uuid, err
}
text = text[byteGroup:]
b = b[byteGroup/2:]
}
return uuid, nil
}
v2ray-core-4.34.0/common/uuid/uuid_test.go 0000664 0000000 0000000 00000003316 13774574720 0020410 0 ustar 00root root 0000000 0000000 package uuid_test
import (
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
. "v2ray.com/core/common/uuid"
)
func TestParseBytes(t *testing.T) {
str := "2418d087-648d-4990-86e8-19dca1d006d3"
bytes := []byte{0x24, 0x18, 0xd0, 0x87, 0x64, 0x8d, 0x49, 0x90, 0x86, 0xe8, 0x19, 0xdc, 0xa1, 0xd0, 0x06, 0xd3}
uuid, err := ParseBytes(bytes)
common.Must(err)
if diff := cmp.Diff(uuid.String(), str); diff != "" {
t.Error(diff)
}
_, err = ParseBytes([]byte{1, 3, 2, 4})
if err == nil {
t.Fatal("Expect error but nil")
}
}
func TestParseString(t *testing.T) {
str := "2418d087-648d-4990-86e8-19dca1d006d3"
expectedBytes := []byte{0x24, 0x18, 0xd0, 0x87, 0x64, 0x8d, 0x49, 0x90, 0x86, 0xe8, 0x19, 0xdc, 0xa1, 0xd0, 0x06, 0xd3}
uuid, err := ParseString(str)
common.Must(err)
if r := cmp.Diff(expectedBytes, uuid.Bytes()); r != "" {
t.Fatal(r)
}
_, err = ParseString("2418d087")
if err == nil {
t.Fatal("Expect error but nil")
}
_, err = ParseString("2418d087-648k-4990-86e8-19dca1d006d3")
if err == nil {
t.Fatal("Expect error but nil")
}
}
func TestNewUUID(t *testing.T) {
uuid := New()
uuid2, err := ParseString(uuid.String())
common.Must(err)
if uuid.String() != uuid2.String() {
t.Error("uuid string: ", uuid.String(), " != ", uuid2.String())
}
if r := cmp.Diff(uuid.Bytes(), uuid2.Bytes()); r != "" {
t.Error(r)
}
}
func TestRandom(t *testing.T) {
uuid := New()
uuid2 := New()
if uuid.String() == uuid2.String() {
t.Error("duplicated uuid")
}
}
func TestEquals(t *testing.T) {
var uuid *UUID
var uuid2 *UUID
if !uuid.Equals(uuid2) {
t.Error("empty uuid should equal")
}
uuid3 := New()
if uuid.Equals(&uuid3) {
t.Error("nil uuid equals non-nil uuid")
}
}
v2ray-core-4.34.0/config.go 0000664 0000000 0000000 00000005130 13774574720 0015406 0 ustar 00root root 0000000 0000000 // +build !confonly
package core
import (
"io"
"strings"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/cmdarg"
"v2ray.com/core/main/confloader"
)
// ConfigFormat is a configurable format of V2Ray config file.
type ConfigFormat struct {
Name string
Extension []string
Loader ConfigLoader
}
// ConfigLoader is a utility to load V2Ray config from external source.
type ConfigLoader func(input interface{}) (*Config, error)
var (
configLoaderByName = make(map[string]*ConfigFormat)
configLoaderByExt = make(map[string]*ConfigFormat)
)
// RegisterConfigLoader add a new ConfigLoader.
func RegisterConfigLoader(format *ConfigFormat) error {
name := strings.ToLower(format.Name)
if _, found := configLoaderByName[name]; found {
return newError(format.Name, " already registered.")
}
configLoaderByName[name] = format
for _, ext := range format.Extension {
lext := strings.ToLower(ext)
if f, found := configLoaderByExt[lext]; found {
return newError(ext, " already registered to ", f.Name)
}
configLoaderByExt[lext] = format
}
return nil
}
func getExtension(filename string) string {
idx := strings.LastIndexByte(filename, '.')
if idx == -1 {
return ""
}
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)
}
}
if f, found := configLoaderByName[formatName]; found {
return f.Loader(input)
}
return nil, newError("Unable to load config in ", formatName).AtWarning()
}
func loadProtobufConfig(data []byte) (*Config, error) {
config := new(Config)
if err := proto.Unmarshal(data, config); err != nil {
return nil, err
}
return config, nil
}
func init() {
common.Must(RegisterConfigLoader(&ConfigFormat{
Name: "Protobuf",
Extension: []string{"pb"},
Loader: func(input interface{}) (*Config, error) {
switch v := input.(type) {
case cmdarg.Arg:
r, err := confloader.LoadConfig(v[0])
common.Must(err)
data, err := buf.ReadAllToBytes(r)
common.Must(err)
return loadProtobufConfig(data)
case io.Reader:
data, err := buf.ReadAllToBytes(v)
common.Must(err)
return loadProtobufConfig(data)
default:
return nil, newError("unknow type")
}
},
}))
}
v2ray-core-4.34.0/config.pb.go 0000664 0000000 0000000 00000041716 13774574720 0016020 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: config.proto
package core
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
serial "v2ray.com/core/common/serial"
transport "v2ray.com/core/transport"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// Config is the master config of V2Ray. V2Ray takes this config as input and
// functions accordingly.
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Inbound handler configurations. Must have at least one item.
Inbound []*InboundHandlerConfig `protobuf:"bytes,1,rep,name=inbound,proto3" json:"inbound,omitempty"`
// Outbound handler configurations. Must have at least one item. The first
// item is used as default for routing.
Outbound []*OutboundHandlerConfig `protobuf:"bytes,2,rep,name=outbound,proto3" json:"outbound,omitempty"`
// App is for configurations of all features in V2Ray. A feature must
// implement the Feature interface, and its config type must be registered
// through common.RegisterConfig.
App []*serial.TypedMessage `protobuf:"bytes,4,rep,name=app,proto3" json:"app,omitempty"`
// Transport settings.
// Deprecated. Each inbound and outbound should choose their own transport
// config. Date to remove: 2020-01-13
//
// Deprecated: Do not use.
Transport *transport.Config `protobuf:"bytes,5,opt,name=transport,proto3" json:"transport,omitempty"`
// Configuration for extensions. The config may not work if corresponding
// extension is not loaded into V2Ray. V2Ray will ignore such config during
// initialization.
Extension []*serial.TypedMessage `protobuf:"bytes,6,rep,name=extension,proto3" json:"extension,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetInbound() []*InboundHandlerConfig {
if x != nil {
return x.Inbound
}
return nil
}
func (x *Config) GetOutbound() []*OutboundHandlerConfig {
if x != nil {
return x.Outbound
}
return nil
}
func (x *Config) GetApp() []*serial.TypedMessage {
if x != nil {
return x.App
}
return nil
}
// Deprecated: Do not use.
func (x *Config) GetTransport() *transport.Config {
if x != nil {
return x.Transport
}
return nil
}
func (x *Config) GetExtension() []*serial.TypedMessage {
if x != nil {
return x.Extension
}
return nil
}
// InboundHandlerConfig is the configuration for inbound handler.
type InboundHandlerConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Tag of the inbound handler. The tag must be unique among all inbound
// handlers
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
// Settings for how this inbound proxy is handled.
ReceiverSettings *serial.TypedMessage `protobuf:"bytes,2,opt,name=receiver_settings,json=receiverSettings,proto3" json:"receiver_settings,omitempty"`
// Settings for inbound proxy. Must be one of the inbound proxies.
ProxySettings *serial.TypedMessage `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"`
}
func (x *InboundHandlerConfig) Reset() {
*x = InboundHandlerConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *InboundHandlerConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*InboundHandlerConfig) ProtoMessage() {}
func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
mi := &file_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use InboundHandlerConfig.ProtoReflect.Descriptor instead.
func (*InboundHandlerConfig) Descriptor() ([]byte, []int) {
return file_config_proto_rawDescGZIP(), []int{1}
}
func (x *InboundHandlerConfig) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
func (x *InboundHandlerConfig) GetReceiverSettings() *serial.TypedMessage {
if x != nil {
return x.ReceiverSettings
}
return nil
}
func (x *InboundHandlerConfig) GetProxySettings() *serial.TypedMessage {
if x != nil {
return x.ProxySettings
}
return nil
}
// OutboundHandlerConfig is the configuration for outbound handler.
type OutboundHandlerConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Tag of this outbound handler.
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
// Settings for how to dial connection for this outbound handler.
SenderSettings *serial.TypedMessage `protobuf:"bytes,2,opt,name=sender_settings,json=senderSettings,proto3" json:"sender_settings,omitempty"`
// Settings for this outbound proxy. Must be one of the outbound proxies.
ProxySettings *serial.TypedMessage `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"`
// If not zero, this outbound will be expired in seconds. Not used for now.
Expire int64 `protobuf:"varint,4,opt,name=expire,proto3" json:"expire,omitempty"`
// Comment of this outbound handler. Not used for now.
Comment string `protobuf:"bytes,5,opt,name=comment,proto3" json:"comment,omitempty"`
}
func (x *OutboundHandlerConfig) Reset() {
*x = OutboundHandlerConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *OutboundHandlerConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OutboundHandlerConfig) ProtoMessage() {}
func (x *OutboundHandlerConfig) ProtoReflect() protoreflect.Message {
mi := &file_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OutboundHandlerConfig.ProtoReflect.Descriptor instead.
func (*OutboundHandlerConfig) Descriptor() ([]byte, []int) {
return file_config_proto_rawDescGZIP(), []int{2}
}
func (x *OutboundHandlerConfig) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
func (x *OutboundHandlerConfig) GetSenderSettings() *serial.TypedMessage {
if x != nil {
return x.SenderSettings
}
return nil
}
func (x *OutboundHandlerConfig) GetProxySettings() *serial.TypedMessage {
if x != nil {
return x.ProxySettings
}
return nil
}
func (x *OutboundHandlerConfig) GetExpire() int64 {
if x != nil {
return x.Expire
}
return 0
}
func (x *OutboundHandlerConfig) GetComment() string {
if x != nil {
return x.Comment
}
return ""
}
var File_config_proto protoreflect.FileDescriptor
var file_config_proto_rawDesc = []byte{
0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x16, 0x74,
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc9, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x12, 0x3a, 0x0a, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49,
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x3d, 0x0a, 0x08,
0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21,
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x38, 0x0a, 0x03, 0x61,
0x70, 0x70, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72,
0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x52, 0x03, 0x61, 0x70, 0x70, 0x12, 0x3e, 0x0a, 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x44, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
0x6f, 0x6e, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72,
0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4a, 0x04, 0x08, 0x03, 0x10,
0x04, 0x22, 0xcc, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e,
0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x53, 0x0a, 0x11,
0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x73, 0x12, 0x4d, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65,
0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x22, 0xfb, 0x01, 0x0a, 0x15, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e,
0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x4f, 0x0a, 0x0f,
0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,
0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0e, 0x73,
0x65, 0x6e, 0x64, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4d, 0x0a,
0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,
0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x16, 0x0a, 0x06,
0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x65, 0x78,
0x70, 0x69, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18,
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x2f,
0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x50, 0x01, 0x5a, 0x0e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f,
0x72, 0x65, 0xaa, 0x02, 0x0a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_config_proto_rawDescOnce sync.Once
file_config_proto_rawDescData = file_config_proto_rawDesc
)
func file_config_proto_rawDescGZIP() []byte {
file_config_proto_rawDescOnce.Do(func() {
file_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_config_proto_rawDescData)
})
return file_config_proto_rawDescData
}
var file_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: v2ray.core.Config
(*InboundHandlerConfig)(nil), // 1: v2ray.core.InboundHandlerConfig
(*OutboundHandlerConfig)(nil), // 2: v2ray.core.OutboundHandlerConfig
(*serial.TypedMessage)(nil), // 3: v2ray.core.common.serial.TypedMessage
(*transport.Config)(nil), // 4: v2ray.core.transport.Config
}
var file_config_proto_depIdxs = []int32{
1, // 0: v2ray.core.Config.inbound:type_name -> v2ray.core.InboundHandlerConfig
2, // 1: v2ray.core.Config.outbound:type_name -> v2ray.core.OutboundHandlerConfig
3, // 2: v2ray.core.Config.app:type_name -> v2ray.core.common.serial.TypedMessage
4, // 3: v2ray.core.Config.transport:type_name -> v2ray.core.transport.Config
3, // 4: v2ray.core.Config.extension:type_name -> v2ray.core.common.serial.TypedMessage
3, // 5: v2ray.core.InboundHandlerConfig.receiver_settings:type_name -> v2ray.core.common.serial.TypedMessage
3, // 6: v2ray.core.InboundHandlerConfig.proxy_settings:type_name -> v2ray.core.common.serial.TypedMessage
3, // 7: v2ray.core.OutboundHandlerConfig.sender_settings:type_name -> v2ray.core.common.serial.TypedMessage
3, // 8: v2ray.core.OutboundHandlerConfig.proxy_settings:type_name -> v2ray.core.common.serial.TypedMessage
9, // [9:9] is the sub-list for method output_type
9, // [9:9] is the sub-list for method input_type
9, // [9:9] is the sub-list for extension type_name
9, // [9:9] is the sub-list for extension extendee
0, // [0:9] is the sub-list for field type_name
}
func init() { file_config_proto_init() }
func file_config_proto_init() {
if File_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*InboundHandlerConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*OutboundHandlerConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_config_proto_goTypes,
DependencyIndexes: file_config_proto_depIdxs,
MessageInfos: file_config_proto_msgTypes,
}.Build()
File_config_proto = out.File
file_config_proto_rawDesc = nil
file_config_proto_goTypes = nil
file_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/config.proto 0000664 0000000 0000000 00000004575 13774574720 0016160 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core;
option csharp_namespace = "V2Ray.Core";
option go_package = "v2ray.com/core";
option java_package = "com.v2ray.core";
option java_multiple_files = true;
import "common/serial/typed_message.proto";
import "transport/config.proto";
// Config is the master config of V2Ray. V2Ray takes this config as input and
// functions accordingly.
message Config {
// Inbound handler configurations. Must have at least one item.
repeated InboundHandlerConfig inbound = 1;
// Outbound handler configurations. Must have at least one item. The first
// item is used as default for routing.
repeated OutboundHandlerConfig outbound = 2;
reserved 3;
// App is for configurations of all features in V2Ray. A feature must
// implement the Feature interface, and its config type must be registered
// through common.RegisterConfig.
repeated v2ray.core.common.serial.TypedMessage app = 4;
// Transport settings.
// Deprecated. Each inbound and outbound should choose their own transport
// config. Date to remove: 2020-01-13
v2ray.core.transport.Config transport = 5 [deprecated = true];
// Configuration for extensions. The config may not work if corresponding
// extension is not loaded into V2Ray. V2Ray will ignore such config during
// initialization.
repeated v2ray.core.common.serial.TypedMessage extension = 6;
}
// InboundHandlerConfig is the configuration for inbound handler.
message InboundHandlerConfig {
// Tag of the inbound handler. The tag must be unique among all inbound
// handlers
string tag = 1;
// Settings for how this inbound proxy is handled.
v2ray.core.common.serial.TypedMessage receiver_settings = 2;
// Settings for inbound proxy. Must be one of the inbound proxies.
v2ray.core.common.serial.TypedMessage proxy_settings = 3;
}
// OutboundHandlerConfig is the configuration for outbound handler.
message OutboundHandlerConfig {
// Tag of this outbound handler.
string tag = 1;
// Settings for how to dial connection for this outbound handler.
v2ray.core.common.serial.TypedMessage sender_settings = 2;
// Settings for this outbound proxy. Must be one of the outbound proxies.
v2ray.core.common.serial.TypedMessage proxy_settings = 3;
// If not zero, this outbound will be expired in seconds. Not used for now.
int64 expire = 4;
// Comment of this outbound handler. Not used for now.
string comment = 5;
}
v2ray-core-4.34.0/context.go 0000664 0000000 0000000 00000001175 13774574720 0015632 0 ustar 00root root 0000000 0000000 // +build !confonly
package core
import (
"context"
)
// V2rayKey is the key type of Instance in Context, exported for test.
type V2rayKey int
const v2rayKey V2rayKey = 1
// FromContext returns an Instance from the given context, or nil if the context doesn't contain one.
func FromContext(ctx context.Context) *Instance {
if s, ok := ctx.Value(v2rayKey).(*Instance); ok {
return s
}
return nil
}
// MustFromContext returns an Instance from the given context, or panics if not present.
func MustFromContext(ctx context.Context) *Instance {
v := FromContext(ctx)
if v == nil {
panic("V is not in context.")
}
return v
}
v2ray-core-4.34.0/context_test.go 0000664 0000000 0000000 00000000370 13774574720 0016665 0 ustar 00root root 0000000 0000000 package core_test
import (
"context"
"testing"
. "v2ray.com/core"
)
func TestContextPanic(t *testing.T) {
defer func() {
r := recover()
if r == nil {
t.Error("expect panic, but nil")
}
}()
MustFromContext(context.Background())
}
v2ray-core-4.34.0/core.go 0000664 0000000 0000000 00000273177 13774574720 0015113 0 ustar 00root root 0000000 0000000 // Package core provides an entry point to use V2Ray core functionalities.
//
// V2Ray makes it possible to accept incoming network connections with certain
// protocol, process the data, and send them through another connection with
// the same or a difference protocol on demand.
//
// It may be configured to work with multiple protocols at the same time, and
// uses the internal router to tunnel through different inbound and outbound
// connections.
package core
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"runtime"
"v2ray.com/core/common/serial"
)
var (
version = "4.34.0"
build = "Custom"
codename = "V2Fly, a community-driven edition of V2Ray."
intro = "A unified platform for anti-censorship."
)
// Version returns V2Ray's version as a string, in the form of "x.y.z" where x, y and z are numbers.
// ".z" part may be omitted in regular releases.
func Version() string {
return version
}
// VersionStatement returns a list of strings representing the full version info.
func VersionStatement() []string {
return []string{
serial.Concat("V2Ray ", Version(), " (", codename, ") ", build, " (", runtime.Version(), " ", runtime.GOOS, "/", runtime.GOARCH, ")"),
intro,
}
}
/*
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::c:::::::::::::::::::::::ccc:::cccc::::::c:::::cccc::::cc::::::::::::::::::::::::ccccccc::cccccccccc::cc:::;:::::::::::::::::::::::::::ccc:::cccc:ccc::::::c:::::::::::::::::::::::::::cccc:cccccccccccccccccccccc:;;::::::::::::::::::c::::ccc::::::ccc:::ccc::cccccc::::cc:cc:::ccccccccccccccccccccccccccccccccccccccc
:::;::::::::::::::::::::::::::::::::::::::::::::::cc:::::::::::::::::::::::::::::::::::::ccc::cc:::::c:::::::::::ccc::ccc:::::ccc::::::cc:::::cccc:::::::::::::::::::::cccccccccccccccccccccccccc:::::::::::::::::::::::::cc::ccc::::::::::::::c::c::::::::::::c::::::::c::::::cccccccccccccccccccccccccc:;:::::::::::::::ccc::cccccccc::c:cccc::cc:::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::cc::::::::cc::::::::::::ccccc:::::ccccccccc::cccc::ccccccc:::c::::::::c:c:::::cccccccccccccccccccccccccc::::::::::::::::::::::::cc:::::ccc:::c::::::::::::::::c::::::::::::::::::::::ccccccccccccccccccccccccccc:::::::::::::::::::::cccccc:ccccc::ccccccccc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
::;;::::::::::::::::::::::::::::::::::::::::::::::::::::::::c:::::::::::::::::::::cc::::::::::::::::c:::cc::::c::::::::cccccc::::cccccccccc::ccccccc::c::::::::c::::::::ccccccccccccccccccccccccc:::::::::::::::::::::::::c::::cccc:::cc:::cc:::::::::::::::::::::::::::c::::::ccccccccccccccccccccccccccc::::::::::::::::::::cccc::cccccc:ccc:cccccccccccccccc:cccccccccccccccccccccccccccccccccccccccccccccccc
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::cc:::::::::::::::ccc:::::c:::cc::::::::::::::::::::::cc:::c::cccc::::::::::cccccccccccc:ccc::c:::::::ccc:::::::cccccccccccccccccccccccccc:::::::::::::::::::cccccccccccccc::::::::ccc::c::cc:::cc::::::::::::::cc:::::cccccccccccccccccccccccccccc::::::::::::::::::::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
::::::::::::::::::::::::::::::::::::::::::::::::::::::c::::::::::::::::::::c::::::::::::::::::::ccccc::::::::::::ccc::cc:::::cccc::::cccccccccccc::::cccccc:::ccccc:::::cccccccccccccccccccccccccc::::::::::::::::::::c:cc:::cc::::::::::::cc::cc:::::::cccc::::::c:::::cc::::::ccccccccccccccccccccccccccc:::::::::ccc::::::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::cc:::::::::::::::ccccccc:::::ccccc::ccc::ccccccccccccccccccccccccccccccc:cccc::::cccccc::::cccccccccccccccccccccccccc::::::::::::::::c:::::cc::::::::cc:::cccc::::cc::::ccc:ccc::c:::::::::cccc::::ccccccccccccccccccccccccccc::::::::::cc::::::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
::::::::::::::::::::::::::::::::::::::::::::::::::::c::::::::cc::::::::::::::cc:::::::ccccc:::c:::::ccc::cccc:::cccccc:ccccccccccccccccccccccccccccccccccc::::ccccccc:::cccccccccccccccccccccccccc:::::::::cc:::::::::::::cc:::cc::cccccccc::cccccc::ccccccccc:c::::::::ccc:::::cccccccccccccccccccccccccccc:::::::::ccc:::::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
::::::::::::::::::::::::::::::::::::::::::::cc:::::::::ccc:::::c::::::cc:::cccc:::c:::ccccc::::ccc::cccccccccc::cccccc::ccccccccccccccccccccccccccccccccccc:ccccccccc::ccccccccccccccccccccccccccc:::::::::::::::::::::::::cc:cccc::cccccccccccc:ccc::cccccc:ccc::::::::cccc:::::ccccccccccccccccccccccccccc:::::::::ccc:::::c:ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
:::::::::::::::::::::::::::::::::::c:::::::c:::::c:::::cc::::::::::::cccccc::::ccccccccc:::::::ccccccccccccccccccccccc:cccccccccccccccccccccccllccccccccccccccccccccc::cccccccccccccccccccccccccccc:::::::::c:::::::::::ccccccccccccccccccccccc::cc:::::cccccccc:::cc:::ccccc::::ccccccccccccccccccccccccccc:::::::::cccc::::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
:::::::::::::::::::::::::::::cc::cc:::::::c:::::::::::::c:::cc:::::::cccccc::::cccccccc:cc:::ccccccccccccccccccccccccccccccccccccccccccccccoxk00Okxddoolllllloodxkkxdoloolccccccccccccccccccccccccc:::::::::c:::::::::cccccccc::cc::ccccc:::cccccc:ccc:ccccccccc:ccccc:::cc:cc:::ccccccccccccccccccccccccccc:::::::::ccccc:::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
::::::::::::::::::c::::::::ccc:::cc:::::::c::::cc::c::::c:::ccc:::ccc::::::ccc:::ccccccccccccccccccccccccccccccccccccccccccccloxxkOO0OkkkkOKXK00000000KKK0KKXXNNWWWWNXKKK0kdoolclloooddollccccccccc:::::::::cc:::::cccccccccccc:ccccccccc::cccccccccccccc:cccccc:ccccc:::cc:cc:::cccccccccccccccccccccccccccc:::::::cccccc:::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
:::::::::::::::::::::::::::::::::::::::c::ccc:::cc::cc::ccc:::::cc:::cc::::ccc::cccc:cccccccccccccccccccccccccccccccccccccccdkO0KKK0000OOkkOKXXXXXXXXXNNXKXNNNNNNNNNNNXXXXXKKKOO0KKKKKKK0Oxxoolllcc:::::::::cc::::ccc::cccc:cccccccc:ccccccccccccccccccccccccccccccc:cc:::cc:::::ccccccccccccccccccccccccccccc::::::::c::c:::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
:::::::::::::::::::::ccc::::c:::c:ccc::c::ccccc:ccc::::ccccccccc:cc:cccccccccccccc:ccccccccccccccccccccccccccccccccccccccclxOOOO00KKKKKKK00KKXXNNNNXNNNNXXXXXNNNNNNNNNXXKKXXXXXXXXXXXKKXXNXXK00KOdl::::::::ccc:::::cccccccccccc:cccc::ccccccccccccccccccccccccccccc::cc:::ccc:cc::ccccccccccccccccccccccccccccc:::::::cccc::::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
::::::::::::::::::ccccccccc:cc::cccc::ccc:ccccc:ccc:::ccccccccccccccccccccccccc:ccccccccccccccccccccccccccccccccccclok000O0XNNNNNXK00KKXK0K0xxk000KXXXXXNNNNNNNXNNNNNNXXXXXNNXXXXXKX0dodxxxxddxOOxl::::::::cccc::::ccccccccccccccccccccc::cccccccccccccccccccccccccccccc::cccccc:::cccccccccccccccccccccccccccc::::::::ccccc::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
:::::::::::::c::::cccc:::c::ccccccccc::cc:ccccc:ccc::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclx0XNNNXNXXXNNNXKKKKXXX0OOxooddoodkKXKKKKXNXXNXXXXKKKKXX00KXKKXXNNXK0kko:;;::cccccc::::::::ccc::::ccccccccccccccccccccccccccccccccccccccccccccccccccccc::cccccc:::cccccccccccccccccccccccccccc::::::::cccccc:::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
::::::::::::::cc:ccc::ccccc:cccccccccc::cccccccccccccccccccccccccccccc:cccccccccccccccccccccccccccccccccccccccclxKNNNNXOO0KOkO0KXXNXXXXK0kololllol:lO0kkxkOKXXXXK0kkxddxO000OOkOO0KKXNNNXOxl:::coolc::::::::ccc:::ccccccccccccccccccccccccccccccccccccccccccccccccccccc:::cccccc:::ccccccccccccccccccccccccccccc::::ccccccccc::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
:ccc::::::::::cc:c:::cccccccccccccccccccccccccccc:ccccccccccccccccccccccccccccccccccccccccc:ccccccccccccccccccoOXNWWNN0dcllldO0KKXXXXXXXXKxllldkkkxxdlc;;lOK00OOOd:;;;:cdk0OxkxoodxxkOOOOO0Okl,cO0kl::::::::ccc:::ccccccccccccccccccccccccccccccccccccccccccccccccccccccc::cccccc::ccccccccccccccccccccccccccccc:::cc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
::cc:::::::::c::::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccldO00KNNNXKOddk0KXXXXXXXXXXKK0OOOOO0KKxc;,,.;oxxddxkOx:;,;loddxxolddlc::ccccc:;cooox0KKkl:::::ccccc:::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc::ccccccccccccccccccccccccccccc:::::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c:cc:::c::cccccc::ccccccccccc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccldkkxdxkKK000kxkkOO0000OOOOOkdloOKKO0K0dc,...;ccc:lxO0dccclllccloolllc:;;;:cc:;.,:cok0Okkkl::::cccccc:::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc::ccccccccccccccccccccccccccccc:::::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
ccc::::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclx0KK0OxdxOOOxl::codxxdoooolccoxO0K00kdoodl;''',;;;:lxOOdollccc::cc:;;;;,'',;;;;'','';:coxxl::::cccccc:::cccccccccccccccccccccccccccccccccccccccccccccccccccccccc:cccccc::cccccccccccccccccccccccccccccc::c::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllccccccccccccccccccccc
cc:::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccldxOKXNXKOxxdl:;;,,,,,,,ckOx;:k00Okkxolc;;;:;,''',,'',:ok0kocc::,.',,;;;;,''',;,;,...',;:ccc::::::ccccc:::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc::ccccclcccclcccccccccccccccccc::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllcc
ccc::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccooloOKKKK0Oo:;,''..'.. ;xO0OxxOkxdddddoll:;,..,,,,;'.'',:ll:,,,,'..'''',,;;,,,,;;;,',,;;::cc:cccc:ccccc::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc::ccccllccccccclcclllcccccccclcc::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllccccccccccccc
cccc:ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclollxOOOO0Oxl:;'''',;;;cdxodxdoolllldk00Od:,'..,;,;;;,,'.....'',,,,,'''.''''.....,,,''',::ccc:cccc::ccccc:ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc:::cccclcccllcclcccllcccccccclcc:::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllcclcclcccccccccccccccc
ccc:ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclxkxdddxO0Oxdoc;'',;:ldxdlc:coolcc::ldxolc;;::,..,,;;;;;;'...'';cccc::;,,,,,,,'....,',;:oolccccccccccccccc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc::cclcccccllccccclccclcllllclccc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllccccclllcccccccccccccccccccccl
cc::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclxOOxddxkkkdoool:;,.';ccc:::::;::::::cc;;;:cdddo:'''',;;;;;;,,;:codddolc:;;,,,;,,''',,,,;:llllc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllclllcccccccclllllllllllcccccccccccccccccccccccccccccccccccccccccccccccccccllccllccccccllccccccccccccllcccccccllcccccc
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclxkkkkO00koc;,'.';;,...;;::;::;,,;:::::::;;;::::::;'''',,,,;,;;:loxkkOkxdolc:;;;,,,'...',:lllclccccc::cccccc:ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc:cclllllllclllcccclllllllllllcccccccccccccccccccccccccccccccccccccccccccccccccccllcclllcccccccccccccccccllclccllccclccccccc
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccldddkOOO00OOOOxl,.';;'...,;;;;;;,;;;;:::;;::;,'',;;,',,,,,,,,;;:loodxxxxxxxddoolc:;;,...;cdkkdlllc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllcllllllccclllllllclllllcccccccccccccccccccccccllccccccccccclccclcccllccccllcccccccccccccccllcclllccclccllccccccccccc
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccloodOOkkkOOOOOOkxc,;:,. ..',;;;;;;'',,,,,,,;,...,;,,;;;,,,;;;:clllllcc::clodxxddolc;'',;:ccodlccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc:cclllllllllllllllllllllllllllc:ccccccccccccccccccccllccclllcccccccccllcccccccccccccccccclccccccllcccccccclccccccccccccccc
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclollxOkxxxxxxxddddoc;'.... ..,;;;,'....';,.','.',,;::::;;;;;::cloddddooc:;::cclddolc:;:::::cllllc:cccccccclcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclccccc:ccllllllllllllllllllllllllcllc:cccccccccccccccccccccccccllccccccccccccccccccccllccccccllllcccccccccccccccccccccccccccccll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclccdkkxdooollccc:::;'.......... ..,,,;,''',;,.''',,,;:ccc:::::::::::cccclccc::::::cloolllc:ccccccllccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclccccc::cllllllllllllllllllllllllllllc:cccccccccccccccccccccccccccccccccccccccclllllccccclllccccccccccccccccccccccccccllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccoxdxkdl::::::cc;,,''.. .....',,,;;,,,,,'',;;:cloodollc::;;;;:;;,,;;;;::::::c:looooolcclllllllcccccccccccccccccccccccccclllcccccccccccccccccccccccccccclccclccccccccccccccccccccccllllllllllllllllllllllllllllc:cccccccccccccccccccccccccccccclllcclllllllllllcccccccccccccccccccccccccclllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllloooc:;,'',;;,,;:..... ....'',,,,,,,,;;;:ccooddxxxxxdol:;;;:ccc::;;;,;;;;;;clollllllllllllllcccccccccccccccccccclccccclccccccccccccccccccccccclcccccccccllcccclcccccccccccccccccllllllllllllllllllllllllllllccccccccccclcccccccccccclllclllllllllllccclllccccccccccccccccccccccllllllllllllllllllllllll
cccccccccccccccclccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc::;,,;:;.. ';;';c;'';;'. ....'',,,;;;;;;:clodddxxxxkkkkkkxdoddxxdol:,,,,;;,;:oxdlllllllllllllllcccccccccccccccclcccccccclccccclllcccccccccllcccclcccccccclllccccccccccccccccccccccclllllllllllllllllllllllllllcccccccccccccccllcccccccccccclcccccccccccccccccccccccccccccclllllllllllllllllllllllllllllll
ccc::cccccccccccccccccccclccccllcccccccccccclcccccccccccccccccccccccccccccccccccccccccccccccccclccol:;,,''''....','';:;,:;. ...',,,,;;;;;:ccloddxxxxxkkOOOO000Okxddool;'',,;;:loxOkoclllllllllllllcccccccccclccccccccccccccccclccllllllcccccccclcccccccccccclllcccccccccccccccllccccccllllllllllllllllllllllllllllccccccccccccccllccccccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclcccclllccccccccccccccccclllllo:;,,,',,,,,,,,'';::::,. ..',,;;;::::cccooddxxxxkkkOOO00000Okxolllc;;:::coxkO00dllllllllllllllccccccccccccccccccccccllllcclcclllllllcccccclllccccccccccclcccclcccccccccccccccccccclllllllllllllllllllllllllllllcccccccccllccccccccccccccccccccccccccccclllllllllllllllllllllllllllllllllllllllllllllllll
ccccccllccllccccccccccccccccccccccccccccccccccccccccclccccccccccccccccccccclllcclccccccllcccclcclccc:;;;,,,,,,;;;::;;:c::;'. .....',;;:::::ccllloddxxxxxkkkkOOO000000OkxdolooddxkOOO00Oolllllllllllllcccccccccccccccllllcclllllcllcclllllllcllccllllcccccccccccccccccccccccccccccclllcccccllllllllllllllllllllllllllllc:cccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllllllllllllllllllllll
ccccccccccccccclccllccllllllcccclccccccccccccccccccccccccccccccccccccccclllllllllcccllcclllllllcllcc:::::;;,',;;;:cl::lc:;;,,,,'...,;:::ccclollllooddddddxxxxkkkkOO00000OOOOOOO00OOOOO00xlllllllllllllccccccccccclcccclllcclllclccccclccccccccccccccccccccccccccccccccccccccccllcllllllccccllllllllllllllllllllllllllllc:cccccccccccccccccccccllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccclcccllcccclllclllclllllccccccccccccccccccccccccccccccccccccccccccccccccccccccccc:::;''...,;;;::;;:clcc:::::;;,;:::cccloooooooooooodddddddxxxkkOOOOO0000000KKKK00O0KOollllllllllllccccccccccccccccccccccccccccccccccccccccccccccccccllllllllllllllllllllcccccclcccccccclllllllllllllllllllllllllllllc:ccccccccccclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccclllclccclcccllllllllcclllccccccccccccccccccccccccccccccccccc:;,.....,;;;:;;,,;;::clllllcc::ccllllllloooooooooooddddddxxkkkOOOOOOOOOOOOOO00K0KKKxllllllllllllcccccccccccccccccccccccccllllcclllllllllllcclllllllllllllcccllccllllllclccccccccccccccllllllllllllllllllllllllllllccllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccllcccccccccccllcccccclllccllllllllllllllllllllcc:;;,..';:::;;,,'.'',,;::cc:::clloooolloddodddoooooddddddxxxkkOOOOOOOkxodxkO00KKKXXOolllllllllllccccccclccclllllllllllcclllcllllcllllllllllllcccccllllcccccccccccccccllcccccccccccc::clllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllool
llllllllllllccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllclllllllcc:;,..,;;;,,,,,''...',,;;;;;:loooooddddddddddddoooddddddxxxkkkkkkkkkxddOKXXXXKKXXXKxllllllllllllcccccccccccccccllcclllcllccclccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
llllllllllllllllllllllllllllcllccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllccc:,'';:;,,,,,,;,'...',,,,;;;clooddddoodddddddooddooodddddxxxxkkkkkkkOkxkkxdxxkkxxkOkolllllllllllccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllolllllllllllllllllllllllllllooloooloo
llllllllllllllllllllllllllllllllllllllllllllllcllcccccccccccccccccccccccccccccccccccccccccccccccccccccc:,.,cllc:;;;;;;;,,'',;;;;;;:llooddddodddddddddddooooodddddxxxkkkkkO0KOdc;..'',:cccoollllllllllllccccccccccccccccccccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllloollllllllllllllollllolooooooooo
llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllcccccccccccccccccccccccccccccccccc::;;cllol:;;;:::;,'',;;;;;;:clloooodddooddddddoooooodddddddxxxkkOOO00K0ko:;;;:;clllllllllllllllllc:ccccccccccccccccccccclccclllcllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllollllllllllllloooolllllloooooooooollolll
llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllcllollcccc:;,'',;;,,,,;;;;;:::ccllloooooooooooooooooooodddddddxxkkkkkOO0KK0kdlclolllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllollllllllllllllllllllllllllllllllllllllllllllllllllllllllloooollllloollooolllloooooooollooooooloolllllcc
llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllollool::;,;;;:;'..',,,,;;;::::::ccclllllllooooooooooooooddddddddxxxxxdddxO0000Oxllollllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllolllllllllllllllllllllllllllllllllllllllllllllllllllllllllllollllllloollloollloooooooooollooollolllllcccc::::::
lllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllldo:;;:cllll:'...;;;::ccccccccccccccllllllllloooooooooooodddddddddolclooollloollllllllllllllllllllllollllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllooolllloooollllllloooollloooloooooolooooooooolllllcccc::::::::::::::
llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllc:clooooollcc:;..';::clllllolcccccccccccllllllllllllloooooooooddddxkkkxdxxxxoclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllloollllloollllllolllllllllllllllollllllllloooolllooooooolllllllloolloolloooloooolllllcccc::::;:::::::::::::::::
lllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllc:::::::c:::;,',;;:clooooddolcccccccccccccccllllllllloooooooddddxkOOOkdlloddooloollllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllloollllllloolloollllollllllllllllllollooollllllllllloooloooooooolllloollllllloooooolllllllccc::::::;::::::::::::::::cccccccc
lllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllc:::::::::;;,'''.,:cloodddddolcccccccccccllcclccclllllloooooddxxkOOOOkdoccclooooolollllllllllolllllllllllllllllollllllllllllllllllllllllllllllllllllllllllllllllllllllllllloolllllllllllllollooooooooooooolllloooooollllooooollllloooollooooooooooooooooollllllccccc::::::::::::::::::::::::ccccccclllllllo
lllllllllllllllllllllllllllllllllllllllllolllllllllllllllllllllllllllllllllllllllllllllllllllllllllllc::;:::;;::cc:;'.,:coodddxxddolc:cccllllllllllllclllllllllooodxxkO000K00kdoooolllllllllollllllllolllllllllolllloolloolllllllllllllllllllllllolllllllllllllllloolllllllllllllloollllooooolloooooooooooooooooooooooooolllloollooooooooooollooooooollllllcccc:::::::;:::::::::::::::::ccccccclllllllllllllllll
ooollllllllloolllllllllllllllllllllllllooollllllllllllllllllllllllllllllllllllllllllllllllllllllllloolc:;;;:::cclllllc:clodddxxxxxdolc::cccllllllllllllllllllllllooddxkO00KKKKK0kdooollllooloooooollooollllllllloolllllllllllllllllllllllllllllllllllllllllllooolllollllllllllllllllolloollooolooloolooooooooooooooooooooooolooollooooooollllllllccccc::::::::;:::::::::::::::ccccccccllllllllloolllllllllccc:::
lloooolllollloollllllllllllllllllllllllllooollllllllolllllllllllloolllllllllllolloolllllllllllllllllollc:;;:::::::::cclllodddxxxxxxddlc::::ccccccclllllllllllllllllloodxxkOOOOkkxdolooooooooooooolllooolllllllllooollloolllllllloolllooloollloolllllloollllooooollllollloollloolooloooooolloollooooooloooooooooooooooooooooooooollllllccccc:::::::;::::::::::::::::::::ccccccclllllllllloollllllllcccc::::cccccl
ooooolllllllllollllllolllllllolllooolllllloooollllllllllllollllllllllolllllllllllllllllllllllllloolllllccc:c::::::;;::lloodddxxxxkkxxdolcc::ccccccclcclllllllllllllllllloooddddoddoooooooooooooooooooooooooooooooloooooollllllllooollllllooollooolllooooooooolllloooooolllllloolllooooolooooollooooooooooooooooooooooooooooolc:::;;;;;;:;;;::::::::::::::::cccccccclllllllllllloollllllllcccc:::::ccccclllllllll
lllllllloooooolllooooollollooolllooooooolllooooolllllllllloooooooollooooooollooooollllooooolllooolloooolcccccc:::::::clooodddxxxkkkkkxdddoollllcccccclllllllllllloooollllloooooooooooooooooooooooooooooooooooooooollloooooooolllooolllllllllloooooooooooooooollooloooooooooooollloooooolooooooooooooooooooooooooooooooooooool:;,,;;;;;::::::::::cccccccccclllllllllloollolllllllccccc:::::ccccclllllllooolloollo
:::c:cccccclllllllooooooooooooolloooooollooooooolooolllooooollooolllooooooolooooooolooooollooooooloooooolc::::::;;;:clooooodddxxxxkkkkkkxxxdddolllcccccclllllllloooooooooooddddoooooooooooooooooooooooooooooooooooooooooooooooolooooolooolloooooooooooooooooooooooooooooooooooolloooooooollllllloooooooooooooooooooooooooooolc:;;;;:::::cccccccllllllllllloollllllllllccccc::cc:cccccclllllllloooooooooooooooolo
::::::::::::::::::cccccccclllllllllllooooooooooooooollloooooolooooooooooooooooooooooooooolooooooooooooool:::::::;;;cllooooodddxxxxkkkkkkkkkxxxddoolllcccllllloooooooodddddddddoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooolllllllllllcccccc::::::cloooooooooooooooooooooooooooolcccccccllllllllllllooolllllllllccccc::::cccccclllllllllooooooooooooooooooooooolooo
:::::::::::::::::::::::::::::::::::cccccccllllllllllllllllloooooooooooooooooooooooooooooooooooooooooooollc::c::::;:loooooooddddxxxkkkkkkkkkkxxxdddooollccccllllllooodddooooooooooooooooooooooooooooooooooooooooodxxkkOOOkkkkkxdooooooooooooooooooooooolollllllllllccccccc:::::::::::::::::::::::loooooooooooooooooooooooooooolllllllllllllolllllllccccccccccccccccclllllllooollooooolooooooooooooooooloooooooooo
lllllccccccccc:c:::::::::::::::::::::::::::::::::::::::cccccccccccllllllllllooooooooooooooooooooooooooooolc:::::::clooooooooddddxxxkkkkkkkkkkxxxxxddddoollcclllloooooooooooooooooooooooooooooooooooooooooooodxkO0KKK000OOOOOOOOkkkxolllllllllccccccccc::::::::::::::::::::::::::::::::::::::::::loooooooooooooooooooooooooooollllllllllllool::::::cccccccllllllllooooooooloooooooooooooooooooooooooooooooooooooo
loolooollollllllllllllccccccccc:::::::::::::::::::::::::::::::::::::::::::::cccccccccccccclllcllllllllllllc::::::cloooooooooddddxxxkkkkkkkkkxxxxxxxxxxxxxddollllooloooooooooooooooooooooooooooooooooooooolloO0OO0KNNNNNXK0OOOOOOOOkkxlc::::::::::::::::::::::::::::::::::::::cccccccccccllllllcclooooooooooooooooooooooooooooolllllllllollolccclllllllooolloooooollloolloooooolooooooooooooooooooooooooooooooooo
llllooooooooooooooooooooolllllllllllllcccccccccccccccc::c::::::::::::::::::::::::::::::::::::::::::::::::::::::;;:loodddoooooddddxxxkkkkkkkxxxxxxxxxxxxxxxxdolllolcllccccclooooooooooooooooooooooooooooooloxkxdxkO0KXXNNNNX0OxxkOOOOO0ko::::::::::::::ccccccccccccccccccllllllllllllllllolooollllloooooooooooooooooooooooooooolllllllloollollllllloooloooooooooooooooooolooooooooooooooooooooooooooooooooooooooo
::::ccccccllllllllllllloooloooooooooooloooollllllllllllllllllcccccccccccccccccccccccccccc::::::::::::::::::::::::cloooddoooooddddxxxkkkkkkkxxxxxdxxxxxxxxddddoollccll:::::cooooooooooooooooooooooooooooodddollllodxkkO0KXXNNNK0xddxkO00Odccccccccclllllllllllllllllloooolloooooooolllollllloollllloooooooooooooooooooooooooooollllllllollooolllllloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
llccccccccccc::cccccccccccllllllllloooooooooooooooooooooooooooooooolllllllllllllllllllllllllcclccccccccccccccc:::clooddddoooooddddxxxkkkkkkxxxddddxxdddddddddooollclolc:::coooooooooooooooooooooooooooxkkxlllllllllooxkO00KXXNNX0xooddddxdollllllooooooooooooooooooooolloolllllllcclcccclllloollllooooooooooooooooooooooooooooolllloloooooooollooloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
lllloooolllllllllllccccccccccccccccccccccclllllllllllllooooooooooooooooooooooooooooooooooooooooooooollllllllollcccooddddddooooodddxxxkkkkkkkxxxxxxxxxdddddddoooollllodollclooooooooooooooooooooooooodxxxxollc:;,;:clllodxkO0KXXNNNKOxdoooxdoolooooooooollllllllllllcccccccc::cc:ccccccccloolllllllooooooooooooooooooooooooooooolllollooooooolllooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
oooooooooooooooooooooooolllllllllllllcccccccccccccccccccccccccllllllllllllllllooooooooooooooooooooooooooooooooooloodddddddddoooddddxxkkkkkkkkkkkkkkkxxxddooooooolllldxdollloooooooooooooooooooooodddlclll:;:;,'''',;cclllodxO0KXNNNNXKOdoddlclccccccccccccccccccccccccccclllllllllllllllloooooollloooooooooooooooooooooooooooooollllooolooooollooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
ooooooooooooooooooooooooooooooooooooooooooolllollllllllllllccccccccccccccccccccccccccccccclllllllllllllllllllllloddddddddddddddddddxxkkkkkkkkkkkkkkkkkxxddoooooolllodkxolllooooooooooooooooooooddol::::::::cccc:;,'''',:llloxOO00KKXXXXKOxolcclcclclllllllllllllloooooooooooooooolllllllloooooollllooooooooooooooooooooooooooooolloooooooooooolooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooolllllllllllllllllllcccclccccccccccccccccldxxddxxxdddddddddddxxkkkkkkkkkkkxxxxxkkkxxddddooooodxkkdlllooooooooooooooooooddolc:ccc:::lxkOkkkxddoc:;,;codk000OOOKKKKXXKOdooooooooooooooooooooooooooooooooooooooooooollooooooolllooooooooooooooooooooooooooooolllooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodxxxxxxxxxxdddxddddddxkkOOOkkkxxxxxxxxxxxxxddxxddddddxkkdooodxxdooooooooooooddolcllllccccloxkkkkOO00KKKKK00KKK00000OOKKKKKXXX0kdoooooooooooooooooooooooooooooooooooooooollloooooolllooooooooooooooooooooooooooooolllooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooxkkkkkxxxxxxxxxxxxddddxkOOOOOkkxxxdddddddddddxxxxxddxxkkOOOkdxO00OOkxxdooooooolllllllllccclloddddxxxkOKKKXXXK0OOO0KKK00KXXKKXXXXKOxoooooooooooooooooooooooooooooooooooooollloooooollloooooooooooooooooooooooooooooollooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodxkOkkkkkkkkkkkkkkkxxdddxkOO0OOkxxddddddddooddxkkkkkxxkkkkOO00xloxkO0KKK0Okxollllllllllllcccclodooooooodxxxxk0KK0OOO00KK00KKKKKKXXXXX0kdoooooooooooooooooooooooooooooooooooolloooooollloooooooooooooooooooooooooooooollooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodxkOOOOOkkkkkkkOkkkkkkxxdddxOO00OOxxdddooooooddkkkOOOkkkkkOOOOO0Oolooddxkkxxddoollooollllllcc:::clllccclloolccldk0KK00000000O0KKKKKKKKKXX0xooooooooooooooooooooooooooooooooooollooooooollooooooooooooooooddoooooooooooollooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodxkOO00000OOOOOOOOOOOOOOkkxxddxkO000OkxddoooooddxkOOOOOOOOOOOOOOOO00d:cooooooooddooooooolllllllccc:::::,,,'':olccccldk00000O000OO00KKKKKKKKKX0xooooooooooooooooooooooooooooooooooolooooooolllooodoooooooodddddooooooooooooolooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooddxkOO00000000000OOOO0000000OOkkxxxxkO000OkdddddddxkkO00000OOOOOOO00OO000xl:cloddddddddoooollllllllllccc:cclcclodxxollllllodxO0000000OO0KKKKKKKXXXKKOdooooooooooooooooooooooooooooooooolooooooolllodoodoooooooddoooooooddddooooolloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodxkkO00KKKKKKKKKKK00000000000KKK00OkkkxxkO0KK0kxdddxxkOO00KKK00OOOO0000000KK0kdc::coddddddooooolllllllllllccccoddxkkkxxxdoodddddoxO0000000O0KKKKKKKXXXXXK0kdoooooooooooooooooooooooooooooooloooooooollooooddoodddddddddddoodoooooooolloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooood
ooooooooooooooooooooooooooooooooodooooooooooooooooooooooooooooooooooooooooooooooooooooooodxkkO0KKKKKKKKKKKKKKKKKKKKKKKKKKKKKXKKK00OOkkxk0KKKOOkkOOO000KKXXKK0OO00KKKKK0KKXK0kol::clooooooolllllllllllllllllllodddoooddxdodddxxdddkO00000000KKKKKXXXXXXKXKOdooooooooooooooooooooooooooooooooooooooollooooodoodddddddddddoodooooodoolloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
oooooooooooooooooooooooodoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodxkO0KKKKKKKKKKKKKKKKKKKKXKKXXKKKKKKKXXXXXXXK00OkkkOKXK00000KKKKKXXXXKKKKKXXXXXXXXXXXXX0kdlccccllllllllllllllllllllllllllcclllllloddxxxdxdddddkO0000000KKKKKXXKXXXKKK0xoooooooooooooooooooooooooooooooooooooollooddddoodddddddddddddddddddddoolodooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodddoooooooooooo
ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooddddddoodkO0KKKKKKKKKKKKKKKKKKKKKXXXXXXXXXXXXXXXXNNXNNNXKK00OkO0KXKKKXXXXXXXXNNXXXXNNNNNNNNXXXNNNNNX0kddocccccccccclllllllllllllloddoooollllllooxkxxxdddddxkO00000000KKKKKKKKKKKKOdoooooooooooooooooooooooooooooooooooooolooddddddddddooddddddddoddooddooloooooooooooooooooooooooooooooooooooooooooooooooooooooddddooodddooddooooooood
oooooooooooooooooooooooooooooooooodooooooooooooooooooooooodddooododddddooddooddxkOKXXKXKKKKKKKKKKKKKXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNXXXKKKXXXXXXNNXXXXNNNNNNNNNNNNNNNNNNNNNNNNNXK0kdol:;;;:::::ccccccllcccldkkOkxddooooooodxkkkxxxxxxxxkOOOOO00000KKKKKKKKKKOdooooooooooooooooooooooooooooooooooooolloddddddodddooddddddddddddddddooooooooooooooooooooooooooooooooooooooooodddooodddoooddddddddddddddddddooooodd
oooooodddddoooddoooooddooooooooooooooooodddoooddoooooooooooooddddddoooddxxkkO0KXXXXXXXXXXXXXXKXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNXXXNNNNNNNNNNNNNNNNNNNWWWNNNNNNNNNNNNNXX0Okdolc;;;;;;::::::ccccccldxxxdoooodddddddxxxxxxxxxxxdxxkkOOOOOOO00000KKKKK0kdoooooooooooooooooooooooooooooooooooolloddddddddddddddddddddddddodddooooooooooooodoooooooooooooddooddoooooooooodooodddooodddddddddddddddddddoodddo
dooooddoodddddddoooooooodddddooooooooooooooooodoodddoodoodddddoooddxkO0KXXXXXXXXXXXXXXXXXXKKKK00KK00KKKKKXXXXXXXXXXXNNNNNNNNNNWWWWWWNNNNNNNNNNNNNWWNNNNNNNNNNWWNWWWWWWWNNWNNNNNNXK0kxdolc:;;;;;;;;;;:::ccc:codoooollooooddddddddddddddddddxxkkkkkkOOOOO000KKK0xoooooooooooooooooooooooooooooooodooooloddddddddddddddddddddddddddddoolodoooooddddooodoooooooooddoooooddoodoooddddodddddddddddddoddddddddddddddddo
ddoooooddddddddddddddddddddddddddddddddddoooooddddddooddddddodxkO0KXXXXXXXXXXXXXXXXXXXXXXKKK0Okkkxxk00KKXXXXXXXXNNNNNNNNNWWNNNNWWWWWWWWWWWWWWWNWWWWWNNNNNWWWWNNNWWWWWWWWWWWNNNNNXK0Okxdoolc:;;,,,,,,;;:clldO00OdoooolllllllllllooooooooodoodddxxxxxkkkkOOO0KK0Oxoddooooooooooooooooooooooooooooooooolodddddddddddddddddddddddddddddoooddddddooddooddooooooooooooddodddodddddddddooddddddddddddodddddoddddddddddd
odddddddddddddddddddddddddddddddddddoodddddddddddddddddddodxO0KXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKK0000KKKXXXXXXXXNNNNNNNNNNNNNNNWWWWWWWWWWWWWWWWWWWWWWNNNNNNNNNNNWWWWWWWWWWWWWWNNXXXK0Okxxddolc:;;,,,,;cdkO0KXXNX0xoooolllllllllllllllllllollllooddddxxxkkOO000000xoodddooooooooooooooooooooooodddddoolodddddddddddddddddddddddddddddoooddooooooddoooodooddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddoddddddddddddddoodddoddddddddddddddddddddk0KXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKKKXXXXXXXXXNNNNNNNNNNNNNNNNWWWWWWWWWWWNNNNWWWWWWWNNNNNNNNNNNNNNNWWWWWWNNNNNXXXK00Okkxxddolc:;;;;;:okOO0KXXXXKkdooollllllccccccccccccccclllllooddddxxkOOO000KKkdoddooodddoooodddooooooooooddooooolooddddddddddddddddddddddddddddoooddoooooddddooodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddoddddddddddddddddddddddk0KKKKXXKXXXXXXKXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKXXXXXXXXXXNNNNNNNNNNNNNNNNNWWWNNNNNNNNNNNNNNNNNNNNNNNXXXXXXNNNNNNNNNNNNNNNNXXXK00OOkkxxxdolc:::::lxkO0KKXXXXX0kdooolllllllccccccccccccccclllloooodddxkkOOO0KKOdoddoooddooooooooooooodoooodoodooooodddddddddddddddddddddddddddddooododddddddddoddddddddodddddddddddddddddddddddddddddddddddddddddddddddddddd
dddddddddddddddddddddddddddddddddddddddddddddddddddddxO0KKKKKKKKKKKKKKXXXXXXXXXKKXXXXXXXXKKXXXXXXXXKKXXXXXXXXNNNNNNNNNNNNNNNNWNNNWWWWWWWWWWWNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNWWNNNNXXKK000OOkkkxxddolcc:codxO0KKKXKXXKKkdoooollllllcccclccccccccccccclllloodxxkOOOOOOkdodddoddddoooodddooooooooodddddoooodddddddddddddddddddddddddddddooodddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddxO000KKKKKKKKKKKKKKKKKKKKKKKKXXXKKXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNWWWWWWWWWWWWWWWWWWWWNNNNNWWWWWWWWWWWNWWWWWWNNNNXXXKK000OOOOkkxxxddolclodxO00KKKKKKKK0kooooolllllcccccccccccccccc:ccllllodxxxxdoodxxdddooddddooddddddddoooooodddddoolodddddddddddddddddddddddddddddooodddddddddddoddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
dddddddddddddddddddddddddddddddddddddddddddddddddddxO0000KKKKKKKKKKKKKKKKKKKKKKKKKKKKKXKKXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNWWWWWWWWWWWWWWWWWWWWWWWWWNWWWWWWWWWWWWWWWWNNNNNNNXXXK0000OOOOkkkkxxddolloxkO0000KKKKKK0Oxdoloollllcccccccccccccc::::cccllllolllccclxxdododddooddddddddooddoooodddddolodddddddddddddddddddddddddddddoooddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddxkOO00000KKKKKKKKKKKKKKKKKKKKKKKKKKKXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNNWWWWWWWWWWWWWWWWWWWWWWWWNNNNNNNNNWWWWWWWWNNNNNNNXXXKK0000OOOOkkkkxxddooddxkO00000KKK00Okxxddolllllllllllcccccccccccclllcccc::cccccdkxddddddooodddddddddddoooddddddooodddddddddddddddddddddddddddddolodddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
dddddddddddddddddddddddddddddddddddddddddddddddddxkO000000KKKKKKKKKKKKKKK0KKKKKKKKKKKXXXXXXXXNNXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNNWWWWWNNNNNNNNNWWWWWWWWNNNNNNNNNNNNNNNNNNNNNNNNNNXXXXKK000OOOOOkkkkkxddoddxkOO00000KKKOkxxkOOkkxdoollllllccccccccccccccc::;;::ccllldxkxddddddodddddddddddddooddddddoooddddddddddddddddddddddddddddddooddddddddddddodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
dddddddddddddddddddddddddddddddddddddddddddddddddxkOO00000KKKKKKKKKKK0000000KKKKKKKXXXXXXXXXXXXXXXXXXNXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNWWNNNNNNNNNNNNNNNNNNNXXXXXXXXXXXXXXNNNNNNNNNNXXXXKKK0000OOOOOkkkkxdddddxkkOO00000KK0kxxkOO000KK0Oxdlllllcccc::::::::;;;;;;;:clooodxxddddddddddddddddddddooddddddoooodddddddddddddddddddddddddddddooddddddddddddodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddxkOOO000000000000000000000000000KKXXXXXXXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNXXXXKKKKKKKKKKKKKKKKXXXXXNNNNNNNNNXXXXXXKKK000OOOOOOkkkxxddddxxkkOO000KKKKOxxkO00KKKKKXXK0kdlllcccc::::;;;;;;;;;;:cloodddxxdddddddddddddddddddooddddddoooodddddddddddddddddddddddddddddooddddddddddddodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
dddddddddddddddddddddddddddddddddddddddddddddddxkkOOO00000000000000000000000000KKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNXXXKK00O000000KKKXXXXXNNNNNNNNNNXXXXXXXKKK00000OOOkkkkxxxddddxxkOO0000KKK0kkO0KKKKKKXXXXXXKxllccc:::::::;;;;;;;;;:clodddxkkddddddddddddddddddooddddddooooddddddddddddddddddddddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
dddddddddddddddddddddddddddddddddddddddddddddddxkOOOOO000000000000000000000000KKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXNXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNXKKK000KKXXXXNNNNNNNNNNNNNNXXXXXXKKKKK0000OOOOkkkxxxxxdddxkOOO00K000K0O0KKKKKKKXXXXXXXKxllccc::::::::;;;;;;;::coddxxkOkdddddddddddddddddoodddddddoooddddddddddddddddddddddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddxkkOOOOOOO0000000000000000000KKKKKKKKXXXXXXKKKKKKKXXXXXXXXXXXXNNXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNWWWWWWNNXXXXXXXXXXXNNNNNNNNNNNNXXXXXXXXKKKK0000OOOOkkkkxxxxdddxxkOO000000KK00KKKKKKKKKXXXXXNKxlccc:::::::::;;;;;;;:clodxxkkkkdddddddddddddddddoddddddddooddddddddddddddddddddddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddxkkkOOOOO0000000000000000000000000KKKKKKKKKKKKKKKKKKKKXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNWWWWNNNNNNXXXXXXXXXXNNNNNXXNNNXXXXXXXXKKKK0000OOOOkkkkkxxxxxxxxkOOO0000000000KKKKKKKKKXXXXXXKxllc:::::::::;;;:;;;;:codxkkkkkkddddddddddddddddoodddddddooddddddddddddddddddddddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddx
dddddddddddddddddddddddddddddddddddddddddddddxxkkkkOOOOO000000000000000OO000000000000000KKKKKKKKKKKKXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNXXKKKKXXXXXXXXLOVEXYOUXFOREVERK0000OOOOkkkkxxxxxxxxxkkOOOO000000000000KKKKKKXXXXXX0dllc:::::::::;;;;;;;;:lodxkkkkkkxddddddddddddddoodddddddooddddddddddddddddddddddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
dddddddddddddddddddddddddddddddddddddddddddddxxkkkkOOOOO000000000O0OOOOOOOOOOOOOOOOOO00000000000KKKKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNXXNNNXKK00KKKXXXXXXXXXXXXXXXXKKKKKKKK0000OOOkkkkkxxxxxxxxkkOOOOO00000O0000000KKKKKKXXXXKxllcc::::;;;;::::;;;;::codxxxxkOkddddddddddddddoodddddddooddddddddddddddddddddddddddddddooddddddddddddddddddddddddddddddddddddddddddddddddddddddxxdddddddddddddddd
dddddddddddddddddddddddddddddddddddddddddddddxxkkkOOOOO000000000OOOOOOOOkkkxxkkkkkkkkOOOOOOO000000KKKKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNXNNNNXKK0KKKXXXXXXXXXXXXXXXXKKKKKKKK00000OOOOkkkkxxxxxxxxkkkOOOOOOOOkkOOOOO0000KKKKKKKKKxllccc::::;;:::;;;;;;;::cloodxxkkxddddddddddddddddddddddooodddddddddddddddddddddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
dddddddddddddddddddddddddddddddddddddddddddddxxxkkOOOOOO0000000OOOOOOOOOkkxdddxxxxddxxkkkOOOOO000000KKKKKKKXXXXXKXXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNXXXXXXXXXXXXXXXXXXXXXXKKKKKKKKK0000OOOOkkkxxxxxxxxxxxkOOkkOkkkddxkkkkOO000000KKKKKklllccc::::::::;;;;;;;;;;:cloddxkkxddddddddddddddddddddddoodddddddddddddddddddddddddxddxdodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddxxkkkkOOOOOO000OOOOOOOOOOkkxollllooolodxxxxkkOOOOO000000KKKKKKKKXKKKKKXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNXXXXXXXXXXXXXXXXXXXKKKKKKKKK0000OOOOOkkkxxxxxdlccoxkkkkkkxxdlldxxxxkkOOO0000000Kkollccc:::::::::::;;;;;;;;;:codxkkkxddddddddddddoddddddddoodddddddddddddddddddddddddxxxxdooddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
dddddddddddddddddddddddddddddddddddddddddddddddxxkkkkOOOOOOOOO000000OOOOkkdlcccllccloddxxxkkkkOOO0000000KKKKKKKKKKKKKXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNXXKKKXXXXXXXXXKKKKKKKKKKKKKKK0000OOOOkkkkxxxxdol:codxkkkkxdo:;clodddxxkkOO0000KKK0dlllcc:::;;:::::::;;;;;;;;;:cldxkOkxdddddddddddoddddddddoodddddddddddddddddddddddddxxxxdooddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
dddddddddddxxddddddddddddddddddddddddddddddddddxxxxkkkkOOOOOO000000OOOOOOOkdcccccccloodddxxxkkkkOOOOOO00000KKKKKKKKKKKKKKKKKKKKXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNXXKKKKKKKKXKKKKKKKKKKKKKKKK0000000OOOkkkxxxxxddollodxxxxxdl:',;cclooddxxkkOO000KKKkollccc:::::;;;;::;;;;;;;,;;;cldxkOOkdddddddddddddddddddoodddddddddddddddddddddddddddxxdooddddddddddddddddddddddddddddddxxxxddddddddddddddddddddddddddddddddxxxxx
ddddddddddddddxxdddddddddddxdddddddxdddddxdooddddxxxkkkkkOOOO000000OOO000OOkocccccclooddddxxxxkkkkkkOOOOO00KKKKKXKKKKKKKKKKKKKXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNXXXKKKKKKKKKKKKKKKKKKKKK000000000OOOOkkkkxxxddxdoooddxxxxdl;'',;;:cclooodxxkkOO000K0dllcccc::::::::;;;;;;;;;;;;;;:ldkO00kddddddddddddddddddoodddxxdxdddddddddddddxxxdddddxdoodxdddddddddxddddddddddddddddddddddddddddddddddddddddddddxxddxxxxxxxxxxx
dddddddddddddxxdddddddddddddddddddxxdddddddoooodddxxxkkkkkOOOO0000000000000Oxoccc:clllooodddxxxkkkkkkkkkkkkO0KK000000KKKKKKKKKKKKXXXXXXXXXXXXXXXXXXXXXNNXXXNNXKK000KKKKKKKKKKKKKKKK00000000OOOOOkkkkxxddddddoooddddddl;'.',,;::ccllooodxxkkkOO00koccccc::::::::;;;:;;;;;;;;;;;:ldkO00Oxddddddddddddddddooddddxxddddddxxddxddxxxxxxxxdxddodxxdddddddddddddddddddxddddddddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxx
xdddxdddxxddddddddddddddddddddxxxxxxdddddxdooooddddxxxxkkkOOOO00000000KKKK00Oxl::ccllllooooodddxxxxxxxkxxxdooooxkkOOO000000KKKKKKKKKKKKXXXXXXXXXXXXXXXXXXXXNNXXK0000000KKKKKKKKKKK00000OOOOOOOOkkkxxxdddddooooooodddl'...',;;;::cccllloodddxxkkOOdlcccc::::::;;;;:::;;;;;;;;;;;:ldkOO0Oxddddddddddddddddodxxdxxdxxxxxxxxxxxxxxxdxxxxxxddodxxddddddddddddddddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxdddxxxxxdddddddddddddddxxxddddddddddddooooodddddxxxkkOOOOO00000KKKKKKK00koc::ccllllllllooodddddxxxxxdoc::ldkOOO000000000KKKKKKKKKKKKKKKKKXXXXXXXXXXXXXXNXXXK00000000000000000000OOOOOOkkkkkkxxdddddoooooooodool,....',;;;;::cccccclllooddxxkxocccc::::::;;;;::;;;;;;;;;;;;;:lxkOOOOkdddddddddddddddoodxdxxxxxdxxxxxxxxxxxxxxxxxxxxdodxxdddddddddddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ddddddxxxxxxxxxxxxdxxxxxxxxxxxxxxxxxxxxddddooooooodddxxxkkkkOOOO000KKKKKKKKK00xl:;:ccllccccclllooodddddxxxdlcldkOOO0O00OOOO000000000KKKKKKKKKKKKKKKKKKKKKKXXNNNXKK000OO00000000000000OOOOkkkkkkkxxxdddooooooooooooo:',;''',;;;;:::ccccccccllloddxxocccc::::::::;;:;::;;;;;;;;;;;;:lxkkkOOkxdddddddddddddoodxxxxxxdddxxxxxxxxxxxxxxxxxxxdooxxddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
dddddxxxddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdolloooooddxxxkkkkkOOO000KKKKKKKKKK0kd:,;:ccccccccccclloooodddddddodxkkkkOOOOOOOOOOOOOO000000000KKKKKKKKKKKKKKKKXXNNNNXXK00OOOOOOOO0OO000OOOOOOkkkkkxxxxdddooooollllloool;':oc;,,;;::::::cccccccccllooddocccc:::::::::;;;;;;;;;;;;;;;;;;coxxkkkOkxddddddddddddoodxdxxxxxxxxxxxxxxxxxxxxxxxxxxxddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxdxxxxxxxxxxxddxxxxxxxxxxxxxxdxxxdxxxxxxxdollooooooddxxxkkkkOOO00KKKKKKKKKKK0Oxc,',:ccccccccccccllllooooooodddxxxxkkkkkkkkkOOOOOO00000000000KKKKKKKKKKKKXNNNNNNNXXXK00OOOOOO0OOOO0000OOOOkkkkkxxxddddooooooolooodl,':ddl:;;;::::::ccccccccllllooolcccccc::::::;;;;;;;;;;;;;;;;;;;:loodxxkkkddxdddddddddoodddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxdxxxxxxxxxxxxxxxdxxxxxxxxxxxdolllooooooddxxxkkOO0000KKKKKKKKKKK0Oxl;..';::ccccccccccccllllloooooddddxxxxxxxkkkkkOOOOO0000000000KKKKKK0KKKXXNNNNNNNNNNNNNXXKKKKKKKKKKKKKK0000OOOOOkkxxddddddooooooodddc,cddddl:;:::::cccccccccclllloolcccccc::::::::;;;;;;;::;;;;;;;;;:ccloddxkxdddddddddddddxxxxxxxxxxxxxxxxxxxxxxxdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdxxxxxxxxxdollloooooooddxkOOO000KKKKKKKKKKKK00Oko:,..',;::::ccccccccccccllllooooddddxxxxxxxkkkkOOOOO0000KKKKKKKKXXXXXNNNNNWNNNNNNNNNNNNNXXXXXXXXXXXXXKKKKK0000OOOkkxxxdddddodddddxko:cdxdddoc::::cccccccccccllloddllccccc::::::::;;;;;;;::;;;;;;;;;;::cllodxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxolllooodddddxkO0000KKKKKKKKKKKKKK00Oko:,...'',;;::ccccccccccccccllllooooddddxxxxxkkkOOOO000KKKKXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNXXXXXXXXXXXXKKKKKK00000OOkkkxxxxddddxxxkOklcdxdddddlc::cccccccccccclodxdlcccccc:::::::;;:;;;;;;;;;;;;;;;;;;;;:cloodxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdooooddxxxkkOO000KKKKKKKKKKKK00K000Okdc,...'',,;;:cccccccccccccccccllllloodddxxxkkkOO000KKKKXXXXXXXXNNNNNNNNNNNNNNNNWWNNNNNNNNXXXXXXXXXXXXXKKKKKKK00000OOOkkkkxxxxxxxkkOOdldxdddddddlccccccccccccllodxdlccccc::::;;;;;::;;;;;;;;;;;;;;;;;;;;;:ccloxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdddddxkkOO00000K0KKKKKKKKKK0K000000Oxdc,...',,,,;;::cccccccccccccccllloooddxxkkOOOO0000KKKKKKKKXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNXNNXXXXXXXXKKKKKKK000000OOOOkkkkkkkkkxkkkkxodxxxxxxxxxdlccllccccccllodddlcccccc::::::::::;;;;;;;;;;;;;;;::;;;;;;:codxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkkOOO00K00KKKKKKKKKKKK00K00000OOxdc,..''',,,;;::cccccccccclllllooodxxkkOOOO000000000KKKKKKKXXXXNNNNNNNNNWWWWNNNNNNNNXXXNXXXXNNNNNXXXXKKKKKKK000000OOOOOOkkkkkxkkxxxkkddxxxxxxxxxxxxdollllcccccllooolccccccc:::::::::;;;;;;;;;;;;;;;;::;;,,;;:ldxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkkOOOO000000KKKKKKKK000000000000Okxoc'..''',,,;;::cccccclllllooodddxkkOOO0000000000KKKKKKXXXXXXNNNNNNNWNNNWWNNNNXXXXXXXKXXXXXXXXXXXXXXXKKKKKKK0000000OOOOOOkkkxxxxxxxxxxdxxxxxxxxxxxxxxdollllcccclllolcccccccc::::::::::::;;;;;;;;;;;;;::;;;;;:cdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkOOOO00000000KKKKKKK0000000000000Okxo:'.''',,,;;:::ccclllooooodddxxkkOOOO000000000KKKKXXXXXXXXXXXNNNNNNNNNNNNNXXXXKKKKKKKK00KKKKKKKKKKKKKKKKKKKKK0000000OOOkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxdolllcccllllllccccccc:::::::::;;;;;;;;;;;;;;;;;::;;;;:cdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkOO00000000000KKKKKKKKK0000000000OOkxo:'.''',,,;;::cclllooooddddxxxkkkkOOOO0000KKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXKK000OOOO000000K0000KKKKKKKKKKKKKK000000OOOkkkkxxxxxxxxxkkxxxxxxxxxxxxxxxxxxdollllccllllcccccccccc:::::::;;;;;;;;;;;;;;;;:::ccloodxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkOO0000000000000000K00KK000000000OOkkxl;,'''',,;;::cclloooooddddxxxxxkkkkOOOO000KKKKKKKKXXXXXKKKKKKKKKKKKKKKKKKKKKK0000OOOOO00000KK0000000K000KKKK000000OOOOkkkkkxxxxxxxxxkkxxxxxxxxxxxxxxxxxxxxddolccclccccccccccc:::::::::;;;;;;;;;;;;;;;::clodxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkOO000000000000000000000000000000OOOkdl;;,,,,,,;;::ccloooooodddddxxxxxxxkkOOOOO0000000KKKKKKKKKKKKKKKKKK0KKKKKKKK0000KKKK0000KKKKKKKK000000000000000000OOOOOkkkkkkxxxxxxxxkkxxxxxxxxxxxxxxxxxxxxxxxollcccccccccccc:::::::::::::;;;;;;;;;;;;::clloxkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkOO000000000000000000000000000000OOkxdl::;;,,,;;;::cloooooooddddddddxxxxkkkkkOOOO0000000000000000000000000KKKKKKKKKKKKXXKKKKKKKKKKKKKKKK0000000000OOOOOOOOkkkkkkkkkxxxxxxkkkxxxxxxxxxxxxxxxxxxxxxxxxdolccccccccc::::::::::::::::;;;;;;;;;;;;::ccloxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxddddoool
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkOOO000OOOOO00000000000000000000OOOkxdlc::;;;;;;;::clooooooooddddddddddxxkkkkkOOOO0000OOOOOOOOOOOOO000000KKKKKKKXXXXXXXXXXKKKKKKKKKKKKKKKK0000000OOOOOkkkkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdocccccccc::cccc:::::::::;;;;;;;;;;;;;;;;:cloxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxddddooollllllcccc
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxddxkkOOOOOOOOOOO0000000000000000000OOOkxdolcc::;;;;;:cllloooddddddxxxxxxxxxxxxkkkkOO0000OOOOOOkkkkkkOOO0000KKKKKKKXXXXXXXXXXXKKKKKKKKKKKKKKKKK0000000OOOOOkkOkkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxolccccccccc::::::::::::;;;;;;;;;;,;;;;;;:clodxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxddddoooolllllcccccccccccccl
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdddxkkkOOOOOOOOOO00000000000K000000OOOkxdxdlcc::;;;;:cclloooddddxxxxkkxxxxxxxxkkkOOOOOO000OOOOOkkkOOOO0000KKKKKKKKKKXXXXXXXKKKKKKKKKKK0000000000000000OOOOOOOOOkkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdlccccccc::::::::::::;;;;;;;;;;;;;;;;;;;:coxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkxxxxxxxxxddddoooolllllllccccccccccclllllllloooo
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxooodxxkkkOkkkkOOOOO00000000KK000000OOkxdxxxdocc:::;::ccclllooddxxxkkkkkkkkkkkkkkkkOOOOOOOOOOOOOOOOOO000000000KKKKKKKKKKKKKKKKKKK000000000000000000000OOOOOOkkkkkkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdllccccccc:::::;;;::::;;;;;;;;;;;;;;;;;cdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkxxxxxxxdddddoooolllllccccccccccccllllllllllooooodddooooooo
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxooodxxkkkkkkkkkOOOOO00000000000000OOOkxdxxxxxolc::::::ccclloodddxxkkkkkkOOOOOkkkkkkkkkkkkkkkkkkkOOOO00000000000000000KKKKKKKKKK00000000000000000000OOOOOOkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdollccc::::::::;;:;:;;;;;;;;;;;;;;;;cdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdddddooooolllllllcccccccccccllllllllooooddddddooooooooooooodddd
kkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxooodxxkkkkkkkkkOOOOO00000000000000OOOkxdxxxxxxdlc:c:::cccclloodddxxxxkkkOOOOOkkxxxxxxxxxkxxxxxxxkkOOOOOOOOOOO000000000000000000OOkOOOOOOO00000000OOOOOkkkkkxxxxxxxxxxxdddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxolccc::::::::::::::;;;;;;;;;;::;cdxxxxxxxxxxxxxxxxxxxxxxxkxxxxkxxxxxxxxxxddddooooolllllllcccccccccccllllllllloooooodddddooooooooooooooodddxxxkkkkkkkk
xxxxxxxkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxdoddxxkkkkkkkkkOOOOO0000000000000OOOkkxdxxxxxxxxolcc::ccllllloooodddxxxkkkOOOkkxxxddddddddddddxxxkkOOOOOOOOOOOOOOOOOOOOOO000OOkkkxxkkkkOOOOOOOOOOOOOOkkkxxxddoooodddddddoooodddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdolccc::::::::::::;;;;;;;;;;::cdxxxxxxxxxkxxxxxxxxxxxxxddddddooooollllllllccccccccccclccllllllllloooodddddddooooooooooooodddddxxxxkkkkkkkkkkkkkkkkkk
llllooooooddddddddxxxxxxxxkkkkkkkkxkkkxdddxxxkkkkkkkkkOOOOOOO00000000000OOkkxdxxxxxxxxxxdocc:clllllllllooooddxxxxkkkkkxxddoooooooooddxxxkkkkkkkkkkOOOOOkkOOOOOOOOOOOkkkxxxxxxxkkkkkkOOOOOkkkkxxxdddoollooooooooollooodxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdolc::::::::::::::;;;;;;;;:coxxxxxxxxddddoooooooollllllllcccccccccccclclllllllllllooooddddddooooooooooooooooddddxxxkkkkkkkkkkkkkkkkkkkkkkkkkkxxxdd
llllllcccclllllllllllooooooooddddddddddddxxxkkkkkkkkkkOOOOOOOO00000000OOOkkkxdxxxxxxxxxxxxoccccllllllllllllooodddxxxxxddooolllllllooddxxxkkkkkkkkkkkkkkkkkkkkkkkOOOOOkkxxxxxxxkkkkkkkkkkkkxxxxdddoooolllllloooooooooodxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxolc:::::::::::::;;::;;;:cloooolllllllccccccccclcclcllccllllllllloooooodddddddooooooooooooooddddddxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxddooollcccc
dddddooooooooollllllllllcccccllllllllooddxxxxkkkkkkkkkOOOOOOOOOO000000OOOOkxdxxxxkkkkkkkkkxoccclcccccllllllllllooooooooolllllcccclloddxxxxkkkkkkkkkkkkkkkkkkkkkkkOOOOOkkkkkkkkkkkkkOOkkkkkxxxdddddoooolllllloooooodddxkkxxxkkxxkkxkkkkxxxxxxxxxxxxxxxxxddddddddddoolcccc::::::::::;;;;;;:cccccccccllllllllllloooooooooodddddddddoooooooooooooodddddddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxddddooolllccc::::::::::
ddddddddxxxxxxxdddddooooooooooooooollodddxxxxkkkkkkkkkOOOOOOOOOOOO000OOkkkxxdoodddddddddddddlcccclcclllllllllllllllllollllllccccclooddxxxxkkkkkkkkkkxkkkkkkkkOOOOOOOOOOOkkkOOOOOOOOOOOOkkkkxxxxdddooodddoooooodddddddxxxxxxxxdddddddddoooooooooooolllllllllllllllclccllcccccccccc:;;::cllooooooooooodddddddddddddooooooooodddodddddddddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxddddoolllccc::::::::::::::::::::::
dddddddddddddddddoooodddddddddxxddxxddddxxxxkkkkkkkkkkkOkOOOOOOOOO000OOkkkxxolcllllllllllllllcccclllllllllllooooooooooooooolllcclloodddxxxkkkkkkkkkkkkkOOOOOOOOOOOOOOOOOOOOO000000OOOOOOOOOkkkxxddooddxxxxxdddddddddollllllllllllllllllllllccccllcccllllllllllllloolooooooooooodoooooodxxxddddooooooooooodddddddddddddddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxdddoolllcccc:::::::::::::::::::::::::::::::::
kkkkkkkkkkkkkxxxxxdddddddddddddddddddoddxxxxkkkkkkkkkkkkkkOOOOOOOOOOOOkkxxxddoooooooooooooollllccclllllllllooooooooddddxddddoolloooddddxxxxxxxkkkkkkkOOOO00O000000000000000KKK000000000OOOOOkkkkxxddddddxxxxddddddddollllllllllooooooooooooooooooooooooodddddddddddddddddddooooooooooooddddddddddddddddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxdddooolllccccc::::::::::::::::::::::::::::::::::::::::::::
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxdddxxxxkkkkOOOkkxxxkkkkkOOOOOOOkkkkxxddddxdddxxxxxxxxxdddolccllllllllooooooodddddddxxdddddddddddddxxxxxxxxkkkOOOO0000000000KK00KKKKKKKKKKKKKKK000000O0OOOOkkkxxddooddddddddddooddddddxxddxxxxxxxxxxddddddddoooddoooooooooodddddddddddddddddddxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxdddoooolllcccc::::::::::::::::::::::::::::::::::::::::::::::::::::::::c:
xxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxdddxxxkkkOOOOOkkkxxxxxkkkkkkkkkkkkkxxddddddddddddddddddddoolccllllllloooooodddddddddddddddddddddddddxxxxxkkOO0000KKKKKKKKKKKKKKKXXKKKKKKKKKKKKK0000000OOOOkkkkxxdololloooooooloddoooooooododdddddddddddddddddddddddxdxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxdddoooollllcccccc::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ccccccc::
cllllloooodddddxxxxxkkkkkkkkkkkkkkkkxdddxxxkkOOOOOOOkkkxxxxxkkkkkkkkxxxxdddxkkkkkkkkkkxxxxxxxxxxdllllloooooooddddddddddddddoooooododdddddxxkkOO00KKKKKKXXXXXXXXXXXXXXXXKKKKKKKKKKKKK000000OOOOOkkkkxxdolllclclllllodddddddddxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxdddddooollllccccccc::::::::::::::::::::::::::::::::::::::::::::::::::::::::c:::cccccccccccccccccc::cc::::
::::::::::::ccccccccclllloooooddddxxdoddxxkOOOOO000OOOkxxxxxxkkkkkkxxxxddddkkkkkkkkkkkkkkkkkkkkkkdolloodddxxxxxxddddddddooooooooddoodddxkkOO00KKKKKKXXXXXXXXXXXXXXXXKKKKKKKXKKKKKKKKK00000OOOOOkkkxxxddoollccccclloxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxddddoooolllllcccccccc::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::cccccccccccccccccc::::::::::ccccccccc
::::::::::::::::::::::::::::::::::cclodxxkkOO00000000OOkxxxxxxxkkkkxxxddodxkkkkkkkkkkkkkkkkkkkkkkkxoloddxxxkkkOOkkkkkkkxxxxxxxxxxxxxxkkOO00KKKKKKKKKKKKKXXXXXXXXXXKKKKKKKKKKKKKKKKKKK00000OOOOkkkkxxddoooollccllllokkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxddddddoooooolllllccccccc:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ccc::ccccccccccccccccccccc::::::::cc:::cccccccccccccccc
:::::::::::::::::::::::::::::::::::clddxkkOO000KKKKKK00OkxxxxxxkkkxxxddolllloolooooooodddddddddxxxxdoodxxkkkO000000000000000000OOkkkkOO000KKKKKKKKKKKKKKKKXXXXXXKKKKKKKKKKKKKKKKKKKKKK0000OOOOkkkxxxddoooolllllllloxxxxxxdddxdddddddddoooolllllllllllccccccccccc:::::::::::::::::c:c::::::::::::::::::::::::::::::::::::::::::::::::::::cccccccccccccccccccccccccccccccc:::::::::::cccccccccccccccccccccccccc:::
:::::::::::::::::::::::::::::::::::clddxkO000KKKKKKKKKK0Okxxxxxxkkkxxddocc:::::::::::::::::cccccccccldxxkOOO00KKKKKKKKKXXXXXXXKK00OOOO000KKKKKKKXKKKXXXXKKKXXXXKKKKKKKKKKKKKKKKKKKKKKKKK000OOkkkxxxxxdddooollllclccccccccccc:::::cc:::::::::::::c::::::::::::::::cc::::::::::::::::::::::::::::::::::::::::::::::cc:::::::ccccc:ccccccccccccccccccccccccc::::::::ccc::ccccccccccccccccccccccccccc:::::::::::::::
ccccccccccc::::::c::::::::::::::::ccodxkO0000KKKKKKXXXKK0Okxxxxxxkkxddol:::::::::::::::::::::::::cc:ldxkOO000KKKKKKXXXXXXXXXXXXXKK00000KKKKXXXXXXXXXXXXXXXXXXXXKKKK000KKXXXXXXXXXXXXXKKKKK00Okkkxxxxxxxxxddoollllc::::::ccc::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::cc::c::::cc:ccccccccccccccccccccccccccccccccccc:::ccccccccccccccccccccccccccccccccccccc::cc::::::::::::cccccccccccc
ccccccccccccccccccccccccccccccccccccodkO00KKKKKXXXXXXXXKK0Okxxxxxkxxdolc:::::::::::::::::::::::::c::lxkOO000KKKKKKXXXXXXXXNNNNNXXXKKKKKKXXXXXXXXXXXXXXXXXXXXXKKKK00000KXXXXXNNNNXXXXXXXXKKK00OOkxxxxkkkkkkxxddoolc:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ccccccccccccccccccccccccccccccccccccccccccc::ccccccccccccccccccccccccccccccccccccc:cc:ccc:c::::::::cccccccccllllllllllllooo
cccccc:ccccccc::cccccccccccccccccccloxO0KKKKKXXXXXXXXXXXKKOkkkkkkkxxdoccc:::::::c::c:::::::::::ccc:lxOOO00KKKKKKKXXXXXXXXXXNNNNXXXKKKXXXXXXXXXXXXXXXXNNNNNNNXXXXK0OO0KKXXXXNNNNNNXXXXXXXXKKK00OOkkkkOOOOkkkkxxddocc:::::::::::::c::::::::::::::::c::::::::cc::cccccccccccccccccccccccccccccccccccccccc:ccccccccccccccccccccccccccccccccccccccccccccccccccccc:cc:::c::::::::ccccccccclllclllllllloooooooooooooodd
cccccccccccccccccccccccccccccccccccldkO00KKKKXXXXXXXXXXXXK0kkkkkkkxxolccccccccccccccccccccccccccccokO0000KKKKKKKXXXXXXXXXXXXNNXXXXKKKKKKXXXXXXXXXXXXXXNNNNNNNNNXXXXXXXXXXXXXNNNNNNNXXXXXXXKKK00OOkkOOOOOOOOkkkxxoccccccccc:ccccccccccccccccccccccccccccccccccccccccccccccccccccccccc::cccccccccccccccccccccccccccccccccccccclcccccccccccccc::cc::c:::cccc::ccccccccccclllllllllllllooooooooooooooddddddddddddddd
ccccccccccclccllcccllcccccccccccccloxkO000KKKKXXXXXXXXXXXKK0OOOOOkkxocccccccccccccccccccccccccccldkO0000KKKKKKKKXXXXXXXXXXXXXXXXXKKKKKKKKKKKKXXXXXXXXXXXXXNNNXXXXK0OOOO0KXXXXXXXXXXXXXXXXKKKK000OOOO000000OOOkkkdlcccccccccccccccccccccccccccccccccccccccc:cccccccccccccccccccccccccccccccccccccccccllcccccccccccccccccccccccccccccccccccccccc::cccccccclccllllllllloooooooooooooodddddddddddddddddddddxxxxxxxxx
cccccccccccccccccccccccccccccclcclloxkOO00KKKKXXXXNNXXXXXXXKK0000OOxlcccccccccccccccccccccccccccok0000KKKKKKKKKKXXXXXXXXXXXXXXXXXKKK0KKKKKKKKKKKKKKKXXXXXXXXXXXXXNXOddxkOKXXXXXXXXXXKXXXKKKKK000OOO0000000OOOOOOxocccccccccccccccccccccc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclclllllllllllloooooooooooodddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxx
llllllllllcccccccccccccccccccccccclooxkO000KKKXXXXXXXXXXXXXXXXXXK0Odlllllcccccccccccccccccccccldk0000KKKKKKKKKXXXXXXXXXXXXXXXXXXXKKKK00KKKK0000KKKKKKKKKKXXXXXNNNNNXKKXNNNNXXXXKKKKKKKKKKKKKK000OOO0000000OOOOOOkdlcccccccclcccccccccccccccccccccccccccclccccccclllcccccccccccccccccccccccccccccccccccccccccccccccllllcclllllllllloooooooooooooooooddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxk
ddddddddoooooollolllllllllllllllllllloxkO00KKKKKXXXXXXXXXXXXNNXXK0OdlllllccllccllllllllllllllldO00KKKKKKKXXXXXXXXXXXXXXXXNNNNNXXXXKKKKKK000000000KKKKKKKKKKXXXXXNNNNNNNNNNXXXKKKKKKKKKKKKKKK000OOOO0000000OOOOOOOkolllllllcllllcclllccclcccccccccccccccccccccccccccccccccccccccccccccccccccccccclllllllllllllloooooooooodddooodddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkxxxxxkkkkkkkkkkkkkkkkk
kkxxxxxxxxxxxxxxxxxxdddddddddddoooollldxkO000KKKXXXXXXXXXXXXXXKKKK0dllllllllllllllllllllllllldOO00KKKKKKXXXXXXXXXXXXXNXXNNNNNNNXXXXKKKKK000000000000KKKKKKKKKKXXXXXNNNXXXXXKKKKKKK0KKKKKK00000OOOOO00000000OOOOOkkdlccccccccccccccccccccccccccccccccccccccccccccclllllllllllllllllllllllloooooooooooooooddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkxxxkkkkkxkkkkxxkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkxkxkxxxxxxxxxxxxdollodxO0000KKKXXXXXXXXXXXXXXKKK0xoooooooollollllllllllllldkO000000KKKKXXXXXXXXNNNNNNNNNNNNNXXXXXXKKKKK00000000000000000KKKKKKXXXXXXXXXKKKKKKK0000000000000OOOOOO00K00000OOOOOkkxolllllllllllllllllllllllllllllllllllloooooooooooooooooooooddddddddddddddddddddddddxdddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkxxxxxkkxxkkkkkkxkkkkkkkkkxxxxkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxdooodxkOO000KKKXXXXXXXXXXXXXXKKKOxxxxxxxxddddddddddddddodxkO0000000KKKKXXXXXXXXXNNNNNNNNNNNXXXXXXXKKKKK000000000000000000KKKKKKKKKKKKKKKKK0000000000000OOOOOOOOO00KK0000OOOOOOkkdoooooooooooooooooooodddddddddddddddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxdoodxxkkkO000KKKXXXXXXXXXXXXXXKK0OkkkkkkkkxkkxxxxxxxxxxxxkkOOO00000000KKKKKKXXXXXXXXNNNNNNXXXXXXXKKKKKK0000000000000000000000000KKKKKK0000000OOOOOO0OOOOOOOOOOO00KKKK00000OOOOOkxxxxdddddxxxxdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkkkkkxxkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkddddxxxkkkOO000KKXXXXXXXXXXXXXXXKKOkkkkkkkkkkkkkkkkkkkkkkxkkkOOOOOO000000000KKKKKXXXXXXXXXXXXXXKKKKKKKKKK0000000000000000000000000KK000000000OOOOOOOOOOOOOOOOOOO00KKKKK000000OOOkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkx
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdddxxkkkOOO0000KKKKKXXXXXXXXXXXXXK0kkkkkkkkkkkkkkkkkkkkkxxxkkkkkkkOOOOOOOOOO000KKKKKKKKKXXXXXKKKKKKKKKKKKKKKK00000000000000000000000000000OOOOOOOOOOOOOOOOOOOOOO0KKKKKKK000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxdd
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxddxkkkOOOO0000KKKKKKXXXXXXXXXXXXK0kkkkkkkkkkkkkkkkkkkkkxxxxxkkkkkkkOOOOOOOOOOO0000KKKKKKXXXKKKKKKKKKKKKKKKKK0000000000000OO00000000000000OOOOOOOOOOOOOOOOOOOOO000KKKKKK0000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxdddooooooooooo
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxddxkkOOOO00000KKKKKXXXKKXXXXXXXXXKOkkkkkkkkkkkkkkkkkkkkxddxxxkkkkkkkkkkkkkkkkOOOO00000KKKKKKKK000000000K00000000000000000O00000000000000OOOOOOOOOOOOOOOOOOO000000KKKK000000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxdddooooooooooooooooddddxxxx
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxdxxkkOOO000000KKKKKKKKXKKXXXXXXXXK0OkkkkkkkkkkkkkkkkkkkxxxxxkkkkkkkkkkkkkkkkkkkkkOOOOOO000000000000000000000000000000000000000000000000OOOOOOOOOOOOOOOOOOO000000KKKK0000000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxddddoooooooooooooooooddddxxxxxxxxxxkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdddxkkOOO0000KKKKKKKXXXXKKKKXXXXXXK0OkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkxxxdxxxxxxkkkOOOOOOOOOOOO00000000000000OO0000000000000000OOOOOOOOOOOOOOOOOOOO00000000KKK0000000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxddddddooooooddooooooooooddddxxxxxxxxxxxxkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdodxkkOOOOOO000KKKKXXXXXXKKKKKXXKKKK0kkkkkkkkkkkkkkkkkkkkxkkkkOOOkkkkkkkkkkkkkkxxxdddodddddxxxxkkkOOOOOO00OOOO0OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO00000000000000000000000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxddddddddooooodddddddddddddddddddxxxxxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
xxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkxdodxxkkOOOOO0000KKKXXXXXKKKKKKKKKKKK0OkkkkkkkkkkkkkkkkkkxxkkOOOOOOOOOOOkkkkkkkkkkkxxdoooooddxxxxxkkkkkOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO000000000000000000000000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkxxxxxxxxxxxxddddddddoooodddddddddddddddddddddxxxxxxxxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
ddddddddddddddddddddxxxxxxxxxxxxxxdoddxkOOOOOO0000KKKKXXXKKKKKKKKKKKKK0OkkkkkkkkkkkkkkkkkkkkOOOO000000000OOOkkxxxxxxxxddooodddxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkOOOOOOOOOOOOOkkOOOOOOOOOOOOO00000000OOOOOOO0000000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxkxxxxxxxxxxxxxdddddddddddddddddddddddddddddddddddxxxxxxxxxxxxxxxkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
xxxxxxxxxxxxxxxdddddddddddddddxdddooodxkOOOOOOO0000KKKKKKKKKKKKKKKKKKK0OkkkkkkkkkkkkkkkkkkkOOOO000000000000OOOkkxxxdddddddddddxxxkkxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOOOOOOOO0000OOOOOOOO00000000000OOOkxkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxddddddddddddddddddddddddddddddddddddddddddxxxxxxxxxxxxxxxkxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkx
kkkkkkkkkkkkkkkkkxxxxxxxxxxxxxxxxxdoodxkkOOO0OO000000KKKKKKKKKKKKKKKK00kdddddddddddddxxxxkOOO00000000000000000000OOkkxxxxxxxxxxddxkkxxxxxxxxxxxxxkkkkkxxkxxxxkkkkxxxkkkkkkkkkkkkkkkkkkkOOOOOOOOOOkkkkOO0000000000OOOkkxxxxxxxxdxxxxdddddddddddddddddddddddddddddddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxddddoooolloo
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdooodxkOOOOOO000000KKKKKKKKKKKKKKK000kxxxxdddddddddddxkkOOO0000000000000000KKKKKK000OOOOOkkkxxddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkxxkkkkkkkkOOOOOOOkkkkkkOO000000000OOOkkxxdddddddddddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxddooooollllllloooodddxxx
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxolodxkkOOOO0000000KKKKKKKKKKKKKKK000OkkkkkkkkxkxxkxxxkkOOO0000000000000KKKKKKKKKKKKKKKK000OkxxddddxxddxxddxxxxxxddddddddxddddddxxxxxdddxxxxxxxkkkkkkkkkkkkkkkxxxkkkOOOOOOOOOOkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxdddooooooolllloooooodddxxxxkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxooodxxkkOOO0000000KKKKKKKKKKKKKK000OOkkkkkkkkkkkkkkkkkkOOO00000000000K0000KKKKKKKKKKKKKKKKK0Okxddddddddddddddddddddddddddddddddddddddddddddxxxxxkkkkkkkkkkkkkxxxkkxxxkkkkkkxxxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxddddooooooooooolooooooodddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdooodxxkOOO000000KKKKKXXXXKKKKKK000OkkkkkkkkkkkkkkkkkkkOOO0000000000K00000000KKKKKKKKKKKKKKK0Okddooooooooooodddddddddddddddddddddddddddddddddddxxxxxxkkkkkkkkxxxxxdoooooddxxxxxkkxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxdddddoooooooooooooooooddddxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
dxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkdoooodxkkOOO0000KKKKXXXXXXXKKKKK00OOkkkkkkkkkkkkkkxkkkkOOO000000000KKKKK0000000KKKKKKKKKKKKKK0Okdooooooodoooooddoooodddddddoooooooooooooooooddddddxxxxxxxxxxxxxxxdollllodxkkkkkxxddxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxddddddoooooooollooooooooddddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
ddddddddddddddddddddddddxxxxxxkkkkkxoooodxxkkOOO000KKKKXXXXXXXKKKKK00OkkkkkkkkkkkkkkkxxkkOOOO000000000KKKKKK00000KKKKKKKKKKKKKKKK0Okddooooooooooooooooooooooooddoooooooooooooooooooddddddxxxxxxdddddollloodxxxxxddddddxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxddddddoooooooooooolloooooooooddddxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkxxxxxxxddddddddddddddddooooddxxkkOO0000KKKKXXXKKKKKKKK00OkkkkkkkkkkkkkkkxxkkOOOO0000000000KKK0000KKKKKXXKKKKK000KKKKK00kxdoooooooooooooooolooooodkOOOOOkkxoooooooooooooooodddddddddddoolllodddddddddxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxdddddddddooooooooooooooooooooooooooodddddxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdoooodxxkkkOO0000KKKKKKKKKKKKKK0OxddddddddddddddddxkkkOOOO0000000000000000KKKKXXXXXXXXKKKKKKKKK00OxooooooolllllllllloodxkkxO00000kkxdoooooooooooloooooooooooooooodxkkkkkkkkkkkOOOOkxxxdddddddddddddoooooooooooooooooooooooooooooooooddddddddxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxoooodxxxkkkOOO000KKKKKKKKKKKKK00kkkkkkxxxxxxxxxxdxxkkOOOOO0000000000000000KKKKXXXXXXXXKKKKKKK0000kxoloollllllllllooodxO00kxdodddkkO0Okxolooooollllllllloooooooxk000000O00000000O0Oxdoooooooddddddddddddxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdlooddxxxkkkkOO00KKKKKKKKKKKK00OkkkkkkkkkkkkkkOkxxkkkOOOOO000000000000000KKKKKKKKKKKKKXXKXXKK0000OkxolllllllllloodxkxdxkOkdlcccldkO0OOOxdoooollllllclllooooodxO000000000000KKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxoloddxxkkkkkkOO000KKKKKKKKKK00OkkkkkkkkkkkkkkkkxxkkkOOOOOOO000000000000KK00KKKKKKKKKKKKKXXXXK0OkkOkxdlccccloddxxdoodxxk0KKKkddO0KK0OkxxxddoolllllllllllloodxO0000000000KKKKKK0000Okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdloodxxkkkkkkOOO00KKKKKKKKKK00OkkkkkkkkkkkkkkkkkkkkkkOOOOOO000000000000000KKKKKKKKK0KKKKKXXXXK0kxkkkkxolcclodxkkkkkkkO0OkkkkxxO000kdodkkkxoollllllllllloodxO0000KKKKKKKKKKKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxooodxkkkkkOOOOOO000KKKKKKKK0OOkkkkkkkkkkkkkkkkkkOOkkkkOOO0000000000000000KKKKKKKKKK000KKKKKXXXKkddxkxxdlclllll::ododxxdolllllodddxddxdodooollllllllllloxkOO000KKKKKKKKKKKKKKK0000Okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdlllodkkkOOOOOOOO000KKKKKKK0OOkkkkkkkkkkkkkkkkkOOOOkkkOOO0000000000000000KKKKKKKKKK00KKKKKKKKXXKOxddddddoloooolloolllcccccccclllloocloodxdollllllllodxkOOO0000KKKKKKKKKKKKKKK0000Okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkoloodkkOOO00000000KKKKKKKK0OkkkkkkkkkkkkkkkkkOOOOOkkkOOO0000000000000000000KKKKKKKKKKKKKKKKKXXXXKOdooooolclloolc:ccccc::;;;::ccccllooolollccclllodxkOOO00000KKKKKKKKKKKKKKKKK000Okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOxloodxkO000KKKK00KKKKKKKXK0OkkkkkkkkkkkkkkkkkOOOOOkkkOOOO000000000000000000KKKKKKKKKKKKKKKKKKKXKKK0kolllccccccc:::cc:;,,,,,,,:ccclcccccclcllodxxkOOOO0000KKKKKKKKKKKKKKKKKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkdoodxkOO00KKKKKKKKKKKXXXK0OkkkkkkkkkkkkkkkkkkkkkkkkkkOOOO0000000000000000000KKKKKKKKKKKKKKKKKKKKKKKOdlccccccccc:::;;,;loxxo:;::ccccc::clodxkkOkkkOO000KKKXXXKKKKKKKKKKKKKKK0000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxx
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxoodxxkO00KKKKKKKKKKKKXXXKOkkkkkkkkkkkkkxxkkkkkkkkkkkkOOOO0000000000000000000KKKKKKKKKKKKKKKKKKKKKK00xl:ccccccccc:::ldOKXXK0xlc:cccc:cldxkkkkkkkkOO00KXXXXXXXXXXXKKKKKKKKK00000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxdd
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdodkkkO00KKKKKKKKKKKKXXXK0kkkkkkkkkkkkkxxxkkkkkkkkkkkkOOOO0000000000000000000KKKKKKKKKKKKKKKKKKKKKKK0kl::ccccccccclokOKXXXXXOocccccloddxxxddddkO0KKXXXXNNXXXXXXXXXXXXXKKKK0000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxxxddddddddddooooo
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxodkkkO00KKKKKKKKKKKKKXXXKOkkkkkkkkkkkxddxxxxkxxxxxkkkkOOOOOO00000O000000000000KKKKKKKKK00KKKKKKKKKKK0ko:;:c::clldooxO0KXXXKKkllccloodooooodkOKXXXNXXXNNNNNNXXNXXXXXXXXKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxxxxdddddddddddddoooollllllllllooll
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdoxkkOO000KKKKKXXXKKKKXXX0OkkkkkkkkkkxdddxxxxxxxxxxxkkkOOOOOOOOOOOO000OOO00000KK00KKKKKK00KKKKKKKKKKK0Oo;,;:::ldOxldkO0XXXKKOxolllooolodxOKKKXXXNNNNNNNNNNNNNNNXXXXXXXKKKK0000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxddddddddddoodoooolllllllllllloollloooooodddddd
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkdoxkOOO00OO0KKKKKKKKK0KKXX0OkkkkkkkkkdoodddxxxxxxxxxkkkOOOOOOOOOOO00OOOOO0000000000KKKK0000K000KKKKKK00Oo;',;:okKOllxO0KKXXK00kllolloxO0KKKKXXXXXXNNNNNNNNNNNNNNNXXXXXXKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkddddddddddddddddddooooolllllllllllllloooooooooddddddddddddoooooooolo
xxxxxxxxxxxxxxxxxxkkkkkkkkkkkOOkkkkkkkOOkkkxddkkkOOOOOOOO0000000000KKKOkkkkkkkkkdooodddddddddxxxkkkkOOOOOOOOO0OOOOO000000000000KKK000000000KKKKK000ko,..:x0XKdlodxk0KK0OO0klloxO0KKKKKXXXXXXXNNNNNNNNNNNNNNNXXXXXXXKKKK00OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkxoooolllllllllloooolooooooooodddddddddddooooooooooooooooooooddddxx
ddddddddddddddddxdxxxxxxxxxxxxxxxxxxxxxxxxxxxdddxxkkkxxxxkkkOOOOkkOO0K0OOOkkkkOkdlooooddddddddxxxkkkkOOOOOOOOOOOOOO000000000O00000000000K000000K000Oko,'d0KKKKkolloxxxkxOXKxxO000KKKKKXXXXXXXNNNNNNNNNNNNNNNXXXXXXXKKKK00OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxddddddddddxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkdoooloooooddddddddddooooooooooooooooooooooodddddxxxkkkkkkkkkkkkkk
lllllllllllllllloooooooodddddddddddddddddddxxxdoooddddddddddxxkOOOOkO00OkxxxxxxxolloooddddddddxxxxkkkkkkkkOOOOOOOOO0000000O0000000000000000000000000OkooO00KKX0o;::ccccoOXX0000KKKKKKKXXXXXNNNNNNNXXXNNNNNNNNXXXXXXKKKKK00Okkkxxkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxddddddddddddddddddddddddddoooooolllllllldkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkxxdoooooooooooooooooooodddddxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
xxdddddddddoooooooooolooolllllllllllllllllloodoollooooddddodddxxkkOOkO00OxddddddollllooodddddddddxxkkkkkkkkkOOOOOOOOOO000O000000000000000000000000000OkkkkkOO0Odc,'''';dOKK000KKKKKKXXXXXXXNNNNNNXXXXXXNNNNNNXXXXXXKKKKKK0Okxxxxdddddddddddddddddddddddddddddddddoooooooollllllllllllllllllllllllloolloooooddxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkxxdooodddddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
oooooooodooodddddddddxxxxxxxxxxxxddddddoooolccccccllooodddddxxxxxxkkkkO0KOxdollllllllooodddddddddxxxxkkkkkkkkkkOOOOOOOOOOOOOOO00000000000000000000000Oxxddodddddo:;,,:lxkOOOO0KKKXXXXXXXXXXXNNNNNXXXXXXXXXXNNXXXXXXXXXKKK00koooooooollllllllllllllllllllllllllllollloooolloooooooooodddddddddddddddddddddxkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
xxxxxxxxddddddddddoodddddooooooooooooooooool:::::cccllloddddxxkkkkkkOOOO0KXKK0kxollllooodddddxddxxxxxxkkkkkkkkkkOOOOOOOOOOOOOO0000000000000000000000Oxooolcccclll:;;;clooddddk0KKXXXXXXXXXXXXNNNNXXXXXXXXXXXNXXXXXXXXXXKKK0Odoooooooooooooooddoddddddddddddxxddddddddddddoooooooooooooooooddddddddddddddddxkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxdddddddddddoc::::::::cclooooodxkkOOO00O00KKKXXK0xollloooddxxxxxxxxxxxkkkxkkkkkkkOOOOOOOOOOOOOO00000000000OOOO00000OOxccllc:ccccc:::::ccccllok0KKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKK0Oxdddddddddoodoooooooooooddoodddddoooodddoddddddddddddddxxxxxxkkkkkkkkkkkkkkkxkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkoc::;;;;;:::cllcccodxkkOO00000KKKKKXK0xoloooddxxxxxxxxxxxkkkkkkkkkkkkkkOOOOOOOOOOOO0000000000OOOOOOOOOOOxc,;c:::cccc:::::::ccclokO0KKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKK0kdxdddddddddddddxxdxxxxxxxxxkkkkkkkkkkkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxc::;;:;;;:::clllcclodxkOOOO000KKKKKKKKOdoooddxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkOOkOOOOO000000000OOOOOOOOOOkxl,',:::::::::::::ccccloxO0KKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKKK0OOOOOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkl:::;;;;;::::ccloollodxxkkOO000KKKKKKKKKkdoddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOOOOO00000000OOOkkkOOkkkxo:'.....''',;:::ccc::cdxO0KKKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKKK0Okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdc::;;;;;;;;:::ccllcclodxxkOO0000000K00KK0kdddxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOOOOO000000000OOkkkkkkkkxoc;. ...',,;,;,,:oxkO0000KKKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKKKKOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdc::;;;;;;;;;;:::ccclllodxxxkOOOOO0000000KK0xdxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOOOOO000000000OOOOkkkkkkxoc;' ...'''',,,:odxkOO0000KKKKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKXKKKOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdc::;;;;;;;;;;::::::cllooddxxxkkOOO000OO00KKKOxxxkkxkkkkkkkkkkkkkkkkkkkkkkkkkkOOOOOOO000000000OOOkkkkkxdol:,. ..'',,,,;;:ldxkkOO000KKKKKKKKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKK0OkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdcc::;;;;;;;;;;:::::::looodddddxkOOO0OO0OO00O0OxxxxxkkkkkkkkkkxxkkkkkkkkkkkkkkkkkOOOOOOOO000000OOkkkkxxdol:,. ..',,,;;;:lddxxkOO0000KKKKKKKKKKKKXXXKXXXXXXXXXXXXXXXXXXXXXXXXXKKKK0OkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxlc::;;;;;;;;;;;:::::::cloooooodxkOOOO0OkkkkkOOkxxxxkkkkkkkkkkxxxkkkxxxkkkkkkkkkkkOOOOOOOOO000OOOkkkxxddolc;. ..',,;:::lodxxxkOOO00000000KKKKKKKKKKKKKKKKKKKKKKKXXXXXXXXXXXXXXXXXK0Okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxoc::;;;;;;;;;;;:::::::::llooolloxxkkOOdloxxkO0OkxxkkkkkkkkkkxxxxxxxxxxxxxxxkkkkkkOOOOOOOOOO00OOOkxxxxddolc:' ..'',;;::clodxxxkkOOO0000000KKKKKKKKKKKKKKKKKKKKKKKKXXXXXXXXXXXXXXXXKK0OkkkkkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdl:::;;;;;;;;;;;;::::::;:clddddooddxOOdcldxxkO0OkkkkkkkkkkkkxxxxxxxxxxxxxxxxkkkkkOOkkOOOOOOO00OOkxxxdddolc:' .'',;;:cloddxxxkkOOOO0000000K00KKK00KKKKKKKKKKKKKKKXXXXXXXXXXXXXXXXKKK0OkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkoc::;;;;;;;;;;;;;;::cccccloddoooddxkOkolodxkO00OkkkkOkkkkkkxxxxxxxxxxxxxxxxxxkkkkkkkkOOOOOO0OOOkkxddddolc:,. ..',;;:cllodddxxkkkOOOO0000000000000000KKKKKKKKKKKKKXXXXXXXXXXXXXXXXXXKK0OkkkkkkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxoc::;;;;;;;;;;;;:c::ccc::::cllodxkOO0kocodxkO00OkkkkkkkkxxxxxxxxxxxxxxxxxxxkkkkkkkkkOOOOOOOOOOOkxxddoolc:,. .',;;:cllodddxxxkkkOOOO000000000000000KKKKKKKKKKKKXXXXXXXXXXXXXXXXXXXXK0OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxl:::;;;;;;;;;;;;::;;;;;;;::ldkkkkOKKKOocldxkO00OkkkkkkxxxxxxxxxxxxxxxxxxxxkkkkkkkkOOOOOOOOOOOOkxxddoolc:,. .',;:ccllloddddxxkkkOOOOO00000000000000KKKKKKKKKKKKKKXXXXXXXXXXXXXXXXXKK0OkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdc:::;;;;;;;;;;;::::::::::::ldkOOOO000OocdkkO000OkxxxxxxxxxxxxxxxxxxxxxxxxxxxkkkkOOOOOOOOOOOOOkxxddoolc:,. ..,;:cclllodddxxxxxkOOOOOOO000000000000KKKKKKKKKKKKKKKKXXXXXXXXXXXXXXXKKK0OOOkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkOko:::;;;;;;;;;;;:cccccc::::::coxxxxkkO0xcokkxxkkkkxxxxxxxxddxxxdxxxxxxxkkxxxxxkkkkOOOOOOOOOOOkkxxddoolc:,. ..';::cllloodddxxxxkkkOOOOOOOOOO00000000KKKKKKKKKKKKKKKKXXXXXXXXXXXXXXKKK0OOOOkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdc::::::;;;;;;;;:lloolc:;::;;:loxxxkkOkccoxxolodxxxdddddddxxxxxxxxxxxxxkkkkkkkkkkkkkOOOOOOOOkkxxdoooll:;. ..';::clllloodddxxxxkkkkkOOOOOOOOO0000000000KKKKKKKKKKKKKXXXXXXXXXXXXXXKKK0OOkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkdc::::::;;;;;;;;:cccclc;;;;;;;:ldxxkOOkl:loxxxxxxxxdddddddxxxxddddxxxxxxkkkkkkkkkkkkkkkOOkkkkkxxdoollc:;. ..,;::ccllloooddddxxxxkkkkkkOOOOOOO0000000000KKKKKKKKKKKKKKKXXXXXXXXXXXXKK00OkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdc::::::;;;;;;;;;:::::;;;,,,;:coxkOO0Oo;:lodxddxxxddddddddxxdddddxxxxxxxkkkkkkkkkkkkkkkkkkkkxxddoollc:;. ..';::cccllloodddddxxxxxkkkkkOOOOOO0000000000000000KKKKKKKKKKKKXXXXXXXXXKKK0OOOOkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxdolc::::;;;;;;;;;;;;;;,'..,;:oxOO00KOl;:codxkOOxdxdddddddddddddxxxxxxxkkkkkkkkkkkkkkkkkkkkxxddoollc:;'....',::cccllllooodddddxxxxxkkkkkkkOOOOO0000000000000KKKKKKKKKKKKKKKKXXXXXKKK00OOOkOOkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkOOkkkkkkkkkkkkkkkkOOkkkxkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxoc:::;;;;;;;;;:::;;'..';cldkOO00Kx:;ccoxkOOkxdddddddddddddddxxxxxxxxxkkkkkkkkkkkkkkxxxxxddoolcc::;'...',;:ccclllllooodddddxxxxxxxxxkkkOOOOO0000000000000KKKKKKKKKKKKXXKKXKKKKKKK0OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkxxkkkkkkkkkkkkkkkkkkkkkkkOOOkkkkkkkkOkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkxdolc:::;;;:::ccc:,...,:codxOO000l,;:codxxdolodddddddddddddddxxxxxxxxkxxxxxkkkkkkkxxxxxddollcc:coc''',,;::cclllllooooodddddxxxxxxxxkkkkOOO00OOOOO0000000KKKKKKKKKKXXXKKXKKKKKKK00OOOOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkOkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxl:::;;::::cc:,....;:cldkkO00x;',,;:c:;:clooooooddddddddddxxxxxxxxxxxkkkkkkkkxxxxxxdoollcc:cxkl,,,,;:::ccccllllooooddddddxxxxxxxkkkkOOOOOOOOO00000000KKKKKKKKKXXKKXXXKKKKK000OOOkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkkOOkkkkkkkkkkkkkkkkkkkkxkkkOkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxl:::;:::::c:;,'..';:clodkOOOd:;'....';clooooooddddddddddxxxxxxxxxxxkkkkkkkxxxxxxxddoolcc:lkOxl;,;;:::ccccllllllooooddddddxxxxxkkkkOOOOOOO00000000000KKKKKKKKKKKKKKKKKKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkOOOkkkkkkkkOkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOxoc::::::::::;,..',;:clldxkkOOOkdl,',:clooooooooodddddddxxxxxxxxxxxxkkkkxxxxxxxxxddoolc::dOkkxc;;;:::cccccllllloooooodddddxxxxxkkkkOOOOOOOOO000000000KKKKKKKKKKKKKKKKKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkdl:::::;:::;,''.,;;:codxkkxkOO00x:,:cllloooooooooooddddxxxxxxxxxxxkkkxxxxxxxxxdddolcc;cxOkkkxc;;::::cccccclllllloooodddddxxxxxkkkkOOOOOOOOO00000000000KKKKKKKKKKKKKKKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkocc::::::;;;,,;:::clooodooodddl;,;:cllloooooooooddddddddddxxxxxxxkkxxxxxxxxxxddooc::okkkkkkxl::::ccccccccccllllooooodddddxxxkkkOOOOOOOOOO0000000000KKKKKKKKKKKKKKKKKKKK000OkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOkkkkkxkkkkkOkkkkkkkOkkkkkkkkkkOOOkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkOOOkkkkkkkkkkkkkkkOOOkkkkkOkkkkkkkkkkkkkkkkkkkOkkxxdl::::;;;,;cc:;;;::::::::;;,,;::cclllooooooooodddddddddxxxxxxxxxxxxxxxxxxxddoc:cxkkkkkkkxl:::ccccccccccclllloooooddddxxxxkkOOOkkkOOOO00000000000KKKKKKKKKKKKKKKKKKKK00OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkOkkkkkxkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkOkkkkkOkkkkkkkOOkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxl:::::;;;:c::;;;;;;;,'.'',;;::ccllllloollooooooooodddddxxxxxxxxxxxxxxxxxxdoc:okkkkkkkkOxl:ccccccccccccllllllloooooddxxxkkOOOkkOOOOOOOO00000000KKKKKKKKKKKKKKKKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkOOkkkkkkkkkkkkkkkkkkkOkkkkkkkkkOOkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkOkkkkkOOOOkkkkOkkkkkkkkkkOOOkkkkOOOkkkkkkkkkkkkkkkkkkkkkkkkkdl::::::::::;;,,,,,,'...',;;;:ccclllllllllooooooooodddddddxxxxxxxxxxxxkxxdoccdOkkkkkkkkkxlcccccccccccccllllllooooodddxxkkkOOOOOOOOOOOO00000000000KKKKKKKKKKKKKKK0000OOOOkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkOOkkkkkOkkkkkkkkkkkkkkOOkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkOOOOOkkkOOOOkkkkOOOOkkkOOOkkOOkkkkkOOkkkkkkkkOOkkkkOkkkkkkkkkOOOkkkkOkkkxdoc:::::::::;;;;;;,,,,;;;;::ccllllllllllllooooooodddddddddxxxddxxxkkkxxoclkOkkkkkkkkkOkoccccccccccccclllllllloodddxxkkkOOOOOOOO0OO0000000000000KKKKKKKKKKKKKK00000OOOkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkkkkOkkkkkkkkkOOkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
OkkkkkOOOkkkkOOkkkkkkkOOkkkOOOOOkkkkkkkkOkkkkkkOOOOOOOOOOOOOOkkkOkkOOkkkkkkkkkOkkxdolc:::cllllc::;;;::;;:::cccccllllllllooooooooddddddddxxxxxxxxkkkkxocdkkkkkkkOkkOkkkdcccccc::ccccccllllllooooddxxkkkOOOOOOO0000000000000000KKKKKKKKKKKKKK00000OOOkkOOOOOkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkOOOkkkkkkkkkkkkkkkkkkkOOOOOOOOkkkkkkOOOOOkkkkkkOOOOkkkkkOOOOkkkkOOkkkkkkkkkkkkkkkxxxxkkkkxoc:::::::;:::ccccccllllllllooooooooooddddddddxxxxkkkkkkdlxOkkkkkkkkkOkkkkxlcccccc:ccccccclllllooooddxxkkkkOOOOO00000000000000000KKKKKKKKKKKK0000000OOkOOkkkkkkkOOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkOOOOOOkkkOOOOOOOkkkkOOOOkkkkkkkOkkkkkOOOkkkkkOOOkkkkkkkOkkOkkkkdlc::c:::;:::::cccclllllllllllllloooooodddddddxxxkkkkkkdoxOkkkkkkkkkkkkkOkxocccccccccccccclllloooooddxxkkkkkOOO0000000000000000KKK00KKKKKKKKK000000OOOOOkkkOkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkOOOkkkkkkkkkkkkkkkkkkkkkkOOkkkkkkkkOOOOOOkkkOOOkkkkkkkkkkOkkkOkkkkkkkkkkkkkkkOkkkOkkkkkxlccc:::::::::cccccclllllllllllllllloooooodddddxxkkkkkkxdkkkkkkkkkkkkkOOOkkkdlccccccccccccccllllloooddxxkkkkkOOOO00000000000KKKKK0KKKKKKKKKKK0000000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOkkkkkxkkkkkkkOOkkkkkkkkkkkOOOkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkOOOkkkkkkkkkkkkkkkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkdccc:::::::::cccccccclllclllllllllllooooodddddxxxkkkkkxxkkkkkkkkkkkkkkkOkkkkxoccccccccccccccllllloooddxxkkkkOOOOOO00000000K0000K0KKKKKKKK0000000000OOkkkkkkkkkkkkkkkkkkkkkkkkkOOOkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkOkkkkOkkkkkkkkkkkkkkkkkkkkkkOkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOOkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxocc::::::::::ccccccccccccllllllllllllooooooddxxxkkkkkkkkkkkkkkkkkkkkkkOkkkkkxolclcccccccccccllllloooddxxxkkkkkOOO0000000000KKKKKKKKKKK000000000000OOOkkkkkkkkkkkkkkkkkkkkkkOOOOOkkkkkkkkkkOOkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkOOOkkkOOkkkkkkkkkkkkkkkkOkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkdlcc::::::::::cccccccccccccccclllllllllooooddxxxkkkkkxxkkkkkkkkkkkkkkkOkkkkkxkxocccccccccccccllllllooddxxxkkkkkOO000000000KKKKKKKKKK000000000000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kOOkkkOkkkkkkkkkkkkkkkkkkkkkkkkkOkkOOOkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOOkkkkkkkkkkkkkkkkkkkkkkkoccc:::::::::cc::ccccccccccccccccllllllloooddxxxxxkkxxkkkOkkkkkkkkOkkOkkkkkxkkxdllccccccc:ccclllllloodddxxkkkkOOO00000000KKKKKKKKK0000000000000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkOkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkkkOOkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkOkkkkkkkkkkkkkkkkkkkkkkkkdcccc::::::::ccc:cccccccccccccccccclllllloodddxxxxkkxxxkkkOOkkkOkOOOOOkkkkkxkkkkxolccccccccccccclllloodddxxkkkOOOO000000000KKKKK000000000000000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkOkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkkkkkkkkOOOOOOOOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkOkkOkkkkkkkkkkkkkkkkkkkkOkocccc::::::::::::::::::::ccccccccccclllloooddxxxxkkxxxkkkkkkkkkkkkOOOkxkkkxkkxkOkxolcccccccccccclllooodddxxkkkOOOO00000000KKKKKKKK00000000000000OOOOkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkOkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkkkOOkkkkkkkOOOOOOOkkkkkkkkkkkkkkkkkOOkkkkkkkkkkkOOOkkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkxlcccc::::::::::::::::::::::::c::ccccllloooddddxxxxxxxkkkkkkkkkkkkkkOkkkkkxkkkkkOOkdlcccccccccccclllooooddxxkkOOOO00000000KKKKKKKK00000000000000OOOkkOkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkOOOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
kkkkkkkkkkkkkOOOkkkkkkkOOOOOOOOOOkkkkkkkkkkkkkkkkkOOOOOkkkkOOOOOkkkOkkkOkkkkkkkkkkkkkkkkkkkkkkkkkOkoccccc::::::::::::::::::::::::::ccccllllooddddxxxxxdxxkkkkkkkkkkkkOOkkkkkxkkkkkOOOOxllcccccccccccllloooddxxkkOOOO0000000000000KKK00000000OOOOOOOOkkkOkkkkkkkOOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOkkkkkkxkkkkkkkkkkOkkkkkOkkkkkkkkkkkkkkkkkkOkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
*/
v2ray-core-4.34.0/errors.generated.go 0000664 0000000 0000000 00000000312 13774574720 0017407 0 ustar 00root root 0000000 0000000 package core
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/features/ 0000775 0000000 0000000 00000000000 13774574720 0015431 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/features/dns/ 0000775 0000000 0000000 00000000000 13774574720 0016215 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/features/dns/client.go 0000664 0000000 0000000 00000002475 13774574720 0020032 0 ustar 00root root 0000000 0000000 package dns
import (
"v2ray.com/core/common/errors"
"v2ray.com/core/common/net"
"v2ray.com/core/common/serial"
"v2ray.com/core/features"
)
// Client is a V2Ray feature for querying DNS information.
//
// v2ray:api:stable
type Client interface {
features.Feature
// LookupIP returns IP address for the given domain. IPs may contain IPv4 and/or IPv6 addresses.
LookupIP(domain string) ([]net.IP, error)
}
// IPv4Lookup is an optional feature for querying IPv4 addresses only.
//
// v2ray:api:beta
type IPv4Lookup interface {
LookupIPv4(domain string) ([]net.IP, error)
}
// IPv6Lookup is an optional feature for querying IPv6 addresses only.
//
// v2ray:api:beta
type IPv6Lookup interface {
LookupIPv6(domain string) ([]net.IP, error)
}
// ClientType returns the type of Client interface. Can be used for implementing common.HasType.
//
// v2ray:api:beta
func ClientType() interface{} {
return (*Client)(nil)
}
// ErrEmptyResponse indicates that DNS query succeeded but no answer was returned.
var ErrEmptyResponse = errors.New("empty response")
type RCodeError uint16
func (e RCodeError) Error() string {
return serial.Concat("rcode: ", uint16(e))
}
func RCodeFromError(err error) uint16 {
if err == nil {
return 0
}
cause := errors.Cause(err)
if r, ok := cause.(RCodeError); ok {
return uint16(r)
}
return 0
}
v2ray-core-4.34.0/features/dns/localdns/ 0000775 0000000 0000000 00000000000 13774574720 0020014 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/features/dns/localdns/client.go 0000664 0000000 0000000 00000003274 13774574720 0021627 0 ustar 00root root 0000000 0000000 package localdns
import (
"v2ray.com/core/common/net"
"v2ray.com/core/features/dns"
)
// Client is an implementation of dns.Client, which queries localhost for DNS.
type Client struct{}
// Type implements common.HasType.
func (*Client) Type() interface{} {
return dns.ClientType()
}
// Start implements common.Runnable.
func (*Client) Start() error { return nil }
// Close implements common.Closable.
func (*Client) Close() error { return nil }
// LookupIP implements Client.
func (*Client) LookupIP(host string) ([]net.IP, error) {
ips, err := net.LookupIP(host)
if err != nil {
return nil, err
}
parsedIPs := make([]net.IP, 0, len(ips))
for _, ip := range ips {
parsed := net.IPAddress(ip)
if parsed != nil {
parsedIPs = append(parsedIPs, parsed.IP())
}
}
if len(parsedIPs) == 0 {
return nil, dns.ErrEmptyResponse
}
return parsedIPs, nil
}
// LookupIPv4 implements IPv4Lookup.
func (c *Client) LookupIPv4(host string) ([]net.IP, error) {
ips, err := c.LookupIP(host)
if err != nil {
return nil, err
}
ipv4 := make([]net.IP, 0, len(ips))
for _, ip := range ips {
if len(ip) == net.IPv4len {
ipv4 = append(ipv4, ip)
}
}
if len(ipv4) == 0 {
return nil, dns.ErrEmptyResponse
}
return ipv4, nil
}
// LookupIPv6 implements IPv6Lookup.
func (c *Client) LookupIPv6(host string) ([]net.IP, error) {
ips, err := c.LookupIP(host)
if err != nil {
return nil, err
}
ipv6 := make([]net.IP, 0, len(ips))
for _, ip := range ips {
if len(ip) == net.IPv6len {
ipv6 = append(ipv6, ip)
}
}
if len(ipv6) == 0 {
return nil, dns.ErrEmptyResponse
}
return ipv6, nil
}
// New create a new dns.Client that queries localhost for DNS.
func New() *Client {
return &Client{}
}
v2ray-core-4.34.0/features/errors.generated.go 0000664 0000000 0000000 00000000316 13774574720 0021231 0 ustar 00root root 0000000 0000000 package features
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/features/feature.go 0000664 0000000 0000000 00000001256 13774574720 0017417 0 ustar 00root root 0000000 0000000 package features
import "v2ray.com/core/common"
//go:generate go run v2ray.com/core/common/errors/errorgen
// Feature is the interface for V2Ray features. All features must implement this interface.
// All existing features have an implementation in app directory. These features can be replaced by third-party ones.
type Feature interface {
common.HasType
common.Runnable
}
// PrintDeprecatedFeatureWarning prints a warning for deprecated feature.
func PrintDeprecatedFeatureWarning(feature string) {
newError("You are using a deprecated feature: " + feature + ". Please update your config file with latest configuration format, or update your client software.").WriteToLog()
}
v2ray-core-4.34.0/features/inbound/ 0000775 0000000 0000000 00000000000 13774574720 0017067 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/features/inbound/inbound.go 0000664 0000000 0000000 00000002030 13774574720 0021047 0 ustar 00root root 0000000 0000000 package inbound
import (
"context"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/features"
)
// Handler is the interface for handlers that process inbound connections.
//
// v2ray:api:stable
type Handler interface {
common.Runnable
// The tag of this handler.
Tag() string
// Deprecated: Do not use in new code.
GetRandomInboundProxy() (interface{}, net.Port, int)
}
// Manager is a feature that manages InboundHandlers.
//
// v2ray:api:stable
type Manager interface {
features.Feature
// GetHandlers returns an InboundHandler for the given tag.
GetHandler(ctx context.Context, tag string) (Handler, error)
// AddHandler adds the given handler into this Manager.
AddHandler(ctx context.Context, handler Handler) error
// RemoveHandler removes a handler from Manager.
RemoveHandler(ctx context.Context, tag string) error
}
// ManagerType returns the type of Manager interface. Can be used for implementing common.HasType.
//
// v2ray:api:stable
func ManagerType() interface{} {
return (*Manager)(nil)
}
v2ray-core-4.34.0/features/outbound/ 0000775 0000000 0000000 00000000000 13774574720 0017270 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/features/outbound/outbound.go 0000664 0000000 0000000 00000002236 13774574720 0021461 0 ustar 00root root 0000000 0000000 package outbound
import (
"context"
"v2ray.com/core/common"
"v2ray.com/core/features"
"v2ray.com/core/transport"
)
// Handler is the interface for handlers that process outbound connections.
//
// v2ray:api:stable
type Handler interface {
common.Runnable
Tag() string
Dispatch(ctx context.Context, link *transport.Link)
}
type HandlerSelector interface {
Select([]string) []string
}
// Manager is a feature that manages outbound.Handlers.
//
// v2ray:api:stable
type Manager interface {
features.Feature
// GetHandler returns an outbound.Handler for the given tag.
GetHandler(tag string) Handler
// GetDefaultHandler returns the default outbound.Handler. It is usually the first outbound.Handler specified in the configuration.
GetDefaultHandler() Handler
// AddHandler adds a handler into this outbound.Manager.
AddHandler(ctx context.Context, handler Handler) error
// RemoveHandler removes a handler from outbound.Manager.
RemoveHandler(ctx context.Context, tag string) error
}
// ManagerType returns the type of Manager interface. Can be used to implement common.HasType.
//
// v2ray:api:stable
func ManagerType() interface{} {
return (*Manager)(nil)
}
v2ray-core-4.34.0/features/policy/ 0000775 0000000 0000000 00000000000 13774574720 0016730 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/features/policy/default.go 0000664 0000000 0000000 00000001263 13774574720 0020705 0 ustar 00root root 0000000 0000000 package policy
import (
"time"
)
// DefaultManager is the implementation of the Manager.
type DefaultManager struct{}
// Type implements common.HasType.
func (DefaultManager) Type() interface{} {
return ManagerType()
}
// ForLevel implements Manager.
func (DefaultManager) ForLevel(level uint32) Session {
p := SessionDefault()
if level == 1 {
p.Timeouts.ConnectionIdle = time.Second * 600
}
return p
}
// ForSystem implements Manager.
func (DefaultManager) ForSystem() System {
return System{}
}
// Start implements common.Runnable.
func (DefaultManager) Start() error {
return nil
}
// Close implements common.Closable.
func (DefaultManager) Close() error {
return nil
}
v2ray-core-4.34.0/features/policy/policy.go 0000664 0000000 0000000 00000010024 13774574720 0020553 0 ustar 00root root 0000000 0000000 package policy
import (
"context"
"runtime"
"time"
"v2ray.com/core/common/platform"
"v2ray.com/core/features"
)
// Timeout contains limits for connection timeout.
type Timeout struct {
// Timeout for handshake phase in a connection.
Handshake time.Duration
// Timeout for connection being idle, i.e., there is no egress or ingress traffic in this connection.
ConnectionIdle time.Duration
// Timeout for an uplink only connection, i.e., the downlink of the connection has been closed.
UplinkOnly time.Duration
// Timeout for an downlink only connection, i.e., the uplink of the connection has been closed.
DownlinkOnly time.Duration
}
// Stats contains settings for stats counters.
type Stats struct {
// Whether or not to enable stat counter for user uplink traffic.
UserUplink bool
// Whether or not to enable stat counter for user downlink traffic.
UserDownlink bool
}
// Buffer contains settings for internal buffer.
type Buffer struct {
// Size of buffer per connection, in bytes. -1 for unlimited buffer.
PerConnection int32
}
// SystemStats contains stat policy settings on system level.
type SystemStats struct {
// Whether or not to enable stat counter for uplink traffic in inbound handlers.
InboundUplink bool
// Whether or not to enable stat counter for downlink traffic in inbound handlers.
InboundDownlink bool
// Whether or not to enable stat counter for uplink traffic in outbound handlers.
OutboundUplink bool
// Whether or not to enable stat counter for downlink traffic in outbound handlers.
OutboundDownlink bool
}
// System contains policy settings at system level.
type System struct {
Stats SystemStats
Buffer Buffer
}
// Session is session based settings for controlling V2Ray requests. It contains various settings (or limits) that may differ for different users in the context.
type Session struct {
Timeouts Timeout // Timeout settings
Stats Stats
Buffer Buffer
}
// Manager is a feature that provides Policy for the given user by its id or level.
//
// v2ray:api:stable
type Manager interface {
features.Feature
// ForLevel returns the Session policy for the given user level.
ForLevel(level uint32) Session
// ForSystem returns the System policy for V2Ray system.
ForSystem() System
}
// ManagerType returns the type of Manager interface. Can be used to implement common.HasType.
//
// v2ray:api:stable
func ManagerType() interface{} {
return (*Manager)(nil)
}
var defaultBufferSize int32
func init() {
const key = "v2ray.ray.buffer.size"
const defaultValue = -17
size := platform.EnvFlag{
Name: key,
AltName: platform.NormalizeEnvName(key),
}.GetValueAsInt(defaultValue)
switch size {
case 0:
defaultBufferSize = -1 // For pipe to use unlimited size
case defaultValue: // Env flag not defined. Use default values per CPU-arch.
switch runtime.GOARCH {
case "arm", "mips", "mipsle":
defaultBufferSize = 0
case "arm64", "mips64", "mips64le":
defaultBufferSize = 4 * 1024 // 4k cache for low-end devices
default:
defaultBufferSize = 512 * 1024
}
default:
defaultBufferSize = int32(size) * 1024 * 1024
}
}
func defaultBufferPolicy() Buffer {
return Buffer{
PerConnection: defaultBufferSize,
}
}
// SessionDefault returns the Policy when user is not specified.
func SessionDefault() Session {
return Session{
Timeouts: Timeout{
// Align Handshake timeout with nginx client_header_timeout
// So that this value will not indicate server identity
Handshake: time.Second * 60,
ConnectionIdle: time.Second * 300,
UplinkOnly: time.Second * 1,
DownlinkOnly: time.Second * 1,
},
Stats: Stats{
UserUplink: false,
UserDownlink: false,
},
Buffer: defaultBufferPolicy(),
}
}
type policyKey int32
const (
bufferPolicyKey policyKey = 0
)
func ContextWithBufferPolicy(ctx context.Context, p Buffer) context.Context {
return context.WithValue(ctx, bufferPolicyKey, p)
}
func BufferPolicyFromContext(ctx context.Context) Buffer {
pPolicy := ctx.Value(bufferPolicyKey)
if pPolicy == nil {
return defaultBufferPolicy()
}
return pPolicy.(Buffer)
}
v2ray-core-4.34.0/features/routing/ 0000775 0000000 0000000 00000000000 13774574720 0017120 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/features/routing/context.go 0000664 0000000 0000000 00000002373 13774574720 0021140 0 ustar 00root root 0000000 0000000 package routing
import (
"v2ray.com/core/common/net"
)
// Context is a feature to store connection information for routing.
//
// v2ray:api:stable
type Context interface {
// GetInboundTag returns the tag of the inbound the connection was from.
GetInboundTag() string
// GetSourcesIPs returns the source IPs bound to the connection.
GetSourceIPs() []net.IP
// GetSourcePort returns the source port of the connection.
GetSourcePort() net.Port
// GetTargetIPs returns the target IP of the connection or resolved IPs of target domain.
GetTargetIPs() []net.IP
// GetTargetPort returns the target port of the connection.
GetTargetPort() net.Port
// GetTargetDomain returns the target domain of the connection, if exists.
GetTargetDomain() string
// GetNetwork returns the network type of the connection.
GetNetwork() net.Network
// GetProtocol returns the protocol from the connection content, if sniffed out.
GetProtocol() string
// GetUser returns the user email from the connection content, if exists.
GetUser() string
// GetAttributes returns extra attributes from the conneciont content.
GetAttributes() map[string]string
// GetSkipDNSResolve returns a flag switch for weather skip dns resolve during route pick.
GetSkipDNSResolve() bool
}
v2ray-core-4.34.0/features/routing/dispatcher.go 0000664 0000000 0000000 00000001332 13774574720 0021574 0 ustar 00root root 0000000 0000000 package routing
import (
"context"
"v2ray.com/core/common/net"
"v2ray.com/core/features"
"v2ray.com/core/transport"
)
// Dispatcher is a feature that dispatches inbound requests to outbound handlers based on rules.
// Dispatcher is required to be registered in a V2Ray instance to make V2Ray function properly.
//
// v2ray:api:stable
type Dispatcher interface {
features.Feature
// Dispatch returns a Ray for transporting data for the given request.
Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error)
}
// DispatcherType returns the type of Dispatcher interface. Can be used to implement common.HasType.
//
// v2ray:api:stable
func DispatcherType() interface{} {
return (*Dispatcher)(nil)
}
v2ray-core-4.34.0/features/routing/dns/ 0000775 0000000 0000000 00000000000 13774574720 0017704 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/features/routing/dns/context.go 0000664 0000000 0000000 00000002216 13774574720 0021720 0 ustar 00root root 0000000 0000000 package dns
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"v2ray.com/core/common/net"
"v2ray.com/core/features/dns"
"v2ray.com/core/features/routing"
)
// ResolvableContext is an implementation of routing.Context, with domain resolving capability.
type ResolvableContext struct {
routing.Context
dnsClient dns.Client
resolvedIPs []net.IP
}
// GetTargetIPs overrides original routing.Context's implementation.
func (ctx *ResolvableContext) GetTargetIPs() []net.IP {
if ips := ctx.Context.GetTargetIPs(); len(ips) != 0 {
return ips
}
if len(ctx.resolvedIPs) > 0 {
return ctx.resolvedIPs
}
if domain := ctx.GetTargetDomain(); len(domain) != 0 {
ips, err := ctx.dnsClient.LookupIP(domain)
if err == nil {
ctx.resolvedIPs = ips
return ips
}
newError("resolve ip for ", domain).Base(err).WriteToLog()
}
return nil
}
// ContextWithDNSClient creates a new routing context with domain resolving capability.
// Resolved domain IPs can be retrieved by GetTargetIPs().
func ContextWithDNSClient(ctx routing.Context, client dns.Client) routing.Context {
return &ResolvableContext{Context: ctx, dnsClient: client}
}
v2ray-core-4.34.0/features/routing/dns/errors.generated.go 0000664 0000000 0000000 00000000311 13774574720 0023477 0 ustar 00root root 0000000 0000000 package dns
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/features/routing/router.go 0000664 0000000 0000000 00000002652 13774574720 0020774 0 ustar 00root root 0000000 0000000 package routing
import (
"v2ray.com/core/common"
"v2ray.com/core/features"
)
// Router is a feature to choose an outbound tag for the given request.
//
// v2ray:api:stable
type Router interface {
features.Feature
// PickRoute returns a route decision based on the given routing context.
PickRoute(ctx Context) (Route, error)
}
// Route is the routing result of Router feature.
//
// v2ray:api:stable
type Route interface {
// A Route is also a routing context.
Context
// GetOutboundGroupTags returns the detoured outbound group tags in sequence before a final outbound is chosen.
GetOutboundGroupTags() []string
// GetOutboundTag returns the tag of the outbound the connection was dispatched to.
GetOutboundTag() string
}
// RouterType return the type of Router interface. Can be used to implement common.HasType.
//
// v2ray:api:stable
func RouterType() interface{} {
return (*Router)(nil)
}
// DefaultRouter is an implementation of Router, which always returns ErrNoClue for routing decisions.
type DefaultRouter struct{}
// Type implements common.HasType.
func (DefaultRouter) Type() interface{} {
return RouterType()
}
// PickRoute implements Router.
func (DefaultRouter) PickRoute(ctx Context) (Route, error) {
return nil, common.ErrNoClue
}
// Start implements common.Runnable.
func (DefaultRouter) Start() error {
return nil
}
// Close implements common.Closable.
func (DefaultRouter) Close() error {
return nil
}
v2ray-core-4.34.0/features/routing/session/ 0000775 0000000 0000000 00000000000 13774574720 0020603 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/features/routing/session/context.go 0000664 0000000 0000000 00000005603 13774574720 0022622 0 ustar 00root root 0000000 0000000 package session
import (
"context"
"v2ray.com/core/common/net"
"v2ray.com/core/common/session"
"v2ray.com/core/features/routing"
)
// Context is an implementation of routing.Context, which is a wrapper of context.context with session info.
type Context struct {
Inbound *session.Inbound
Outbound *session.Outbound
Content *session.Content
}
// GetInboundTag implements routing.Context.
func (ctx *Context) GetInboundTag() string {
if ctx.Inbound == nil {
return ""
}
return ctx.Inbound.Tag
}
// GetSourceIPs implements routing.Context.
func (ctx *Context) GetSourceIPs() []net.IP {
if ctx.Inbound == nil || !ctx.Inbound.Source.IsValid() {
return nil
}
dest := ctx.Inbound.Source
if dest.Address.Family().IsDomain() {
return nil
}
return []net.IP{dest.Address.IP()}
}
// GetSourcePort implements routing.Context.
func (ctx *Context) GetSourcePort() net.Port {
if ctx.Inbound == nil || !ctx.Inbound.Source.IsValid() {
return 0
}
return ctx.Inbound.Source.Port
}
// GetTargetIPs implements routing.Context.
func (ctx *Context) GetTargetIPs() []net.IP {
if ctx.Outbound == nil || !ctx.Outbound.Target.IsValid() {
return nil
}
if ctx.Outbound.Target.Address.Family().IsIP() {
return []net.IP{ctx.Outbound.Target.Address.IP()}
}
return nil
}
// GetTargetPort implements routing.Context.
func (ctx *Context) GetTargetPort() net.Port {
if ctx.Outbound == nil || !ctx.Outbound.Target.IsValid() {
return 0
}
return ctx.Outbound.Target.Port
}
// GetTargetDomain implements routing.Context.
func (ctx *Context) GetTargetDomain() string {
if ctx.Outbound == nil || !ctx.Outbound.Target.IsValid() {
return ""
}
dest := ctx.Outbound.Target
if !dest.Address.Family().IsDomain() {
return ""
}
return dest.Address.Domain()
}
// GetNetwork implements routing.Context.
func (ctx *Context) GetNetwork() net.Network {
if ctx.Outbound == nil {
return net.Network_Unknown
}
return ctx.Outbound.Target.Network
}
// GetProtocol implements routing.Context.
func (ctx *Context) GetProtocol() string {
if ctx.Content == nil {
return ""
}
return ctx.Content.Protocol
}
// GetUser implements routing.Context.
func (ctx *Context) GetUser() string {
if ctx.Inbound == nil || ctx.Inbound.User == nil {
return ""
}
return ctx.Inbound.User.Email
}
// GetAttributes implements routing.Context.
func (ctx *Context) GetAttributes() map[string]string {
if ctx.Content == nil {
return nil
}
return ctx.Content.Attributes
}
// GetSkipDNSResolve implements routing.Context.
func (ctx *Context) GetSkipDNSResolve() bool {
if ctx.Content == nil {
return false
}
return ctx.Content.SkipDNSResolve
}
// AsRoutingContext creates a context from context.context with session info.
func AsRoutingContext(ctx context.Context) routing.Context {
return &Context{
Inbound: session.InboundFromContext(ctx),
Outbound: session.OutboundFromContext(ctx),
Content: session.ContentFromContext(ctx),
}
}
v2ray-core-4.34.0/features/stats/ 0000775 0000000 0000000 00000000000 13774574720 0016567 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/features/stats/errors.generated.go 0000664 0000000 0000000 00000000313 13774574720 0022364 0 ustar 00root root 0000000 0000000 package stats
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/features/stats/stats.go 0000664 0000000 0000000 00000010473 13774574720 0020261 0 ustar 00root root 0000000 0000000 package stats
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"v2ray.com/core/common"
"v2ray.com/core/features"
)
// Counter is the interface for stats counters.
//
// v2ray:api:stable
type Counter interface {
// Value is the current value of the counter.
Value() int64
// Set sets a new value to the counter, and returns the previous one.
Set(int64) int64
// Add adds a value to the current counter value, and returns the previous value.
Add(int64) int64
}
// Channel is the interface for stats channel.
//
// v2ray:api:stable
type Channel interface {
// Channel is a runnable unit.
common.Runnable
// Publish broadcasts a message through the channel with a controlling context.
Publish(context.Context, interface{})
// SubscriberCount returns the number of the subscribers.
Subscribers() []chan interface{}
// Subscribe registers for listening to channel stream and returns a new listener channel.
Subscribe() (chan interface{}, error)
// Unsubscribe unregisters a listener channel from current Channel object.
Unsubscribe(chan interface{}) error
}
// SubscribeRunnableChannel subscribes the channel and starts it if there is first subscriber coming.
func SubscribeRunnableChannel(c Channel) (chan interface{}, error) {
if len(c.Subscribers()) == 0 {
if err := c.Start(); err != nil {
return nil, err
}
}
return c.Subscribe()
}
// UnsubscribeClosableChannel unsubcribes the channel and close it if there is no more subscriber.
func UnsubscribeClosableChannel(c Channel, sub chan interface{}) error {
if err := c.Unsubscribe(sub); err != nil {
return err
}
if len(c.Subscribers()) == 0 {
return c.Close()
}
return nil
}
// Manager is the interface for stats manager.
//
// v2ray:api:stable
type Manager interface {
features.Feature
// RegisterCounter registers a new counter to the manager. The identifier string must not be empty, and unique among other counters.
RegisterCounter(string) (Counter, error)
// UnregisterCounter unregisters a counter from the manager by its identifier.
UnregisterCounter(string) error
// GetCounter returns a counter by its identifier.
GetCounter(string) Counter
// RegisterChannel registers a new channel to the manager. The identifier string must not be empty, and unique among other channels.
RegisterChannel(string) (Channel, error)
// UnregisterCounter unregisters a channel from the manager by its identifier.
UnregisterChannel(string) error
// GetChannel returns a channel by its identifier.
GetChannel(string) Channel
}
// GetOrRegisterCounter tries to get the StatCounter first. If not exist, it then tries to create a new counter.
func GetOrRegisterCounter(m Manager, name string) (Counter, error) {
counter := m.GetCounter(name)
if counter != nil {
return counter, nil
}
return m.RegisterCounter(name)
}
// GetOrRegisterChannel tries to get the StatChannel first. If not exist, it then tries to create a new channel.
func GetOrRegisterChannel(m Manager, name string) (Channel, error) {
channel := m.GetChannel(name)
if channel != nil {
return channel, nil
}
return m.RegisterChannel(name)
}
// ManagerType returns the type of Manager interface. Can be used to implement common.HasType.
//
// v2ray:api:stable
func ManagerType() interface{} {
return (*Manager)(nil)
}
// NoopManager is an implementation of Manager, which doesn't has actual functionalities.
type NoopManager struct{}
// Type implements common.HasType.
func (NoopManager) Type() interface{} {
return ManagerType()
}
// RegisterCounter implements Manager.
func (NoopManager) RegisterCounter(string) (Counter, error) {
return nil, newError("not implemented")
}
// UnregisterCounter implements Manager.
func (NoopManager) UnregisterCounter(string) error {
return nil
}
// GetCounter implements Manager.
func (NoopManager) GetCounter(string) Counter {
return nil
}
// RegisterChannel implements Manager.
func (NoopManager) RegisterChannel(string) (Channel, error) {
return nil, newError("not implemented")
}
// UnregisterChannel implements Manager.
func (NoopManager) UnregisterChannel(string) error {
return nil
}
// GetChannel implements Manager.
func (NoopManager) GetChannel(string) Channel {
return nil
}
// Start implements common.Runnable.
func (NoopManager) Start() error { return nil }
// Close implements common.Closable.
func (NoopManager) Close() error { return nil }
v2ray-core-4.34.0/functions.go 0000664 0000000 0000000 00000005173 13774574720 0016160 0 ustar 00root root 0000000 0000000 // +build !confonly
package core
import (
"bytes"
"context"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/features/routing"
"v2ray.com/core/transport/internet/udp"
)
// CreateObject creates a new object based on the given V2Ray instance and config. The V2Ray instance may be nil.
func CreateObject(v *Instance, config interface{}) (interface{}, error) {
var ctx context.Context
if v != nil {
ctx = context.WithValue(v.ctx, v2rayKey, v)
}
return common.CreateObject(ctx, config)
}
// StartInstance starts a new V2Ray instance with given serialized config.
// By default V2Ray only support config in protobuf format, i.e., configFormat = "protobuf". Caller need to load other packages to add JSON support.
//
// v2ray:api:stable
func StartInstance(configFormat string, configBytes []byte) (*Instance, error) {
config, err := LoadConfig(configFormat, "", bytes.NewReader(configBytes))
if err != nil {
return nil, err
}
instance, err := New(config)
if err != nil {
return nil, err
}
if err := instance.Start(); err != nil {
return nil, err
}
return instance, nil
}
// Dial provides an easy way for upstream caller to create net.Conn through V2Ray.
// It dispatches the request to the given destination by the given V2Ray instance.
// Since it is under a proxy context, the LocalAddr() and RemoteAddr() in returned net.Conn
// will not show real addresses being used for communication.
//
// v2ray:api:stable
func Dial(ctx context.Context, v *Instance, dest net.Destination) (net.Conn, error) {
dispatcher := v.GetFeature(routing.DispatcherType())
if dispatcher == nil {
return nil, newError("routing.Dispatcher is not registered in V2Ray core")
}
r, err := dispatcher.(routing.Dispatcher).Dispatch(ctx, dest)
if err != nil {
return nil, err
}
var readerOpt net.ConnectionOption
if dest.Network == net.Network_TCP {
readerOpt = net.ConnectionOutputMulti(r.Reader)
} else {
readerOpt = net.ConnectionOutputMultiUDP(r.Reader)
}
return net.NewConnection(net.ConnectionInputMulti(r.Writer), readerOpt), nil
}
// DialUDP provides a way to exchange UDP packets through V2Ray instance to remote servers.
// Since it is under a proxy context, the LocalAddr() in returned PacketConn will not show the real address.
//
// TODO: SetDeadline() / SetReadDeadline() / SetWriteDeadline() are not implemented.
//
// v2ray:api:beta
func DialUDP(ctx context.Context, v *Instance) (net.PacketConn, error) {
dispatcher := v.GetFeature(routing.DispatcherType())
if dispatcher == nil {
return nil, newError("routing.Dispatcher is not registered in V2Ray core")
}
return udp.DialDispatcher(ctx, dispatcher.(routing.Dispatcher))
}
v2ray-core-4.34.0/functions_test.go 0000664 0000000 0000000 00000011265 13774574720 0017216 0 ustar 00root root 0000000 0000000 package core_test
import (
"context"
"crypto/rand"
"io"
"testing"
"time"
"github.com/golang/protobuf/proto"
"github.com/google/go-cmp/cmp"
"v2ray.com/core"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/freedom"
"v2ray.com/core/testing/servers/tcp"
"v2ray.com/core/testing/servers/udp"
)
func xor(b []byte) []byte {
r := make([]byte, len(b))
for i, v := range b {
r[i] = v ^ 'c'
}
return r
}
func xor2(b []byte) []byte {
r := make([]byte, len(b))
for i, v := range b {
r[i] = v ^ 'd'
}
return r
}
func TestV2RayDial(t *testing.T) {
tcpServer := tcp.Server{
MsgProcessor: xor,
}
dest, err := tcpServer.Start()
common.Must(err)
defer tcpServer.Close()
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.InboundConfig{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
cfgBytes, err := proto.Marshal(config)
common.Must(err)
server, err := core.StartInstance("protobuf", cfgBytes)
common.Must(err)
defer server.Close()
conn, err := core.Dial(context.Background(), server, dest)
common.Must(err)
defer conn.Close()
const size = 10240 * 1024
payload := make([]byte, size)
common.Must2(rand.Read(payload))
if _, err := conn.Write(payload); err != nil {
t.Fatal(err)
}
receive := make([]byte, size)
if _, err := io.ReadFull(conn, receive); err != nil {
t.Fatal("failed to read all response: ", err)
}
if r := cmp.Diff(xor(receive), payload); r != "" {
t.Error(r)
}
}
func TestV2RayDialUDPConn(t *testing.T) {
udpServer := udp.Server{
MsgProcessor: xor,
}
dest, err := udpServer.Start()
common.Must(err)
defer udpServer.Close()
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.InboundConfig{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
cfgBytes, err := proto.Marshal(config)
common.Must(err)
server, err := core.StartInstance("protobuf", cfgBytes)
common.Must(err)
defer server.Close()
conn, err := core.Dial(context.Background(), server, dest)
common.Must(err)
defer conn.Close()
const size = 1024
payload := make([]byte, size)
common.Must2(rand.Read(payload))
for i := 0; i < 2; i++ {
if _, err := conn.Write(payload); err != nil {
t.Fatal(err)
}
}
time.Sleep(time.Millisecond * 500)
receive := make([]byte, size*2)
for i := 0; i < 2; i++ {
n, err := conn.Read(receive)
if err != nil {
t.Fatal("expect no error, but got ", err)
}
if n != size {
t.Fatal("expect read size ", size, " but got ", n)
}
if r := cmp.Diff(xor(receive[:n]), payload); r != "" {
t.Fatal(r)
}
}
}
func TestV2RayDialUDP(t *testing.T) {
udpServer1 := udp.Server{
MsgProcessor: xor,
}
dest1, err := udpServer1.Start()
common.Must(err)
defer udpServer1.Close()
udpServer2 := udp.Server{
MsgProcessor: xor2,
}
dest2, err := udpServer2.Start()
common.Must(err)
defer udpServer2.Close()
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.InboundConfig{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
cfgBytes, err := proto.Marshal(config)
common.Must(err)
server, err := core.StartInstance("protobuf", cfgBytes)
common.Must(err)
defer server.Close()
conn, err := core.DialUDP(context.Background(), server)
common.Must(err)
defer conn.Close()
const size = 1024
{
payload := make([]byte, size)
common.Must2(rand.Read(payload))
if _, err := conn.WriteTo(payload, &net.UDPAddr{
IP: dest1.Address.IP(),
Port: int(dest1.Port),
}); err != nil {
t.Fatal(err)
}
receive := make([]byte, size)
if _, _, err := conn.ReadFrom(receive); err != nil {
t.Fatal(err)
}
if r := cmp.Diff(xor(receive), payload); r != "" {
t.Error(r)
}
}
{
payload := make([]byte, size)
common.Must2(rand.Read(payload))
if _, err := conn.WriteTo(payload, &net.UDPAddr{
IP: dest2.Address.IP(),
Port: int(dest2.Port),
}); err != nil {
t.Fatal(err)
}
receive := make([]byte, size)
if _, _, err := conn.ReadFrom(receive); err != nil {
t.Fatal(err)
}
if r := cmp.Diff(xor2(receive), payload); r != "" {
t.Error(r)
}
}
}
v2ray-core-4.34.0/go.mod 0000664 0000000 0000000 00000001456 13774574720 0014727 0 ustar 00root root 0000000 0000000 module v2ray.com/core
go 1.15
require (
github.com/golang/mock v1.4.4
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/pires/go-proxyproto v0.3.3
github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c
github.com/stretchr/testify v1.6.1
github.com/v2fly/VSign v0.0.0-20201108000810-e2adc24bf848
go.starlark.net v0.0.0-20201210151846-e81fc95f7bd5
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/net v0.0.0-20201224014010-6772e930b67b
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
golang.org/x/sys v0.0.0-20201231184435-2d18734c6014
google.golang.org/grpc v1.34.0
google.golang.org/protobuf v1.25.0
h12.io/socks v1.0.2
)
v2ray-core-4.34.0/go.sum 0000664 0000000 0000000 00000101070 13774574720 0014745 0 ustar 00root root 0000000 0000000 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 h1:BS21ZUJ/B5X2UVUbczfmdWH7GapPWAhxcMsDnjJTU1E=
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/ebfe/bcrypt_pbkdf v0.0.0-20140212075826-3c8d2dcb253a h1:YtdtTUN1iH97s+6PUjLnaiKSQj4oG1/EZ3N9bx6g4kU=
github.com/ebfe/bcrypt_pbkdf v0.0.0-20140212075826-3c8d2dcb253a/go.mod h1:/CZpbhAusDOobpcb9yubw46kdYjq0zRC0Wpg9a9zFQM=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
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/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=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
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.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=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364 h1:5XxdakFhqd9dnXoAZy1Mb2R/DZ6D1e+0bGC/JhucGYI=
github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364/go.mod h1:eDJQioIyy4Yn3MVivT7rv/39gAJTrA7lgmYr8EW950c=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lucas-clemente/quic-go v0.19.3 h1:eCDQqvGBB+kCTkA0XrAFtNe81FMa0/fn4QSoeAbmiF4=
github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc=
github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs=
github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07VxbSabxn5A5gZQ=
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/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=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
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.3.3 h1:jOXGrsAfSQVFiD1hWg1aiHpLYsd6SJw/8cLN594sB7Q=
github.com/pires/go-proxyproto v0.3.3/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=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c h1:pqy40B3MQWYrza7YZXOXgl0Nf0QGFqrOC0BKae1UNAA=
github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/v2fly/VSign v0.0.0-20201108000810-e2adc24bf848 h1:p1UzXK6VAutXFFQMnre66h7g1BjRKUnLv0HfmmRoz7w=
github.com/v2fly/VSign v0.0.0-20201108000810-e2adc24bf848/go.mod h1:p80Bv154ZtrGpXMN15slDCqc9UGmfBuUzheDFBYaW/M=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
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-20201210151846-e81fc95f7bd5 h1:F1LaLz0cvAJWMa5r3bogEYXD7/5fgA9a9jOX4DAobN8=
go.starlark.net v0.0.0-20201210151846-e81fc95f7bd5/go.mod h1:vxxlMsgCAPH7BR2LtxjJC4WhhZhCGd/b01+CIpj8H4k=
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=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
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/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/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=
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-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-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/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=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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/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=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201231184435-2d18734c6014 h1:joucsQqXmyBVxViHCPFjG3hx8JzIFSaym3l3MM/Jsdg=
golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/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=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
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-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
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=
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=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
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.34.0 h1:raiipEjMOIC/TO2AvyTxP25XFdLxNIBwzDh3FM3XztI=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
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=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
h12.io/socks v1.0.2 h1:cZhhbV8+DE0Y1kotwhr1a3RC3kFO7AtuZ4GLr3qKSc8=
h12.io/socks v1.0.2/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
v2ray-core-4.34.0/infra/ 0000775 0000000 0000000 00000000000 13774574720 0014712 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/infra/conf/ 0000775 0000000 0000000 00000000000 13774574720 0015637 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/infra/conf/api.go 0000664 0000000 0000000 00000002107 13774574720 0016737 0 ustar 00root root 0000000 0000000 package conf
import (
"strings"
"v2ray.com/core/app/commander"
loggerservice "v2ray.com/core/app/log/command"
handlerservice "v2ray.com/core/app/proxyman/command"
statsservice "v2ray.com/core/app/stats/command"
"v2ray.com/core/common/serial"
)
type APIConfig struct {
Tag string `json:"tag"`
Services []string `json:"services"`
}
func (c *APIConfig) Build() (*commander.Config, error) {
if c.Tag == "" {
return nil, newError("API tag can't be empty.")
}
services := make([]*serial.TypedMessage, 0, 16)
for _, s := range c.Services {
switch strings.ToLower(s) {
case "reflectionservice":
services = append(services, serial.ToTypedMessage(&commander.ReflectionConfig{}))
case "handlerservice":
services = append(services, serial.ToTypedMessage(&handlerservice.Config{}))
case "loggerservice":
services = append(services, serial.ToTypedMessage(&loggerservice.Config{}))
case "statsservice":
services = append(services, serial.ToTypedMessage(&statsservice.Config{}))
}
}
return &commander.Config{
Tag: c.Tag,
Service: services,
}, nil
}
v2ray-core-4.34.0/infra/conf/blackhole.go 0000664 0000000 0000000 00000002172 13774574720 0020114 0 ustar 00root root 0000000 0000000 package conf
import (
"encoding/json"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/blackhole"
)
type NoneResponse struct{}
func (*NoneResponse) Build() (proto.Message, error) {
return new(blackhole.NoneResponse), nil
}
type HTTPResponse struct{}
func (*HTTPResponse) Build() (proto.Message, error) {
return new(blackhole.HTTPResponse), nil
}
type BlackholeConfig struct {
Response json.RawMessage `json:"response"`
}
func (v *BlackholeConfig) Build() (proto.Message, error) {
config := new(blackhole.Config)
if v.Response != nil {
response, _, err := configLoader.Load(v.Response)
if err != nil {
return nil, newError("Config: Failed to parse Blackhole response config.").Base(err)
}
responseSettings, err := response.(Buildable).Build()
if err != nil {
return nil, err
}
config.Response = serial.ToTypedMessage(responseSettings)
}
return config, nil
}
var (
configLoader = NewJSONConfigLoader(
ConfigCreatorCache{
"none": func() interface{} { return new(NoneResponse) },
"http": func() interface{} { return new(HTTPResponse) },
},
"type",
"")
)
v2ray-core-4.34.0/infra/conf/blackhole_test.go 0000664 0000000 0000000 00000001101 13774574720 0021142 0 ustar 00root root 0000000 0000000 package conf_test
import (
"testing"
"v2ray.com/core/common/serial"
. "v2ray.com/core/infra/conf"
"v2ray.com/core/proxy/blackhole"
)
func TestHTTPResponseJSON(t *testing.T) {
creator := func() Buildable {
return new(BlackholeConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"response": {
"type": "http"
}
}`,
Parser: loadJSON(creator),
Output: &blackhole.Config{
Response: serial.ToTypedMessage(&blackhole.HTTPResponse{}),
},
},
{
Input: `{}`,
Parser: loadJSON(creator),
Output: &blackhole.Config{},
},
})
}
v2ray-core-4.34.0/infra/conf/buildable.go 0000664 0000000 0000000 00000000166 13774574720 0020114 0 ustar 00root root 0000000 0000000 package conf
import "github.com/golang/protobuf/proto"
type Buildable interface {
Build() (proto.Message, error)
}
v2ray-core-4.34.0/infra/conf/command/ 0000775 0000000 0000000 00000000000 13774574720 0017255 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/infra/conf/command/command.go 0000664 0000000 0000000 00000002000 13774574720 0021212 0 ustar 00root root 0000000 0000000 package command
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"os"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common"
"v2ray.com/core/infra/conf/serial"
"v2ray.com/core/infra/control"
)
type ConfigCommand struct{}
func (c *ConfigCommand) Name() string {
return "config"
}
func (c *ConfigCommand) Description() control.Description {
return control.Description{
Short: "Convert config among different formats.",
Usage: []string{
"v2ctl config",
},
}
}
func (c *ConfigCommand) Execute(args []string) error {
pbConfig, err := serial.LoadJSONConfig(os.Stdin)
if err != nil {
return newError("failed to parse json config").Base(err)
}
bytesConfig, err := proto.Marshal(pbConfig)
if err != nil {
return newError("failed to marshal proto config").Base(err)
}
if _, err := os.Stdout.Write(bytesConfig); err != nil {
return newError("failed to write proto config").Base(err)
}
return nil
}
func init() {
common.Must(control.RegisterCommand(&ConfigCommand{}))
}
v2ray-core-4.34.0/infra/conf/command/errors.generated.go 0000664 0000000 0000000 00000000315 13774574720 0023054 0 ustar 00root root 0000000 0000000 package command
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/infra/conf/common.go 0000664 0000000 0000000 00000012306 13774574720 0017460 0 ustar 00root root 0000000 0000000 package conf
import (
"encoding/json"
"os"
"strings"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
)
type StringList []string
func NewStringList(raw []string) *StringList {
list := StringList(raw)
return &list
}
func (v StringList) Len() int {
return len(v)
}
func (v *StringList) UnmarshalJSON(data []byte) error {
var strarray []string
if err := json.Unmarshal(data, &strarray); err == nil {
*v = *NewStringList(strarray)
return nil
}
var rawstr string
if err := json.Unmarshal(data, &rawstr); err == nil {
strlist := strings.Split(rawstr, ",")
*v = *NewStringList(strlist)
return nil
}
return newError("unknown format of a string list: " + string(data))
}
type Address struct {
net.Address
}
func (v *Address) UnmarshalJSON(data []byte) error {
var rawStr string
if err := json.Unmarshal(data, &rawStr); err != nil {
return newError("invalid address: ", string(data)).Base(err)
}
v.Address = net.ParseAddress(rawStr)
return nil
}
func (v *Address) Build() *net.IPOrDomain {
return net.NewIPOrDomain(v.Address)
}
type Network string
func (v Network) Build() net.Network {
switch strings.ToLower(string(v)) {
case "tcp":
return net.Network_TCP
case "udp":
return net.Network_UDP
case "unix":
return net.Network_UNIX
default:
return net.Network_Unknown
}
}
type NetworkList []Network
func (v *NetworkList) UnmarshalJSON(data []byte) error {
var strarray []Network
if err := json.Unmarshal(data, &strarray); err == nil {
nl := NetworkList(strarray)
*v = nl
return nil
}
var rawstr Network
if err := json.Unmarshal(data, &rawstr); err == nil {
strlist := strings.Split(string(rawstr), ",")
nl := make([]Network, len(strlist))
for idx, network := range strlist {
nl[idx] = Network(network)
}
*v = nl
return nil
}
return newError("unknown format of a string list: " + string(data))
}
func (v *NetworkList) Build() []net.Network {
if v == nil {
return []net.Network{net.Network_TCP}
}
list := make([]net.Network, 0, len(*v))
for _, network := range *v {
list = append(list, network.Build())
}
return list
}
func parseIntPort(data []byte) (net.Port, error) {
var intPort uint32
err := json.Unmarshal(data, &intPort)
if err != nil {
return net.Port(0), err
}
return net.PortFromInt(intPort)
}
func parseStringPort(s string) (net.Port, net.Port, error) {
if strings.HasPrefix(s, "env:") {
s = s[4:]
s = os.Getenv(s)
}
pair := strings.SplitN(s, "-", 2)
if len(pair) == 0 {
return net.Port(0), net.Port(0), newError("invalid port range: ", s)
}
if len(pair) == 1 {
port, err := net.PortFromString(pair[0])
return port, port, err
}
fromPort, err := net.PortFromString(pair[0])
if err != nil {
return net.Port(0), net.Port(0), err
}
toPort, err := net.PortFromString(pair[1])
if err != nil {
return net.Port(0), net.Port(0), err
}
return fromPort, toPort, nil
}
func parseJSONStringPort(data []byte) (net.Port, net.Port, error) {
var s string
err := json.Unmarshal(data, &s)
if err != nil {
return net.Port(0), net.Port(0), err
}
return parseStringPort(s)
}
type PortRange struct {
From uint32
To uint32
}
func (v *PortRange) Build() *net.PortRange {
return &net.PortRange{
From: v.From,
To: v.To,
}
}
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
func (v *PortRange) UnmarshalJSON(data []byte) error {
port, err := parseIntPort(data)
if err == nil {
v.From = uint32(port)
v.To = uint32(port)
return nil
}
from, to, err := parseJSONStringPort(data)
if err == nil {
v.From = uint32(from)
v.To = uint32(to)
if v.From > v.To {
return newError("invalid port range ", v.From, " -> ", v.To)
}
return nil
}
return newError("invalid port range: ", string(data))
}
type PortList struct {
Range []PortRange
}
func (list *PortList) Build() *net.PortList {
portList := new(net.PortList)
for _, r := range list.Range {
portList.Range = append(portList.Range, r.Build())
}
return portList
}
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
func (list *PortList) UnmarshalJSON(data []byte) error {
var listStr string
var number uint32
if err := json.Unmarshal(data, &listStr); err != nil {
if err2 := json.Unmarshal(data, &number); err2 != nil {
return newError("invalid port: ", string(data)).Base(err2)
}
}
rangelist := strings.Split(listStr, ",")
for _, rangeStr := range rangelist {
trimmed := strings.TrimSpace(rangeStr)
if len(trimmed) > 0 {
if strings.Contains(trimmed, "-") {
from, to, err := parseStringPort(trimmed)
if err != nil {
return newError("invalid port range: ", trimmed).Base(err)
}
list.Range = append(list.Range, PortRange{From: uint32(from), To: uint32(to)})
} else {
port, err := parseIntPort([]byte(trimmed))
if err != nil {
return newError("invalid port: ", trimmed).Base(err)
}
list.Range = append(list.Range, PortRange{From: uint32(port), To: uint32(port)})
}
}
}
if number != 0 {
list.Range = append(list.Range, PortRange{From: number, To: number})
}
return nil
}
type User struct {
EmailString string `json:"email"`
LevelByte byte `json:"level"`
}
func (v *User) Build() *protocol.User {
return &protocol.User{
Email: v.EmailString,
Level: uint32(v.LevelByte),
}
}
v2ray-core-4.34.0/infra/conf/common_test.go 0000664 0000000 0000000 00000011707 13774574720 0020523 0 ustar 00root root 0000000 0000000 package conf_test
import (
"encoding/json"
"os"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
. "v2ray.com/core/infra/conf"
)
func TestStringListUnmarshalError(t *testing.T) {
rawJSON := `1234`
list := new(StringList)
err := json.Unmarshal([]byte(rawJSON), list)
if err == nil {
t.Error("expected error, but got nil")
}
}
func TestStringListLen(t *testing.T) {
rawJSON := `"a, b, c, d"`
var list StringList
err := json.Unmarshal([]byte(rawJSON), &list)
common.Must(err)
if r := cmp.Diff([]string(list), []string{"a", " b", " c", " d"}); r != "" {
t.Error(r)
}
}
func TestIPParsing(t *testing.T) {
rawJSON := "\"8.8.8.8\""
var address Address
err := json.Unmarshal([]byte(rawJSON), &address)
common.Must(err)
if r := cmp.Diff(address.IP(), net.IP{8, 8, 8, 8}); r != "" {
t.Error(r)
}
}
func TestDomainParsing(t *testing.T) {
rawJSON := "\"v2ray.com\""
var address Address
common.Must(json.Unmarshal([]byte(rawJSON), &address))
if address.Domain() != "v2ray.com" {
t.Error("domain: ", address.Domain())
}
}
func TestURLParsing(t *testing.T) {
{
rawJSON := "\"https://dns.google/dns-query\""
var address Address
common.Must(json.Unmarshal([]byte(rawJSON), &address))
if address.Domain() != "https://dns.google/dns-query" {
t.Error("URL: ", address.Domain())
}
}
{
rawJSON := "\"https+local://dns.google/dns-query\""
var address Address
common.Must(json.Unmarshal([]byte(rawJSON), &address))
if address.Domain() != "https+local://dns.google/dns-query" {
t.Error("URL: ", address.Domain())
}
}
}
func TestInvalidAddressJson(t *testing.T) {
rawJSON := "1234"
var address Address
err := json.Unmarshal([]byte(rawJSON), &address)
if err == nil {
t.Error("nil error")
}
}
func TestStringNetwork(t *testing.T) {
var network Network
common.Must(json.Unmarshal([]byte(`"tcp"`), &network))
if v := network.Build(); v != net.Network_TCP {
t.Error("network: ", v)
}
}
func TestArrayNetworkList(t *testing.T) {
var list NetworkList
common.Must(json.Unmarshal([]byte("[\"Tcp\"]"), &list))
nlist := list.Build()
if !net.HasNetwork(nlist, net.Network_TCP) {
t.Error("no tcp network")
}
if net.HasNetwork(nlist, net.Network_UDP) {
t.Error("has udp network")
}
}
func TestStringNetworkList(t *testing.T) {
var list NetworkList
common.Must(json.Unmarshal([]byte("\"TCP, ip\""), &list))
nlist := list.Build()
if !net.HasNetwork(nlist, net.Network_TCP) {
t.Error("no tcp network")
}
if net.HasNetwork(nlist, net.Network_UDP) {
t.Error("has udp network")
}
}
func TestInvalidNetworkJson(t *testing.T) {
var list NetworkList
err := json.Unmarshal([]byte("0"), &list)
if err == nil {
t.Error("nil error")
}
}
func TestIntPort(t *testing.T) {
var portRange PortRange
common.Must(json.Unmarshal([]byte("1234"), &portRange))
if r := cmp.Diff(portRange, PortRange{
From: 1234, To: 1234,
}); r != "" {
t.Error(r)
}
}
func TestOverRangeIntPort(t *testing.T) {
var portRange PortRange
err := json.Unmarshal([]byte("70000"), &portRange)
if err == nil {
t.Error("nil error")
}
err = json.Unmarshal([]byte("-1"), &portRange)
if err == nil {
t.Error("nil error")
}
}
func TestEnvPort(t *testing.T) {
common.Must(os.Setenv("PORT", "1234"))
var portRange PortRange
common.Must(json.Unmarshal([]byte("\"env:PORT\""), &portRange))
if r := cmp.Diff(portRange, PortRange{
From: 1234, To: 1234,
}); r != "" {
t.Error(r)
}
}
func TestSingleStringPort(t *testing.T) {
var portRange PortRange
common.Must(json.Unmarshal([]byte("\"1234\""), &portRange))
if r := cmp.Diff(portRange, PortRange{
From: 1234, To: 1234,
}); r != "" {
t.Error(r)
}
}
func TestStringPairPort(t *testing.T) {
var portRange PortRange
common.Must(json.Unmarshal([]byte("\"1234-5678\""), &portRange))
if r := cmp.Diff(portRange, PortRange{
From: 1234, To: 5678,
}); r != "" {
t.Error(r)
}
}
func TestOverRangeStringPort(t *testing.T) {
var portRange PortRange
err := json.Unmarshal([]byte("\"65536\""), &portRange)
if err == nil {
t.Error("nil error")
}
err = json.Unmarshal([]byte("\"70000-80000\""), &portRange)
if err == nil {
t.Error("nil error")
}
err = json.Unmarshal([]byte("\"1-90000\""), &portRange)
if err == nil {
t.Error("nil error")
}
err = json.Unmarshal([]byte("\"700-600\""), &portRange)
if err == nil {
t.Error("nil error")
}
}
func TestUserParsing(t *testing.T) {
user := new(User)
common.Must(json.Unmarshal([]byte(`{
"id": "96edb838-6d68-42ef-a933-25f7ac3a9d09",
"email": "love@v2ray.com",
"level": 1,
"alterId": 100
}`), user))
nUser := user.Build()
if r := cmp.Diff(nUser, &protocol.User{
Level: 1,
Email: "love@v2ray.com",
}, cmpopts.IgnoreUnexported(protocol.User{})); r != "" {
t.Error(r)
}
}
func TestInvalidUserJson(t *testing.T) {
user := new(User)
err := json.Unmarshal([]byte(`{"email": 1234}`), user)
if err == nil {
t.Error("nil error")
}
}
v2ray-core-4.34.0/infra/conf/conf.go 0000664 0000000 0000000 00000000111 13774574720 0017104 0 ustar 00root root 0000000 0000000 package conf
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/infra/conf/dns.go 0000664 0000000 0000000 00000016574 13774574720 0016767 0 ustar 00root root 0000000 0000000 package conf
import (
"encoding/json"
"sort"
"strings"
"v2ray.com/core/app/dns"
"v2ray.com/core/app/router"
"v2ray.com/core/common/net"
)
type NameServerConfig struct {
Address *Address
ClientIP *Address
Port uint16
Domains []string
ExpectIPs StringList
}
func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
var address Address
if err := json.Unmarshal(data, &address); err == nil {
c.Address = &address
return nil
}
var advanced struct {
Address *Address `json:"address"`
ClientIP *Address `json:"clientIp"`
Port uint16 `json:"port"`
Domains []string `json:"domains"`
ExpectIPs StringList `json:"expectIps"`
}
if err := json.Unmarshal(data, &advanced); err == nil {
c.Address = advanced.Address
c.ClientIP = advanced.ClientIP
c.Port = advanced.Port
c.Domains = advanced.Domains
c.ExpectIPs = advanced.ExpectIPs
return nil
}
return newError("failed to parse name server: ", string(data))
}
func toDomainMatchingType(t router.Domain_Type) dns.DomainMatchingType {
switch t {
case router.Domain_Domain:
return dns.DomainMatchingType_Subdomain
case router.Domain_Full:
return dns.DomainMatchingType_Full
case router.Domain_Plain:
return dns.DomainMatchingType_Keyword
case router.Domain_Regex:
return dns.DomainMatchingType_Regex
default:
panic("unknown domain type")
}
}
func (c *NameServerConfig) Build() (*dns.NameServer, error) {
if c.Address == nil {
return nil, newError("NameServer address is not specified.")
}
var domains []*dns.NameServer_PriorityDomain
var originalRules []*dns.NameServer_OriginalRule
for _, rule := range c.Domains {
parsedDomain, err := parseDomainRule(rule)
if err != nil {
return nil, newError("invalid domain rule: ", rule).Base(err)
}
for _, pd := range parsedDomain {
domains = append(domains, &dns.NameServer_PriorityDomain{
Type: toDomainMatchingType(pd.Type),
Domain: pd.Value,
})
}
originalRules = append(originalRules, &dns.NameServer_OriginalRule{
Rule: rule,
Size: uint32(len(parsedDomain)),
})
}
geoipList, err := toCidrList(c.ExpectIPs)
if err != nil {
return nil, newError("invalid IP rule: ", c.ExpectIPs).Base(err)
}
var myClientIP []byte
if c.ClientIP != nil {
if !c.ClientIP.Family().IsIP() {
return nil, newError("not an IP address:", c.ClientIP.String())
}
myClientIP = []byte(c.ClientIP.IP())
}
return &dns.NameServer{
Address: &net.Endpoint{
Network: net.Network_UDP,
Address: c.Address.Build(),
Port: uint32(c.Port),
},
ClientIp: myClientIP,
PrioritizedDomain: domains,
Geoip: geoipList,
OriginalRules: originalRules,
}, nil
}
var typeMap = map[router.Domain_Type]dns.DomainMatchingType{
router.Domain_Full: dns.DomainMatchingType_Full,
router.Domain_Domain: dns.DomainMatchingType_Subdomain,
router.Domain_Plain: dns.DomainMatchingType_Keyword,
router.Domain_Regex: dns.DomainMatchingType_Regex,
}
// DNSConfig is a JSON serializable object for dns.Config.
type DNSConfig struct {
Servers []*NameServerConfig `json:"servers"`
Hosts map[string]*Address `json:"hosts"`
ClientIP *Address `json:"clientIp"`
Tag string `json:"tag"`
}
func getHostMapping(addr *Address) *dns.Config_HostMapping {
if addr.Family().IsIP() {
return &dns.Config_HostMapping{
Ip: [][]byte{[]byte(addr.IP())},
}
}
return &dns.Config_HostMapping{
ProxiedDomain: addr.Domain(),
}
}
// Build implements Buildable
func (c *DNSConfig) Build() (*dns.Config, error) {
config := &dns.Config{
Tag: c.Tag,
}
if c.ClientIP != nil {
if !c.ClientIP.Family().IsIP() {
return nil, newError("not an IP address:", c.ClientIP.String())
}
config.ClientIp = []byte(c.ClientIP.IP())
}
for _, server := range c.Servers {
ns, err := server.Build()
if err != nil {
return nil, newError("failed to build nameserver").Base(err)
}
config.NameServer = append(config.NameServer, ns)
}
if BootstrapDNS() {
newError("Bootstrap DNS: ", bootstrapDNS).AtWarning().WriteToLog()
}
if c.Hosts != nil && len(c.Hosts) > 0 {
domains := make([]string, 0, len(c.Hosts))
for domain := range c.Hosts {
domains = append(domains, domain)
}
sort.Strings(domains)
for _, domain := range domains {
addr := c.Hosts[domain]
var mappings []*dns.Config_HostMapping
switch {
case strings.HasPrefix(domain, "domain:"):
domainName := domain[7:]
if len(domainName) == 0 {
return nil, newError("empty domain type of rule: ", domain)
}
mapping := getHostMapping(addr)
mapping.Type = dns.DomainMatchingType_Subdomain
mapping.Domain = domainName
mappings = append(mappings, mapping)
case strings.HasPrefix(domain, "geosite:"):
listName := domain[8:]
if len(listName) == 0 {
return nil, newError("empty geosite rule: ", domain)
}
domains, err := loadGeositeWithAttr("geosite.dat", listName)
if err != nil {
return nil, newError("failed to load geosite: ", listName).Base(err)
}
for _, d := range domains {
mapping := getHostMapping(addr)
mapping.Type = typeMap[d.Type]
mapping.Domain = d.Value
mappings = append(mappings, mapping)
}
case strings.HasPrefix(domain, "regexp:"):
regexpVal := domain[7:]
if len(regexpVal) == 0 {
return nil, newError("empty regexp type of rule: ", domain)
}
mapping := getHostMapping(addr)
mapping.Type = dns.DomainMatchingType_Regex
mapping.Domain = regexpVal
mappings = append(mappings, mapping)
case strings.HasPrefix(domain, "keyword:"):
keywordVal := domain[8:]
if len(keywordVal) == 0 {
return nil, newError("empty keyword type of rule: ", domain)
}
mapping := getHostMapping(addr)
mapping.Type = dns.DomainMatchingType_Keyword
mapping.Domain = keywordVal
mappings = append(mappings, mapping)
case strings.HasPrefix(domain, "full:"):
fullVal := domain[5:]
if len(fullVal) == 0 {
return nil, newError("empty full domain type of rule: ", domain)
}
mapping := getHostMapping(addr)
mapping.Type = dns.DomainMatchingType_Full
mapping.Domain = fullVal
mappings = append(mappings, mapping)
case strings.HasPrefix(domain, "dotless:"):
mapping := getHostMapping(addr)
mapping.Type = dns.DomainMatchingType_Regex
switch substr := domain[8:]; {
case substr == "":
mapping.Domain = "^[^.]*$"
case !strings.Contains(substr, "."):
mapping.Domain = "^[^.]*" + substr + "[^.]*$"
default:
return nil, newError("substr in dotless rule should not contain a dot: ", substr)
}
mappings = append(mappings, mapping)
case strings.HasPrefix(domain, "ext:"):
kv := strings.Split(domain[4:], ":")
if len(kv) != 2 {
return nil, newError("invalid external resource: ", domain)
}
filename := kv[0]
list := kv[1]
domains, err := loadGeositeWithAttr(filename, list)
if err != nil {
return nil, newError("failed to load domain list: ", list, " from ", filename).Base(err)
}
for _, d := range domains {
mapping := getHostMapping(addr)
mapping.Type = typeMap[d.Type]
mapping.Domain = d.Value
mappings = append(mappings, mapping)
}
default:
mapping := getHostMapping(addr)
mapping.Type = dns.DomainMatchingType_Full
mapping.Domain = domain
mappings = append(mappings, mapping)
}
config.StaticHosts = append(config.StaticHosts, mappings...)
}
}
return config, nil
}
v2ray-core-4.34.0/infra/conf/dns_bootstrap.go 0000664 0000000 0000000 00000000146 13774574720 0021050 0 ustar 00root root 0000000 0000000 // +build !android
package conf
const bootstrapDNS = ""
func BootstrapDNS() bool {
return false
}
v2ray-core-4.34.0/infra/conf/dns_bootstrap_android.go 0000664 0000000 0000000 00000000654 13774574720 0022554 0 ustar 00root root 0000000 0000000 // +build android
package conf
import (
"context"
"net"
)
const bootstrapDNS = "8.8.8.8:53"
func BootstrapDNS() bool {
var dialer net.Dialer
net.DefaultResolver = &net.Resolver{
PreferGo: false,
Dial: func(context context.Context, _, _ string) (net.Conn, error) {
conn, err := dialer.DialContext(context, "udp", bootstrapDNS)
if err != nil {
return nil, err
}
return conn, nil
},
}
return true
}
v2ray-core-4.34.0/infra/conf/dns_bootstrap_test.go 0000664 0000000 0000000 00000001056 13774574720 0022110 0 ustar 00root root 0000000 0000000 package conf
import (
"context"
"net"
"testing"
)
func TestBootstrapDNS(t *testing.T) {
const (
defaultNS = "8.8.8.8:53"
domain = "github.com"
)
var dialer net.Dialer
net.DefaultResolver = &net.Resolver{
PreferGo: true,
Dial: func(context context.Context, network, address string) (net.Conn, error) {
conn, err := dialer.DialContext(context, "udp", defaultNS)
if err != nil {
return nil, err
}
return conn, nil
},
}
if ips, err := net.LookupIP(domain); len(ips) == 0 {
t.Error("set BootstrapDNS failed: ", err)
}
}
v2ray-core-4.34.0/infra/conf/dns_proxy.go 0000664 0000000 0000000 00000001015 13774574720 0020210 0 ustar 00root root 0000000 0000000 package conf
import (
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/net"
"v2ray.com/core/proxy/dns"
)
type DNSOutboundConfig struct {
Network Network `json:"network"`
Address *Address `json:"address"`
Port uint16 `json:"port"`
}
func (c *DNSOutboundConfig) Build() (proto.Message, error) {
config := &dns.Config{
Server: &net.Endpoint{
Network: c.Network.Build(),
Port: uint32(c.Port),
},
}
if c.Address != nil {
config.Server.Address = c.Address.Build()
}
return config, nil
}
v2ray-core-4.34.0/infra/conf/dns_proxy_test.go 0000664 0000000 0000000 00000001104 13774574720 0021246 0 ustar 00root root 0000000 0000000 package conf_test
import (
"testing"
"v2ray.com/core/common/net"
. "v2ray.com/core/infra/conf"
"v2ray.com/core/proxy/dns"
)
func TestDnsProxyConfig(t *testing.T) {
creator := func() Buildable {
return new(DNSOutboundConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"address": "8.8.8.8",
"port": 53,
"network": "tcp"
}`,
Parser: loadJSON(creator),
Output: &dns.Config{
Server: &net.Endpoint{
Network: net.Network_TCP,
Address: net.NewIPOrDomain(net.IPAddress([]byte{8, 8, 8, 8})),
Port: 53,
},
},
},
})
}
v2ray-core-4.34.0/infra/conf/dns_test.go 0000664 0000000 0000000 00000006531 13774574720 0020016 0 ustar 00root root 0000000 0000000 package conf_test
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"github.com/golang/protobuf/proto"
"v2ray.com/core/app/dns"
"v2ray.com/core/app/router"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/common/platform"
"v2ray.com/core/common/platform/filesystem"
. "v2ray.com/core/infra/conf"
)
func init() {
wd, err := os.Getwd()
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")))
}
geositeFilePath := filepath.Join(wd, "geosite.dat")
os.Setenv("v2ray.location.asset", wd)
geositeFile, err := os.OpenFile(geositeFilePath, os.O_CREATE|os.O_WRONLY, 0600)
common.Must(err)
defer geositeFile.Close()
list := &router.GeoSiteList{
Entry: []*router.GeoSite{
{
CountryCode: "TEST",
Domain: []*router.Domain{
{Type: router.Domain_Full, Value: "example.com"},
},
},
},
}
listBytes, err := proto.Marshal(list)
common.Must(err)
common.Must2(geositeFile.Write(listBytes))
}
func TestDNSConfigParsing(t *testing.T) {
geositePath := platform.GetAssetLocation("geosite.dat")
defer func() {
os.Remove(geositePath)
os.Unsetenv("v2ray.location.asset")
}()
parserCreator := func() func(string) (proto.Message, error) {
return func(s string) (proto.Message, error) {
config := new(DNSConfig)
if err := json.Unmarshal([]byte(s), config); err != nil {
return nil, err
}
return config.Build()
}
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"servers": [{
"address": "8.8.8.8",
"clientIp": "10.0.0.1",
"port": 5353,
"domains": ["domain:v2ray.com"]
}],
"hosts": {
"v2ray.com": "127.0.0.1",
"domain:example.com": "google.com",
"geosite:test": "10.0.0.1",
"keyword:google": "8.8.8.8",
"regexp:.*\\.com": "8.8.4.4"
},
"clientIp": "10.0.0.1"
}`,
Parser: parserCreator(),
Output: &dns.Config{
NameServer: []*dns.NameServer{
{
Address: &net.Endpoint{
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{8, 8, 8, 8},
},
},
Network: net.Network_UDP,
Port: 5353,
},
ClientIp: []byte{10, 0, 0, 1},
PrioritizedDomain: []*dns.NameServer_PriorityDomain{
{
Type: dns.DomainMatchingType_Subdomain,
Domain: "v2ray.com",
},
},
OriginalRules: []*dns.NameServer_OriginalRule{
{
Rule: "domain:v2ray.com",
Size: 1,
},
},
},
},
StaticHosts: []*dns.Config_HostMapping{
{
Type: dns.DomainMatchingType_Subdomain,
Domain: "example.com",
ProxiedDomain: "google.com",
},
{
Type: dns.DomainMatchingType_Full,
Domain: "example.com",
Ip: [][]byte{{10, 0, 0, 1}},
},
{
Type: dns.DomainMatchingType_Keyword,
Domain: "google",
Ip: [][]byte{{8, 8, 8, 8}},
},
{
Type: dns.DomainMatchingType_Regex,
Domain: ".*\\.com",
Ip: [][]byte{{8, 8, 4, 4}},
},
{
Type: dns.DomainMatchingType_Full,
Domain: "v2ray.com",
Ip: [][]byte{{127, 0, 0, 1}},
},
},
ClientIp: []byte{10, 0, 0, 1},
},
},
})
}
v2ray-core-4.34.0/infra/conf/dokodemo.go 0000664 0000000 0000000 00000001347 13774574720 0017774 0 ustar 00root root 0000000 0000000 package conf
import (
"github.com/golang/protobuf/proto"
"v2ray.com/core/proxy/dokodemo"
)
type DokodemoConfig struct {
Host *Address `json:"address"`
PortValue uint16 `json:"port"`
NetworkList *NetworkList `json:"network"`
TimeoutValue uint32 `json:"timeout"`
Redirect bool `json:"followRedirect"`
UserLevel uint32 `json:"userLevel"`
}
func (v *DokodemoConfig) Build() (proto.Message, error) {
config := new(dokodemo.Config)
if v.Host != nil {
config.Address = v.Host.Build()
}
config.Port = uint32(v.PortValue)
config.Networks = v.NetworkList.Build()
config.Timeout = v.TimeoutValue
config.FollowRedirect = v.Redirect
config.UserLevel = v.UserLevel
return config, nil
}
v2ray-core-4.34.0/infra/conf/dokodemo_test.go 0000664 0000000 0000000 00000001371 13774574720 0021030 0 ustar 00root root 0000000 0000000 package conf_test
import (
"testing"
"v2ray.com/core/common/net"
. "v2ray.com/core/infra/conf"
"v2ray.com/core/proxy/dokodemo"
)
func TestDokodemoConfig(t *testing.T) {
creator := func() Buildable {
return new(DokodemoConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"address": "8.8.8.8",
"port": 53,
"network": "tcp",
"timeout": 10,
"followRedirect": true,
"userLevel": 1
}`,
Parser: loadJSON(creator),
Output: &dokodemo.Config{
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{8, 8, 8, 8},
},
},
Port: 53,
Networks: []net.Network{net.Network_TCP},
Timeout: 10,
FollowRedirect: true,
UserLevel: 1,
},
},
})
}
v2ray-core-4.34.0/infra/conf/errors.generated.go 0000664 0000000 0000000 00000000312 13774574720 0021433 0 ustar 00root root 0000000 0000000 package conf
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/infra/conf/freedom.go 0000664 0000000 0000000 00000003100 13774574720 0017601 0 ustar 00root root 0000000 0000000 package conf
import (
"net"
"strings"
"github.com/golang/protobuf/proto"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/proxy/freedom"
)
type FreedomConfig struct {
DomainStrategy string `json:"domainStrategy"`
Timeout *uint32 `json:"timeout"`
Redirect string `json:"redirect"`
UserLevel uint32 `json:"userLevel"`
}
// Build implements Buildable
func (c *FreedomConfig) Build() (proto.Message, error) {
config := new(freedom.Config)
config.DomainStrategy = freedom.Config_AS_IS
switch strings.ToLower(c.DomainStrategy) {
case "useip", "use_ip":
config.DomainStrategy = freedom.Config_USE_IP
case "useip4", "useipv4", "use_ipv4", "use_ip_v4", "use_ip4":
config.DomainStrategy = freedom.Config_USE_IP4
case "useip6", "useipv6", "use_ipv6", "use_ip_v6", "use_ip6":
config.DomainStrategy = freedom.Config_USE_IP6
}
if c.Timeout != nil {
config.Timeout = *c.Timeout
}
config.UserLevel = c.UserLevel
if len(c.Redirect) > 0 {
host, portStr, err := net.SplitHostPort(c.Redirect)
if err != nil {
return nil, newError("invalid redirect address: ", c.Redirect, ": ", err).Base(err)
}
port, err := v2net.PortFromString(portStr)
if err != nil {
return nil, newError("invalid redirect port: ", c.Redirect, ": ", err).Base(err)
}
config.DestinationOverride = &freedom.DestinationOverride{
Server: &protocol.ServerEndpoint{
Port: uint32(port),
},
}
if len(host) > 0 {
config.DestinationOverride.Server.Address = v2net.NewIPOrDomain(v2net.ParseAddress(host))
}
}
return config, nil
}
v2ray-core-4.34.0/infra/conf/freedom_test.go 0000664 0000000 0000000 00000001505 13774574720 0020647 0 ustar 00root root 0000000 0000000 package conf_test
import (
"testing"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
. "v2ray.com/core/infra/conf"
"v2ray.com/core/proxy/freedom"
)
func TestFreedomConfig(t *testing.T) {
creator := func() Buildable {
return new(FreedomConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"domainStrategy": "AsIs",
"timeout": 10,
"redirect": "127.0.0.1:3366",
"userLevel": 1
}`,
Parser: loadJSON(creator),
Output: &freedom.Config{
DomainStrategy: freedom.Config_AS_IS,
Timeout: 10,
DestinationOverride: &freedom.DestinationOverride{
Server: &protocol.ServerEndpoint{
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: 3366,
},
},
UserLevel: 1,
},
},
})
}
v2ray-core-4.34.0/infra/conf/general_test.go 0000664 0000000 0000000 00000001527 13774574720 0020647 0 ustar 00root root 0000000 0000000 package conf_test
import (
"encoding/json"
"testing"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common"
. "v2ray.com/core/infra/conf"
)
func loadJSON(creator func() Buildable) func(string) (proto.Message, error) {
return func(s string) (proto.Message, error) {
instance := creator()
if err := json.Unmarshal([]byte(s), instance); err != nil {
return nil, err
}
return instance.Build()
}
}
type TestCase struct {
Input string
Parser func(string) (proto.Message, error)
Output proto.Message
}
func runMultiTestCase(t *testing.T, testCases []TestCase) {
for _, testCase := range testCases {
actual, err := testCase.Parser(testCase.Input)
common.Must(err)
if !proto.Equal(actual, testCase.Output) {
t.Fatalf("Failed in test case:\n%s\nActual:\n%v\nExpected:\n%v", testCase.Input, actual, testCase.Output)
}
}
}
v2ray-core-4.34.0/infra/conf/http.go 0000664 0000000 0000000 00000004105 13774574720 0017145 0 ustar 00root root 0000000 0000000 package conf
import (
"encoding/json"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/http"
)
type HTTPAccount struct {
Username string `json:"user"`
Password string `json:"pass"`
}
func (v *HTTPAccount) Build() *http.Account {
return &http.Account{
Username: v.Username,
Password: v.Password,
}
}
type HTTPServerConfig struct {
Timeout uint32 `json:"timeout"`
Accounts []*HTTPAccount `json:"accounts"`
Transparent bool `json:"allowTransparent"`
UserLevel uint32 `json:"userLevel"`
}
func (c *HTTPServerConfig) Build() (proto.Message, error) {
config := &http.ServerConfig{
Timeout: c.Timeout,
AllowTransparent: c.Transparent,
UserLevel: c.UserLevel,
}
if len(c.Accounts) > 0 {
config.Accounts = make(map[string]string)
for _, account := range c.Accounts {
config.Accounts[account.Username] = account.Password
}
}
return config, nil
}
type HTTPRemoteConfig struct {
Address *Address `json:"address"`
Port uint16 `json:"port"`
Users []json.RawMessage `json:"users"`
}
type HTTPClientConfig struct {
Servers []*HTTPRemoteConfig `json:"servers"`
}
func (v *HTTPClientConfig) Build() (proto.Message, error) {
config := new(http.ClientConfig)
config.Server = make([]*protocol.ServerEndpoint, len(v.Servers))
for idx, serverConfig := range v.Servers {
server := &protocol.ServerEndpoint{
Address: serverConfig.Address.Build(),
Port: uint32(serverConfig.Port),
}
for _, rawUser := range serverConfig.Users {
user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil {
return nil, newError("failed to parse HTTP user").Base(err).AtError()
}
account := new(HTTPAccount)
if err := json.Unmarshal(rawUser, account); err != nil {
return nil, newError("failed to parse HTTP account").Base(err).AtError()
}
user.Account = serial.ToTypedMessage(account.Build())
server.User = append(server.User, user)
}
config.Server[idx] = server
}
return config, nil
}
v2ray-core-4.34.0/infra/conf/http_test.go 0000664 0000000 0000000 00000001230 13774574720 0020200 0 ustar 00root root 0000000 0000000 package conf_test
import (
"testing"
. "v2ray.com/core/infra/conf"
"v2ray.com/core/proxy/http"
)
func TestHTTPServerConfig(t *testing.T) {
creator := func() Buildable {
return new(HTTPServerConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"timeout": 10,
"accounts": [
{
"user": "my-username",
"pass": "my-password"
}
],
"allowTransparent": true,
"userLevel": 1
}`,
Parser: loadJSON(creator),
Output: &http.ServerConfig{
Accounts: map[string]string{
"my-username": "my-password",
},
AllowTransparent: true,
UserLevel: 1,
Timeout: 10,
},
},
})
}
v2ray-core-4.34.0/infra/conf/json/ 0000775 0000000 0000000 00000000000 13774574720 0016610 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/infra/conf/json/reader.go 0000664 0000000 0000000 00000004771 13774574720 0020412 0 ustar 00root root 0000000 0000000 package json
import (
"io"
"v2ray.com/core/common/buf"
)
// State is the internal state of parser.
type State byte
const (
StateContent State = iota
StateEscape
StateDoubleQuote
StateDoubleQuoteEscape
StateSingleQuote
StateSingleQuoteEscape
StateComment
StateSlash
StateMultilineComment
StateMultilineCommentStar
)
// Reader is a reader for filtering comments.
// It supports Java style single and multi line comment syntax, and Python style single line comment syntax.
type Reader struct {
io.Reader
state State
br *buf.BufferedReader
}
// Read implements io.Reader.Read(). Buffer must be at least 3 bytes.
func (v *Reader) Read(b []byte) (int, error) {
if v.br == nil {
v.br = &buf.BufferedReader{Reader: buf.NewReader(v.Reader)}
}
p := b[:0]
for len(p) < len(b)-2 {
x, err := v.br.ReadByte()
if err != nil {
if len(p) == 0 {
return 0, err
}
return len(p), nil
}
switch v.state {
case StateContent:
switch x {
case '"':
v.state = StateDoubleQuote
p = append(p, x)
case '\'':
v.state = StateSingleQuote
p = append(p, x)
case '\\':
v.state = StateEscape
case '#':
v.state = StateComment
case '/':
v.state = StateSlash
default:
p = append(p, x)
}
case StateEscape:
p = append(p, '\\', x)
v.state = StateContent
case StateDoubleQuote:
switch x {
case '"':
v.state = StateContent
p = append(p, x)
case '\\':
v.state = StateDoubleQuoteEscape
default:
p = append(p, x)
}
case StateDoubleQuoteEscape:
p = append(p, '\\', x)
v.state = StateDoubleQuote
case StateSingleQuote:
switch x {
case '\'':
v.state = StateContent
p = append(p, x)
case '\\':
v.state = StateSingleQuoteEscape
default:
p = append(p, x)
}
case StateSingleQuoteEscape:
p = append(p, '\\', x)
v.state = StateSingleQuote
case StateComment:
if x == '\n' {
v.state = StateContent
p = append(p, '\n')
}
case StateSlash:
switch x {
case '/':
v.state = StateComment
case '*':
v.state = StateMultilineComment
default:
p = append(p, '/', x)
}
case StateMultilineComment:
switch x {
case '*':
v.state = StateMultilineCommentStar
case '\n':
p = append(p, '\n')
}
case StateMultilineCommentStar:
switch x {
case '/':
v.state = StateContent
case '*':
// Stay
case '\n':
p = append(p, '\n')
default:
v.state = StateMultilineComment
}
default:
panic("Unknown state.")
}
}
return len(p), nil
}
v2ray-core-4.34.0/infra/conf/json/reader_test.go 0000664 0000000 0000000 00000003556 13774574720 0021451 0 ustar 00root root 0000000 0000000 package json_test
import (
"bytes"
"io"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
. "v2ray.com/core/infra/conf/json"
)
func TestReader(t *testing.T) {
data := []struct {
input string
output string
}{
{
`
content #comment 1
#comment 2
content 2`,
`
content
content 2`},
{`content`, `content`},
{" ", " "},
{`con/*abcd*/tent`, "content"},
{`
text // adlkhdf /*
//comment adfkj
text 2*/`, `
text
text 2*`},
{`"//"content`, `"//"content`},
{`abcd'//'abcd`, `abcd'//'abcd`},
{`"\""`, `"\""`},
{`\"/*abcd*/\"`, `\"\"`},
}
for _, testCase := range data {
reader := &Reader{
Reader: bytes.NewReader([]byte(testCase.input)),
}
actual := make([]byte, 1024)
n, err := reader.Read(actual)
common.Must(err)
if r := cmp.Diff(string(actual[:n]), testCase.output); r != "" {
t.Error(r)
}
}
}
func TestReader1(t *testing.T) {
type dataStruct struct {
input string
output string
}
bufLen := 8
data := []dataStruct{
{"loooooooooooooooooooooooooooooooooooooooog", "loooooooooooooooooooooooooooooooooooooooog"},
{`{"t": "\/testlooooooooooooooooooooooooooooong"}`, `{"t": "\/testlooooooooooooooooooooooooooooong"}`},
{`{"t": "\/test"}`, `{"t": "\/test"}`},
{`"\// fake comment"`, `"\// fake comment"`},
{`"\/\/\/\/\/"`, `"\/\/\/\/\/"`},
}
for _, testCase := range data {
reader := &Reader{
Reader: bytes.NewReader([]byte(testCase.input)),
}
target := make([]byte, 0)
buf := make([]byte, bufLen)
var n int
var err error
for n, err = reader.Read(buf); err == nil; n, err = reader.Read(buf) {
if n > len(buf) {
t.Error("n: ", n)
}
target = append(target, buf[:n]...)
buf = make([]byte, bufLen)
}
if err != nil && err != io.EOF {
t.Error("error: ", err)
}
if string(target) != testCase.output {
t.Error("got ", string(target), " want ", testCase.output)
}
}
}
v2ray-core-4.34.0/infra/conf/loader.go 0000664 0000000 0000000 00000003545 13774574720 0017443 0 ustar 00root root 0000000 0000000 package conf
import (
"encoding/json"
"strings"
)
type ConfigCreator func() interface{}
type ConfigCreatorCache map[string]ConfigCreator
func (v ConfigCreatorCache) RegisterCreator(id string, creator ConfigCreator) error {
if _, found := v[id]; found {
return newError(id, " already registered.").AtError()
}
v[id] = creator
return nil
}
func (v ConfigCreatorCache) CreateConfig(id string) (interface{}, error) {
creator, found := v[id]
if !found {
return nil, newError("unknown config id: ", id)
}
return creator(), nil
}
type JSONConfigLoader struct {
cache ConfigCreatorCache
idKey string
configKey string
}
func NewJSONConfigLoader(cache ConfigCreatorCache, idKey string, configKey string) *JSONConfigLoader {
return &JSONConfigLoader{
idKey: idKey,
configKey: configKey,
cache: cache,
}
}
func (v *JSONConfigLoader) LoadWithID(raw []byte, id string) (interface{}, error) {
id = strings.ToLower(id)
config, err := v.cache.CreateConfig(id)
if err != nil {
return nil, err
}
if err := json.Unmarshal(raw, config); err != nil {
return nil, err
}
return config, nil
}
func (v *JSONConfigLoader) Load(raw []byte) (interface{}, string, error) {
var obj map[string]json.RawMessage
if err := json.Unmarshal(raw, &obj); err != nil {
return nil, "", err
}
rawID, found := obj[v.idKey]
if !found {
return nil, "", newError(v.idKey, " not found in JSON context").AtError()
}
var id string
if err := json.Unmarshal(rawID, &id); err != nil {
return nil, "", err
}
rawConfig := json.RawMessage(raw)
if len(v.configKey) > 0 {
configValue, found := obj[v.configKey]
if found {
rawConfig = configValue
} else {
// Default to empty json object.
rawConfig = json.RawMessage([]byte("{}"))
}
}
config, err := v.LoadWithID([]byte(rawConfig), id)
if err != nil {
return nil, id, err
}
return config, id, nil
}
v2ray-core-4.34.0/infra/conf/log.go 0000664 0000000 0000000 00000002514 13774574720 0016751 0 ustar 00root root 0000000 0000000 package conf
import (
"strings"
"v2ray.com/core/app/log"
clog "v2ray.com/core/common/log"
)
func DefaultLogConfig() *log.Config {
return &log.Config{
AccessLogType: log.LogType_None,
ErrorLogType: log.LogType_Console,
ErrorLogLevel: clog.Severity_Warning,
}
}
type LogConfig struct {
AccessLog string `json:"access"`
ErrorLog string `json:"error"`
LogLevel string `json:"loglevel"`
}
func (v *LogConfig) Build() *log.Config {
if v == nil {
return nil
}
config := &log.Config{
ErrorLogType: log.LogType_Console,
AccessLogType: log.LogType_Console,
}
if v.AccessLog == "none" {
config.AccessLogType = log.LogType_None
} else if len(v.AccessLog) > 0 {
config.AccessLogPath = v.AccessLog
config.AccessLogType = log.LogType_File
}
if v.ErrorLog == "none" {
config.ErrorLogType = log.LogType_None
} else if len(v.ErrorLog) > 0 {
config.ErrorLogPath = v.ErrorLog
config.ErrorLogType = log.LogType_File
}
level := strings.ToLower(v.LogLevel)
switch level {
case "debug":
config.ErrorLogLevel = clog.Severity_Debug
case "info":
config.ErrorLogLevel = clog.Severity_Info
case "error":
config.ErrorLogLevel = clog.Severity_Error
case "none":
config.ErrorLogType = log.LogType_None
config.AccessLogType = log.LogType_None
default:
config.ErrorLogLevel = clog.Severity_Warning
}
return config
}
v2ray-core-4.34.0/infra/conf/mtproto.go 0000664 0000000 0000000 00000003206 13774574720 0017673 0 ustar 00root root 0000000 0000000 package conf
import (
"encoding/hex"
"encoding/json"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/mtproto"
)
type MTProtoAccount struct {
Secret string `json:"secret"`
}
// Build implements Buildable
func (a *MTProtoAccount) Build() (*mtproto.Account, error) {
if len(a.Secret) != 32 {
return nil, newError("MTProto secret must have 32 chars")
}
secret, err := hex.DecodeString(a.Secret)
if err != nil {
return nil, newError("failed to decode secret: ", a.Secret).Base(err)
}
return &mtproto.Account{
Secret: secret,
}, nil
}
type MTProtoServerConfig struct {
Users []json.RawMessage `json:"users"`
}
func (c *MTProtoServerConfig) Build() (proto.Message, error) {
config := &mtproto.ServerConfig{}
if len(c.Users) == 0 {
return nil, newError("zero MTProto users configured.")
}
config.User = make([]*protocol.User, len(c.Users))
for idx, rawData := range c.Users {
user := new(protocol.User)
if err := json.Unmarshal(rawData, user); err != nil {
return nil, newError("invalid MTProto user").Base(err)
}
account := new(MTProtoAccount)
if err := json.Unmarshal(rawData, account); err != nil {
return nil, newError("invalid MTProto user").Base(err)
}
accountProto, err := account.Build()
if err != nil {
return nil, newError("failed to parse MTProto user").Base(err)
}
user.Account = serial.ToTypedMessage(accountProto)
config.User[idx] = user
}
return config, nil
}
type MTProtoClientConfig struct {
}
func (c *MTProtoClientConfig) Build() (proto.Message, error) {
config := new(mtproto.ClientConfig)
return config, nil
}
v2ray-core-4.34.0/infra/conf/mtproto_test.go 0000664 0000000 0000000 00000001450 13774574720 0020731 0 ustar 00root root 0000000 0000000 package conf_test
import (
"testing"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
. "v2ray.com/core/infra/conf"
"v2ray.com/core/proxy/mtproto"
)
func TestMTProtoServerConfig(t *testing.T) {
creator := func() Buildable {
return new(MTProtoServerConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"users": [{
"email": "love@v2ray.com",
"level": 1,
"secret": "b0cbcef5a486d9636472ac27f8e11a9d"
}]
}`,
Parser: loadJSON(creator),
Output: &mtproto.ServerConfig{
User: []*protocol.User{
{
Email: "love@v2ray.com",
Level: 1,
Account: serial.ToTypedMessage(&mtproto.Account{
Secret: []byte{176, 203, 206, 245, 164, 134, 217, 99, 100, 114, 172, 39, 248, 225, 26, 157},
}),
},
},
},
},
})
}
v2ray-core-4.34.0/infra/conf/policy.go 0000664 0000000 0000000 00000004450 13774574720 0017470 0 ustar 00root root 0000000 0000000 package conf
import (
"v2ray.com/core/app/policy"
)
type Policy struct {
Handshake *uint32 `json:"handshake"`
ConnectionIdle *uint32 `json:"connIdle"`
UplinkOnly *uint32 `json:"uplinkOnly"`
DownlinkOnly *uint32 `json:"downlinkOnly"`
StatsUserUplink bool `json:"statsUserUplink"`
StatsUserDownlink bool `json:"statsUserDownlink"`
BufferSize *int32 `json:"bufferSize"`
}
func (t *Policy) Build() (*policy.Policy, error) {
config := new(policy.Policy_Timeout)
if t.Handshake != nil {
config.Handshake = &policy.Second{Value: *t.Handshake}
}
if t.ConnectionIdle != nil {
config.ConnectionIdle = &policy.Second{Value: *t.ConnectionIdle}
}
if t.UplinkOnly != nil {
config.UplinkOnly = &policy.Second{Value: *t.UplinkOnly}
}
if t.DownlinkOnly != nil {
config.DownlinkOnly = &policy.Second{Value: *t.DownlinkOnly}
}
p := &policy.Policy{
Timeout: config,
Stats: &policy.Policy_Stats{
UserUplink: t.StatsUserUplink,
UserDownlink: t.StatsUserDownlink,
},
}
if t.BufferSize != nil {
bs := int32(-1)
if *t.BufferSize >= 0 {
bs = (*t.BufferSize) * 1024
}
p.Buffer = &policy.Policy_Buffer{
Connection: bs,
}
}
return p, nil
}
type SystemPolicy struct {
StatsInboundUplink bool `json:"statsInboundUplink"`
StatsInboundDownlink bool `json:"statsInboundDownlink"`
StatsOutboundUplink bool `json:"statsOutboundUplink"`
StatsOutboundDownlink bool `json:"statsOutboundDownlink"`
}
func (p *SystemPolicy) Build() (*policy.SystemPolicy, error) {
return &policy.SystemPolicy{
Stats: &policy.SystemPolicy_Stats{
InboundUplink: p.StatsInboundUplink,
InboundDownlink: p.StatsInboundDownlink,
OutboundUplink: p.StatsOutboundUplink,
OutboundDownlink: p.StatsOutboundDownlink,
},
}, nil
}
type PolicyConfig struct {
Levels map[uint32]*Policy `json:"levels"`
System *SystemPolicy `json:"system"`
}
func (c *PolicyConfig) Build() (*policy.Config, error) {
levels := make(map[uint32]*policy.Policy)
for l, p := range c.Levels {
if p != nil {
pp, err := p.Build()
if err != nil {
return nil, err
}
levels[l] = pp
}
}
config := &policy.Config{
Level: levels,
}
if c.System != nil {
sc, err := c.System.Build()
if err != nil {
return nil, err
}
config.System = sc
}
return config, nil
}
v2ray-core-4.34.0/infra/conf/policy_test.go 0000664 0000000 0000000 00000001071 13774574720 0020523 0 ustar 00root root 0000000 0000000 package conf_test
import (
"testing"
"v2ray.com/core/common"
. "v2ray.com/core/infra/conf"
)
func TestBufferSize(t *testing.T) {
cases := []struct {
Input int32
Output int32
}{
{
Input: 0,
Output: 0,
},
{
Input: -1,
Output: -1,
},
{
Input: 1,
Output: 1024,
},
}
for _, c := range cases {
bs := c.Input
pConf := Policy{
BufferSize: &bs,
}
p, err := pConf.Build()
common.Must(err)
if p.Buffer.Connection != c.Output {
t.Error("expected buffer size ", c.Output, " but got ", p.Buffer.Connection)
}
}
}
v2ray-core-4.34.0/infra/conf/reverse.go 0000664 0000000 0000000 00000002123 13774574720 0017637 0 ustar 00root root 0000000 0000000 package conf
import (
"github.com/golang/protobuf/proto"
"v2ray.com/core/app/reverse"
)
type BridgeConfig struct {
Tag string `json:"tag"`
Domain string `json:"domain"`
}
func (c *BridgeConfig) Build() (*reverse.BridgeConfig, error) {
return &reverse.BridgeConfig{
Tag: c.Tag,
Domain: c.Domain,
}, nil
}
type PortalConfig struct {
Tag string `json:"tag"`
Domain string `json:"domain"`
}
func (c *PortalConfig) Build() (*reverse.PortalConfig, error) {
return &reverse.PortalConfig{
Tag: c.Tag,
Domain: c.Domain,
}, nil
}
type ReverseConfig struct {
Bridges []BridgeConfig `json:"bridges"`
Portals []PortalConfig `json:"portals"`
}
func (c *ReverseConfig) Build() (proto.Message, error) {
config := &reverse.Config{}
for _, bconfig := range c.Bridges {
b, err := bconfig.Build()
if err != nil {
return nil, err
}
config.BridgeConfig = append(config.BridgeConfig, b)
}
for _, pconfig := range c.Portals {
p, err := pconfig.Build()
if err != nil {
return nil, err
}
config.PortalConfig = append(config.PortalConfig, p)
}
return config, nil
}
v2ray-core-4.34.0/infra/conf/reverse_test.go 0000664 0000000 0000000 00000001421 13774574720 0020676 0 ustar 00root root 0000000 0000000 package conf_test
import (
"testing"
"v2ray.com/core/app/reverse"
"v2ray.com/core/infra/conf"
)
func TestReverseConfig(t *testing.T) {
creator := func() conf.Buildable {
return new(conf.ReverseConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"bridges": [{
"tag": "test",
"domain": "test.v2ray.com"
}]
}`,
Parser: loadJSON(creator),
Output: &reverse.Config{
BridgeConfig: []*reverse.BridgeConfig{
{Tag: "test", Domain: "test.v2ray.com"},
},
},
},
{
Input: `{
"portals": [{
"tag": "test",
"domain": "test.v2ray.com"
}]
}`,
Parser: loadJSON(creator),
Output: &reverse.Config{
PortalConfig: []*reverse.PortalConfig{
{Tag: "test", Domain: "test.v2ray.com"},
},
},
},
})
}
v2ray-core-4.34.0/infra/conf/router.go 0000664 0000000 0000000 00000033273 13774574720 0017516 0 ustar 00root root 0000000 0000000 package conf
import (
"encoding/json"
"strconv"
"strings"
"github.com/golang/protobuf/proto"
"v2ray.com/core/app/router"
"v2ray.com/core/common/net"
"v2ray.com/core/common/platform/filesystem"
)
type RouterRulesConfig struct {
RuleList []json.RawMessage `json:"rules"`
DomainStrategy string `json:"domainStrategy"`
}
type BalancingRule struct {
Tag string `json:"tag"`
Selectors StringList `json:"selector"`
}
func (r *BalancingRule) Build() (*router.BalancingRule, error) {
if r.Tag == "" {
return nil, newError("empty balancer tag")
}
if len(r.Selectors) == 0 {
return nil, newError("empty selector list")
}
return &router.BalancingRule{
Tag: r.Tag,
OutboundSelector: []string(r.Selectors),
}, nil
}
type RouterConfig struct {
Settings *RouterRulesConfig `json:"settings"` // Deprecated
RuleList []json.RawMessage `json:"rules"`
DomainStrategy *string `json:"domainStrategy"`
Balancers []*BalancingRule `json:"balancers"`
}
func (c *RouterConfig) getDomainStrategy() router.Config_DomainStrategy {
ds := ""
if c.DomainStrategy != nil {
ds = *c.DomainStrategy
} else if c.Settings != nil {
ds = c.Settings.DomainStrategy
}
switch strings.ToLower(ds) {
case "alwaysip", "always_ip", "always-ip":
return router.Config_UseIp
case "ipifnonmatch", "ip_if_non_match", "ip-if-non-match":
return router.Config_IpIfNonMatch
case "ipondemand", "ip_on_demand", "ip-on-demand":
return router.Config_IpOnDemand
default:
return router.Config_AsIs
}
}
func (c *RouterConfig) Build() (*router.Config, error) {
config := new(router.Config)
config.DomainStrategy = c.getDomainStrategy()
var rawRuleList []json.RawMessage
if c != nil {
rawRuleList = c.RuleList
if c.Settings != nil {
c.RuleList = append(c.RuleList, c.Settings.RuleList...)
rawRuleList = c.RuleList
}
}
for _, rawRule := range rawRuleList {
rule, err := ParseRule(rawRule)
if err != nil {
return nil, err
}
config.Rule = append(config.Rule, rule)
}
for _, rawBalancer := range c.Balancers {
balancer, err := rawBalancer.Build()
if err != nil {
return nil, err
}
config.BalancingRule = append(config.BalancingRule, balancer)
}
return config, nil
}
type RouterRule struct {
Type string `json:"type"`
OutboundTag string `json:"outboundTag"`
BalancerTag string `json:"balancerTag"`
}
func ParseIP(s string) (*router.CIDR, error) {
var addr, mask string
i := strings.Index(s, "/")
if i < 0 {
addr = s
} else {
addr = s[:i]
mask = s[i+1:]
}
ip := net.ParseAddress(addr)
switch ip.Family() {
case net.AddressFamilyIPv4:
bits := uint32(32)
if len(mask) > 0 {
bits64, err := strconv.ParseUint(mask, 10, 32)
if err != nil {
return nil, newError("invalid network mask for router: ", mask).Base(err)
}
bits = uint32(bits64)
}
if bits > 32 {
return nil, newError("invalid network mask for router: ", bits)
}
return &router.CIDR{
Ip: []byte(ip.IP()),
Prefix: bits,
}, nil
case net.AddressFamilyIPv6:
bits := uint32(128)
if len(mask) > 0 {
bits64, err := strconv.ParseUint(mask, 10, 32)
if err != nil {
return nil, newError("invalid network mask for router: ", mask).Base(err)
}
bits = uint32(bits64)
}
if bits > 128 {
return nil, newError("invalid network mask for router: ", bits)
}
return &router.CIDR{
Ip: []byte(ip.IP()),
Prefix: bits,
}, nil
default:
return nil, newError("unsupported address for router: ", s)
}
}
func loadGeoIP(country string) ([]*router.CIDR, error) {
return loadIP("geoip.dat", country)
}
func loadIP(filename, country string) ([]*router.CIDR, error) {
geoipBytes, err := filesystem.ReadAsset(filename)
if err != nil {
return nil, newError("failed to open file: ", filename).Base(err)
}
var geoipList router.GeoIPList
if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil {
return nil, err
}
for _, geoip := range geoipList.Entry {
if strings.EqualFold(geoip.CountryCode, country) {
return geoip.Cidr, nil
}
}
return nil, newError("country not found in ", filename, ": ", country)
}
func loadSite(filename, list string) ([]*router.Domain, error) {
geositeBytes, err := filesystem.ReadAsset(filename)
if err != nil {
return nil, newError("failed to open file: ", filename).Base(err)
}
var geositeList router.GeoSiteList
if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil {
return nil, err
}
for _, site := range geositeList.Entry {
if strings.EqualFold(site.CountryCode, list) {
return site.Domain, nil
}
}
return nil, newError("list not found in ", filename, ": ", list)
}
type AttributeMatcher interface {
Match(*router.Domain) bool
}
type BooleanMatcher string
func (m BooleanMatcher) Match(domain *router.Domain) bool {
for _, attr := range domain.Attribute {
if strings.EqualFold(attr.GetKey(), string(m)) {
return true
}
}
return false
}
type AttributeList struct {
matcher []AttributeMatcher
}
func (al *AttributeList) Match(domain *router.Domain) bool {
for _, matcher := range al.matcher {
if !matcher.Match(domain) {
return false
}
}
return true
}
func (al *AttributeList) IsEmpty() bool {
return len(al.matcher) == 0
}
func parseAttrs(attrs []string) *AttributeList {
al := new(AttributeList)
for _, attr := range attrs {
trimmedAttr := strings.ToLower(strings.TrimSpace(attr))
if len(trimmedAttr) == 0 {
continue
}
al.matcher = append(al.matcher, BooleanMatcher(trimmedAttr))
}
return al
}
func loadGeositeWithAttr(file string, siteWithAttr string) ([]*router.Domain, error) {
parts := strings.Split(siteWithAttr, "@")
if len(parts) == 0 {
return nil, newError("empty rule")
}
list := strings.TrimSpace(parts[0])
attrVal := parts[1:]
if len(list) == 0 {
return nil, newError("empty listname in rule: ", siteWithAttr)
}
domains, err := loadSite(file, list)
if err != nil {
return nil, err
}
attrs := parseAttrs(attrVal)
if attrs.IsEmpty() {
if strings.Contains(siteWithAttr, "@") {
newError("empty attribute list: ", siteWithAttr)
}
return domains, nil
}
filteredDomains := make([]*router.Domain, 0, len(domains))
hasAttrMatched := false
for _, domain := range domains {
if attrs.Match(domain) {
hasAttrMatched = true
filteredDomains = append(filteredDomains, domain)
}
}
if !hasAttrMatched {
newError("attribute match no rule: geosite:", siteWithAttr)
}
return filteredDomains, nil
}
func parseDomainRule(domain string) ([]*router.Domain, error) {
if strings.HasPrefix(domain, "geosite:") {
list := domain[8:]
if len(list) == 0 {
return nil, newError("empty listname in rule: ", domain)
}
domains, err := loadGeositeWithAttr("geosite.dat", list)
if err != nil {
return nil, newError("failed to load geosite: ", list).Base(err)
}
return domains, nil
}
var isExtDatFile = 0
{
const prefix = "ext:"
if strings.HasPrefix(domain, prefix) {
isExtDatFile = len(prefix)
}
const prefixQualified = "ext-domain:"
if strings.HasPrefix(domain, prefixQualified) {
isExtDatFile = len(prefixQualified)
}
}
if isExtDatFile != 0 {
kv := strings.Split(domain[isExtDatFile:], ":")
if len(kv) != 2 {
return nil, newError("invalid external resource: ", domain)
}
filename := kv[0]
list := kv[1]
domains, err := loadGeositeWithAttr(filename, list)
if err != nil {
return nil, newError("failed to load external geosite: ", list, " from ", filename).Base(err)
}
return domains, nil
}
domainRule := new(router.Domain)
switch {
case strings.HasPrefix(domain, "regexp:"):
regexpVal := domain[7:]
if len(regexpVal) == 0 {
return nil, newError("empty regexp type of rule: ", domain)
}
domainRule.Type = router.Domain_Regex
domainRule.Value = regexpVal
case strings.HasPrefix(domain, "domain:"):
domainName := domain[7:]
if len(domainName) == 0 {
return nil, newError("empty domain type of rule: ", domain)
}
domainRule.Type = router.Domain_Domain
domainRule.Value = domainName
case strings.HasPrefix(domain, "full:"):
fullVal := domain[5:]
if len(fullVal) == 0 {
return nil, newError("empty full domain type of rule: ", domain)
}
domainRule.Type = router.Domain_Full
domainRule.Value = fullVal
case strings.HasPrefix(domain, "keyword:"):
keywordVal := domain[8:]
if len(keywordVal) == 0 {
return nil, newError("empty keyword type of rule: ", domain)
}
domainRule.Type = router.Domain_Plain
domainRule.Value = keywordVal
case strings.HasPrefix(domain, "dotless:"):
domainRule.Type = router.Domain_Regex
switch substr := domain[8:]; {
case substr == "":
domainRule.Value = "^[^.]*$"
case !strings.Contains(substr, "."):
domainRule.Value = "^[^.]*" + substr + "[^.]*$"
default:
return nil, newError("substr in dotless rule should not contain a dot: ", substr)
}
default:
domainRule.Type = router.Domain_Plain
domainRule.Value = domain
}
return []*router.Domain{domainRule}, nil
}
func toCidrList(ips StringList) ([]*router.GeoIP, error) {
var geoipList []*router.GeoIP
var customCidrs []*router.CIDR
for _, ip := range ips {
if strings.HasPrefix(ip, "geoip:") {
country := ip[6:]
if len(country) == 0 {
return nil, newError("empty country name in rule")
}
geoip, err := loadGeoIP(country)
if err != nil {
return nil, newError("failed to load geoip: ", country).Base(err)
}
geoipList = append(geoipList, &router.GeoIP{
CountryCode: strings.ToUpper(country),
Cidr: geoip,
})
continue
}
var isExtDatFile = 0
{
const prefix = "ext:"
if strings.HasPrefix(ip, prefix) {
isExtDatFile = len(prefix)
}
const prefixQualified = "ext-ip:"
if strings.HasPrefix(ip, prefixQualified) {
isExtDatFile = len(prefixQualified)
}
}
if isExtDatFile != 0 {
kv := strings.Split(ip[isExtDatFile:], ":")
if len(kv) != 2 {
return nil, newError("invalid external resource: ", ip)
}
filename := kv[0]
country := kv[1]
if len(filename) == 0 || len(country) == 0 {
return nil, newError("empty filename or empty country in rule")
}
geoip, err := loadIP(filename, country)
if err != nil {
return nil, newError("failed to load geoip: ", country, " from ", filename).Base(err)
}
geoipList = append(geoipList, &router.GeoIP{
CountryCode: strings.ToUpper(filename + "_" + country),
Cidr: geoip,
})
continue
}
ipRule, err := ParseIP(ip)
if err != nil {
return nil, newError("invalid IP: ", ip).Base(err)
}
customCidrs = append(customCidrs, ipRule)
}
if len(customCidrs) > 0 {
geoipList = append(geoipList, &router.GeoIP{
Cidr: customCidrs,
})
}
return geoipList, nil
}
func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
type RawFieldRule struct {
RouterRule
Domain *StringList `json:"domain"`
Domains *StringList `json:"domains"`
IP *StringList `json:"ip"`
Port *PortList `json:"port"`
Network *NetworkList `json:"network"`
SourceIP *StringList `json:"source"`
SourcePort *PortList `json:"sourcePort"`
User *StringList `json:"user"`
InboundTag *StringList `json:"inboundTag"`
Protocols *StringList `json:"protocol"`
Attributes string `json:"attrs"`
}
rawFieldRule := new(RawFieldRule)
err := json.Unmarshal(msg, rawFieldRule)
if err != nil {
return nil, err
}
rule := new(router.RoutingRule)
switch {
case len(rawFieldRule.OutboundTag) > 0:
rule.TargetTag = &router.RoutingRule_Tag{
Tag: rawFieldRule.OutboundTag,
}
case len(rawFieldRule.BalancerTag) > 0:
rule.TargetTag = &router.RoutingRule_BalancingTag{
BalancingTag: rawFieldRule.BalancerTag,
}
default:
return nil, newError("neither outboundTag nor balancerTag is specified in routing rule")
}
if rawFieldRule.Domain != nil {
for _, domain := range *rawFieldRule.Domain {
rules, err := parseDomainRule(domain)
if err != nil {
return nil, newError("failed to parse domain rule: ", domain).Base(err)
}
rule.Domain = append(rule.Domain, rules...)
}
}
if rawFieldRule.Domains != nil {
for _, domain := range *rawFieldRule.Domains {
rules, err := parseDomainRule(domain)
if err != nil {
return nil, newError("failed to parse domain rule: ", domain).Base(err)
}
rule.Domain = append(rule.Domain, rules...)
}
}
if rawFieldRule.IP != nil {
geoipList, err := toCidrList(*rawFieldRule.IP)
if err != nil {
return nil, err
}
rule.Geoip = geoipList
}
if rawFieldRule.Port != nil {
rule.PortList = rawFieldRule.Port.Build()
}
if rawFieldRule.Network != nil {
rule.Networks = rawFieldRule.Network.Build()
}
if rawFieldRule.SourceIP != nil {
geoipList, err := toCidrList(*rawFieldRule.SourceIP)
if err != nil {
return nil, err
}
rule.SourceGeoip = geoipList
}
if rawFieldRule.SourcePort != nil {
rule.SourcePortList = rawFieldRule.SourcePort.Build()
}
if rawFieldRule.User != nil {
for _, s := range *rawFieldRule.User {
rule.UserEmail = append(rule.UserEmail, s)
}
}
if rawFieldRule.InboundTag != nil {
for _, s := range *rawFieldRule.InboundTag {
rule.InboundTag = append(rule.InboundTag, s)
}
}
if rawFieldRule.Protocols != nil {
for _, s := range *rawFieldRule.Protocols {
rule.Protocol = append(rule.Protocol, s)
}
}
if len(rawFieldRule.Attributes) > 0 {
rule.Attributes = rawFieldRule.Attributes
}
return rule, nil
}
func ParseRule(msg json.RawMessage) (*router.RoutingRule, error) {
rawRule := new(RouterRule)
err := json.Unmarshal(msg, rawRule)
if err != nil {
return nil, newError("invalid router rule").Base(err)
}
if strings.EqualFold(rawRule.Type, "field") {
fieldrule, err := parseFieldRule(msg)
if err != nil {
return nil, newError("invalid field rule").Base(err)
}
return fieldrule, nil
}
return nil, newError("unknown router rule type: ", rawRule.Type)
}
v2ray-core-4.34.0/infra/conf/router_test.go 0000664 0000000 0000000 00000014262 13774574720 0020552 0 ustar 00root root 0000000 0000000 package conf_test
import (
"encoding/json"
"testing"
"github.com/golang/protobuf/proto"
"v2ray.com/core/app/router"
"v2ray.com/core/common/net"
. "v2ray.com/core/infra/conf"
)
func TestRouterConfig(t *testing.T) {
createParser := func() func(string) (proto.Message, error) {
return func(s string) (proto.Message, error) {
config := new(RouterConfig)
if err := json.Unmarshal([]byte(s), config); err != nil {
return nil, err
}
return config.Build()
}
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"strategy": "rules",
"settings": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": [
"baidu.com",
"qq.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"domains": [
"v2fly.org",
"github.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"10.0.0.0/8",
"::1/128"
],
"outboundTag": "test"
},{
"type": "field",
"port": "53, 443, 1000-2000",
"outboundTag": "test"
},{
"type": "field",
"port": 123,
"outboundTag": "test"
}
]
},
"balancers": [
{
"tag": "b1",
"selector": ["test"]
}
]
}`,
Parser: createParser(),
Output: &router.Config{
DomainStrategy: router.Config_AsIs,
BalancingRule: []*router.BalancingRule{
{
Tag: "b1",
OutboundSelector: []string{"test"},
},
},
Rule: []*router.RoutingRule{
{
Domain: []*router.Domain{
{
Type: router.Domain_Plain,
Value: "baidu.com",
},
{
Type: router.Domain_Plain,
Value: "qq.com",
},
},
TargetTag: &router.RoutingRule_Tag{
Tag: "direct",
},
},
{
Domain: []*router.Domain{
{
Type: router.Domain_Plain,
Value: "v2fly.org",
},
{
Type: router.Domain_Plain,
Value: "github.com",
},
},
TargetTag: &router.RoutingRule_Tag{
Tag: "direct",
},
},
{
Geoip: []*router.GeoIP{
{
Cidr: []*router.CIDR{
{
Ip: []byte{10, 0, 0, 0},
Prefix: 8,
},
{
Ip: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
Prefix: 128,
},
},
},
},
TargetTag: &router.RoutingRule_Tag{
Tag: "test",
},
},
{
PortList: &net.PortList{
Range: []*net.PortRange{
{From: 53, To: 53},
{From: 443, To: 443},
{From: 1000, To: 2000},
},
},
TargetTag: &router.RoutingRule_Tag{
Tag: "test",
},
},
{
PortList: &net.PortList{
Range: []*net.PortRange{
{From: 123, To: 123},
},
},
TargetTag: &router.RoutingRule_Tag{
Tag: "test",
},
},
},
},
},
{
Input: `{
"strategy": "rules",
"settings": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": [
"baidu.com",
"qq.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"domains": [
"v2fly.org",
"github.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"10.0.0.0/8",
"::1/128"
],
"outboundTag": "test"
}
]
}
}`,
Parser: createParser(),
Output: &router.Config{
DomainStrategy: router.Config_IpIfNonMatch,
Rule: []*router.RoutingRule{
{
Domain: []*router.Domain{
{
Type: router.Domain_Plain,
Value: "baidu.com",
},
{
Type: router.Domain_Plain,
Value: "qq.com",
},
},
TargetTag: &router.RoutingRule_Tag{
Tag: "direct",
},
},
{
Domain: []*router.Domain{
{
Type: router.Domain_Plain,
Value: "v2fly.org",
},
{
Type: router.Domain_Plain,
Value: "github.com",
},
},
TargetTag: &router.RoutingRule_Tag{
Tag: "direct",
},
},
{
Geoip: []*router.GeoIP{
{
Cidr: []*router.CIDR{
{
Ip: []byte{10, 0, 0, 0},
Prefix: 8,
},
{
Ip: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
Prefix: 128,
},
},
},
},
TargetTag: &router.RoutingRule_Tag{
Tag: "test",
},
},
},
},
},
{
Input: `{
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": [
"baidu.com",
"qq.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"domains": [
"v2fly.org",
"github.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"10.0.0.0/8",
"::1/128"
],
"outboundTag": "test"
}
]
}`,
Parser: createParser(),
Output: &router.Config{
DomainStrategy: router.Config_AsIs,
Rule: []*router.RoutingRule{
{
Domain: []*router.Domain{
{
Type: router.Domain_Plain,
Value: "baidu.com",
},
{
Type: router.Domain_Plain,
Value: "qq.com",
},
},
TargetTag: &router.RoutingRule_Tag{
Tag: "direct",
},
},
{
Domain: []*router.Domain{
{
Type: router.Domain_Plain,
Value: "v2fly.org",
},
{
Type: router.Domain_Plain,
Value: "github.com",
},
},
TargetTag: &router.RoutingRule_Tag{
Tag: "direct",
},
},
{
Geoip: []*router.GeoIP{
{
Cidr: []*router.CIDR{
{
Ip: []byte{10, 0, 0, 0},
Prefix: 8,
},
{
Ip: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
Prefix: 128,
},
},
},
},
TargetTag: &router.RoutingRule_Tag{
Tag: "test",
},
},
},
},
},
})
}
v2ray-core-4.34.0/infra/conf/serial/ 0000775 0000000 0000000 00000000000 13774574720 0017116 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/infra/conf/serial/errors.generated.go 0000664 0000000 0000000 00000000314 13774574720 0022714 0 ustar 00root root 0000000 0000000 package serial
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/infra/conf/serial/loader.go 0000664 0000000 0000000 00000003260 13774574720 0020714 0 ustar 00root root 0000000 0000000 package serial
import (
"bytes"
"encoding/json"
"io"
"v2ray.com/core"
"v2ray.com/core/common/errors"
"v2ray.com/core/infra/conf"
json_reader "v2ray.com/core/infra/conf/json"
)
type offset struct {
line int
char int
}
func findOffset(b []byte, o int) *offset {
if o >= len(b) || o < 0 {
return nil
}
line := 1
char := 0
for i, x := range b {
if i == o {
break
}
if x == '\n' {
line++
char = 0
} else {
char++
}
}
return &offset{line: line, char: char}
}
// DecodeJSONConfig reads from reader and decode the config into *conf.Config
// syntax error could be detected.
func DecodeJSONConfig(reader io.Reader) (*conf.Config, error) {
jsonConfig := &conf.Config{}
jsonContent := bytes.NewBuffer(make([]byte, 0, 10240))
jsonReader := io.TeeReader(&json_reader.Reader{
Reader: reader,
}, jsonContent)
decoder := json.NewDecoder(jsonReader)
if err := decoder.Decode(jsonConfig); err != nil {
var pos *offset
cause := errors.Cause(err)
switch tErr := cause.(type) {
case *json.SyntaxError:
pos = findOffset(jsonContent.Bytes(), int(tErr.Offset))
case *json.UnmarshalTypeError:
pos = findOffset(jsonContent.Bytes(), int(tErr.Offset))
}
if pos != nil {
return nil, newError("failed to read config file at line ", pos.line, " char ", pos.char).Base(err)
}
return nil, newError("failed to read config file").Base(err)
}
return jsonConfig, nil
}
func LoadJSONConfig(reader io.Reader) (*core.Config, error) {
jsonConfig, err := DecodeJSONConfig(reader)
if err != nil {
return nil, err
}
pbConfig, err := jsonConfig.Build()
if err != nil {
return nil, newError("failed to parse json config").Base(err)
}
return pbConfig, nil
}
v2ray-core-4.34.0/infra/conf/serial/loader_test.go 0000664 0000000 0000000 00000002023 13774574720 0021747 0 ustar 00root root 0000000 0000000 package serial_test
import (
"bytes"
"strings"
"testing"
"v2ray.com/core/infra/conf/serial"
)
func TestLoaderError(t *testing.T) {
testCases := []struct {
Input string
Output string
}{
{
Input: `{
"log": {
// abcd
0,
"loglevel": "info"
}
}`,
Output: "line 4 char 6",
},
{
Input: `{
"log": {
// abcd
"loglevel": "info",
}
}`,
Output: "line 5 char 5",
},
{
Input: `{
"port": 1,
"inbounds": [{
"protocol": "test"
}]
}`,
Output: "parse json config",
},
{
Input: `{
"inbounds": [{
"port": 1,
"listen": 0,
"protocol": "test"
}]
}`,
Output: "line 1 char 1",
},
}
for _, testCase := range testCases {
reader := bytes.NewReader([]byte(testCase.Input))
_, err := serial.LoadJSONConfig(reader)
errString := err.Error()
if !strings.Contains(errString, testCase.Output) {
t.Error("unexpected output from json: ", testCase.Input, ". expected ", testCase.Output, ", but actually ", errString)
}
}
}
v2ray-core-4.34.0/infra/conf/serial/serial.go 0000664 0000000 0000000 00000000113 13774574720 0020717 0 ustar 00root root 0000000 0000000 package serial
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/infra/conf/shadowsocks.go 0000664 0000000 0000000 00000006145 13774574720 0020524 0 ustar 00root root 0000000 0000000 package conf
import (
"strings"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/shadowsocks"
)
func cipherFromString(c string) shadowsocks.CipherType {
switch strings.ToLower(c) {
case "aes-128-gcm", "aead_aes_128_gcm":
return shadowsocks.CipherType_AES_128_GCM
case "aes-256-gcm", "aead_aes_256_gcm":
return shadowsocks.CipherType_AES_256_GCM
case "chacha20-poly1305", "aead_chacha20_poly1305", "chacha20-ietf-poly1305":
return shadowsocks.CipherType_CHACHA20_POLY1305
case "none", "plain":
return shadowsocks.CipherType_NONE
default:
return shadowsocks.CipherType_UNKNOWN
}
}
type ShadowsocksServerConfig struct {
Cipher string `json:"method"`
Password string `json:"password"`
UDP bool `json:"udp"`
Level byte `json:"level"`
Email string `json:"email"`
NetworkList *NetworkList `json:"network"`
}
func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
config := new(shadowsocks.ServerConfig)
config.UdpEnabled = v.UDP
config.Network = v.NetworkList.Build()
if v.Password == "" {
return nil, newError("Shadowsocks password is not specified.")
}
account := &shadowsocks.Account{
Password: v.Password,
}
account.CipherType = cipherFromString(v.Cipher)
if account.CipherType == shadowsocks.CipherType_UNKNOWN {
return nil, newError("unknown cipher method: ", v.Cipher)
}
config.User = &protocol.User{
Email: v.Email,
Level: uint32(v.Level),
Account: serial.ToTypedMessage(account),
}
return config, nil
}
type ShadowsocksServerTarget struct {
Address *Address `json:"address"`
Port uint16 `json:"port"`
Cipher string `json:"method"`
Password string `json:"password"`
Email string `json:"email"`
Ota bool `json:"ota"`
Level byte `json:"level"`
}
type ShadowsocksClientConfig struct {
Servers []*ShadowsocksServerTarget `json:"servers"`
}
func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
config := new(shadowsocks.ClientConfig)
if len(v.Servers) == 0 {
return nil, newError("0 Shadowsocks server configured.")
}
serverSpecs := make([]*protocol.ServerEndpoint, len(v.Servers))
for idx, server := range v.Servers {
if server.Address == nil {
return nil, newError("Shadowsocks server address is not set.")
}
if server.Port == 0 {
return nil, newError("Invalid Shadowsocks port.")
}
if server.Password == "" {
return nil, newError("Shadowsocks password is not specified.")
}
account := &shadowsocks.Account{
Password: server.Password,
}
account.CipherType = cipherFromString(server.Cipher)
if account.CipherType == shadowsocks.CipherType_UNKNOWN {
return nil, newError("unknown cipher method: ", server.Cipher)
}
ss := &protocol.ServerEndpoint{
Address: server.Address.Build(),
Port: uint32(server.Port),
User: []*protocol.User{
{
Level: uint32(server.Level),
Email: server.Email,
Account: serial.ToTypedMessage(account),
},
},
}
serverSpecs[idx] = ss
}
config.Server = serverSpecs
return config, nil
}
v2ray-core-4.34.0/infra/conf/shadowsocks_test.go 0000664 0000000 0000000 00000001405 13774574720 0021555 0 ustar 00root root 0000000 0000000 package conf_test
import (
"testing"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
. "v2ray.com/core/infra/conf"
"v2ray.com/core/proxy/shadowsocks"
)
func TestShadowsocksServerConfigParsing(t *testing.T) {
creator := func() Buildable {
return new(ShadowsocksServerConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"method": "aes-256-GCM",
"password": "v2ray-password"
}`,
Parser: loadJSON(creator),
Output: &shadowsocks.ServerConfig{
User: &protocol.User{
Account: serial.ToTypedMessage(&shadowsocks.Account{
CipherType: shadowsocks.CipherType_AES_256_GCM,
Password: "v2ray-password",
}),
},
Network: []net.Network{net.Network_TCP},
},
},
})
}
v2ray-core-4.34.0/infra/conf/socks.go 0000664 0000000 0000000 00000005150 13774574720 0017311 0 ustar 00root root 0000000 0000000 package conf
import (
"encoding/json"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/socks"
)
type SocksAccount struct {
Username string `json:"user"`
Password string `json:"pass"`
}
func (v *SocksAccount) Build() *socks.Account {
return &socks.Account{
Username: v.Username,
Password: v.Password,
}
}
const (
AuthMethodNoAuth = "noauth"
AuthMethodUserPass = "password"
)
type SocksServerConfig struct {
AuthMethod string `json:"auth"`
Accounts []*SocksAccount `json:"accounts"`
UDP bool `json:"udp"`
Host *Address `json:"ip"`
Timeout uint32 `json:"timeout"`
UserLevel uint32 `json:"userLevel"`
}
func (v *SocksServerConfig) Build() (proto.Message, error) {
config := new(socks.ServerConfig)
switch v.AuthMethod {
case AuthMethodNoAuth:
config.AuthType = socks.AuthType_NO_AUTH
case AuthMethodUserPass:
config.AuthType = socks.AuthType_PASSWORD
default:
// newError("unknown socks auth method: ", v.AuthMethod, ". Default to noauth.").AtWarning().WriteToLog()
config.AuthType = socks.AuthType_NO_AUTH
}
if len(v.Accounts) > 0 {
config.Accounts = make(map[string]string, len(v.Accounts))
for _, account := range v.Accounts {
config.Accounts[account.Username] = account.Password
}
}
config.UdpEnabled = v.UDP
if v.Host != nil {
config.Address = v.Host.Build()
}
config.Timeout = v.Timeout
config.UserLevel = v.UserLevel
return config, nil
}
type SocksRemoteConfig struct {
Address *Address `json:"address"`
Port uint16 `json:"port"`
Users []json.RawMessage `json:"users"`
}
type SocksClientConfig struct {
Servers []*SocksRemoteConfig `json:"servers"`
}
func (v *SocksClientConfig) Build() (proto.Message, error) {
config := new(socks.ClientConfig)
config.Server = make([]*protocol.ServerEndpoint, len(v.Servers))
for idx, serverConfig := range v.Servers {
server := &protocol.ServerEndpoint{
Address: serverConfig.Address.Build(),
Port: uint32(serverConfig.Port),
}
for _, rawUser := range serverConfig.Users {
user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil {
return nil, newError("failed to parse Socks user").Base(err).AtError()
}
account := new(SocksAccount)
if err := json.Unmarshal(rawUser, account); err != nil {
return nil, newError("failed to parse socks account").Base(err).AtError()
}
user.Account = serial.ToTypedMessage(account.Build())
server.User = append(server.User, user)
}
config.Server[idx] = server
}
return config, nil
}
v2ray-core-4.34.0/infra/conf/socks_test.go 0000664 0000000 0000000 00000003354 13774574720 0020354 0 ustar 00root root 0000000 0000000 package conf_test
import (
"testing"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
. "v2ray.com/core/infra/conf"
"v2ray.com/core/proxy/socks"
)
func TestSocksInboundConfig(t *testing.T) {
creator := func() Buildable {
return new(SocksServerConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"auth": "password",
"accounts": [
{
"user": "my-username",
"pass": "my-password"
}
],
"udp": false,
"ip": "127.0.0.1",
"timeout": 5,
"userLevel": 1
}`,
Parser: loadJSON(creator),
Output: &socks.ServerConfig{
AuthType: socks.AuthType_PASSWORD,
Accounts: map[string]string{
"my-username": "my-password",
},
UdpEnabled: false,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Timeout: 5,
UserLevel: 1,
},
},
})
}
func TestSocksOutboundConfig(t *testing.T) {
creator := func() Buildable {
return new(SocksClientConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"servers": [{
"address": "127.0.0.1",
"port": 1234,
"users": [
{"user": "test user", "pass": "test pass", "email": "test@email.com"}
]
}]
}`,
Parser: loadJSON(creator),
Output: &socks.ClientConfig{
Server: []*protocol.ServerEndpoint{
{
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: 1234,
User: []*protocol.User{
{
Email: "test@email.com",
Account: serial.ToTypedMessage(&socks.Account{
Username: "test user",
Password: "test pass",
}),
},
},
},
},
},
},
})
}
v2ray-core-4.34.0/infra/conf/transport.go 0000664 0000000 0000000 00000004757 13774574720 0020237 0 ustar 00root root 0000000 0000000 package conf
import (
"v2ray.com/core/common/serial"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
)
type TransportConfig struct {
TCPConfig *TCPConfig `json:"tcpSettings"`
KCPConfig *KCPConfig `json:"kcpSettings"`
WSConfig *WebSocketConfig `json:"wsSettings"`
HTTPConfig *HTTPConfig `json:"httpSettings"`
DSConfig *DomainSocketConfig `json:"dsSettings"`
QUICConfig *QUICConfig `json:"quicSettings"`
}
// Build implements Buildable.
func (c *TransportConfig) Build() (*transport.Config, error) {
config := new(transport.Config)
if c.TCPConfig != nil {
ts, err := c.TCPConfig.Build()
if err != nil {
return nil, newError("failed to build TCP config").Base(err).AtError()
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "tcp",
Settings: serial.ToTypedMessage(ts),
})
}
if c.KCPConfig != nil {
ts, err := c.KCPConfig.Build()
if err != nil {
return nil, newError("failed to build mKCP config").Base(err).AtError()
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "mkcp",
Settings: serial.ToTypedMessage(ts),
})
}
if c.WSConfig != nil {
ts, err := c.WSConfig.Build()
if err != nil {
return nil, newError("failed to build WebSocket config").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "websocket",
Settings: serial.ToTypedMessage(ts),
})
}
if c.HTTPConfig != nil {
ts, err := c.HTTPConfig.Build()
if err != nil {
return nil, newError("Failed to build HTTP config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "http",
Settings: serial.ToTypedMessage(ts),
})
}
if c.DSConfig != nil {
ds, err := c.DSConfig.Build()
if err != nil {
return nil, newError("Failed to build DomainSocket config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "domainsocket",
Settings: serial.ToTypedMessage(ds),
})
}
if c.QUICConfig != nil {
qs, err := c.QUICConfig.Build()
if err != nil {
return nil, newError("Failed to build QUIC config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "quic",
Settings: serial.ToTypedMessage(qs),
})
}
return config, nil
}
v2ray-core-4.34.0/infra/conf/transport_authenticators.go 0000664 0000000 0000000 00000012145 13774574720 0023342 0 ustar 00root root 0000000 0000000 package conf
import (
"sort"
"github.com/golang/protobuf/proto"
"v2ray.com/core/transport/internet/headers/http"
"v2ray.com/core/transport/internet/headers/noop"
"v2ray.com/core/transport/internet/headers/srtp"
"v2ray.com/core/transport/internet/headers/tls"
"v2ray.com/core/transport/internet/headers/utp"
"v2ray.com/core/transport/internet/headers/wechat"
"v2ray.com/core/transport/internet/headers/wireguard"
)
type NoOpAuthenticator struct{}
func (NoOpAuthenticator) Build() (proto.Message, error) {
return new(noop.Config), nil
}
type NoOpConnectionAuthenticator struct{}
func (NoOpConnectionAuthenticator) Build() (proto.Message, error) {
return new(noop.ConnectionConfig), nil
}
type SRTPAuthenticator struct{}
func (SRTPAuthenticator) Build() (proto.Message, error) {
return new(srtp.Config), nil
}
type UTPAuthenticator struct{}
func (UTPAuthenticator) Build() (proto.Message, error) {
return new(utp.Config), nil
}
type WechatVideoAuthenticator struct{}
func (WechatVideoAuthenticator) Build() (proto.Message, error) {
return new(wechat.VideoConfig), nil
}
type WireguardAuthenticator struct{}
func (WireguardAuthenticator) Build() (proto.Message, error) {
return new(wireguard.WireguardConfig), nil
}
type DTLSAuthenticator struct{}
func (DTLSAuthenticator) Build() (proto.Message, error) {
return new(tls.PacketConfig), nil
}
type AuthenticatorRequest struct {
Version string `json:"version"`
Method string `json:"method"`
Path StringList `json:"path"`
Headers map[string]*StringList `json:"headers"`
}
func sortMapKeys(m map[string]*StringList) []string {
var keys []string
for key := range m {
keys = append(keys, key)
}
sort.Strings(keys)
return keys
}
func (v *AuthenticatorRequest) Build() (*http.RequestConfig, error) {
config := &http.RequestConfig{
Uri: []string{"/"},
Header: []*http.Header{
{
Name: "Host",
Value: []string{"www.baidu.com", "www.bing.com"},
},
{
Name: "User-Agent",
Value: []string{
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36",
"Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46",
},
},
{
Name: "Accept-Encoding",
Value: []string{"gzip, deflate"},
},
{
Name: "Connection",
Value: []string{"keep-alive"},
},
{
Name: "Pragma",
Value: []string{"no-cache"},
},
},
}
if len(v.Version) > 0 {
config.Version = &http.Version{Value: v.Version}
}
if len(v.Method) > 0 {
config.Method = &http.Method{Value: v.Method}
}
if len(v.Path) > 0 {
config.Uri = append([]string(nil), (v.Path)...)
}
if len(v.Headers) > 0 {
config.Header = make([]*http.Header, 0, len(v.Headers))
headerNames := sortMapKeys(v.Headers)
for _, key := range headerNames {
value := v.Headers[key]
if value == nil {
return nil, newError("empty HTTP header value: " + key).AtError()
}
config.Header = append(config.Header, &http.Header{
Name: key,
Value: append([]string(nil), (*value)...),
})
}
}
return config, nil
}
type AuthenticatorResponse struct {
Version string `json:"version"`
Status string `json:"status"`
Reason string `json:"reason"`
Headers map[string]*StringList `json:"headers"`
}
func (v *AuthenticatorResponse) Build() (*http.ResponseConfig, error) {
config := &http.ResponseConfig{
Header: []*http.Header{
{
Name: "Content-Type",
Value: []string{"application/octet-stream", "video/mpeg"},
},
{
Name: "Transfer-Encoding",
Value: []string{"chunked"},
},
{
Name: "Connection",
Value: []string{"keep-alive"},
},
{
Name: "Pragma",
Value: []string{"no-cache"},
},
{
Name: "Cache-Control",
Value: []string{"private", "no-cache"},
},
},
}
if len(v.Version) > 0 {
config.Version = &http.Version{Value: v.Version}
}
if len(v.Status) > 0 || len(v.Reason) > 0 {
config.Status = &http.Status{
Code: "200",
Reason: "OK",
}
if len(v.Status) > 0 {
config.Status.Code = v.Status
}
if len(v.Reason) > 0 {
config.Status.Reason = v.Reason
}
}
if len(v.Headers) > 0 {
config.Header = make([]*http.Header, 0, len(v.Headers))
headerNames := sortMapKeys(v.Headers)
for _, key := range headerNames {
value := v.Headers[key]
if value == nil {
return nil, newError("empty HTTP header value: " + key).AtError()
}
config.Header = append(config.Header, &http.Header{
Name: key,
Value: append([]string(nil), (*value)...),
})
}
}
return config, nil
}
type Authenticator struct {
Request AuthenticatorRequest `json:"request"`
Response AuthenticatorResponse `json:"response"`
}
func (v *Authenticator) Build() (proto.Message, error) {
config := new(http.Config)
requestConfig, err := v.Request.Build()
if err != nil {
return nil, err
}
config.Request = requestConfig
responseConfig, err := v.Response.Build()
if err != nil {
return nil, err
}
config.Response = responseConfig
return config, nil
}
v2ray-core-4.34.0/infra/conf/transport_internet.go 0000664 0000000 0000000 00000033442 13774574720 0022140 0 ustar 00root root 0000000 0000000 package conf
import (
"encoding/json"
"strings"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/platform/filesystem"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/domainsocket"
"v2ray.com/core/transport/internet/http"
"v2ray.com/core/transport/internet/kcp"
"v2ray.com/core/transport/internet/quic"
"v2ray.com/core/transport/internet/tcp"
"v2ray.com/core/transport/internet/tls"
"v2ray.com/core/transport/internet/websocket"
)
var (
kcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
"none": func() interface{} { return new(NoOpAuthenticator) },
"srtp": func() interface{} { return new(SRTPAuthenticator) },
"utp": func() interface{} { return new(UTPAuthenticator) },
"wechat-video": func() interface{} { return new(WechatVideoAuthenticator) },
"dtls": func() interface{} { return new(DTLSAuthenticator) },
"wireguard": func() interface{} { return new(WireguardAuthenticator) },
}, "type", "")
tcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
"none": func() interface{} { return new(NoOpConnectionAuthenticator) },
"http": func() interface{} { return new(Authenticator) },
}, "type", "")
)
type KCPConfig struct {
Mtu *uint32 `json:"mtu"`
Tti *uint32 `json:"tti"`
UpCap *uint32 `json:"uplinkCapacity"`
DownCap *uint32 `json:"downlinkCapacity"`
Congestion *bool `json:"congestion"`
ReadBufferSize *uint32 `json:"readBufferSize"`
WriteBufferSize *uint32 `json:"writeBufferSize"`
HeaderConfig json.RawMessage `json:"header"`
Seed *string `json:"seed"`
}
// Build implements Buildable.
func (c *KCPConfig) Build() (proto.Message, error) {
config := new(kcp.Config)
if c.Mtu != nil {
mtu := *c.Mtu
if mtu < 576 || mtu > 1460 {
return nil, newError("invalid mKCP MTU size: ", mtu).AtError()
}
config.Mtu = &kcp.MTU{Value: mtu}
}
if c.Tti != nil {
tti := *c.Tti
if tti < 10 || tti > 100 {
return nil, newError("invalid mKCP TTI: ", tti).AtError()
}
config.Tti = &kcp.TTI{Value: tti}
}
if c.UpCap != nil {
config.UplinkCapacity = &kcp.UplinkCapacity{Value: *c.UpCap}
}
if c.DownCap != nil {
config.DownlinkCapacity = &kcp.DownlinkCapacity{Value: *c.DownCap}
}
if c.Congestion != nil {
config.Congestion = *c.Congestion
}
if c.ReadBufferSize != nil {
size := *c.ReadBufferSize
if size > 0 {
config.ReadBuffer = &kcp.ReadBuffer{Size: size * 1024 * 1024}
} else {
config.ReadBuffer = &kcp.ReadBuffer{Size: 512 * 1024}
}
}
if c.WriteBufferSize != nil {
size := *c.WriteBufferSize
if size > 0 {
config.WriteBuffer = &kcp.WriteBuffer{Size: size * 1024 * 1024}
} else {
config.WriteBuffer = &kcp.WriteBuffer{Size: 512 * 1024}
}
}
if len(c.HeaderConfig) > 0 {
headerConfig, _, err := kcpHeaderLoader.Load(c.HeaderConfig)
if err != nil {
return nil, newError("invalid mKCP header config.").Base(err).AtError()
}
ts, err := headerConfig.(Buildable).Build()
if err != nil {
return nil, newError("invalid mKCP header config").Base(err).AtError()
}
config.HeaderConfig = serial.ToTypedMessage(ts)
}
if c.Seed != nil {
config.Seed = &kcp.EncryptionSeed{Seed: *c.Seed}
}
return config, nil
}
type TCPConfig struct {
HeaderConfig json.RawMessage `json:"header"`
AcceptProxyProtocol bool `json:"acceptProxyProtocol"`
}
// Build implements Buildable.
func (c *TCPConfig) Build() (proto.Message, error) {
config := new(tcp.Config)
if len(c.HeaderConfig) > 0 {
headerConfig, _, err := tcpHeaderLoader.Load(c.HeaderConfig)
if err != nil {
return nil, newError("invalid TCP header config").Base(err).AtError()
}
ts, err := headerConfig.(Buildable).Build()
if err != nil {
return nil, newError("invalid TCP header config").Base(err).AtError()
}
config.HeaderSettings = serial.ToTypedMessage(ts)
}
if c.AcceptProxyProtocol {
config.AcceptProxyProtocol = c.AcceptProxyProtocol
}
return config, nil
}
type WebSocketConfig struct {
Path string `json:"path"`
Path2 string `json:"Path"` // The key was misspelled. For backward compatibility, we have to keep track the old key.
Headers map[string]string `json:"headers"`
AcceptProxyProtocol bool `json:"acceptProxyProtocol"`
}
// Build implements Buildable.
func (c *WebSocketConfig) Build() (proto.Message, error) {
path := c.Path
if path == "" && c.Path2 != "" {
path = c.Path2
}
header := make([]*websocket.Header, 0, 32)
for key, value := range c.Headers {
header = append(header, &websocket.Header{
Key: key,
Value: value,
})
}
config := &websocket.Config{
Path: path,
Header: header,
}
if c.AcceptProxyProtocol {
config.AcceptProxyProtocol = c.AcceptProxyProtocol
}
return config, nil
}
type HTTPConfig struct {
Host *StringList `json:"host"`
Path string `json:"path"`
}
// Build implements Buildable.
func (c *HTTPConfig) Build() (proto.Message, error) {
config := &http.Config{
Path: c.Path,
}
if c.Host != nil {
config.Host = []string(*c.Host)
}
return config, nil
}
type QUICConfig struct {
Header json.RawMessage `json:"header"`
Security string `json:"security"`
Key string `json:"key"`
}
// Build implements Buildable.
func (c *QUICConfig) Build() (proto.Message, error) {
config := &quic.Config{
Key: c.Key,
}
if len(c.Header) > 0 {
headerConfig, _, err := kcpHeaderLoader.Load(c.Header)
if err != nil {
return nil, newError("invalid QUIC header config.").Base(err).AtError()
}
ts, err := headerConfig.(Buildable).Build()
if err != nil {
return nil, newError("invalid QUIC header config").Base(err).AtError()
}
config.Header = serial.ToTypedMessage(ts)
}
var st protocol.SecurityType
switch strings.ToLower(c.Security) {
case "aes-128-gcm":
st = protocol.SecurityType_AES128_GCM
case "chacha20-poly1305":
st = protocol.SecurityType_CHACHA20_POLY1305
default:
st = protocol.SecurityType_NONE
}
config.Security = &protocol.SecurityConfig{
Type: st,
}
return config, nil
}
type DomainSocketConfig struct {
Path string `json:"path"`
Abstract bool `json:"abstract"`
Padding bool `json:"padding"`
}
// Build implements Buildable.
func (c *DomainSocketConfig) Build() (proto.Message, error) {
return &domainsocket.Config{
Path: c.Path,
Abstract: c.Abstract,
Padding: c.Padding,
}, nil
}
func readFileOrString(f string, s []string) ([]byte, error) {
if len(f) > 0 {
return filesystem.ReadFile(f)
}
if len(s) > 0 {
return []byte(strings.Join(s, "\n")), nil
}
return nil, newError("both file and bytes are empty.")
}
type TLSCertConfig struct {
CertFile string `json:"certificateFile"`
CertStr []string `json:"certificate"`
KeyFile string `json:"keyFile"`
KeyStr []string `json:"key"`
Usage string `json:"usage"`
}
// Build implements Buildable.
func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
certificate := new(tls.Certificate)
cert, err := readFileOrString(c.CertFile, c.CertStr)
if err != nil {
return nil, newError("failed to parse certificate").Base(err)
}
certificate.Certificate = cert
if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {
key, err := readFileOrString(c.KeyFile, c.KeyStr)
if err != nil {
return nil, newError("failed to parse key").Base(err)
}
certificate.Key = key
}
switch strings.ToLower(c.Usage) {
case "encipherment":
certificate.Usage = tls.Certificate_ENCIPHERMENT
case "verify":
certificate.Usage = tls.Certificate_AUTHORITY_VERIFY
case "issue":
certificate.Usage = tls.Certificate_AUTHORITY_ISSUE
default:
certificate.Usage = tls.Certificate_ENCIPHERMENT
}
return certificate, nil
}
type TLSConfig struct {
Insecure bool `json:"allowInsecure"`
Certs []*TLSCertConfig `json:"certificates"`
ServerName string `json:"serverName"`
ALPN *StringList `json:"alpn"`
EnableSessionResumption bool `json:"enableSessionResumption"`
DisableSystemRoot bool `json:"disableSystemRoot"`
}
// Build implements Buildable.
func (c *TLSConfig) Build() (proto.Message, error) {
config := new(tls.Config)
config.Certificate = make([]*tls.Certificate, len(c.Certs))
for idx, certConf := range c.Certs {
cert, err := certConf.Build()
if err != nil {
return nil, err
}
config.Certificate[idx] = cert
}
serverName := c.ServerName
config.AllowInsecure = c.Insecure
if len(c.ServerName) > 0 {
config.ServerName = serverName
}
if c.ALPN != nil && len(*c.ALPN) > 0 {
config.NextProtocol = []string(*c.ALPN)
}
config.EnableSessionResumption = c.EnableSessionResumption
config.DisableSystemRoot = c.DisableSystemRoot
return config, nil
}
type TransportProtocol string
// Build implements Buildable.
func (p TransportProtocol) Build() (string, error) {
switch strings.ToLower(string(p)) {
case "tcp":
return "tcp", nil
case "kcp", "mkcp":
return "mkcp", nil
case "ws", "websocket":
return "websocket", nil
case "h2", "http":
return "http", nil
case "ds", "domainsocket":
return "domainsocket", nil
case "quic":
return "quic", nil
default:
return "", newError("Config: unknown transport protocol: ", p)
}
}
type SocketConfig struct {
Mark int32 `json:"mark"`
TFO *bool `json:"tcpFastOpen"`
TProxy string `json:"tproxy"`
AcceptProxyProtocol bool `json:"acceptProxyProtocol"`
}
// Build implements Buildable.
func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
var tfoSettings internet.SocketConfig_TCPFastOpenState
if c.TFO != nil {
if *c.TFO {
tfoSettings = internet.SocketConfig_Enable
} else {
tfoSettings = internet.SocketConfig_Disable
}
}
var tproxy internet.SocketConfig_TProxyMode
switch strings.ToLower(c.TProxy) {
case "tproxy":
tproxy = internet.SocketConfig_TProxy
case "redirect":
tproxy = internet.SocketConfig_Redirect
default:
tproxy = internet.SocketConfig_Off
}
return &internet.SocketConfig{
Mark: c.Mark,
Tfo: tfoSettings,
Tproxy: tproxy,
AcceptProxyProtocol: c.AcceptProxyProtocol,
}, nil
}
type StreamConfig struct {
Network *TransportProtocol `json:"network"`
Security string `json:"security"`
TLSSettings *TLSConfig `json:"tlsSettings"`
TCPSettings *TCPConfig `json:"tcpSettings"`
KCPSettings *KCPConfig `json:"kcpSettings"`
WSSettings *WebSocketConfig `json:"wsSettings"`
HTTPSettings *HTTPConfig `json:"httpSettings"`
DSSettings *DomainSocketConfig `json:"dsSettings"`
QUICSettings *QUICConfig `json:"quicSettings"`
SocketSettings *SocketConfig `json:"sockopt"`
}
// Build implements Buildable.
func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
config := &internet.StreamConfig{
ProtocolName: "tcp",
}
if c.Network != nil {
protocol, err := c.Network.Build()
if err != nil {
return nil, err
}
config.ProtocolName = protocol
}
if strings.EqualFold(c.Security, "tls") {
tlsSettings := c.TLSSettings
if tlsSettings == nil {
tlsSettings = &TLSConfig{}
}
ts, err := tlsSettings.Build()
if err != nil {
return nil, newError("Failed to build TLS config.").Base(err)
}
tm := serial.ToTypedMessage(ts)
config.SecuritySettings = append(config.SecuritySettings, tm)
config.SecurityType = tm.Type
}
if c.TCPSettings != nil {
ts, err := c.TCPSettings.Build()
if err != nil {
return nil, newError("Failed to build TCP config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "tcp",
Settings: serial.ToTypedMessage(ts),
})
}
if c.KCPSettings != nil {
ts, err := c.KCPSettings.Build()
if err != nil {
return nil, newError("Failed to build mKCP config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "mkcp",
Settings: serial.ToTypedMessage(ts),
})
}
if c.WSSettings != nil {
ts, err := c.WSSettings.Build()
if err != nil {
return nil, newError("Failed to build WebSocket config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "websocket",
Settings: serial.ToTypedMessage(ts),
})
}
if c.HTTPSettings != nil {
ts, err := c.HTTPSettings.Build()
if err != nil {
return nil, newError("Failed to build HTTP config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "http",
Settings: serial.ToTypedMessage(ts),
})
}
if c.DSSettings != nil {
ds, err := c.DSSettings.Build()
if err != nil {
return nil, newError("Failed to build DomainSocket config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "domainsocket",
Settings: serial.ToTypedMessage(ds),
})
}
if c.QUICSettings != nil {
qs, err := c.QUICSettings.Build()
if err != nil {
return nil, newError("Failed to build QUIC config").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "quic",
Settings: serial.ToTypedMessage(qs),
})
}
if c.SocketSettings != nil {
ss, err := c.SocketSettings.Build()
if err != nil {
return nil, newError("Failed to build sockopt").Base(err)
}
config.SocketSettings = ss
}
return config, nil
}
type ProxyConfig struct {
Tag string `json:"tag"`
}
// Build implements Buildable.
func (v *ProxyConfig) Build() (*internet.ProxyConfig, error) {
if v.Tag == "" {
return nil, newError("Proxy tag is not set.")
}
return &internet.ProxyConfig{
Tag: v.Tag,
}, nil
}
v2ray-core-4.34.0/infra/conf/transport_test.go 0000664 0000000 0000000 00000007665 13774574720 0021277 0 ustar 00root root 0000000 0000000 package conf_test
import (
"encoding/json"
"testing"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
. "v2ray.com/core/infra/conf"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/headers/http"
"v2ray.com/core/transport/internet/headers/noop"
"v2ray.com/core/transport/internet/headers/tls"
"v2ray.com/core/transport/internet/kcp"
"v2ray.com/core/transport/internet/quic"
"v2ray.com/core/transport/internet/tcp"
"v2ray.com/core/transport/internet/websocket"
)
func TestSocketConfig(t *testing.T) {
createParser := func() func(string) (proto.Message, error) {
return func(s string) (proto.Message, error) {
config := new(SocketConfig)
if err := json.Unmarshal([]byte(s), config); err != nil {
return nil, err
}
return config.Build()
}
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"mark": 1,
"tcpFastOpen": true
}`,
Parser: createParser(),
Output: &internet.SocketConfig{
Mark: 1,
Tfo: internet.SocketConfig_Enable,
},
},
})
}
func TestTransportConfig(t *testing.T) {
createParser := func() func(string) (proto.Message, error) {
return func(s string) (proto.Message, error) {
config := new(TransportConfig)
if err := json.Unmarshal([]byte(s), config); err != nil {
return nil, err
}
return config.Build()
}
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"tcpSettings": {
"header": {
"type": "http",
"request": {
"version": "1.1",
"method": "GET",
"path": "/b",
"headers": {
"a": "b",
"c": "d"
}
},
"response": {
"version": "1.0",
"status": "404",
"reason": "Not Found"
}
}
},
"kcpSettings": {
"mtu": 1200,
"header": {
"type": "none"
}
},
"wsSettings": {
"path": "/t"
},
"quicSettings": {
"key": "abcd",
"header": {
"type": "dtls"
}
}
}`,
Parser: createParser(),
Output: &transport.Config{
TransportSettings: []*internet.TransportConfig{
{
ProtocolName: "tcp",
Settings: serial.ToTypedMessage(&tcp.Config{
HeaderSettings: serial.ToTypedMessage(&http.Config{
Request: &http.RequestConfig{
Version: &http.Version{Value: "1.1"},
Method: &http.Method{Value: "GET"},
Uri: []string{"/b"},
Header: []*http.Header{
{Name: "a", Value: []string{"b"}},
{Name: "c", Value: []string{"d"}},
},
},
Response: &http.ResponseConfig{
Version: &http.Version{Value: "1.0"},
Status: &http.Status{Code: "404", Reason: "Not Found"},
Header: []*http.Header{
{
Name: "Content-Type",
Value: []string{"application/octet-stream", "video/mpeg"},
},
{
Name: "Transfer-Encoding",
Value: []string{"chunked"},
},
{
Name: "Connection",
Value: []string{"keep-alive"},
},
{
Name: "Pragma",
Value: []string{"no-cache"},
},
{
Name: "Cache-Control",
Value: []string{"private", "no-cache"},
},
},
},
}),
}),
},
{
ProtocolName: "mkcp",
Settings: serial.ToTypedMessage(&kcp.Config{
Mtu: &kcp.MTU{Value: 1200},
HeaderConfig: serial.ToTypedMessage(&noop.Config{}),
}),
},
{
ProtocolName: "websocket",
Settings: serial.ToTypedMessage(&websocket.Config{
Path: "/t",
}),
},
{
ProtocolName: "quic",
Settings: serial.ToTypedMessage(&quic.Config{
Key: "abcd",
Security: &protocol.SecurityConfig{
Type: protocol.SecurityType_NONE,
},
Header: serial.ToTypedMessage(&tls.PacketConfig{}),
}),
},
},
},
},
})
}
v2ray-core-4.34.0/infra/conf/trojan.go 0000664 0000000 0000000 00000010662 13774574720 0017470 0 ustar 00root root 0000000 0000000 package conf
import (
"encoding/json"
"runtime"
"strconv"
"syscall"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/trojan"
)
// TrojanServerTarget is configuration of a single trojan server
type TrojanServerTarget struct {
Address *Address `json:"address"`
Port uint16 `json:"port"`
Password string `json:"password"`
Email string `json:"email"`
Level byte `json:"level"`
}
// TrojanClientConfig is configuration of trojan servers
type TrojanClientConfig struct {
Servers []*TrojanServerTarget `json:"servers"`
}
// Build implements Buildable
func (c *TrojanClientConfig) Build() (proto.Message, error) {
config := new(trojan.ClientConfig)
if len(c.Servers) == 0 {
return nil, newError("0 Trojan server configured.")
}
serverSpecs := make([]*protocol.ServerEndpoint, len(c.Servers))
for idx, rec := range c.Servers {
if rec.Address == nil {
return nil, newError("Trojan server address is not set.")
}
if rec.Port == 0 {
return nil, newError("Invalid Trojan port.")
}
if rec.Password == "" {
return nil, newError("Trojan password is not specified.")
}
account := &trojan.Account{
Password: rec.Password,
}
trojan := &protocol.ServerEndpoint{
Address: rec.Address.Build(),
Port: uint32(rec.Port),
User: []*protocol.User{
{
Level: uint32(rec.Level),
Email: rec.Email,
Account: serial.ToTypedMessage(account),
},
},
}
serverSpecs[idx] = trojan
}
config.Server = serverSpecs
return config, nil
}
// TrojanInboundFallback is fallback configuration
type TrojanInboundFallback struct {
Alpn string `json:"alpn"`
Path string `json:"path"`
Type string `json:"type"`
Dest json.RawMessage `json:"dest"`
Xver uint64 `json:"xver"`
}
// TrojanUserConfig is user configuration
type TrojanUserConfig struct {
Password string `json:"password"`
Level byte `json:"level"`
Email string `json:"email"`
}
// TrojanServerConfig is Inbound configuration
type TrojanServerConfig struct {
Clients []*TrojanUserConfig `json:"clients"`
Fallback json.RawMessage `json:"fallback"`
Fallbacks []*TrojanInboundFallback `json:"fallbacks"`
}
// Build implements Buildable
func (c *TrojanServerConfig) Build() (proto.Message, error) {
config := new(trojan.ServerConfig)
config.Users = make([]*protocol.User, len(c.Clients))
for idx, rawUser := range c.Clients {
user := new(protocol.User)
account := &trojan.Account{
Password: rawUser.Password,
}
user.Email = rawUser.Email
user.Level = uint32(rawUser.Level)
user.Account = serial.ToTypedMessage(account)
config.Users[idx] = user
}
if c.Fallback != nil {
return nil, newError(`Trojan settings: please use "fallbacks":[{}] instead of "fallback":{}`)
}
for _, fb := range c.Fallbacks {
var i uint16
var s string
if err := json.Unmarshal(fb.Dest, &i); err == nil {
s = strconv.Itoa(int(i))
} else {
_ = json.Unmarshal(fb.Dest, &s)
}
config.Fallbacks = append(config.Fallbacks, &trojan.Fallback{
Alpn: fb.Alpn,
Path: fb.Path,
Type: fb.Type,
Dest: s,
Xver: fb.Xver,
})
}
for _, fb := range config.Fallbacks {
/*
if fb.Alpn == "h2" && fb.Path != "" {
return nil, newError(`Trojan fallbacks: "alpn":"h2" doesn't support "path"`)
}
*/
if fb.Path != "" && fb.Path[0] != '/' {
return nil, newError(`Trojan fallbacks: "path" must be empty or start with "/"`)
}
if fb.Type == "" && fb.Dest != "" {
if fb.Dest == "serve-ws-none" {
fb.Type = "serve"
} else {
switch fb.Dest[0] {
case '@', '/':
fb.Type = "unix"
if fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy
copy(fullAddr, fb.Dest[1:])
fb.Dest = string(fullAddr)
}
default:
if _, err := strconv.Atoi(fb.Dest); err == nil {
fb.Dest = "127.0.0.1:" + fb.Dest
}
if _, _, err := net.SplitHostPort(fb.Dest); err == nil {
fb.Type = "tcp"
}
}
}
}
if fb.Type == "" {
return nil, newError(`Trojan fallbacks: please fill in a valid value for every "dest"`)
}
if fb.Xver > 2 {
return nil, newError(`Trojan fallbacks: invalid PROXY protocol version, "xver" only accepts 0, 1, 2`)
}
}
return config, nil
}
v2ray-core-4.34.0/infra/conf/v2ray.go 0000664 0000000 0000000 00000042026 13774574720 0017235 0 ustar 00root root 0000000 0000000 package conf
import (
"encoding/json"
"log"
"os"
"strings"
"v2ray.com/core"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/app/stats"
"v2ray.com/core/common/serial"
)
var (
inboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
"dokodemo-door": func() interface{} { return new(DokodemoConfig) },
"http": func() interface{} { return new(HTTPServerConfig) },
"shadowsocks": func() interface{} { return new(ShadowsocksServerConfig) },
"socks": func() interface{} { return new(SocksServerConfig) },
"vless": func() interface{} { return new(VLessInboundConfig) },
"vmess": func() interface{} { return new(VMessInboundConfig) },
"trojan": func() interface{} { return new(TrojanServerConfig) },
"mtproto": func() interface{} { return new(MTProtoServerConfig) },
}, "protocol", "settings")
outboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
"blackhole": func() interface{} { return new(BlackholeConfig) },
"freedom": func() interface{} { return new(FreedomConfig) },
"http": func() interface{} { return new(HTTPClientConfig) },
"shadowsocks": func() interface{} { return new(ShadowsocksClientConfig) },
"socks": func() interface{} { return new(SocksClientConfig) },
"vless": func() interface{} { return new(VLessOutboundConfig) },
"vmess": func() interface{} { return new(VMessOutboundConfig) },
"trojan": func() interface{} { return new(TrojanClientConfig) },
"mtproto": func() interface{} { return new(MTProtoClientConfig) },
"dns": func() interface{} { return new(DNSOutboundConfig) },
}, "protocol", "settings")
ctllog = log.New(os.Stderr, "v2ctl> ", 0)
)
func toProtocolList(s []string) ([]proxyman.KnownProtocols, error) {
kp := make([]proxyman.KnownProtocols, 0, 8)
for _, p := range s {
switch strings.ToLower(p) {
case "http":
kp = append(kp, proxyman.KnownProtocols_HTTP)
case "https", "tls", "ssl":
kp = append(kp, proxyman.KnownProtocols_TLS)
default:
return nil, newError("Unknown protocol: ", p)
}
}
return kp, nil
}
type SniffingConfig struct {
Enabled bool `json:"enabled"`
DestOverride *StringList `json:"destOverride"`
}
// Build implements Buildable.
func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {
var p []string
if c.DestOverride != nil {
for _, domainOverride := range *c.DestOverride {
switch strings.ToLower(domainOverride) {
case "http":
p = append(p, "http")
case "tls", "https", "ssl":
p = append(p, "tls")
default:
return nil, newError("unknown protocol: ", domainOverride)
}
}
}
return &proxyman.SniffingConfig{
Enabled: c.Enabled,
DestinationOverride: p,
}, nil
}
type MuxConfig struct {
Enabled bool `json:"enabled"`
Concurrency int16 `json:"concurrency"`
}
// Build creates MultiplexingConfig, Concurrency < 0 completely disables mux.
func (m *MuxConfig) Build() *proxyman.MultiplexingConfig {
if m.Concurrency < 0 {
return nil
}
var con uint32 = 8
if m.Concurrency > 0 {
con = uint32(m.Concurrency)
}
return &proxyman.MultiplexingConfig{
Enabled: m.Enabled,
Concurrency: con,
}
}
type InboundDetourAllocationConfig struct {
Strategy string `json:"strategy"`
Concurrency *uint32 `json:"concurrency"`
RefreshMin *uint32 `json:"refresh"`
}
// Build implements Buildable.
func (c *InboundDetourAllocationConfig) Build() (*proxyman.AllocationStrategy, error) {
config := new(proxyman.AllocationStrategy)
switch strings.ToLower(c.Strategy) {
case "always":
config.Type = proxyman.AllocationStrategy_Always
case "random":
config.Type = proxyman.AllocationStrategy_Random
case "external":
config.Type = proxyman.AllocationStrategy_External
default:
return nil, newError("unknown allocation strategy: ", c.Strategy)
}
if c.Concurrency != nil {
config.Concurrency = &proxyman.AllocationStrategy_AllocationStrategyConcurrency{
Value: *c.Concurrency,
}
}
if c.RefreshMin != nil {
config.Refresh = &proxyman.AllocationStrategy_AllocationStrategyRefresh{
Value: *c.RefreshMin,
}
}
return config, nil
}
type InboundDetourConfig struct {
Protocol string `json:"protocol"`
PortRange *PortRange `json:"port"`
ListenOn *Address `json:"listen"`
Settings *json.RawMessage `json:"settings"`
Tag string `json:"tag"`
Allocation *InboundDetourAllocationConfig `json:"allocate"`
StreamSetting *StreamConfig `json:"streamSettings"`
DomainOverride *StringList `json:"domainOverride"`
SniffingConfig *SniffingConfig `json:"sniffing"`
}
// Build implements Buildable.
func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
receiverSettings := &proxyman.ReceiverConfig{}
if c.ListenOn == nil {
// Listen on anyip, must set PortRange
if c.PortRange == nil {
return nil, newError("Listen on AnyIP but no Port(s) set in InboundDetour.")
}
receiverSettings.PortRange = c.PortRange.Build()
} else {
// Listen on specific IP or Unix Domain Socket
receiverSettings.Listen = c.ListenOn.Build()
listenDS := c.ListenOn.Family().IsDomain() && (c.ListenOn.Domain()[0] == '/' || c.ListenOn.Domain()[0] == '@')
listenIP := c.ListenOn.Family().IsIP() || (c.ListenOn.Family().IsDomain() && c.ListenOn.Domain() == "localhost")
switch {
case listenIP:
// Listen on specific IP, must set PortRange
if c.PortRange == nil {
return nil, newError("Listen on specific ip without port in InboundDetour.")
}
// Listen on IP:Port
receiverSettings.PortRange = c.PortRange.Build()
case listenDS:
if c.PortRange != nil {
// Listen on Unix Domain Socket, PortRange should be nil
receiverSettings.PortRange = nil
}
default:
return nil, newError("unable to listen on domain address: ", c.ListenOn.Domain())
}
}
if c.Allocation != nil {
concurrency := -1
if c.Allocation.Concurrency != nil && c.Allocation.Strategy == "random" {
concurrency = int(*c.Allocation.Concurrency)
}
portRange := int(c.PortRange.To - c.PortRange.From + 1)
if concurrency >= 0 && concurrency >= portRange {
return nil, newError("not enough ports. concurrency = ", concurrency, " ports: ", c.PortRange.From, " - ", c.PortRange.To)
}
as, err := c.Allocation.Build()
if err != nil {
return nil, err
}
receiverSettings.AllocationStrategy = as
}
if c.StreamSetting != nil {
ss, err := c.StreamSetting.Build()
if err != nil {
return nil, err
}
receiverSettings.StreamSettings = ss
}
if c.SniffingConfig != nil {
s, err := c.SniffingConfig.Build()
if err != nil {
return nil, newError("failed to build sniffing config").Base(err)
}
receiverSettings.SniffingSettings = s
}
if c.DomainOverride != nil {
kp, err := toProtocolList(*c.DomainOverride)
if err != nil {
return nil, newError("failed to parse inbound detour config").Base(err)
}
receiverSettings.DomainOverride = kp
}
settings := []byte("{}")
if c.Settings != nil {
settings = ([]byte)(*c.Settings)
}
rawConfig, err := inboundConfigLoader.LoadWithID(settings, c.Protocol)
if err != nil {
return nil, newError("failed to load inbound detour config.").Base(err)
}
if dokodemoConfig, ok := rawConfig.(*DokodemoConfig); ok {
receiverSettings.ReceiveOriginalDestination = dokodemoConfig.Redirect
}
ts, err := rawConfig.(Buildable).Build()
if err != nil {
return nil, err
}
return &core.InboundHandlerConfig{
Tag: c.Tag,
ReceiverSettings: serial.ToTypedMessage(receiverSettings),
ProxySettings: serial.ToTypedMessage(ts),
}, nil
}
type OutboundDetourConfig struct {
Protocol string `json:"protocol"`
SendThrough *Address `json:"sendThrough"`
Tag string `json:"tag"`
Settings *json.RawMessage `json:"settings"`
StreamSetting *StreamConfig `json:"streamSettings"`
ProxySettings *ProxyConfig `json:"proxySettings"`
MuxSettings *MuxConfig `json:"mux"`
}
// Build implements Buildable.
func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
senderSettings := &proxyman.SenderConfig{}
if c.SendThrough != nil {
address := c.SendThrough
if address.Family().IsDomain() {
return nil, newError("unable to send through: " + address.String())
}
senderSettings.Via = address.Build()
}
if c.StreamSetting != nil {
ss, err := c.StreamSetting.Build()
if err != nil {
return nil, err
}
senderSettings.StreamSettings = ss
}
if c.ProxySettings != nil {
ps, err := c.ProxySettings.Build()
if err != nil {
return nil, newError("invalid outbound detour proxy settings.").Base(err)
}
senderSettings.ProxySettings = ps
}
if c.MuxSettings != nil {
senderSettings.MultiplexSettings = c.MuxSettings.Build()
}
settings := []byte("{}")
if c.Settings != nil {
settings = ([]byte)(*c.Settings)
}
rawConfig, err := outboundConfigLoader.LoadWithID(settings, c.Protocol)
if err != nil {
return nil, newError("failed to parse to outbound detour config.").Base(err)
}
ts, err := rawConfig.(Buildable).Build()
if err != nil {
return nil, err
}
return &core.OutboundHandlerConfig{
SenderSettings: serial.ToTypedMessage(senderSettings),
Tag: c.Tag,
ProxySettings: serial.ToTypedMessage(ts),
}, nil
}
type StatsConfig struct{}
// Build implements Buildable.
func (c *StatsConfig) Build() (*stats.Config, error) {
return &stats.Config{}, nil
}
type Config struct {
// Port of this Point server.
// Deprecated: Port exists for historical compatibility
// and should not be used.
Port uint16 `json:"port"`
// Deprecated: InboundConfig exists for historical compatibility
// and should not be used.
InboundConfig *InboundDetourConfig `json:"inbound"`
// Deprecated: OutboundConfig exists for historical compatibility
// and should not be used.
OutboundConfig *OutboundDetourConfig `json:"outbound"`
// Deprecated: InboundDetours exists for historical compatibility
// and should not be used.
InboundDetours []InboundDetourConfig `json:"inboundDetour"`
// Deprecated: OutboundDetours exists for historical compatibility
// and should not be used.
OutboundDetours []OutboundDetourConfig `json:"outboundDetour"`
LogConfig *LogConfig `json:"log"`
RouterConfig *RouterConfig `json:"routing"`
DNSConfig *DNSConfig `json:"dns"`
InboundConfigs []InboundDetourConfig `json:"inbounds"`
OutboundConfigs []OutboundDetourConfig `json:"outbounds"`
Transport *TransportConfig `json:"transport"`
Policy *PolicyConfig `json:"policy"`
API *APIConfig `json:"api"`
Stats *StatsConfig `json:"stats"`
Reverse *ReverseConfig `json:"reverse"`
}
func (c *Config) findInboundTag(tag string) int {
found := -1
for idx, ib := range c.InboundConfigs {
if ib.Tag == tag {
found = idx
break
}
}
return found
}
func (c *Config) findOutboundTag(tag string) int {
found := -1
for idx, ob := range c.OutboundConfigs {
if ob.Tag == tag {
found = idx
break
}
}
return found
}
// Override method accepts another Config overrides the current attribute
func (c *Config) Override(o *Config, fn string) {
// only process the non-deprecated members
if o.LogConfig != nil {
c.LogConfig = o.LogConfig
}
if o.RouterConfig != nil {
c.RouterConfig = o.RouterConfig
}
if o.DNSConfig != nil {
c.DNSConfig = o.DNSConfig
}
if o.Transport != nil {
c.Transport = o.Transport
}
if o.Policy != nil {
c.Policy = o.Policy
}
if o.API != nil {
c.API = o.API
}
if o.Stats != nil {
c.Stats = o.Stats
}
if o.Reverse != nil {
c.Reverse = o.Reverse
}
// deprecated attrs... keep them for now
if o.InboundConfig != nil {
c.InboundConfig = o.InboundConfig
}
if o.OutboundConfig != nil {
c.OutboundConfig = o.OutboundConfig
}
if o.InboundDetours != nil {
c.InboundDetours = o.InboundDetours
}
if o.OutboundDetours != nil {
c.OutboundDetours = o.OutboundDetours
}
// deprecated attrs
// update the Inbound in slice if the only one in overide config has same tag
if len(o.InboundConfigs) > 0 {
if len(c.InboundConfigs) > 0 && len(o.InboundConfigs) == 1 {
if idx := c.findInboundTag(o.InboundConfigs[0].Tag); idx > -1 {
c.InboundConfigs[idx] = o.InboundConfigs[0]
ctllog.Println("[", fn, "] updated inbound with tag: ", o.InboundConfigs[0].Tag)
} else {
c.InboundConfigs = append(c.InboundConfigs, o.InboundConfigs[0])
ctllog.Println("[", fn, "] appended inbound with tag: ", o.InboundConfigs[0].Tag)
}
} else {
c.InboundConfigs = o.InboundConfigs
}
}
// update the Outbound in slice if the only one in overide config has same tag
if len(o.OutboundConfigs) > 0 {
if len(c.OutboundConfigs) > 0 && len(o.OutboundConfigs) == 1 {
if idx := c.findOutboundTag(o.OutboundConfigs[0].Tag); idx > -1 {
c.OutboundConfigs[idx] = o.OutboundConfigs[0]
ctllog.Println("[", fn, "] updated outbound with tag: ", o.OutboundConfigs[0].Tag)
} else {
if strings.Contains(strings.ToLower(fn), "tail") {
c.OutboundConfigs = append(c.OutboundConfigs, o.OutboundConfigs[0])
ctllog.Println("[", fn, "] appended outbound with tag: ", o.OutboundConfigs[0].Tag)
} else {
c.OutboundConfigs = append(o.OutboundConfigs, c.OutboundConfigs...)
ctllog.Println("[", fn, "] prepended outbound with tag: ", o.OutboundConfigs[0].Tag)
}
}
} else {
c.OutboundConfigs = o.OutboundConfigs
}
}
}
func applyTransportConfig(s *StreamConfig, t *TransportConfig) {
if s.TCPSettings == nil {
s.TCPSettings = t.TCPConfig
}
if s.KCPSettings == nil {
s.KCPSettings = t.KCPConfig
}
if s.WSSettings == nil {
s.WSSettings = t.WSConfig
}
if s.HTTPSettings == nil {
s.HTTPSettings = t.HTTPConfig
}
if s.DSSettings == nil {
s.DSSettings = t.DSConfig
}
}
// Build implements Buildable.
func (c *Config) Build() (*core.Config, error) {
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.InboundConfig{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
},
}
if c.API != nil {
apiConf, err := c.API.Build()
if err != nil {
return nil, err
}
config.App = append(config.App, serial.ToTypedMessage(apiConf))
}
if c.Stats != nil {
statsConf, err := c.Stats.Build()
if err != nil {
return nil, err
}
config.App = append(config.App, serial.ToTypedMessage(statsConf))
}
var logConfMsg *serial.TypedMessage
if c.LogConfig != nil {
logConfMsg = serial.ToTypedMessage(c.LogConfig.Build())
} else {
logConfMsg = serial.ToTypedMessage(DefaultLogConfig())
}
// let logger module be the first App to start,
// so that other modules could print log during initiating
config.App = append([]*serial.TypedMessage{logConfMsg}, config.App...)
if c.RouterConfig != nil {
routerConfig, err := c.RouterConfig.Build()
if err != nil {
return nil, err
}
config.App = append(config.App, serial.ToTypedMessage(routerConfig))
}
if c.DNSConfig != nil {
dnsApp, err := c.DNSConfig.Build()
if err != nil {
return nil, newError("failed to parse DNS config").Base(err)
}
config.App = append(config.App, serial.ToTypedMessage(dnsApp))
}
if c.Policy != nil {
pc, err := c.Policy.Build()
if err != nil {
return nil, err
}
config.App = append(config.App, serial.ToTypedMessage(pc))
}
if c.Reverse != nil {
r, err := c.Reverse.Build()
if err != nil {
return nil, err
}
config.App = append(config.App, serial.ToTypedMessage(r))
}
var inbounds []InboundDetourConfig
if c.InboundConfig != nil {
inbounds = append(inbounds, *c.InboundConfig)
}
if len(c.InboundDetours) > 0 {
inbounds = append(inbounds, c.InboundDetours...)
}
if len(c.InboundConfigs) > 0 {
inbounds = append(inbounds, c.InboundConfigs...)
}
// Backward compatibility.
if len(inbounds) > 0 && inbounds[0].PortRange == nil && c.Port > 0 {
inbounds[0].PortRange = &PortRange{
From: uint32(c.Port),
To: uint32(c.Port),
}
}
for _, rawInboundConfig := range inbounds {
if c.Transport != nil {
if rawInboundConfig.StreamSetting == nil {
rawInboundConfig.StreamSetting = &StreamConfig{}
}
applyTransportConfig(rawInboundConfig.StreamSetting, c.Transport)
}
ic, err := rawInboundConfig.Build()
if err != nil {
return nil, err
}
config.Inbound = append(config.Inbound, ic)
}
var outbounds []OutboundDetourConfig
if c.OutboundConfig != nil {
outbounds = append(outbounds, *c.OutboundConfig)
}
if len(c.OutboundDetours) > 0 {
outbounds = append(outbounds, c.OutboundDetours...)
}
if len(c.OutboundConfigs) > 0 {
outbounds = append(outbounds, c.OutboundConfigs...)
}
for _, rawOutboundConfig := range outbounds {
if c.Transport != nil {
if rawOutboundConfig.StreamSetting == nil {
rawOutboundConfig.StreamSetting = &StreamConfig{}
}
applyTransportConfig(rawOutboundConfig.StreamSetting, c.Transport)
}
oc, err := rawOutboundConfig.Build()
if err != nil {
return nil, err
}
config.Outbound = append(config.Outbound, oc)
}
return config, nil
}
v2ray-core-4.34.0/infra/conf/v2ray_test.go 0000664 0000000 0000000 00000030520 13774574720 0020270 0 ustar 00root root 0000000 0000000 package conf_test
import (
"encoding/json"
"reflect"
"testing"
"github.com/golang/protobuf/proto"
"github.com/google/go-cmp/cmp"
"v2ray.com/core"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/log"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/app/router"
"v2ray.com/core/common"
clog "v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
. "v2ray.com/core/infra/conf"
"v2ray.com/core/proxy/blackhole"
dns_proxy "v2ray.com/core/proxy/dns"
"v2ray.com/core/proxy/freedom"
"v2ray.com/core/proxy/vmess"
"v2ray.com/core/proxy/vmess/inbound"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/http"
"v2ray.com/core/transport/internet/tls"
"v2ray.com/core/transport/internet/websocket"
)
func TestV2RayConfig(t *testing.T) {
createParser := func() func(string) (proto.Message, error) {
return func(s string) (proto.Message, error) {
config := new(Config)
if err := json.Unmarshal([]byte(s), config); err != nil {
return nil, err
}
return config.Build()
}
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"outbound": {
"protocol": "freedom",
"settings": {}
},
"log": {
"access": "/var/log/v2ray/access.log",
"loglevel": "error",
"error": "/var/log/v2ray/error.log"
},
"inbound": {
"streamSettings": {
"network": "ws",
"wsSettings": {
"headers": {
"host": "example.domain"
},
"path": ""
},
"tlsSettings": {
"alpn": "h2"
},
"security": "tls"
},
"protocol": "vmess",
"port": 443,
"settings": {
"clients": [
{
"alterId": 100,
"security": "aes-128-gcm",
"id": "0cdf8a45-303d-4fed-9780-29aa7f54175e"
}
]
}
},
"inbounds": [{
"streamSettings": {
"network": "ws",
"wsSettings": {
"headers": {
"host": "example.domain"
},
"path": ""
},
"tlsSettings": {
"alpn": "h2"
},
"security": "tls"
},
"protocol": "vmess",
"port": "443-500",
"allocate": {
"strategy": "random",
"concurrency": 3
},
"settings": {
"clients": [
{
"alterId": 100,
"security": "aes-128-gcm",
"id": "0cdf8a45-303d-4fed-9780-29aa7f54175e"
}
]
}
}],
"outboundDetour": [
{
"tag": "blocked",
"protocol": "blackhole"
},
{
"protocol": "dns"
}
],
"routing": {
"strategy": "rules",
"settings": {
"rules": [
{
"ip": [
"10.0.0.0/8"
],
"type": "field",
"outboundTag": "blocked"
}
]
}
},
"transport": {
"httpSettings": {
"path": "/test"
}
}
}`,
Parser: createParser(),
Output: &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogType: log.LogType_File,
ErrorLogPath: "/var/log/v2ray/error.log",
ErrorLogLevel: clog.Severity_Error,
AccessLogType: log.LogType_File,
AccessLogPath: "/var/log/v2ray/access.log",
}),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.InboundConfig{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(&router.Config{
DomainStrategy: router.Config_AsIs,
Rule: []*router.RoutingRule{
{
Geoip: []*router.GeoIP{
{
Cidr: []*router.CIDR{
{
Ip: []byte{10, 0, 0, 0},
Prefix: 8,
},
},
},
},
TargetTag: &router.RoutingRule_Tag{
Tag: "blocked",
},
},
},
}),
},
Outbound: []*core.OutboundHandlerConfig{
{
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
StreamSettings: &internet.StreamConfig{
ProtocolName: "tcp",
TransportSettings: []*internet.TransportConfig{
{
ProtocolName: "http",
Settings: serial.ToTypedMessage(&http.Config{
Path: "/test",
}),
},
},
},
}),
ProxySettings: serial.ToTypedMessage(&freedom.Config{
DomainStrategy: freedom.Config_AS_IS,
UserLevel: 0,
}),
},
{
Tag: "blocked",
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
StreamSettings: &internet.StreamConfig{
ProtocolName: "tcp",
TransportSettings: []*internet.TransportConfig{
{
ProtocolName: "http",
Settings: serial.ToTypedMessage(&http.Config{
Path: "/test",
}),
},
},
},
}),
ProxySettings: serial.ToTypedMessage(&blackhole.Config{}),
},
{
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
StreamSettings: &internet.StreamConfig{
ProtocolName: "tcp",
TransportSettings: []*internet.TransportConfig{
{
ProtocolName: "http",
Settings: serial.ToTypedMessage(&http.Config{
Path: "/test",
}),
},
},
},
}),
ProxySettings: serial.ToTypedMessage(&dns_proxy.Config{
Server: &net.Endpoint{},
}),
},
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: &net.PortRange{
From: 443,
To: 443,
},
StreamSettings: &internet.StreamConfig{
ProtocolName: "websocket",
TransportSettings: []*internet.TransportConfig{
{
ProtocolName: "websocket",
Settings: serial.ToTypedMessage(&websocket.Config{
Header: []*websocket.Header{
{
Key: "host",
Value: "example.domain",
},
},
}),
},
{
ProtocolName: "http",
Settings: serial.ToTypedMessage(&http.Config{
Path: "/test",
}),
},
},
SecurityType: "v2ray.core.transport.internet.tls.Config",
SecuritySettings: []*serial.TypedMessage{
serial.ToTypedMessage(&tls.Config{
NextProtocol: []string{"h2"},
}),
},
},
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
Level: 0,
Account: serial.ToTypedMessage(&vmess.Account{
Id: "0cdf8a45-303d-4fed-9780-29aa7f54175e",
AlterId: 100,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
},
},
}),
},
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: &net.PortRange{
From: 443,
To: 500,
},
AllocationStrategy: &proxyman.AllocationStrategy{
Type: proxyman.AllocationStrategy_Random,
Concurrency: &proxyman.AllocationStrategy_AllocationStrategyConcurrency{
Value: 3,
},
},
StreamSettings: &internet.StreamConfig{
ProtocolName: "websocket",
TransportSettings: []*internet.TransportConfig{
{
ProtocolName: "websocket",
Settings: serial.ToTypedMessage(&websocket.Config{
Header: []*websocket.Header{
{
Key: "host",
Value: "example.domain",
},
},
}),
},
{
ProtocolName: "http",
Settings: serial.ToTypedMessage(&http.Config{
Path: "/test",
}),
},
},
SecurityType: "v2ray.core.transport.internet.tls.Config",
SecuritySettings: []*serial.TypedMessage{
serial.ToTypedMessage(&tls.Config{
NextProtocol: []string{"h2"},
}),
},
},
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
Level: 0,
Account: serial.ToTypedMessage(&vmess.Account{
Id: "0cdf8a45-303d-4fed-9780-29aa7f54175e",
AlterId: 100,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
},
},
}),
},
},
},
},
})
}
func TestMuxConfig_Build(t *testing.T) {
tests := []struct {
name string
fields string
want *proxyman.MultiplexingConfig
}{
{"default", `{"enabled": true, "concurrency": 16}`, &proxyman.MultiplexingConfig{
Enabled: true,
Concurrency: 16,
}},
{"empty def", `{}`, &proxyman.MultiplexingConfig{
Enabled: false,
Concurrency: 8,
}},
{"not enable", `{"enabled": false, "concurrency": 4}`, &proxyman.MultiplexingConfig{
Enabled: false,
Concurrency: 4,
}},
{"forbidden", `{"enabled": false, "concurrency": -1}`, nil},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := &MuxConfig{}
common.Must(json.Unmarshal([]byte(tt.fields), m))
if got := m.Build(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("MuxConfig.Build() = %v, want %v", got, tt.want)
}
})
}
}
func TestConfig_Override(t *testing.T) {
tests := []struct {
name string
orig *Config
over *Config
fn string
want *Config
}{
{"combine/empty",
&Config{},
&Config{
LogConfig: &LogConfig{},
RouterConfig: &RouterConfig{},
DNSConfig: &DNSConfig{},
Transport: &TransportConfig{},
Policy: &PolicyConfig{},
API: &APIConfig{},
Stats: &StatsConfig{},
Reverse: &ReverseConfig{},
},
"",
&Config{
LogConfig: &LogConfig{},
RouterConfig: &RouterConfig{},
DNSConfig: &DNSConfig{},
Transport: &TransportConfig{},
Policy: &PolicyConfig{},
API: &APIConfig{},
Stats: &StatsConfig{},
Reverse: &ReverseConfig{},
},
},
{"combine/newattr",
&Config{InboundConfigs: []InboundDetourConfig{{Tag: "old"}}},
&Config{LogConfig: &LogConfig{}}, "",
&Config{LogConfig: &LogConfig{}, InboundConfigs: []InboundDetourConfig{{Tag: "old"}}}},
{"replace/inbounds",
&Config{InboundConfigs: []InboundDetourConfig{{Tag: "pos0"}, {Protocol: "vmess", Tag: "pos1"}}},
&Config{InboundConfigs: []InboundDetourConfig{{Tag: "pos1", Protocol: "kcp"}}},
"",
&Config{InboundConfigs: []InboundDetourConfig{{Tag: "pos0"}, {Tag: "pos1", Protocol: "kcp"}}}},
{"replace/inbounds-replaceall",
&Config{InboundConfigs: []InboundDetourConfig{{Tag: "pos0"}, {Protocol: "vmess", Tag: "pos1"}}},
&Config{InboundConfigs: []InboundDetourConfig{{Tag: "pos1", Protocol: "kcp"}, {Tag: "pos2", Protocol: "kcp"}}},
"",
&Config{InboundConfigs: []InboundDetourConfig{{Tag: "pos1", Protocol: "kcp"}, {Tag: "pos2", Protocol: "kcp"}}}},
{"replace/notag-append",
&Config{InboundConfigs: []InboundDetourConfig{{}, {Protocol: "vmess"}}},
&Config{InboundConfigs: []InboundDetourConfig{{Tag: "pos1", Protocol: "kcp"}}},
"",
&Config{InboundConfigs: []InboundDetourConfig{{}, {Protocol: "vmess"}, {Tag: "pos1", Protocol: "kcp"}}}},
{"replace/outbounds",
&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos0"}, {Protocol: "vmess", Tag: "pos1"}}},
&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos1", Protocol: "kcp"}}},
"",
&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos0"}, {Tag: "pos1", Protocol: "kcp"}}}},
{"replace/outbounds-prepend",
&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos0"}, {Protocol: "vmess", Tag: "pos1"}}},
&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos1", Protocol: "kcp"}, {Tag: "pos2", Protocol: "kcp"}}},
"config.json",
&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos1", Protocol: "kcp"}, {Tag: "pos2", Protocol: "kcp"}}}},
{"replace/outbounds-append",
&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos0"}, {Protocol: "vmess", Tag: "pos1"}}},
&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos2", Protocol: "kcp"}}},
"config_tail.json",
&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos0"}, {Protocol: "vmess", Tag: "pos1"}, {Tag: "pos2", Protocol: "kcp"}}}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.orig.Override(tt.over, tt.fn)
if r := cmp.Diff(tt.orig, tt.want); r != "" {
t.Error(r)
}
})
}
}
v2ray-core-4.34.0/infra/conf/vless.go 0000664 0000000 0000000 00000011523 13774574720 0017324 0 ustar 00root root 0000000 0000000 package conf
import (
"encoding/json"
"runtime"
"strconv"
"syscall"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/vless"
"v2ray.com/core/proxy/vless/inbound"
"v2ray.com/core/proxy/vless/outbound"
)
type VLessInboundFallback struct {
Alpn string `json:"alpn"`
Path string `json:"path"`
Type string `json:"type"`
Dest json.RawMessage `json:"dest"`
Xver uint64 `json:"xver"`
}
type VLessInboundConfig struct {
Clients []json.RawMessage `json:"clients"`
Decryption string `json:"decryption"`
Fallback json.RawMessage `json:"fallback"`
Fallbacks []*VLessInboundFallback `json:"fallbacks"`
}
// Build implements Buildable
func (c *VLessInboundConfig) Build() (proto.Message, error) {
config := new(inbound.Config)
config.Clients = make([]*protocol.User, len(c.Clients))
for idx, rawUser := range c.Clients {
user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil {
return nil, newError(`VLESS clients: invalid user`).Base(err)
}
account := new(vless.Account)
if err := json.Unmarshal(rawUser, account); err != nil {
return nil, newError(`VLESS clients: invalid user`).Base(err)
}
if account.Encryption != "" {
return nil, newError(`VLESS clients: "encryption" should not in inbound settings`)
}
user.Account = serial.ToTypedMessage(account)
config.Clients[idx] = user
}
if c.Decryption != "none" {
return nil, newError(`VLESS settings: please add/set "decryption":"none" to every settings`)
}
config.Decryption = c.Decryption
if c.Fallback != nil {
return nil, newError(`VLESS settings: please use "fallbacks":[{}] instead of "fallback":{}`)
}
for _, fb := range c.Fallbacks {
var i uint16
var s string
if err := json.Unmarshal(fb.Dest, &i); err == nil {
s = strconv.Itoa(int(i))
} else {
_ = json.Unmarshal(fb.Dest, &s)
}
config.Fallbacks = append(config.Fallbacks, &inbound.Fallback{
Alpn: fb.Alpn,
Path: fb.Path,
Type: fb.Type,
Dest: s,
Xver: fb.Xver,
})
}
for _, fb := range config.Fallbacks {
/*
if fb.Alpn == "h2" && fb.Path != "" {
return nil, newError(`VLESS fallbacks: "alpn":"h2" doesn't support "path"`)
}
*/
if fb.Path != "" && fb.Path[0] != '/' {
return nil, newError(`VLESS fallbacks: "path" must be empty or start with "/"`)
}
if fb.Type == "" && fb.Dest != "" {
if fb.Dest == "serve-ws-none" {
fb.Type = "serve"
} else {
switch fb.Dest[0] {
case '@', '/':
fb.Type = "unix"
if fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy
copy(fullAddr, fb.Dest[1:])
fb.Dest = string(fullAddr)
}
default:
if _, err := strconv.Atoi(fb.Dest); err == nil {
fb.Dest = "127.0.0.1:" + fb.Dest
}
if _, _, err := net.SplitHostPort(fb.Dest); err == nil {
fb.Type = "tcp"
}
}
}
}
if fb.Type == "" {
return nil, newError(`VLESS fallbacks: please fill in a valid value for every "dest"`)
}
if fb.Xver > 2 {
return nil, newError(`VLESS fallbacks: invalid PROXY protocol version, "xver" only accepts 0, 1, 2`)
}
}
return config, nil
}
type VLessOutboundVnext struct {
Address *Address `json:"address"`
Port uint16 `json:"port"`
Users []json.RawMessage `json:"users"`
}
type VLessOutboundConfig struct {
Vnext []*VLessOutboundVnext `json:"vnext"`
}
// Build implements Buildable
func (c *VLessOutboundConfig) Build() (proto.Message, error) {
config := new(outbound.Config)
if len(c.Vnext) == 0 {
return nil, newError(`VLESS settings: "vnext" is empty`)
}
config.Vnext = make([]*protocol.ServerEndpoint, len(c.Vnext))
for idx, rec := range c.Vnext {
if rec.Address == nil {
return nil, newError(`VLESS vnext: "address" is not set`)
}
if len(rec.Users) == 0 {
return nil, newError(`VLESS vnext: "users" is empty`)
}
spec := &protocol.ServerEndpoint{
Address: rec.Address.Build(),
Port: uint32(rec.Port),
User: make([]*protocol.User, len(rec.Users)),
}
for idx, rawUser := range rec.Users {
user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil {
return nil, newError(`VLESS users: invalid user`).Base(err)
}
account := new(vless.Account)
if err := json.Unmarshal(rawUser, account); err != nil {
return nil, newError(`VLESS users: invalid user`).Base(err)
}
if account.Encryption != "none" {
return nil, newError(`VLESS users: please add/set "encryption":"none" for every user`)
}
user.Account = serial.ToTypedMessage(account)
spec.User[idx] = user
}
config.Vnext[idx] = spec
}
return config, nil
}
v2ray-core-4.34.0/infra/conf/vless_test.go 0000664 0000000 0000000 00000004562 13774574720 0020370 0 ustar 00root root 0000000 0000000 package conf_test
import (
"testing"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
. "v2ray.com/core/infra/conf"
"v2ray.com/core/proxy/vless"
"v2ray.com/core/proxy/vless/inbound"
"v2ray.com/core/proxy/vless/outbound"
)
func TestVLessOutbound(t *testing.T) {
creator := func() Buildable {
return new(VLessOutboundConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"vnext": [{
"address": "example.com",
"port": 443,
"users": [
{
"id": "27848739-7e62-4138-9fd3-098a63964b6b",
"encryption": "none",
"level": 0
}
]
}]
}`,
Parser: loadJSON(creator),
Output: &outbound.Config{
Vnext: []*protocol.ServerEndpoint{
{
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Domain{
Domain: "example.com",
},
},
Port: 443,
User: []*protocol.User{
{
Account: serial.ToTypedMessage(&vless.Account{
Id: "27848739-7e62-4138-9fd3-098a63964b6b",
Encryption: "none",
}),
Level: 0,
},
},
},
},
},
},
})
}
func TestVLessInbound(t *testing.T) {
creator := func() Buildable {
return new(VLessInboundConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"clients": [
{
"id": "27848739-7e62-4138-9fd3-098a63964b6b",
"level": 0,
"email": "love@v2fly.org"
}
],
"decryption": "none",
"fallbacks": [
{
"dest": 80
},
{
"alpn": "h2",
"dest": "@/dev/shm/domain.socket",
"xver": 2
},
{
"path": "/innerws",
"dest": "serve-ws-none"
}
]
}`,
Parser: loadJSON(creator),
Output: &inbound.Config{
Clients: []*protocol.User{
{
Account: serial.ToTypedMessage(&vless.Account{
Id: "27848739-7e62-4138-9fd3-098a63964b6b",
}),
Level: 0,
Email: "love@v2fly.org",
},
},
Decryption: "none",
Fallbacks: []*inbound.Fallback{
{
Alpn: "",
Path: "",
Type: "tcp",
Dest: "127.0.0.1:80",
Xver: 0,
},
{
Alpn: "h2",
Path: "",
Type: "unix",
Dest: "@/dev/shm/domain.socket",
Xver: 2,
},
{
Alpn: "",
Path: "/innerws",
Type: "serve",
Dest: "serve-ws-none",
Xver: 0,
},
},
},
},
})
}
v2ray-core-4.34.0/infra/conf/vmess.go 0000664 0000000 0000000 00000010064 13774574720 0017324 0 ustar 00root root 0000000 0000000 package conf
import (
"encoding/json"
"strings"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/vmess"
"v2ray.com/core/proxy/vmess/inbound"
"v2ray.com/core/proxy/vmess/outbound"
)
type VMessAccount struct {
ID string `json:"id"`
AlterIds uint16 `json:"alterId"`
Security string `json:"security"`
}
// Build implements Buildable
func (a *VMessAccount) Build() *vmess.Account {
var st protocol.SecurityType
switch strings.ToLower(a.Security) {
case "aes-128-gcm":
st = protocol.SecurityType_AES128_GCM
case "chacha20-poly1305":
st = protocol.SecurityType_CHACHA20_POLY1305
case "auto":
st = protocol.SecurityType_AUTO
case "none":
st = protocol.SecurityType_NONE
default:
st = protocol.SecurityType_AUTO
}
return &vmess.Account{
Id: a.ID,
AlterId: uint32(a.AlterIds),
SecuritySettings: &protocol.SecurityConfig{
Type: st,
},
}
}
type VMessDetourConfig struct {
ToTag string `json:"to"`
}
// Build implements Buildable
func (c *VMessDetourConfig) Build() *inbound.DetourConfig {
return &inbound.DetourConfig{
To: c.ToTag,
}
}
type FeaturesConfig struct {
Detour *VMessDetourConfig `json:"detour"`
}
type VMessDefaultConfig struct {
AlterIDs uint16 `json:"alterId"`
Level byte `json:"level"`
}
// Build implements Buildable
func (c *VMessDefaultConfig) Build() *inbound.DefaultConfig {
config := new(inbound.DefaultConfig)
config.AlterId = uint32(c.AlterIDs)
config.Level = uint32(c.Level)
return config
}
type VMessInboundConfig struct {
Users []json.RawMessage `json:"clients"`
Features *FeaturesConfig `json:"features"`
Defaults *VMessDefaultConfig `json:"default"`
DetourConfig *VMessDetourConfig `json:"detour"`
SecureOnly bool `json:"disableInsecureEncryption"`
}
// Build implements Buildable
func (c *VMessInboundConfig) Build() (proto.Message, error) {
config := &inbound.Config{
SecureEncryptionOnly: c.SecureOnly,
}
if c.Defaults != nil {
config.Default = c.Defaults.Build()
}
if c.DetourConfig != nil {
config.Detour = c.DetourConfig.Build()
} else if c.Features != nil && c.Features.Detour != nil {
config.Detour = c.Features.Detour.Build()
}
config.User = make([]*protocol.User, len(c.Users))
for idx, rawData := range c.Users {
user := new(protocol.User)
if err := json.Unmarshal(rawData, user); err != nil {
return nil, newError("invalid VMess user").Base(err)
}
account := new(VMessAccount)
if err := json.Unmarshal(rawData, account); err != nil {
return nil, newError("invalid VMess user").Base(err)
}
user.Account = serial.ToTypedMessage(account.Build())
config.User[idx] = user
}
return config, nil
}
type VMessOutboundTarget struct {
Address *Address `json:"address"`
Port uint16 `json:"port"`
Users []json.RawMessage `json:"users"`
}
type VMessOutboundConfig struct {
Receivers []*VMessOutboundTarget `json:"vnext"`
}
// Build implements Buildable
func (c *VMessOutboundConfig) Build() (proto.Message, error) {
config := new(outbound.Config)
if len(c.Receivers) == 0 {
return nil, newError("0 VMess receiver configured")
}
serverSpecs := make([]*protocol.ServerEndpoint, len(c.Receivers))
for idx, rec := range c.Receivers {
if len(rec.Users) == 0 {
return nil, newError("0 user configured for VMess outbound")
}
if rec.Address == nil {
return nil, newError("address is not set in VMess outbound config")
}
spec := &protocol.ServerEndpoint{
Address: rec.Address.Build(),
Port: uint32(rec.Port),
}
for _, rawUser := range rec.Users {
user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil {
return nil, newError("invalid VMess user").Base(err)
}
account := new(VMessAccount)
if err := json.Unmarshal(rawUser, account); err != nil {
return nil, newError("invalid VMess user").Base(err)
}
user.Account = serial.ToTypedMessage(account.Build())
spec.User = append(spec.User, user)
}
serverSpecs[idx] = spec
}
config.Receiver = serverSpecs
return config, nil
}
v2ray-core-4.34.0/infra/conf/vmess_test.go 0000664 0000000 0000000 00000004544 13774574720 0020371 0 ustar 00root root 0000000 0000000 package conf_test
import (
"testing"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
. "v2ray.com/core/infra/conf"
"v2ray.com/core/proxy/vmess"
"v2ray.com/core/proxy/vmess/inbound"
"v2ray.com/core/proxy/vmess/outbound"
)
func TestVMessOutbound(t *testing.T) {
creator := func() Buildable {
return new(VMessOutboundConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"vnext": [{
"address": "127.0.0.1",
"port": 80,
"users": [
{
"id": "e641f5ad-9397-41e3-bf1a-e8740dfed019",
"email": "love@v2ray.com",
"level": 255
}
]
}]
}`,
Parser: loadJSON(creator),
Output: &outbound.Config{
Receiver: []*protocol.ServerEndpoint{
{
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: 80,
User: []*protocol.User{
{
Email: "love@v2ray.com",
Level: 255,
Account: serial.ToTypedMessage(&vmess.Account{
Id: "e641f5ad-9397-41e3-bf1a-e8740dfed019",
AlterId: 0,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AUTO,
},
}),
},
},
},
},
},
},
})
}
func TestVMessInbound(t *testing.T) {
creator := func() Buildable {
return new(VMessInboundConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"clients": [
{
"id": "27848739-7e62-4138-9fd3-098a63964b6b",
"level": 0,
"alterId": 16,
"email": "love@v2ray.com",
"security": "aes-128-gcm"
}
],
"default": {
"level": 0,
"alterId": 32
},
"detour": {
"to": "tag_to_detour"
},
"disableInsecureEncryption": true
}`,
Parser: loadJSON(creator),
Output: &inbound.Config{
User: []*protocol.User{
{
Level: 0,
Email: "love@v2ray.com",
Account: serial.ToTypedMessage(&vmess.Account{
Id: "27848739-7e62-4138-9fd3-098a63964b6b",
AlterId: 16,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
},
},
Default: &inbound.DefaultConfig{
Level: 0,
AlterId: 32,
},
Detour: &inbound.DetourConfig{
To: "tag_to_detour",
},
SecureEncryptionOnly: true,
},
},
})
}
v2ray-core-4.34.0/infra/control/ 0000775 0000000 0000000 00000000000 13774574720 0016372 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/infra/control/api.go 0000664 0000000 0000000 00000010221 13774574720 0017466 0 ustar 00root root 0000000 0000000 package control
import (
"context"
"errors"
"flag"
"fmt"
"strings"
"time"
"github.com/golang/protobuf/proto"
"google.golang.org/grpc"
logService "v2ray.com/core/app/log/command"
statsService "v2ray.com/core/app/stats/command"
"v2ray.com/core/common"
)
type APICommand struct{}
func (c *APICommand) Name() string {
return "api"
}
func (c *APICommand) Description() Description {
return Description{
Short: "Call V2Ray API",
Usage: []string{
"v2ctl api [--server=127.0.0.1:8080] Service.Method Request",
"Call an API in an V2Ray process.",
"The following methods are currently supported:",
"\tLoggerService.RestartLogger",
"\tStatsService.GetStats",
"\tStatsService.QueryStats",
"API calls in this command have a timeout to the server of 3 seconds.",
"Examples:",
"v2ctl api --server=127.0.0.1:8080 LoggerService.RestartLogger '' ",
"v2ctl api --server=127.0.0.1:8080 StatsService.QueryStats 'pattern: \"\" reset: false'",
"v2ctl api --server=127.0.0.1:8080 StatsService.GetStats 'name: \"inbound>>>statin>>>traffic>>>downlink\" reset: false'",
"v2ctl api --server=127.0.0.1:8080 StatsService.GetSysStats ''",
},
}
}
func (c *APICommand) Execute(args []string) error {
fs := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
serverAddrPtr := fs.String("server", "127.0.0.1:8080", "Server address")
if err := fs.Parse(args); err != nil {
return err
}
unnamedArgs := fs.Args()
if len(unnamedArgs) < 2 {
return newError("service name or request not specified.")
}
service, method := getServiceMethod(unnamedArgs[0])
handler, found := serivceHandlerMap[strings.ToLower(service)]
if !found {
return newError("unknown service: ", service)
}
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
conn, err := grpc.DialContext(ctx, *serverAddrPtr, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
return newError("failed to dial ", *serverAddrPtr).Base(err)
}
defer conn.Close()
response, err := handler(ctx, conn, method, unnamedArgs[1])
if err != nil {
return newError("failed to call service ", unnamedArgs[0]).Base(err)
}
fmt.Println(response)
return nil
}
func getServiceMethod(s string) (string, string) {
ss := strings.Split(s, ".")
service := ss[0]
var method string
if len(ss) > 1 {
method = ss[1]
}
return service, method
}
type serviceHandler func(ctx context.Context, conn *grpc.ClientConn, method string, request string) (string, error)
var serivceHandlerMap = map[string]serviceHandler{
"statsservice": callStatsService,
"loggerservice": callLogService,
}
func callLogService(ctx context.Context, conn *grpc.ClientConn, method string, request string) (string, error) {
client := logService.NewLoggerServiceClient(conn)
switch strings.ToLower(method) {
case "restartlogger":
r := &logService.RestartLoggerRequest{}
if err := proto.UnmarshalText(request, r); err != nil {
return "", err
}
resp, err := client.RestartLogger(ctx, r)
if err != nil {
return "", err
}
return proto.MarshalTextString(resp), nil
default:
return "", errors.New("Unknown method: " + method)
}
}
func callStatsService(ctx context.Context, conn *grpc.ClientConn, method string, request string) (string, error) {
client := statsService.NewStatsServiceClient(conn)
switch strings.ToLower(method) {
case "getstats":
r := &statsService.GetStatsRequest{}
if err := proto.UnmarshalText(request, r); err != nil {
return "", err
}
resp, err := client.GetStats(ctx, r)
if err != nil {
return "", err
}
return proto.MarshalTextString(resp), nil
case "querystats":
r := &statsService.QueryStatsRequest{}
if err := proto.UnmarshalText(request, r); err != nil {
return "", err
}
resp, err := client.QueryStats(ctx, r)
if err != nil {
return "", err
}
return proto.MarshalTextString(resp), nil
case "getsysstats":
// SysStatsRequest is an empty message
r := &statsService.SysStatsRequest{}
resp, err := client.GetSysStats(ctx, r)
if err != nil {
return "", err
}
return proto.MarshalTextString(resp), nil
default:
return "", errors.New("Unknown method: " + method)
}
}
func init() {
common.Must(RegisterCommand(&APICommand{}))
}
v2ray-core-4.34.0/infra/control/cert.go 0000664 0000000 0000000 00000006706 13774574720 0017667 0 ustar 00root root 0000000 0000000 package control
import (
"context"
"crypto/x509"
"encoding/json"
"flag"
"os"
"strings"
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/protocol/tls/cert"
"v2ray.com/core/common/task"
)
type stringList []string
func (l *stringList) String() string {
return "String list"
}
func (l *stringList) Set(v string) error {
if v == "" {
return newError("empty value")
}
*l = append(*l, v)
return nil
}
type jsonCert struct {
Certificate []string `json:"certificate"`
Key []string `json:"key"`
}
type CertificateCommand struct {
}
func (c *CertificateCommand) Name() string {
return "cert"
}
func (c *CertificateCommand) Description() Description {
return Description{
Short: "Generate TLS certificates.",
Usage: []string{
"v2ctl cert [--ca] [--domain=v2ray.com] [--expire=240h]",
"Generate new TLS certificate",
"--ca The new certificate is a CA certificate",
"--domain Common name for the certificate",
"--expire Time until certificate expires. 240h = 10 days.",
},
}
}
func (c *CertificateCommand) printJSON(certificate *cert.Certificate) {
certPEM, keyPEM := certificate.ToPEM()
jCert := &jsonCert{
Certificate: strings.Split(strings.TrimSpace(string(certPEM)), "\n"),
Key: strings.Split(strings.TrimSpace(string(keyPEM)), "\n"),
}
content, err := json.MarshalIndent(jCert, "", " ")
common.Must(err)
os.Stdout.Write(content)
os.Stdout.WriteString("\n")
}
func (c *CertificateCommand) writeFile(content []byte, name string) error {
f, err := os.Create(name)
if err != nil {
return err
}
defer f.Close()
return common.Error2(f.Write(content))
}
func (c *CertificateCommand) printFile(certificate *cert.Certificate, name string) error {
certPEM, keyPEM := certificate.ToPEM()
return task.Run(context.Background(), func() error {
return c.writeFile(certPEM, name+"_cert.pem")
}, func() error {
return c.writeFile(keyPEM, name+"_key.pem")
})
}
func (c *CertificateCommand) Execute(args []string) error {
fs := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
var domainNames stringList
fs.Var(&domainNames, "domain", "Domain name for the certificate")
commonName := fs.String("name", "V2Ray Inc", "The common name of this certificate")
organization := fs.String("org", "V2Ray Inc", "Organization of the certificate")
isCA := fs.Bool("ca", false, "Whether this certificate is a CA")
jsonOutput := fs.Bool("json", true, "Print certificate in JSON format")
fileOutput := fs.String("file", "", "Save certificate in file.")
expire := fs.Duration("expire", time.Hour*24*90 /* 90 days */, "Time until the certificate expires. Default value 3 months.")
if err := fs.Parse(args); err != nil {
return err
}
var opts []cert.Option
if *isCA {
opts = append(opts, cert.Authority(*isCA))
opts = append(opts, cert.KeyUsage(x509.KeyUsageCertSign|x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature))
}
opts = append(opts, cert.NotAfter(time.Now().Add(*expire)))
opts = append(opts, cert.CommonName(*commonName))
if len(domainNames) > 0 {
opts = append(opts, cert.DNSNames(domainNames...))
}
opts = append(opts, cert.Organization(*organization))
cert, err := cert.Generate(nil, opts...)
if err != nil {
return newError("failed to generate TLS certificate").Base(err)
}
if *jsonOutput {
c.printJSON(cert)
}
if len(*fileOutput) > 0 {
if err := c.printFile(cert, *fileOutput); err != nil {
return err
}
}
return nil
}
func init() {
common.Must(RegisterCommand(&CertificateCommand{}))
}
v2ray-core-4.34.0/infra/control/command.go 0000664 0000000 0000000 00000001532 13774574720 0020340 0 ustar 00root root 0000000 0000000 package control
import (
"fmt"
"log"
"os"
"strings"
)
type Description struct {
Short string
Usage []string
}
type Command interface {
Name() string
Description() Description
Execute(args []string) error
}
var (
commandRegistry = make(map[string]Command)
ctllog = log.New(os.Stderr, "v2ctl> ", 0)
)
func RegisterCommand(cmd Command) error {
entry := strings.ToLower(cmd.Name())
if entry == "" {
return newError("empty command name")
}
commandRegistry[entry] = cmd
return nil
}
func GetCommand(name string) Command {
cmd, found := commandRegistry[name]
if !found {
return nil
}
return cmd
}
type hiddenCommand interface {
Hidden() bool
}
func PrintUsage() {
for name, cmd := range commandRegistry {
if _, ok := cmd.(hiddenCommand); ok {
continue
}
fmt.Println(" ", name, "\t\t\t", cmd.Description())
}
}
v2ray-core-4.34.0/infra/control/config.go 0000664 0000000 0000000 00000003450 13774574720 0020170 0 ustar 00root root 0000000 0000000 package control
import (
"bytes"
"io"
"io/ioutil"
"os"
"strings"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common"
"v2ray.com/core/infra/conf"
"v2ray.com/core/infra/conf/serial"
)
// ConfigCommand is the json to pb convert struct
type ConfigCommand struct{}
// Name for cmd usage
func (c *ConfigCommand) Name() string {
return "config"
}
// Description for help usage
func (c *ConfigCommand) Description() Description {
return Description{
Short: "merge multiple json config",
Usage: []string{"v2ctl config config.json c1.json c2.json .json"},
}
}
// Execute real work here.
func (c *ConfigCommand) Execute(args []string) error {
if len(args) < 1 {
return newError("empty config list")
}
conf := &conf.Config{}
for _, arg := range args {
ctllog.Println("Read config: ", arg)
r, err := c.LoadArg(arg)
common.Must(err)
c, err := serial.DecodeJSONConfig(r)
if err != nil {
ctllog.Fatalln(err)
}
conf.Override(c, arg)
}
pbConfig, err := conf.Build()
if err != nil {
return err
}
bytesConfig, err := proto.Marshal(pbConfig)
if err != nil {
return newError("failed to marshal proto config").Base(err)
}
if _, err := os.Stdout.Write(bytesConfig); err != nil {
return newError("failed to write proto config").Base(err)
}
return nil
}
// LoadArg loads one arg, maybe an remote url, or local file path
func (c *ConfigCommand) LoadArg(arg string) (out io.Reader, err error) {
var data []byte
switch {
case strings.HasPrefix(arg, "http://"), strings.HasPrefix(arg, "https://"):
data, err = FetchHTTPContent(arg)
case arg == "stdin:":
data, err = ioutil.ReadAll(os.Stdin)
default:
data, err = ioutil.ReadFile(arg)
}
if err != nil {
return
}
out = bytes.NewBuffer(data)
return
}
func init() {
common.Must(RegisterCommand(&ConfigCommand{}))
}
v2ray-core-4.34.0/infra/control/control.go 0000664 0000000 0000000 00000000114 13774574720 0020375 0 ustar 00root root 0000000 0000000 package control
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/infra/control/errors.generated.go 0000664 0000000 0000000 00000000315 13774574720 0022171 0 ustar 00root root 0000000 0000000 package control
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/infra/control/fetch.go 0000664 0000000 0000000 00000003077 13774574720 0020021 0 ustar 00root root 0000000 0000000 package control
import (
"net/http"
"net/url"
"os"
"strings"
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
)
type FetchCommand struct{}
func (c *FetchCommand) Name() string {
return "fetch"
}
func (c *FetchCommand) Description() Description {
return Description{
Short: "Fetch resources",
Usage: []string{"v2ctl fetch "},
}
}
func (c *FetchCommand) Execute(args []string) error {
if len(args) < 1 {
return newError("empty url")
}
content, err := FetchHTTPContent(args[0])
if err != nil {
return newError("failed to read HTTP response").Base(err)
}
os.Stdout.Write(content)
return nil
}
// FetchHTTPContent dials https for remote content
func FetchHTTPContent(target string) ([]byte, error) {
parsedTarget, err := url.Parse(target)
if err != nil {
return nil, newError("invalid URL: ", target).Base(err)
}
if s := strings.ToLower(parsedTarget.Scheme); s != "http" && s != "https" {
return nil, newError("invalid scheme: ", parsedTarget.Scheme)
}
client := &http.Client{
Timeout: 30 * time.Second,
}
resp, err := client.Do(&http.Request{
Method: "GET",
URL: parsedTarget,
Close: true,
})
if err != nil {
return nil, newError("failed to dial to ", target).Base(err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, newError("unexpected HTTP status code: ", resp.StatusCode)
}
content, err := buf.ReadAllToBytes(resp.Body)
if err != nil {
return nil, newError("failed to read HTTP response").Base(err)
}
return content, nil
}
func init() {
common.Must(RegisterCommand(&FetchCommand{}))
}
v2ray-core-4.34.0/infra/control/love.go 0000664 0000000 0000000 00000003614 13774574720 0017672 0 ustar 00root root 0000000 0000000 package control
import (
"bufio"
"bytes"
"compress/gzip"
"encoding/base64"
"fmt"
"v2ray.com/core/common"
"v2ray.com/core/common/platform"
)
const content = "H4sIAAAAAAAC/4SVMaskNwzH+/kUW6izcSthMGrcqLhVk0rdQS5cSMg7Xu4S0vizB8meZd57M3ta2GHX/ukvyZZmY2ZKDMzCzJyY5yOlxKII1omsf+qkBiiC6WhbYsbkjDAfySQsJqD3jtrD0EBM3sBHzG3kUsrglIQREXonpd47kYIi4AHmgI9Wcq2jlJITC6JZJ+v3ECYzBMAHyYm392yuY4zWsjACmHZSh6l3A0JETzGlWZqDsnArpTg62mhJONhOdO90p97V1BAnteoaOcuummtrrtuERQwUiJwP8a4KGKcyxdOCw1spOY+WHueFqmakAIgUSSuhwKNgobxKXSLbtg6r5cFmBiAeF6yCkYycmv+BiCIiW8ScHa3DgxAuZQbRhFNrLTFo96RBmx9jKWWG5nBsjyJzuIkftUblonppZU5t5LzwIks5L1a4lijagQxLokbIYwxfytNDC+XQqrWW9fzAunhqh5/Tg8PuaMw0d/Tcw3iDO81bHfWM/AnutMh2xqSUntMzd3wHDy9iHMQz8bmUZYvqedTJ5GgOnrNt7FIbSlwXE3wDI19n/KA38MsLaP4l89b5F8AV3ESOMIEhIBgezHBc0H6xV9KbaXwMvPcNvIHcC0C7UPZQx4JVTb35/AneSQq+bAYXsBmY7TCRupF2NTdVm/+ch22xa0pvRERKqt1oxj9DUbXzU84Gvj5hc5a81SlAUwMwgEs4T9+7sg9lb9h+908MWiKV8xtWciVTmnB3tivRjNerfXdxpfEBbq2NUvLMM5R9NLuyQg8nXT0PIh1xPd/wrcV49oJ6zbZaPlj2V87IY9T3F2XCOcW2MbZyZd49H+9m81E1N9SxlU+ff/1y+/f3719vf7788+Ugv/ffbMIH7ZNj0dsT4WMHHwLPu/Rp2O75uh99AK+N2xn7ZHq1OK6gczkN+9ngdOl1Qvki5xwSR8vFX6D+9vXA97B/+fr5rz9u/738uP328urP19vfP759e3n9Xs6jamvqlfJ/AAAA//+YAMZjDgkAAA=="
type LoveCommand struct{}
func (*LoveCommand) Name() string {
return "lovevictoria"
}
func (*LoveCommand) Hidden() bool {
return false
}
func (c *LoveCommand) Description() Description {
return Description{
Short: "",
Usage: []string{""},
}
}
func (*LoveCommand) Execute([]string) error {
c, err := base64.StdEncoding.DecodeString(content)
common.Must(err)
reader, err := gzip.NewReader(bytes.NewBuffer(c))
common.Must(err)
b := make([]byte, 4096)
nBytes, _ := reader.Read(b)
bb := bytes.NewBuffer(b[:nBytes])
scanner := bufio.NewScanner(bb)
for scanner.Scan() {
s := scanner.Text()
fmt.Print(s + platform.LineSeparator())
}
return nil
}
func init() {
common.Must(RegisterCommand(&LoveCommand{}))
}
v2ray-core-4.34.0/infra/control/main/ 0000775 0000000 0000000 00000000000 13774574720 0017316 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/infra/control/main/main.go 0000664 0000000 0000000 00000001660 13774574720 0020574 0 ustar 00root root 0000000 0000000 package main
import (
"flag"
"fmt"
"os"
commlog "v2ray.com/core/common/log"
// _ "v2ray.com/core/infra/conf/command"
"v2ray.com/core/infra/control"
)
func getCommandName() string {
if len(os.Args) > 1 {
return os.Args[1]
}
return ""
}
func main() {
// let the v2ctl prints log at stderr
commlog.RegisterHandler(commlog.NewLogger(commlog.CreateStderrLogWriter()))
name := getCommandName()
cmd := control.GetCommand(name)
if cmd == nil {
fmt.Fprintln(os.Stderr, "Unknown command:", name)
fmt.Fprintln(os.Stderr)
fmt.Println("v2ctl ")
fmt.Println("Available commands:")
control.PrintUsage()
return
}
if err := cmd.Execute(os.Args[2:]); err != nil {
hasError := false
if err != flag.ErrHelp {
fmt.Fprintln(os.Stderr, err.Error())
fmt.Fprintln(os.Stderr)
hasError = true
}
for _, line := range cmd.Description().Usage {
fmt.Println(line)
}
if hasError {
os.Exit(-1)
}
}
}
v2ray-core-4.34.0/infra/control/tlsping.go 0000664 0000000 0000000 00000005115 13774574720 0020403 0 ustar 00root root 0000000 0000000 package control
import (
"crypto/tls"
"crypto/x509"
"flag"
"fmt"
"net"
"v2ray.com/core/common"
)
type TLSPingCommand struct{}
func (c *TLSPingCommand) Name() string {
return "tlsping"
}
func (c *TLSPingCommand) Description() Description {
return Description{
Short: "Ping the domain with TLS handshake",
Usage: []string{"v2ctl tlsping --ip "},
}
}
func printCertificates(certs []*x509.Certificate) {
for _, cert := range certs {
if len(cert.DNSNames) == 0 {
continue
}
fmt.Println("Allowed domains: ", cert.DNSNames)
}
}
func (c *TLSPingCommand) Execute(args []string) error {
fs := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
ipStr := fs.String("ip", "", "IP address of the domain")
if err := fs.Parse(args); err != nil {
return newError("flag parsing").Base(err)
}
if fs.NArg() < 1 {
return newError("domain not specified")
}
domain := fs.Arg(0)
fmt.Println("Tls ping: ", domain)
var ip net.IP
if len(*ipStr) > 0 {
v := net.ParseIP(*ipStr)
if v == nil {
return newError("invalid IP: ", *ipStr)
}
ip = v
} else {
v, err := net.ResolveIPAddr("ip", domain)
if err != nil {
return newError("resolve IP").Base(err)
}
ip = v.IP
}
fmt.Println("Using IP: ", ip.String())
fmt.Println("-------------------")
fmt.Println("Pinging without SNI")
{
tcpConn, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: ip, Port: 443})
if err != nil {
return newError("dial tcp").Base(err)
}
tlsConn := tls.Client(tcpConn, &tls.Config{
InsecureSkipVerify: true,
NextProtos: []string{"http/1.1"},
MaxVersion: tls.VersionTLS12,
MinVersion: tls.VersionTLS12,
})
err = tlsConn.Handshake()
if err != nil {
fmt.Println("Handshake failure: ", err)
} else {
fmt.Println("Handshake succeeded")
printCertificates(tlsConn.ConnectionState().PeerCertificates)
}
tlsConn.Close()
}
fmt.Println("-------------------")
fmt.Println("Pinging with SNI")
{
tcpConn, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: ip, Port: 443})
if err != nil {
return newError("dial tcp").Base(err)
}
tlsConn := tls.Client(tcpConn, &tls.Config{
ServerName: domain,
NextProtos: []string{"http/1.1"},
MaxVersion: tls.VersionTLS12,
MinVersion: tls.VersionTLS12,
})
err = tlsConn.Handshake()
if err != nil {
fmt.Println("handshake failure: ", err)
} else {
fmt.Println("handshake succeeded")
printCertificates(tlsConn.ConnectionState().PeerCertificates)
}
tlsConn.Close()
}
fmt.Println("Tls ping finished")
return nil
}
func init() {
common.Must(RegisterCommand(&TLSPingCommand{}))
}
v2ray-core-4.34.0/infra/control/uuid.go 0000664 0000000 0000000 00000000743 13774574720 0017673 0 ustar 00root root 0000000 0000000 package control
import (
"fmt"
"v2ray.com/core/common"
"v2ray.com/core/common/uuid"
)
type UUIDCommand struct{}
func (c *UUIDCommand) Name() string {
return "uuid"
}
func (c *UUIDCommand) Description() Description {
return Description{
Short: "Generate new UUIDs",
Usage: []string{"v2ctl uuid"},
}
}
func (c *UUIDCommand) Execute([]string) error {
u := uuid.New()
fmt.Println(u.String())
return nil
}
func init() {
common.Must(RegisterCommand(&UUIDCommand{}))
}
v2ray-core-4.34.0/infra/control/verify.go 0000664 0000000 0000000 00000002333 13774574720 0020226 0 ustar 00root root 0000000 0000000 package control
import (
"flag"
"os"
"github.com/v2fly/VSign/signerVerify"
"v2ray.com/core/common"
)
type VerifyCommand struct{}
func (c *VerifyCommand) Name() string {
return "verify"
}
func (c *VerifyCommand) Description() Description {
return Description{
Short: "Verify if a binary is officially signed.",
Usage: []string{
"v2ctl verify --sig= file...",
"Verify the file officially signed by V2Ray.",
},
}
}
func (c *VerifyCommand) Execute(args []string) error {
fs := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
sigFile := fs.String("sig", "", "Path to the signature file")
if err := fs.Parse(args); err != nil {
return err
}
target := fs.Arg(0)
if target == "" {
return newError("empty file path.")
}
if *sigFile == "" {
return newError("empty signature path.")
}
sigReader, err := os.Open(os.ExpandEnv(*sigFile))
if err != nil {
return newError("failed to open file ", *sigFile).Base(err)
}
files := fs.Args()
err = signerVerify.OutputAndJudge(signerVerify.CheckSignaturesV2Fly(sigReader, files))
if err == nil {
return nil
}
return newError("file is not officially signed by V2Ray").Base(err)
}
func init() {
common.Must(RegisterCommand(&VerifyCommand{}))
}
v2ray-core-4.34.0/infra/vprotogen/ 0000775 0000000 0000000 00000000000 13774574720 0016735 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/infra/vprotogen/main.go 0000664 0000000 0000000 00000004226 13774574720 0020214 0 ustar 00root root 0000000 0000000 package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"v2ray.com/core"
"v2ray.com/core/common"
)
func main() {
pwd, wdErr := os.Getwd()
if wdErr != nil {
fmt.Println("Can not get current working directory.")
os.Exit(1)
}
GOBIN := common.GetGOBIN()
binPath := os.Getenv("PATH")
pathSlice := []string{binPath, GOBIN, pwd}
binPath = strings.Join(pathSlice, string(os.PathListSeparator))
os.Setenv("PATH", binPath)
EXE := ""
if runtime.GOOS == "windows" {
EXE = ".exe"
}
protoc := "protoc" + EXE
if path, err := exec.LookPath(protoc); err != nil {
fmt.Println("Make sure that you have `" + protoc + "` in your system path or current path. To download it, please visit https://github.com/protocolbuffers/protobuf/releases")
os.Exit(1)
} else {
protoc = path
}
protoFilesMap := make(map[string][]string)
walkErr := filepath.Walk("./", func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Println(err)
return err
}
if info.IsDir() {
return nil
}
dir := filepath.Dir(path)
filename := filepath.Base(path)
if strings.HasSuffix(filename, ".proto") {
protoFilesMap[dir] = append(protoFilesMap[dir], path)
}
return nil
})
if walkErr != nil {
fmt.Println(walkErr)
os.Exit(1)
}
for _, files := range protoFilesMap {
for _, relProtoFile := range files {
var args []string
if core.ProtoFilesUsingProtocGenGoFast[relProtoFile] {
args = []string{"--gofast_out", pwd, "--gofast_opt", "paths=source_relative", "--plugin", "protoc-gen-gofast=" + GOBIN + "/protoc-gen-gofast" + EXE}
} else {
args = []string{"--go_out", pwd, "--go_opt", "paths=source_relative", "--go-grpc_out", pwd, "--go-grpc_opt", "paths=source_relative", "--plugin", "protoc-gen-go=" + GOBIN + "/protoc-gen-go" + EXE, "--plugin", "protoc-gen-go-grpc=" + GOBIN + "/protoc-gen-go-grpc" + EXE}
}
args = append(args, relProtoFile)
cmd := exec.Command(protoc, args...)
cmd.Env = append(cmd.Env, os.Environ()...)
output, cmdErr := cmd.CombinedOutput()
if len(output) > 0 {
fmt.Println(string(output))
}
if cmdErr != nil {
fmt.Println(cmdErr)
os.Exit(1)
}
}
}
}
v2ray-core-4.34.0/main/ 0000775 0000000 0000000 00000000000 13774574720 0014537 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/main/confloader/ 0000775 0000000 0000000 00000000000 13774574720 0016653 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/main/confloader/confloader.go 0000664 0000000 0000000 00000001632 13774574720 0021320 0 ustar 00root root 0000000 0000000 package confloader
import (
"io"
"os"
)
type configFileLoader func(string) (io.Reader, error)
type extconfigLoader func([]string, io.Reader) (io.Reader, error)
var (
EffectiveConfigFileLoader configFileLoader
EffectiveExtConfigLoader extconfigLoader
)
// LoadConfig reads from a path/url/stdin
// actual work is in external module
func LoadConfig(file string) (io.Reader, error) {
if EffectiveConfigFileLoader == nil {
newError("external config module not loaded, reading from stdin").AtInfo().WriteToLog()
return os.Stdin, nil
}
return EffectiveConfigFileLoader(file)
}
// LoadExtConfig calls v2ctl to handle multiple config
// the actual work also in external module
func LoadExtConfig(files []string, reader io.Reader) (io.Reader, error) {
if EffectiveExtConfigLoader == nil {
return nil, newError("external config module not loaded").AtError()
}
return EffectiveExtConfigLoader(files, reader)
}
v2ray-core-4.34.0/main/confloader/errors.generated.go 0000664 0000000 0000000 00000000320 13774574720 0022446 0 ustar 00root root 0000000 0000000 package confloader
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/main/confloader/external/ 0000775 0000000 0000000 00000000000 13774574720 0020475 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/main/confloader/external/errors.generated.go 0000664 0000000 0000000 00000000316 13774574720 0024275 0 ustar 00root root 0000000 0000000 package external
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/main/confloader/external/external.go 0000664 0000000 0000000 00000003501 13774574720 0022645 0 ustar 00root root 0000000 0000000 package external
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"bytes"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"strings"
"time"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/platform/ctlcmd"
"v2ray.com/core/main/confloader"
)
func ConfigLoader(arg string) (out io.Reader, err error) {
var data []byte
switch {
case strings.HasPrefix(arg, "http://"), strings.HasPrefix(arg, "https://"):
data, err = FetchHTTPContent(arg)
case arg == "stdin:":
data, err = ioutil.ReadAll(os.Stdin)
default:
data, err = ioutil.ReadFile(arg)
}
if err != nil {
return
}
out = bytes.NewBuffer(data)
return
}
func FetchHTTPContent(target string) ([]byte, error) {
parsedTarget, err := url.Parse(target)
if err != nil {
return nil, newError("invalid URL: ", target).Base(err)
}
if s := strings.ToLower(parsedTarget.Scheme); s != "http" && s != "https" {
return nil, newError("invalid scheme: ", parsedTarget.Scheme)
}
client := &http.Client{
Timeout: 30 * time.Second,
}
resp, err := client.Do(&http.Request{
Method: "GET",
URL: parsedTarget,
Close: true,
})
if err != nil {
return nil, newError("failed to dial to ", target).Base(err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, newError("unexpected HTTP status code: ", resp.StatusCode)
}
content, err := buf.ReadAllToBytes(resp.Body)
if err != nil {
return nil, newError("failed to read HTTP response").Base(err)
}
return content, nil
}
func ExtConfigLoader(files []string, reader io.Reader) (io.Reader, error) {
buf, err := ctlcmd.Run(append([]string{"config"}, files...), reader)
if err != nil {
return nil, err
}
return strings.NewReader(buf.String()), nil
}
func init() {
confloader.EffectiveConfigFileLoader = ConfigLoader
confloader.EffectiveExtConfigLoader = ExtConfigLoader
}
v2ray-core-4.34.0/main/distro/ 0000775 0000000 0000000 00000000000 13774574720 0016043 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/main/distro/all/ 0000775 0000000 0000000 00000000000 13774574720 0016613 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/main/distro/all/all.go 0000664 0000000 0000000 00000004366 13774574720 0017723 0 ustar 00root root 0000000 0000000 package all
import (
// The following are necessary as they register handlers in their init functions.
// Required features. Can't remove unless there is replacements.
_ "v2ray.com/core/app/dispatcher"
_ "v2ray.com/core/app/proxyman/inbound"
_ "v2ray.com/core/app/proxyman/outbound"
// Default commander and all its services. This is an optional feature.
_ "v2ray.com/core/app/commander"
_ "v2ray.com/core/app/log/command"
_ "v2ray.com/core/app/proxyman/command"
_ "v2ray.com/core/app/stats/command"
// Other optional features.
_ "v2ray.com/core/app/dns"
_ "v2ray.com/core/app/log"
_ "v2ray.com/core/app/policy"
_ "v2ray.com/core/app/reverse"
_ "v2ray.com/core/app/router"
_ "v2ray.com/core/app/stats"
// Inbound and outbound proxies.
_ "v2ray.com/core/proxy/blackhole"
_ "v2ray.com/core/proxy/dns"
_ "v2ray.com/core/proxy/dokodemo"
_ "v2ray.com/core/proxy/freedom"
_ "v2ray.com/core/proxy/http"
_ "v2ray.com/core/proxy/mtproto"
_ "v2ray.com/core/proxy/shadowsocks"
_ "v2ray.com/core/proxy/socks"
_ "v2ray.com/core/proxy/trojan"
_ "v2ray.com/core/proxy/vless/inbound"
_ "v2ray.com/core/proxy/vless/outbound"
_ "v2ray.com/core/proxy/vmess/inbound"
_ "v2ray.com/core/proxy/vmess/outbound"
// Transports
_ "v2ray.com/core/transport/internet/domainsocket"
_ "v2ray.com/core/transport/internet/http"
_ "v2ray.com/core/transport/internet/kcp"
_ "v2ray.com/core/transport/internet/quic"
_ "v2ray.com/core/transport/internet/tcp"
_ "v2ray.com/core/transport/internet/tls"
_ "v2ray.com/core/transport/internet/udp"
_ "v2ray.com/core/transport/internet/websocket"
// Transport headers
_ "v2ray.com/core/transport/internet/headers/http"
_ "v2ray.com/core/transport/internet/headers/noop"
_ "v2ray.com/core/transport/internet/headers/srtp"
_ "v2ray.com/core/transport/internet/headers/tls"
_ "v2ray.com/core/transport/internet/headers/utp"
_ "v2ray.com/core/transport/internet/headers/wechat"
_ "v2ray.com/core/transport/internet/headers/wireguard"
// JSON config support. Choose only one from the two below.
// The following line loads JSON from v2ctl
// _ "v2ray.com/core/main/json"
// The following line loads JSON internally
_ "v2ray.com/core/main/jsonem"
// Load config from file or http(s)
_ "v2ray.com/core/main/confloader/external"
)
v2ray-core-4.34.0/main/distro/debug/ 0000775 0000000 0000000 00000000000 13774574720 0017131 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/main/distro/debug/debug.go 0000664 0000000 0000000 00000000155 13774574720 0020547 0 ustar 00root root 0000000 0000000 package debug
import (
"net/http"
)
func init() {
go func() {
http.ListenAndServe(":6060", nil)
}()
}
v2ray-core-4.34.0/main/errors.generated.go 0000664 0000000 0000000 00000000312 13774574720 0020333 0 ustar 00root root 0000000 0000000 package main
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/main/json/ 0000775 0000000 0000000 00000000000 13774574720 0015510 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/main/json/config_json.go 0000664 0000000 0000000 00000001741 13774574720 0020340 0 ustar 00root root 0000000 0000000 package json
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"io"
"os"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/cmdarg"
"v2ray.com/core/main/confloader"
)
func init() {
common.Must(core.RegisterConfigLoader(&core.ConfigFormat{
Name: "JSON",
Extension: []string{"json"},
Loader: func(input interface{}) (*core.Config, error) {
switch v := input.(type) {
case cmdarg.Arg:
r, err := confloader.LoadExtConfig(v, os.Stdin)
if err != nil {
return nil, newError("failed to execute v2ctl to convert config file.").Base(err).AtWarning()
}
return core.LoadConfig("protobuf", "", r)
case io.Reader:
r, err := confloader.LoadExtConfig([]string{"stdin:"}, os.Stdin)
if err != nil {
return nil, newError("failed to execute v2ctl to convert config file.").Base(err).AtWarning()
}
return core.LoadConfig("protobuf", "", r)
default:
return nil, newError("unknown type")
}
},
}))
}
v2ray-core-4.34.0/main/json/errors.generated.go 0000664 0000000 0000000 00000000312 13774574720 0021304 0 ustar 00root root 0000000 0000000 package json
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/main/jsonem/ 0000775 0000000 0000000 00000000000 13774574720 0016032 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/main/jsonem/errors.generated.go 0000664 0000000 0000000 00000000314 13774574720 0021630 0 ustar 00root root 0000000 0000000 package jsonem
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/main/jsonem/jsonem.go 0000664 0000000 0000000 00000002051 13774574720 0017652 0 ustar 00root root 0000000 0000000 package jsonem
import (
"io"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/cmdarg"
"v2ray.com/core/infra/conf"
"v2ray.com/core/infra/conf/serial"
"v2ray.com/core/main/confloader"
)
func init() {
common.Must(core.RegisterConfigLoader(&core.ConfigFormat{
Name: "JSON",
Extension: []string{"json"},
Loader: func(input interface{}) (*core.Config, error) {
switch v := input.(type) {
case cmdarg.Arg:
cf := &conf.Config{}
for i, arg := range v {
newError("Reading config: ", arg).AtInfo().WriteToLog()
r, err := confloader.LoadConfig(arg)
common.Must(err)
c, err := serial.DecodeJSONConfig(r)
common.Must(err)
if i == 0 {
// This ensure even if the muti-json parser do not support a setting,
// It is still respected automatically for the first configure file
*cf = *c
continue
}
cf.Override(c, arg)
}
return cf.Build()
case io.Reader:
return serial.LoadJSONConfig(v)
default:
return nil, newError("unknow type")
}
},
}))
}
v2ray-core-4.34.0/main/main.go 0000664 0000000 0000000 00000007240 13774574720 0016015 0 ustar 00root root 0000000 0000000 package main
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"os/signal"
"path"
"path/filepath"
"runtime"
"strings"
"syscall"
"v2ray.com/core"
"v2ray.com/core/common/cmdarg"
"v2ray.com/core/common/platform"
_ "v2ray.com/core/main/distro/all"
)
var (
configFiles cmdarg.Arg // "Config file for V2Ray.", the option is customed type, parse in main
configDir string
version = flag.Bool("version", false, "Show current version of V2Ray.")
test = flag.Bool("test", false, "Test config file only, without launching V2Ray server.")
format = flag.String("format", "json", "Format of input file.")
/* We have to do this here because Golang's Test will also need to parse flag, before
* main func in this file is run.
*/
_ = func() error { // nolint: unparam
flag.Var(&configFiles, "config", "Config file for V2Ray. Multiple assign is accepted (only json). Latter ones overrides the former ones.")
flag.Var(&configFiles, "c", "Short alias of -config")
flag.StringVar(&configDir, "confdir", "", "A dir with multiple json config")
return nil
}()
)
func fileExists(file string) bool {
info, err := os.Stat(file)
return err == nil && !info.IsDir()
}
func dirExists(file string) bool {
if file == "" {
return false
}
info, err := os.Stat(file)
return err == nil && info.IsDir()
}
func readConfDir(dirPath string) {
confs, err := ioutil.ReadDir(dirPath)
if err != nil {
log.Fatalln(err)
}
for _, f := range confs {
if strings.HasSuffix(f.Name(), ".json") {
configFiles.Set(path.Join(dirPath, f.Name()))
}
}
}
func getConfigFilePath() cmdarg.Arg {
if dirExists(configDir) {
log.Println("Using confdir from arg:", configDir)
readConfDir(configDir)
} else if envConfDir := platform.GetConfDirPath(); dirExists(envConfDir) {
log.Println("Using confdir from env:", envConfDir)
readConfDir(envConfDir)
}
if len(configFiles) > 0 {
return configFiles
}
if workingDir, err := os.Getwd(); err == nil {
configFile := filepath.Join(workingDir, "config.json")
if fileExists(configFile) {
log.Println("Using default config: ", configFile)
return cmdarg.Arg{configFile}
}
}
if configFile := platform.GetConfigurationPath(); fileExists(configFile) {
log.Println("Using config from env: ", configFile)
return cmdarg.Arg{configFile}
}
log.Println("Using config from STDIN")
return cmdarg.Arg{"stdin:"}
}
func GetConfigFormat() string {
switch strings.ToLower(*format) {
case "pb", "protobuf":
return "protobuf"
default:
return "json"
}
}
func startV2Ray() (core.Server, error) {
configFiles := getConfigFilePath()
config, err := core.LoadConfig(GetConfigFormat(), configFiles[0], configFiles)
if err != nil {
return nil, newError("failed to read config files: [", configFiles.String(), "]").Base(err)
}
server, err := core.New(config)
if err != nil {
return nil, newError("failed to create server").Base(err)
}
return server, nil
}
func printVersion() {
version := core.VersionStatement()
for _, s := range version {
fmt.Println(s)
}
}
func main() {
flag.Parse()
printVersion()
if *version {
return
}
server, err := startV2Ray()
if err != nil {
fmt.Println(err)
// Configuration error. Exit with a special value to prevent systemd from restarting.
os.Exit(23)
}
if *test {
fmt.Println("Configuration OK.")
os.Exit(0)
}
if err := server.Start(); err != nil {
fmt.Println("Failed to start", err)
os.Exit(-1)
}
defer server.Close()
// Explicitly triggering GC to remove garbage from config loading.
runtime.GC()
{
osSignals := make(chan os.Signal, 1)
signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM)
<-osSignals
}
}
v2ray-core-4.34.0/main/main_test.go 0000664 0000000 0000000 00000000163 13774574720 0017051 0 ustar 00root root 0000000 0000000 // +build coveragemain
package main
import (
"testing"
)
func TestRunMainForCoverage(t *testing.T) {
main()
}
v2ray-core-4.34.0/mocks.go 0000664 0000000 0000000 00000002164 13774574720 0015261 0 ustar 00root root 0000000 0000000 package core
//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/io.go -mock_names Reader=Reader,Writer=Writer io Reader,Writer
//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/log.go -mock_names Handler=LogHandler v2ray.com/core/common/log Handler
//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/mux.go -mock_names ClientWorkerFactory=MuxClientWorkerFactory v2ray.com/core/common/mux ClientWorkerFactory
//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/dns.go -mock_names Client=DNSClient v2ray.com/core/features/dns Client
//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/outbound.go -mock_names Manager=OutboundManager,HandlerSelector=OutboundHandlerSelector v2ray.com/core/features/outbound Manager,HandlerSelector
//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/proxy.go -mock_names Inbound=ProxyInbound,Outbound=ProxyOutbound v2ray.com/core/proxy Inbound,Outbound
v2ray-core-4.34.0/proto.go 0000664 0000000 0000000 00000001034 13774574720 0015303 0 ustar 00root root 0000000 0000000 package core
import "path/filepath"
//go:generate go install -v google.golang.org/protobuf/cmd/protoc-gen-go
//go:generate go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc
//go:generate go install -v github.com/gogo/protobuf/protoc-gen-gofast
//go:generate go run ./infra/vprotogen/main.go
// ProtoFilesUsingProtocGenGoFast is the map of Proto files
// that use `protoc-gen-gofast` to generate pb.go files
var ProtoFilesUsingProtocGenGoFast = map[string]bool{filepath.Join("proxy", "vless", "encoding", "addons.proto"): true}
v2ray-core-4.34.0/proxy/ 0000775 0000000 0000000 00000000000 13774574720 0014774 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/blackhole/ 0000775 0000000 0000000 00000000000 13774574720 0016720 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/blackhole/blackhole.go 0000664 0000000 0000000 00000002257 13774574720 0021201 0 ustar 00root root 0000000 0000000 // +build !confonly
// Package blackhole is an outbound handler that blocks all connections.
package blackhole
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"time"
"v2ray.com/core/common"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
)
// Handler is an outbound connection that silently swallow the entire payload.
type Handler struct {
response ResponseConfig
}
// New creates a new blackhole handler.
func New(ctx context.Context, config *Config) (*Handler, error) {
response, err := config.GetInternalResponse()
if err != nil {
return nil, err
}
return &Handler{
response: response,
}, nil
}
// Process implements OutboundHandler.Dispatch().
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
nBytes := h.response.WriteTo(link.Writer)
if nBytes > 0 {
// Sleep a little here to make sure the response is sent to client.
time.Sleep(time.Second)
}
common.Interrupt(link.Writer)
return nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
}))
}
v2ray-core-4.34.0/proxy/blackhole/blackhole_test.go 0000664 0000000 0000000 00000001476 13774574720 0022242 0 ustar 00root root 0000000 0000000 package blackhole_test
import (
"context"
"testing"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/blackhole"
"v2ray.com/core/transport"
"v2ray.com/core/transport/pipe"
)
func TestBlackholeHTTPResponse(t *testing.T) {
handler, err := blackhole.New(context.Background(), &blackhole.Config{
Response: serial.ToTypedMessage(&blackhole.HTTPResponse{}),
})
common.Must(err)
reader, writer := pipe.New(pipe.WithoutSizeLimit())
var mb buf.MultiBuffer
var rerr error
go func() {
b, e := reader.ReadMultiBuffer()
mb = b
rerr = e
}()
link := transport.Link{
Reader: reader,
Writer: writer,
}
common.Must(handler.Process(context.Background(), &link, nil))
common.Must(rerr)
if mb.IsEmpty() {
t.Error("expect http response, but nothing")
}
}
v2ray-core-4.34.0/proxy/blackhole/config.go 0000664 0000000 0000000 00000002101 13774574720 0020506 0 ustar 00root root 0000000 0000000 package blackhole
import (
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
)
const (
http403response = `HTTP/1.1 403 Forbidden
Connection: close
Cache-Control: max-age=3600, public
Content-Length: 0
`
)
// ResponseConfig is the configuration for blackhole responses.
type ResponseConfig interface {
// WriteTo writes predefined response to the give buffer.
WriteTo(buf.Writer) int32
}
// WriteTo implements ResponseConfig.WriteTo().
func (*NoneResponse) WriteTo(buf.Writer) int32 { return 0 }
// WriteTo implements ResponseConfig.WriteTo().
func (*HTTPResponse) WriteTo(writer buf.Writer) int32 {
b := buf.New()
common.Must2(b.WriteString(http403response))
n := b.Len()
writer.WriteMultiBuffer(buf.MultiBuffer{b})
return n
}
// GetInternalResponse converts response settings from proto to internal data structure.
func (c *Config) GetInternalResponse() (ResponseConfig, error) {
if c.GetResponse() == nil {
return new(NoneResponse), nil
}
config, err := c.GetResponse().GetInstance()
if err != nil {
return nil, err
}
return config.(ResponseConfig), nil
}
v2ray-core-4.34.0/proxy/blackhole/config.pb.go 0000664 0000000 0000000 00000021500 13774574720 0021112 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/blackhole/config.proto
package blackhole
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
serial "v2ray.com/core/common/serial"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type NoneResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *NoneResponse) Reset() {
*x = NoneResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_blackhole_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *NoneResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NoneResponse) ProtoMessage() {}
func (x *NoneResponse) ProtoReflect() protoreflect.Message {
mi := &file_proxy_blackhole_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NoneResponse.ProtoReflect.Descriptor instead.
func (*NoneResponse) Descriptor() ([]byte, []int) {
return file_proxy_blackhole_config_proto_rawDescGZIP(), []int{0}
}
type HTTPResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *HTTPResponse) Reset() {
*x = HTTPResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_blackhole_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *HTTPResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HTTPResponse) ProtoMessage() {}
func (x *HTTPResponse) ProtoReflect() protoreflect.Message {
mi := &file_proxy_blackhole_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HTTPResponse.ProtoReflect.Descriptor instead.
func (*HTTPResponse) Descriptor() ([]byte, []int) {
return file_proxy_blackhole_config_proto_rawDescGZIP(), []int{1}
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Response *serial.TypedMessage `protobuf:"bytes,1,opt,name=response,proto3" json:"response,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_blackhole_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_proxy_blackhole_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_proxy_blackhole_config_proto_rawDescGZIP(), []int{2}
}
func (x *Config) GetResponse() *serial.TypedMessage {
if x != nil {
return x.Response
}
return nil
}
var File_proxy_blackhole_config_proto protoreflect.FileDescriptor
var file_proxy_blackhole_config_proto_rawDesc = []byte{
0x0a, 0x1c, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x68, 0x6f, 0x6c,
0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
0x2e, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x65, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x0e, 0x0a,
0x0c, 0x4e, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0e, 0x0a,
0x0c, 0x48, 0x54, 0x54, 0x50, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4c, 0x0a,
0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x42, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65,
0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x5f, 0x0a, 0x1e, 0x63,
0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x2e, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x65, 0x50, 0x01, 0x5a,
0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x65, 0xaa,
0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f,
0x78, 0x79, 0x2e, 0x42, 0x6c, 0x61, 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x65, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proxy_blackhole_config_proto_rawDescOnce sync.Once
file_proxy_blackhole_config_proto_rawDescData = file_proxy_blackhole_config_proto_rawDesc
)
func file_proxy_blackhole_config_proto_rawDescGZIP() []byte {
file_proxy_blackhole_config_proto_rawDescOnce.Do(func() {
file_proxy_blackhole_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_blackhole_config_proto_rawDescData)
})
return file_proxy_blackhole_config_proto_rawDescData
}
var file_proxy_blackhole_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_proxy_blackhole_config_proto_goTypes = []interface{}{
(*NoneResponse)(nil), // 0: v2ray.core.proxy.blackhole.NoneResponse
(*HTTPResponse)(nil), // 1: v2ray.core.proxy.blackhole.HTTPResponse
(*Config)(nil), // 2: v2ray.core.proxy.blackhole.Config
(*serial.TypedMessage)(nil), // 3: v2ray.core.common.serial.TypedMessage
}
var file_proxy_blackhole_config_proto_depIdxs = []int32{
3, // 0: v2ray.core.proxy.blackhole.Config.response:type_name -> v2ray.core.common.serial.TypedMessage
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_proxy_blackhole_config_proto_init() }
func file_proxy_blackhole_config_proto_init() {
if File_proxy_blackhole_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_blackhole_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NoneResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_blackhole_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*HTTPResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_blackhole_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_blackhole_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_blackhole_config_proto_goTypes,
DependencyIndexes: file_proxy_blackhole_config_proto_depIdxs,
MessageInfos: file_proxy_blackhole_config_proto_msgTypes,
}.Build()
File_proxy_blackhole_config_proto = out.File
file_proxy_blackhole_config_proto_rawDesc = nil
file_proxy_blackhole_config_proto_goTypes = nil
file_proxy_blackhole_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/blackhole/config.proto 0000664 0000000 0000000 00000000652 13774574720 0021255 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.blackhole;
option csharp_namespace = "V2Ray.Core.Proxy.Blackhole";
option go_package = "v2ray.com/core/proxy/blackhole";
option java_package = "com.v2ray.core.proxy.blackhole";
option java_multiple_files = true;
import "common/serial/typed_message.proto";
message NoneResponse {}
message HTTPResponse {}
message Config {
v2ray.core.common.serial.TypedMessage response = 1;
}
v2ray-core-4.34.0/proxy/blackhole/config_test.go 0000664 0000000 0000000 00000001033 13774574720 0021550 0 ustar 00root root 0000000 0000000 package blackhole_test
import (
"bufio"
"net/http"
"testing"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
. "v2ray.com/core/proxy/blackhole"
)
func TestHTTPResponse(t *testing.T) {
buffer := buf.New()
httpResponse := new(HTTPResponse)
httpResponse.WriteTo(buf.NewWriter(buffer))
reader := bufio.NewReader(buffer)
response, err := http.ReadResponse(reader, nil)
common.Must(err)
defer response.Body.Close()
if response.StatusCode != 403 {
t.Error("expected status code 403, but got ", response.StatusCode)
}
}
v2ray-core-4.34.0/proxy/blackhole/errors.generated.go 0000664 0000000 0000000 00000000317 13774574720 0022521 0 ustar 00root root 0000000 0000000 package blackhole
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/dns/ 0000775 0000000 0000000 00000000000 13774574720 0015560 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/dns/config.pb.go 0000664 0000000 0000000 00000013064 13774574720 0017760 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/dns/config.proto
package dns
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
net "v2ray.com/core/common/net"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Server is the DNS server address. If specified, this address overrides the
// original one.
Server *net.Endpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_dns_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_proxy_dns_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_proxy_dns_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetServer() *net.Endpoint {
if x != nil {
return x.Server
}
return nil
}
var File_proxy_dns_config_proto protoreflect.FileDescriptor
var file_proxy_dns_config_proto_rawDesc = []byte{
0x0a, 0x16, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x1c,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x65, 0x73, 0x74, 0x69,
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x41, 0x0a, 0x06,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x37, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45,
0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42,
0x4d, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x18, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x14, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,
0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proxy_dns_config_proto_rawDescOnce sync.Once
file_proxy_dns_config_proto_rawDescData = file_proxy_dns_config_proto_rawDesc
)
func file_proxy_dns_config_proto_rawDescGZIP() []byte {
file_proxy_dns_config_proto_rawDescOnce.Do(func() {
file_proxy_dns_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_dns_config_proto_rawDescData)
})
return file_proxy_dns_config_proto_rawDescData
}
var file_proxy_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_proxy_dns_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: v2ray.core.proxy.dns.Config
(*net.Endpoint)(nil), // 1: v2ray.core.common.net.Endpoint
}
var file_proxy_dns_config_proto_depIdxs = []int32{
1, // 0: v2ray.core.proxy.dns.Config.server:type_name -> v2ray.core.common.net.Endpoint
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_proxy_dns_config_proto_init() }
func file_proxy_dns_config_proto_init() {
if File_proxy_dns_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_dns_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_dns_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_dns_config_proto_goTypes,
DependencyIndexes: file_proxy_dns_config_proto_depIdxs,
MessageInfos: file_proxy_dns_config_proto_msgTypes,
}.Build()
File_proxy_dns_config_proto = out.File
file_proxy_dns_config_proto_rawDesc = nil
file_proxy_dns_config_proto_goTypes = nil
file_proxy_dns_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/dns/config.proto 0000664 0000000 0000000 00000000665 13774574720 0020121 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.dns;
option csharp_namespace = "V2Ray.Core.Proxy.Dns";
option go_package = "v2ray.com/core/proxy/dns";
option java_package = "com.v2ray.core.proxy.dns";
option java_multiple_files = true;
import "common/net/destination.proto";
message Config {
// Server is the DNS server address. If specified, this address overrides the
// original one.
v2ray.core.common.net.Endpoint server = 1;
}
v2ray-core-4.34.0/proxy/dns/dns.go 0000664 0000000 0000000 00000015764 13774574720 0016710 0 ustar 00root root 0000000 0000000 // +build !confonly
package dns
import (
"context"
"io"
"sync"
"golang.org/x/net/dns/dnsmessage"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
dns_proto "v2ray.com/core/common/protocol/dns"
"v2ray.com/core/common/session"
"v2ray.com/core/common/task"
"v2ray.com/core/features/dns"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
)
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
h := new(Handler)
if err := core.RequireFeatures(ctx, func(dnsClient dns.Client) error {
return h.Init(config.(*Config), dnsClient)
}); err != nil {
return nil, err
}
return h, nil
}))
}
type ownLinkVerifier interface {
IsOwnLink(ctx context.Context) bool
}
type Handler struct {
ipv4Lookup dns.IPv4Lookup
ipv6Lookup dns.IPv6Lookup
ownLinkVerifier ownLinkVerifier
server net.Destination
}
func (h *Handler) Init(config *Config, dnsClient dns.Client) error {
ipv4lookup, ok := dnsClient.(dns.IPv4Lookup)
if !ok {
return newError("dns.Client doesn't implement IPv4Lookup")
}
h.ipv4Lookup = ipv4lookup
ipv6lookup, ok := dnsClient.(dns.IPv6Lookup)
if !ok {
return newError("dns.Client doesn't implement IPv6Lookup")
}
h.ipv6Lookup = ipv6lookup
if v, ok := dnsClient.(ownLinkVerifier); ok {
h.ownLinkVerifier = v
}
if config.Server != nil {
h.server = config.Server.AsDestination()
}
return nil
}
func (h *Handler) isOwnLink(ctx context.Context) bool {
return h.ownLinkVerifier != nil && h.ownLinkVerifier.IsOwnLink(ctx)
}
func parseIPQuery(b []byte) (r bool, domain string, id uint16, qType dnsmessage.Type) {
var parser dnsmessage.Parser
header, err := parser.Start(b)
if err != nil {
newError("parser start").Base(err).WriteToLog()
return
}
id = header.ID
q, err := parser.Question()
if err != nil {
newError("question").Base(err).WriteToLog()
return
}
qType = q.Type
if qType != dnsmessage.TypeA && qType != dnsmessage.TypeAAAA {
return
}
domain = q.Name.String()
r = true
return
}
// Process implements proxy.Outbound.
func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.Dialer) error {
outbound := session.OutboundFromContext(ctx)
if outbound == nil || !outbound.Target.IsValid() {
return newError("invalid outbound")
}
srcNetwork := outbound.Target.Network
dest := outbound.Target
if h.server.Network != net.Network_Unknown {
dest.Network = h.server.Network
}
if h.server.Address != nil {
dest.Address = h.server.Address
}
if h.server.Port != 0 {
dest.Port = h.server.Port
}
newError("handling DNS traffic to ", dest).WriteToLog(session.ExportIDToError(ctx))
conn := &outboundConn{
dialer: func() (internet.Connection, error) {
return d.Dial(ctx, dest)
},
connReady: make(chan struct{}, 1),
}
var reader dns_proto.MessageReader
var writer dns_proto.MessageWriter
if srcNetwork == net.Network_TCP {
reader = dns_proto.NewTCPReader(link.Reader)
writer = &dns_proto.TCPWriter{
Writer: link.Writer,
}
} else {
reader = &dns_proto.UDPReader{
Reader: link.Reader,
}
writer = &dns_proto.UDPWriter{
Writer: link.Writer,
}
}
var connReader dns_proto.MessageReader
var connWriter dns_proto.MessageWriter
if dest.Network == net.Network_TCP {
connReader = dns_proto.NewTCPReader(buf.NewReader(conn))
connWriter = &dns_proto.TCPWriter{
Writer: buf.NewWriter(conn),
}
} else {
connReader = &dns_proto.UDPReader{
Reader: buf.NewPacketReader(conn),
}
connWriter = &dns_proto.UDPWriter{
Writer: buf.NewWriter(conn),
}
}
request := func() error {
defer conn.Close()
for {
b, err := reader.ReadMessage()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
if !h.isOwnLink(ctx) {
isIPQuery, domain, id, qType := parseIPQuery(b.Bytes())
if isIPQuery {
go h.handleIPQuery(id, qType, domain, writer)
continue
}
}
if err := connWriter.WriteMessage(b); err != nil {
return err
}
}
}
response := func() error {
for {
b, err := connReader.ReadMessage()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
if err := writer.WriteMessage(b); err != nil {
return err
}
}
}
if err := task.Run(ctx, request, response); err != nil {
return newError("connection ends").Base(err)
}
return nil
}
func (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string, writer dns_proto.MessageWriter) {
var ips []net.IP
var err error
switch qType {
case dnsmessage.TypeA:
ips, err = h.ipv4Lookup.LookupIPv4(domain)
case dnsmessage.TypeAAAA:
ips, err = h.ipv6Lookup.LookupIPv6(domain)
}
rcode := dns.RCodeFromError(err)
if rcode == 0 && len(ips) == 0 && err != dns.ErrEmptyResponse {
newError("ip query").Base(err).WriteToLog()
return
}
b := buf.New()
rawBytes := b.Extend(buf.Size)
builder := dnsmessage.NewBuilder(rawBytes[:0], dnsmessage.Header{
ID: id,
RCode: dnsmessage.RCode(rcode),
RecursionAvailable: true,
RecursionDesired: true,
Response: true,
Authoritative: true,
})
builder.EnableCompression()
common.Must(builder.StartQuestions())
common.Must(builder.Question(dnsmessage.Question{
Name: dnsmessage.MustNewName(domain),
Class: dnsmessage.ClassINET,
Type: qType,
}))
common.Must(builder.StartAnswers())
rHeader := dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName(domain), Class: dnsmessage.ClassINET, TTL: 600}
for _, ip := range ips {
if len(ip) == net.IPv4len {
var r dnsmessage.AResource
copy(r.A[:], ip)
common.Must(builder.AResource(rHeader, r))
} else {
var r dnsmessage.AAAAResource
copy(r.AAAA[:], ip)
common.Must(builder.AAAAResource(rHeader, r))
}
}
msgBytes, err := builder.Finish()
if err != nil {
newError("pack message").Base(err).WriteToLog()
b.Release()
return
}
b.Resize(0, int32(len(msgBytes)))
if err := writer.WriteMessage(b); err != nil {
newError("write IP answer").Base(err).WriteToLog()
}
}
type outboundConn struct {
access sync.Mutex
dialer func() (internet.Connection, error)
conn net.Conn
connReady chan struct{}
}
func (c *outboundConn) dial() error {
conn, err := c.dialer()
if err != nil {
return err
}
c.conn = conn
c.connReady <- struct{}{}
return nil
}
func (c *outboundConn) Write(b []byte) (int, error) {
c.access.Lock()
if c.conn == nil {
if err := c.dial(); err != nil {
c.access.Unlock()
newError("failed to dial outbound connection").Base(err).AtWarning().WriteToLog()
return len(b), nil
}
}
c.access.Unlock()
return c.conn.Write(b)
}
func (c *outboundConn) Read(b []byte) (int, error) {
var conn net.Conn
c.access.Lock()
conn = c.conn
c.access.Unlock()
if conn == nil {
_, open := <-c.connReady
if !open {
return 0, io.EOF
}
conn = c.conn
}
return conn.Read(b)
}
func (c *outboundConn) Close() error {
c.access.Lock()
close(c.connReady)
if c.conn != nil {
c.conn.Close()
}
c.access.Unlock()
return nil
}
v2ray-core-4.34.0/proxy/dns/dns_test.go 0000664 0000000 0000000 00000021556 13774574720 0017743 0 ustar 00root root 0000000 0000000 package dns_test
import (
"strconv"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/miekg/dns"
"v2ray.com/core"
"v2ray.com/core/app/dispatcher"
dnsapp "v2ray.com/core/app/dns"
"v2ray.com/core/app/policy"
"v2ray.com/core/app/proxyman"
_ "v2ray.com/core/app/proxyman/inbound"
_ "v2ray.com/core/app/proxyman/outbound"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/common/serial"
dns_proxy "v2ray.com/core/proxy/dns"
"v2ray.com/core/proxy/dokodemo"
"v2ray.com/core/testing/servers/tcp"
"v2ray.com/core/testing/servers/udp"
)
type staticHandler struct {
}
func (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
ans := new(dns.Msg)
ans.Id = r.Id
var clientIP net.IP
opt := r.IsEdns0()
if opt != nil {
for _, o := range opt.Option {
if o.Option() == dns.EDNS0SUBNET {
subnet := o.(*dns.EDNS0_SUBNET)
clientIP = subnet.Address
}
}
}
for _, q := range r.Question {
switch {
case q.Name == "google.com." && q.Qtype == dns.TypeA:
if clientIP == nil {
rr, _ := dns.NewRR("google.com. IN A 8.8.8.8")
ans.Answer = append(ans.Answer, rr)
} else {
rr, _ := dns.NewRR("google.com. IN A 8.8.4.4")
ans.Answer = append(ans.Answer, rr)
}
case q.Name == "facebook.com." && q.Qtype == dns.TypeA:
rr, _ := dns.NewRR("facebook.com. IN A 9.9.9.9")
ans.Answer = append(ans.Answer, rr)
case q.Name == "ipv6.google.com." && q.Qtype == dns.TypeA:
rr, err := dns.NewRR("ipv6.google.com. IN A 8.8.8.7")
common.Must(err)
ans.Answer = append(ans.Answer, rr)
case q.Name == "ipv6.google.com." && q.Qtype == dns.TypeAAAA:
rr, err := dns.NewRR("ipv6.google.com. IN AAAA 2001:4860:4860::8888")
common.Must(err)
ans.Answer = append(ans.Answer, rr)
case q.Name == "notexist.google.com." && q.Qtype == dns.TypeAAAA:
ans.MsgHdr.Rcode = dns.RcodeNameError
}
}
w.WriteMsg(ans)
}
func TestUDPDNSTunnel(t *testing.T) {
port := udp.PickPort()
dnsServer := dns.Server{
Addr: "127.0.0.1:" + port.String(),
Net: "udp",
Handler: &staticHandler{},
UDPSize: 1200,
}
defer dnsServer.Shutdown()
go dnsServer.ListenAndServe()
time.Sleep(time.Second)
serverPort := udp.PickPort()
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&dnsapp.Config{
NameServers: []*net.Endpoint{
{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
},
}),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(&proxyman.InboundConfig{}),
serial.ToTypedMessage(&policy.Config{}),
},
Inbound: []*core.InboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(port),
Networks: []net.Network{net.Network_UDP},
}),
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort),
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&dns_proxy.Config{}),
},
},
}
v, err := core.New(config)
common.Must(err)
common.Must(v.Start())
defer v.Close()
{
m1 := new(dns.Msg)
m1.Id = dns.Id()
m1.RecursionDesired = true
m1.Question = make([]dns.Question, 1)
m1.Question[0] = dns.Question{Name: "google.com.", Qtype: dns.TypeA, Qclass: dns.ClassINET}
c := new(dns.Client)
in, _, err := c.Exchange(m1, "127.0.0.1:"+strconv.Itoa(int(serverPort)))
common.Must(err)
if len(in.Answer) != 1 {
t.Fatal("len(answer): ", len(in.Answer))
}
rr, ok := in.Answer[0].(*dns.A)
if !ok {
t.Fatal("not A record")
}
if r := cmp.Diff(rr.A[:], net.IP{8, 8, 8, 8}); r != "" {
t.Error(r)
}
}
{
m1 := new(dns.Msg)
m1.Id = dns.Id()
m1.RecursionDesired = true
m1.Question = make([]dns.Question, 1)
m1.Question[0] = dns.Question{Name: "ipv4only.google.com.", Qtype: dns.TypeAAAA, Qclass: dns.ClassINET}
c := new(dns.Client)
c.Timeout = 10 * time.Second
in, _, err := c.Exchange(m1, "127.0.0.1:"+strconv.Itoa(int(serverPort)))
common.Must(err)
if len(in.Answer) != 0 {
t.Fatal("len(answer): ", len(in.Answer))
}
}
{
m1 := new(dns.Msg)
m1.Id = dns.Id()
m1.RecursionDesired = true
m1.Question = make([]dns.Question, 1)
m1.Question[0] = dns.Question{Name: "notexist.google.com.", Qtype: dns.TypeAAAA, Qclass: dns.ClassINET}
c := new(dns.Client)
in, _, err := c.Exchange(m1, "127.0.0.1:"+strconv.Itoa(int(serverPort)))
common.Must(err)
if in.Rcode != dns.RcodeNameError {
t.Error("expected NameError, but got ", in.Rcode)
}
}
}
func TestTCPDNSTunnel(t *testing.T) {
port := udp.PickPort()
dnsServer := dns.Server{
Addr: "127.0.0.1:" + port.String(),
Net: "udp",
Handler: &staticHandler{},
}
defer dnsServer.Shutdown()
go dnsServer.ListenAndServe()
time.Sleep(time.Second)
serverPort := tcp.PickPort()
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&dnsapp.Config{
NameServer: []*dnsapp.NameServer{
{
Address: &net.Endpoint{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
},
},
}),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(&proxyman.InboundConfig{}),
serial.ToTypedMessage(&policy.Config{}),
},
Inbound: []*core.InboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(port),
Networks: []net.Network{net.Network_TCP},
}),
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort),
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&dns_proxy.Config{}),
},
},
}
v, err := core.New(config)
common.Must(err)
common.Must(v.Start())
defer v.Close()
m1 := new(dns.Msg)
m1.Id = dns.Id()
m1.RecursionDesired = true
m1.Question = make([]dns.Question, 1)
m1.Question[0] = dns.Question{Name: "google.com.", Qtype: dns.TypeA, Qclass: dns.ClassINET}
c := &dns.Client{
Net: "tcp",
}
in, _, err := c.Exchange(m1, "127.0.0.1:"+serverPort.String())
common.Must(err)
if len(in.Answer) != 1 {
t.Fatal("len(answer): ", len(in.Answer))
}
rr, ok := in.Answer[0].(*dns.A)
if !ok {
t.Fatal("not A record")
}
if r := cmp.Diff(rr.A[:], net.IP{8, 8, 8, 8}); r != "" {
t.Error(r)
}
}
func TestUDP2TCPDNSTunnel(t *testing.T) {
port := tcp.PickPort()
dnsServer := dns.Server{
Addr: "127.0.0.1:" + port.String(),
Net: "tcp",
Handler: &staticHandler{},
}
defer dnsServer.Shutdown()
go dnsServer.ListenAndServe()
time.Sleep(time.Second)
serverPort := tcp.PickPort()
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&dnsapp.Config{
NameServer: []*dnsapp.NameServer{
{
Address: &net.Endpoint{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
},
},
}),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(&proxyman.InboundConfig{}),
serial.ToTypedMessage(&policy.Config{}),
},
Inbound: []*core.InboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(port),
Networks: []net.Network{net.Network_TCP},
}),
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort),
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&dns_proxy.Config{
Server: &net.Endpoint{
Network: net.Network_TCP,
},
}),
},
},
}
v, err := core.New(config)
common.Must(err)
common.Must(v.Start())
defer v.Close()
m1 := new(dns.Msg)
m1.Id = dns.Id()
m1.RecursionDesired = true
m1.Question = make([]dns.Question, 1)
m1.Question[0] = dns.Question{Name: "google.com.", Qtype: dns.TypeA, Qclass: dns.ClassINET}
c := &dns.Client{
Net: "tcp",
}
in, _, err := c.Exchange(m1, "127.0.0.1:"+serverPort.String())
common.Must(err)
if len(in.Answer) != 1 {
t.Fatal("len(answer): ", len(in.Answer))
}
rr, ok := in.Answer[0].(*dns.A)
if !ok {
t.Fatal("not A record")
}
if r := cmp.Diff(rr.A[:], net.IP{8, 8, 8, 8}); r != "" {
t.Error(r)
}
}
v2ray-core-4.34.0/proxy/dns/errors.generated.go 0000664 0000000 0000000 00000000311 13774574720 0021353 0 ustar 00root root 0000000 0000000 package dns
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/dokodemo/ 0000775 0000000 0000000 00000000000 13774574720 0016575 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/dokodemo/config.go 0000664 0000000 0000000 00000000446 13774574720 0020375 0 ustar 00root root 0000000 0000000 package dokodemo
import (
"v2ray.com/core/common/net"
)
// GetPredefinedAddress returns the defined address from proto config. Null if address is not valid.
func (v *Config) GetPredefinedAddress() net.Address {
addr := v.Address.AsAddress()
if addr == nil {
return nil
}
return addr
}
v2ray-core-4.34.0/proxy/dokodemo/config.pb.go 0000664 0000000 0000000 00000022410 13774574720 0020770 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/dokodemo/config.proto
package dokodemo
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
net "v2ray.com/core/common/net"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
// List of networks that the Dokodemo accepts.
// Deprecated. Use networks.
//
// Deprecated: Do not use.
NetworkList *net.NetworkList `protobuf:"bytes,3,opt,name=network_list,json=networkList,proto3" json:"network_list,omitempty"`
// List of networks that the Dokodemo accepts.
Networks []net.Network `protobuf:"varint,7,rep,packed,name=networks,proto3,enum=v2ray.core.common.net.Network" json:"networks,omitempty"`
// Deprecated: Do not use.
Timeout uint32 `protobuf:"varint,4,opt,name=timeout,proto3" json:"timeout,omitempty"`
FollowRedirect bool `protobuf:"varint,5,opt,name=follow_redirect,json=followRedirect,proto3" json:"follow_redirect,omitempty"`
UserLevel uint32 `protobuf:"varint,6,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_dokodemo_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_proxy_dokodemo_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_proxy_dokodemo_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetAddress() *net.IPOrDomain {
if x != nil {
return x.Address
}
return nil
}
func (x *Config) GetPort() uint32 {
if x != nil {
return x.Port
}
return 0
}
// Deprecated: Do not use.
func (x *Config) GetNetworkList() *net.NetworkList {
if x != nil {
return x.NetworkList
}
return nil
}
func (x *Config) GetNetworks() []net.Network {
if x != nil {
return x.Networks
}
return nil
}
// Deprecated: Do not use.
func (x *Config) GetTimeout() uint32 {
if x != nil {
return x.Timeout
}
return 0
}
func (x *Config) GetFollowRedirect() bool {
if x != nil {
return x.FollowRedirect
}
return false
}
func (x *Config) GetUserLevel() uint32 {
if x != nil {
return x.UserLevel
}
return 0
}
var File_proxy_dokodemo_config_proto protoreflect.FileDescriptor
var file_proxy_dokodemo_config_proto_rawDesc = []byte{
0x0a, 0x1b, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x64, 0x6f, 0x6b, 0x6f, 0x64, 0x65, 0x6d, 0x6f,
0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
0x64, 0x6f, 0x6b, 0x6f, 0x64, 0x65, 0x6d, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e,
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc6, 0x02, 0x0a,
0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,
0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,
0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x07, 0x61, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x49, 0x0a, 0x0c, 0x6e, 0x65, 0x74, 0x77,
0x6f, 0x72, 0x6b, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22,
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69,
0x73, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c,
0x69, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18,
0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65,
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12,
0x1c, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d,
0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x27, 0x0a,
0x0f, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65,
0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c,
0x65, 0x76, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72,
0x4c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x5c, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6f,
0x6b, 0x6f, 0x64, 0x65, 0x6d, 0x6f, 0x50, 0x01, 0x5a, 0x1d, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x64,
0x6f, 0x6b, 0x6f, 0x64, 0x65, 0x6d, 0x6f, 0xaa, 0x02, 0x19, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,
0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x44, 0x6f, 0x6b, 0x6f, 0x64,
0x65, 0x6d, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proxy_dokodemo_config_proto_rawDescOnce sync.Once
file_proxy_dokodemo_config_proto_rawDescData = file_proxy_dokodemo_config_proto_rawDesc
)
func file_proxy_dokodemo_config_proto_rawDescGZIP() []byte {
file_proxy_dokodemo_config_proto_rawDescOnce.Do(func() {
file_proxy_dokodemo_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_dokodemo_config_proto_rawDescData)
})
return file_proxy_dokodemo_config_proto_rawDescData
}
var file_proxy_dokodemo_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_proxy_dokodemo_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: v2ray.core.proxy.dokodemo.Config
(*net.IPOrDomain)(nil), // 1: v2ray.core.common.net.IPOrDomain
(*net.NetworkList)(nil), // 2: v2ray.core.common.net.NetworkList
(net.Network)(0), // 3: v2ray.core.common.net.Network
}
var file_proxy_dokodemo_config_proto_depIdxs = []int32{
1, // 0: v2ray.core.proxy.dokodemo.Config.address:type_name -> v2ray.core.common.net.IPOrDomain
2, // 1: v2ray.core.proxy.dokodemo.Config.network_list:type_name -> v2ray.core.common.net.NetworkList
3, // 2: v2ray.core.proxy.dokodemo.Config.networks:type_name -> v2ray.core.common.net.Network
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_proxy_dokodemo_config_proto_init() }
func file_proxy_dokodemo_config_proto_init() {
if File_proxy_dokodemo_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_dokodemo_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_dokodemo_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_dokodemo_config_proto_goTypes,
DependencyIndexes: file_proxy_dokodemo_config_proto_depIdxs,
MessageInfos: file_proxy_dokodemo_config_proto_msgTypes,
}.Build()
File_proxy_dokodemo_config_proto = out.File
file_proxy_dokodemo_config_proto_rawDesc = nil
file_proxy_dokodemo_config_proto_goTypes = nil
file_proxy_dokodemo_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/dokodemo/config.proto 0000664 0000000 0000000 00000001376 13774574720 0021136 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.dokodemo;
option csharp_namespace = "V2Ray.Core.Proxy.Dokodemo";
option go_package = "v2ray.com/core/proxy/dokodemo";
option java_package = "com.v2ray.core.proxy.dokodemo";
option java_multiple_files = true;
import "common/net/address.proto";
import "common/net/network.proto";
message Config {
v2ray.core.common.net.IPOrDomain address = 1;
uint32 port = 2;
// List of networks that the Dokodemo accepts.
// Deprecated. Use networks.
v2ray.core.common.net.NetworkList network_list = 3 [deprecated = true];
// List of networks that the Dokodemo accepts.
repeated v2ray.core.common.net.Network networks = 7;
uint32 timeout = 4 [deprecated = true];
bool follow_redirect = 5;
uint32 user_level = 6;
}
v2ray-core-4.34.0/proxy/dokodemo/dokodemo.go 0000664 0000000 0000000 00000013233 13774574720 0020727 0 ustar 00root root 0000000 0000000 // +build !confonly
package dokodemo
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"sync/atomic"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/policy"
"v2ray.com/core/features/routing"
"v2ray.com/core/transport/internet"
)
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
d := new(Door)
err := core.RequireFeatures(ctx, func(pm policy.Manager) error {
return d.Init(config.(*Config), pm, session.SockoptFromContext(ctx))
})
return d, err
}))
}
type Door struct {
policyManager policy.Manager
config *Config
address net.Address
port net.Port
sockopt *session.Sockopt
}
// Init initializes the Door instance with necessary parameters.
func (d *Door) Init(config *Config, pm policy.Manager, sockopt *session.Sockopt) error {
if (config.NetworkList == nil || len(config.NetworkList.Network) == 0) && len(config.Networks) == 0 {
return newError("no network specified")
}
d.config = config
d.address = config.GetPredefinedAddress()
d.port = net.Port(config.Port)
d.policyManager = pm
d.sockopt = sockopt
return nil
}
// Network implements proxy.Inbound.
func (d *Door) Network() []net.Network {
if len(d.config.Networks) > 0 {
return d.config.Networks
}
return d.config.NetworkList.Network
}
func (d *Door) policy() policy.Session {
config := d.config
p := d.policyManager.ForLevel(config.UserLevel)
if config.Timeout > 0 && config.UserLevel == 0 {
p.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second
}
return p
}
type hasHandshakeAddress interface {
HandshakeAddress() net.Address
}
// Process implements proxy.Inbound.
func (d *Door) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {
newError("processing connection from: ", conn.RemoteAddr()).AtDebug().WriteToLog(session.ExportIDToError(ctx))
dest := net.Destination{
Network: network,
Address: d.address,
Port: d.port,
}
destinationOverridden := false
if d.config.FollowRedirect {
if outbound := session.OutboundFromContext(ctx); outbound != nil && outbound.Target.IsValid() {
dest = outbound.Target
destinationOverridden = true
} else if handshake, ok := conn.(hasHandshakeAddress); ok {
addr := handshake.HandshakeAddress()
if addr != nil {
dest.Address = addr
destinationOverridden = true
}
}
}
if !dest.IsValid() || dest.Address == nil {
return newError("unable to get destination")
}
if inbound := session.InboundFromContext(ctx); inbound != nil {
inbound.User = &protocol.MemoryUser{
Level: d.config.UserLevel,
}
}
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: conn.RemoteAddr(),
To: dest,
Status: log.AccessAccepted,
Reason: "",
})
newError("received request for ", conn.RemoteAddr()).WriteToLog(session.ExportIDToError(ctx))
plcy := d.policy()
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle)
ctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer)
link, err := dispatcher.Dispatch(ctx, dest)
if err != nil {
return newError("failed to dispatch request").Base(err)
}
requestCount := int32(1)
requestDone := func() error {
defer func() {
if atomic.AddInt32(&requestCount, -1) == 0 {
timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
}
}()
var reader buf.Reader
if dest.Network == net.Network_UDP {
reader = buf.NewPacketReader(conn)
} else {
reader = buf.NewReader(conn)
}
if err := buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport request").Base(err)
}
return nil
}
tproxyRequest := func() error {
return nil
}
var writer buf.Writer
if network == net.Network_TCP {
writer = buf.NewWriter(conn)
} else {
// if we are in TPROXY mode, use linux's udp forging functionality
if !destinationOverridden {
writer = &buf.SequentialWriter{Writer: conn}
} else {
sockopt := &internet.SocketConfig{
Tproxy: internet.SocketConfig_TProxy,
}
if dest.Address.Family().IsIP() {
sockopt.BindAddress = dest.Address.IP()
sockopt.BindPort = uint32(dest.Port)
}
if d.sockopt != nil {
sockopt.Mark = d.sockopt.Mark
}
tConn, err := internet.DialSystem(ctx, net.DestinationFromAddr(conn.RemoteAddr()), sockopt)
if err != nil {
return err
}
defer tConn.Close()
writer = &buf.SequentialWriter{Writer: tConn}
tReader := buf.NewPacketReader(tConn)
requestCount++
tproxyRequest = func() error {
defer func() {
if atomic.AddInt32(&requestCount, -1) == 0 {
timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
}
}()
if err := buf.Copy(tReader, link.Writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport request (TPROXY conn)").Base(err)
}
return nil
}
}
}
responseDone := func() error {
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
if err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport response").Base(err)
}
return nil
}
if err := task.Run(ctx, task.OnSuccess(func() error {
return task.Run(ctx, requestDone, tproxyRequest)
}, task.Close(link.Writer)), responseDone); err != nil {
common.Interrupt(link.Reader)
common.Interrupt(link.Writer)
return newError("connection ends").Base(err)
}
return nil
}
v2ray-core-4.34.0/proxy/dokodemo/errors.generated.go 0000664 0000000 0000000 00000000316 13774574720 0022375 0 ustar 00root root 0000000 0000000 package dokodemo
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/freedom/ 0000775 0000000 0000000 00000000000 13774574720 0016415 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/freedom/config.go 0000664 0000000 0000000 00000000251 13774574720 0020207 0 ustar 00root root 0000000 0000000 package freedom
func (c *Config) useIP() bool {
return c.DomainStrategy == Config_USE_IP || c.DomainStrategy == Config_USE_IP4 || c.DomainStrategy == Config_USE_IP6
}
v2ray-core-4.34.0/proxy/freedom/config.pb.go 0000664 0000000 0000000 00000030142 13774574720 0020611 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/freedom/config.proto
package freedom
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
protocol "v2ray.com/core/common/protocol"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Config_DomainStrategy int32
const (
Config_AS_IS Config_DomainStrategy = 0
Config_USE_IP Config_DomainStrategy = 1
Config_USE_IP4 Config_DomainStrategy = 2
Config_USE_IP6 Config_DomainStrategy = 3
)
// Enum value maps for Config_DomainStrategy.
var (
Config_DomainStrategy_name = map[int32]string{
0: "AS_IS",
1: "USE_IP",
2: "USE_IP4",
3: "USE_IP6",
}
Config_DomainStrategy_value = map[string]int32{
"AS_IS": 0,
"USE_IP": 1,
"USE_IP4": 2,
"USE_IP6": 3,
}
)
func (x Config_DomainStrategy) Enum() *Config_DomainStrategy {
p := new(Config_DomainStrategy)
*p = x
return p
}
func (x Config_DomainStrategy) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Config_DomainStrategy) Descriptor() protoreflect.EnumDescriptor {
return file_proxy_freedom_config_proto_enumTypes[0].Descriptor()
}
func (Config_DomainStrategy) Type() protoreflect.EnumType {
return &file_proxy_freedom_config_proto_enumTypes[0]
}
func (x Config_DomainStrategy) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Config_DomainStrategy.Descriptor instead.
func (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) {
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{1, 0}
}
type DestinationOverride struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Server *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
}
func (x *DestinationOverride) Reset() {
*x = DestinationOverride{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_freedom_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DestinationOverride) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DestinationOverride) ProtoMessage() {}
func (x *DestinationOverride) ProtoReflect() protoreflect.Message {
mi := &file_proxy_freedom_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DestinationOverride.ProtoReflect.Descriptor instead.
func (*DestinationOverride) Descriptor() ([]byte, []int) {
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{0}
}
func (x *DestinationOverride) GetServer() *protocol.ServerEndpoint {
if x != nil {
return x.Server
}
return nil
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
DomainStrategy Config_DomainStrategy `protobuf:"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=v2ray.core.proxy.freedom.Config_DomainStrategy" json:"domain_strategy,omitempty"`
// Deprecated: Do not use.
Timeout uint32 `protobuf:"varint,2,opt,name=timeout,proto3" json:"timeout,omitempty"`
DestinationOverride *DestinationOverride `protobuf:"bytes,3,opt,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
UserLevel uint32 `protobuf:"varint,4,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_freedom_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_proxy_freedom_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{1}
}
func (x *Config) GetDomainStrategy() Config_DomainStrategy {
if x != nil {
return x.DomainStrategy
}
return Config_AS_IS
}
// Deprecated: Do not use.
func (x *Config) GetTimeout() uint32 {
if x != nil {
return x.Timeout
}
return 0
}
func (x *Config) GetDestinationOverride() *DestinationOverride {
if x != nil {
return x.DestinationOverride
}
return nil
}
func (x *Config) GetUserLevel() uint32 {
if x != nil {
return x.UserLevel
}
return 0
}
var File_proxy_freedom_config_proto protoreflect.FileDescriptor
var file_proxy_freedom_config_proto_rawDesc = []byte{
0x0a, 0x1a, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2f,
0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x18, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66,
0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73,
0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x59, 0x0a, 0x13, 0x44, 0x65, 0x73,
0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
0x12, 0x42, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65,
0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x22, 0xc4, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x58, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65,
0x64, 0x6f, 0x6d, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x1c, 0x0a, 0x07, 0x74, 0x69, 0x6d,
0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07,
0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x60, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69,
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d,
0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72,
0x72, 0x69, 0x64, 0x65, 0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65,
0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75,
0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x41, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61,
0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53,
0x5f, 0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10,
0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b,
0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x42, 0x59, 0x0a, 0x1c, 0x63,
0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x50, 0x01, 0x5a, 0x1c, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x2f, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x18, 0x56, 0x32,
0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x46,
0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proxy_freedom_config_proto_rawDescOnce sync.Once
file_proxy_freedom_config_proto_rawDescData = file_proxy_freedom_config_proto_rawDesc
)
func file_proxy_freedom_config_proto_rawDescGZIP() []byte {
file_proxy_freedom_config_proto_rawDescOnce.Do(func() {
file_proxy_freedom_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_freedom_config_proto_rawDescData)
})
return file_proxy_freedom_config_proto_rawDescData
}
var file_proxy_freedom_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_proxy_freedom_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_proxy_freedom_config_proto_goTypes = []interface{}{
(Config_DomainStrategy)(0), // 0: v2ray.core.proxy.freedom.Config.DomainStrategy
(*DestinationOverride)(nil), // 1: v2ray.core.proxy.freedom.DestinationOverride
(*Config)(nil), // 2: v2ray.core.proxy.freedom.Config
(*protocol.ServerEndpoint)(nil), // 3: v2ray.core.common.protocol.ServerEndpoint
}
var file_proxy_freedom_config_proto_depIdxs = []int32{
3, // 0: v2ray.core.proxy.freedom.DestinationOverride.server:type_name -> v2ray.core.common.protocol.ServerEndpoint
0, // 1: v2ray.core.proxy.freedom.Config.domain_strategy:type_name -> v2ray.core.proxy.freedom.Config.DomainStrategy
1, // 2: v2ray.core.proxy.freedom.Config.destination_override:type_name -> v2ray.core.proxy.freedom.DestinationOverride
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_proxy_freedom_config_proto_init() }
func file_proxy_freedom_config_proto_init() {
if File_proxy_freedom_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_freedom_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DestinationOverride); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_freedom_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_freedom_config_proto_rawDesc,
NumEnums: 1,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_freedom_config_proto_goTypes,
DependencyIndexes: file_proxy_freedom_config_proto_depIdxs,
EnumInfos: file_proxy_freedom_config_proto_enumTypes,
MessageInfos: file_proxy_freedom_config_proto_msgTypes,
}.Build()
File_proxy_freedom_config_proto = out.File
file_proxy_freedom_config_proto_rawDesc = nil
file_proxy_freedom_config_proto_goTypes = nil
file_proxy_freedom_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/freedom/config.proto 0000664 0000000 0000000 00000001211 13774574720 0020742 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.freedom;
option csharp_namespace = "V2Ray.Core.Proxy.Freedom";
option go_package = "v2ray.com/core/proxy/freedom";
option java_package = "com.v2ray.core.proxy.freedom";
option java_multiple_files = true;
import "common/protocol/server_spec.proto";
message DestinationOverride {
v2ray.core.common.protocol.ServerEndpoint server = 1;
}
message Config {
enum DomainStrategy {
AS_IS = 0;
USE_IP = 1;
USE_IP4 = 2;
USE_IP6 = 3;
}
DomainStrategy domain_strategy = 1;
uint32 timeout = 2 [deprecated = true];
DestinationOverride destination_override = 3;
uint32 user_level = 4;
}
v2ray-core-4.34.0/proxy/freedom/errors.generated.go 0000664 0000000 0000000 00000000315 13774574720 0022214 0 ustar 00root root 0000000 0000000 package freedom
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/freedom/freedom.go 0000664 0000000 0000000 00000011514 13774574720 0020367 0 ustar 00root root 0000000 0000000 // +build !confonly
package freedom
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/dice"
"v2ray.com/core/common/net"
"v2ray.com/core/common/retry"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/dns"
"v2ray.com/core/features/policy"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
)
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
h := new(Handler)
if err := core.RequireFeatures(ctx, func(pm policy.Manager, d dns.Client) error {
return h.Init(config.(*Config), pm, d)
}); err != nil {
return nil, err
}
return h, nil
}))
}
// Handler handles Freedom connections.
type Handler struct {
policyManager policy.Manager
dns dns.Client
config *Config
}
// Init initializes the Handler with necessary parameters.
func (h *Handler) Init(config *Config, pm policy.Manager, d dns.Client) error {
h.config = config
h.policyManager = pm
h.dns = d
return nil
}
func (h *Handler) policy() policy.Session {
p := h.policyManager.ForLevel(h.config.UserLevel)
if h.config.Timeout > 0 && h.config.UserLevel == 0 {
p.Timeouts.ConnectionIdle = time.Duration(h.config.Timeout) * time.Second
}
return p
}
func (h *Handler) resolveIP(ctx context.Context, domain string, localAddr net.Address) net.Address {
var lookupFunc func(string) ([]net.IP, error) = h.dns.LookupIP
if h.config.DomainStrategy == Config_USE_IP4 || (localAddr != nil && localAddr.Family().IsIPv4()) {
if lookupIPv4, ok := h.dns.(dns.IPv4Lookup); ok {
lookupFunc = lookupIPv4.LookupIPv4
}
} else if h.config.DomainStrategy == Config_USE_IP6 || (localAddr != nil && localAddr.Family().IsIPv6()) {
if lookupIPv6, ok := h.dns.(dns.IPv6Lookup); ok {
lookupFunc = lookupIPv6.LookupIPv6
}
}
ips, err := lookupFunc(domain)
if err != nil {
newError("failed to get IP address for domain ", domain).Base(err).WriteToLog(session.ExportIDToError(ctx))
}
if len(ips) == 0 {
return nil
}
return net.IPAddress(ips[dice.Roll(len(ips))])
}
func isValidAddress(addr *net.IPOrDomain) bool {
if addr == nil {
return false
}
a := addr.AsAddress()
return a != net.AnyIP
}
// Process implements proxy.Outbound.
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
outbound := session.OutboundFromContext(ctx)
if outbound == nil || !outbound.Target.IsValid() {
return newError("target not specified.")
}
destination := outbound.Target
if h.config.DestinationOverride != nil {
server := h.config.DestinationOverride.Server
if isValidAddress(server.Address) {
destination.Address = server.Address.AsAddress()
}
if server.Port != 0 {
destination.Port = net.Port(server.Port)
}
}
newError("opening connection to ", destination).WriteToLog(session.ExportIDToError(ctx))
input := link.Reader
output := link.Writer
var conn internet.Connection
err := retry.ExponentialBackoff(5, 100).On(func() error {
dialDest := destination
if h.config.useIP() && dialDest.Address.Family().IsDomain() {
ip := h.resolveIP(ctx, dialDest.Address.Domain(), dialer.Address())
if ip != nil {
dialDest = net.Destination{
Network: dialDest.Network,
Address: ip,
Port: dialDest.Port,
}
newError("dialing to to ", dialDest).WriteToLog(session.ExportIDToError(ctx))
}
}
rawConn, err := dialer.Dial(ctx, dialDest)
if err != nil {
return err
}
conn = rawConn
return nil
})
if err != nil {
return newError("failed to open connection to ", destination).Base(err)
}
defer conn.Close()
plcy := h.policy()
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle)
requestDone := func() error {
defer timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
var writer buf.Writer
if destination.Network == net.Network_TCP {
writer = buf.NewWriter(conn)
} else {
writer = &buf.SequentialWriter{Writer: conn}
}
if err := buf.Copy(input, writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to process request").Base(err)
}
return nil
}
responseDone := func() error {
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
var reader buf.Reader
if destination.Network == net.Network_TCP {
reader = buf.NewReader(conn)
} else {
reader = buf.NewPacketReader(conn)
}
if err := buf.Copy(reader, output, buf.UpdateActivity(timer)); err != nil {
return newError("failed to process response").Base(err)
}
return nil
}
if err := task.Run(ctx, requestDone, task.OnSuccess(responseDone, task.Close(output))); err != nil {
return newError("connection ends").Base(err)
}
return nil
}
v2ray-core-4.34.0/proxy/http/ 0000775 0000000 0000000 00000000000 13774574720 0015753 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/http/client.go 0000664 0000000 0000000 00000017011 13774574720 0017560 0 ustar 00root root 0000000 0000000 // +build !confonly
package http
import (
"bufio"
"context"
"encoding/base64"
"io"
"net/http"
"net/url"
"sync"
"golang.org/x/net/http2"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/bytespool"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/retry"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/policy"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/tls"
)
type Client struct {
serverPicker protocol.ServerPicker
policyManager policy.Manager
}
type h2Conn struct {
rawConn net.Conn
h2Conn *http2.ClientConn
}
var (
cachedH2Mutex sync.Mutex
cachedH2Conns map[net.Destination]h2Conn
)
// NewClient create a new http client based on the given config.
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
serverList := protocol.NewServerList()
for _, rec := range config.Server {
s, err := protocol.NewServerSpecFromPB(rec)
if err != nil {
return nil, newError("failed to get server spec").Base(err)
}
serverList.AddServer(s)
}
if serverList.Size() == 0 {
return nil, newError("0 target server")
}
v := core.MustFromContext(ctx)
return &Client{
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
}, nil
}
// Process implements proxy.Outbound.Process. We first create a socket tunnel via HTTP CONNECT method, then redirect all inbound traffic to that tunnel.
func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
outbound := session.OutboundFromContext(ctx)
if outbound == nil || !outbound.Target.IsValid() {
return newError("target not specified.")
}
target := outbound.Target
targetAddr := target.NetAddr()
if target.Network == net.Network_UDP {
return newError("UDP is not supported by HTTP outbound")
}
var user *protocol.MemoryUser
var conn internet.Connection
mbuf, _ := link.Reader.ReadMultiBuffer()
len := mbuf.Len()
firstPayload := bytespool.Alloc(len)
mbuf, _ = buf.SplitBytes(mbuf, firstPayload)
firstPayload = firstPayload[:len]
buf.ReleaseMulti(mbuf)
defer bytespool.Free(firstPayload)
if err := retry.ExponentialBackoff(5, 100).On(func() error {
server := c.serverPicker.PickServer()
dest := server.Destination()
user = server.PickUser()
netConn, err := setUpHTTPTunnel(ctx, dest, targetAddr, user, dialer, firstPayload)
if netConn != nil {
if _, ok := netConn.(*http2Conn); !ok {
if _, err := netConn.Write(firstPayload); err != nil {
netConn.Close()
return err
}
}
conn = internet.Connection(netConn)
}
return err
}); err != nil {
return newError("failed to find an available destination").Base(err)
}
defer func() {
if err := conn.Close(); err != nil {
newError("failed to closed connection").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
}()
p := c.policyManager.ForLevel(0)
if user != nil {
p = c.policyManager.ForLevel(user.Level)
}
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, p.Timeouts.ConnectionIdle)
requestFunc := func() error {
defer timer.SetTimeout(p.Timeouts.DownlinkOnly)
return buf.Copy(link.Reader, buf.NewWriter(conn), buf.UpdateActivity(timer))
}
responseFunc := func() error {
defer timer.SetTimeout(p.Timeouts.UplinkOnly)
return buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer))
}
var responseDonePost = task.OnSuccess(responseFunc, task.Close(link.Writer))
if err := task.Run(ctx, requestFunc, responseDonePost); err != nil {
return newError("connection ends").Base(err)
}
return nil
}
// setUpHTTPTunnel will create a socket tunnel via HTTP CONNECT method
func setUpHTTPTunnel(ctx context.Context, dest net.Destination, target string, user *protocol.MemoryUser, dialer internet.Dialer, firstPayload []byte) (net.Conn, error) {
req := &http.Request{
Method: http.MethodConnect,
URL: &url.URL{Host: target},
Header: make(http.Header),
Host: target,
}
if user != nil && user.Account != nil {
account := user.Account.(*Account)
auth := account.GetUsername() + ":" + account.GetPassword()
req.Header.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth)))
}
connectHTTP1 := func(rawConn net.Conn) (net.Conn, error) {
req.Header.Set("Proxy-Connection", "Keep-Alive")
err := req.Write(rawConn)
if err != nil {
rawConn.Close()
return nil, err
}
resp, err := http.ReadResponse(bufio.NewReader(rawConn), req)
if err != nil {
rawConn.Close()
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
rawConn.Close()
return nil, newError("Proxy responded with non 200 code: " + resp.Status)
}
return rawConn, nil
}
connectHTTP2 := func(rawConn net.Conn, h2clientConn *http2.ClientConn) (net.Conn, error) {
pr, pw := io.Pipe()
req.Body = pr
var pErr error
var wg sync.WaitGroup
wg.Add(1)
go func() {
_, pErr = pw.Write(firstPayload)
wg.Done()
}()
resp, err := h2clientConn.RoundTrip(req) // nolint: bodyclose
if err != nil {
rawConn.Close()
return nil, err
}
wg.Wait()
if pErr != nil {
rawConn.Close()
return nil, pErr
}
if resp.StatusCode != http.StatusOK {
rawConn.Close()
return nil, newError("Proxy responded with non 200 code: " + resp.Status)
}
return newHTTP2Conn(rawConn, pw, resp.Body), nil
}
cachedH2Mutex.Lock()
cachedConn, cachedConnFound := cachedH2Conns[dest]
cachedH2Mutex.Unlock()
if cachedConnFound {
rc, cc := cachedConn.rawConn, cachedConn.h2Conn
if cc.CanTakeNewRequest() {
proxyConn, err := connectHTTP2(rc, cc)
if err != nil {
return nil, err
}
return proxyConn, nil
}
}
rawConn, err := dialer.Dial(ctx, dest)
if err != nil {
return nil, err
}
iConn := rawConn
if statConn, ok := iConn.(*internet.StatCouterConnection); ok {
iConn = statConn.Connection
}
nextProto := ""
if tlsConn, ok := iConn.(*tls.Conn); ok {
if err := tlsConn.Handshake(); err != nil {
rawConn.Close()
return nil, err
}
nextProto = tlsConn.ConnectionState().NegotiatedProtocol
}
switch nextProto {
case "", "http/1.1":
return connectHTTP1(rawConn)
case "h2":
t := http2.Transport{}
h2clientConn, err := t.NewClientConn(rawConn)
if err != nil {
rawConn.Close()
return nil, err
}
proxyConn, err := connectHTTP2(rawConn, h2clientConn)
if err != nil {
rawConn.Close()
return nil, err
}
cachedH2Mutex.Lock()
if cachedH2Conns == nil {
cachedH2Conns = make(map[net.Destination]h2Conn)
}
cachedH2Conns[dest] = h2Conn{
rawConn: rawConn,
h2Conn: h2clientConn,
}
cachedH2Mutex.Unlock()
return proxyConn, err
default:
return nil, newError("negotiated unsupported application layer protocol: " + nextProto)
}
}
func newHTTP2Conn(c net.Conn, pipedReqBody *io.PipeWriter, respBody io.ReadCloser) net.Conn {
return &http2Conn{Conn: c, in: pipedReqBody, out: respBody}
}
type http2Conn struct {
net.Conn
in *io.PipeWriter
out io.ReadCloser
}
func (h *http2Conn) Read(p []byte) (n int, err error) {
return h.out.Read(p)
}
func (h *http2Conn) Write(p []byte) (n int, err error) {
return h.in.Write(p)
}
func (h *http2Conn) Close() error {
h.in.Close()
return h.out.Close()
}
func init() {
common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewClient(ctx, config.(*ClientConfig))
}))
}
v2ray-core-4.34.0/proxy/http/config.go 0000664 0000000 0000000 00000000765 13774574720 0017557 0 ustar 00root root 0000000 0000000 package http
import (
"v2ray.com/core/common/protocol"
)
func (a *Account) Equals(another protocol.Account) bool {
if account, ok := another.(*Account); ok {
return a.Username == account.Username
}
return false
}
func (a *Account) AsAccount() (protocol.Account, error) {
return a, nil
}
func (sc *ServerConfig) HasAccount(username, password string) bool {
if sc.Accounts == nil {
return false
}
p, found := sc.Accounts[username]
if !found {
return false
}
return p == password
}
v2ray-core-4.34.0/proxy/http/config.pb.go 0000664 0000000 0000000 00000030041 13774574720 0020145 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/http/config.proto
package http
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
protocol "v2ray.com/core/common/protocol"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Account struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
}
func (x *Account) Reset() {
*x = Account{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_http_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Account) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Account) ProtoMessage() {}
func (x *Account) ProtoReflect() protoreflect.Message {
mi := &file_proxy_http_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Account.ProtoReflect.Descriptor instead.
func (*Account) Descriptor() ([]byte, []int) {
return file_proxy_http_config_proto_rawDescGZIP(), []int{0}
}
func (x *Account) GetUsername() string {
if x != nil {
return x.Username
}
return ""
}
func (x *Account) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
// Config for HTTP proxy server.
type ServerConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Deprecated: Do not use.
Timeout uint32 `protobuf:"varint,1,opt,name=timeout,proto3" json:"timeout,omitempty"`
Accounts map[string]string `protobuf:"bytes,2,rep,name=accounts,proto3" json:"accounts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
AllowTransparent bool `protobuf:"varint,3,opt,name=allow_transparent,json=allowTransparent,proto3" json:"allow_transparent,omitempty"`
UserLevel uint32 `protobuf:"varint,4,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
}
func (x *ServerConfig) Reset() {
*x = ServerConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_http_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServerConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServerConfig) ProtoMessage() {}
func (x *ServerConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_http_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServerConfig.ProtoReflect.Descriptor instead.
func (*ServerConfig) Descriptor() ([]byte, []int) {
return file_proxy_http_config_proto_rawDescGZIP(), []int{1}
}
// Deprecated: Do not use.
func (x *ServerConfig) GetTimeout() uint32 {
if x != nil {
return x.Timeout
}
return 0
}
func (x *ServerConfig) GetAccounts() map[string]string {
if x != nil {
return x.Accounts
}
return nil
}
func (x *ServerConfig) GetAllowTransparent() bool {
if x != nil {
return x.AllowTransparent
}
return false
}
func (x *ServerConfig) GetUserLevel() uint32 {
if x != nil {
return x.UserLevel
}
return 0
}
// ClientConfig is the protobuf config for HTTP proxy client.
type ClientConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Sever is a list of HTTP server addresses.
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"`
}
func (x *ClientConfig) Reset() {
*x = ClientConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_http_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ClientConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientConfig) ProtoMessage() {}
func (x *ClientConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_http_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead.
func (*ClientConfig) Descriptor() ([]byte, []int) {
return file_proxy_http_config_proto_rawDescGZIP(), []int{2}
}
func (x *ClientConfig) GetServer() []*protocol.ServerEndpoint {
if x != nil {
return x.Server
}
return nil
}
var File_proxy_http_config_proto protoreflect.FileDescriptor
var file_proxy_http_config_proto_rawDesc = []byte{
0x0a, 0x17, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x68, 0x74, 0x74, 0x70,
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0x41, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a,
0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61,
0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61,
0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x84, 0x02, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65,
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f,
0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x74, 0x69,
0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x4d, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x2e,
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x41, 0x63, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x61, 0x63, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x74, 0x72,
0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,
0x10, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e,
0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18,
0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c,
0x1a, 0x3b, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x52, 0x0a,
0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x42, 0x0a,
0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65,
0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x50, 0x01,
0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65,
0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x68, 0x74, 0x74, 0x70, 0xaa, 0x02, 0x15, 0x56, 0x32,
0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x48,
0x74, 0x74, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proxy_http_config_proto_rawDescOnce sync.Once
file_proxy_http_config_proto_rawDescData = file_proxy_http_config_proto_rawDesc
)
func file_proxy_http_config_proto_rawDescGZIP() []byte {
file_proxy_http_config_proto_rawDescOnce.Do(func() {
file_proxy_http_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_http_config_proto_rawDescData)
})
return file_proxy_http_config_proto_rawDescData
}
var file_proxy_http_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_proxy_http_config_proto_goTypes = []interface{}{
(*Account)(nil), // 0: v2ray.core.proxy.http.Account
(*ServerConfig)(nil), // 1: v2ray.core.proxy.http.ServerConfig
(*ClientConfig)(nil), // 2: v2ray.core.proxy.http.ClientConfig
nil, // 3: v2ray.core.proxy.http.ServerConfig.AccountsEntry
(*protocol.ServerEndpoint)(nil), // 4: v2ray.core.common.protocol.ServerEndpoint
}
var file_proxy_http_config_proto_depIdxs = []int32{
3, // 0: v2ray.core.proxy.http.ServerConfig.accounts:type_name -> v2ray.core.proxy.http.ServerConfig.AccountsEntry
4, // 1: v2ray.core.proxy.http.ClientConfig.server:type_name -> v2ray.core.common.protocol.ServerEndpoint
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_proxy_http_config_proto_init() }
func file_proxy_http_config_proto_init() {
if File_proxy_http_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_http_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Account); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_http_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ServerConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_http_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ClientConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_http_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_http_config_proto_goTypes,
DependencyIndexes: file_proxy_http_config_proto_depIdxs,
MessageInfos: file_proxy_http_config_proto_msgTypes,
}.Build()
File_proxy_http_config_proto = out.File
file_proxy_http_config_proto_rawDesc = nil
file_proxy_http_config_proto_goTypes = nil
file_proxy_http_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/http/config.proto 0000664 0000000 0000000 00000001345 13774574720 0020310 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.http;
option csharp_namespace = "V2Ray.Core.Proxy.Http";
option go_package = "v2ray.com/core/proxy/http";
option java_package = "com.v2ray.core.proxy.http";
option java_multiple_files = true;
import "common/protocol/server_spec.proto";
message Account {
string username = 1;
string password = 2;
}
// Config for HTTP proxy server.
message ServerConfig {
uint32 timeout = 1 [deprecated = true];
map accounts = 2;
bool allow_transparent = 3;
uint32 user_level = 4;
}
// ClientConfig is the protobuf config for HTTP proxy client.
message ClientConfig {
// Sever is a list of HTTP server addresses.
repeated v2ray.core.common.protocol.ServerEndpoint server = 1;
}
v2ray-core-4.34.0/proxy/http/errors.generated.go 0000664 0000000 0000000 00000000312 13774574720 0021547 0 ustar 00root root 0000000 0000000 package http
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/http/http.go 0000664 0000000 0000000 00000000111 13774574720 0017252 0 ustar 00root root 0000000 0000000 package http
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/proxy/http/server.go 0000664 0000000 0000000 00000022160 13774574720 0017611 0 ustar 00root root 0000000 0000000 // +build !confonly
package http
import (
"bufio"
"context"
"encoding/base64"
"io"
"net/http"
"strings"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
http_proto "v2ray.com/core/common/protocol/http"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/policy"
"v2ray.com/core/features/routing"
"v2ray.com/core/transport/internet"
)
// Server is an HTTP proxy server.
type Server struct {
config *ServerConfig
policyManager policy.Manager
}
// NewServer creates a new HTTP inbound handler.
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
v := core.MustFromContext(ctx)
s := &Server{
config: config,
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
}
return s, nil
}
func (s *Server) policy() policy.Session {
config := s.config
p := s.policyManager.ForLevel(config.UserLevel)
if config.Timeout > 0 && config.UserLevel == 0 {
p.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second
}
return p
}
// Network implements proxy.Inbound.
func (*Server) Network() []net.Network {
return []net.Network{net.Network_TCP, net.Network_UNIX}
}
func isTimeout(err error) bool {
nerr, ok := errors.Cause(err).(net.Error)
return ok && nerr.Timeout()
}
func parseBasicAuth(auth string) (username, password string, ok bool) {
const prefix = "Basic "
if !strings.HasPrefix(auth, prefix) {
return
}
c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
if err != nil {
return
}
cs := string(c)
s := strings.IndexByte(cs, ':')
if s < 0 {
return
}
return cs[:s], cs[s+1:], true
}
type readerOnly struct {
io.Reader
}
func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {
inbound := session.InboundFromContext(ctx)
if inbound != nil {
inbound.User = &protocol.MemoryUser{
Level: s.config.UserLevel,
}
}
reader := bufio.NewReaderSize(readerOnly{conn}, buf.Size)
Start:
if err := conn.SetReadDeadline(time.Now().Add(s.policy().Timeouts.Handshake)); err != nil {
newError("failed to set read deadline").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
request, err := http.ReadRequest(reader)
if err != nil {
trace := newError("failed to read http request").Base(err)
if errors.Cause(err) != io.EOF && !isTimeout(errors.Cause(err)) {
trace.AtWarning()
}
return trace
}
if len(s.config.Accounts) > 0 {
user, pass, ok := parseBasicAuth(request.Header.Get("Proxy-Authorization"))
if !ok || !s.config.HasAccount(user, pass) {
return common.Error2(conn.Write([]byte("HTTP/1.1 407 Proxy Authentication Required\r\nProxy-Authenticate: Basic realm=\"proxy\"\r\n\r\n")))
}
if inbound != nil {
inbound.User.Email = user
}
}
newError("request to Method [", request.Method, "] Host [", request.Host, "] with URL [", request.URL, "]").WriteToLog(session.ExportIDToError(ctx))
if err := conn.SetReadDeadline(time.Time{}); err != nil {
newError("failed to clear read deadline").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
defaultPort := net.Port(80)
if strings.EqualFold(request.URL.Scheme, "https") {
defaultPort = net.Port(443)
}
host := request.Host
if host == "" {
host = request.URL.Host
}
dest, err := http_proto.ParseHost(host, defaultPort)
if err != nil {
return newError("malformed proxy host: ", host).AtWarning().Base(err)
}
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: conn.RemoteAddr(),
To: request.URL,
Status: log.AccessAccepted,
Reason: "",
})
if strings.EqualFold(request.Method, "CONNECT") {
return s.handleConnect(ctx, request, reader, conn, dest, dispatcher)
}
keepAlive := (strings.TrimSpace(strings.ToLower(request.Header.Get("Proxy-Connection"))) == "keep-alive")
err = s.handlePlainHTTP(ctx, request, conn, dest, dispatcher)
if err == errWaitAnother {
if keepAlive {
goto Start
}
err = nil
}
return err
}
func (s *Server) handleConnect(ctx context.Context, _ *http.Request, reader *bufio.Reader, conn internet.Connection, dest net.Destination, dispatcher routing.Dispatcher) error {
_, err := conn.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n"))
if err != nil {
return newError("failed to write back OK response").Base(err)
}
plcy := s.policy()
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle)
ctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer)
link, err := dispatcher.Dispatch(ctx, dest)
if err != nil {
return err
}
if reader.Buffered() > 0 {
payload, err := buf.ReadFrom(io.LimitReader(reader, int64(reader.Buffered())))
if err != nil {
return err
}
if err := link.Writer.WriteMultiBuffer(payload); err != nil {
return err
}
reader = nil
}
requestDone := func() error {
defer timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
return buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer))
}
responseDone := func() error {
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
v2writer := buf.NewWriter(conn)
if err := buf.Copy(link.Reader, v2writer, buf.UpdateActivity(timer)); err != nil {
return err
}
return nil
}
var closeWriter = task.OnSuccess(requestDone, task.Close(link.Writer))
if err := task.Run(ctx, closeWriter, responseDone); err != nil {
common.Interrupt(link.Reader)
common.Interrupt(link.Writer)
return newError("connection ends").Base(err)
}
return nil
}
var errWaitAnother = newError("keep alive")
func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, writer io.Writer, dest net.Destination, dispatcher routing.Dispatcher) error {
if !s.config.AllowTransparent && request.URL.Host == "" {
// RFC 2068 (HTTP/1.1) requires URL to be absolute URL in HTTP proxy.
response := &http.Response{
Status: "Bad Request",
StatusCode: 400,
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: http.Header(make(map[string][]string)),
Body: nil,
ContentLength: 0,
Close: true,
}
response.Header.Set("Proxy-Connection", "close")
response.Header.Set("Connection", "close")
return response.Write(writer)
}
if len(request.URL.Host) > 0 {
request.Host = request.URL.Host
}
http_proto.RemoveHopByHopHeaders(request.Header)
// Prevent UA from being set to golang's default ones
if request.Header.Get("User-Agent") == "" {
request.Header.Set("User-Agent", "")
}
content := &session.Content{
Protocol: "http/1.1",
}
content.SetAttribute(":method", strings.ToUpper(request.Method))
content.SetAttribute(":path", request.URL.Path)
for key := range request.Header {
value := request.Header.Get(key)
content.SetAttribute(strings.ToLower(key), value)
}
ctx = session.ContextWithContent(ctx, content)
link, err := dispatcher.Dispatch(ctx, dest)
if err != nil {
return err
}
// Plain HTTP request is not a stream. The request always finishes before response. Hense request has to be closed later.
defer common.Close(link.Writer)
var result error = errWaitAnother
requestDone := func() error {
request.Header.Set("Connection", "close")
requestWriter := buf.NewBufferedWriter(link.Writer)
common.Must(requestWriter.SetBuffered(false))
if err := request.Write(requestWriter); err != nil {
return newError("failed to write whole request").Base(err).AtWarning()
}
return nil
}
responseDone := func() error {
responseReader := bufio.NewReaderSize(&buf.BufferedReader{Reader: link.Reader}, buf.Size)
response, err := http.ReadResponse(responseReader, request)
if err == nil {
http_proto.RemoveHopByHopHeaders(response.Header)
if response.ContentLength >= 0 {
response.Header.Set("Proxy-Connection", "keep-alive")
response.Header.Set("Connection", "keep-alive")
response.Header.Set("Keep-Alive", "timeout=4")
response.Close = false
} else {
response.Close = true
result = nil
}
defer response.Body.Close()
} else {
newError("failed to read response from ", request.Host).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))
response = &http.Response{
Status: "Service Unavailable",
StatusCode: 503,
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: http.Header(make(map[string][]string)),
Body: nil,
ContentLength: 0,
Close: true,
}
response.Header.Set("Connection", "close")
response.Header.Set("Proxy-Connection", "close")
}
if err := response.Write(writer); err != nil {
return newError("failed to write response").Base(err).AtWarning()
}
return nil
}
if err := task.Run(ctx, requestDone, responseDone); err != nil {
common.Interrupt(link.Reader)
common.Interrupt(link.Writer)
return newError("connection ends").Base(err)
}
return result
}
func init() {
common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewServer(ctx, config.(*ServerConfig))
}))
}
v2ray-core-4.34.0/proxy/mtproto/ 0000775 0000000 0000000 00000000000 13774574720 0016500 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/mtproto/auth.go 0000664 0000000 0000000 00000006430 13774574720 0017773 0 ustar 00root root 0000000 0000000 package mtproto
import (
"context"
"crypto/rand"
"crypto/sha256"
"io"
"sync"
"v2ray.com/core/common"
)
const (
HeaderSize = 64
)
type SessionContext struct {
ConnectionType [4]byte
DataCenterID uint16
}
func DefaultSessionContext() SessionContext {
return SessionContext{
ConnectionType: [4]byte{0xef, 0xef, 0xef, 0xef},
DataCenterID: 0,
}
}
type contextKey int32
const (
sessionContextKey contextKey = iota
)
func ContextWithSessionContext(ctx context.Context, c SessionContext) context.Context {
return context.WithValue(ctx, sessionContextKey, c)
}
func SessionContextFromContext(ctx context.Context) SessionContext {
if c := ctx.Value(sessionContextKey); c != nil {
return c.(SessionContext)
}
return DefaultSessionContext()
}
type Authentication struct {
Header [HeaderSize]byte
DecodingKey [32]byte
EncodingKey [32]byte
DecodingNonce [16]byte
EncodingNonce [16]byte
}
func (a *Authentication) DataCenterID() uint16 {
x := ((int16(a.Header[61]) << 8) | int16(a.Header[60]))
if x < 0 {
x = -x
}
return uint16(x) - 1
}
func (a *Authentication) ConnectionType() [4]byte {
var x [4]byte
copy(x[:], a.Header[56:60])
return x
}
func (a *Authentication) ApplySecret(b []byte) {
a.DecodingKey = sha256.Sum256(append(a.DecodingKey[:], b...))
a.EncodingKey = sha256.Sum256(append(a.EncodingKey[:], b...))
}
func generateRandomBytes(random []byte, connType [4]byte) {
for {
common.Must2(rand.Read(random))
if random[0] == 0xef {
continue
}
val := (uint32(random[3]) << 24) | (uint32(random[2]) << 16) | (uint32(random[1]) << 8) | uint32(random[0])
if val == 0x44414548 || val == 0x54534f50 || val == 0x20544547 || val == 0x4954504f || val == 0xeeeeeeee {
continue
}
if (uint32(random[7])<<24)|(uint32(random[6])<<16)|(uint32(random[5])<<8)|uint32(random[4]) == 0x00000000 {
continue
}
copy(random[56:60], connType[:])
return
}
}
func NewAuthentication(sc SessionContext) *Authentication {
auth := getAuthenticationObject()
random := auth.Header[:]
generateRandomBytes(random, sc.ConnectionType)
copy(auth.EncodingKey[:], random[8:])
copy(auth.EncodingNonce[:], random[8+32:])
keyivInverse := Inverse(random[8 : 8+32+16])
copy(auth.DecodingKey[:], keyivInverse)
copy(auth.DecodingNonce[:], keyivInverse[32:])
return auth
}
func ReadAuthentication(reader io.Reader) (*Authentication, error) {
auth := getAuthenticationObject()
if _, err := io.ReadFull(reader, auth.Header[:]); err != nil {
putAuthenticationObject(auth)
return nil, err
}
copy(auth.DecodingKey[:], auth.Header[8:])
copy(auth.DecodingNonce[:], auth.Header[8+32:])
keyivInverse := Inverse(auth.Header[8 : 8+32+16])
copy(auth.EncodingKey[:], keyivInverse)
copy(auth.EncodingNonce[:], keyivInverse[32:])
return auth, nil
}
// Inverse returns a new byte array. It is a sequence of bytes when the input is read from end to beginning.Inverse
// Visible for testing only.
func Inverse(b []byte) []byte {
lenb := len(b)
b2 := make([]byte, lenb)
for i, v := range b {
b2[lenb-i-1] = v
}
return b2
}
var (
authPool = sync.Pool{
New: func() interface{} {
return new(Authentication)
},
}
)
func getAuthenticationObject() *Authentication {
return authPool.Get().(*Authentication)
}
func putAuthenticationObject(auth *Authentication) {
authPool.Put(auth)
}
v2ray-core-4.34.0/proxy/mtproto/auth_test.go 0000664 0000000 0000000 00000002065 13774574720 0021032 0 ustar 00root root 0000000 0000000 package mtproto_test
import (
"bytes"
"crypto/rand"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
. "v2ray.com/core/proxy/mtproto"
)
func TestInverse(t *testing.T) {
const size = 64
b := make([]byte, 64)
for b[0] == b[size-1] {
common.Must2(rand.Read(b))
}
bi := Inverse(b)
if b[0] == bi[0] {
t.Fatal("seems bytes are not inversed: ", b[0], "vs", bi[0])
}
bii := Inverse(bi)
if r := cmp.Diff(bii, b); r != "" {
t.Fatal(r)
}
}
func TestAuthenticationReadWrite(t *testing.T) {
a := NewAuthentication(DefaultSessionContext())
b := bytes.NewReader(a.Header[:])
a2, err := ReadAuthentication(b)
common.Must(err)
if r := cmp.Diff(a.EncodingKey[:], a2.DecodingKey[:]); r != "" {
t.Error("decoding key: ", r)
}
if r := cmp.Diff(a.EncodingNonce[:], a2.DecodingNonce[:]); r != "" {
t.Error("decoding nonce: ", r)
}
if r := cmp.Diff(a.DecodingKey[:], a2.EncodingKey[:]); r != "" {
t.Error("encoding key: ", r)
}
if r := cmp.Diff(a.DecodingNonce[:], a2.EncodingNonce[:]); r != "" {
t.Error("encoding nonce: ", r)
}
}
v2ray-core-4.34.0/proxy/mtproto/client.go 0000664 0000000 0000000 00000004126 13774574720 0020310 0 ustar 00root root 0000000 0000000 package mtproto
import (
"context"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/crypto"
"v2ray.com/core/common/net"
"v2ray.com/core/common/session"
"v2ray.com/core/common/task"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
)
type Client struct {
}
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
return &Client{}, nil
}
func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
outbound := session.OutboundFromContext(ctx)
if outbound == nil || !outbound.Target.IsValid() {
return newError("unknown destination.")
}
dest := outbound.Target
if dest.Network != net.Network_TCP {
return newError("not TCP traffic", dest)
}
conn, err := dialer.Dial(ctx, dest)
if err != nil {
return newError("failed to dial to ", dest).Base(err).AtWarning()
}
defer conn.Close()
sc := SessionContextFromContext(ctx)
auth := NewAuthentication(sc)
defer putAuthenticationObject(auth)
request := func() error {
encryptor := crypto.NewAesCTRStream(auth.EncodingKey[:], auth.EncodingNonce[:])
var header [HeaderSize]byte
encryptor.XORKeyStream(header[:], auth.Header[:])
copy(header[:56], auth.Header[:])
if _, err := conn.Write(header[:]); err != nil {
return newError("failed to write auth header").Base(err)
}
connWriter := buf.NewWriter(crypto.NewCryptionWriter(encryptor, conn))
return buf.Copy(link.Reader, connWriter)
}
response := func() error {
decryptor := crypto.NewAesCTRStream(auth.DecodingKey[:], auth.DecodingNonce[:])
connReader := buf.NewReader(crypto.NewCryptionReader(decryptor, conn))
return buf.Copy(connReader, link.Writer)
}
var responseDoneAndCloseWriter = task.OnSuccess(response, task.Close(link.Writer))
if err := task.Run(ctx, request, responseDoneAndCloseWriter); err != nil {
return newError("connection ends").Base(err)
}
return nil
}
func init() {
common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewClient(ctx, config.(*ClientConfig))
}))
}
v2ray-core-4.34.0/proxy/mtproto/config.go 0000664 0000000 0000000 00000000513 13774574720 0020273 0 ustar 00root root 0000000 0000000 package mtproto
import (
"v2ray.com/core/common/protocol"
)
func (a *Account) Equals(another protocol.Account) bool {
aa, ok := another.(*Account)
if !ok {
return false
}
if len(a.Secret) != len(aa.Secret) {
return false
}
for i, v := range a.Secret {
if v != aa.Secret[i] {
return false
}
}
return true
}
v2ray-core-4.34.0/proxy/mtproto/config.pb.go 0000664 0000000 0000000 00000021745 13774574720 0020705 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/mtproto/config.proto
package mtproto
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
protocol "v2ray.com/core/common/protocol"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Account struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Secret []byte `protobuf:"bytes,1,opt,name=secret,proto3" json:"secret,omitempty"`
}
func (x *Account) Reset() {
*x = Account{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_mtproto_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Account) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Account) ProtoMessage() {}
func (x *Account) ProtoReflect() protoreflect.Message {
mi := &file_proxy_mtproto_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Account.ProtoReflect.Descriptor instead.
func (*Account) Descriptor() ([]byte, []int) {
return file_proxy_mtproto_config_proto_rawDescGZIP(), []int{0}
}
func (x *Account) GetSecret() []byte {
if x != nil {
return x.Secret
}
return nil
}
type ServerConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// User is a list of users that allowed to connect to this inbound.
// Although this is a repeated field, only the first user is effective for
// now.
User []*protocol.User `protobuf:"bytes,1,rep,name=user,proto3" json:"user,omitempty"`
}
func (x *ServerConfig) Reset() {
*x = ServerConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_mtproto_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServerConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServerConfig) ProtoMessage() {}
func (x *ServerConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_mtproto_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServerConfig.ProtoReflect.Descriptor instead.
func (*ServerConfig) Descriptor() ([]byte, []int) {
return file_proxy_mtproto_config_proto_rawDescGZIP(), []int{1}
}
func (x *ServerConfig) GetUser() []*protocol.User {
if x != nil {
return x.User
}
return nil
}
type ClientConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ClientConfig) Reset() {
*x = ClientConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_mtproto_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ClientConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientConfig) ProtoMessage() {}
func (x *ClientConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_mtproto_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead.
func (*ClientConfig) Descriptor() ([]byte, []int) {
return file_proxy_mtproto_config_proto_rawDescGZIP(), []int{2}
}
var File_proxy_mtproto_config_proto protoreflect.FileDescriptor
var file_proxy_mtproto_config_proto_rawDesc = []byte{
0x0a, 0x1a, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x6d, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x18, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x6d,
0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x22, 0x21, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a,
0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73,
0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x44, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x0e, 0x0a, 0x0c, 0x43,
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x59, 0x0a, 0x1c, 0x63,
0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x2e, 0x6d, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x1c, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x2f, 0x6d, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0xaa, 0x02, 0x18, 0x56, 0x32,
0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x4d,
0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proxy_mtproto_config_proto_rawDescOnce sync.Once
file_proxy_mtproto_config_proto_rawDescData = file_proxy_mtproto_config_proto_rawDesc
)
func file_proxy_mtproto_config_proto_rawDescGZIP() []byte {
file_proxy_mtproto_config_proto_rawDescOnce.Do(func() {
file_proxy_mtproto_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_mtproto_config_proto_rawDescData)
})
return file_proxy_mtproto_config_proto_rawDescData
}
var file_proxy_mtproto_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_proxy_mtproto_config_proto_goTypes = []interface{}{
(*Account)(nil), // 0: v2ray.core.proxy.mtproto.Account
(*ServerConfig)(nil), // 1: v2ray.core.proxy.mtproto.ServerConfig
(*ClientConfig)(nil), // 2: v2ray.core.proxy.mtproto.ClientConfig
(*protocol.User)(nil), // 3: v2ray.core.common.protocol.User
}
var file_proxy_mtproto_config_proto_depIdxs = []int32{
3, // 0: v2ray.core.proxy.mtproto.ServerConfig.user:type_name -> v2ray.core.common.protocol.User
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_proxy_mtproto_config_proto_init() }
func file_proxy_mtproto_config_proto_init() {
if File_proxy_mtproto_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_mtproto_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Account); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_mtproto_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ServerConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_mtproto_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ClientConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_mtproto_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_mtproto_config_proto_goTypes,
DependencyIndexes: file_proxy_mtproto_config_proto_depIdxs,
MessageInfos: file_proxy_mtproto_config_proto_msgTypes,
}.Build()
File_proxy_mtproto_config_proto = out.File
file_proxy_mtproto_config_proto_rawDesc = nil
file_proxy_mtproto_config_proto_goTypes = nil
file_proxy_mtproto_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/mtproto/config.proto 0000664 0000000 0000000 00000001115 13774574720 0021030 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.mtproto;
option csharp_namespace = "V2Ray.Core.Proxy.Mtproto";
option go_package = "v2ray.com/core/proxy/mtproto";
option java_package = "com.v2ray.core.proxy.mtproto";
option java_multiple_files = true;
import "common/protocol/user.proto";
message Account {
bytes secret = 1;
}
message ServerConfig {
// User is a list of users that allowed to connect to this inbound.
// Although this is a repeated field, only the first user is effective for
// now.
repeated v2ray.core.common.protocol.User user = 1;
}
message ClientConfig {}
v2ray-core-4.34.0/proxy/mtproto/errors.generated.go 0000664 0000000 0000000 00000000315 13774574720 0022277 0 ustar 00root root 0000000 0000000 package mtproto
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/mtproto/mtproto.go 0000664 0000000 0000000 00000000114 13774574720 0020527 0 ustar 00root root 0000000 0000000 package mtproto
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/proxy/mtproto/server.go 0000664 0000000 0000000 00000010312 13774574720 0020332 0 ustar 00root root 0000000 0000000 // +build !confonly
package mtproto
import (
"bytes"
"context"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/crypto"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/policy"
"v2ray.com/core/features/routing"
"v2ray.com/core/transport/internet"
)
var (
dcList = []net.Address{
net.ParseAddress("149.154.175.50"),
net.ParseAddress("149.154.167.51"),
net.ParseAddress("149.154.175.100"),
net.ParseAddress("149.154.167.91"),
net.ParseAddress("149.154.171.5"),
}
)
type Server struct {
user *protocol.User
account *Account
policy policy.Manager
}
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
if len(config.User) == 0 {
return nil, newError("no user configured.")
}
user := config.User[0]
rawAccount, err := config.User[0].GetTypedAccount()
if err != nil {
return nil, newError("invalid account").Base(err)
}
account, ok := rawAccount.(*Account)
if !ok {
return nil, newError("not a MTProto account")
}
v := core.MustFromContext(ctx)
return &Server{
user: user,
account: account,
policy: v.GetFeature(policy.ManagerType()).(policy.Manager),
}, nil
}
func (s *Server) Network() []net.Network {
return []net.Network{net.Network_TCP}
}
var ctype1 = []byte{0xef, 0xef, 0xef, 0xef}
var ctype2 = []byte{0xee, 0xee, 0xee, 0xee}
func isValidConnectionType(c [4]byte) bool {
if bytes.Equal(c[:], ctype1) {
return true
}
if bytes.Equal(c[:], ctype2) {
return true
}
return false
}
func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {
sPolicy := s.policy.ForLevel(s.user.Level)
if err := conn.SetDeadline(time.Now().Add(sPolicy.Timeouts.Handshake)); err != nil {
newError("failed to set deadline").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
auth, err := ReadAuthentication(conn)
if err != nil {
return newError("failed to read authentication header").Base(err)
}
defer putAuthenticationObject(auth)
if err := conn.SetDeadline(time.Time{}); err != nil {
newError("failed to clear deadline").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
auth.ApplySecret(s.account.Secret)
decryptor := crypto.NewAesCTRStream(auth.DecodingKey[:], auth.DecodingNonce[:])
decryptor.XORKeyStream(auth.Header[:], auth.Header[:])
ct := auth.ConnectionType()
if !isValidConnectionType(ct) {
return newError("invalid connection type: ", ct)
}
dcID := auth.DataCenterID()
if dcID >= uint16(len(dcList)) {
return newError("invalid datacenter id: ", dcID)
}
dest := net.Destination{
Network: net.Network_TCP,
Address: dcList[dcID],
Port: net.Port(443),
}
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sPolicy.Timeouts.ConnectionIdle)
ctx = policy.ContextWithBufferPolicy(ctx, sPolicy.Buffer)
sc := SessionContext{
ConnectionType: ct,
DataCenterID: dcID,
}
ctx = ContextWithSessionContext(ctx, sc)
link, err := dispatcher.Dispatch(ctx, dest)
if err != nil {
return newError("failed to dispatch request to: ", dest).Base(err)
}
request := func() error {
defer timer.SetTimeout(sPolicy.Timeouts.DownlinkOnly)
reader := buf.NewReader(crypto.NewCryptionReader(decryptor, conn))
return buf.Copy(reader, link.Writer, buf.UpdateActivity(timer))
}
response := func() error {
defer timer.SetTimeout(sPolicy.Timeouts.UplinkOnly)
encryptor := crypto.NewAesCTRStream(auth.EncodingKey[:], auth.EncodingNonce[:])
writer := buf.NewWriter(crypto.NewCryptionWriter(encryptor, conn))
return buf.Copy(link.Reader, writer, buf.UpdateActivity(timer))
}
var responseDoneAndCloseWriter = task.OnSuccess(response, task.Close(link.Writer))
if err := task.Run(ctx, request, responseDoneAndCloseWriter); err != nil {
common.Interrupt(link.Reader)
common.Interrupt(link.Writer)
return newError("connection ends").Base(err)
}
return nil
}
func init() {
common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewServer(ctx, config.(*ServerConfig))
}))
}
v2ray-core-4.34.0/proxy/proxy.go 0000664 0000000 0000000 00000002776 13774574720 0016520 0 ustar 00root root 0000000 0000000 // Package proxy contains all proxies used by V2Ray.
//
// To implement an inbound or outbound proxy, one needs to do the following:
// 1. Implement the interface(s) below.
// 2. Register a config creator through common.RegisterConfig.
package proxy
import (
"context"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/features/routing"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
)
// An Inbound processes inbound connections.
type Inbound interface {
// Network returns a list of networks that this inbound supports. Connections with not-supported networks will not be passed into Process().
Network() []net.Network
// Process processes a connection of given network. If necessary, the Inbound can dispatch the connection to an Outbound.
Process(context.Context, net.Network, internet.Connection, routing.Dispatcher) error
}
// An Outbound process outbound connections.
type Outbound interface {
// Process processes the given connection. The given dialer may be used to dial a system outbound connection.
Process(context.Context, *transport.Link, internet.Dialer) error
}
// UserManager is the interface for Inbounds and Outbounds that can manage their users.
type UserManager interface {
// AddUser adds a new user.
AddUser(context.Context, *protocol.MemoryUser) error
// RemoveUser removes a user by email.
RemoveUser(context.Context, string) error
}
type GetInbound interface {
GetInbound() Inbound
}
type GetOutbound interface {
GetOutbound() Outbound
}
v2ray-core-4.34.0/proxy/shadowsocks/ 0000775 0000000 0000000 00000000000 13774574720 0017324 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/shadowsocks/client.go 0000664 0000000 0000000 00000011573 13774574720 0021140 0 ustar 00root root 0000000 0000000 // +build !confonly
package shadowsocks
import (
"context"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/retry"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/policy"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
)
// Client is a inbound handler for Shadowsocks protocol
type Client struct {
serverPicker protocol.ServerPicker
policyManager policy.Manager
}
// NewClient create a new Shadowsocks client.
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
serverList := protocol.NewServerList()
for _, rec := range config.Server {
s, err := protocol.NewServerSpecFromPB(rec)
if err != nil {
return nil, newError("failed to parse server spec").Base(err)
}
serverList.AddServer(s)
}
if serverList.Size() == 0 {
return nil, newError("0 server")
}
v := core.MustFromContext(ctx)
client := &Client{
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
}
return client, nil
}
// Process implements OutboundHandler.Process().
func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
outbound := session.OutboundFromContext(ctx)
if outbound == nil || !outbound.Target.IsValid() {
return newError("target not specified")
}
destination := outbound.Target
network := destination.Network
var server *protocol.ServerSpec
var conn internet.Connection
err := retry.ExponentialBackoff(5, 100).On(func() error {
server = c.serverPicker.PickServer()
dest := server.Destination()
dest.Network = network
rawConn, err := dialer.Dial(ctx, dest)
if err != nil {
return err
}
conn = rawConn
return nil
})
if err != nil {
return newError("failed to find an available destination").AtWarning().Base(err)
}
newError("tunneling request to ", destination, " via ", server.Destination()).WriteToLog(session.ExportIDToError(ctx))
defer conn.Close()
request := &protocol.RequestHeader{
Version: Version,
Address: destination.Address,
Port: destination.Port,
}
if destination.Network == net.Network_TCP {
request.Command = protocol.RequestCommandTCP
} else {
request.Command = protocol.RequestCommandUDP
}
user := server.PickUser()
_, ok := user.Account.(*MemoryAccount)
if !ok {
return newError("user account is not valid")
}
request.User = user
sessionPolicy := c.policyManager.ForLevel(user.Level)
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
if request.Command == protocol.RequestCommandTCP {
bufferedWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
bodyWriter, err := WriteTCPRequest(request, bufferedWriter)
if err != nil {
return newError("failed to write request").Base(err)
}
if err := bufferedWriter.SetBuffered(false); err != nil {
return err
}
requestDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
return buf.Copy(link.Reader, bodyWriter, buf.UpdateActivity(timer))
}
responseDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
responseReader, err := ReadTCPResponse(user, conn)
if err != nil {
return err
}
return buf.Copy(responseReader, link.Writer, buf.UpdateActivity(timer))
}
var responseDoneAndCloseWriter = task.OnSuccess(responseDone, task.Close(link.Writer))
if err := task.Run(ctx, requestDone, responseDoneAndCloseWriter); err != nil {
return newError("connection ends").Base(err)
}
return nil
}
if request.Command == protocol.RequestCommandUDP {
writer := &buf.SequentialWriter{Writer: &UDPWriter{
Writer: conn,
Request: request,
}}
requestDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
if err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport all UDP request").Base(err)
}
return nil
}
responseDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
reader := &UDPReader{
Reader: conn,
User: user,
}
if err := buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport all UDP response").Base(err)
}
return nil
}
var responseDoneAndCloseWriter = task.OnSuccess(responseDone, task.Close(link.Writer))
if err := task.Run(ctx, requestDone, responseDoneAndCloseWriter); err != nil {
return newError("connection ends").Base(err)
}
return nil
}
return nil
}
func init() {
common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewClient(ctx, config.(*ClientConfig))
}))
}
v2ray-core-4.34.0/proxy/shadowsocks/config.go 0000664 0000000 0000000 00000012266 13774574720 0021127 0 ustar 00root root 0000000 0000000 package shadowsocks
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"crypto/sha1"
"io"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/hkdf"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/crypto"
"v2ray.com/core/common/protocol"
)
// MemoryAccount is an account type converted from Account.
type MemoryAccount struct {
Cipher Cipher
Key []byte
}
// Equals implements protocol.Account.Equals().
func (a *MemoryAccount) Equals(another protocol.Account) bool {
if account, ok := another.(*MemoryAccount); ok {
return bytes.Equal(a.Key, account.Key)
}
return false
}
func createAesGcm(key []byte) cipher.AEAD {
block, err := aes.NewCipher(key)
common.Must(err)
gcm, err := cipher.NewGCM(block)
common.Must(err)
return gcm
}
func createChaCha20Poly1305(key []byte) cipher.AEAD {
ChaChaPoly1305, err := chacha20poly1305.New(key)
common.Must(err)
return ChaChaPoly1305
}
func (a *Account) getCipher() (Cipher, error) {
switch a.CipherType {
case CipherType_AES_128_GCM:
return &AEADCipher{
KeyBytes: 16,
IVBytes: 16,
AEADAuthCreator: createAesGcm,
}, nil
case CipherType_AES_256_GCM:
return &AEADCipher{
KeyBytes: 32,
IVBytes: 32,
AEADAuthCreator: createAesGcm,
}, nil
case CipherType_CHACHA20_POLY1305:
return &AEADCipher{
KeyBytes: 32,
IVBytes: 32,
AEADAuthCreator: createChaCha20Poly1305,
}, nil
case CipherType_NONE:
return NoneCipher{}, nil
default:
return nil, newError("Unsupported cipher.")
}
}
// AsAccount implements protocol.AsAccount.
func (a *Account) AsAccount() (protocol.Account, error) {
Cipher, err := a.getCipher()
if err != nil {
return nil, newError("failed to get cipher").Base(err)
}
return &MemoryAccount{
Cipher: Cipher,
Key: passwordToCipherKey([]byte(a.Password), Cipher.KeySize()),
}, nil
}
// Cipher is an interface for all Shadowsocks ciphers.
type Cipher interface {
KeySize() int32
IVSize() int32
NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error)
NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error)
IsAEAD() bool
EncodePacket(key []byte, b *buf.Buffer) error
DecodePacket(key []byte, b *buf.Buffer) error
}
type AEADCipher struct {
KeyBytes int32
IVBytes int32
AEADAuthCreator func(key []byte) cipher.AEAD
}
func (*AEADCipher) IsAEAD() bool {
return true
}
func (c *AEADCipher) KeySize() int32 {
return c.KeyBytes
}
func (c *AEADCipher) IVSize() int32 {
return c.IVBytes
}
func (c *AEADCipher) createAuthenticator(key []byte, iv []byte) *crypto.AEADAuthenticator {
nonce := crypto.GenerateInitialAEADNonce()
subkey := make([]byte, c.KeyBytes)
hkdfSHA1(key, iv, subkey)
return &crypto.AEADAuthenticator{
AEAD: c.AEADAuthCreator(subkey),
NonceGenerator: nonce,
}
}
func (c *AEADCipher) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {
auth := c.createAuthenticator(key, iv)
return crypto.NewAuthenticationWriter(auth, &crypto.AEADChunkSizeParser{
Auth: auth,
}, writer, protocol.TransferTypeStream, nil), nil
}
func (c *AEADCipher) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
auth := c.createAuthenticator(key, iv)
return crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
Auth: auth,
}, reader, protocol.TransferTypeStream, nil), nil
}
func (c *AEADCipher) EncodePacket(key []byte, b *buf.Buffer) error {
ivLen := c.IVSize()
payloadLen := b.Len()
auth := c.createAuthenticator(key, b.BytesTo(ivLen))
b.Extend(int32(auth.Overhead()))
_, err := auth.Seal(b.BytesTo(ivLen), b.BytesRange(ivLen, payloadLen))
return err
}
func (c *AEADCipher) DecodePacket(key []byte, b *buf.Buffer) error {
if b.Len() <= c.IVSize() {
return newError("insufficient data: ", b.Len())
}
ivLen := c.IVSize()
payloadLen := b.Len()
auth := c.createAuthenticator(key, b.BytesTo(ivLen))
bbb, err := auth.Open(b.BytesTo(ivLen), b.BytesRange(ivLen, payloadLen))
if err != nil {
return err
}
b.Resize(ivLen, int32(len(bbb)))
return nil
}
type NoneCipher struct{}
func (NoneCipher) KeySize() int32 { return 0 }
func (NoneCipher) IVSize() int32 { return 0 }
func (NoneCipher) IsAEAD() bool {
return false
}
func (NoneCipher) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
return buf.NewReader(reader), nil
}
func (NoneCipher) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {
return buf.NewWriter(writer), nil
}
func (NoneCipher) EncodePacket(key []byte, b *buf.Buffer) error {
return nil
}
func (NoneCipher) DecodePacket(key []byte, b *buf.Buffer) error {
return nil
}
func passwordToCipherKey(password []byte, keySize int32) []byte {
key := make([]byte, 0, keySize)
md5Sum := md5.Sum(password)
key = append(key, md5Sum[:]...)
for int32(len(key)) < keySize {
md5Hash := md5.New()
common.Must2(md5Hash.Write(md5Sum[:]))
common.Must2(md5Hash.Write(password))
md5Hash.Sum(md5Sum[:0])
key = append(key, md5Sum[:]...)
}
return key
}
func hkdfSHA1(secret, salt, outKey []byte) {
r := hkdf.New(sha1.New, secret, salt, []byte("ss-subkey"))
common.Must2(io.ReadFull(r, outKey))
}
v2ray-core-4.34.0/proxy/shadowsocks/config.pb.go 0000664 0000000 0000000 00000035223 13774574720 0021525 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.12.4
// source: proxy/shadowsocks/config.proto
package shadowsocks
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
net "v2ray.com/core/common/net"
protocol "v2ray.com/core/common/protocol"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type CipherType int32
const (
CipherType_UNKNOWN CipherType = 0
CipherType_AES_128_GCM CipherType = 1
CipherType_AES_256_GCM CipherType = 2
CipherType_CHACHA20_POLY1305 CipherType = 3
CipherType_NONE CipherType = 4
)
// Enum value maps for CipherType.
var (
CipherType_name = map[int32]string{
0: "UNKNOWN",
1: "AES_128_GCM",
2: "AES_256_GCM",
3: "CHACHA20_POLY1305",
4: "NONE",
}
CipherType_value = map[string]int32{
"UNKNOWN": 0,
"AES_128_GCM": 1,
"AES_256_GCM": 2,
"CHACHA20_POLY1305": 3,
"NONE": 4,
}
)
func (x CipherType) Enum() *CipherType {
p := new(CipherType)
*p = x
return p
}
func (x CipherType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (CipherType) Descriptor() protoreflect.EnumDescriptor {
return file_proxy_shadowsocks_config_proto_enumTypes[0].Descriptor()
}
func (CipherType) Type() protoreflect.EnumType {
return &file_proxy_shadowsocks_config_proto_enumTypes[0]
}
func (x CipherType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use CipherType.Descriptor instead.
func (CipherType) EnumDescriptor() ([]byte, []int) {
return file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{0}
}
type Account struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"`
CipherType CipherType `protobuf:"varint,2,opt,name=cipher_type,json=cipherType,proto3,enum=v2ray.core.proxy.shadowsocks.CipherType" json:"cipher_type,omitempty"`
}
func (x *Account) Reset() {
*x = Account{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_shadowsocks_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Account) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Account) ProtoMessage() {}
func (x *Account) ProtoReflect() protoreflect.Message {
mi := &file_proxy_shadowsocks_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Account.ProtoReflect.Descriptor instead.
func (*Account) Descriptor() ([]byte, []int) {
return file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{0}
}
func (x *Account) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
func (x *Account) GetCipherType() CipherType {
if x != nil {
return x.CipherType
}
return CipherType_UNKNOWN
}
type ServerConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// UdpEnabled specified whether or not to enable UDP for Shadowsocks.
// Deprecated. Use 'network' field.
//
// Deprecated: Do not use.
UdpEnabled bool `protobuf:"varint,1,opt,name=udp_enabled,json=udpEnabled,proto3" json:"udp_enabled,omitempty"`
User *protocol.User `protobuf:"bytes,2,opt,name=user,proto3" json:"user,omitempty"`
Network []net.Network `protobuf:"varint,3,rep,packed,name=network,proto3,enum=v2ray.core.common.net.Network" json:"network,omitempty"`
}
func (x *ServerConfig) Reset() {
*x = ServerConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_shadowsocks_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServerConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServerConfig) ProtoMessage() {}
func (x *ServerConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_shadowsocks_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServerConfig.ProtoReflect.Descriptor instead.
func (*ServerConfig) Descriptor() ([]byte, []int) {
return file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{1}
}
// Deprecated: Do not use.
func (x *ServerConfig) GetUdpEnabled() bool {
if x != nil {
return x.UdpEnabled
}
return false
}
func (x *ServerConfig) GetUser() *protocol.User {
if x != nil {
return x.User
}
return nil
}
func (x *ServerConfig) GetNetwork() []net.Network {
if x != nil {
return x.Network
}
return nil
}
type ClientConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"`
}
func (x *ClientConfig) Reset() {
*x = ClientConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_shadowsocks_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ClientConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientConfig) ProtoMessage() {}
func (x *ClientConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_shadowsocks_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead.
func (*ClientConfig) Descriptor() ([]byte, []int) {
return file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{2}
}
func (x *ClientConfig) GetServer() []*protocol.ServerEndpoint {
if x != nil {
return x.Server
}
return nil
}
var File_proxy_shadowsocks_config_proto protoreflect.FileDescriptor
var file_proxy_shadowsocks_config_proto_rawDesc = []byte{
0x0a, 0x1e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f,
0x63, 0x6b, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x12, 0x1c, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x1a, 0x18,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f,
0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65,
0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x70, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x49,
0x0a, 0x0b, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63,
0x6b, 0x73, 0x2e, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63,
0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x22, 0xa3, 0x01, 0x0a, 0x0c, 0x53, 0x65,
0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x0a, 0x0b, 0x75, 0x64,
0x70, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x42,
0x02, 0x18, 0x01, 0x52, 0x0a, 0x75, 0x64, 0x70, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12,
0x34, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52,
0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
0x18, 0x03, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e,
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22,
0x52, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x42, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72,
0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x2a, 0x5c, 0x0a, 0x0a, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70,
0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0f,
0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43, 0x4d, 0x10, 0x01, 0x12,
0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x47, 0x43, 0x4d, 0x10, 0x02,
0x12, 0x15, 0x0a, 0x11, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x50, 0x4f, 0x4c,
0x59, 0x31, 0x33, 0x30, 0x35, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10,
0x04, 0x42, 0x65, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77,
0x73, 0x6f, 0x63, 0x6b, 0x73, 0x50, 0x01, 0x5a, 0x20, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x68,
0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0xaa, 0x02, 0x1c, 0x56, 0x32, 0x52, 0x61,
0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x68, 0x61,
0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proxy_shadowsocks_config_proto_rawDescOnce sync.Once
file_proxy_shadowsocks_config_proto_rawDescData = file_proxy_shadowsocks_config_proto_rawDesc
)
func file_proxy_shadowsocks_config_proto_rawDescGZIP() []byte {
file_proxy_shadowsocks_config_proto_rawDescOnce.Do(func() {
file_proxy_shadowsocks_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_shadowsocks_config_proto_rawDescData)
})
return file_proxy_shadowsocks_config_proto_rawDescData
}
var file_proxy_shadowsocks_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_proxy_shadowsocks_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_proxy_shadowsocks_config_proto_goTypes = []interface{}{
(CipherType)(0), // 0: v2ray.core.proxy.shadowsocks.CipherType
(*Account)(nil), // 1: v2ray.core.proxy.shadowsocks.Account
(*ServerConfig)(nil), // 2: v2ray.core.proxy.shadowsocks.ServerConfig
(*ClientConfig)(nil), // 3: v2ray.core.proxy.shadowsocks.ClientConfig
(*protocol.User)(nil), // 4: v2ray.core.common.protocol.User
(net.Network)(0), // 5: v2ray.core.common.net.Network
(*protocol.ServerEndpoint)(nil), // 6: v2ray.core.common.protocol.ServerEndpoint
}
var file_proxy_shadowsocks_config_proto_depIdxs = []int32{
0, // 0: v2ray.core.proxy.shadowsocks.Account.cipher_type:type_name -> v2ray.core.proxy.shadowsocks.CipherType
4, // 1: v2ray.core.proxy.shadowsocks.ServerConfig.user:type_name -> v2ray.core.common.protocol.User
5, // 2: v2ray.core.proxy.shadowsocks.ServerConfig.network:type_name -> v2ray.core.common.net.Network
6, // 3: v2ray.core.proxy.shadowsocks.ClientConfig.server:type_name -> v2ray.core.common.protocol.ServerEndpoint
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_proxy_shadowsocks_config_proto_init() }
func file_proxy_shadowsocks_config_proto_init() {
if File_proxy_shadowsocks_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_shadowsocks_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Account); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_shadowsocks_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ServerConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_shadowsocks_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ClientConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_shadowsocks_config_proto_rawDesc,
NumEnums: 1,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_shadowsocks_config_proto_goTypes,
DependencyIndexes: file_proxy_shadowsocks_config_proto_depIdxs,
EnumInfos: file_proxy_shadowsocks_config_proto_enumTypes,
MessageInfos: file_proxy_shadowsocks_config_proto_msgTypes,
}.Build()
File_proxy_shadowsocks_config_proto = out.File
file_proxy_shadowsocks_config_proto_rawDesc = nil
file_proxy_shadowsocks_config_proto_goTypes = nil
file_proxy_shadowsocks_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/shadowsocks/config.proto 0000664 0000000 0000000 00000001650 13774574720 0021660 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.shadowsocks;
option csharp_namespace = "V2Ray.Core.Proxy.Shadowsocks";
option go_package = "v2ray.com/core/proxy/shadowsocks";
option java_package = "com.v2ray.core.proxy.shadowsocks";
option java_multiple_files = true;
import "common/net/network.proto";
import "common/protocol/user.proto";
import "common/protocol/server_spec.proto";
message Account {
string password = 1;
CipherType cipher_type = 2;
}
enum CipherType {
UNKNOWN = 0;
AES_128_GCM = 1;
AES_256_GCM = 2;
CHACHA20_POLY1305 = 3;
NONE = 4;
}
message ServerConfig {
// UdpEnabled specified whether or not to enable UDP for Shadowsocks.
// Deprecated. Use 'network' field.
bool udp_enabled = 1 [deprecated = true];
v2ray.core.common.protocol.User user = 2;
repeated v2ray.core.common.net.Network network = 3;
}
message ClientConfig {
repeated v2ray.core.common.protocol.ServerEndpoint server = 1;
}
v2ray-core-4.34.0/proxy/shadowsocks/config_test.go 0000664 0000000 0000000 00000001541 13774574720 0022160 0 ustar 00root root 0000000 0000000 package shadowsocks_test
import (
"crypto/rand"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/proxy/shadowsocks"
)
func TestAEADCipherUDP(t *testing.T) {
rawAccount := &shadowsocks.Account{
CipherType: shadowsocks.CipherType_AES_128_GCM,
Password: "test",
}
account, err := rawAccount.AsAccount()
common.Must(err)
cipher := account.(*shadowsocks.MemoryAccount).Cipher
key := make([]byte, cipher.KeySize())
common.Must2(rand.Read(key))
payload := make([]byte, 1024)
common.Must2(rand.Read(payload))
b1 := buf.New()
common.Must2(b1.ReadFullFrom(rand.Reader, cipher.IVSize()))
common.Must2(b1.Write(payload))
common.Must(cipher.EncodePacket(key, b1))
common.Must(cipher.DecodePacket(key, b1))
if diff := cmp.Diff(b1.Bytes(), payload); diff != "" {
t.Error(diff)
}
}
v2ray-core-4.34.0/proxy/shadowsocks/errors.generated.go 0000664 0000000 0000000 00000000321 13774574720 0023120 0 ustar 00root root 0000000 0000000 package shadowsocks
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/shadowsocks/protocol.go 0000664 0000000 0000000 00000015373 13774574720 0021525 0 ustar 00root root 0000000 0000000 // +build !confonly
package shadowsocks
import (
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"hash/crc32"
"io"
"io/ioutil"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/dice"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
)
const (
Version = 1
)
var addrParser = protocol.NewAddressParser(
protocol.AddressFamilyByte(0x01, net.AddressFamilyIPv4),
protocol.AddressFamilyByte(0x04, net.AddressFamilyIPv6),
protocol.AddressFamilyByte(0x03, net.AddressFamilyDomain),
protocol.WithAddressTypeParser(func(b byte) byte {
return b & 0x0F
}),
)
// ReadTCPSession reads a Shadowsocks TCP session from the given reader, returns its header and remaining parts.
func ReadTCPSession(user *protocol.MemoryUser, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {
account := user.Account.(*MemoryAccount)
hashkdf := hmac.New(sha256.New, []byte("SSBSKDF"))
hashkdf.Write(account.Key)
behaviorSeed := crc32.ChecksumIEEE(hashkdf.Sum(nil))
behaviorRand := dice.NewDeterministicDice(int64(behaviorSeed))
BaseDrainSize := behaviorRand.Roll(3266)
RandDrainMax := behaviorRand.Roll(64) + 1
RandDrainRolled := dice.Roll(RandDrainMax)
DrainSize := BaseDrainSize + 16 + 38 + RandDrainRolled
readSizeRemain := DrainSize
buffer := buf.New()
defer buffer.Release()
ivLen := account.Cipher.IVSize()
var iv []byte
if ivLen > 0 {
if _, err := buffer.ReadFullFrom(reader, ivLen); err != nil {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed to read IV").Base(err)
}
iv = append([]byte(nil), buffer.BytesTo(ivLen)...)
}
r, err := account.Cipher.NewDecryptionReader(account.Key, iv, reader)
if err != nil {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed to initialize decoding stream").Base(err).AtError()
}
br := &buf.BufferedReader{Reader: r}
request := &protocol.RequestHeader{
Version: Version,
User: user,
Command: protocol.RequestCommandTCP,
}
readSizeRemain -= int(buffer.Len())
buffer.Clear()
addr, port, err := addrParser.ReadAddressPort(buffer, br)
if err != nil {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed to read address").Base(err)
}
request.Address = addr
request.Port = port
if request.Address == nil {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("invalid remote address.")
}
return request, br, nil
}
func DrainConnN(reader io.Reader, n int) error {
_, err := io.CopyN(ioutil.Discard, reader, int64(n))
return err
}
// WriteTCPRequest writes Shadowsocks request into the given writer, and returns a writer for body.
func WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (buf.Writer, error) {
user := request.User
account := user.Account.(*MemoryAccount)
var iv []byte
if account.Cipher.IVSize() > 0 {
iv = make([]byte, account.Cipher.IVSize())
common.Must2(rand.Read(iv))
if err := buf.WriteAllBytes(writer, iv); err != nil {
return nil, newError("failed to write IV")
}
}
w, err := account.Cipher.NewEncryptionWriter(account.Key, iv, writer)
if err != nil {
return nil, newError("failed to create encoding stream").Base(err).AtError()
}
header := buf.New()
if err := addrParser.WriteAddressPort(header, request.Address, request.Port); err != nil {
return nil, newError("failed to write address").Base(err)
}
if err := w.WriteMultiBuffer(buf.MultiBuffer{header}); err != nil {
return nil, newError("failed to write header").Base(err)
}
return w, nil
}
func ReadTCPResponse(user *protocol.MemoryUser, reader io.Reader) (buf.Reader, error) {
account := user.Account.(*MemoryAccount)
var iv []byte
if account.Cipher.IVSize() > 0 {
iv = make([]byte, account.Cipher.IVSize())
if _, err := io.ReadFull(reader, iv); err != nil {
return nil, newError("failed to read IV").Base(err)
}
}
return account.Cipher.NewDecryptionReader(account.Key, iv, reader)
}
func WriteTCPResponse(request *protocol.RequestHeader, writer io.Writer) (buf.Writer, error) {
user := request.User
account := user.Account.(*MemoryAccount)
var iv []byte
if account.Cipher.IVSize() > 0 {
iv = make([]byte, account.Cipher.IVSize())
common.Must2(rand.Read(iv))
if err := buf.WriteAllBytes(writer, iv); err != nil {
return nil, newError("failed to write IV.").Base(err)
}
}
return account.Cipher.NewEncryptionWriter(account.Key, iv, writer)
}
func EncodeUDPPacket(request *protocol.RequestHeader, payload []byte) (*buf.Buffer, error) {
user := request.User
account := user.Account.(*MemoryAccount)
buffer := buf.New()
ivLen := account.Cipher.IVSize()
if ivLen > 0 {
common.Must2(buffer.ReadFullFrom(rand.Reader, ivLen))
}
if err := addrParser.WriteAddressPort(buffer, request.Address, request.Port); err != nil {
return nil, newError("failed to write address").Base(err)
}
buffer.Write(payload)
if err := account.Cipher.EncodePacket(account.Key, buffer); err != nil {
return nil, newError("failed to encrypt UDP payload").Base(err)
}
return buffer, nil
}
func DecodeUDPPacket(user *protocol.MemoryUser, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) {
account := user.Account.(*MemoryAccount)
var iv []byte
if !account.Cipher.IsAEAD() && account.Cipher.IVSize() > 0 {
// Keep track of IV as it gets removed from payload in DecodePacket.
iv = make([]byte, account.Cipher.IVSize())
copy(iv, payload.BytesTo(account.Cipher.IVSize()))
}
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,
User: user,
Command: protocol.RequestCommandUDP,
}
payload.SetByte(0, payload.Byte(0)&0x0F)
addr, port, err := addrParser.ReadAddressPort(nil, payload)
if err != nil {
return nil, nil, newError("failed to parse address").Base(err)
}
request.Address = addr
request.Port = port
return request, payload, nil
}
type UDPReader struct {
Reader io.Reader
User *protocol.MemoryUser
}
func (v *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
buffer := buf.New()
_, err := buffer.ReadFrom(v.Reader)
if err != nil {
buffer.Release()
return nil, err
}
_, payload, err := DecodeUDPPacket(v.User, buffer)
if err != nil {
buffer.Release()
return nil, err
}
return buf.MultiBuffer{payload}, nil
}
type UDPWriter struct {
Writer io.Writer
Request *protocol.RequestHeader
}
// Write implements io.Writer.
func (w *UDPWriter) Write(payload []byte) (int, error) {
packet, err := EncodeUDPPacket(w.Request, payload)
if err != nil {
return 0, err
}
_, err = w.Writer.Write(packet.Bytes())
packet.Release()
return len(payload), err
}
v2ray-core-4.34.0/proxy/shadowsocks/protocol_test.go 0000664 0000000 0000000 00000010503 13774574720 0022552 0 ustar 00root root 0000000 0000000 package shadowsocks_test
import (
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
. "v2ray.com/core/proxy/shadowsocks"
)
func toAccount(a *Account) protocol.Account {
account, err := a.AsAccount()
common.Must(err)
return account
}
func equalRequestHeader(x, y *protocol.RequestHeader) bool {
return cmp.Equal(x, y, cmp.Comparer(func(x, y protocol.RequestHeader) bool {
return x == y
}))
}
func TestUDPEncoding(t *testing.T) {
request := &protocol.RequestHeader{
Version: Version,
Command: protocol.RequestCommandUDP,
Address: net.LocalHostIP,
Port: 1234,
User: &protocol.MemoryUser{
Email: "love@v2fly.org",
Account: toAccount(&Account{
Password: "password",
CipherType: CipherType_AES_128_GCM,
}),
},
}
data := buf.New()
common.Must2(data.WriteString("test string"))
encodedData, err := EncodeUDPPacket(request, data.Bytes())
common.Must(err)
decodedRequest, decodedData, err := DecodeUDPPacket(request.User, encodedData)
common.Must(err)
if r := cmp.Diff(decodedData.Bytes(), data.Bytes()); r != "" {
t.Error("data: ", r)
}
if equalRequestHeader(decodedRequest, request) == false {
t.Error("different request")
}
}
func TestTCPRequest(t *testing.T) {
cases := []struct {
request *protocol.RequestHeader
payload []byte
}{
{
request: &protocol.RequestHeader{
Version: Version,
Command: protocol.RequestCommandTCP,
Address: net.LocalHostIP,
Port: 1234,
User: &protocol.MemoryUser{
Email: "love@v2fly.org",
Account: toAccount(&Account{
Password: "tcp-password",
CipherType: CipherType_AES_128_GCM,
}),
},
},
payload: []byte("test string"),
},
{
request: &protocol.RequestHeader{
Version: Version,
Command: protocol.RequestCommandTCP,
Address: net.LocalHostIPv6,
Port: 1234,
User: &protocol.MemoryUser{
Email: "love@v2fly.org",
Account: toAccount(&Account{
Password: "password",
CipherType: CipherType_AES_256_GCM,
}),
},
},
payload: []byte("test string"),
},
{
request: &protocol.RequestHeader{
Version: Version,
Command: protocol.RequestCommandTCP,
Address: net.DomainAddress("v2fly.org"),
Port: 1234,
User: &protocol.MemoryUser{
Email: "love@v2fly.org",
Account: toAccount(&Account{
Password: "password",
CipherType: CipherType_CHACHA20_POLY1305,
}),
},
},
payload: []byte("test string"),
},
}
runTest := func(request *protocol.RequestHeader, payload []byte) {
data := buf.New()
common.Must2(data.Write(payload))
cache := buf.New()
defer cache.Release()
writer, err := WriteTCPRequest(request, cache)
common.Must(err)
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{data}))
decodedRequest, reader, err := ReadTCPSession(request.User, cache)
common.Must(err)
if equalRequestHeader(decodedRequest, request) == false {
t.Error("different request")
}
decodedData, err := reader.ReadMultiBuffer()
common.Must(err)
if r := cmp.Diff(decodedData[0].Bytes(), payload); r != "" {
t.Error("data: ", r)
}
}
for _, test := range cases {
runTest(test.request, test.payload)
}
}
func TestUDPReaderWriter(t *testing.T) {
user := &protocol.MemoryUser{
Account: toAccount(&Account{
Password: "test-password",
CipherType: CipherType_CHACHA20_POLY1305,
}),
}
cache := buf.New()
defer cache.Release()
writer := &buf.SequentialWriter{Writer: &UDPWriter{
Writer: cache,
Request: &protocol.RequestHeader{
Version: Version,
Address: net.DomainAddress("v2fly.org"),
Port: 123,
User: user,
},
}}
reader := &UDPReader{
Reader: cache,
User: user,
}
{
b := buf.New()
common.Must2(b.WriteString("test payload"))
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{b}))
payload, err := reader.ReadMultiBuffer()
common.Must(err)
if payload[0].String() != "test payload" {
t.Error("unexpected output: ", payload[0].String())
}
}
{
b := buf.New()
common.Must2(b.WriteString("test payload 2"))
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{b}))
payload, err := reader.ReadMultiBuffer()
common.Must(err)
if payload[0].String() != "test payload 2" {
t.Error("unexpected output: ", payload[0].String())
}
}
}
v2ray-core-4.34.0/proxy/shadowsocks/server.go 0000664 0000000 0000000 00000014627 13774574720 0021173 0 ustar 00root root 0000000 0000000 // +build !confonly
package shadowsocks
import (
"context"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
udp_proto "v2ray.com/core/common/protocol/udp"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/policy"
"v2ray.com/core/features/routing"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/udp"
)
type Server struct {
config *ServerConfig
user *protocol.MemoryUser
policyManager policy.Manager
}
// NewServer create a new Shadowsocks server.
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
if config.GetUser() == nil {
return nil, newError("user is not specified")
}
mUser, err := config.User.ToMemoryUser()
if err != nil {
return nil, newError("failed to parse user account").Base(err)
}
v := core.MustFromContext(ctx)
s := &Server{
config: config,
user: mUser,
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
}
return s, nil
}
func (s *Server) Network() []net.Network {
list := s.config.Network
if len(list) == 0 {
list = append(list, net.Network_TCP)
}
if s.config.UdpEnabled {
list = append(list, net.Network_UDP)
}
return list
}
func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {
switch network {
case net.Network_TCP:
return s.handleConnection(ctx, conn, dispatcher)
case net.Network_UDP:
return s.handlerUDPPayload(ctx, conn, dispatcher)
default:
return newError("unknown network: ", network)
}
}
func (s *Server) handlerUDPPayload(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 {
return
}
payload := packet.Payload
data, err := EncodeUDPPacket(request, payload.Bytes())
payload.Release()
if err != nil {
newError("failed to encode UDP packet").Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))
return
}
defer data.Release()
conn.Write(data.Bytes())
})
inbound := session.InboundFromContext(ctx)
if inbound == nil {
panic("no inbound metadata")
}
inbound.User = s.user
reader := buf.NewPacketReader(conn)
for {
mpayload, err := reader.ReadMultiBuffer()
if err != nil {
break
}
for _, payload := range mpayload {
request, data, err := DecodeUDPPacket(s.user, payload)
if err != nil {
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() {
newError("dropping invalid UDP packet from: ", inbound.Source).Base(err).WriteToLog(session.ExportIDToError(ctx))
log.Record(&log.AccessMessage{
From: inbound.Source,
To: "",
Status: log.AccessRejected,
Reason: err,
})
}
payload.Release()
continue
}
currentPacketCtx := ctx
dest := request.Destination()
if inbound.Source.IsValid() {
currentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: inbound.Source,
To: dest,
Status: log.AccessAccepted,
Reason: "",
Email: request.User.Email,
})
}
newError("tunnelling request to ", dest).WriteToLog(session.ExportIDToError(currentPacketCtx))
currentPacketCtx = protocol.ContextWithRequestHeader(currentPacketCtx, request)
udpServer.Dispatch(currentPacketCtx, dest, data)
}
}
return nil
}
func (s *Server) handleConnection(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error {
sessionPolicy := s.policyManager.ForLevel(s.user.Level)
conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake))
bufferedReader := buf.BufferedReader{Reader: buf.NewReader(conn)}
request, bodyReader, err := ReadTCPSession(s.user, &bufferedReader)
if err != nil {
log.Record(&log.AccessMessage{
From: conn.RemoteAddr(),
To: "",
Status: log.AccessRejected,
Reason: err,
})
return newError("failed to create request from: ", conn.RemoteAddr()).Base(err)
}
conn.SetReadDeadline(time.Time{})
inbound := session.InboundFromContext(ctx)
if inbound == nil {
panic("no inbound metadata")
}
inbound.User = s.user
dest := request.Destination()
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: conn.RemoteAddr(),
To: dest,
Status: log.AccessAccepted,
Reason: "",
Email: request.User.Email,
})
newError("tunnelling request to ", dest).WriteToLog(session.ExportIDToError(ctx))
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)
link, err := dispatcher.Dispatch(ctx, dest)
if err != nil {
return err
}
responseDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
bufferedWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
responseWriter, err := WriteTCPResponse(request, bufferedWriter)
if err != nil {
return newError("failed to write response").Base(err)
}
{
payload, err := link.Reader.ReadMultiBuffer()
if err != nil {
return err
}
if err := responseWriter.WriteMultiBuffer(payload); err != nil {
return err
}
}
if err := bufferedWriter.SetBuffered(false); err != nil {
return err
}
if err := buf.Copy(link.Reader, responseWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport all TCP response").Base(err)
}
return nil
}
requestDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
if err := buf.Copy(bodyReader, link.Writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport all TCP request").Base(err)
}
return nil
}
var requestDoneAndCloseWriter = task.OnSuccess(requestDone, task.Close(link.Writer))
if err := task.Run(ctx, requestDoneAndCloseWriter, responseDone); err != nil {
common.Interrupt(link.Reader)
common.Interrupt(link.Writer)
return newError("connection ends").Base(err)
}
return nil
}
func init() {
common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewServer(ctx, config.(*ServerConfig))
}))
}
v2ray-core-4.34.0/proxy/shadowsocks/shadowsocks.go 0000664 0000000 0000000 00000000433 13774574720 0022203 0 ustar 00root root 0000000 0000000 // Package shadowsocks provides compatible functionality to Shadowsocks.
//
// Shadowsocks client and server are implemented as outbound and inbound respectively in V2Ray's term.
//
// R.I.P Shadowsocks
package shadowsocks
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/proxy/socks/ 0000775 0000000 0000000 00000000000 13774574720 0016116 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/socks/client.go 0000664 0000000 0000000 00000011460 13774574720 0017725 0 ustar 00root root 0000000 0000000 // +build !confonly
package socks
import (
"context"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/retry"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/policy"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
)
// Client is a Socks5 client.
type Client struct {
serverPicker protocol.ServerPicker
policyManager policy.Manager
}
// NewClient create a new Socks5 client based on the given config.
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
serverList := protocol.NewServerList()
for _, rec := range config.Server {
s, err := protocol.NewServerSpecFromPB(rec)
if err != nil {
return nil, newError("failed to get server spec").Base(err)
}
serverList.AddServer(s)
}
if serverList.Size() == 0 {
return nil, newError("0 target server")
}
v := core.MustFromContext(ctx)
return &Client{
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
}, nil
}
// Process implements proxy.Outbound.Process.
func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
outbound := session.OutboundFromContext(ctx)
if outbound == nil || !outbound.Target.IsValid() {
return newError("target not specified.")
}
// Destination of the inner request.
destination := outbound.Target
// Outbound server.
var server *protocol.ServerSpec
// Outbound server's destination.
var dest net.Destination
// Connection to the outbound server.
var conn internet.Connection
if err := retry.ExponentialBackoff(5, 100).On(func() error {
server = c.serverPicker.PickServer()
dest = server.Destination()
rawConn, err := dialer.Dial(ctx, dest)
if err != nil {
return err
}
conn = rawConn
return nil
}); err != nil {
return newError("failed to find an available destination").Base(err)
}
defer func() {
if err := conn.Close(); err != nil {
newError("failed to closed connection").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
}()
p := c.policyManager.ForLevel(0)
request := &protocol.RequestHeader{
Version: socks5Version,
Command: protocol.RequestCommandTCP,
Address: destination.Address,
Port: destination.Port,
}
if destination.Network == net.Network_UDP {
request.Command = protocol.RequestCommandUDP
}
user := server.PickUser()
if user != nil {
request.User = user
p = c.policyManager.ForLevel(user.Level)
}
if err := conn.SetDeadline(time.Now().Add(p.Timeouts.Handshake)); err != nil {
newError("failed to set deadline for handshake").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
udpRequest, err := ClientHandshake(request, conn, conn)
if err != nil {
return newError("failed to establish connection to server").AtWarning().Base(err)
}
if udpRequest != nil {
if udpRequest.Address == net.AnyIP || udpRequest.Address == net.AnyIPv6 {
udpRequest.Address = dest.Address
}
}
if err := conn.SetDeadline(time.Time{}); err != nil {
newError("failed to clear deadline after handshake").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, p.Timeouts.ConnectionIdle)
var requestFunc func() error
var responseFunc func() error
if request.Command == protocol.RequestCommandTCP {
requestFunc = func() error {
defer timer.SetTimeout(p.Timeouts.DownlinkOnly)
return buf.Copy(link.Reader, buf.NewWriter(conn), buf.UpdateActivity(timer))
}
responseFunc = func() error {
defer timer.SetTimeout(p.Timeouts.UplinkOnly)
return buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer))
}
} else if request.Command == protocol.RequestCommandUDP {
udpConn, err := dialer.Dial(ctx, udpRequest.Destination())
if err != nil {
return newError("failed to create UDP connection").Base(err)
}
defer udpConn.Close()
requestFunc = func() error {
defer timer.SetTimeout(p.Timeouts.DownlinkOnly)
return buf.Copy(link.Reader, &buf.SequentialWriter{Writer: NewUDPWriter(request, udpConn)}, buf.UpdateActivity(timer))
}
responseFunc = func() error {
defer timer.SetTimeout(p.Timeouts.UplinkOnly)
reader := &UDPReader{reader: udpConn}
return buf.Copy(reader, link.Writer, buf.UpdateActivity(timer))
}
}
var responseDonePost = task.OnSuccess(responseFunc, task.Close(link.Writer))
if err := task.Run(ctx, requestFunc, responseDonePost); err != nil {
return newError("connection ends").Base(err)
}
return nil
}
func init() {
common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewClient(ctx, config.(*ClientConfig))
}))
}
v2ray-core-4.34.0/proxy/socks/config.go 0000664 0000000 0000000 00000001030 13774574720 0017704 0 ustar 00root root 0000000 0000000 // +build !confonly
package socks
import "v2ray.com/core/common/protocol"
func (a *Account) Equals(another protocol.Account) bool {
if account, ok := another.(*Account); ok {
return a.Username == account.Username
}
return false
}
func (a *Account) AsAccount() (protocol.Account, error) {
return a, nil
}
func (c *ServerConfig) HasAccount(username, password string) bool {
if c.Accounts == nil {
return false
}
storedPassed, found := c.Accounts[username]
if !found {
return false
}
return storedPassed == password
}
v2ray-core-4.34.0/proxy/socks/config.pb.go 0000664 0000000 0000000 00000036313 13774574720 0020320 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/socks/config.proto
package socks
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
net "v2ray.com/core/common/net"
protocol "v2ray.com/core/common/protocol"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// AuthType is the authentication type of Socks proxy.
type AuthType int32
const (
// NO_AUTH is for anounymous authentication.
AuthType_NO_AUTH AuthType = 0
// PASSWORD is for username/password authentication.
AuthType_PASSWORD AuthType = 1
)
// Enum value maps for AuthType.
var (
AuthType_name = map[int32]string{
0: "NO_AUTH",
1: "PASSWORD",
}
AuthType_value = map[string]int32{
"NO_AUTH": 0,
"PASSWORD": 1,
}
)
func (x AuthType) Enum() *AuthType {
p := new(AuthType)
*p = x
return p
}
func (x AuthType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (AuthType) Descriptor() protoreflect.EnumDescriptor {
return file_proxy_socks_config_proto_enumTypes[0].Descriptor()
}
func (AuthType) Type() protoreflect.EnumType {
return &file_proxy_socks_config_proto_enumTypes[0]
}
func (x AuthType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use AuthType.Descriptor instead.
func (AuthType) EnumDescriptor() ([]byte, []int) {
return file_proxy_socks_config_proto_rawDescGZIP(), []int{0}
}
// Account represents a Socks account.
type Account struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
}
func (x *Account) Reset() {
*x = Account{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_socks_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Account) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Account) ProtoMessage() {}
func (x *Account) ProtoReflect() protoreflect.Message {
mi := &file_proxy_socks_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Account.ProtoReflect.Descriptor instead.
func (*Account) Descriptor() ([]byte, []int) {
return file_proxy_socks_config_proto_rawDescGZIP(), []int{0}
}
func (x *Account) GetUsername() string {
if x != nil {
return x.Username
}
return ""
}
func (x *Account) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
// ServerConfig is the protobuf config for Socks server.
type ServerConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
AuthType AuthType `protobuf:"varint,1,opt,name=auth_type,json=authType,proto3,enum=v2ray.core.proxy.socks.AuthType" json:"auth_type,omitempty"`
Accounts map[string]string `protobuf:"bytes,2,rep,name=accounts,proto3" json:"accounts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Address *net.IPOrDomain `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"`
UdpEnabled bool `protobuf:"varint,4,opt,name=udp_enabled,json=udpEnabled,proto3" json:"udp_enabled,omitempty"`
// Deprecated: Do not use.
Timeout uint32 `protobuf:"varint,5,opt,name=timeout,proto3" json:"timeout,omitempty"`
UserLevel uint32 `protobuf:"varint,6,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
}
func (x *ServerConfig) Reset() {
*x = ServerConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_socks_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServerConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServerConfig) ProtoMessage() {}
func (x *ServerConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_socks_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServerConfig.ProtoReflect.Descriptor instead.
func (*ServerConfig) Descriptor() ([]byte, []int) {
return file_proxy_socks_config_proto_rawDescGZIP(), []int{1}
}
func (x *ServerConfig) GetAuthType() AuthType {
if x != nil {
return x.AuthType
}
return AuthType_NO_AUTH
}
func (x *ServerConfig) GetAccounts() map[string]string {
if x != nil {
return x.Accounts
}
return nil
}
func (x *ServerConfig) GetAddress() *net.IPOrDomain {
if x != nil {
return x.Address
}
return nil
}
func (x *ServerConfig) GetUdpEnabled() bool {
if x != nil {
return x.UdpEnabled
}
return false
}
// Deprecated: Do not use.
func (x *ServerConfig) GetTimeout() uint32 {
if x != nil {
return x.Timeout
}
return 0
}
func (x *ServerConfig) GetUserLevel() uint32 {
if x != nil {
return x.UserLevel
}
return 0
}
// ClientConfig is the protobuf config for Socks client.
type ClientConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Sever is a list of Socks server addresses.
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"`
}
func (x *ClientConfig) Reset() {
*x = ClientConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_socks_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ClientConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientConfig) ProtoMessage() {}
func (x *ClientConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_socks_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead.
func (*ClientConfig) Descriptor() ([]byte, []int) {
return file_proxy_socks_config_proto_rawDescGZIP(), []int{2}
}
func (x *ClientConfig) GetServer() []*protocol.ServerEndpoint {
if x != nil {
return x.Server
}
return nil
}
var File_proxy_socks_config_proto protoreflect.FileDescriptor
var file_proxy_socks_config_proto_rawDesc = []byte{
0x0a, 0x18, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x2f, 0x63, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x76, 0x32, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x6f, 0x63,
0x6b, 0x73, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
0x41, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73,
0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73,
0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x22, 0xf5, 0x02, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x12, 0x3d, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x79, 0x70, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x2e,
0x41, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x54, 0x79,
0x70, 0x65, 0x12, 0x4e, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x02,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x2e, 0x53, 0x65,
0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x73, 0x12, 0x3b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72,
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12,
0x1f, 0x0a, 0x0b, 0x75, 0x64, 0x70, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x04,
0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x64, 0x70, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
0x12, 0x1c, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28,
0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1d,
0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01,
0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x3b, 0x0a,
0x0d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x52, 0x0a, 0x0c, 0x43, 0x6c,
0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x42, 0x0a, 0x06, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e,
0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2a, 0x25,
0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x4e, 0x4f,
0x5f, 0x41, 0x55, 0x54, 0x48, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x41, 0x53, 0x53, 0x57,
0x4f, 0x52, 0x44, 0x10, 0x01, 0x42, 0x53, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x6f,
0x63, 0x6b, 0x73, 0x50, 0x01, 0x5a, 0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x6f, 0x63, 0x6b,
0x73, 0xaa, 0x02, 0x16, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50,
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_proxy_socks_config_proto_rawDescOnce sync.Once
file_proxy_socks_config_proto_rawDescData = file_proxy_socks_config_proto_rawDesc
)
func file_proxy_socks_config_proto_rawDescGZIP() []byte {
file_proxy_socks_config_proto_rawDescOnce.Do(func() {
file_proxy_socks_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_socks_config_proto_rawDescData)
})
return file_proxy_socks_config_proto_rawDescData
}
var file_proxy_socks_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_proxy_socks_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_proxy_socks_config_proto_goTypes = []interface{}{
(AuthType)(0), // 0: v2ray.core.proxy.socks.AuthType
(*Account)(nil), // 1: v2ray.core.proxy.socks.Account
(*ServerConfig)(nil), // 2: v2ray.core.proxy.socks.ServerConfig
(*ClientConfig)(nil), // 3: v2ray.core.proxy.socks.ClientConfig
nil, // 4: v2ray.core.proxy.socks.ServerConfig.AccountsEntry
(*net.IPOrDomain)(nil), // 5: v2ray.core.common.net.IPOrDomain
(*protocol.ServerEndpoint)(nil), // 6: v2ray.core.common.protocol.ServerEndpoint
}
var file_proxy_socks_config_proto_depIdxs = []int32{
0, // 0: v2ray.core.proxy.socks.ServerConfig.auth_type:type_name -> v2ray.core.proxy.socks.AuthType
4, // 1: v2ray.core.proxy.socks.ServerConfig.accounts:type_name -> v2ray.core.proxy.socks.ServerConfig.AccountsEntry
5, // 2: v2ray.core.proxy.socks.ServerConfig.address:type_name -> v2ray.core.common.net.IPOrDomain
6, // 3: v2ray.core.proxy.socks.ClientConfig.server:type_name -> v2ray.core.common.protocol.ServerEndpoint
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_proxy_socks_config_proto_init() }
func file_proxy_socks_config_proto_init() {
if File_proxy_socks_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_socks_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Account); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_socks_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ServerConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_socks_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ClientConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_socks_config_proto_rawDesc,
NumEnums: 1,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_socks_config_proto_goTypes,
DependencyIndexes: file_proxy_socks_config_proto_depIdxs,
EnumInfos: file_proxy_socks_config_proto_enumTypes,
MessageInfos: file_proxy_socks_config_proto_msgTypes,
}.Build()
File_proxy_socks_config_proto = out.File
file_proxy_socks_config_proto_rawDesc = nil
file_proxy_socks_config_proto_goTypes = nil
file_proxy_socks_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/socks/config.proto 0000664 0000000 0000000 00000002132 13774574720 0020446 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.socks;
option csharp_namespace = "V2Ray.Core.Proxy.Socks";
option go_package = "v2ray.com/core/proxy/socks";
option java_package = "com.v2ray.core.proxy.socks";
option java_multiple_files = true;
import "common/net/address.proto";
import "common/protocol/server_spec.proto";
// Account represents a Socks account.
message Account {
string username = 1;
string password = 2;
}
// AuthType is the authentication type of Socks proxy.
enum AuthType {
// NO_AUTH is for anounymous authentication.
NO_AUTH = 0;
// PASSWORD is for username/password authentication.
PASSWORD = 1;
}
// ServerConfig is the protobuf config for Socks server.
message ServerConfig {
AuthType auth_type = 1;
map accounts = 2;
v2ray.core.common.net.IPOrDomain address = 3;
bool udp_enabled = 4;
uint32 timeout = 5 [deprecated = true];
uint32 user_level = 6;
}
// ClientConfig is the protobuf config for Socks client.
message ClientConfig {
// Sever is a list of Socks server addresses.
repeated v2ray.core.common.protocol.ServerEndpoint server = 1;
}
v2ray-core-4.34.0/proxy/socks/errors.generated.go 0000664 0000000 0000000 00000000313 13774574720 0021713 0 ustar 00root root 0000000 0000000 package socks
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/socks/protocol.go 0000664 0000000 0000000 00000031604 13774574720 0020312 0 ustar 00root root 0000000 0000000 // +build !confonly
package socks
import (
"encoding/binary"
"io"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
)
const (
socks5Version = 0x05
socks4Version = 0x04
cmdTCPConnect = 0x01
cmdTCPBind = 0x02
cmdUDPAssociate = 0x03
cmdTorResolve = 0xF0
cmdTorResolvePTR = 0xF1
socks4RequestGranted = 90
socks4RequestRejected = 91
authNotRequired = 0x00
// authGssAPI = 0x01
authPassword = 0x02
authNoMatchingMethod = 0xFF
statusSuccess = 0x00
statusCmdNotSupport = 0x07
)
var addrParser = protocol.NewAddressParser(
protocol.AddressFamilyByte(0x01, net.AddressFamilyIPv4),
protocol.AddressFamilyByte(0x04, net.AddressFamilyIPv6),
protocol.AddressFamilyByte(0x03, net.AddressFamilyDomain),
)
type ServerSession struct {
config *ServerConfig
address net.Address
port net.Port
clientAddress net.Address
}
func (s *ServerSession) handshake4(cmd byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {
if s.config.AuthType == AuthType_PASSWORD {
writeSocks4Response(writer, socks4RequestRejected, net.AnyIP, net.Port(0))
return nil, newError("socks 4 is not allowed when auth is required.")
}
var port net.Port
var address net.Address
{
buffer := buf.StackNew()
if _, err := buffer.ReadFullFrom(reader, 6); err != nil {
buffer.Release()
return nil, newError("insufficient header").Base(err)
}
port = net.PortFromBytes(buffer.BytesRange(0, 2))
address = net.IPAddress(buffer.BytesRange(2, 6))
buffer.Release()
}
if _, err := ReadUntilNull(reader); /* user id */ err != nil {
return nil, err
}
if address.IP()[0] == 0x00 {
domain, err := ReadUntilNull(reader)
if err != nil {
return nil, newError("failed to read domain for socks 4a").Base(err)
}
address = net.DomainAddress(domain)
}
switch cmd {
case cmdTCPConnect:
request := &protocol.RequestHeader{
Command: protocol.RequestCommandTCP,
Address: address,
Port: port,
Version: socks4Version,
}
if err := writeSocks4Response(writer, socks4RequestGranted, net.AnyIP, net.Port(0)); err != nil {
return nil, err
}
return request, nil
default:
writeSocks4Response(writer, socks4RequestRejected, net.AnyIP, net.Port(0))
return nil, newError("unsupported command: ", cmd)
}
}
func (s *ServerSession) auth5(nMethod byte, reader io.Reader, writer io.Writer) (username string, err error) {
buffer := buf.StackNew()
defer buffer.Release()
if _, err = buffer.ReadFullFrom(reader, int32(nMethod)); err != nil {
return "", newError("failed to read auth methods").Base(err)
}
var expectedAuth byte = authNotRequired
if s.config.AuthType == AuthType_PASSWORD {
expectedAuth = authPassword
}
if !hasAuthMethod(expectedAuth, buffer.BytesRange(0, int32(nMethod))) {
writeSocks5AuthenticationResponse(writer, socks5Version, authNoMatchingMethod)
return "", newError("no matching auth method")
}
if err := writeSocks5AuthenticationResponse(writer, socks5Version, expectedAuth); err != nil {
return "", newError("failed to write auth response").Base(err)
}
if expectedAuth == authPassword {
username, password, err := ReadUsernamePassword(reader)
if err != nil {
return "", newError("failed to read username and password for authentication").Base(err)
}
if !s.config.HasAccount(username, password) {
writeSocks5AuthenticationResponse(writer, 0x01, 0xFF)
return "", newError("invalid username or password")
}
if err := writeSocks5AuthenticationResponse(writer, 0x01, 0x00); err != nil {
return "", newError("failed to write auth response").Base(err)
}
return username, nil
}
return "", nil
}
func (s *ServerSession) handshake5(nMethod byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {
var (
username string
err error
)
if username, err = s.auth5(nMethod, reader, writer); err != nil {
return nil, err
}
var cmd byte
{
buffer := buf.StackNew()
if _, err := buffer.ReadFullFrom(reader, 3); err != nil {
buffer.Release()
return nil, newError("failed to read request").Base(err)
}
cmd = buffer.Byte(1)
buffer.Release()
}
request := new(protocol.RequestHeader)
if username != "" {
request.User = &protocol.MemoryUser{Email: username}
}
switch cmd {
case cmdTCPConnect, cmdTorResolve, cmdTorResolvePTR:
// We don't have a solution for Tor case now. Simply treat it as connect command.
request.Command = protocol.RequestCommandTCP
case cmdUDPAssociate:
if !s.config.UdpEnabled {
writeSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0))
return nil, newError("UDP is not enabled.")
}
request.Command = protocol.RequestCommandUDP
case cmdTCPBind:
writeSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0))
return nil, newError("TCP bind is not supported.")
default:
writeSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0))
return nil, newError("unknown command ", cmd)
}
request.Version = socks5Version
addr, port, err := addrParser.ReadAddressPort(nil, reader)
if err != nil {
return nil, newError("failed to read address").Base(err)
}
request.Address = addr
request.Port = port
responseAddress := s.address
responsePort := s.port
//nolint:gocritic // Use if else chain for clarity
if request.Command == protocol.RequestCommandUDP {
if s.config.Address != nil {
// Use configured IP as remote address in the response to UdpAssociate
responseAddress = s.config.Address.AsAddress()
} else if s.clientAddress == net.LocalHostIP || s.clientAddress == net.LocalHostIPv6 {
// For localhost clients use loopback IP
responseAddress = s.clientAddress
} else {
// For non-localhost clients use inbound listening address
responseAddress = s.address
}
}
if err := writeSocks5Response(writer, statusSuccess, responseAddress, responsePort); err != nil {
return nil, err
}
return request, nil
}
// Handshake performs a Socks4/4a/5 handshake.
func (s *ServerSession) Handshake(reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {
buffer := buf.StackNew()
if _, err := buffer.ReadFullFrom(reader, 2); err != nil {
buffer.Release()
return nil, newError("insufficient header").Base(err)
}
version := buffer.Byte(0)
cmd := buffer.Byte(1)
buffer.Release()
switch version {
case socks4Version:
return s.handshake4(cmd, reader, writer)
case socks5Version:
return s.handshake5(cmd, reader, writer)
default:
return nil, newError("unknown Socks version: ", version)
}
}
// ReadUsernamePassword reads Socks 5 username/password message from the given reader.
// +----+------+----------+------+----------+
// |VER | ULEN | UNAME | PLEN | PASSWD |
// +----+------+----------+------+----------+
// | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
// +----+------+----------+------+----------+
func ReadUsernamePassword(reader io.Reader) (string, string, error) {
buffer := buf.StackNew()
defer buffer.Release()
if _, err := buffer.ReadFullFrom(reader, 2); err != nil {
return "", "", err
}
nUsername := int32(buffer.Byte(1))
buffer.Clear()
if _, err := buffer.ReadFullFrom(reader, nUsername); err != nil {
return "", "", err
}
username := buffer.String()
buffer.Clear()
if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
return "", "", err
}
nPassword := int32(buffer.Byte(0))
buffer.Clear()
if _, err := buffer.ReadFullFrom(reader, nPassword); err != nil {
return "", "", err
}
password := buffer.String()
return username, password, nil
}
// ReadUntilNull reads content from given reader, until a null (0x00) byte.
func ReadUntilNull(reader io.Reader) (string, error) {
b := buf.StackNew()
defer b.Release()
for {
_, err := b.ReadFullFrom(reader, 1)
if err != nil {
return "", err
}
if b.Byte(b.Len()-1) == 0x00 {
b.Resize(0, b.Len()-1)
return b.String(), nil
}
if b.IsFull() {
return "", newError("buffer overrun")
}
}
}
func hasAuthMethod(expectedAuth byte, authCandidates []byte) bool {
for _, a := range authCandidates {
if a == expectedAuth {
return true
}
}
return false
}
func writeSocks5AuthenticationResponse(writer io.Writer, version byte, auth byte) error {
return buf.WriteAllBytes(writer, []byte{version, auth})
}
func writeSocks5Response(writer io.Writer, errCode byte, address net.Address, port net.Port) error {
buffer := buf.New()
defer buffer.Release()
common.Must2(buffer.Write([]byte{socks5Version, errCode, 0x00 /* reserved */}))
if err := addrParser.WriteAddressPort(buffer, address, port); err != nil {
return err
}
return buf.WriteAllBytes(writer, buffer.Bytes())
}
func writeSocks4Response(writer io.Writer, errCode byte, address net.Address, port net.Port) error {
buffer := buf.StackNew()
defer buffer.Release()
common.Must(buffer.WriteByte(0x00))
common.Must(buffer.WriteByte(errCode))
portBytes := buffer.Extend(2)
binary.BigEndian.PutUint16(portBytes, port.Value())
common.Must2(buffer.Write(address.IP()))
return buf.WriteAllBytes(writer, buffer.Bytes())
}
func DecodeUDPPacket(packet *buf.Buffer) (*protocol.RequestHeader, error) {
if packet.Len() < 5 {
return nil, newError("insufficient length of packet.")
}
request := &protocol.RequestHeader{
Version: socks5Version,
Command: protocol.RequestCommandUDP,
}
// packet[0] and packet[1] are reserved
if packet.Byte(2) != 0 /* fragments */ {
return nil, newError("discarding fragmented payload.")
}
packet.Advance(3)
addr, port, err := addrParser.ReadAddressPort(nil, packet)
if err != nil {
return nil, newError("failed to read UDP header").Base(err)
}
request.Address = addr
request.Port = port
return request, nil
}
func EncodeUDPPacket(request *protocol.RequestHeader, data []byte) (*buf.Buffer, error) {
b := buf.New()
common.Must2(b.Write([]byte{0, 0, 0 /* Fragment */}))
if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil {
b.Release()
return nil, err
}
common.Must2(b.Write(data))
return b, nil
}
type UDPReader struct {
reader io.Reader
}
func NewUDPReader(reader io.Reader) *UDPReader {
return &UDPReader{reader: reader}
}
func (r *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
b := buf.New()
if _, err := b.ReadFrom(r.reader); err != nil {
return nil, err
}
if _, err := DecodeUDPPacket(b); err != nil {
return nil, err
}
return buf.MultiBuffer{b}, nil
}
type UDPWriter struct {
request *protocol.RequestHeader
writer io.Writer
}
func NewUDPWriter(request *protocol.RequestHeader, writer io.Writer) *UDPWriter {
return &UDPWriter{
request: request,
writer: writer,
}
}
// Write implements io.Writer.
func (w *UDPWriter) Write(b []byte) (int, error) {
eb, err := EncodeUDPPacket(w.request, b)
if err != nil {
return 0, err
}
defer eb.Release()
if _, err := w.writer.Write(eb.Bytes()); err != nil {
return 0, err
}
return len(b), nil
}
func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {
authByte := byte(authNotRequired)
if request.User != nil {
authByte = byte(authPassword)
}
b := buf.New()
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
}
b.Clear()
if _, err := b.ReadFullFrom(reader, 2); err != nil {
return nil, err
}
if b.Byte(0) != socks5Version {
return nil, newError("unexpected server version: ", b.Byte(0)).AtWarning()
}
if b.Byte(1) != authByte {
return nil, newError("auth method not supported.").AtWarning()
}
if authByte == authPassword {
b.Clear()
if _, err := b.ReadFullFrom(reader, 2); err != nil {
return nil, err
}
if b.Byte(1) != 0x00 {
return nil, newError("server rejects account: ", b.Byte(1))
}
}
b.Clear()
command := byte(cmdTCPConnect)
if request.Command == protocol.RequestCommandUDP {
command = byte(cmdUDPAssociate)
}
common.Must2(b.Write([]byte{socks5Version, command, 0x00 /* reserved */}))
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
}
b.Clear()
if _, err := b.ReadFullFrom(reader, 3); err != nil {
return nil, err
}
resp := b.Byte(1)
if resp != 0x00 {
return nil, newError("server rejects request: ", resp)
}
b.Clear()
address, port, err := addrParser.ReadAddressPort(b, reader)
if err != nil {
return nil, err
}
if request.Command == protocol.RequestCommandUDP {
udpRequest := &protocol.RequestHeader{
Version: socks5Version,
Command: protocol.RequestCommandUDP,
Address: address,
Port: port,
}
return udpRequest, nil
}
return nil, nil
}
v2ray-core-4.34.0/proxy/socks/protocol_test.go 0000664 0000000 0000000 00000005524 13774574720 0021353 0 ustar 00root root 0000000 0000000 package socks_test
import (
"bytes"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
. "v2ray.com/core/proxy/socks"
)
func TestUDPEncoding(t *testing.T) {
b := buf.New()
request := &protocol.RequestHeader{
Address: net.IPAddress([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}),
Port: 1024,
}
writer := &buf.SequentialWriter{Writer: NewUDPWriter(request, b)}
content := []byte{'a'}
payload := buf.New()
payload.Write(content)
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{payload}))
reader := NewUDPReader(b)
decodedPayload, err := reader.ReadMultiBuffer()
common.Must(err)
if r := cmp.Diff(decodedPayload[0].Bytes(), content); r != "" {
t.Error(r)
}
}
func TestReadUsernamePassword(t *testing.T) {
testCases := []struct {
Input []byte
Username string
Password string
Error bool
}{
{
Input: []byte{0x05, 0x01, 'a', 0x02, 'b', 'c'},
Username: "a",
Password: "bc",
},
{
Input: []byte{0x05, 0x18, 'a', 0x02, 'b', 'c'},
Error: true,
},
}
for _, testCase := range testCases {
reader := bytes.NewReader(testCase.Input)
username, password, err := ReadUsernamePassword(reader)
if testCase.Error {
if err == nil {
t.Error("for input: ", testCase.Input, " expect error, but actually nil")
}
} else {
if err != nil {
t.Error("for input: ", testCase.Input, " expect no error, but actually ", err.Error())
}
if testCase.Username != username {
t.Error("for input: ", testCase.Input, " expect username ", testCase.Username, " but actually ", username)
}
if testCase.Password != password {
t.Error("for input: ", testCase.Input, " expect passowrd ", testCase.Password, " but actually ", password)
}
}
}
}
func TestReadUntilNull(t *testing.T) {
testCases := []struct {
Input []byte
Output string
Error bool
}{
{
Input: []byte{'a', 'b', 0x00},
Output: "ab",
},
{
Input: []byte{'a'},
Error: true,
},
}
for _, testCase := range testCases {
reader := bytes.NewReader(testCase.Input)
value, err := ReadUntilNull(reader)
if testCase.Error {
if err == nil {
t.Error("for input: ", testCase.Input, " expect error, but actually nil")
}
} else {
if err != nil {
t.Error("for input: ", testCase.Input, " expect no error, but actually ", err.Error())
}
if testCase.Output != value {
t.Error("for input: ", testCase.Input, " expect output ", testCase.Output, " but actually ", value)
}
}
}
}
func BenchmarkReadUsernamePassword(b *testing.B) {
input := []byte{0x05, 0x01, 'a', 0x02, 'b', 'c'}
buffer := buf.New()
buffer.Write(input)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _, err := ReadUsernamePassword(buffer)
common.Must(err)
buffer.Clear()
buffer.Extend(int32(len(input)))
}
}
v2ray-core-4.34.0/proxy/socks/server.go 0000664 0000000 0000000 00000016505 13774574720 0017762 0 ustar 00root root 0000000 0000000 // +build !confonly
package socks
import (
"context"
"io"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
udp_proto "v2ray.com/core/common/protocol/udp"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features"
"v2ray.com/core/features/policy"
"v2ray.com/core/features/routing"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/udp"
)
// Server is a SOCKS 5 proxy server
type Server struct {
config *ServerConfig
policyManager policy.Manager
}
// NewServer creates a new Server object.
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
v := core.MustFromContext(ctx)
s := &Server{
config: config,
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
}
return s, nil
}
func (s *Server) policy() policy.Session {
config := s.config
p := s.policyManager.ForLevel(config.UserLevel)
if config.Timeout > 0 {
features.PrintDeprecatedFeatureWarning("Socks timeout")
}
if config.Timeout > 0 && config.UserLevel == 0 {
p.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second
}
return p
}
// Network implements proxy.Inbound.
func (s *Server) Network() []net.Network {
list := []net.Network{net.Network_TCP}
if s.config.UdpEnabled {
list = append(list, net.Network_UDP)
}
return list
}
// Process implements proxy.Inbound.
func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {
if inbound := session.InboundFromContext(ctx); inbound != nil {
inbound.User = &protocol.MemoryUser{
Level: s.config.UserLevel,
}
}
switch network {
case net.Network_TCP:
return s.processTCP(ctx, conn, dispatcher)
case net.Network_UDP:
return s.handleUDPPayload(ctx, conn, dispatcher)
default:
return newError("unknown network: ", network)
}
}
func (s *Server) processTCP(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error {
plcy := s.policy()
if err := conn.SetReadDeadline(time.Now().Add(plcy.Timeouts.Handshake)); err != nil {
newError("failed to set deadline").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
inbound := session.InboundFromContext(ctx)
if inbound == nil || !inbound.Gateway.IsValid() {
return newError("inbound gateway not specified")
}
svrSession := &ServerSession{
config: s.config,
address: inbound.Gateway.Address,
port: inbound.Gateway.Port,
clientAddress: inbound.Source.Address,
}
reader := &buf.BufferedReader{Reader: buf.NewReader(conn)}
request, err := svrSession.Handshake(reader, conn)
if err != nil {
if inbound != nil && inbound.Source.IsValid() {
log.Record(&log.AccessMessage{
From: inbound.Source,
To: "",
Status: log.AccessRejected,
Reason: err,
})
}
return newError("failed to read request").Base(err)
}
if request.User != nil {
inbound.User.Email = request.User.Email
}
if err := conn.SetReadDeadline(time.Time{}); err != nil {
newError("failed to clear deadline").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
if request.Command == protocol.RequestCommandTCP {
dest := request.Destination()
newError("TCP Connect request to ", dest).WriteToLog(session.ExportIDToError(ctx))
if inbound != nil && inbound.Source.IsValid() {
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: inbound.Source,
To: dest,
Status: log.AccessAccepted,
Reason: "",
})
}
return s.transport(ctx, reader, conn, dest, dispatcher)
}
if request.Command == protocol.RequestCommandUDP {
return s.handleUDP(conn)
}
return nil
}
func (*Server) handleUDP(c io.Reader) error {
// The TCP connection closes after this method returns. We need to wait until
// the client closes it.
return common.Error2(io.Copy(buf.DiscardBytes, c))
}
func (s *Server) transport(ctx context.Context, reader io.Reader, writer io.Writer, dest net.Destination, dispatcher routing.Dispatcher) error {
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, s.policy().Timeouts.ConnectionIdle)
plcy := s.policy()
ctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer)
link, err := dispatcher.Dispatch(ctx, dest)
if err != nil {
return err
}
requestDone := func() error {
defer timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
if err := buf.Copy(buf.NewReader(reader), link.Writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport all TCP request").Base(err)
}
return nil
}
responseDone := func() error {
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
v2writer := buf.NewWriter(writer)
if err := buf.Copy(link.Reader, v2writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport all TCP response").Base(err)
}
return nil
}
var requestDonePost = task.OnSuccess(requestDone, task.Close(link.Writer))
if err := task.Run(ctx, requestDonePost, responseDone); err != nil {
common.Interrupt(link.Reader)
common.Interrupt(link.Writer)
return newError("connection ends").Base(err)
}
return nil
}
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) {
payload := packet.Payload
newError("writing back UDP response with ", payload.Len(), " bytes").AtDebug().WriteToLog(session.ExportIDToError(ctx))
request := protocol.RequestHeaderFromContext(ctx)
if request == nil {
return
}
udpMessage, err := EncodeUDPPacket(request, payload.Bytes())
payload.Release()
defer udpMessage.Release()
if err != nil {
newError("failed to write UDP response").AtWarning().Base(err).WriteToLog(session.ExportIDToError(ctx))
}
conn.Write(udpMessage.Bytes())
})
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() {
newError("client UDP connection from ", inbound.Source).WriteToLog(session.ExportIDToError(ctx))
}
reader := buf.NewPacketReader(conn)
for {
mpayload, err := reader.ReadMultiBuffer()
if err != nil {
return err
}
for _, payload := range mpayload {
request, err := DecodeUDPPacket(payload)
if err != nil {
newError("failed to parse UDP request").Base(err).WriteToLog(session.ExportIDToError(ctx))
payload.Release()
continue
}
if payload.IsEmpty() {
payload.Release()
continue
}
currentPacketCtx := ctx
newError("send packet to ", request.Destination(), " with ", payload.Len(), " bytes").AtDebug().WriteToLog(session.ExportIDToError(ctx))
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() {
currentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: inbound.Source,
To: request.Destination(),
Status: log.AccessAccepted,
Reason: "",
})
}
currentPacketCtx = protocol.ContextWithRequestHeader(currentPacketCtx, request)
udpServer.Dispatch(currentPacketCtx, request.Destination(), payload)
}
}
}
func init() {
common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewServer(ctx, config.(*ServerConfig))
}))
}
v2ray-core-4.34.0/proxy/socks/socks.go 0000664 0000000 0000000 00000000216 13774574720 0017566 0 ustar 00root root 0000000 0000000 // Package socks provides implements of Socks protocol 4, 4a and 5.
package socks
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/proxy/trojan/ 0000775 0000000 0000000 00000000000 13774574720 0016271 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/trojan/client.go 0000664 0000000 0000000 00000010267 13774574720 0020104 0 ustar 00root root 0000000 0000000 // +build !confonly
package trojan
import (
"context"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/retry"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/policy"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
)
// Client is a inbound handler for trojan protocol
type Client struct {
serverPicker protocol.ServerPicker
policyManager policy.Manager
}
// NewClient create a new trojan client.
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
serverList := protocol.NewServerList()
for _, rec := range config.Server {
s, err := protocol.NewServerSpecFromPB(rec)
if err != nil {
return nil, newError("failed to parse server spec").Base(err)
}
serverList.AddServer(s)
}
if serverList.Size() == 0 {
return nil, newError("0 server")
}
v := core.MustFromContext(ctx)
client := &Client{
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
}
return client, nil
}
// Process implements OutboundHandler.Process().
func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
outbound := session.OutboundFromContext(ctx)
if outbound == nil || !outbound.Target.IsValid() {
return newError("target not specified")
}
destination := outbound.Target
network := destination.Network
var server *protocol.ServerSpec
var conn internet.Connection
err := retry.ExponentialBackoff(5, 100).On(func() error {
server = c.serverPicker.PickServer()
rawConn, err := dialer.Dial(ctx, server.Destination())
if err != nil {
return err
}
conn = rawConn
return nil
})
if err != nil {
return newError("failed to find an available destination").AtWarning().Base(err)
}
newError("tunneling request to ", destination, " via ", server.Destination()).WriteToLog(session.ExportIDToError(ctx))
defer conn.Close()
user := server.PickUser()
account, ok := user.Account.(*MemoryAccount)
if !ok {
return newError("user account is not valid")
}
sessionPolicy := c.policyManager.ForLevel(user.Level)
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
var bodyWriter buf.Writer
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
connWriter := &ConnWriter{Writer: bufferWriter, Target: destination, Account: account}
if destination.Network == net.Network_UDP {
bodyWriter = &PacketWriter{Writer: connWriter, Target: destination}
} else {
bodyWriter = connWriter
}
// write some request payload to buffer
if err = buf.CopyOnceTimeout(link.Reader, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
return newError("failed to write A request payload").Base(err).AtWarning()
}
// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer
if err = bufferWriter.SetBuffered(false); err != nil {
return newError("failed to flush payload").Base(err).AtWarning()
}
if err = buf.Copy(link.Reader, bodyWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transfer request payload").Base(err).AtInfo()
}
return nil
}
getResponse := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
var reader buf.Reader
if network == net.Network_UDP {
reader = &PacketReader{
Reader: conn,
}
} else {
reader = buf.NewReader(conn)
}
return buf.Copy(reader, link.Writer, buf.UpdateActivity(timer))
}
var responseDoneAndCloseWriter = task.OnSuccess(getResponse, task.Close(link.Writer))
if err := task.Run(ctx, postRequest, responseDoneAndCloseWriter); err != nil {
return newError("connection ends").Base(err)
}
return nil
}
func init() {
common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewClient(ctx, config.(*ClientConfig))
}))
}
v2ray-core-4.34.0/proxy/trojan/config.go 0000664 0000000 0000000 00000001765 13774574720 0020076 0 ustar 00root root 0000000 0000000 package trojan
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"v2ray.com/core/common"
"v2ray.com/core/common/protocol"
)
// MemoryAccount is an account type converted from Account.
type MemoryAccount struct {
Password string
Key []byte
}
// AsAccount implements protocol.AsAccount.
func (a *Account) AsAccount() (protocol.Account, error) {
password := a.GetPassword()
key := hexSha224(password)
return &MemoryAccount{
Password: password,
Key: key,
}, nil
}
// Equals implements protocol.Account.Equals().
func (a *MemoryAccount) Equals(another protocol.Account) bool {
if account, ok := another.(*MemoryAccount); ok {
return a.Password == account.Password
}
return false
}
func hexSha224(password string) []byte {
buf := make([]byte, 56)
hash := sha256.New224()
common.Must2(hash.Write([]byte(password)))
hex.Encode(buf, hash.Sum(nil))
return buf
}
func hexString(data []byte) string {
str := ""
for _, v := range data {
str += fmt.Sprintf("%02x", v)
}
return str
}
v2ray-core-4.34.0/proxy/trojan/config.pb.go 0000664 0000000 0000000 00000032444 13774574720 0020474 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/trojan/config.proto
package trojan
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
protocol "v2ray.com/core/common/protocol"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Account struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"`
}
func (x *Account) Reset() {
*x = Account{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_trojan_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Account) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Account) ProtoMessage() {}
func (x *Account) ProtoReflect() protoreflect.Message {
mi := &file_proxy_trojan_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Account.ProtoReflect.Descriptor instead.
func (*Account) Descriptor() ([]byte, []int) {
return file_proxy_trojan_config_proto_rawDescGZIP(), []int{0}
}
func (x *Account) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
type Fallback struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Alpn string `protobuf:"bytes,1,opt,name=alpn,proto3" json:"alpn,omitempty"`
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
Dest string `protobuf:"bytes,4,opt,name=dest,proto3" json:"dest,omitempty"`
Xver uint64 `protobuf:"varint,5,opt,name=xver,proto3" json:"xver,omitempty"`
}
func (x *Fallback) Reset() {
*x = Fallback{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_trojan_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Fallback) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Fallback) ProtoMessage() {}
func (x *Fallback) ProtoReflect() protoreflect.Message {
mi := &file_proxy_trojan_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Fallback.ProtoReflect.Descriptor instead.
func (*Fallback) Descriptor() ([]byte, []int) {
return file_proxy_trojan_config_proto_rawDescGZIP(), []int{1}
}
func (x *Fallback) GetAlpn() string {
if x != nil {
return x.Alpn
}
return ""
}
func (x *Fallback) GetPath() string {
if x != nil {
return x.Path
}
return ""
}
func (x *Fallback) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *Fallback) GetDest() string {
if x != nil {
return x.Dest
}
return ""
}
func (x *Fallback) GetXver() uint64 {
if x != nil {
return x.Xver
}
return 0
}
type ClientConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"`
}
func (x *ClientConfig) Reset() {
*x = ClientConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_trojan_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ClientConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientConfig) ProtoMessage() {}
func (x *ClientConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_trojan_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead.
func (*ClientConfig) Descriptor() ([]byte, []int) {
return file_proxy_trojan_config_proto_rawDescGZIP(), []int{2}
}
func (x *ClientConfig) GetServer() []*protocol.ServerEndpoint {
if x != nil {
return x.Server
}
return nil
}
type ServerConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Users []*protocol.User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"`
Fallbacks []*Fallback `protobuf:"bytes,3,rep,name=fallbacks,proto3" json:"fallbacks,omitempty"`
}
func (x *ServerConfig) Reset() {
*x = ServerConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_trojan_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServerConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServerConfig) ProtoMessage() {}
func (x *ServerConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_trojan_config_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServerConfig.ProtoReflect.Descriptor instead.
func (*ServerConfig) Descriptor() ([]byte, []int) {
return file_proxy_trojan_config_proto_rawDescGZIP(), []int{3}
}
func (x *ServerConfig) GetUsers() []*protocol.User {
if x != nil {
return x.Users
}
return nil
}
func (x *ServerConfig) GetFallbacks() []*Fallback {
if x != nil {
return x.Fallbacks
}
return nil
}
var File_proxy_trojan_config_proto protoreflect.FileDescriptor
var file_proxy_trojan_config_proto_rawDesc = []byte{
0x0a, 0x19, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2f, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72,
0x6f, 0x6a, 0x61, 0x6e, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0x25, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a,
0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x6e, 0x0a, 0x08, 0x46, 0x61,
0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61,
0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12,
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79,
0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x05,
0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0x52, 0x0a, 0x0c, 0x43, 0x6c,
0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x42, 0x0a, 0x06, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e,
0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x87,
0x01, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x36, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20,
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72,
0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x3f, 0x0a, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62,
0x61, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72,
0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x09, 0x66,
0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x42, 0x56, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x1b, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f,
0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0xaa, 0x02, 0x17, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43,
0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x54, 0x72, 0x6f, 0x6a, 0x61, 0x6e,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proxy_trojan_config_proto_rawDescOnce sync.Once
file_proxy_trojan_config_proto_rawDescData = file_proxy_trojan_config_proto_rawDesc
)
func file_proxy_trojan_config_proto_rawDescGZIP() []byte {
file_proxy_trojan_config_proto_rawDescOnce.Do(func() {
file_proxy_trojan_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_trojan_config_proto_rawDescData)
})
return file_proxy_trojan_config_proto_rawDescData
}
var file_proxy_trojan_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_proxy_trojan_config_proto_goTypes = []interface{}{
(*Account)(nil), // 0: v2ray.core.proxy.trojan.Account
(*Fallback)(nil), // 1: v2ray.core.proxy.trojan.Fallback
(*ClientConfig)(nil), // 2: v2ray.core.proxy.trojan.ClientConfig
(*ServerConfig)(nil), // 3: v2ray.core.proxy.trojan.ServerConfig
(*protocol.ServerEndpoint)(nil), // 4: v2ray.core.common.protocol.ServerEndpoint
(*protocol.User)(nil), // 5: v2ray.core.common.protocol.User
}
var file_proxy_trojan_config_proto_depIdxs = []int32{
4, // 0: v2ray.core.proxy.trojan.ClientConfig.server:type_name -> v2ray.core.common.protocol.ServerEndpoint
5, // 1: v2ray.core.proxy.trojan.ServerConfig.users:type_name -> v2ray.core.common.protocol.User
1, // 2: v2ray.core.proxy.trojan.ServerConfig.fallbacks:type_name -> v2ray.core.proxy.trojan.Fallback
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_proxy_trojan_config_proto_init() }
func file_proxy_trojan_config_proto_init() {
if File_proxy_trojan_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_trojan_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Account); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_trojan_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Fallback); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_trojan_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ClientConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_trojan_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ServerConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_trojan_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_trojan_config_proto_goTypes,
DependencyIndexes: file_proxy_trojan_config_proto_depIdxs,
MessageInfos: file_proxy_trojan_config_proto_msgTypes,
}.Build()
File_proxy_trojan_config_proto = out.File
file_proxy_trojan_config_proto_rawDesc = nil
file_proxy_trojan_config_proto_goTypes = nil
file_proxy_trojan_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/trojan/config.proto 0000664 0000000 0000000 00000001266 13774574720 0020630 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.trojan;
option csharp_namespace = "V2Ray.Core.Proxy.Trojan";
option go_package = "v2ray.com/core/proxy/trojan";
option java_package = "com.v2ray.core.proxy.trojan";
option java_multiple_files = true;
import "common/protocol/user.proto";
import "common/protocol/server_spec.proto";
message Account {
string password = 1;
}
message Fallback {
string alpn = 1;
string path = 2;
string type = 3;
string dest = 4;
uint64 xver = 5;
}
message ClientConfig {
repeated v2ray.core.common.protocol.ServerEndpoint server = 1;
}
message ServerConfig {
repeated v2ray.core.common.protocol.User users = 1;
repeated Fallback fallbacks = 3;
}
v2ray-core-4.34.0/proxy/trojan/errors.generated.go 0000664 0000000 0000000 00000000314 13774574720 0022067 0 ustar 00root root 0000000 0000000 package trojan
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/trojan/protocol.go 0000664 0000000 0000000 00000014507 13774574720 0020470 0 ustar 00root root 0000000 0000000 package trojan
import (
"encoding/binary"
"io"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
)
var (
crlf = []byte{'\r', '\n'}
addrParser = protocol.NewAddressParser(
protocol.AddressFamilyByte(0x01, net.AddressFamilyIPv4),
protocol.AddressFamilyByte(0x04, net.AddressFamilyIPv6),
protocol.AddressFamilyByte(0x03, net.AddressFamilyDomain),
)
)
const (
maxLength = 8192
commandTCP byte = 1
commandUDP byte = 3
)
// ConnWriter is TCP Connection Writer Wrapper for trojan protocol
type ConnWriter struct {
io.Writer
Target net.Destination
Account *MemoryAccount
headerSent bool
}
// Write implements io.Writer
func (c *ConnWriter) Write(p []byte) (n int, err error) {
if !c.headerSent {
if err := c.writeHeader(); err != nil {
return 0, newError("failed to write request header").Base(err)
}
}
return c.Writer.Write(p)
}
// WriteMultiBuffer implements buf.Writer
func (c *ConnWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
defer buf.ReleaseMulti(mb)
for _, b := range mb {
if !b.IsEmpty() {
if _, err := c.Write(b.Bytes()); err != nil {
return err
}
}
}
return nil
}
func (c *ConnWriter) writeHeader() error {
buffer := buf.StackNew()
defer buffer.Release()
command := commandTCP
if c.Target.Network == net.Network_UDP {
command = commandUDP
}
if _, err := buffer.Write(c.Account.Key); err != nil {
return err
}
if _, err := buffer.Write(crlf); err != nil {
return err
}
if err := buffer.WriteByte(command); err != nil {
return err
}
if err := addrParser.WriteAddressPort(&buffer, c.Target.Address, c.Target.Port); err != nil {
return err
}
if _, err := buffer.Write(crlf); err != nil {
return err
}
_, err := c.Writer.Write(buffer.Bytes())
if err == nil {
c.headerSent = true
}
return err
}
// PacketWriter UDP Connection Writer Wrapper for trojan protocol
type PacketWriter struct {
io.Writer
Target net.Destination
}
// WriteMultiBuffer implements buf.Writer
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
b := make([]byte, maxLength)
for !mb.IsEmpty() {
var length int
mb, length = buf.SplitBytes(mb, b)
if _, err := w.writePacket(b[:length], w.Target); err != nil {
buf.ReleaseMulti(mb)
return err
}
}
return nil
}
// WriteMultiBufferWithMetadata writes udp packet with destination specified
func (w *PacketWriter) WriteMultiBufferWithMetadata(mb buf.MultiBuffer, dest net.Destination) error {
b := make([]byte, maxLength)
for !mb.IsEmpty() {
var length int
mb, length = buf.SplitBytes(mb, b)
if _, err := w.writePacket(b[:length], dest); err != nil {
buf.ReleaseMulti(mb)
return err
}
}
return nil
}
func (w *PacketWriter) writePacket(payload []byte, dest net.Destination) (int, error) { // nolint: unparam
buffer := buf.StackNew()
defer buffer.Release()
length := len(payload)
lengthBuf := [2]byte{}
binary.BigEndian.PutUint16(lengthBuf[:], uint16(length))
if err := addrParser.WriteAddressPort(&buffer, dest.Address, dest.Port); err != nil {
return 0, err
}
if _, err := buffer.Write(lengthBuf[:]); err != nil {
return 0, err
}
if _, err := buffer.Write(crlf); err != nil {
return 0, err
}
if _, err := buffer.Write(payload); err != nil {
return 0, err
}
_, err := w.Write(buffer.Bytes())
if err != nil {
return 0, err
}
return length, nil
}
// ConnReader is TCP Connection Reader Wrapper for trojan protocol
type ConnReader struct {
io.Reader
Target net.Destination
headerParsed bool
}
// ParseHeader parses the trojan protocol header
func (c *ConnReader) ParseHeader() error {
var crlf [2]byte
var command [1]byte
var hash [56]byte
if _, err := io.ReadFull(c.Reader, hash[:]); err != nil {
return newError("failed to read user hash").Base(err)
}
if _, err := io.ReadFull(c.Reader, crlf[:]); err != nil {
return newError("failed to read crlf").Base(err)
}
if _, err := io.ReadFull(c.Reader, command[:]); err != nil {
return newError("failed to read command").Base(err)
}
network := net.Network_TCP
if command[0] == commandUDP {
network = net.Network_UDP
}
addr, port, err := addrParser.ReadAddressPort(nil, c.Reader)
if err != nil {
return newError("failed to read address and port").Base(err)
}
c.Target = net.Destination{Network: network, Address: addr, Port: port}
if _, err := io.ReadFull(c.Reader, crlf[:]); err != nil {
return newError("failed to read crlf").Base(err)
}
c.headerParsed = true
return nil
}
// Read implements io.Reader
func (c *ConnReader) Read(p []byte) (int, error) {
if !c.headerParsed {
if err := c.ParseHeader(); err != nil {
return 0, err
}
}
return c.Reader.Read(p)
}
// ReadMultiBuffer implements buf.Reader
func (c *ConnReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
b := buf.New()
_, err := b.ReadFrom(c)
return buf.MultiBuffer{b}, err
}
// PacketPayload combines udp payload and destination
type PacketPayload struct {
Target net.Destination
Buffer buf.MultiBuffer
}
// PacketReader is UDP Connection Reader Wrapper for trojan protocol
type PacketReader struct {
io.Reader
}
// ReadMultiBuffer implements buf.Reader
func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
p, err := r.ReadMultiBufferWithMetadata()
if p != nil {
return p.Buffer, err
}
return nil, err
}
// ReadMultiBufferWithMetadata reads udp packet with destination
func (r *PacketReader) ReadMultiBufferWithMetadata() (*PacketPayload, error) {
addr, port, err := addrParser.ReadAddressPort(nil, r)
if err != nil {
return nil, newError("failed to read address and port").Base(err)
}
var lengthBuf [2]byte
if _, err := io.ReadFull(r, lengthBuf[:]); err != nil {
return nil, newError("failed to read payload length").Base(err)
}
remain := int(binary.BigEndian.Uint16(lengthBuf[:]))
if remain > maxLength {
return nil, newError("oversize payload")
}
var crlf [2]byte
if _, err := io.ReadFull(r, crlf[:]); err != nil {
return nil, newError("failed to read crlf").Base(err)
}
dest := net.UDPDestination(addr, port)
var mb buf.MultiBuffer
for remain > 0 {
length := buf.Size
if remain < length {
length = remain
}
b := buf.New()
mb = append(mb, b)
n, err := b.ReadFullFrom(r, int32(length))
if err != nil {
buf.ReleaseMulti(mb)
return nil, newError("failed to read payload").Base(err)
}
remain -= int(n)
}
return &PacketPayload{Target: dest, Buffer: mb}, nil
}
v2ray-core-4.34.0/proxy/trojan/protocol_test.go 0000664 0000000 0000000 00000004404 13774574720 0021522 0 ustar 00root root 0000000 0000000 package trojan_test
import (
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
. "v2ray.com/core/proxy/trojan"
)
func toAccount(a *Account) protocol.Account {
account, err := a.AsAccount()
common.Must(err)
return account
}
func TestTCPRequest(t *testing.T) {
user := &protocol.MemoryUser{
Email: "love@v2ray.com",
Account: toAccount(&Account{
Password: "password",
}),
}
payload := []byte("test string")
data := buf.New()
common.Must2(data.Write(payload))
buffer := buf.New()
defer buffer.Release()
destination := net.Destination{Network: net.Network_TCP, Address: net.LocalHostIP, Port: 1234}
writer := &ConnWriter{Writer: buffer, Target: destination, Account: user.Account.(*MemoryAccount)}
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{data}))
reader := &ConnReader{Reader: buffer}
common.Must(reader.ParseHeader())
if r := cmp.Diff(reader.Target, destination); r != "" {
t.Error("destination: ", r)
}
decodedData, err := reader.ReadMultiBuffer()
common.Must(err)
if r := cmp.Diff(decodedData[0].Bytes(), payload); r != "" {
t.Error("data: ", r)
}
}
func TestUDPRequest(t *testing.T) {
user := &protocol.MemoryUser{
Email: "love@v2ray.com",
Account: toAccount(&Account{
Password: "password",
}),
}
payload := []byte("test string")
data := buf.New()
common.Must2(data.Write(payload))
buffer := buf.New()
defer buffer.Release()
destination := net.Destination{Network: net.Network_UDP, Address: net.LocalHostIP, Port: 1234}
writer := &PacketWriter{Writer: &ConnWriter{Writer: buffer, Target: destination, Account: user.Account.(*MemoryAccount)}, Target: destination}
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{data}))
connReader := &ConnReader{Reader: buffer}
common.Must(connReader.ParseHeader())
packetReader := &PacketReader{Reader: connReader}
p, err := packetReader.ReadMultiBufferWithMetadata()
common.Must(err)
if p.Buffer.IsEmpty() {
t.Error("no request data")
}
if r := cmp.Diff(p.Target, destination); r != "" {
t.Error("destination: ", r)
}
mb, decoded := buf.SplitFirst(p.Buffer)
buf.ReleaseMulti(mb)
if r := cmp.Diff(decoded.Bytes(), payload); r != "" {
t.Error("data: ", r)
}
}
v2ray-core-4.34.0/proxy/trojan/server.go 0000664 0000000 0000000 00000031201 13774574720 0020123 0 ustar 00root root 0000000 0000000 // +build !confonly
package trojan
import (
"context"
"crypto/tls"
"io"
"strconv"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
udp_proto "v2ray.com/core/common/protocol/udp"
"v2ray.com/core/common/retry"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/policy"
"v2ray.com/core/features/routing"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/udp"
)
func init() {
common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewServer(ctx, config.(*ServerConfig))
}))
}
// Server is an inbound connection handler that handles messages in trojan protocol.
type Server struct {
policyManager policy.Manager
validator *Validator
fallbacks map[string]map[string]*Fallback // or nil
}
// NewServer creates a new trojan inbound handler.
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
validator := new(Validator)
for _, user := range config.Users {
u, err := user.ToMemoryUser()
if err != nil {
return nil, newError("failed to get trojan 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)
server := &Server{
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
validator: validator,
}
if config.Fallbacks != nil {
server.fallbacks = make(map[string]map[string]*Fallback)
for _, fb := range config.Fallbacks {
if server.fallbacks[fb.Alpn] == nil {
server.fallbacks[fb.Alpn] = make(map[string]*Fallback)
}
server.fallbacks[fb.Alpn][fb.Path] = fb
}
if server.fallbacks[""] != nil {
for alpn, pfb := range server.fallbacks {
if alpn != "" { // && alpn != "h2" {
for path, fb := range server.fallbacks[""] {
if pfb[path] == nil {
pfb[path] = fb
}
}
}
}
}
}
return server, 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)
}
// Network implements proxy.Inbound.Network().
func (s *Server) Network() []net.Network {
return []net.Network{net.Network_TCP, net.Network_UNIX}
}
// Process implements proxy.Inbound.Process().
func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {
sid := session.ExportIDToError(ctx)
iConn := conn
if statConn, ok := iConn.(*internet.StatCouterConnection); ok {
iConn = statConn.Connection
}
sessionPolicy := s.policyManager.ForLevel(0)
if err := conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
return newError("unable to set read deadline").Base(err).AtWarning()
}
first := buf.New()
defer first.Release()
firstLen, err := first.ReadFrom(conn)
if err != nil {
return newError("failed to read first request").Base(err)
}
newError("firstLen = ", firstLen).AtInfo().WriteToLog(sid)
bufferedReader := &buf.BufferedReader{
Reader: buf.NewReader(conn),
Buffer: buf.MultiBuffer{first},
}
var user *protocol.MemoryUser
apfb := s.fallbacks
isfb := apfb != nil
shouldFallback := false
if firstLen < 58 || first.Byte(56) != '\r' {
// invalid protocol
err = newError("not trojan protocol")
log.Record(&log.AccessMessage{
From: conn.RemoteAddr(),
To: "",
Status: log.AccessRejected,
Reason: err,
})
shouldFallback = true
} else {
user = s.validator.Get(hexString(first.BytesTo(56)))
if user == nil {
// invalid user, let's fallback
err = newError("not a valid user")
log.Record(&log.AccessMessage{
From: conn.RemoteAddr(),
To: "",
Status: log.AccessRejected,
Reason: err,
})
shouldFallback = true
}
}
if isfb && shouldFallback {
return s.fallback(ctx, sid, err, sessionPolicy, conn, iConn, apfb, first, firstLen, bufferedReader)
} else if shouldFallback {
return newError("invalid protocol or invalid user")
}
clientReader := &ConnReader{Reader: bufferedReader}
if err := clientReader.ParseHeader(); err != nil {
log.Record(&log.AccessMessage{
From: conn.RemoteAddr(),
To: "",
Status: log.AccessRejected,
Reason: err,
})
return newError("failed to create request from: ", conn.RemoteAddr()).Base(err)
}
destination := clientReader.Target
if err := conn.SetReadDeadline(time.Time{}); err != nil {
return newError("unable to set read deadline").Base(err).AtWarning()
}
inbound := session.InboundFromContext(ctx)
if inbound == nil {
panic("no inbound metadata")
}
inbound.User = user
sessionPolicy = s.policyManager.ForLevel(user.Level)
if destination.Network == net.Network_UDP { // handle udp request
return s.handleUDPPayload(ctx, &PacketReader{Reader: clientReader}, &PacketWriter{Writer: conn}, dispatcher)
}
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: conn.RemoteAddr(),
To: destination,
Status: log.AccessAccepted,
Reason: "",
Email: user.Email,
})
newError("received request for ", destination).WriteToLog(sid)
return s.handleConnection(ctx, sessionPolicy, destination, clientReader, buf.NewWriter(conn), dispatcher)
}
func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReader, clientWriter *PacketWriter, dispatcher routing.Dispatcher) error {
udpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) {
common.Must(clientWriter.WriteMultiBufferWithMetadata(buf.MultiBuffer{packet.Payload}, packet.Source))
})
inbound := session.InboundFromContext(ctx)
user := inbound.User
for {
select {
case <-ctx.Done():
return nil
default:
p, err := clientReader.ReadMultiBufferWithMetadata()
if err != nil {
if errors.Cause(err) != io.EOF {
return newError("unexpected EOF").Base(err)
}
return nil
}
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: inbound.Source,
To: p.Target,
Status: log.AccessAccepted,
Reason: "",
Email: user.Email,
})
newError("tunnelling request to ", p.Target).WriteToLog(session.ExportIDToError(ctx))
for _, b := range p.Buffer {
udpServer.Dispatch(ctx, p.Target, b)
}
}
}
}
func (s *Server) handleConnection(ctx context.Context, sessionPolicy policy.Session,
destination net.Destination,
clientReader buf.Reader,
clientWriter buf.Writer, dispatcher routing.Dispatcher) error {
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)
link, err := dispatcher.Dispatch(ctx, destination)
if err != nil {
return newError("failed to dispatch request to ", destination).Base(err)
}
requestDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
if err := buf.Copy(clientReader, link.Writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transfer request").Base(err)
}
return nil
}
responseDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
if err := buf.Copy(link.Reader, clientWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to write response").Base(err)
}
return nil
}
var requestDonePost = task.OnSuccess(requestDone, task.Close(link.Writer))
if err := task.Run(ctx, requestDonePost, responseDone); err != nil {
common.Must(common.Interrupt(link.Reader))
common.Must(common.Interrupt(link.Writer))
return newError("connection ends").Base(err)
}
return nil
}
func (s *Server) fallback(ctx context.Context, sid errors.ExportOption, err error, sessionPolicy policy.Session, connection internet.Connection, iConn internet.Connection, apfb map[string]map[string]*Fallback, first *buf.Buffer, firstLen int64, reader buf.Reader) error {
if err := connection.SetReadDeadline(time.Time{}); err != nil {
newError("unable to set back read deadline").Base(err).AtWarning().WriteToLog(sid)
}
newError("fallback starts").Base(err).AtInfo().WriteToLog(sid)
alpn := ""
if len(apfb) > 1 || apfb[""] == nil {
if tlsConn, ok := iConn.(*tls.Conn); ok {
alpn = tlsConn.ConnectionState().NegotiatedProtocol
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
}
if apfb[alpn] == nil {
alpn = ""
}
}
pfb := apfb[alpn]
if pfb == nil {
return newError(`failed to find the default "alpn" config`).AtWarning()
}
path := ""
if len(pfb) > 1 || pfb[""] == nil {
if firstLen >= 18 && first.Byte(4) != '*' { // not h2c
firstBytes := first.Bytes()
for i := 4; i <= 8; i++ { // 5 -> 9
if firstBytes[i] == '/' && firstBytes[i-1] == ' ' {
search := len(firstBytes)
if search > 64 {
search = 64 // up to about 60
}
for j := i + 1; j < search; j++ {
k := firstBytes[j]
if k == '\r' || k == '\n' { // avoid logging \r or \n
break
}
if k == ' ' {
path = string(firstBytes[i:j])
newError("realPath = " + path).AtInfo().WriteToLog(sid)
if pfb[path] == nil {
path = ""
}
break
}
}
break
}
}
}
}
fb := pfb[path]
if fb == nil {
return newError(`failed to find the default "path" config`).AtWarning()
}
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)
var conn net.Conn
if err := retry.ExponentialBackoff(5, 100).On(func() error {
var dialer net.Dialer
conn, err = dialer.DialContext(ctx, fb.Type, fb.Dest)
if err != nil {
return err
}
return nil
}); err != nil {
return newError("failed to dial to " + fb.Dest).Base(err).AtWarning()
}
defer conn.Close()
serverReader := buf.NewReader(conn)
serverWriter := buf.NewWriter(conn)
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
if fb.Xver != 0 {
remoteAddr, remotePort, err := net.SplitHostPort(connection.RemoteAddr().String())
if err != nil {
return err
}
localAddr, localPort, err := net.SplitHostPort(connection.LocalAddr().String())
if err != nil {
return err
}
ipv4 := true
for i := 0; i < len(remoteAddr); i++ {
if remoteAddr[i] == ':' {
ipv4 = false
break
}
}
pro := buf.New()
defer pro.Release()
switch fb.Xver {
case 1:
if ipv4 {
common.Must2(pro.Write([]byte("PROXY TCP4 " + remoteAddr + " " + localAddr + " " + remotePort + " " + localPort + "\r\n")))
} else {
common.Must2(pro.Write([]byte("PROXY TCP6 " + remoteAddr + " " + localAddr + " " + remotePort + " " + localPort + "\r\n")))
}
case 2:
common.Must2(pro.Write([]byte("\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x21"))) // signature + v2 + PROXY
if ipv4 {
common.Must2(pro.Write([]byte("\x11\x00\x0C"))) // AF_INET + STREAM + 12 bytes
common.Must2(pro.Write(net.ParseIP(remoteAddr).To4()))
common.Must2(pro.Write(net.ParseIP(localAddr).To4()))
} else {
common.Must2(pro.Write([]byte("\x21\x00\x24"))) // AF_INET6 + STREAM + 36 bytes
common.Must2(pro.Write(net.ParseIP(remoteAddr).To16()))
common.Must2(pro.Write(net.ParseIP(localAddr).To16()))
}
p1, _ := strconv.ParseUint(remotePort, 10, 16)
p2, _ := strconv.ParseUint(localPort, 10, 16)
common.Must2(pro.Write([]byte{byte(p1 >> 8), byte(p1), byte(p2 >> 8), byte(p2)}))
}
if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {
return newError("failed to set PROXY protocol v", fb.Xver).Base(err).AtWarning()
}
}
if err := buf.Copy(reader, serverWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to fallback request payload").Base(err).AtInfo()
}
return nil
}
writer := buf.NewWriter(connection)
getResponse := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
if err := buf.Copy(serverReader, writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to deliver response payload").Base(err).AtInfo()
}
return nil
}
if err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), task.OnSuccess(getResponse, task.Close(writer))); err != nil {
common.Must(common.Interrupt(serverReader))
common.Must(common.Interrupt(serverWriter))
return newError("fallback ends").Base(err).AtInfo()
}
return nil
}
v2ray-core-4.34.0/proxy/trojan/trojan.go 0000664 0000000 0000000 00000000017 13774574720 0020113 0 ustar 00root root 0000000 0000000 package trojan
v2ray-core-4.34.0/proxy/trojan/validator.go 0000664 0000000 0000000 00000002330 13774574720 0020603 0 ustar 00root root 0000000 0000000 // +build !confonly
package trojan
import (
"strings"
"sync"
"v2ray.com/core/common/protocol"
)
// Validator stores valid trojan 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 trojan user, Email must be empty or unique.
func (v *Validator) Add(u *protocol.MemoryUser) error {
if u.Email != "" {
_, loaded := v.email.LoadOrStore(strings.ToLower(u.Email), u)
if loaded {
return newError("User ", u.Email, " already exists.")
}
}
v.users.Store(hexString(u.Account.(*MemoryAccount).Key), u)
return nil
}
// Del a trojan 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.")
}
v.email.Delete(le)
v.users.Delete(hexString(u.(*protocol.MemoryUser).Account.(*MemoryAccount).Key))
return nil
}
// Get a trojan user with hashed key, nil if user doesn't exist.
func (v *Validator) Get(hash string) *protocol.MemoryUser {
u, _ := v.users.Load(hash)
if u != nil {
return u.(*protocol.MemoryUser)
}
return nil
}
v2ray-core-4.34.0/proxy/vless/ 0000775 0000000 0000000 00000000000 13774574720 0016130 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/vless/account.go 0000664 0000000 0000000 00000001767 13774574720 0020126 0 ustar 00root root 0000000 0000000 // +build !confonly
package vless
import (
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/uuid"
)
// AsAccount implements protocol.Account.AsAccount().
func (a *Account) AsAccount() (protocol.Account, error) {
id, err := uuid.ParseString(a.Id)
if err != nil {
return nil, newError("failed to parse ID").Base(err).AtError()
}
return &MemoryAccount{
ID: protocol.NewID(id),
Flow: a.Flow, // needs parser here?
Encryption: a.Encryption, // needs parser here?
}, nil
}
// MemoryAccount is an in-memory form of VLess account.
type MemoryAccount struct {
// ID of the account.
ID *protocol.ID
// Flow of the account.
Flow string
// Encryption of the account. Used for client connections, and only accepts "none" for now.
Encryption string
}
// Equals implements protocol.Account.Equals().
func (a *MemoryAccount) Equals(account protocol.Account) bool {
vlessAccount, ok := account.(*MemoryAccount)
if !ok {
return false
}
return a.ID.Equals(vlessAccount.ID)
}
v2ray-core-4.34.0/proxy/vless/account.pb.go 0000664 0000000 0000000 00000013530 13774574720 0020515 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/vless/account.proto
package vless
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Account struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
// Flow settings.
Flow string `protobuf:"bytes,2,opt,name=flow,proto3" json:"flow,omitempty"`
// Encryption settings. Only applies to client side, and only accepts "none" for now.
Encryption string `protobuf:"bytes,3,opt,name=encryption,proto3" json:"encryption,omitempty"`
}
func (x *Account) Reset() {
*x = Account{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_vless_account_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Account) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Account) ProtoMessage() {}
func (x *Account) ProtoReflect() protoreflect.Message {
mi := &file_proxy_vless_account_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Account.ProtoReflect.Descriptor instead.
func (*Account) Descriptor() ([]byte, []int) {
return file_proxy_vless_account_proto_rawDescGZIP(), []int{0}
}
func (x *Account) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *Account) GetFlow() string {
if x != nil {
return x.Flow
}
return ""
}
func (x *Account) GetEncryption() string {
if x != nil {
return x.Encryption
}
return ""
}
var File_proxy_vless_account_proto protoreflect.FileDescriptor
var file_proxy_vless_account_proto_rawDesc = []byte{
0x0a, 0x19, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x61, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c,
0x65, 0x73, 0x73, 0x22, 0x4d, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e,
0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12,
0x0a, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c,
0x6f, 0x77, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x42, 0x53, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73,
0x50, 0x01, 0x5a, 0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f,
0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0xaa, 0x02,
0x16, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78,
0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proxy_vless_account_proto_rawDescOnce sync.Once
file_proxy_vless_account_proto_rawDescData = file_proxy_vless_account_proto_rawDesc
)
func file_proxy_vless_account_proto_rawDescGZIP() []byte {
file_proxy_vless_account_proto_rawDescOnce.Do(func() {
file_proxy_vless_account_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_vless_account_proto_rawDescData)
})
return file_proxy_vless_account_proto_rawDescData
}
var file_proxy_vless_account_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_proxy_vless_account_proto_goTypes = []interface{}{
(*Account)(nil), // 0: v2ray.core.proxy.vless.Account
}
var file_proxy_vless_account_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_proxy_vless_account_proto_init() }
func file_proxy_vless_account_proto_init() {
if File_proxy_vless_account_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_vless_account_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Account); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_vless_account_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_vless_account_proto_goTypes,
DependencyIndexes: file_proxy_vless_account_proto_depIdxs,
MessageInfos: file_proxy_vless_account_proto_msgTypes,
}.Build()
File_proxy_vless_account_proto = out.File
file_proxy_vless_account_proto_rawDesc = nil
file_proxy_vless_account_proto_goTypes = nil
file_proxy_vless_account_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/vless/account.proto 0000664 0000000 0000000 00000001014 13774574720 0020645 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.vless;
option csharp_namespace = "V2Ray.Core.Proxy.Vless";
option go_package = "v2ray.com/core/proxy/vless";
option java_package = "com.v2ray.core.proxy.vless";
option java_multiple_files = true;
message Account {
// ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
string id = 1;
// Flow settings.
string flow = 2;
// Encryption settings. Only applies to client side, and only accepts "none" for now.
string encryption = 3;
}
v2ray-core-4.34.0/proxy/vless/encoding/ 0000775 0000000 0000000 00000000000 13774574720 0017716 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/vless/encoding/addons.go 0000664 0000000 0000000 00000007656 13774574720 0021533 0 ustar 00root root 0000000 0000000 // +build !confonly
package encoding
import (
"io"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/protocol"
)
// EncodeHeaderAddons Add addons byte to the header
func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {
if err := buffer.WriteByte(0); err != nil {
return newError("failed to write addons protobuf length").Base(err)
}
return nil
}
func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {
addons := new(Addons)
buffer.Clear()
if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
return nil, newError("failed to read addons protobuf length").Base(err)
}
if length := int32(buffer.Byte(0)); length != 0 {
buffer.Clear()
if _, err := buffer.ReadFullFrom(reader, length); err != nil {
return nil, newError("failed to read addons protobuf value").Base(err)
}
if err := proto.Unmarshal(buffer.Bytes(), addons); err != nil {
return nil, newError("failed to unmarshal addons protobuf value").Base(err)
}
}
return addons, nil
}
// EncodeBodyAddons returns a Writer that auto-encrypt content written by caller.
func EncodeBodyAddons(writer io.Writer, request *protocol.RequestHeader, addons *Addons) buf.Writer {
if request.Command == protocol.RequestCommandUDP {
return NewMultiLengthPacketWriter(writer.(buf.Writer))
}
return buf.NewWriter(writer)
}
// DecodeBodyAddons returns a Reader from which caller can fetch decrypted body.
func DecodeBodyAddons(reader io.Reader, request *protocol.RequestHeader, addons *Addons) buf.Reader {
if request.Command == protocol.RequestCommandUDP {
return NewLengthPacketReader(reader)
}
return buf.NewReader(reader)
}
func NewMultiLengthPacketWriter(writer buf.Writer) *MultiLengthPacketWriter {
return &MultiLengthPacketWriter{
Writer: writer,
}
}
type MultiLengthPacketWriter struct {
buf.Writer
}
func (w *MultiLengthPacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
defer buf.ReleaseMulti(mb)
if len(mb)+1 > 64*1024*1024 {
return errors.New("value too large")
}
sliceSize := len(mb) + 1
mb2Write := make(buf.MultiBuffer, 0, sliceSize)
for _, b := range mb {
length := b.Len()
if length == 0 || length+2 > buf.Size {
continue
}
eb := buf.New()
if err := eb.WriteByte(byte(length >> 8)); err != nil {
eb.Release()
continue
}
if err := eb.WriteByte(byte(length)); err != nil {
eb.Release()
continue
}
if _, err := eb.Write(b.Bytes()); err != nil {
eb.Release()
continue
}
mb2Write = append(mb2Write, eb)
}
if mb2Write.IsEmpty() {
return nil
}
return w.Writer.WriteMultiBuffer(mb2Write)
}
type LengthPacketWriter struct {
io.Writer
cache []byte
}
func (w *LengthPacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
length := mb.Len() // none of mb is nil
if length == 0 {
return nil
}
defer func() {
w.cache = w.cache[:0]
}()
w.cache = append(w.cache, byte(length>>8), byte(length))
for i, b := range mb {
w.cache = append(w.cache, b.Bytes()...)
b.Release()
mb[i] = nil
}
if _, err := w.Write(w.cache); err != nil {
return newError("failed to write a packet").Base(err)
}
return nil
}
func NewLengthPacketReader(reader io.Reader) *LengthPacketReader {
return &LengthPacketReader{
Reader: reader,
cache: make([]byte, 2),
}
}
type LengthPacketReader struct {
io.Reader
cache []byte
}
func (r *LengthPacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
if _, err := io.ReadFull(r.Reader, r.cache); err != nil { // maybe EOF
return nil, newError("failed to read packet length").Base(err)
}
length := int32(r.cache[0])<<8 | int32(r.cache[1])
mb := make(buf.MultiBuffer, 0, length/buf.Size+1)
for length > 0 {
size := length
if size > buf.Size {
size = buf.Size
}
length -= size
b := buf.New()
if _, err := b.ReadFullFrom(r.Reader, size); err != nil {
return nil, newError("failed to read packet payload").Base(err)
}
mb = append(mb, b)
}
return mb, nil
}
v2ray-core-4.34.0/proxy/vless/encoding/addons.pb.go 0000664 0000000 0000000 00000022223 13774574720 0022116 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: proxy/vless/encoding/addons.proto
package encoding // import "v2ray.com/core/proxy/vless/encoding"
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Addons struct {
Flow string `protobuf:"bytes,1,opt,name=Flow,proto3" json:"Flow,omitempty"`
Seed []byte `protobuf:"bytes,2,opt,name=Seed,proto3" json:"Seed,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Addons) Reset() { *m = Addons{} }
func (m *Addons) String() string { return proto.CompactTextString(m) }
func (*Addons) ProtoMessage() {}
func (*Addons) Descriptor() ([]byte, []int) {
return fileDescriptor_addons_715144385dbf650f, []int{0}
}
func (m *Addons) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *Addons) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_Addons.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalTo(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (dst *Addons) XXX_Merge(src proto.Message) {
xxx_messageInfo_Addons.Merge(dst, src)
}
func (m *Addons) XXX_Size() int {
return m.Size()
}
func (m *Addons) XXX_DiscardUnknown() {
xxx_messageInfo_Addons.DiscardUnknown(m)
}
var xxx_messageInfo_Addons proto.InternalMessageInfo
func (m *Addons) GetFlow() string {
if m != nil {
return m.Flow
}
return ""
}
func (m *Addons) GetSeed() []byte {
if m != nil {
return m.Seed
}
return nil
}
func init() {
proto.RegisterType((*Addons)(nil), "v2ray.core.proxy.vless.encoding.Addons")
}
func (m *Addons) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Addons) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Flow) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintAddons(dAtA, i, uint64(len(m.Flow)))
i += copy(dAtA[i:], m.Flow)
}
if len(m.Seed) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintAddons(dAtA, i, uint64(len(m.Seed)))
i += copy(dAtA[i:], m.Seed)
}
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
}
return i, nil
}
func encodeVarintAddons(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *Addons) Size() (n int) {
var l int
_ = l
l = len(m.Flow)
if l > 0 {
n += 1 + l + sovAddons(uint64(l))
}
l = len(m.Seed)
if l > 0 {
n += 1 + l + sovAddons(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func sovAddons(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozAddons(x uint64) (n int) {
return sovAddons(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *Addons) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAddons
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Addons: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Addons: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Flow", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAddons
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthAddons
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Flow = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Seed", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAddons
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthAddons
}
postIndex := iNdEx + byteLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Seed = append(m.Seed[:0], dAtA[iNdEx:postIndex]...)
if m.Seed == nil {
m.Seed = []byte{}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipAddons(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthAddons
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipAddons(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowAddons
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowAddons
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowAddons
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthAddons
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowAddons
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipAddons(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthAddons = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowAddons = fmt.Errorf("proto: integer overflow")
)
func init() {
proto.RegisterFile("proxy/vless/encoding/addons.proto", fileDescriptor_addons_715144385dbf650f)
}
var fileDescriptor_addons_715144385dbf650f = []byte{
// 186 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x2c, 0x28, 0xca, 0xaf,
0xa8, 0xd4, 0x2f, 0xcb, 0x49, 0x2d, 0x2e, 0xd6, 0x4f, 0xcd, 0x4b, 0xce, 0x4f, 0xc9, 0xcc, 0x4b,
0xd7, 0x4f, 0x4c, 0x49, 0xc9, 0xcf, 0x2b, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x2f,
0x33, 0x2a, 0x4a, 0xac, 0xd4, 0x4b, 0xce, 0x2f, 0x4a, 0xd5, 0x03, 0xab, 0xd6, 0x03, 0xab, 0xd6,
0x83, 0xa9, 0x56, 0x32, 0xe0, 0x62, 0x73, 0x04, 0x6b, 0x10, 0x12, 0xe2, 0x62, 0x71, 0xcb, 0xc9,
0x2f, 0x97, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x02, 0xb3, 0x41, 0x62, 0xc1, 0xa9, 0xa9, 0x29,
0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0x3c, 0x41, 0x60, 0xb6, 0x53, 0xdd, 0x89, 0x47, 0x72, 0x8c, 0x17,
0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe3, 0xb1, 0x1c, 0x03, 0x97, 0x72, 0x72, 0x7e,
0xae, 0x1e, 0x01, 0x8b, 0x02, 0x18, 0xa3, 0x94, 0x61, 0x4a, 0x72, 0xf5, 0x41, 0xca, 0xf4, 0xb1,
0xb9, 0x7e, 0x15, 0x93, 0x7c, 0x98, 0x51, 0x50, 0x62, 0xa5, 0x9e, 0x33, 0xc8, 0xa0, 0x00, 0xb0,
0x41, 0x61, 0x60, 0x83, 0x5c, 0xa1, 0x2a, 0x92, 0xd8, 0xc0, 0x3e, 0x33, 0x06, 0x04, 0x00, 0x00,
0xff, 0xff, 0x36, 0x32, 0x14, 0x7c, 0xfe, 0x00, 0x00, 0x00,
}
v2ray-core-4.34.0/proxy/vless/encoding/addons.proto 0000664 0000000 0000000 00000000516 13774574720 0022255 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.vless.encoding;
option csharp_namespace = "V2Ray.Core.Proxy.Vless.Encoding";
option go_package = "v2ray.com/core/proxy/vless/encoding";
option java_package = "com.v2ray.core.proxy.vless.encoding";
option java_multiple_files = true;
message Addons {
string Flow = 1;
bytes Seed = 2;
}
v2ray-core-4.34.0/proxy/vless/encoding/encoding.go 0000664 0000000 0000000 00000012055 13774574720 0022036 0 ustar 00root root 0000000 0000000 // +build !confonly
package encoding
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"io"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/proxy/vless"
)
const (
Version = byte(0)
)
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(),
)
// EncodeRequestHeader writes encoded request header into the given writer.
func EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requestAddons *Addons) error {
buffer := buf.StackNew()
defer buffer.Release()
if err := buffer.WriteByte(request.Version); err != nil {
return newError("failed to write request version").Base(err)
}
if _, err := buffer.Write(request.User.Account.(*vless.MemoryAccount).ID.Bytes()); err != nil {
return newError("failed to write request user id").Base(err)
}
if err := EncodeHeaderAddons(&buffer, requestAddons); err != nil {
return newError("failed to encode request header addons").Base(err)
}
if err := buffer.WriteByte(byte(request.Command)); err != nil {
return newError("failed to write request command").Base(err)
}
if request.Command != protocol.RequestCommandMux {
if err := addrParser.WriteAddressPort(&buffer, request.Address, request.Port); err != nil {
return newError("failed to write request address and port").Base(err)
}
}
if _, err := writer.Write(buffer.Bytes()); err != nil {
return newError("failed to write request header").Base(err)
}
return nil
}
// DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream.
func DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validator *vless.Validator) (*protocol.RequestHeader, *Addons, bool, error) {
buffer := buf.StackNew()
defer buffer.Release()
request := new(protocol.RequestHeader)
if isfb {
request.Version = first.Byte(0)
} else {
if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
return nil, nil, false, newError("failed to read request version").Base(err)
}
request.Version = buffer.Byte(0)
}
switch request.Version {
case 0:
var id [16]byte
if isfb {
copy(id[:], first.BytesRange(1, 17))
} else {
buffer.Clear()
if _, err := buffer.ReadFullFrom(reader, 16); err != nil {
return nil, nil, false, newError("failed to read request user id").Base(err)
}
copy(id[:], buffer.Bytes())
}
if request.User = validator.Get(id); request.User == nil {
return nil, nil, isfb, newError("invalid request user id")
}
if isfb {
first.Advance(17)
}
requestAddons, err := DecodeHeaderAddons(&buffer, reader)
if err != nil {
return nil, nil, false, newError("failed to decode request header addons").Base(err)
}
buffer.Clear()
if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
return nil, nil, false, newError("failed to read request command").Base(err)
}
request.Command = protocol.RequestCommand(buffer.Byte(0))
switch request.Command {
case protocol.RequestCommandMux:
request.Address = net.DomainAddress("v1.mux.cool")
request.Port = 0
case protocol.RequestCommandTCP, protocol.RequestCommandUDP:
if addr, port, err := addrParser.ReadAddressPort(&buffer, reader); err == nil {
request.Address = addr
request.Port = port
}
}
if request.Address == nil {
return nil, nil, false, newError("invalid request address")
}
return request, requestAddons, false, nil
default:
return nil, nil, isfb, newError("invalid request version")
}
}
// EncodeResponseHeader writes encoded response header into the given writer.
func EncodeResponseHeader(writer io.Writer, request *protocol.RequestHeader, responseAddons *Addons) error {
buffer := buf.StackNew()
defer buffer.Release()
if err := buffer.WriteByte(request.Version); err != nil {
return newError("failed to write response version").Base(err)
}
if err := EncodeHeaderAddons(&buffer, responseAddons); err != nil {
return newError("failed to encode response header addons").Base(err)
}
if _, err := writer.Write(buffer.Bytes()); err != nil {
return newError("failed to write response header").Base(err)
}
return nil
}
// DecodeResponseHeader decodes and returns (if successful) a ResponseHeader from an input stream.
func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*Addons, error) {
buffer := buf.StackNew()
defer buffer.Release()
if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
return nil, newError("failed to read response version").Base(err)
}
if buffer.Byte(0) != request.Version {
return nil, newError("unexpected response version. Expecting ", int(request.Version), " but actually ", int(buffer.Byte(0)))
}
responseAddons, err := DecodeHeaderAddons(&buffer, reader)
if err != nil {
return nil, newError("failed to decode response header addons").Base(err)
}
return responseAddons, nil
}
v2ray-core-4.34.0/proxy/vless/encoding/encoding_test.go 0000664 0000000 0000000 00000005553 13774574720 0023102 0 ustar 00root root 0000000 0000000 package encoding_test
import (
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/uuid"
"v2ray.com/core/proxy/vless"
. "v2ray.com/core/proxy/vless/encoding"
)
func toAccount(a *vless.Account) protocol.Account {
account, err := a.AsAccount()
common.Must(err)
return account
}
func TestRequestSerialization(t *testing.T) {
user := &protocol.MemoryUser{
Level: 0,
Email: "test@v2fly.org",
}
id := uuid.New()
account := &vless.Account{
Id: id.String(),
}
user.Account = toAccount(account)
expectedRequest := &protocol.RequestHeader{
Version: Version,
User: user,
Command: protocol.RequestCommandTCP,
Address: net.DomainAddress("www.v2fly.org"),
Port: net.Port(443),
}
expectedAddons := &Addons{}
buffer := buf.StackNew()
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
Validator := new(vless.Validator)
Validator.Add(user)
actualRequest, actualAddons, _, err := DecodeRequestHeader(false, nil, &buffer, Validator)
common.Must(err)
if r := cmp.Diff(actualRequest, expectedRequest, cmp.AllowUnexported(protocol.ID{})); r != "" {
t.Error(r)
}
if r := cmp.Diff(actualAddons, expectedAddons); r != "" {
t.Error(r)
}
}
func TestInvalidRequest(t *testing.T) {
user := &protocol.MemoryUser{
Level: 0,
Email: "test@v2fly.org",
}
id := uuid.New()
account := &vless.Account{
Id: id.String(),
}
user.Account = toAccount(account)
expectedRequest := &protocol.RequestHeader{
Version: Version,
User: user,
Command: protocol.RequestCommand(100),
Address: net.DomainAddress("www.v2fly.org"),
Port: net.Port(443),
}
expectedAddons := &Addons{}
buffer := buf.StackNew()
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
Validator := new(vless.Validator)
Validator.Add(user)
_, _, _, err := DecodeRequestHeader(false, nil, &buffer, Validator)
if err == nil {
t.Error("nil error")
}
}
func TestMuxRequest(t *testing.T) {
user := &protocol.MemoryUser{
Level: 0,
Email: "test@v2fly.org",
}
id := uuid.New()
account := &vless.Account{
Id: id.String(),
}
user.Account = toAccount(account)
expectedRequest := &protocol.RequestHeader{
Version: Version,
User: user,
Command: protocol.RequestCommandMux,
Address: net.DomainAddress("v1.mux.cool"),
}
expectedAddons := &Addons{}
buffer := buf.StackNew()
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
Validator := new(vless.Validator)
Validator.Add(user)
actualRequest, actualAddons, _, err := DecodeRequestHeader(false, nil, &buffer, Validator)
common.Must(err)
if r := cmp.Diff(actualRequest, expectedRequest, cmp.AllowUnexported(protocol.ID{})); r != "" {
t.Error(r)
}
if r := cmp.Diff(actualAddons, expectedAddons); r != "" {
t.Error(r)
}
}
v2ray-core-4.34.0/proxy/vless/encoding/errors.generated.go 0000664 0000000 0000000 00000000316 13774574720 0023516 0 ustar 00root root 0000000 0000000 package encoding
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/vless/errors.generated.go 0000664 0000000 0000000 00000000313 13774574720 0021725 0 ustar 00root root 0000000 0000000 package vless
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/vless/inbound/ 0000775 0000000 0000000 00000000000 13774574720 0017566 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/vless/inbound/config.go 0000664 0000000 0000000 00000000045 13774574720 0021361 0 ustar 00root root 0000000 0000000 // +build !confonly
package inbound
v2ray-core-4.34.0/proxy/vless/inbound/config.pb.go 0000664 0000000 0000000 00000024066 13774574720 0021772 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/vless/inbound/config.proto
package inbound
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
protocol "v2ray.com/core/common/protocol"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Fallback struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Alpn string `protobuf:"bytes,1,opt,name=alpn,proto3" json:"alpn,omitempty"`
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
Dest string `protobuf:"bytes,4,opt,name=dest,proto3" json:"dest,omitempty"`
Xver uint64 `protobuf:"varint,5,opt,name=xver,proto3" json:"xver,omitempty"`
}
func (x *Fallback) Reset() {
*x = Fallback{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_vless_inbound_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Fallback) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Fallback) ProtoMessage() {}
func (x *Fallback) ProtoReflect() protoreflect.Message {
mi := &file_proxy_vless_inbound_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Fallback.ProtoReflect.Descriptor instead.
func (*Fallback) Descriptor() ([]byte, []int) {
return file_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{0}
}
func (x *Fallback) GetAlpn() string {
if x != nil {
return x.Alpn
}
return ""
}
func (x *Fallback) GetPath() string {
if x != nil {
return x.Path
}
return ""
}
func (x *Fallback) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *Fallback) GetDest() string {
if x != nil {
return x.Dest
}
return ""
}
func (x *Fallback) GetXver() uint64 {
if x != nil {
return x.Xver
}
return 0
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Clients []*protocol.User `protobuf:"bytes,1,rep,name=clients,proto3" json:"clients,omitempty"`
// Decryption settings. Only applies to server side, and only accepts "none"
// for now.
Decryption string `protobuf:"bytes,2,opt,name=decryption,proto3" json:"decryption,omitempty"`
Fallbacks []*Fallback `protobuf:"bytes,3,rep,name=fallbacks,proto3" json:"fallbacks,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_vless_inbound_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_proxy_vless_inbound_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{1}
}
func (x *Config) GetClients() []*protocol.User {
if x != nil {
return x.Clients
}
return nil
}
func (x *Config) GetDecryption() string {
if x != nil {
return x.Decryption
}
return ""
}
func (x *Config) GetFallbacks() []*Fallback {
if x != nil {
return x.Fallbacks
}
return nil
}
var File_proxy_vless_inbound_config_proto protoreflect.FileDescriptor
var file_proxy_vless_inbound_config_proto_rawDesc = []byte{
0x0a, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e,
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x12, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75,
0x6e, 0x64, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6e,
0x0a, 0x08, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c,
0x70, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12,
0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61,
0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x04,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76,
0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0xac,
0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3a, 0x0a, 0x07, 0x63, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x07, 0x63, 0x6c,
0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x63, 0x72, 0x79,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x0a, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73,
0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61,
0x63, 0x6b, 0x52, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x42, 0x6b, 0x0a,
0x22, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x22, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73,
0x73, 0x2f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02, 0x1e, 0x56, 0x32, 0x52, 0x61,
0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65,
0x73, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_proxy_vless_inbound_config_proto_rawDescOnce sync.Once
file_proxy_vless_inbound_config_proto_rawDescData = file_proxy_vless_inbound_config_proto_rawDesc
)
func file_proxy_vless_inbound_config_proto_rawDescGZIP() []byte {
file_proxy_vless_inbound_config_proto_rawDescOnce.Do(func() {
file_proxy_vless_inbound_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_vless_inbound_config_proto_rawDescData)
})
return file_proxy_vless_inbound_config_proto_rawDescData
}
var file_proxy_vless_inbound_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_proxy_vless_inbound_config_proto_goTypes = []interface{}{
(*Fallback)(nil), // 0: v2ray.core.proxy.vless.inbound.Fallback
(*Config)(nil), // 1: v2ray.core.proxy.vless.inbound.Config
(*protocol.User)(nil), // 2: v2ray.core.common.protocol.User
}
var file_proxy_vless_inbound_config_proto_depIdxs = []int32{
2, // 0: v2ray.core.proxy.vless.inbound.Config.clients:type_name -> v2ray.core.common.protocol.User
0, // 1: v2ray.core.proxy.vless.inbound.Config.fallbacks:type_name -> v2ray.core.proxy.vless.inbound.Fallback
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_proxy_vless_inbound_config_proto_init() }
func file_proxy_vless_inbound_config_proto_init() {
if File_proxy_vless_inbound_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_vless_inbound_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Fallback); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_vless_inbound_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_vless_inbound_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_vless_inbound_config_proto_goTypes,
DependencyIndexes: file_proxy_vless_inbound_config_proto_depIdxs,
MessageInfos: file_proxy_vless_inbound_config_proto_msgTypes,
}.Build()
File_proxy_vless_inbound_config_proto = out.File
file_proxy_vless_inbound_config_proto_rawDesc = nil
file_proxy_vless_inbound_config_proto_goTypes = nil
file_proxy_vless_inbound_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/vless/inbound/config.proto 0000664 0000000 0000000 00000001221 13774574720 0022114 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.vless.inbound;
option csharp_namespace = "V2Ray.Core.Proxy.Vless.Inbound";
option go_package = "v2ray.com/core/proxy/vless/inbound";
option java_package = "com.v2ray.core.proxy.vless.inbound";
option java_multiple_files = true;
import "common/protocol/user.proto";
message Fallback {
string alpn = 1;
string path = 2;
string type = 3;
string dest = 4;
uint64 xver = 5;
}
message Config {
repeated v2ray.core.common.protocol.User clients = 1;
// Decryption settings. Only applies to server side, and only accepts "none"
// for now.
string decryption = 2;
repeated Fallback fallbacks = 3;
}
v2ray-core-4.34.0/proxy/vless/inbound/errors.generated.go 0000664 0000000 0000000 00000000315 13774574720 0023365 0 ustar 00root root 0000000 0000000 package inbound
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/vless/inbound/inbound.go 0000664 0000000 0000000 00000032064 13774574720 0021560 0 ustar 00root root 0000000 0000000 // +build !confonly
package inbound
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"io"
"strconv"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/retry"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/dns"
feature_inbound "v2ray.com/core/features/inbound"
"v2ray.com/core/features/policy"
"v2ray.com/core/features/routing"
"v2ray.com/core/proxy/vless"
"v2ray.com/core/proxy/vless/encoding"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/tls"
)
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
var dc dns.Client
if err := core.RequireFeatures(ctx, func(d dns.Client) error {
dc = d
return nil
}); err != nil {
return nil, err
}
return New(ctx, config.(*Config), dc)
}))
}
// Handler is an inbound connection handler that handles messages in VLess protocol.
type Handler struct {
inboundHandlerManager feature_inbound.Manager
policyManager policy.Manager
validator *vless.Validator
dns dns.Client
fallbacks map[string]map[string]*Fallback // or nil
// regexps map[string]*regexp.Regexp // or nil
}
// New creates a new VLess inbound handler.
func New(ctx context.Context, config *Config, dc dns.Client) (*Handler, error) {
v := core.MustFromContext(ctx)
handler := &Handler{
inboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
validator: new(vless.Validator),
dns: dc,
}
for _, user := range config.Clients {
u, err := user.ToMemoryUser()
if err != nil {
return nil, newError("failed to get VLESS user").Base(err).AtError()
}
if err := handler.AddUser(ctx, u); err != nil {
return nil, newError("failed to initiate user").Base(err).AtError()
}
}
if config.Fallbacks != nil {
handler.fallbacks = make(map[string]map[string]*Fallback)
// handler.regexps = make(map[string]*regexp.Regexp)
for _, fb := range config.Fallbacks {
if handler.fallbacks[fb.Alpn] == nil {
handler.fallbacks[fb.Alpn] = make(map[string]*Fallback)
}
handler.fallbacks[fb.Alpn][fb.Path] = fb
/*
if fb.Path != "" {
if r, err := regexp.Compile(fb.Path); err != nil {
return nil, newError("invalid path regexp").Base(err).AtError()
} else {
handler.regexps[fb.Path] = r
}
}
*/
}
if handler.fallbacks[""] != nil {
for alpn, pfb := range handler.fallbacks {
if alpn != "" { // && alpn != "h2" {
for path, fb := range handler.fallbacks[""] {
if pfb[path] == nil {
pfb[path] = fb
}
}
}
}
}
}
return handler, nil
}
// Close implements common.Closable.Close().
func (h *Handler) Close() error {
return errors.Combine(common.Close(h.validator))
}
// AddUser implements proxy.UserManager.AddUser().
func (h *Handler) AddUser(ctx context.Context, u *protocol.MemoryUser) error {
return h.validator.Add(u)
}
// RemoveUser implements proxy.UserManager.RemoveUser().
func (h *Handler) RemoveUser(ctx context.Context, e string) error {
return h.validator.Del(e)
}
// Network implements proxy.Inbound.Network().
func (*Handler) Network() []net.Network {
return []net.Network{net.Network_TCP, net.Network_UNIX}
}
// Process implements proxy.Inbound.Process().
func (h *Handler) Process(ctx context.Context, network net.Network, connection internet.Connection, dispatcher routing.Dispatcher) error {
sid := session.ExportIDToError(ctx)
iConn := connection
statConn, ok := iConn.(*internet.StatCouterConnection)
if ok {
iConn = statConn.Connection
}
sessionPolicy := h.policyManager.ForLevel(0)
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
return newError("unable to set read deadline").Base(err).AtWarning()
}
first := buf.New()
defer first.Release()
firstLen, _ := first.ReadFrom(connection)
newError("firstLen = ", firstLen).AtInfo().WriteToLog(sid)
reader := &buf.BufferedReader{
Reader: buf.NewReader(connection),
Buffer: buf.MultiBuffer{first},
}
var request *protocol.RequestHeader
var requestAddons *encoding.Addons
var err error
apfb := h.fallbacks
isfb := apfb != nil
if isfb && firstLen < 18 {
err = newError("fallback directly")
} else {
request, requestAddons, isfb, err = encoding.DecodeRequestHeader(isfb, first, reader, h.validator)
}
if err != nil {
if isfb {
if err := connection.SetReadDeadline(time.Time{}); err != nil {
newError("unable to set back read deadline").Base(err).AtWarning().WriteToLog(sid)
}
newError("fallback starts").Base(err).AtInfo().WriteToLog(sid)
alpn := ""
if len(apfb) > 1 || apfb[""] == nil {
if tlsConn, ok := iConn.(*tls.Conn); ok {
alpn = tlsConn.ConnectionState().NegotiatedProtocol
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
}
if apfb[alpn] == nil {
alpn = ""
}
}
pfb := apfb[alpn]
if pfb == nil {
return newError(`failed to find the default "alpn" config`).AtWarning()
}
path := ""
if len(pfb) > 1 || pfb[""] == nil {
/*
if lines := bytes.Split(firstBytes, []byte{'\r', '\n'}); len(lines) > 1 {
if s := bytes.Split(lines[0], []byte{' '}); len(s) == 3 {
if len(s[0]) < 8 && len(s[1]) > 0 && len(s[2]) == 8 {
newError("realPath = " + string(s[1])).AtInfo().WriteToLog(sid)
for _, fb := range pfb {
if fb.Path != "" && h.regexps[fb.Path].Match(s[1]) {
path = fb.Path
break
}
}
}
}
}
*/
if firstLen >= 18 && first.Byte(4) != '*' { // not h2c
firstBytes := first.Bytes()
for i := 4; i <= 8; i++ { // 5 -> 9
if firstBytes[i] == '/' && firstBytes[i-1] == ' ' {
search := len(firstBytes)
if search > 64 {
search = 64 // up to about 60
}
for j := i + 1; j < search; j++ {
k := firstBytes[j]
if k == '\r' || k == '\n' { // avoid logging \r or \n
break
}
if k == ' ' {
path = string(firstBytes[i:j])
newError("realPath = " + path).AtInfo().WriteToLog(sid)
if pfb[path] == nil {
path = ""
}
break
}
}
break
}
}
}
}
fb := pfb[path]
if fb == nil {
return newError(`failed to find the default "path" config`).AtWarning()
}
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)
var conn net.Conn
if err := retry.ExponentialBackoff(5, 100).On(func() error {
var dialer net.Dialer
conn, err = dialer.DialContext(ctx, fb.Type, fb.Dest)
if err != nil {
return err
}
return nil
}); err != nil {
return newError("failed to dial to " + fb.Dest).Base(err).AtWarning()
}
defer conn.Close()
serverReader := buf.NewReader(conn)
serverWriter := buf.NewWriter(conn)
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
if fb.Xver != 0 {
remoteAddr, remotePort, err := net.SplitHostPort(connection.RemoteAddr().String())
if err != nil {
return err
}
localAddr, localPort, err := net.SplitHostPort(connection.LocalAddr().String())
if err != nil {
return err
}
ipv4 := true
for i := 0; i < len(remoteAddr); i++ {
if remoteAddr[i] == ':' {
ipv4 = false
break
}
}
pro := buf.New()
defer pro.Release()
switch fb.Xver {
case 1:
if ipv4 {
pro.Write([]byte("PROXY TCP4 " + remoteAddr + " " + localAddr + " " + remotePort + " " + localPort + "\r\n"))
} else {
pro.Write([]byte("PROXY TCP6 " + remoteAddr + " " + localAddr + " " + remotePort + " " + localPort + "\r\n"))
}
case 2:
pro.Write([]byte("\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x21")) // signature + v2 + PROXY
if ipv4 {
pro.Write([]byte("\x11\x00\x0C")) // AF_INET + STREAM + 12 bytes
pro.Write(net.ParseIP(remoteAddr).To4())
pro.Write(net.ParseIP(localAddr).To4())
} else {
pro.Write([]byte("\x21\x00\x24")) // AF_INET6 + STREAM + 36 bytes
pro.Write(net.ParseIP(remoteAddr).To16())
pro.Write(net.ParseIP(localAddr).To16())
}
p1, _ := strconv.ParseUint(remotePort, 10, 16)
p2, _ := strconv.ParseUint(localPort, 10, 16)
pro.Write([]byte{byte(p1 >> 8), byte(p1), byte(p2 >> 8), byte(p2)})
}
if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {
return newError("failed to set PROXY protocol v", fb.Xver).Base(err).AtWarning()
}
}
if err := buf.Copy(reader, serverWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to fallback request payload").Base(err).AtInfo()
}
return nil
}
writer := buf.NewWriter(connection)
getResponse := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
if err := buf.Copy(serverReader, writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to deliver response payload").Base(err).AtInfo()
}
return nil
}
if err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), task.OnSuccess(getResponse, task.Close(writer))); err != nil {
common.Interrupt(serverReader)
common.Interrupt(serverWriter)
return newError("fallback ends").Base(err).AtInfo()
}
return nil
}
if errors.Cause(err) != io.EOF {
log.Record(&log.AccessMessage{
From: connection.RemoteAddr(),
To: "",
Status: log.AccessRejected,
Reason: err,
})
err = newError("invalid request from ", connection.RemoteAddr()).Base(err).AtInfo()
}
return err
}
if err := connection.SetReadDeadline(time.Time{}); err != nil {
newError("unable to set back read deadline").Base(err).AtWarning().WriteToLog(sid)
}
newError("received request for ", request.Destination()).AtInfo().WriteToLog(sid)
inbound := session.InboundFromContext(ctx)
if inbound == nil {
panic("no inbound metadata")
}
inbound.User = request.User
responseAddons := &encoding.Addons{}
if request.Command != protocol.RequestCommandMux {
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: connection.RemoteAddr(),
To: request.Destination(),
Status: log.AccessAccepted,
Reason: "",
Email: request.User.Email,
})
}
sessionPolicy = h.policyManager.ForLevel(request.User.Level)
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)
link, err := dispatcher.Dispatch(ctx, request.Destination())
if err != nil {
return newError("failed to dispatch request to ", request.Destination()).Base(err).AtWarning()
}
serverReader := link.Reader // .(*pipe.Reader)
serverWriter := link.Writer // .(*pipe.Writer)
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
// default: clientReader := reader
clientReader := encoding.DecodeBodyAddons(reader, request, requestAddons)
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
if err := buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transfer request payload").Base(err).AtInfo()
}
return nil
}
getResponse := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(connection))
if err := encoding.EncodeResponseHeader(bufferWriter, request, responseAddons); err != nil {
return newError("failed to encode response header").Base(err).AtWarning()
}
// default: clientWriter := bufferWriter
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, responseAddons)
{
multiBuffer, err := serverReader.ReadMultiBuffer()
if err != nil {
return err // ...
}
if err := clientWriter.WriteMultiBuffer(multiBuffer); err != nil {
return err // ...
}
}
// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer
if err := bufferWriter.SetBuffered(false); err != nil {
return newError("failed to write A response payload").Base(err).AtWarning()
}
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
if err := buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transfer response payload").Base(err).AtInfo()
}
return nil
}
if err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), getResponse); err != nil {
common.Interrupt(serverReader)
common.Interrupt(serverWriter)
return newError("connection ends").Base(err).AtInfo()
}
return nil
}
v2ray-core-4.34.0/proxy/vless/outbound/ 0000775 0000000 0000000 00000000000 13774574720 0017767 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/vless/outbound/config.go 0000664 0000000 0000000 00000000046 13774574720 0021563 0 ustar 00root root 0000000 0000000 // +build !confonly
package outbound
v2ray-core-4.34.0/proxy/vless/outbound/config.pb.go 0000664 0000000 0000000 00000014431 13774574720 0022166 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/vless/outbound/config.proto
package outbound
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
protocol "v2ray.com/core/common/protocol"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Vnext []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=vnext,proto3" json:"vnext,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_vless_outbound_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_proxy_vless_outbound_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_proxy_vless_outbound_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetVnext() []*protocol.ServerEndpoint {
if x != nil {
return x.Vnext
}
return nil
}
var File_proxy_vless_outbound_config_proto protoreflect.FileDescriptor
var file_proxy_vless_outbound_config_proto_rawDesc = []byte{
0x0a, 0x21, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x6f, 0x75,
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x1f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x6f, 0x75, 0x74, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65,
0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4a, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x12, 0x40, 0x0a, 0x05, 0x76, 0x6e, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65,
0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x6e,
0x65, 0x78, 0x74, 0x42, 0x6e, 0x0a, 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73,
0x73, 0x2e, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x23, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e,
0x64, 0xaa, 0x02, 0x1f, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50,
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proxy_vless_outbound_config_proto_rawDescOnce sync.Once
file_proxy_vless_outbound_config_proto_rawDescData = file_proxy_vless_outbound_config_proto_rawDesc
)
func file_proxy_vless_outbound_config_proto_rawDescGZIP() []byte {
file_proxy_vless_outbound_config_proto_rawDescOnce.Do(func() {
file_proxy_vless_outbound_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_vless_outbound_config_proto_rawDescData)
})
return file_proxy_vless_outbound_config_proto_rawDescData
}
var file_proxy_vless_outbound_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_proxy_vless_outbound_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: v2ray.core.proxy.vless.outbound.Config
(*protocol.ServerEndpoint)(nil), // 1: v2ray.core.common.protocol.ServerEndpoint
}
var file_proxy_vless_outbound_config_proto_depIdxs = []int32{
1, // 0: v2ray.core.proxy.vless.outbound.Config.vnext:type_name -> v2ray.core.common.protocol.ServerEndpoint
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_proxy_vless_outbound_config_proto_init() }
func file_proxy_vless_outbound_config_proto_init() {
if File_proxy_vless_outbound_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_vless_outbound_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_vless_outbound_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_vless_outbound_config_proto_goTypes,
DependencyIndexes: file_proxy_vless_outbound_config_proto_depIdxs,
MessageInfos: file_proxy_vless_outbound_config_proto_msgTypes,
}.Build()
File_proxy_vless_outbound_config_proto = out.File
file_proxy_vless_outbound_config_proto_rawDesc = nil
file_proxy_vless_outbound_config_proto_goTypes = nil
file_proxy_vless_outbound_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/vless/outbound/config.proto 0000664 0000000 0000000 00000000626 13774574720 0022325 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.vless.outbound;
option csharp_namespace = "V2Ray.Core.Proxy.Vless.Outbound";
option go_package = "v2ray.com/core/proxy/vless/outbound";
option java_package = "com.v2ray.core.proxy.vless.outbound";
option java_multiple_files = true;
import "common/protocol/server_spec.proto";
message Config {
repeated v2ray.core.common.protocol.ServerEndpoint vnext = 1;
}
v2ray-core-4.34.0/proxy/vless/outbound/errors.generated.go 0000664 0000000 0000000 00000000316 13774574720 0023567 0 ustar 00root root 0000000 0000000 package outbound
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/vless/outbound/outbound.go 0000664 0000000 0000000 00000012056 13774574720 0022161 0 ustar 00root root 0000000 0000000 // +build !confonly
package outbound
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/retry"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/policy"
"v2ray.com/core/proxy/vless"
"v2ray.com/core/proxy/vless/encoding"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
)
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
}))
}
// Handler is an outbound connection handler for VLess protocol.
type Handler struct {
serverList *protocol.ServerList
serverPicker protocol.ServerPicker
policyManager policy.Manager
}
// New creates a new VLess outbound handler.
func New(ctx context.Context, config *Config) (*Handler, error) {
serverList := protocol.NewServerList()
for _, rec := range config.Vnext {
s, err := protocol.NewServerSpecFromPB(rec)
if err != nil {
return nil, newError("failed to parse server spec").Base(err).AtError()
}
serverList.AddServer(s)
}
v := core.MustFromContext(ctx)
handler := &Handler{
serverList: serverList,
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
}
return handler, nil
}
// Process implements proxy.Outbound.Process().
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
var rec *protocol.ServerSpec
var conn internet.Connection
if err := retry.ExponentialBackoff(5, 200).On(func() error {
rec = h.serverPicker.PickServer()
var err error
conn, err = dialer.Dial(ctx, rec.Destination())
if err != nil {
return err
}
return nil
}); err != nil {
return newError("failed to find an available destination").Base(err).AtWarning()
}
defer conn.Close()
outbound := session.OutboundFromContext(ctx)
if outbound == nil || !outbound.Target.IsValid() {
return newError("target not specified").AtError()
}
target := outbound.Target
newError("tunneling request to ", target, " via ", rec.Destination()).AtInfo().WriteToLog(session.ExportIDToError(ctx))
command := protocol.RequestCommandTCP
if target.Network == net.Network_UDP {
command = protocol.RequestCommandUDP
}
if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.cool" {
command = protocol.RequestCommandMux
}
request := &protocol.RequestHeader{
Version: encoding.Version,
User: rec.PickUser(),
Command: command,
Address: target.Address,
Port: target.Port,
}
account := request.User.Account.(*vless.MemoryAccount)
requestAddons := &encoding.Addons{
Flow: account.Flow,
}
sessionPolicy := h.policyManager.ForLevel(request.User.Level)
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
clientReader := link.Reader // .(*pipe.Reader)
clientWriter := link.Writer // .(*pipe.Writer)
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
if err := encoding.EncodeRequestHeader(bufferWriter, request, requestAddons); err != nil {
return newError("failed to encode request header").Base(err).AtWarning()
}
// default: serverWriter := bufferWriter
serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons)
if err := buf.CopyOnceTimeout(clientReader, serverWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
return err // ...
}
// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer
if err := bufferWriter.SetBuffered(false); err != nil {
return newError("failed to write A request payload").Base(err).AtWarning()
}
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
if err := buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transfer request payload").Base(err).AtInfo()
}
return nil
}
getResponse := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
responseAddons, err := encoding.DecodeResponseHeader(conn, request)
if err != nil {
return newError("failed to decode response header").Base(err).AtInfo()
}
// default: serverReader := buf.NewReader(conn)
serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons)
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
if err := buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transfer response payload").Base(err).AtInfo()
}
return nil
}
if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil {
return newError("connection ends").Base(err).AtInfo()
}
return nil
}
v2ray-core-4.34.0/proxy/vless/validator.go 0000664 0000000 0000000 00000002340 13774574720 0020443 0 ustar 00root root 0000000 0000000 // +build !confonly
package vless
import (
"strings"
"sync"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/uuid"
)
// Validator stores valid VLESS 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 VLESS user, Email must be empty or unique.
func (v *Validator) Add(u *protocol.MemoryUser) error {
if u.Email != "" {
_, loaded := v.email.LoadOrStore(strings.ToLower(u.Email), u)
if loaded {
return newError("User ", u.Email, " already exists.")
}
}
v.users.Store(u.Account.(*MemoryAccount).ID.UUID(), u)
return nil
}
// Del a VLESS 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.")
}
v.email.Delete(le)
v.users.Delete(u.(*protocol.MemoryUser).Account.(*MemoryAccount).ID.UUID())
return nil
}
// Get a VLESS user with UUID, nil if user doesn't exist.
func (v *Validator) Get(id uuid.UUID) *protocol.MemoryUser {
u, _ := v.users.Load(id)
if u != nil {
return u.(*protocol.MemoryUser)
}
return nil
}
v2ray-core-4.34.0/proxy/vless/vless.go 0000664 0000000 0000000 00000000611 13774574720 0017611 0 ustar 00root root 0000000 0000000 // Package vless contains the implementation of VLess protocol and transportation.
//
// VLess contains both inbound and outbound connections. VLess inbound is usually used on servers
// together with 'freedom' to talk to final destination, while VLess outbound is usually used on
// clients with 'socks' for proxying.
package vless
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/proxy/vmess/ 0000775 0000000 0000000 00000000000 13774574720 0016131 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/vmess/account.go 0000664 0000000 0000000 00000002530 13774574720 0020114 0 ustar 00root root 0000000 0000000 // +build !confonly
package vmess
import (
"v2ray.com/core/common/dice"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/uuid"
)
// MemoryAccount is an in-memory form of VMess account.
type MemoryAccount struct {
// ID is the main ID of the account.
ID *protocol.ID
// AlterIDs are the alternative IDs of the account.
AlterIDs []*protocol.ID
// Security type of the account. Used for client connections.
Security protocol.SecurityType
}
// AnyValidID returns an ID that is either the main ID or one of the alternative IDs if any.
func (a *MemoryAccount) AnyValidID() *protocol.ID {
if len(a.AlterIDs) == 0 {
return a.ID
}
return a.AlterIDs[dice.Roll(len(a.AlterIDs))]
}
// Equals implements protocol.Account.
func (a *MemoryAccount) Equals(account protocol.Account) bool {
vmessAccount, ok := account.(*MemoryAccount)
if !ok {
return false
}
// TODO: handle AlterIds difference
return a.ID.Equals(vmessAccount.ID)
}
// AsAccount implements protocol.Account.
func (a *Account) AsAccount() (protocol.Account, error) {
id, err := uuid.ParseString(a.Id)
if err != nil {
return nil, newError("failed to parse ID").Base(err).AtError()
}
protoID := protocol.NewID(id)
return &MemoryAccount{
ID: protoID,
AlterIDs: protocol.NewAlterIDs(protoID, uint16(a.AlterId)),
Security: a.SecuritySettings.GetSecurityType(),
}, nil
}
v2ray-core-4.34.0/proxy/vmess/account.pb.go 0000664 0000000 0000000 00000016432 13774574720 0020522 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/vmess/account.proto
package vmess
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
protocol "v2ray.com/core/common/protocol"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Account struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// ID of the account, in the form of a UUID, e.g.,
// "66ad4540-b58c-4ad2-9926-ea63445a9b57".
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
// Number of alternative IDs. Client and server must share the same number.
AlterId uint32 `protobuf:"varint,2,opt,name=alter_id,json=alterId,proto3" json:"alter_id,omitempty"`
// Security settings. Only applies to client side.
SecuritySettings *protocol.SecurityConfig `protobuf:"bytes,3,opt,name=security_settings,json=securitySettings,proto3" json:"security_settings,omitempty"`
// Define tests enabled for this account
TestsEnabled string `protobuf:"bytes,4,opt,name=tests_enabled,json=testsEnabled,proto3" json:"tests_enabled,omitempty"`
}
func (x *Account) Reset() {
*x = Account{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_vmess_account_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Account) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Account) ProtoMessage() {}
func (x *Account) ProtoReflect() protoreflect.Message {
mi := &file_proxy_vmess_account_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Account.ProtoReflect.Descriptor instead.
func (*Account) Descriptor() ([]byte, []int) {
return file_proxy_vmess_account_proto_rawDescGZIP(), []int{0}
}
func (x *Account) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *Account) GetAlterId() uint32 {
if x != nil {
return x.AlterId
}
return 0
}
func (x *Account) GetSecuritySettings() *protocol.SecurityConfig {
if x != nil {
return x.SecuritySettings
}
return nil
}
func (x *Account) GetTestsEnabled() string {
if x != nil {
return x.TestsEnabled
}
return ""
}
var File_proxy_vmess_account_proto protoreflect.FileDescriptor
var file_proxy_vmess_account_proto_rawDesc = []byte{
0x0a, 0x19, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x61, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d,
0x65, 0x73, 0x73, 0x1a, 0x1d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x22, 0xb2, 0x01, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e,
0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19,
0x0a, 0x08, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x07, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x57, 0x0a, 0x11, 0x73, 0x65, 0x63,
0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
0x65, 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, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x52, 0x10, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x65, 0x73, 0x74, 0x73, 0x5f, 0x65, 0x6e, 0x61, 0x62,
0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x65, 0x73, 0x74, 0x73,
0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x42, 0x53, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
0x76, 0x6d, 0x65, 0x73, 0x73, 0x50, 0x01, 0x5a, 0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6d,
0x65, 0x73, 0x73, 0xaa, 0x02, 0x16, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65,
0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6d, 0x65, 0x73, 0x73, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proxy_vmess_account_proto_rawDescOnce sync.Once
file_proxy_vmess_account_proto_rawDescData = file_proxy_vmess_account_proto_rawDesc
)
func file_proxy_vmess_account_proto_rawDescGZIP() []byte {
file_proxy_vmess_account_proto_rawDescOnce.Do(func() {
file_proxy_vmess_account_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_vmess_account_proto_rawDescData)
})
return file_proxy_vmess_account_proto_rawDescData
}
var file_proxy_vmess_account_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_proxy_vmess_account_proto_goTypes = []interface{}{
(*Account)(nil), // 0: v2ray.core.proxy.vmess.Account
(*protocol.SecurityConfig)(nil), // 1: v2ray.core.common.protocol.SecurityConfig
}
var file_proxy_vmess_account_proto_depIdxs = []int32{
1, // 0: v2ray.core.proxy.vmess.Account.security_settings:type_name -> v2ray.core.common.protocol.SecurityConfig
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_proxy_vmess_account_proto_init() }
func file_proxy_vmess_account_proto_init() {
if File_proxy_vmess_account_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_vmess_account_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Account); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_vmess_account_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_vmess_account_proto_goTypes,
DependencyIndexes: file_proxy_vmess_account_proto_depIdxs,
MessageInfos: file_proxy_vmess_account_proto_msgTypes,
}.Build()
File_proxy_vmess_account_proto = out.File
file_proxy_vmess_account_proto_rawDesc = nil
file_proxy_vmess_account_proto_goTypes = nil
file_proxy_vmess_account_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/vmess/account.proto 0000664 0000000 0000000 00000001306 13774574720 0020652 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.vmess;
option csharp_namespace = "V2Ray.Core.Proxy.Vmess";
option go_package = "v2ray.com/core/proxy/vmess";
option java_package = "com.v2ray.core.proxy.vmess";
option java_multiple_files = true;
import "common/protocol/headers.proto";
message Account {
// ID of the account, in the form of a UUID, e.g.,
// "66ad4540-b58c-4ad2-9926-ea63445a9b57".
string id = 1;
// Number of alternative IDs. Client and server must share the same number.
uint32 alter_id = 2;
// Security settings. Only applies to client side.
v2ray.core.common.protocol.SecurityConfig security_settings = 3;
// Define tests enabled for this account
string tests_enabled = 4;
}
v2ray-core-4.34.0/proxy/vmess/aead/ 0000775 0000000 0000000 00000000000 13774574720 0017023 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/vmess/aead/authid.go 0000664 0000000 0000000 00000005236 13774574720 0020636 0 ustar 00root root 0000000 0000000 package aead
import (
"bytes"
"crypto/aes"
"crypto/cipher"
rand3 "crypto/rand"
"encoding/binary"
"errors"
"hash/crc32"
"io"
"math"
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/antireplay"
)
var (
ErrNotFound = errors.New("user do not exist")
ErrReplay = errors.New("replayed request")
)
func CreateAuthID(cmdKey []byte, time int64) [16]byte {
buf := bytes.NewBuffer(nil)
common.Must(binary.Write(buf, binary.BigEndian, time))
var zero uint32
common.Must2(io.CopyN(buf, rand3.Reader, 4))
zero = crc32.ChecksumIEEE(buf.Bytes())
common.Must(binary.Write(buf, binary.BigEndian, zero))
aesBlock := NewCipherFromKey(cmdKey)
if buf.Len() != 16 {
panic("Size unexpected")
}
var result [16]byte
aesBlock.Encrypt(result[:], buf.Bytes())
return result
}
func NewCipherFromKey(cmdKey []byte) cipher.Block {
aesBlock, err := aes.NewCipher(KDF16(cmdKey, KDFSaltConstAuthIDEncryptionKey))
if err != nil {
panic(err)
}
return aesBlock
}
type AuthIDDecoder struct {
s cipher.Block
}
func NewAuthIDDecoder(cmdKey []byte) *AuthIDDecoder {
return &AuthIDDecoder{NewCipherFromKey(cmdKey)}
}
func (aidd *AuthIDDecoder) Decode(data [16]byte) (int64, uint32, int32, []byte) {
aidd.s.Decrypt(data[:], data[:])
var t int64
var zero uint32
var rand int32
reader := bytes.NewReader(data[:])
common.Must(binary.Read(reader, binary.BigEndian, &t))
common.Must(binary.Read(reader, binary.BigEndian, &rand))
common.Must(binary.Read(reader, binary.BigEndian, &zero))
return t, zero, rand, data[:]
}
func NewAuthIDDecoderHolder() *AuthIDDecoderHolder {
return &AuthIDDecoderHolder{make(map[string]*AuthIDDecoderItem), antireplay.NewReplayFilter(120)}
}
type AuthIDDecoderHolder struct {
decoders map[string]*AuthIDDecoderItem
filter *antireplay.ReplayFilter
}
type AuthIDDecoderItem struct {
dec *AuthIDDecoder
ticket interface{}
}
func NewAuthIDDecoderItem(key [16]byte, ticket interface{}) *AuthIDDecoderItem {
return &AuthIDDecoderItem{
dec: NewAuthIDDecoder(key[:]),
ticket: ticket,
}
}
func (a *AuthIDDecoderHolder) AddUser(key [16]byte, ticket interface{}) {
a.decoders[string(key[:])] = NewAuthIDDecoderItem(key, ticket)
}
func (a *AuthIDDecoderHolder) RemoveUser(key [16]byte) {
delete(a.decoders, string(key[:]))
}
func (a *AuthIDDecoderHolder) Match(authID [16]byte) (interface{}, error) {
for _, v := range a.decoders {
t, z, _, d := v.dec.Decode(authID)
if z != crc32.ChecksumIEEE(d[:12]) {
continue
}
if t < 0 {
continue
}
if math.Abs(math.Abs(float64(t))-float64(time.Now().Unix())) > 120 {
continue
}
if !a.filter.Check(authID[:]) {
return nil, ErrReplay
}
return v.ticket, nil
}
return nil, ErrNotFound
}
v2ray-core-4.34.0/proxy/vmess/aead/authid_test.go 0000664 0000000 0000000 00000006372 13774574720 0021677 0 ustar 00root root 0000000 0000000 package aead
import (
"fmt"
"strconv"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestCreateAuthID(t *testing.T) {
key := KDF16([]byte("Demo Key for Auth ID Test"), "Demo Path for Auth ID Test")
authid := CreateAuthID(key, time.Now().Unix())
fmt.Println(key)
fmt.Println(authid)
}
func TestCreateAuthIDAndDecode(t *testing.T) {
key := KDF16([]byte("Demo Key for Auth ID Test"), "Demo Path for Auth ID Test")
authid := CreateAuthID(key, time.Now().Unix())
fmt.Println(key)
fmt.Println(authid)
AuthDecoder := NewAuthIDDecoderHolder()
var keyw [16]byte
copy(keyw[:], key)
AuthDecoder.AddUser(keyw, "Demo User")
res, err := AuthDecoder.Match(authid)
fmt.Println(res)
fmt.Println(err)
assert.Equal(t, "Demo User", res)
assert.Nil(t, err)
}
func TestCreateAuthIDAndDecode2(t *testing.T) {
key := KDF16([]byte("Demo Key for Auth ID Test"), "Demo Path for Auth ID Test")
authid := CreateAuthID(key, time.Now().Unix())
fmt.Println(key)
fmt.Println(authid)
AuthDecoder := NewAuthIDDecoderHolder()
var keyw [16]byte
copy(keyw[:], key)
AuthDecoder.AddUser(keyw, "Demo User")
res, err := AuthDecoder.Match(authid)
fmt.Println(res)
fmt.Println(err)
assert.Equal(t, "Demo User", res)
assert.Nil(t, err)
key2 := KDF16([]byte("Demo Key for Auth ID Test2"), "Demo Path for Auth ID Test")
authid2 := CreateAuthID(key2, time.Now().Unix())
res2, err2 := AuthDecoder.Match(authid2)
assert.EqualError(t, err2, "user do not exist")
assert.Nil(t, res2)
}
func TestCreateAuthIDAndDecodeMassive(t *testing.T) {
key := KDF16([]byte("Demo Key for Auth ID Test"), "Demo Path for Auth ID Test")
authid := CreateAuthID(key, time.Now().Unix())
fmt.Println(key)
fmt.Println(authid)
AuthDecoder := NewAuthIDDecoderHolder()
var keyw [16]byte
copy(keyw[:], key)
AuthDecoder.AddUser(keyw, "Demo User")
res, err := AuthDecoder.Match(authid)
fmt.Println(res)
fmt.Println(err)
assert.Equal(t, "Demo User", res)
assert.Nil(t, err)
for i := 0; i <= 10000; i++ {
key2 := KDF16([]byte("Demo Key for Auth ID Test2"), "Demo Path for Auth ID Test", strconv.Itoa(i))
var keyw2 [16]byte
copy(keyw2[:], key2)
AuthDecoder.AddUser(keyw2, "Demo User"+strconv.Itoa(i))
}
authid3 := CreateAuthID(key, time.Now().Unix())
res2, err2 := AuthDecoder.Match(authid3)
assert.Equal(t, "Demo User", res2)
assert.Nil(t, err2)
}
func TestCreateAuthIDAndDecodeSuperMassive(t *testing.T) {
key := KDF16([]byte("Demo Key for Auth ID Test"), "Demo Path for Auth ID Test")
authid := CreateAuthID(key, time.Now().Unix())
fmt.Println(key)
fmt.Println(authid)
AuthDecoder := NewAuthIDDecoderHolder()
var keyw [16]byte
copy(keyw[:], key)
AuthDecoder.AddUser(keyw, "Demo User")
res, err := AuthDecoder.Match(authid)
fmt.Println(res)
fmt.Println(err)
assert.Equal(t, "Demo User", res)
assert.Nil(t, err)
for i := 0; i <= 1000000; i++ {
key2 := KDF16([]byte("Demo Key for Auth ID Test2"), "Demo Path for Auth ID Test", strconv.Itoa(i))
var keyw2 [16]byte
copy(keyw2[:], key2)
AuthDecoder.AddUser(keyw2, "Demo User"+strconv.Itoa(i))
}
authid3 := CreateAuthID(key, time.Now().Unix())
before := time.Now()
res2, err2 := AuthDecoder.Match(authid3)
after := time.Now()
assert.Equal(t, "Demo User", res2)
assert.Nil(t, err2)
fmt.Println(after.Sub(before).Seconds())
}
v2ray-core-4.34.0/proxy/vmess/aead/consts.go 0000664 0000000 0000000 00000001354 13774574720 0020666 0 ustar 00root root 0000000 0000000 package aead
const (
KDFSaltConstAuthIDEncryptionKey = "AES Auth ID Encryption"
KDFSaltConstAEADRespHeaderLenKey = "AEAD Resp Header Len Key"
KDFSaltConstAEADRespHeaderLenIV = "AEAD Resp Header Len IV"
KDFSaltConstAEADRespHeaderPayloadKey = "AEAD Resp Header Key"
KDFSaltConstAEADRespHeaderPayloadIV = "AEAD Resp Header IV"
KDFSaltConstVMessAEADKDF = "VMess AEAD KDF"
KDFSaltConstVMessHeaderPayloadAEADKey = "VMess Header AEAD Key"
KDFSaltConstVMessHeaderPayloadAEADIV = "VMess Header AEAD Nonce"
KDFSaltConstVMessHeaderPayloadLengthAEADKey = "VMess Header AEAD Key_Length"
KDFSaltConstVMessHeaderPayloadLengthAEADIV = "VMess Header AEAD Nonce_Length"
)
v2ray-core-4.34.0/proxy/vmess/aead/encrypt.go 0000664 0000000 0000000 00000012132 13774574720 0021035 0 ustar 00root root 0000000 0000000 package aead
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/binary"
"io"
"time"
"v2ray.com/core/common"
)
func SealVMessAEADHeader(key [16]byte, data []byte) []byte {
generatedAuthID := CreateAuthID(key[:], time.Now().Unix())
connectionNonce := make([]byte, 8)
if _, err := io.ReadFull(rand.Reader, connectionNonce); err != nil {
panic(err.Error())
}
aeadPayloadLengthSerializeBuffer := bytes.NewBuffer(nil)
headerPayloadDataLen := uint16(len(data))
common.Must(binary.Write(aeadPayloadLengthSerializeBuffer, binary.BigEndian, headerPayloadDataLen))
aeadPayloadLengthSerializedByte := aeadPayloadLengthSerializeBuffer.Bytes()
var payloadHeaderLengthAEADEncrypted []byte
{
payloadHeaderLengthAEADKey := KDF16(key[:], KDFSaltConstVMessHeaderPayloadLengthAEADKey, string(generatedAuthID[:]), string(connectionNonce))
payloadHeaderLengthAEADNonce := KDF(key[:], KDFSaltConstVMessHeaderPayloadLengthAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12]
payloadHeaderLengthAEADAESBlock, err := aes.NewCipher(payloadHeaderLengthAEADKey)
if err != nil {
panic(err.Error())
}
payloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderLengthAEADAESBlock)
if err != nil {
panic(err.Error())
}
payloadHeaderLengthAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderLengthAEADNonce, aeadPayloadLengthSerializedByte, generatedAuthID[:])
}
var payloadHeaderAEADEncrypted []byte
{
payloadHeaderAEADKey := KDF16(key[:], KDFSaltConstVMessHeaderPayloadAEADKey, string(generatedAuthID[:]), string(connectionNonce))
payloadHeaderAEADNonce := KDF(key[:], KDFSaltConstVMessHeaderPayloadAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12]
payloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderAEADKey)
if err != nil {
panic(err.Error())
}
payloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock)
if err != nil {
panic(err.Error())
}
payloadHeaderAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderAEADNonce, data, generatedAuthID[:])
}
var outputBuffer = bytes.NewBuffer(nil)
common.Must2(outputBuffer.Write(generatedAuthID[:])) // 16
common.Must2(outputBuffer.Write(payloadHeaderLengthAEADEncrypted)) // 2+16
common.Must2(outputBuffer.Write(connectionNonce)) // 8
common.Must2(outputBuffer.Write(payloadHeaderAEADEncrypted))
return outputBuffer.Bytes()
}
func OpenVMessAEADHeader(key [16]byte, authid [16]byte, data io.Reader) ([]byte, bool, int, error) {
var payloadHeaderLengthAEADEncrypted [18]byte
var nonce [8]byte
var bytesRead int
authidCheckValueReadBytesCounts, err := io.ReadFull(data, payloadHeaderLengthAEADEncrypted[:])
bytesRead += authidCheckValueReadBytesCounts
if err != nil {
return nil, false, bytesRead, err
}
nonceReadBytesCounts, err := io.ReadFull(data, nonce[:])
bytesRead += nonceReadBytesCounts
if err != nil {
return nil, false, bytesRead, err
}
// Decrypt Length
var decryptedAEADHeaderLengthPayloadResult []byte
{
payloadHeaderLengthAEADKey := KDF16(key[:], KDFSaltConstVMessHeaderPayloadLengthAEADKey, string(authid[:]), string(nonce[:]))
payloadHeaderLengthAEADNonce := KDF(key[:], KDFSaltConstVMessHeaderPayloadLengthAEADIV, string(authid[:]), string(nonce[:]))[:12]
payloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderLengthAEADKey)
if err != nil {
panic(err.Error())
}
payloadHeaderLengthAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock)
if err != nil {
panic(err.Error())
}
decryptedAEADHeaderLengthPayload, erropenAEAD := payloadHeaderLengthAEAD.Open(nil, payloadHeaderLengthAEADNonce, payloadHeaderLengthAEADEncrypted[:], authid[:])
if erropenAEAD != nil {
return nil, true, bytesRead, erropenAEAD
}
decryptedAEADHeaderLengthPayloadResult = decryptedAEADHeaderLengthPayload
}
var length uint16
common.Must(binary.Read(bytes.NewReader(decryptedAEADHeaderLengthPayloadResult), binary.BigEndian, &length))
var decryptedAEADHeaderPayloadR []byte
var payloadHeaderAEADEncryptedReadedBytesCounts int
{
payloadHeaderAEADKey := KDF16(key[:], KDFSaltConstVMessHeaderPayloadAEADKey, string(authid[:]), string(nonce[:]))
payloadHeaderAEADNonce := KDF(key[:], KDFSaltConstVMessHeaderPayloadAEADIV, string(authid[:]), string(nonce[:]))[:12]
// 16 == AEAD Tag size
payloadHeaderAEADEncrypted := make([]byte, length+16)
payloadHeaderAEADEncryptedReadedBytesCounts, err = io.ReadFull(data, payloadHeaderAEADEncrypted)
bytesRead += payloadHeaderAEADEncryptedReadedBytesCounts
if err != nil {
return nil, false, bytesRead, err
}
payloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderAEADKey)
if err != nil {
panic(err.Error())
}
payloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock)
if err != nil {
panic(err.Error())
}
decryptedAEADHeaderPayload, erropenAEAD := payloadHeaderAEAD.Open(nil, payloadHeaderAEADNonce, payloadHeaderAEADEncrypted, authid[:])
if erropenAEAD != nil {
return nil, true, bytesRead, erropenAEAD
}
decryptedAEADHeaderPayloadR = decryptedAEADHeaderPayload
}
return decryptedAEADHeaderPayloadR, false, bytesRead, nil
}
v2ray-core-4.34.0/proxy/vmess/aead/encrypt_test.go 0000664 0000000 0000000 00000004755 13774574720 0022110 0 ustar 00root root 0000000 0000000 package aead
import (
"bytes"
"fmt"
"io"
"testing"
"github.com/stretchr/testify/assert"
)
func TestOpenVMessAEADHeader(t *testing.T) {
TestHeader := []byte("Test Header")
key := KDF16([]byte("Demo Key for Auth ID Test"), "Demo Path for Auth ID Test")
var keyw [16]byte
copy(keyw[:], key)
sealed := SealVMessAEADHeader(keyw, TestHeader)
var AEADR = bytes.NewReader(sealed)
var authid [16]byte
io.ReadFull(AEADR, authid[:])
out, _, _, err := OpenVMessAEADHeader(keyw, authid, AEADR)
fmt.Println(string(out))
fmt.Println(err)
}
func TestOpenVMessAEADHeader2(t *testing.T) {
TestHeader := []byte("Test Header")
key := KDF16([]byte("Demo Key for Auth ID Test"), "Demo Path for Auth ID Test")
var keyw [16]byte
copy(keyw[:], key)
sealed := SealVMessAEADHeader(keyw, TestHeader)
var AEADR = bytes.NewReader(sealed)
var authid [16]byte
io.ReadFull(AEADR, authid[:])
out, _, readen, err := OpenVMessAEADHeader(keyw, authid, AEADR)
assert.Equal(t, len(sealed)-16-AEADR.Len(), readen)
assert.Equal(t, string(TestHeader), string(out))
assert.Nil(t, err)
}
func TestOpenVMessAEADHeader4(t *testing.T) {
for i := 0; i <= 60; i++ {
TestHeader := []byte("Test Header")
key := KDF16([]byte("Demo Key for Auth ID Test"), "Demo Path for Auth ID Test")
var keyw [16]byte
copy(keyw[:], key)
sealed := SealVMessAEADHeader(keyw, TestHeader)
var sealedm [16]byte
copy(sealedm[:], sealed)
sealed[i] ^= 0xff
var AEADR = bytes.NewReader(sealed)
var authid [16]byte
io.ReadFull(AEADR, authid[:])
out, drain, readen, err := OpenVMessAEADHeader(keyw, authid, AEADR)
assert.Equal(t, len(sealed)-16-AEADR.Len(), readen)
assert.Equal(t, true, drain)
assert.NotNil(t, err)
if err == nil {
fmt.Println(">")
}
assert.Nil(t, out)
}
}
func TestOpenVMessAEADHeader4Massive(t *testing.T) {
for j := 0; j < 1000; j++ {
for i := 0; i <= 60; i++ {
TestHeader := []byte("Test Header")
key := KDF16([]byte("Demo Key for Auth ID Test"), "Demo Path for Auth ID Test")
var keyw [16]byte
copy(keyw[:], key)
sealed := SealVMessAEADHeader(keyw, TestHeader)
var sealedm [16]byte
copy(sealedm[:], sealed)
sealed[i] ^= 0xff
var AEADR = bytes.NewReader(sealed)
var authid [16]byte
io.ReadFull(AEADR, authid[:])
out, drain, readen, err := OpenVMessAEADHeader(keyw, authid, AEADR)
assert.Equal(t, len(sealed)-16-AEADR.Len(), readen)
assert.Equal(t, true, drain)
assert.NotNil(t, err)
if err == nil {
fmt.Println(">")
}
assert.Nil(t, out)
}
}
}
v2ray-core-4.34.0/proxy/vmess/aead/kdf.go 0000664 0000000 0000000 00000000632 13774574720 0020117 0 ustar 00root root 0000000 0000000 package aead
import (
"crypto/hmac"
"crypto/sha256"
"hash"
)
func KDF(key []byte, path ...string) []byte {
hmacf := hmac.New(sha256.New, []byte(KDFSaltConstVMessAEADKDF))
for _, v := range path {
hmacf = hmac.New(func() hash.Hash {
return hmacf
}, []byte(v))
}
hmacf.Write(key)
return hmacf.Sum(nil)
}
func KDF16(key []byte, path ...string) []byte {
r := KDF(key, path...)
return r[:16]
}
v2ray-core-4.34.0/proxy/vmess/encoding/ 0000775 0000000 0000000 00000000000 13774574720 0017717 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/vmess/encoding/auth.go 0000664 0000000 0000000 00000005242 13774574720 0021212 0 ustar 00root root 0000000 0000000 package encoding
import (
"crypto/md5"
"encoding/binary"
"hash/fnv"
"v2ray.com/core/common"
"golang.org/x/crypto/sha3"
)
// Authenticate authenticates a byte array using Fnv hash.
func Authenticate(b []byte) uint32 {
fnv1hash := fnv.New32a()
common.Must2(fnv1hash.Write(b))
return fnv1hash.Sum32()
}
type NoOpAuthenticator struct{}
func (NoOpAuthenticator) NonceSize() int {
return 0
}
func (NoOpAuthenticator) Overhead() int {
return 0
}
// Seal implements AEAD.Seal().
func (NoOpAuthenticator) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
return append(dst[:0], plaintext...)
}
// Open implements AEAD.Open().
func (NoOpAuthenticator) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
return append(dst[:0], ciphertext...), nil
}
// FnvAuthenticator is an AEAD based on Fnv hash.
type FnvAuthenticator struct {
}
// NonceSize implements AEAD.NonceSize().
func (*FnvAuthenticator) NonceSize() int {
return 0
}
// Overhead impelements AEAD.Overhead().
func (*FnvAuthenticator) Overhead() int {
return 4
}
// Seal implements AEAD.Seal().
func (*FnvAuthenticator) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
dst = append(dst, 0, 0, 0, 0)
binary.BigEndian.PutUint32(dst, Authenticate(plaintext))
return append(dst, plaintext...)
}
// Open implements AEAD.Open().
func (*FnvAuthenticator) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
if binary.BigEndian.Uint32(ciphertext[:4]) != Authenticate(ciphertext[4:]) {
return dst, newError("invalid authentication")
}
return append(dst, ciphertext[4:]...), nil
}
// GenerateChacha20Poly1305Key generates a 32-byte key from a given 16-byte array.
func GenerateChacha20Poly1305Key(b []byte) []byte {
key := make([]byte, 32)
t := md5.Sum(b)
copy(key, t[:])
t = md5.Sum(key[:16])
copy(key[16:], t[:])
return key
}
type ShakeSizeParser struct {
shake sha3.ShakeHash
buffer [2]byte
}
func NewShakeSizeParser(nonce []byte) *ShakeSizeParser {
shake := sha3.NewShake128()
common.Must2(shake.Write(nonce))
return &ShakeSizeParser{
shake: shake,
}
}
func (*ShakeSizeParser) SizeBytes() int32 {
return 2
}
func (s *ShakeSizeParser) next() uint16 {
common.Must2(s.shake.Read(s.buffer[:]))
return binary.BigEndian.Uint16(s.buffer[:])
}
func (s *ShakeSizeParser) Decode(b []byte) (uint16, error) {
mask := s.next()
size := binary.BigEndian.Uint16(b)
return mask ^ size, nil
}
func (s *ShakeSizeParser) Encode(size uint16, b []byte) []byte {
mask := s.next()
binary.BigEndian.PutUint16(b, mask^size)
return b[:2]
}
func (s *ShakeSizeParser) NextPaddingLen() uint16 {
return s.next() % 64
}
func (s *ShakeSizeParser) MaxPaddingLen() uint16 {
return 64
}
v2ray-core-4.34.0/proxy/vmess/encoding/auth_test.go 0000664 0000000 0000000 00000001024 13774574720 0022243 0 ustar 00root root 0000000 0000000 package encoding_test
import (
"crypto/rand"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
. "v2ray.com/core/proxy/vmess/encoding"
)
func TestFnvAuth(t *testing.T) {
fnvAuth := new(FnvAuthenticator)
expectedText := make([]byte, 256)
_, err := rand.Read(expectedText)
common.Must(err)
buffer := make([]byte, 512)
b := fnvAuth.Seal(buffer[:0], nil, expectedText, nil)
b, err = fnvAuth.Open(buffer[:0], nil, b, nil)
common.Must(err)
if r := cmp.Diff(b, expectedText); r != "" {
t.Error(r)
}
}
v2ray-core-4.34.0/proxy/vmess/encoding/client.go 0000664 0000000 0000000 00000031106 13774574720 0021525 0 ustar 00root root 0000000 0000000 package encoding
import (
"bytes"
"context"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"crypto/rand"
"crypto/sha256"
"encoding/binary"
"hash"
"hash/fnv"
"io"
"golang.org/x/crypto/chacha20poly1305"
"v2ray.com/core/common"
"v2ray.com/core/common/bitmask"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/crypto"
"v2ray.com/core/common/dice"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/vmess"
vmessaead "v2ray.com/core/proxy/vmess/aead"
)
func hashTimestamp(h hash.Hash, t protocol.Timestamp) []byte {
common.Must2(serial.WriteUint64(h, uint64(t)))
common.Must2(serial.WriteUint64(h, uint64(t)))
common.Must2(serial.WriteUint64(h, uint64(t)))
common.Must2(serial.WriteUint64(h, uint64(t)))
return h.Sum(nil)
}
// ClientSession stores connection session info for VMess client.
type ClientSession struct {
isAEAD bool
idHash protocol.IDHash
requestBodyKey [16]byte
requestBodyIV [16]byte
responseBodyKey [16]byte
responseBodyIV [16]byte
responseReader io.Reader
responseHeader byte
}
// NewClientSession creates a new ClientSession.
func NewClientSession(ctx context.Context, isAEAD bool, idHash protocol.IDHash) *ClientSession {
session := &ClientSession{
isAEAD: isAEAD,
idHash: idHash,
}
randomBytes := make([]byte, 33) // 16 + 16 + 1
common.Must2(rand.Read(randomBytes))
copy(session.requestBodyKey[:], randomBytes[:16])
copy(session.requestBodyIV[:], randomBytes[16:32])
session.responseHeader = randomBytes[32]
if !session.isAEAD {
session.responseBodyKey = md5.Sum(session.requestBodyKey[:])
session.responseBodyIV = md5.Sum(session.requestBodyIV[:])
} else {
BodyKey := sha256.Sum256(session.requestBodyKey[:])
copy(session.responseBodyKey[:], BodyKey[:16])
BodyIV := sha256.Sum256(session.requestBodyIV[:])
copy(session.responseBodyIV[:], BodyIV[:16])
}
return session
}
func (c *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writer io.Writer) error {
timestamp := protocol.NewTimestampGenerator(protocol.NowTime(), 30)()
account := header.User.Account.(*vmess.MemoryAccount)
if !c.isAEAD {
idHash := c.idHash(account.AnyValidID().Bytes())
common.Must2(serial.WriteUint64(idHash, uint64(timestamp)))
common.Must2(writer.Write(idHash.Sum(nil)))
}
buffer := buf.New()
defer buffer.Release()
common.Must(buffer.WriteByte(Version))
common.Must2(buffer.Write(c.requestBodyIV[:]))
common.Must2(buffer.Write(c.requestBodyKey[:]))
common.Must(buffer.WriteByte(c.responseHeader))
common.Must(buffer.WriteByte(byte(header.Option)))
paddingLen := dice.Roll(16)
security := byte(paddingLen<<4) | byte(header.Security)
common.Must2(buffer.Write([]byte{security, byte(0), byte(header.Command)}))
if header.Command != protocol.RequestCommandMux {
if err := addrParser.WriteAddressPort(buffer, header.Address, header.Port); err != nil {
return newError("failed to writer address and port").Base(err)
}
}
if paddingLen > 0 {
common.Must2(buffer.ReadFullFrom(rand.Reader, int32(paddingLen)))
}
{
fnv1a := fnv.New32a()
common.Must2(fnv1a.Write(buffer.Bytes()))
hashBytes := buffer.Extend(int32(fnv1a.Size()))
fnv1a.Sum(hashBytes[:0])
}
if !c.isAEAD {
iv := hashTimestamp(md5.New(), timestamp)
aesStream := crypto.NewAesEncryptionStream(account.ID.CmdKey(), iv)
aesStream.XORKeyStream(buffer.Bytes(), buffer.Bytes())
common.Must2(writer.Write(buffer.Bytes()))
} else {
var fixedLengthCmdKey [16]byte
copy(fixedLengthCmdKey[:], account.ID.CmdKey())
vmessout := vmessaead.SealVMessAEADHeader(fixedLengthCmdKey, buffer.Bytes())
common.Must2(io.Copy(writer, bytes.NewReader(vmessout)))
}
return nil
}
func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, writer io.Writer) buf.Writer {
var sizeParser crypto.ChunkSizeEncoder = crypto.PlainChunkSizeParser{}
if request.Option.Has(protocol.RequestOptionChunkMasking) {
sizeParser = NewShakeSizeParser(c.requestBodyIV[:])
}
var padding crypto.PaddingLengthGenerator
if request.Option.Has(protocol.RequestOptionGlobalPadding) {
padding = sizeParser.(crypto.PaddingLengthGenerator)
}
switch request.Security {
case protocol.SecurityType_NONE:
if request.Option.Has(protocol.RequestOptionChunkStream) {
if request.Command.TransferType() == protocol.TransferTypeStream {
return crypto.NewChunkStreamWriter(sizeParser, writer)
}
auth := &crypto.AEADAuthenticator{
AEAD: new(NoOpAuthenticator),
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, protocol.TransferTypePacket, padding)
}
return buf.NewWriter(writer)
case protocol.SecurityType_LEGACY:
aesStream := crypto.NewAesEncryptionStream(c.requestBodyKey[:], c.requestBodyIV[:])
cryptionWriter := crypto.NewCryptionWriter(aesStream, writer)
if request.Option.Has(protocol.RequestOptionChunkStream) {
auth := &crypto.AEADAuthenticator{
AEAD: new(FnvAuthenticator),
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, cryptionWriter, request.Command.TransferType(), padding)
}
return &buf.SequentialWriter{Writer: cryptionWriter}
case protocol.SecurityType_AES128_GCM:
aead := crypto.NewAesGcm(c.requestBodyKey[:])
auth := &crypto.AEADAuthenticator{
AEAD: aead,
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
case protocol.SecurityType_CHACHA20_POLY1305:
aead, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.requestBodyKey[:]))
common.Must(err)
auth := &crypto.AEADAuthenticator{
AEAD: aead,
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
default:
panic("Unknown security type.")
}
}
func (c *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.ResponseHeader, error) {
if !c.isAEAD {
aesStream := crypto.NewAesDecryptionStream(c.responseBodyKey[:], c.responseBodyIV[:])
c.responseReader = crypto.NewCryptionReader(aesStream, reader)
} else {
aeadResponseHeaderLengthEncryptionKey := vmessaead.KDF16(c.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderLenKey)
aeadResponseHeaderLengthEncryptionIV := vmessaead.KDF(c.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderLenIV)[:12]
aeadResponseHeaderLengthEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)).(cipher.Block)
aeadResponseHeaderLengthEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)).(cipher.AEAD)
var aeadEncryptedResponseHeaderLength [18]byte
var decryptedResponseHeaderLength int
var decryptedResponseHeaderLengthBinaryDeserializeBuffer uint16
if _, err := io.ReadFull(reader, aeadEncryptedResponseHeaderLength[:]); err != nil {
return nil, newError("Unable to Read Header Len").Base(err)
}
if decryptedResponseHeaderLengthBinaryBuffer, err := aeadResponseHeaderLengthEncryptionAEAD.Open(nil, aeadResponseHeaderLengthEncryptionIV, aeadEncryptedResponseHeaderLength[:], nil); err != nil {
return nil, newError("Failed To Decrypt Length").Base(err)
} else { // nolint: golint
common.Must(binary.Read(bytes.NewReader(decryptedResponseHeaderLengthBinaryBuffer), binary.BigEndian, &decryptedResponseHeaderLengthBinaryDeserializeBuffer))
decryptedResponseHeaderLength = int(decryptedResponseHeaderLengthBinaryDeserializeBuffer)
}
aeadResponseHeaderPayloadEncryptionKey := vmessaead.KDF16(c.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadKey)
aeadResponseHeaderPayloadEncryptionIV := vmessaead.KDF(c.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadIV)[:12]
aeadResponseHeaderPayloadEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)).(cipher.Block)
aeadResponseHeaderPayloadEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)).(cipher.AEAD)
encryptedResponseHeaderBuffer := make([]byte, decryptedResponseHeaderLength+16)
if _, err := io.ReadFull(reader, encryptedResponseHeaderBuffer); err != nil {
return nil, newError("Unable to Read Header Data").Base(err)
}
if decryptedResponseHeaderBuffer, err := aeadResponseHeaderPayloadEncryptionAEAD.Open(nil, aeadResponseHeaderPayloadEncryptionIV, encryptedResponseHeaderBuffer, nil); err != nil {
return nil, newError("Failed To Decrypt Payload").Base(err)
} else { // nolint: golint
c.responseReader = bytes.NewReader(decryptedResponseHeaderBuffer)
}
}
buffer := buf.StackNew()
defer buffer.Release()
if _, err := buffer.ReadFullFrom(c.responseReader, 4); err != nil {
return nil, newError("failed to read response header").Base(err).AtWarning()
}
if buffer.Byte(0) != c.responseHeader {
return nil, newError("unexpected response header. Expecting ", int(c.responseHeader), " but actually ", int(buffer.Byte(0)))
}
header := &protocol.ResponseHeader{
Option: bitmask.Byte(buffer.Byte(1)),
}
if buffer.Byte(2) != 0 {
cmdID := buffer.Byte(2)
dataLen := int32(buffer.Byte(3))
buffer.Clear()
if _, err := buffer.ReadFullFrom(c.responseReader, dataLen); err != nil {
return nil, newError("failed to read response command").Base(err)
}
command, err := UnmarshalCommand(cmdID, buffer.Bytes())
if err == nil {
header.Command = command
}
}
if c.isAEAD {
aesStream := crypto.NewAesDecryptionStream(c.responseBodyKey[:], c.responseBodyIV[:])
c.responseReader = crypto.NewCryptionReader(aesStream, reader)
}
return header, nil
}
func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, reader io.Reader) buf.Reader {
var sizeParser crypto.ChunkSizeDecoder = crypto.PlainChunkSizeParser{}
if request.Option.Has(protocol.RequestOptionChunkMasking) {
sizeParser = NewShakeSizeParser(c.responseBodyIV[:])
}
var padding crypto.PaddingLengthGenerator
if request.Option.Has(protocol.RequestOptionGlobalPadding) {
padding = sizeParser.(crypto.PaddingLengthGenerator)
}
switch request.Security {
case protocol.SecurityType_NONE:
if request.Option.Has(protocol.RequestOptionChunkStream) {
if request.Command.TransferType() == protocol.TransferTypeStream {
return crypto.NewChunkStreamReader(sizeParser, reader)
}
auth := &crypto.AEADAuthenticator{
AEAD: new(NoOpAuthenticator),
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, protocol.TransferTypePacket, padding)
}
return buf.NewReader(reader)
case protocol.SecurityType_LEGACY:
if request.Option.Has(protocol.RequestOptionChunkStream) {
auth := &crypto.AEADAuthenticator{
AEAD: new(FnvAuthenticator),
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, c.responseReader, request.Command.TransferType(), padding)
}
return buf.NewReader(c.responseReader)
case protocol.SecurityType_AES128_GCM:
aead := crypto.NewAesGcm(c.responseBodyKey[:])
auth := &crypto.AEADAuthenticator{
AEAD: aead,
NonceGenerator: GenerateChunkNonce(c.responseBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
case protocol.SecurityType_CHACHA20_POLY1305:
aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.responseBodyKey[:]))
auth := &crypto.AEADAuthenticator{
AEAD: aead,
NonceGenerator: GenerateChunkNonce(c.responseBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
default:
panic("Unknown security type.")
}
}
func GenerateChunkNonce(nonce []byte, size uint32) crypto.BytesGenerator {
c := append([]byte(nil), nonce...)
count := uint16(0)
return func() []byte {
binary.BigEndian.PutUint16(c, count)
count++
return c[:size]
}
}
v2ray-core-4.34.0/proxy/vmess/encoding/commands.go 0000664 0000000 0000000 00000007234 13774574720 0022055 0 ustar 00root root 0000000 0000000 package encoding
import (
"encoding/binary"
"io"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/common/uuid"
)
var (
ErrCommandTypeMismatch = newError("Command type mismatch.")
ErrUnknownCommand = newError("Unknown command.")
ErrCommandTooLarge = newError("Command too large.")
)
func MarshalCommand(command interface{}, writer io.Writer) error {
if command == nil {
return ErrUnknownCommand
}
var cmdID byte
var factory CommandFactory
switch command.(type) {
case *protocol.CommandSwitchAccount:
factory = new(CommandSwitchAccountFactory)
cmdID = 1
default:
return ErrUnknownCommand
}
buffer := buf.New()
defer buffer.Release()
err := factory.Marshal(command, buffer)
if err != nil {
return err
}
auth := Authenticate(buffer.Bytes())
length := buffer.Len() + 4
if length > 255 {
return ErrCommandTooLarge
}
common.Must2(writer.Write([]byte{cmdID, byte(length), byte(auth >> 24), byte(auth >> 16), byte(auth >> 8), byte(auth)}))
common.Must2(writer.Write(buffer.Bytes()))
return nil
}
func UnmarshalCommand(cmdID byte, data []byte) (protocol.ResponseCommand, error) {
if len(data) <= 4 {
return nil, newError("insufficient length")
}
expectedAuth := Authenticate(data[4:])
actualAuth := binary.BigEndian.Uint32(data[:4])
if expectedAuth != actualAuth {
return nil, newError("invalid auth")
}
var factory CommandFactory
switch cmdID {
case 1:
factory = new(CommandSwitchAccountFactory)
default:
return nil, ErrUnknownCommand
}
return factory.Unmarshal(data[4:])
}
type CommandFactory interface {
Marshal(command interface{}, writer io.Writer) error
Unmarshal(data []byte) (interface{}, error)
}
type CommandSwitchAccountFactory struct {
}
func (f *CommandSwitchAccountFactory) Marshal(command interface{}, writer io.Writer) error {
cmd, ok := command.(*protocol.CommandSwitchAccount)
if !ok {
return ErrCommandTypeMismatch
}
hostStr := ""
if cmd.Host != nil {
hostStr = cmd.Host.String()
}
common.Must2(writer.Write([]byte{byte(len(hostStr))}))
if len(hostStr) > 0 {
common.Must2(writer.Write([]byte(hostStr)))
}
common.Must2(serial.WriteUint16(writer, cmd.Port.Value()))
idBytes := cmd.ID.Bytes()
common.Must2(writer.Write(idBytes))
common.Must2(serial.WriteUint16(writer, cmd.AlterIds))
common.Must2(writer.Write([]byte{byte(cmd.Level)}))
common.Must2(writer.Write([]byte{cmd.ValidMin}))
return nil
}
func (f *CommandSwitchAccountFactory) Unmarshal(data []byte) (interface{}, error) {
cmd := new(protocol.CommandSwitchAccount)
if len(data) == 0 {
return nil, newError("insufficient length.")
}
lenHost := int(data[0])
if len(data) < lenHost+1 {
return nil, newError("insufficient length.")
}
if lenHost > 0 {
cmd.Host = net.ParseAddress(string(data[1 : 1+lenHost]))
}
portStart := 1 + lenHost
if len(data) < portStart+2 {
return nil, newError("insufficient length.")
}
cmd.Port = net.PortFromBytes(data[portStart : portStart+2])
idStart := portStart + 2
if len(data) < idStart+16 {
return nil, newError("insufficient length.")
}
cmd.ID, _ = uuid.ParseBytes(data[idStart : idStart+16])
alterIDStart := idStart + 16
if len(data) < alterIDStart+2 {
return nil, newError("insufficient length.")
}
cmd.AlterIds = binary.BigEndian.Uint16(data[alterIDStart : alterIDStart+2])
levelStart := alterIDStart + 2
if len(data) < levelStart+1 {
return nil, newError("insufficient length.")
}
cmd.Level = uint32(data[levelStart])
timeStart := levelStart + 1
if len(data) < timeStart {
return nil, newError("insufficient length.")
}
cmd.ValidMin = data[timeStart]
return cmd, nil
}
v2ray-core-4.34.0/proxy/vmess/encoding/commands_test.go 0000664 0000000 0000000 00000001333 13774574720 0023106 0 ustar 00root root 0000000 0000000 package encoding_test
import (
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/uuid"
. "v2ray.com/core/proxy/vmess/encoding"
)
func TestSwitchAccount(t *testing.T) {
sa := &protocol.CommandSwitchAccount{
Port: 1234,
ID: uuid.New(),
AlterIds: 1024,
Level: 128,
ValidMin: 16,
}
buffer := buf.New()
common.Must(MarshalCommand(sa, buffer))
cmd, err := UnmarshalCommand(1, buffer.BytesFrom(2))
common.Must(err)
sa2, ok := cmd.(*protocol.CommandSwitchAccount)
if !ok {
t.Fatal("failed to convert command to CommandSwitchAccount")
}
if r := cmp.Diff(sa2, sa); r != "" {
t.Error(r)
}
}
v2ray-core-4.34.0/proxy/vmess/encoding/encoding.go 0000664 0000000 0000000 00000001002 13774574720 0022025 0 ustar 00root root 0000000 0000000 package encoding
import (
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
)
//go:generate go run v2ray.com/core/common/errors/errorgen
const (
Version = byte(1)
)
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(),
)
v2ray-core-4.34.0/proxy/vmess/encoding/encoding_test.go 0000664 0000000 0000000 00000007445 13774574720 0023105 0 ustar 00root root 0000000 0000000 package encoding_test
import (
"context"
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/uuid"
"v2ray.com/core/proxy/vmess"
. "v2ray.com/core/proxy/vmess/encoding"
)
func toAccount(a *vmess.Account) protocol.Account {
account, err := a.AsAccount()
common.Must(err)
return account
}
func TestRequestSerialization(t *testing.T) {
user := &protocol.MemoryUser{
Level: 0,
Email: "test@v2ray.com",
}
id := uuid.New()
account := &vmess.Account{
Id: id.String(),
AlterId: 0,
}
user.Account = toAccount(account)
expectedRequest := &protocol.RequestHeader{
Version: 1,
User: user,
Command: protocol.RequestCommandTCP,
Address: net.DomainAddress("www.v2ray.com"),
Port: net.Port(443),
Security: protocol.SecurityType_AES128_GCM,
}
buffer := buf.New()
client := NewClientSession(context.TODO(), true, protocol.DefaultIDHash)
common.Must(client.EncodeRequestHeader(expectedRequest, buffer))
buffer2 := buf.New()
buffer2.Write(buffer.Bytes())
sessionHistory := NewSessionHistory()
defer common.Close(sessionHistory)
userValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash)
userValidator.Add(user)
defer common.Close(userValidator)
server := NewServerSession(userValidator, sessionHistory)
actualRequest, err := server.DecodeRequestHeader(buffer)
common.Must(err)
if r := cmp.Diff(actualRequest, expectedRequest, cmp.AllowUnexported(protocol.ID{})); r != "" {
t.Error(r)
}
_, err = server.DecodeRequestHeader(buffer2)
// anti replay attack
if err == nil {
t.Error("nil error")
}
}
func TestInvalidRequest(t *testing.T) {
user := &protocol.MemoryUser{
Level: 0,
Email: "test@v2ray.com",
}
id := uuid.New()
account := &vmess.Account{
Id: id.String(),
AlterId: 0,
}
user.Account = toAccount(account)
expectedRequest := &protocol.RequestHeader{
Version: 1,
User: user,
Command: protocol.RequestCommand(100),
Address: net.DomainAddress("www.v2ray.com"),
Port: net.Port(443),
Security: protocol.SecurityType_AES128_GCM,
}
buffer := buf.New()
client := NewClientSession(context.TODO(), true, protocol.DefaultIDHash)
common.Must(client.EncodeRequestHeader(expectedRequest, buffer))
buffer2 := buf.New()
buffer2.Write(buffer.Bytes())
sessionHistory := NewSessionHistory()
defer common.Close(sessionHistory)
userValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash)
userValidator.Add(user)
defer common.Close(userValidator)
server := NewServerSession(userValidator, sessionHistory)
_, err := server.DecodeRequestHeader(buffer)
if err == nil {
t.Error("nil error")
}
}
func TestMuxRequest(t *testing.T) {
user := &protocol.MemoryUser{
Level: 0,
Email: "test@v2ray.com",
}
id := uuid.New()
account := &vmess.Account{
Id: id.String(),
AlterId: 0,
}
user.Account = toAccount(account)
expectedRequest := &protocol.RequestHeader{
Version: 1,
User: user,
Command: protocol.RequestCommandMux,
Security: protocol.SecurityType_AES128_GCM,
Address: net.DomainAddress("v1.mux.cool"),
}
buffer := buf.New()
client := NewClientSession(context.TODO(), true, protocol.DefaultIDHash)
common.Must(client.EncodeRequestHeader(expectedRequest, buffer))
buffer2 := buf.New()
buffer2.Write(buffer.Bytes())
sessionHistory := NewSessionHistory()
defer common.Close(sessionHistory)
userValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash)
userValidator.Add(user)
defer common.Close(userValidator)
server := NewServerSession(userValidator, sessionHistory)
actualRequest, err := server.DecodeRequestHeader(buffer)
common.Must(err)
if r := cmp.Diff(actualRequest, expectedRequest, cmp.AllowUnexported(protocol.ID{})); r != "" {
t.Error(r)
}
}
v2ray-core-4.34.0/proxy/vmess/encoding/errors.generated.go 0000664 0000000 0000000 00000000316 13774574720 0023517 0 ustar 00root root 0000000 0000000 package encoding
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/vmess/encoding/server.go 0000664 0000000 0000000 00000042110 13774574720 0021552 0 ustar 00root root 0000000 0000000 package encoding
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"crypto/sha256"
"encoding/binary"
"hash/fnv"
"io"
"io/ioutil"
"sync"
"time"
"golang.org/x/crypto/chacha20poly1305"
"v2ray.com/core/common"
"v2ray.com/core/common/bitmask"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/crypto"
"v2ray.com/core/common/dice"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/task"
"v2ray.com/core/proxy/vmess"
vmessaead "v2ray.com/core/proxy/vmess/aead"
)
type sessionID struct {
user [16]byte
key [16]byte
nonce [16]byte
}
// SessionHistory keeps track of historical session ids, to prevent replay attacks.
type SessionHistory struct {
sync.RWMutex
cache map[sessionID]time.Time
task *task.Periodic
}
// NewSessionHistory creates a new SessionHistory object.
func NewSessionHistory() *SessionHistory {
h := &SessionHistory{
cache: make(map[sessionID]time.Time, 128),
}
h.task = &task.Periodic{
Interval: time.Second * 30,
Execute: h.removeExpiredEntries,
}
return h
}
// Close implements common.Closable.
func (h *SessionHistory) Close() error {
return h.task.Close()
}
func (h *SessionHistory) addIfNotExits(session sessionID) bool {
h.Lock()
if expire, found := h.cache[session]; found && expire.After(time.Now()) {
h.Unlock()
return false
}
h.cache[session] = time.Now().Add(time.Minute * 3)
h.Unlock()
common.Must(h.task.Start())
return true
}
func (h *SessionHistory) removeExpiredEntries() error {
now := time.Now()
h.Lock()
defer h.Unlock()
if len(h.cache) == 0 {
return newError("nothing to do")
}
for session, expire := range h.cache {
if expire.Before(now) {
delete(h.cache, session)
}
}
if len(h.cache) == 0 {
h.cache = make(map[sessionID]time.Time, 128)
}
return nil
}
// ServerSession keeps information for a session in VMess server.
type ServerSession struct {
userValidator *vmess.TimedUserValidator
sessionHistory *SessionHistory
requestBodyKey [16]byte
requestBodyIV [16]byte
responseBodyKey [16]byte
responseBodyIV [16]byte
responseWriter io.Writer
responseHeader byte
isAEADRequest bool
isAEADForced bool
}
// NewServerSession creates a new ServerSession, using the given UserValidator.
// The ServerSession instance doesn't take ownership of the validator.
func NewServerSession(validator *vmess.TimedUserValidator, sessionHistory *SessionHistory) *ServerSession {
return &ServerSession{
userValidator: validator,
sessionHistory: sessionHistory,
}
}
func parseSecurityType(b byte) protocol.SecurityType {
if _, f := protocol.SecurityType_name[int32(b)]; f {
st := protocol.SecurityType(b)
// For backward compatibility.
if st == protocol.SecurityType_UNKNOWN {
st = protocol.SecurityType_LEGACY
}
return st
}
return protocol.SecurityType_UNKNOWN
}
// DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream.
func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.RequestHeader, error) {
buffer := buf.New()
behaviorRand := dice.NewDeterministicDice(int64(s.userValidator.GetBehaviorSeed()))
BaseDrainSize := behaviorRand.Roll(3266)
RandDrainMax := behaviorRand.Roll(64) + 1
RandDrainRolled := dice.Roll(RandDrainMax)
DrainSize := BaseDrainSize + 16 + 38 + RandDrainRolled
readSizeRemain := DrainSize
drainConnection := func(e error) error {
// We read a deterministic generated length of data before closing the connection to offset padding read pattern
readSizeRemain -= int(buffer.Len())
if readSizeRemain > 0 {
err := s.DrainConnN(reader, readSizeRemain)
if err != nil {
return newError("failed to drain connection DrainSize = ", BaseDrainSize, " ", RandDrainMax, " ", RandDrainRolled).Base(err).Base(e)
}
return newError("connection drained DrainSize = ", BaseDrainSize, " ", RandDrainMax, " ", RandDrainRolled).Base(e)
}
return e
}
defer func() {
buffer.Release()
}()
if _, err := buffer.ReadFullFrom(reader, protocol.IDBytesLen); err != nil {
return nil, newError("failed to read request header").Base(err)
}
var decryptor io.Reader
var vmessAccount *vmess.MemoryAccount
user, foundAEAD, errorAEAD := s.userValidator.GetAEAD(buffer.Bytes())
var fixedSizeAuthID [16]byte
copy(fixedSizeAuthID[:], buffer.Bytes())
switch {
case foundAEAD:
vmessAccount = user.Account.(*vmess.MemoryAccount)
var fixedSizeCmdKey [16]byte
copy(fixedSizeCmdKey[:], vmessAccount.ID.CmdKey())
aeadData, shouldDrain, bytesRead, errorReason := vmessaead.OpenVMessAEADHeader(fixedSizeCmdKey, fixedSizeAuthID, reader)
if errorReason != nil {
if shouldDrain {
readSizeRemain -= bytesRead
return nil, drainConnection(newError("AEAD read failed").Base(errorReason))
}
return nil, drainConnection(newError("AEAD read failed, drain skipped").Base(errorReason))
}
decryptor = bytes.NewReader(aeadData)
s.isAEADRequest = true
case !s.isAEADForced && errorAEAD == vmessaead.ErrNotFound:
userLegacy, timestamp, valid, userValidationError := s.userValidator.Get(buffer.Bytes())
if !valid || userValidationError != nil {
return nil, drainConnection(newError("invalid user").Base(userValidationError))
}
user = userLegacy
iv := hashTimestamp(md5.New(), timestamp)
vmessAccount = userLegacy.Account.(*vmess.MemoryAccount)
aesStream := crypto.NewAesDecryptionStream(vmessAccount.ID.CmdKey(), iv)
decryptor = crypto.NewCryptionReader(aesStream, reader)
default:
return nil, drainConnection(newError("invalid user").Base(errorAEAD))
}
readSizeRemain -= int(buffer.Len())
buffer.Clear()
if _, err := buffer.ReadFullFrom(decryptor, 38); err != nil {
return nil, newError("failed to read request header").Base(err)
}
request := &protocol.RequestHeader{
User: user,
Version: buffer.Byte(0),
}
copy(s.requestBodyIV[:], buffer.BytesRange(1, 17)) // 16 bytes
copy(s.requestBodyKey[:], buffer.BytesRange(17, 33)) // 16 bytes
var sid sessionID
copy(sid.user[:], vmessAccount.ID.Bytes())
sid.key = s.requestBodyKey
sid.nonce = s.requestBodyIV
if !s.sessionHistory.addIfNotExits(sid) {
if !s.isAEADRequest {
drainErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:])
if drainErr != nil {
return nil, drainConnection(newError("duplicated session id, possibly under replay attack, and failed to taint userHash").Base(drainErr))
}
return nil, drainConnection(newError("duplicated session id, possibly under replay attack, userHash tainted"))
}
return nil, newError("duplicated session id, possibly under replay attack, but this is a AEAD request")
}
s.responseHeader = buffer.Byte(33) // 1 byte
request.Option = bitmask.Byte(buffer.Byte(34)) // 1 byte
paddingLen := int(buffer.Byte(35) >> 4)
request.Security = parseSecurityType(buffer.Byte(35) & 0x0F)
// 1 bytes reserved
request.Command = protocol.RequestCommand(buffer.Byte(37))
switch request.Command {
case protocol.RequestCommandMux:
request.Address = net.DomainAddress("v1.mux.cool")
request.Port = 0
case protocol.RequestCommandTCP, protocol.RequestCommandUDP:
if addr, port, err := addrParser.ReadAddressPort(buffer, decryptor); err == nil {
request.Address = addr
request.Port = port
}
}
if paddingLen > 0 {
if _, err := buffer.ReadFullFrom(decryptor, int32(paddingLen)); err != nil {
if !s.isAEADRequest {
burnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:])
if burnErr != nil {
return nil, newError("failed to read padding, failed to taint userHash").Base(burnErr).Base(err)
}
return nil, newError("failed to read padding, userHash tainted").Base(err)
}
return nil, newError("failed to read padding").Base(err)
}
}
if _, err := buffer.ReadFullFrom(decryptor, 4); err != nil {
if !s.isAEADRequest {
burnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:])
if burnErr != nil {
return nil, newError("failed to read checksum, failed to taint userHash").Base(burnErr).Base(err)
}
return nil, newError("failed to read checksum, userHash tainted").Base(err)
}
return nil, newError("failed to read checksum").Base(err)
}
fnv1a := fnv.New32a()
common.Must2(fnv1a.Write(buffer.BytesTo(-4)))
actualHash := fnv1a.Sum32()
expectedHash := binary.BigEndian.Uint32(buffer.BytesFrom(-4))
if actualHash != expectedHash {
if !s.isAEADRequest {
Autherr := newError("invalid auth, legacy userHash tainted")
burnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:])
if burnErr != nil {
Autherr = newError("invalid auth, can't taint legacy userHash").Base(burnErr)
}
// It is possible that we are under attack described in https://github.com/v2ray/v2ray-core/issues/2523
return nil, drainConnection(Autherr)
}
return nil, newError("invalid auth, but this is a AEAD request")
}
if request.Address == nil {
return nil, newError("invalid remote address")
}
if request.Security == protocol.SecurityType_UNKNOWN || request.Security == protocol.SecurityType_AUTO {
return nil, newError("unknown security type: ", request.Security)
}
return request, nil
}
// DecodeRequestBody returns Reader from which caller can fetch decrypted body.
func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reader io.Reader) buf.Reader {
var sizeParser crypto.ChunkSizeDecoder = crypto.PlainChunkSizeParser{}
if request.Option.Has(protocol.RequestOptionChunkMasking) {
sizeParser = NewShakeSizeParser(s.requestBodyIV[:])
}
var padding crypto.PaddingLengthGenerator
if request.Option.Has(protocol.RequestOptionGlobalPadding) {
padding = sizeParser.(crypto.PaddingLengthGenerator)
}
switch request.Security {
case protocol.SecurityType_NONE:
if request.Option.Has(protocol.RequestOptionChunkStream) {
if request.Command.TransferType() == protocol.TransferTypeStream {
return crypto.NewChunkStreamReader(sizeParser, reader)
}
auth := &crypto.AEADAuthenticator{
AEAD: new(NoOpAuthenticator),
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, protocol.TransferTypePacket, padding)
}
return buf.NewReader(reader)
case protocol.SecurityType_LEGACY:
aesStream := crypto.NewAesDecryptionStream(s.requestBodyKey[:], s.requestBodyIV[:])
cryptionReader := crypto.NewCryptionReader(aesStream, reader)
if request.Option.Has(protocol.RequestOptionChunkStream) {
auth := &crypto.AEADAuthenticator{
AEAD: new(FnvAuthenticator),
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, cryptionReader, request.Command.TransferType(), padding)
}
return buf.NewReader(cryptionReader)
case protocol.SecurityType_AES128_GCM:
aead := crypto.NewAesGcm(s.requestBodyKey[:])
auth := &crypto.AEADAuthenticator{
AEAD: aead,
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
case protocol.SecurityType_CHACHA20_POLY1305:
aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.requestBodyKey[:]))
auth := &crypto.AEADAuthenticator{
AEAD: aead,
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
default:
panic("Unknown security type.")
}
}
// EncodeResponseHeader writes encoded response header into the given writer.
func (s *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, writer io.Writer) {
var encryptionWriter io.Writer
if !s.isAEADRequest {
s.responseBodyKey = md5.Sum(s.requestBodyKey[:])
s.responseBodyIV = md5.Sum(s.requestBodyIV[:])
} else {
BodyKey := sha256.Sum256(s.requestBodyKey[:])
copy(s.responseBodyKey[:], BodyKey[:16])
BodyIV := sha256.Sum256(s.requestBodyIV[:])
copy(s.responseBodyIV[:], BodyIV[:16])
}
aesStream := crypto.NewAesEncryptionStream(s.responseBodyKey[:], s.responseBodyIV[:])
encryptionWriter = crypto.NewCryptionWriter(aesStream, writer)
s.responseWriter = encryptionWriter
aeadEncryptedHeaderBuffer := bytes.NewBuffer(nil)
if s.isAEADRequest {
encryptionWriter = aeadEncryptedHeaderBuffer
}
common.Must2(encryptionWriter.Write([]byte{s.responseHeader, byte(header.Option)}))
err := MarshalCommand(header.Command, encryptionWriter)
if err != nil {
common.Must2(encryptionWriter.Write([]byte{0x00, 0x00}))
}
if s.isAEADRequest {
aeadResponseHeaderLengthEncryptionKey := vmessaead.KDF16(s.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderLenKey)
aeadResponseHeaderLengthEncryptionIV := vmessaead.KDF(s.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderLenIV)[:12]
aeadResponseHeaderLengthEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)).(cipher.Block)
aeadResponseHeaderLengthEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)).(cipher.AEAD)
aeadResponseHeaderLengthEncryptionBuffer := bytes.NewBuffer(nil)
decryptedResponseHeaderLengthBinaryDeserializeBuffer := uint16(aeadEncryptedHeaderBuffer.Len())
common.Must(binary.Write(aeadResponseHeaderLengthEncryptionBuffer, binary.BigEndian, decryptedResponseHeaderLengthBinaryDeserializeBuffer))
AEADEncryptedLength := aeadResponseHeaderLengthEncryptionAEAD.Seal(nil, aeadResponseHeaderLengthEncryptionIV, aeadResponseHeaderLengthEncryptionBuffer.Bytes(), nil)
common.Must2(io.Copy(writer, bytes.NewReader(AEADEncryptedLength)))
aeadResponseHeaderPayloadEncryptionKey := vmessaead.KDF16(s.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadKey)
aeadResponseHeaderPayloadEncryptionIV := vmessaead.KDF(s.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadIV)[:12]
aeadResponseHeaderPayloadEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)).(cipher.Block)
aeadResponseHeaderPayloadEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)).(cipher.AEAD)
aeadEncryptedHeaderPayload := aeadResponseHeaderPayloadEncryptionAEAD.Seal(nil, aeadResponseHeaderPayloadEncryptionIV, aeadEncryptedHeaderBuffer.Bytes(), nil)
common.Must2(io.Copy(writer, bytes.NewReader(aeadEncryptedHeaderPayload)))
}
}
// EncodeResponseBody returns a Writer that auto-encrypt content written by caller.
func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writer io.Writer) buf.Writer {
var sizeParser crypto.ChunkSizeEncoder = crypto.PlainChunkSizeParser{}
if request.Option.Has(protocol.RequestOptionChunkMasking) {
sizeParser = NewShakeSizeParser(s.responseBodyIV[:])
}
var padding crypto.PaddingLengthGenerator
if request.Option.Has(protocol.RequestOptionGlobalPadding) {
padding = sizeParser.(crypto.PaddingLengthGenerator)
}
switch request.Security {
case protocol.SecurityType_NONE:
if request.Option.Has(protocol.RequestOptionChunkStream) {
if request.Command.TransferType() == protocol.TransferTypeStream {
return crypto.NewChunkStreamWriter(sizeParser, writer)
}
auth := &crypto.AEADAuthenticator{
AEAD: new(NoOpAuthenticator),
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, protocol.TransferTypePacket, padding)
}
return buf.NewWriter(writer)
case protocol.SecurityType_LEGACY:
if request.Option.Has(protocol.RequestOptionChunkStream) {
auth := &crypto.AEADAuthenticator{
AEAD: new(FnvAuthenticator),
NonceGenerator: crypto.GenerateEmptyBytes(),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, s.responseWriter, request.Command.TransferType(), padding)
}
return &buf.SequentialWriter{Writer: s.responseWriter}
case protocol.SecurityType_AES128_GCM:
aead := crypto.NewAesGcm(s.responseBodyKey[:])
auth := &crypto.AEADAuthenticator{
AEAD: aead,
NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
case protocol.SecurityType_CHACHA20_POLY1305:
aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.responseBodyKey[:]))
auth := &crypto.AEADAuthenticator{
AEAD: aead,
NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
default:
panic("Unknown security type.")
}
}
func (s *ServerSession) DrainConnN(reader io.Reader, n int) error {
_, err := io.CopyN(ioutil.Discard, reader, int64(n))
return err
}
v2ray-core-4.34.0/proxy/vmess/errors.generated.go 0000664 0000000 0000000 00000000313 13774574720 0021726 0 ustar 00root root 0000000 0000000 package vmess
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/vmess/inbound/ 0000775 0000000 0000000 00000000000 13774574720 0017567 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/vmess/inbound/config.go 0000664 0000000 0000000 00000000345 13774574720 0021365 0 ustar 00root root 0000000 0000000 // +build !confonly
package inbound
// GetDefaultValue returns default settings of DefaultConfig.
func (c *Config) GetDefaultValue() *DefaultConfig {
if c.GetDefault() == nil {
return &DefaultConfig{}
}
return c.Default
}
v2ray-core-4.34.0/proxy/vmess/inbound/config.pb.go 0000664 0000000 0000000 00000027642 13774574720 0021776 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/vmess/inbound/config.proto
package inbound
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
protocol "v2ray.com/core/common/protocol"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type DetourConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
To string `protobuf:"bytes,1,opt,name=to,proto3" json:"to,omitempty"`
}
func (x *DetourConfig) Reset() {
*x = DetourConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_vmess_inbound_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DetourConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DetourConfig) ProtoMessage() {}
func (x *DetourConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_vmess_inbound_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DetourConfig.ProtoReflect.Descriptor instead.
func (*DetourConfig) Descriptor() ([]byte, []int) {
return file_proxy_vmess_inbound_config_proto_rawDescGZIP(), []int{0}
}
func (x *DetourConfig) GetTo() string {
if x != nil {
return x.To
}
return ""
}
type DefaultConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
AlterId uint32 `protobuf:"varint,1,opt,name=alter_id,json=alterId,proto3" json:"alter_id,omitempty"`
Level uint32 `protobuf:"varint,2,opt,name=level,proto3" json:"level,omitempty"`
}
func (x *DefaultConfig) Reset() {
*x = DefaultConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_vmess_inbound_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DefaultConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DefaultConfig) ProtoMessage() {}
func (x *DefaultConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_vmess_inbound_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DefaultConfig.ProtoReflect.Descriptor instead.
func (*DefaultConfig) Descriptor() ([]byte, []int) {
return file_proxy_vmess_inbound_config_proto_rawDescGZIP(), []int{1}
}
func (x *DefaultConfig) GetAlterId() uint32 {
if x != nil {
return x.AlterId
}
return 0
}
func (x *DefaultConfig) GetLevel() uint32 {
if x != nil {
return x.Level
}
return 0
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
User []*protocol.User `protobuf:"bytes,1,rep,name=user,proto3" json:"user,omitempty"`
Default *DefaultConfig `protobuf:"bytes,2,opt,name=default,proto3" json:"default,omitempty"`
Detour *DetourConfig `protobuf:"bytes,3,opt,name=detour,proto3" json:"detour,omitempty"`
SecureEncryptionOnly bool `protobuf:"varint,4,opt,name=secure_encryption_only,json=secureEncryptionOnly,proto3" json:"secure_encryption_only,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_vmess_inbound_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_proxy_vmess_inbound_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_proxy_vmess_inbound_config_proto_rawDescGZIP(), []int{2}
}
func (x *Config) GetUser() []*protocol.User {
if x != nil {
return x.User
}
return nil
}
func (x *Config) GetDefault() *DefaultConfig {
if x != nil {
return x.Default
}
return nil
}
func (x *Config) GetDetour() *DetourConfig {
if x != nil {
return x.Detour
}
return nil
}
func (x *Config) GetSecureEncryptionOnly() bool {
if x != nil {
return x.SecureEncryptionOnly
}
return false
}
var File_proxy_vmess_inbound_config_proto protoreflect.FileDescriptor
var file_proxy_vmess_inbound_config_proto_rawDesc = []byte{
0x0a, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e,
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x12, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75,
0x6e, 0x64, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1e,
0x0a, 0x0c, 0x44, 0x65, 0x74, 0x6f, 0x75, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x0e,
0x0a, 0x02, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x22, 0x40,
0x0a, 0x0d, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x19, 0x0a, 0x08, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0d, 0x52, 0x07, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65,
0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c,
0x22, 0x83, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x75,
0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65,
0x72, 0x12, 0x47, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x44, 0x0a, 0x06, 0x64, 0x65,
0x74, 0x6f, 0x75, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d,
0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x74, 0x6f,
0x75, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x64, 0x65, 0x74, 0x6f, 0x75, 0x72,
0x12, 0x34, 0x0a, 0x16, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08,
0x52, 0x14, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x4f, 0x6e, 0x6c, 0x79, 0x42, 0x6b, 0x0a, 0x22, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76,
0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x22,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e, 0x62, 0x6f, 0x75,
0x6e, 0x64, 0xaa, 0x02, 0x1e, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e,
0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proxy_vmess_inbound_config_proto_rawDescOnce sync.Once
file_proxy_vmess_inbound_config_proto_rawDescData = file_proxy_vmess_inbound_config_proto_rawDesc
)
func file_proxy_vmess_inbound_config_proto_rawDescGZIP() []byte {
file_proxy_vmess_inbound_config_proto_rawDescOnce.Do(func() {
file_proxy_vmess_inbound_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_vmess_inbound_config_proto_rawDescData)
})
return file_proxy_vmess_inbound_config_proto_rawDescData
}
var file_proxy_vmess_inbound_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_proxy_vmess_inbound_config_proto_goTypes = []interface{}{
(*DetourConfig)(nil), // 0: v2ray.core.proxy.vmess.inbound.DetourConfig
(*DefaultConfig)(nil), // 1: v2ray.core.proxy.vmess.inbound.DefaultConfig
(*Config)(nil), // 2: v2ray.core.proxy.vmess.inbound.Config
(*protocol.User)(nil), // 3: v2ray.core.common.protocol.User
}
var file_proxy_vmess_inbound_config_proto_depIdxs = []int32{
3, // 0: v2ray.core.proxy.vmess.inbound.Config.user:type_name -> v2ray.core.common.protocol.User
1, // 1: v2ray.core.proxy.vmess.inbound.Config.default:type_name -> v2ray.core.proxy.vmess.inbound.DefaultConfig
0, // 2: v2ray.core.proxy.vmess.inbound.Config.detour:type_name -> v2ray.core.proxy.vmess.inbound.DetourConfig
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_proxy_vmess_inbound_config_proto_init() }
func file_proxy_vmess_inbound_config_proto_init() {
if File_proxy_vmess_inbound_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_vmess_inbound_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DetourConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_vmess_inbound_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DefaultConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_vmess_inbound_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_vmess_inbound_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_vmess_inbound_config_proto_goTypes,
DependencyIndexes: file_proxy_vmess_inbound_config_proto_depIdxs,
MessageInfos: file_proxy_vmess_inbound_config_proto_msgTypes,
}.Build()
File_proxy_vmess_inbound_config_proto = out.File
file_proxy_vmess_inbound_config_proto_rawDesc = nil
file_proxy_vmess_inbound_config_proto_goTypes = nil
file_proxy_vmess_inbound_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/vmess/inbound/config.proto 0000664 0000000 0000000 00000001114 13774574720 0022116 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.vmess.inbound;
option csharp_namespace = "V2Ray.Core.Proxy.Vmess.Inbound";
option go_package = "v2ray.com/core/proxy/vmess/inbound";
option java_package = "com.v2ray.core.proxy.vmess.inbound";
option java_multiple_files = true;
import "common/protocol/user.proto";
message DetourConfig {
string to = 1;
}
message DefaultConfig {
uint32 alter_id = 1;
uint32 level = 2;
}
message Config {
repeated v2ray.core.common.protocol.User user = 1;
DefaultConfig default = 2;
DetourConfig detour = 3;
bool secure_encryption_only = 4;
}
v2ray-core-4.34.0/proxy/vmess/inbound/errors.generated.go 0000664 0000000 0000000 00000000315 13774574720 0023366 0 ustar 00root root 0000000 0000000 package inbound
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/vmess/inbound/inbound.go 0000664 0000000 0000000 00000023476 13774574720 0021570 0 ustar 00root root 0000000 0000000 // +build !confonly
package inbound
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"io"
"strings"
"sync"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/common/uuid"
feature_inbound "v2ray.com/core/features/inbound"
"v2ray.com/core/features/policy"
"v2ray.com/core/features/routing"
"v2ray.com/core/proxy/vmess"
"v2ray.com/core/proxy/vmess/encoding"
"v2ray.com/core/transport/internet"
)
type userByEmail struct {
sync.Mutex
cache map[string]*protocol.MemoryUser
defaultLevel uint32
defaultAlterIDs uint16
}
func newUserByEmail(config *DefaultConfig) *userByEmail {
return &userByEmail{
cache: make(map[string]*protocol.MemoryUser),
defaultLevel: config.Level,
defaultAlterIDs: uint16(config.AlterId),
}
}
func (v *userByEmail) addNoLock(u *protocol.MemoryUser) bool {
email := strings.ToLower(u.Email)
_, found := v.cache[email]
if found {
return false
}
v.cache[email] = u
return true
}
func (v *userByEmail) Add(u *protocol.MemoryUser) bool {
v.Lock()
defer v.Unlock()
return v.addNoLock(u)
}
func (v *userByEmail) Get(email string) (*protocol.MemoryUser, bool) {
email = strings.ToLower(email)
v.Lock()
defer v.Unlock()
user, found := v.cache[email]
if !found {
id := uuid.New()
rawAccount := &vmess.Account{
Id: id.String(),
AlterId: uint32(v.defaultAlterIDs),
}
account, err := rawAccount.AsAccount()
common.Must(err)
user = &protocol.MemoryUser{
Level: v.defaultLevel,
Email: email,
Account: account,
}
v.cache[email] = user
}
return user, found
}
func (v *userByEmail) Remove(email string) bool {
email = strings.ToLower(email)
v.Lock()
defer v.Unlock()
if _, found := v.cache[email]; !found {
return false
}
delete(v.cache, email)
return true
}
// Handler is an inbound connection handler that handles messages in VMess protocol.
type Handler struct {
policyManager policy.Manager
inboundHandlerManager feature_inbound.Manager
clients *vmess.TimedUserValidator
usersByEmail *userByEmail
detours *DetourConfig
sessionHistory *encoding.SessionHistory
secure bool
}
// New creates a new VMess inbound handler.
func New(ctx context.Context, config *Config) (*Handler, error) {
v := core.MustFromContext(ctx)
handler := &Handler{
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
inboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager),
clients: vmess.NewTimedUserValidator(protocol.DefaultIDHash),
detours: config.Detour,
usersByEmail: newUserByEmail(config.GetDefaultValue()),
sessionHistory: encoding.NewSessionHistory(),
secure: config.SecureEncryptionOnly,
}
for _, user := range config.User {
mUser, err := user.ToMemoryUser()
if err != nil {
return nil, newError("failed to get VMess user").Base(err)
}
if err := handler.AddUser(ctx, mUser); err != nil {
return nil, newError("failed to initiate user").Base(err)
}
}
return handler, nil
}
// Close implements common.Closable.
func (h *Handler) Close() error {
return errors.Combine(
h.clients.Close(),
h.sessionHistory.Close(),
common.Close(h.usersByEmail))
}
// Network implements proxy.Inbound.Network().
func (*Handler) Network() []net.Network {
return []net.Network{net.Network_TCP, net.Network_UNIX}
}
func (h *Handler) GetUser(email string) *protocol.MemoryUser {
user, existing := h.usersByEmail.Get(email)
if !existing {
h.clients.Add(user)
}
return user
}
func (h *Handler) AddUser(ctx context.Context, user *protocol.MemoryUser) error {
if len(user.Email) > 0 && !h.usersByEmail.Add(user) {
return newError("User ", user.Email, " already exists.")
}
return h.clients.Add(user)
}
func (h *Handler) RemoveUser(ctx context.Context, email string) error {
if email == "" {
return newError("Email must not be empty.")
}
if !h.usersByEmail.Remove(email) {
return newError("User ", email, " not found.")
}
h.clients.Remove(email)
return nil
}
func transferResponse(timer signal.ActivityUpdater, session *encoding.ServerSession, request *protocol.RequestHeader, response *protocol.ResponseHeader, input buf.Reader, output *buf.BufferedWriter) error {
session.EncodeResponseHeader(response, output)
bodyWriter := session.EncodeResponseBody(request, output)
{
// Optimize for small response packet
data, err := input.ReadMultiBuffer()
if err != nil {
return err
}
if err := bodyWriter.WriteMultiBuffer(data); err != nil {
return err
}
}
if err := output.SetBuffered(false); err != nil {
return err
}
if err := buf.Copy(input, bodyWriter, buf.UpdateActivity(timer)); err != nil {
return err
}
if request.Option.Has(protocol.RequestOptionChunkStream) {
if err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {
return err
}
}
return nil
}
func isInsecureEncryption(s protocol.SecurityType) bool {
return s == protocol.SecurityType_NONE || s == protocol.SecurityType_LEGACY || s == protocol.SecurityType_UNKNOWN
}
// Process implements proxy.Inbound.Process().
func (h *Handler) Process(ctx context.Context, network net.Network, connection internet.Connection, dispatcher routing.Dispatcher) error {
sessionPolicy := h.policyManager.ForLevel(0)
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
return newError("unable to set read deadline").Base(err).AtWarning()
}
reader := &buf.BufferedReader{Reader: buf.NewReader(connection)}
svrSession := encoding.NewServerSession(h.clients, h.sessionHistory)
request, err := svrSession.DecodeRequestHeader(reader)
if err != nil {
if errors.Cause(err) != io.EOF {
log.Record(&log.AccessMessage{
From: connection.RemoteAddr(),
To: "",
Status: log.AccessRejected,
Reason: err,
})
err = newError("invalid request from ", connection.RemoteAddr()).Base(err).AtInfo()
}
return err
}
if h.secure && isInsecureEncryption(request.Security) {
log.Record(&log.AccessMessage{
From: connection.RemoteAddr(),
To: "",
Status: log.AccessRejected,
Reason: "Insecure encryption",
Email: request.User.Email,
})
return newError("client is using insecure encryption: ", request.Security)
}
if request.Command != protocol.RequestCommandMux {
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: connection.RemoteAddr(),
To: request.Destination(),
Status: log.AccessAccepted,
Reason: "",
Email: request.User.Email,
})
}
newError("received request for ", request.Destination()).WriteToLog(session.ExportIDToError(ctx))
if err := connection.SetReadDeadline(time.Time{}); err != nil {
newError("unable to set back read deadline").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
inbound := session.InboundFromContext(ctx)
if inbound == nil {
panic("no inbound metadata")
}
inbound.User = request.User
sessionPolicy = h.policyManager.ForLevel(request.User.Level)
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)
link, err := dispatcher.Dispatch(ctx, request.Destination())
if err != nil {
return newError("failed to dispatch request to ", request.Destination()).Base(err)
}
requestDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
bodyReader := svrSession.DecodeRequestBody(request, reader)
if err := buf.Copy(bodyReader, link.Writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transfer request").Base(err)
}
return nil
}
responseDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
writer := buf.NewBufferedWriter(buf.NewWriter(connection))
defer writer.Flush()
response := &protocol.ResponseHeader{
Command: h.generateCommand(ctx, request),
}
return transferResponse(timer, svrSession, request, response, link.Reader, writer)
}
var requestDonePost = task.OnSuccess(requestDone, task.Close(link.Writer))
if err := task.Run(ctx, requestDonePost, responseDone); err != nil {
common.Interrupt(link.Reader)
common.Interrupt(link.Writer)
return newError("connection ends").Base(err)
}
return nil
}
func (h *Handler) generateCommand(ctx context.Context, request *protocol.RequestHeader) protocol.ResponseCommand {
if h.detours != nil {
tag := h.detours.To
if h.inboundHandlerManager != nil {
handler, err := h.inboundHandlerManager.GetHandler(ctx, tag)
if err != nil {
newError("failed to get detour handler: ", tag).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))
return nil
}
proxyHandler, port, availableMin := handler.GetRandomInboundProxy()
inboundHandler, ok := proxyHandler.(*Handler)
if ok && inboundHandler != nil {
if availableMin > 255 {
availableMin = 255
}
newError("pick detour handler for port ", port, " for ", availableMin, " minutes.").AtDebug().WriteToLog(session.ExportIDToError(ctx))
user := inboundHandler.GetUser(request.User.Email)
if user == nil {
return nil
}
account := user.Account.(*vmess.MemoryAccount)
return &protocol.CommandSwitchAccount{
Port: port,
ID: account.ID.UUID(),
AlterIds: uint16(len(account.AlterIDs)),
Level: user.Level,
ValidMin: byte(availableMin),
}
}
}
}
return nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
}))
}
v2ray-core-4.34.0/proxy/vmess/outbound/ 0000775 0000000 0000000 00000000000 13774574720 0017770 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/proxy/vmess/outbound/command.go 0000664 0000000 0000000 00000002072 13774574720 0021736 0 ustar 00root root 0000000 0000000 // +build !confonly
package outbound
import (
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/proxy/vmess"
)
func (h *Handler) handleSwitchAccount(cmd *protocol.CommandSwitchAccount) {
rawAccount := &vmess.Account{
Id: cmd.ID.String(),
AlterId: uint32(cmd.AlterIds),
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_LEGACY,
},
}
account, err := rawAccount.AsAccount()
common.Must(err)
user := &protocol.MemoryUser{
Email: "",
Level: cmd.Level,
Account: account,
}
dest := net.TCPDestination(cmd.Host, cmd.Port)
until := time.Now().Add(time.Duration(cmd.ValidMin) * time.Minute)
h.serverList.AddServer(protocol.NewServerSpec(dest, protocol.BeforeTime(until), user))
}
func (h *Handler) handleCommand(dest net.Destination, cmd protocol.ResponseCommand) {
switch typedCommand := cmd.(type) {
case *protocol.CommandSwitchAccount:
if typedCommand.Host == nil {
typedCommand.Host = dest.Address
}
h.handleSwitchAccount(typedCommand)
default:
}
}
v2ray-core-4.34.0/proxy/vmess/outbound/config.go 0000664 0000000 0000000 00000000021 13774574720 0021555 0 ustar 00root root 0000000 0000000 package outbound
v2ray-core-4.34.0/proxy/vmess/outbound/config.pb.go 0000664 0000000 0000000 00000014520 13774574720 0022166 0 ustar 00root root 0000000 0000000 // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/vmess/outbound/config.proto
package outbound
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
protocol "v2ray.com/core/common/protocol"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Receiver []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=Receiver,proto3" json:"Receiver,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_vmess_outbound_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_proxy_vmess_outbound_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_proxy_vmess_outbound_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetReceiver() []*protocol.ServerEndpoint {
if x != nil {
return x.Receiver
}
return nil
}
var File_proxy_vmess_outbound_config_proto protoreflect.FileDescriptor
var file_proxy_vmess_outbound_config_proto_rawDesc = []byte{
0x0a, 0x21, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x6f, 0x75,
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x1f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x6f, 0x75, 0x74, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65,
0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x50, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x12, 0x46, 0x0a, 0x08, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52,
0x08, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x42, 0x6e, 0x0a, 0x23, 0x63, 0x6f, 0x6d,
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78,
0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x50, 0x01, 0x5a, 0x23, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f,
0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x6f,
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02, 0x1f, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,
0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6d, 0x65, 0x73, 0x73,
0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
file_proxy_vmess_outbound_config_proto_rawDescOnce sync.Once
file_proxy_vmess_outbound_config_proto_rawDescData = file_proxy_vmess_outbound_config_proto_rawDesc
)
func file_proxy_vmess_outbound_config_proto_rawDescGZIP() []byte {
file_proxy_vmess_outbound_config_proto_rawDescOnce.Do(func() {
file_proxy_vmess_outbound_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_vmess_outbound_config_proto_rawDescData)
})
return file_proxy_vmess_outbound_config_proto_rawDescData
}
var file_proxy_vmess_outbound_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_proxy_vmess_outbound_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: v2ray.core.proxy.vmess.outbound.Config
(*protocol.ServerEndpoint)(nil), // 1: v2ray.core.common.protocol.ServerEndpoint
}
var file_proxy_vmess_outbound_config_proto_depIdxs = []int32{
1, // 0: v2ray.core.proxy.vmess.outbound.Config.Receiver:type_name -> v2ray.core.common.protocol.ServerEndpoint
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_proxy_vmess_outbound_config_proto_init() }
func file_proxy_vmess_outbound_config_proto_init() {
if File_proxy_vmess_outbound_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_vmess_outbound_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_vmess_outbound_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_vmess_outbound_config_proto_goTypes,
DependencyIndexes: file_proxy_vmess_outbound_config_proto_depIdxs,
MessageInfos: file_proxy_vmess_outbound_config_proto_msgTypes,
}.Build()
File_proxy_vmess_outbound_config_proto = out.File
file_proxy_vmess_outbound_config_proto_rawDesc = nil
file_proxy_vmess_outbound_config_proto_goTypes = nil
file_proxy_vmess_outbound_config_proto_depIdxs = nil
}
v2ray-core-4.34.0/proxy/vmess/outbound/config.proto 0000664 0000000 0000000 00000000631 13774574720 0022322 0 ustar 00root root 0000000 0000000 syntax = "proto3";
package v2ray.core.proxy.vmess.outbound;
option csharp_namespace = "V2Ray.Core.Proxy.Vmess.Outbound";
option go_package = "v2ray.com/core/proxy/vmess/outbound";
option java_package = "com.v2ray.core.proxy.vmess.outbound";
option java_multiple_files = true;
import "common/protocol/server_spec.proto";
message Config {
repeated v2ray.core.common.protocol.ServerEndpoint Receiver = 1;
}
v2ray-core-4.34.0/proxy/vmess/outbound/errors.generated.go 0000664 0000000 0000000 00000000316 13774574720 0023570 0 ustar 00root root 0000000 0000000 package outbound
import "v2ray.com/core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}
v2ray-core-4.34.0/proxy/vmess/outbound/outbound.go 0000664 0000000 0000000 00000013632 13774574720 0022163 0 ustar 00root root 0000000 0000000 // +build !confonly
package outbound
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/platform"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/retry"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/policy"
"v2ray.com/core/proxy/vmess"
"v2ray.com/core/proxy/vmess/encoding"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
)
// Handler is an outbound connection handler for VMess protocol.
type Handler struct {
serverList *protocol.ServerList
serverPicker protocol.ServerPicker
policyManager policy.Manager
}
// New creates a new VMess outbound handler.
func New(ctx context.Context, config *Config) (*Handler, error) {
serverList := protocol.NewServerList()
for _, rec := range config.Receiver {
s, err := protocol.NewServerSpecFromPB(rec)
if err != nil {
return nil, newError("failed to parse server spec").Base(err)
}
serverList.AddServer(s)
}
v := core.MustFromContext(ctx)
handler := &Handler{
serverList: serverList,
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
}
return handler, nil
}
// Process implements proxy.Outbound.Process().
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
var rec *protocol.ServerSpec
var conn internet.Connection
err := retry.ExponentialBackoff(5, 200).On(func() error {
rec = h.serverPicker.PickServer()
rawConn, err := dialer.Dial(ctx, rec.Destination())
if err != nil {
return err
}
conn = rawConn
return nil
})
if err != nil {
return newError("failed to find an available destination").Base(err).AtWarning()
}
defer conn.Close()
outbound := session.OutboundFromContext(ctx)
if outbound == nil || !outbound.Target.IsValid() {
return newError("target not specified").AtError()
}
target := outbound.Target
newError("tunneling request to ", target, " via ", rec.Destination()).WriteToLog(session.ExportIDToError(ctx))
command := protocol.RequestCommandTCP
if target.Network == net.Network_UDP {
command = protocol.RequestCommandUDP
}
if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.cool" {
command = protocol.RequestCommandMux
}
user := rec.PickUser()
request := &protocol.RequestHeader{
Version: encoding.Version,
User: user,
Command: command,
Address: target.Address,
Port: target.Port,
Option: protocol.RequestOptionChunkStream,
}
account := request.User.Account.(*vmess.MemoryAccount)
request.Security = account.Security
if request.Security == protocol.SecurityType_AES128_GCM || request.Security == protocol.SecurityType_NONE || request.Security == protocol.SecurityType_CHACHA20_POLY1305 {
request.Option.Set(protocol.RequestOptionChunkMasking)
}
if shouldEnablePadding(request.Security) && request.Option.Has(protocol.RequestOptionChunkMasking) {
request.Option.Set(protocol.RequestOptionGlobalPadding)
}
input := link.Reader
output := link.Writer
isAEAD := false
if !aeadDisabled && len(account.AlterIDs) == 0 {
isAEAD = true
}
session := encoding.NewClientSession(ctx, isAEAD, protocol.DefaultIDHash)
sessionPolicy := h.policyManager.ForLevel(request.User.Level)
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
requestDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
writer := buf.NewBufferedWriter(buf.NewWriter(conn))
if err := session.EncodeRequestHeader(request, writer); err != nil {
return newError("failed to encode request").Base(err).AtWarning()
}
bodyWriter := session.EncodeRequestBody(request, writer)
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)
}
if err := writer.SetBuffered(false); err != nil {
return err
}
if err := buf.Copy(input, bodyWriter, buf.UpdateActivity(timer)); err != nil {
return err
}
if request.Option.Has(protocol.RequestOptionChunkStream) {
if err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {
return err
}
}
return nil
}
responseDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
reader := &buf.BufferedReader{Reader: buf.NewReader(conn)}
header, err := session.DecodeResponseHeader(reader)
if err != nil {
return newError("failed to read header").Base(err)
}
h.handleCommand(rec.Destination(), header.Command)
bodyReader := session.DecodeResponseBody(request, reader)
return buf.Copy(bodyReader, output, buf.UpdateActivity(timer))
}
var responseDonePost = task.OnSuccess(responseDone, task.Close(output))
if err := task.Run(ctx, requestDone, responseDonePost); err != nil {
return newError("connection ends").Base(err)
}
return nil
}
var (
enablePadding = false
aeadDisabled = false
)
func shouldEnablePadding(s protocol.SecurityType) bool {
return enablePadding || s == protocol.SecurityType_AES128_GCM || s == protocol.SecurityType_CHACHA20_POLY1305 || s == protocol.SecurityType_AUTO
}
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"
paddingValue := platform.NewEnvFlag("v2ray.vmess.padding").GetValue(func() string { return defaultFlagValue })
if paddingValue != defaultFlagValue {
enablePadding = true
}
isAeadDisabled := platform.NewEnvFlag("v2ray.vmess.aead.disabled").GetValue(func() string { return defaultFlagValue })
if isAeadDisabled == "true" {
aeadDisabled = true
}
}
v2ray-core-4.34.0/proxy/vmess/validator.go 0000664 0000000 0000000 00000012730 13774574720 0020450 0 ustar 00root root 0000000 0000000 // +build !confonly
package vmess
import (
"crypto/hmac"
"crypto/sha256"
"hash/crc64"
"strings"
"sync"
"sync/atomic"
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/dice"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/common/task"
"v2ray.com/core/proxy/vmess/aead"
)
const (
updateInterval = 10 * time.Second
cacheDurationSec = 120
)
type user struct {
user protocol.MemoryUser
lastSec protocol.Timestamp
}
// TimedUserValidator is a user Validator based on time.
type TimedUserValidator struct {
sync.RWMutex
users []*user
userHash map[[16]byte]indexTimePair
hasher protocol.IDHash
baseTime protocol.Timestamp
task *task.Periodic
behaviorSeed uint64
behaviorFused bool
aeadDecoderHolder *aead.AuthIDDecoderHolder
}
type indexTimePair struct {
user *user
timeInc uint32
taintedFuse *uint32
}
// NewTimedUserValidator creates a new TimedUserValidator.
func NewTimedUserValidator(hasher protocol.IDHash) *TimedUserValidator {
tuv := &TimedUserValidator{
users: make([]*user, 0, 16),
userHash: make(map[[16]byte]indexTimePair, 1024),
hasher: hasher,
baseTime: protocol.Timestamp(time.Now().Unix() - cacheDurationSec*2),
aeadDecoderHolder: aead.NewAuthIDDecoderHolder(),
}
tuv.task = &task.Periodic{
Interval: updateInterval,
Execute: func() error {
tuv.updateUserHash()
return nil
},
}
common.Must(tuv.task.Start())
return tuv
}
func (v *TimedUserValidator) generateNewHashes(nowSec protocol.Timestamp, user *user) {
var hashValue [16]byte
genEndSec := nowSec + cacheDurationSec
genHashForID := func(id *protocol.ID) {
idHash := v.hasher(id.Bytes())
genBeginSec := user.lastSec
if genBeginSec < nowSec-cacheDurationSec {
genBeginSec = nowSec - cacheDurationSec
}
for ts := genBeginSec; ts <= genEndSec; ts++ {
common.Must2(serial.WriteUint64(idHash, uint64(ts)))
idHash.Sum(hashValue[:0])
idHash.Reset()
v.userHash[hashValue] = indexTimePair{
user: user,
timeInc: uint32(ts - v.baseTime),
taintedFuse: new(uint32),
}
}
}
account := user.user.Account.(*MemoryAccount)
genHashForID(account.ID)
for _, id := range account.AlterIDs {
genHashForID(id)
}
user.lastSec = genEndSec
}
func (v *TimedUserValidator) removeExpiredHashes(expire uint32) {
for key, pair := range v.userHash {
if pair.timeInc < expire {
delete(v.userHash, key)
}
}
}
func (v *TimedUserValidator) updateUserHash() {
now := time.Now()
nowSec := protocol.Timestamp(now.Unix())
v.Lock()
defer v.Unlock()
for _, user := range v.users {
v.generateNewHashes(nowSec, user)
}
expire := protocol.Timestamp(now.Unix() - cacheDurationSec)
if expire > v.baseTime {
v.removeExpiredHashes(uint32(expire - v.baseTime))
}
}
func (v *TimedUserValidator) Add(u *protocol.MemoryUser) error {
v.Lock()
defer v.Unlock()
nowSec := time.Now().Unix()
uu := &user{
user: *u,
lastSec: protocol.Timestamp(nowSec - cacheDurationSec),
}
v.users = append(v.users, uu)
v.generateNewHashes(protocol.Timestamp(nowSec), uu)
account := uu.user.Account.(*MemoryAccount)
if !v.behaviorFused {
hashkdf := hmac.New(sha256.New, []byte("VMESSBSKDF"))
hashkdf.Write(account.ID.Bytes())
v.behaviorSeed = crc64.Update(v.behaviorSeed, crc64.MakeTable(crc64.ECMA), hashkdf.Sum(nil))
}
var cmdkeyfl [16]byte
copy(cmdkeyfl[:], account.ID.CmdKey())
v.aeadDecoderHolder.AddUser(cmdkeyfl, u)
return nil
}
func (v *TimedUserValidator) Get(userHash []byte) (*protocol.MemoryUser, protocol.Timestamp, bool, error) {
v.RLock()
defer v.RUnlock()
v.behaviorFused = true
var fixedSizeHash [16]byte
copy(fixedSizeHash[:], userHash)
pair, found := v.userHash[fixedSizeHash]
if found {
user := pair.user.user
if atomic.LoadUint32(pair.taintedFuse) == 0 {
return &user, protocol.Timestamp(pair.timeInc) + v.baseTime, true, nil
}
return nil, 0, false, ErrTainted
}
return nil, 0, false, ErrNotFound
}
func (v *TimedUserValidator) GetAEAD(userHash []byte) (*protocol.MemoryUser, bool, error) {
v.RLock()
defer v.RUnlock()
var userHashFL [16]byte
copy(userHashFL[:], userHash)
userd, err := v.aeadDecoderHolder.Match(userHashFL)
if err != nil {
return nil, false, err
}
return userd.(*protocol.MemoryUser), true, err
}
func (v *TimedUserValidator) Remove(email string) bool {
v.Lock()
defer v.Unlock()
email = strings.ToLower(email)
idx := -1
for i, u := range v.users {
if strings.EqualFold(u.user.Email, email) {
idx = i
var cmdkeyfl [16]byte
copy(cmdkeyfl[:], u.user.Account.(*MemoryAccount).ID.CmdKey())
v.aeadDecoderHolder.RemoveUser(cmdkeyfl)
break
}
}
if idx == -1 {
return false
}
ulen := len(v.users)
v.users[idx] = v.users[ulen-1]
v.users[ulen-1] = nil
v.users = v.users[:ulen-1]
return true
}
// Close implements common.Closable.
func (v *TimedUserValidator) Close() error {
return v.task.Close()
}
func (v *TimedUserValidator) GetBehaviorSeed() uint64 {
v.Lock()
defer v.Unlock()
v.behaviorFused = true
if v.behaviorSeed == 0 {
v.behaviorSeed = dice.RollUint64()
}
return v.behaviorSeed
}
func (v *TimedUserValidator) BurnTaintFuse(userHash []byte) error {
v.RLock()
defer v.RUnlock()
var userHashFL [16]byte
copy(userHashFL[:], userHash)
pair, found := v.userHash[userHashFL]
if found {
if atomic.CompareAndSwapUint32(pair.taintedFuse, 0, 1) {
return nil
}
return ErrTainted
}
return ErrNotFound
}
var ErrNotFound = newError("Not Found")
var ErrTainted = newError("ErrTainted")
v2ray-core-4.34.0/proxy/vmess/validator_test.go 0000664 0000000 0000000 00000004333 13774574720 0021507 0 ustar 00root root 0000000 0000000 package vmess_test
import (
"testing"
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/common/uuid"
. "v2ray.com/core/proxy/vmess"
)
func toAccount(a *Account) protocol.Account {
account, err := a.AsAccount()
common.Must(err)
return account
}
func TestUserValidator(t *testing.T) {
hasher := protocol.DefaultIDHash
v := NewTimedUserValidator(hasher)
defer common.Close(v)
id := uuid.New()
user := &protocol.MemoryUser{
Email: "test",
Account: toAccount(&Account{
Id: id.String(),
AlterId: 8,
}),
}
common.Must(v.Add(user))
{
testSmallLag := func(lag time.Duration) {
ts := protocol.Timestamp(time.Now().Add(time.Second * lag).Unix())
idHash := hasher(id.Bytes())
common.Must2(serial.WriteUint64(idHash, uint64(ts)))
userHash := idHash.Sum(nil)
euser, ets, found, _ := v.Get(userHash)
if !found {
t.Fatal("user not found")
}
if euser.Email != user.Email {
t.Error("unexpected user email: ", euser.Email, " want ", user.Email)
}
if ets != ts {
t.Error("unexpected timestamp: ", ets, " want ", ts)
}
}
testSmallLag(0)
testSmallLag(40)
testSmallLag(-40)
testSmallLag(80)
testSmallLag(-80)
testSmallLag(120)
testSmallLag(-120)
}
{
testBigLag := func(lag time.Duration) {
ts := protocol.Timestamp(time.Now().Add(time.Second * lag).Unix())
idHash := hasher(id.Bytes())
common.Must2(serial.WriteUint64(idHash, uint64(ts)))
userHash := idHash.Sum(nil)
euser, _, found, _ := v.Get(userHash)
if found || euser != nil {
t.Error("unexpected user")
}
}
testBigLag(121)
testBigLag(-121)
testBigLag(310)
testBigLag(-310)
testBigLag(500)
testBigLag(-500)
}
if v := v.Remove(user.Email); !v {
t.Error("unable to remove user")
}
if v := v.Remove(user.Email); v {
t.Error("remove user twice")
}
}
func BenchmarkUserValidator(b *testing.B) {
for i := 0; i < b.N; i++ {
hasher := protocol.DefaultIDHash
v := NewTimedUserValidator(hasher)
for j := 0; j < 1500; j++ {
id := uuid.New()
v.Add(&protocol.MemoryUser{
Email: "test",
Account: toAccount(&Account{
Id: id.String(),
AlterId: 16,
}),
})
}
common.Close(v)
}
}
v2ray-core-4.34.0/proxy/vmess/vmess.go 0000664 0000000 0000000 00000000611 13774574720 0017613 0 ustar 00root root 0000000 0000000 // Package vmess contains the implementation of VMess protocol and transportation.
//
// VMess contains both inbound and outbound connections. VMess inbound is usually used on servers
// together with 'freedom' to talk to final destination, while VMess outbound is usually used on
// clients with 'socks' for proxying.
package vmess
//go:generate go run v2ray.com/core/common/errors/errorgen
v2ray-core-4.34.0/proxy/vmess/vmessCtxInterface.go 0000664 0000000 0000000 00000000106 13774574720 0022112 0 ustar 00root root 0000000 0000000 package vmess
// example
const AlterID = "VMessCtxInterface_AlterID"
v2ray-core-4.34.0/release/ 0000775 0000000 0000000 00000000000 13774574720 0015233 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/release/config/ 0000775 0000000 0000000 00000000000 13774574720 0016500 5 ustar 00root root 0000000 0000000 v2ray-core-4.34.0/release/config/config.json 0000664 0000000 0000000 00000010175 13774574720 0020644 0 ustar 00root root 0000000 0000000 // Config file of V2Ray. This file follows standard JSON format, with comments support.
// Uncomment entries below to satisfy your needs. Also read our manual for more detail at
// https://www.v2ray.com/
{
"log": {
// By default, V2Ray writes access log to stdout.
// "access": "/path/to/access/log/file",
// By default, V2Ray write error log to stdout.
// "error": "/path/to/error/log/file",
// Log level, one of "debug", "info", "warning", "error", "none"
"loglevel": "warning"
},
// List of inbound proxy configurations.
"inbounds": [{
// Port to listen on. You may need root access if the value is less than 1024.
"port": 1080,
// IP address to listen on. Change to "0.0.0.0" to listen on all network interfaces.
"listen": "127.0.0.1",
// Tag of the inbound proxy. May be used for routing.
"tag": "socks-inbound",
// Protocol name of inbound proxy.
"protocol": "socks",
// Settings of the protocol. Varies based on protocol.
"settings": {
"auth": "noauth",
"udp": false,
"ip": "127.0.0.1"
},
// Enable sniffing on TCP connection.
"sniffing": {
"enabled": true,
// Target domain will be overriden to the one carried by the connection, if the connection is HTTP or HTTPS.
"destOverride": ["http", "tls"]
}
}],
// List of outbound proxy configurations.
"outbounds": [{
// Protocol name of the outbound proxy.
"protocol": "freedom",
// Settings of the protocol. Varies based on protocol.
"settings": {},
// Tag of the outbound. May be used for routing.
"tag": "direct"
},{
"protocol": "blackhole",
"settings": {},
"tag": "blocked"
}],
// Transport is for global transport settings. If you have multiple transports with same settings
// (say mKCP), you may put it here, instead of in each individual inbound/outbounds.
//"transport": {},
// Routing controls how traffic from inbounds are sent to outbounds.
"routing": {
"domainStrategy": "IPOnDemand",
"rules":[
{
// Blocks access to private IPs. Remove this if you want to access your router.
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "blocked"
},
{
// Blocks major ads.
"type": "field",
"domain": ["geosite:category-ads"],
"outboundTag": "blocked"
}
]
},
// Dns settings for domain resolution.
"dns": {
// Static hosts, similar to hosts file.
"hosts": {
// Match v2ray.com to another domain on CloudFlare. This domain will be used when querying IPs for v2ray.com.
"domain:v2ray.com": "www.vicemc.net",
// The following settings help to eliminate DNS poisoning in mainland China.
// It is safe to comment these out if this is not the case for you.
"domain:github.io": "pages.github.com",
"domain:wikipedia.org": "www.wikimedia.org",
"domain:shadowsocks.org": "electronicsrealm.com"
},
"servers": [
"1.1.1.1",
{
"address": "114.114.114.114",
"port": 53,
// List of domains that use this DNS first.
"domains": [
"geosite:cn"
]
},
"8.8.8.8",
"localhost"
]
},
// Policy controls some internal behavior of how V2Ray handles connections.
// It may be on connection level by user levels in 'levels', or global settings in 'system.'
"policy": {
// Connection policys by user levels
"levels": {
"0": {
"uplinkOnly": 0,
"downlinkOnly": 0
}
},
"system": {
"statsInboundUplink": false,
"statsInboundDownlink": false,
"statsOutboundUplink": false,
"statsOutboundDownlink": false
}
},
// Stats enables internal stats counter.
// This setting can be used together with Policy and Api.
//"stats":{},
// Api enables gRPC APIs for external programs to communicate with V2Ray instance.
//"api": {
//"tag": "api",
//"services": [
// "HandlerService",
// "LoggerService",
// "StatsService"
//]
//},
// You may add other entries to the configuration, but they will not be recognized by V2Ray.
"other": {}
}
v2ray-core-4.34.0/release/config/geoip.dat 0000664 0000000 0000000 00024315532 13774574720 0020314 0 ustar 00root root 0000000 0000000
B
US
!L
8
8
8
8
8
88
8r
8t
8x
8
8
8
8
8
8
8
8
8
8
8
8
8
9
9
9
9
9
9
9
:D
:H
:J
:L
:P
:S
:T
:
:
:
:
:
:
:
:
:
:
;
;8
;
;
;
;
;
J
L
P
`
(
0
P
d
l
t
}
@
8
@
@
!
!
!
!
!
!
"
$
(
0
8
:
;
;
;
;
;
;
;H
;P
;X
;`
;
;
;
;
<