mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-08-22 17:46:48 +08:00
Compare commits
149 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c29cf43d65 | ||
![]() |
b7be7807ac | ||
![]() |
68ae33c9e5 | ||
![]() |
0cceea75da | ||
![]() |
4b21c9aed3 | ||
![]() |
cde6e33ec9 | ||
![]() |
5dce7e4e25 | ||
![]() |
9359844149 | ||
![]() |
8222f43eea | ||
![]() |
04e6439b51 | ||
![]() |
bd86732f68 | ||
![]() |
d4f11e6d68 | ||
![]() |
00f3147242 | ||
![]() |
7cbf5b004c | ||
![]() |
87fff12fd9 | ||
![]() |
a02723e63f | ||
![]() |
146b14ab55 | ||
![]() |
b2829219a0 | ||
![]() |
116cd70a3a | ||
![]() |
c569f478af | ||
![]() |
b6b51c51c8 | ||
![]() |
fb7a9d8d61 | ||
![]() |
3fe02a658a | ||
![]() |
5f93ff6c3a | ||
![]() |
10376f5b4d | ||
![]() |
1ea00fad81 | ||
![]() |
cfcf2a63d1 | ||
![]() |
66025f2889 | ||
![]() |
c9cd26d6d3 | ||
![]() |
caee152adf | ||
![]() |
eb433d9462 | ||
![]() |
87d8b97d9a | ||
![]() |
9d15ecf1f9 | ||
![]() |
4f45c5faa5 | ||
![]() |
26de58933f | ||
![]() |
31b508d372 | ||
![]() |
955a569181 | ||
![]() |
d141d01d0c | ||
![]() |
4e826abebf | ||
![]() |
4433641e30 | ||
![]() |
a196a16c55 | ||
![]() |
8c0bf15901 | ||
![]() |
dbd9125686 | ||
![]() |
923b5d7229 | ||
![]() |
f90fae22aa | ||
![]() |
b065595f58 | ||
![]() |
308f8a7459 | ||
![]() |
050f596e8f | ||
![]() |
3b47d0846e | ||
![]() |
7f23a1cb65 | ||
![]() |
446315cf1f | ||
![]() |
eed05549fc | ||
![]() |
2b4a8d235b | ||
![]() |
83686ebfaa | ||
![]() |
79c6f99384 | ||
![]() |
ca8ef209a7 | ||
![]() |
cbcab89c7e | ||
![]() |
abd551e9f7 | ||
![]() |
10dbeb4335 | ||
![]() |
6afd721ced | ||
![]() |
5c0bc361d3 | ||
![]() |
3a2ac9d0bf | ||
![]() |
1785178762 | ||
![]() |
1976d02ec9 | ||
![]() |
3ba733079e | ||
![]() |
6a8a85f83a | ||
![]() |
409e4e8f12 | ||
![]() |
486d005986 | ||
![]() |
cb1afb33e6 | ||
![]() |
38ed2cc387 | ||
![]() |
b043db8260 | ||
![]() |
27742da2c6 | ||
![]() |
fbae89d017 | ||
![]() |
58c28b4aeb | ||
![]() |
ca1c4b63f6 | ||
![]() |
18ab291e0c | ||
![]() |
e011b746dc | ||
![]() |
f4b23c6565 | ||
![]() |
7d36cad3e0 | ||
![]() |
a576a4b183 | ||
![]() |
f38d3f786a | ||
![]() |
402067d281 | ||
![]() |
97fdcb4228 | ||
![]() |
bfbccc2721 | ||
![]() |
f67c70c4a2 | ||
![]() |
83e5fa4f3c | ||
![]() |
4e1a6f0fd1 | ||
![]() |
ab0b9a6220 | ||
![]() |
b80e319655 | ||
![]() |
6232e230d9 | ||
![]() |
028e1114e6 | ||
![]() |
af7a76da67 | ||
![]() |
d44c78b819 | ||
![]() |
d0c80fc80d | ||
![]() |
1f49bfc6a5 | ||
![]() |
dd52732e1f | ||
![]() |
4af53ab364 | ||
![]() |
462bc3cfba | ||
![]() |
84c8e24a6c | ||
![]() |
9fe4ee75b7 | ||
![]() |
f1116cee60 | ||
![]() |
800b8b50cc | ||
![]() |
ef1c165cc5 | ||
![]() |
bb0e561caf | ||
![]() |
09d84c42e9 | ||
![]() |
7ddc4a2525 | ||
![]() |
882975ce5a | ||
![]() |
30bf7be429 | ||
![]() |
c53c1bfc51 | ||
![]() |
72170d8b6b | ||
![]() |
e9b3c53a0d | ||
![]() |
7afed1e74d | ||
![]() |
6ed636840b | ||
![]() |
f0dfbc2e66 | ||
![]() |
0d0fe7ef7a | ||
![]() |
59aa5e1b88 | ||
![]() |
3e52f73e3c | ||
![]() |
d4ca42715a | ||
![]() |
c847c21f3b | ||
![]() |
87ab8e5128 | ||
![]() |
54c6513fd4 | ||
![]() |
5e6a5ae01d | ||
![]() |
19ba9cbe91 | ||
![]() |
16641fc4b5 | ||
![]() |
aa4134f4a6 | ||
![]() |
1c4e246788 | ||
![]() |
d9ebb9b2dc | ||
![]() |
2eed70e17d | ||
![]() |
58c48664e2 | ||
![]() |
a608c5a1db | ||
![]() |
0dd74cf072 | ||
![]() |
922ae98a4a | ||
![]() |
800b33c626 | ||
![]() |
0563c9750e | ||
![]() |
907a182f64 | ||
![]() |
0995fa41fe | ||
![]() |
2916b1b977 | ||
![]() |
8212325980 | ||
![]() |
5f3ae64f0c | ||
![]() |
7a2f42f8d5 | ||
![]() |
53552d73cc | ||
![]() |
19e884bebf | ||
![]() |
78a1e37e89 | ||
![]() |
2d3126b752 | ||
![]() |
0dbab7bcd7 | ||
![]() |
ab15822ee3 | ||
![]() |
8b2fe32a33 | ||
![]() |
dd2a40e64d | ||
![]() |
33a4336b1d |
72
.github/docker/Dockerfile
vendored
72
.github/docker/Dockerfile
vendored
@@ -1,28 +1,62 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM --platform=$BUILDPLATFORM golang:alpine AS build
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM --platform=$BUILDPLATFORM golang:latest AS build
|
||||
|
||||
# Build xray-core
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
|
||||
ADD https://github.com/v2fly/geoip/releases/latest/download/geoip.dat /v2fly/geoip.dat
|
||||
ADD https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat /v2fly/geosite.dat
|
||||
ADD https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat /loyalsoldier/geoip.dat
|
||||
ADD https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat /loyalsoldier/geosite.dat
|
||||
|
||||
# chainguard/static contains only tzdata and ca-certificates, can be built with multiarch static binaries.
|
||||
FROM --platform=linux/amd64 chainguard/static:latest
|
||||
WORKDIR /var/log/xray
|
||||
COPY .github/docker/files/config.json /etc/xray/config.json
|
||||
COPY --from=build --chmod=755 /src/xray /usr/bin/xray
|
||||
# Download geodat into a staging directory
|
||||
ADD https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geoip.dat /tmp/geodat/geoip.dat
|
||||
ADD https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat /tmp/geodat/geosite.dat
|
||||
|
||||
USER root
|
||||
WORKDIR /root
|
||||
VOLUME /etc/xray
|
||||
ARG TZ=Asia/Shanghai
|
||||
RUN mkdir -p /tmp/empty
|
||||
|
||||
# Create config files with empty JSON content
|
||||
RUN mkdir -p /tmp/usr/local/etc/xray
|
||||
RUN cat <<EOF >/tmp/usr/local/etc/xray/00_log.json
|
||||
{
|
||||
"log": {
|
||||
"error": "/var/log/xray/error.log",
|
||||
"loglevel": "warning",
|
||||
"access": "none",
|
||||
"dnsLog": false
|
||||
}
|
||||
}
|
||||
EOF
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/01_api.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/02_dns.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/03_routing.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/04_policy.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/05_inbounds.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/06_outbounds.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/07_transport.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/08_stats.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/09_reverse.json
|
||||
|
||||
# Create log files
|
||||
RUN mkdir -p /tmp/var/log/xray && touch \
|
||||
/tmp/var/log/xray/access.log \
|
||||
/tmp/var/log/xray/error.log
|
||||
|
||||
# Build finally image
|
||||
FROM gcr.io/distroless/static:nonroot
|
||||
|
||||
COPY --from=build --chown=0:0 --chmod=755 /src/xray /usr/local/bin/xray
|
||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /usr/local/share/xray
|
||||
COPY --from=build --chown=0:0 --chmod=644 /tmp/geodat/*.dat /usr/local/share/xray/
|
||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /usr/local/etc/xray
|
||||
COPY --from=build --chown=0:0 --chmod=644 /tmp/usr/local/etc/xray/*.json /usr/local/etc/xray/
|
||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /var/log/xray
|
||||
COPY --from=build --chown=65532:65532 --chmod=600 /tmp/var/log/xray/*.log /var/log/xray/
|
||||
|
||||
VOLUME /usr/local/etc/xray
|
||||
VOLUME /var/log/xray
|
||||
|
||||
ARG TZ=Etc/UTC
|
||||
ENV TZ=$TZ
|
||||
ENTRYPOINT [ "/usr/bin/xray" ]
|
||||
CMD [ "-confdir", "/etc/xray/" ]
|
||||
|
||||
ARG flavor=v2fly
|
||||
COPY --from=build --chmod=644 /$flavor /usr/share/xray
|
||||
ENTRYPOINT [ "/usr/local/bin/xray" ]
|
||||
CMD [ "-confdir", "/usr/local/etc/xray/" ]
|
||||
|
71
.github/docker/Dockerfile.usa
vendored
Normal file
71
.github/docker/Dockerfile.usa
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM --platform=$BUILDPLATFORM golang:latest AS build
|
||||
|
||||
# Build xray-core
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
|
||||
|
||||
# Download geodat into a staging directory
|
||||
ADD https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geoip.dat /tmp/geodat/geoip.dat
|
||||
ADD https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat /tmp/geodat/geosite.dat
|
||||
|
||||
RUN mkdir -p /tmp/empty
|
||||
|
||||
# Create config files with empty JSON content
|
||||
RUN mkdir -p /tmp/usr/local/etc/xray
|
||||
RUN cat <<EOF >/tmp/usr/local/etc/xray/00_log.json
|
||||
{
|
||||
"log": {
|
||||
"error": "/var/log/xray/error.log",
|
||||
"loglevel": "warning",
|
||||
"access": "none",
|
||||
"dnsLog": false
|
||||
}
|
||||
}
|
||||
EOF
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/01_api.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/02_dns.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/03_routing.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/04_policy.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/05_inbounds.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/06_outbounds.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/07_transport.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/08_stats.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/09_reverse.json
|
||||
|
||||
# Create log files
|
||||
RUN mkdir -p /tmp/var/log/xray && touch \
|
||||
/tmp/var/log/xray/access.log \
|
||||
/tmp/var/log/xray/error.log
|
||||
|
||||
# Build finally image
|
||||
# Note on Distroless Base Image and Architecture Support:
|
||||
# - The official 'gcr.io/distroless/static' image provided by Google only supports a limited set of architectures for Linux:
|
||||
# - linux/amd64
|
||||
# - linux/arm/v7
|
||||
# - linux/arm64/v8
|
||||
# - linux/ppc64le
|
||||
# - linux/s390x
|
||||
# - Upon inspection, the blob contents of the Distroless images across these architectures are nearly identical, with only minor differences in metadata (e.g., 'Architecture' field in the manifest).
|
||||
# - Due to this similarity in content, it is feasible to forcibly specify a single platform (e.g., '--platform=linux/amd64') for unsupported architectures, as the core image content remains compatible with statically compiled binaries like Go applications.
|
||||
FROM --platform=linux/amd64 gcr.io/distroless/static:nonroot
|
||||
|
||||
COPY --from=build --chown=0:0 --chmod=755 /src/xray /usr/local/bin/xray
|
||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /usr/local/share/xray
|
||||
COPY --from=build --chown=0:0 --chmod=644 /tmp/geodat/*.dat /usr/local/share/xray/
|
||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /usr/local/etc/xray
|
||||
COPY --from=build --chown=0:0 --chmod=644 /tmp/usr/local/etc/xray/*.json /usr/local/etc/xray/
|
||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /var/log/xray
|
||||
COPY --from=build --chown=65532:65532 --chmod=600 /tmp/var/log/xray/*.log /var/log/xray/
|
||||
|
||||
VOLUME /usr/local/etc/xray
|
||||
VOLUME /var/log/xray
|
||||
|
||||
ARG TZ=Etc/UTC
|
||||
ENV TZ=$TZ
|
||||
|
||||
ENTRYPOINT [ "/usr/local/bin/xray" ]
|
||||
CMD [ "-confdir", "/usr/local/etc/xray/" ]
|
18
.github/docker/files/config.json
vendored
18
.github/docker/files/config.json
vendored
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"inbounds": [{
|
||||
"port": 9000,
|
||||
"protocol": "vmess",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"id": "1eb6e917-774b-4a84-aff6-b058577c60a5",
|
||||
"level": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}],
|
||||
"outbounds": [{
|
||||
"protocol": "freedom",
|
||||
"settings": {}
|
||||
}]
|
||||
}
|
155
.github/workflows/docker.yml
vendored
155
.github/workflows/docker.yml
vendored
@@ -1,76 +1,133 @@
|
||||
name: Build docker image
|
||||
name: Build and Push Docker Image
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
types:
|
||||
- published
|
||||
- released
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Docker image tag:"
|
||||
required: true
|
||||
latest:
|
||||
description: "Set to latest"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build-image:
|
||||
build-and-push:
|
||||
if: (github.event.action != 'published') || (github.event.action == 'published' && github.event.release.prerelease == true)
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/xray-core
|
||||
flavor: latest=auto
|
||||
tags: |
|
||||
type=sha
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
- name: Docker metadata Loyalsoldier flavor
|
||||
id: loyalsoldier
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/xray-core
|
||||
flavor: |
|
||||
latest=auto
|
||||
suffix=-ls,onlatest=true
|
||||
tags: |
|
||||
type=sha
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
- name: Set repository and image name to lowercase
|
||||
env:
|
||||
IMAGE_NAME: "${{ github.repository }}"
|
||||
run: |
|
||||
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
|
||||
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
|
||||
|
||||
- name: Validate and extract tag
|
||||
run: |
|
||||
SOURCE_TAG="${{ github.event.inputs.tag }}"
|
||||
if [[ -z "$SOURCE_TAG" ]]; then
|
||||
SOURCE_TAG="${{ github.ref_name }}"
|
||||
fi
|
||||
if [[ -z "$SOURCE_TAG" ]]; then
|
||||
SOURCE_TAG="${{ github.event.release.tag_name }}"
|
||||
fi
|
||||
|
||||
if [[ -z "$SOURCE_TAG" ]]; then
|
||||
echo "Error: Could not determine a valid tag source. Input tag and context tag (github.ref_name) are both empty."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$SOURCE_TAG" =~ ^v[0-9]+\.[0-9] ]]; then
|
||||
IMAGE_TAG="${SOURCE_TAG#v}"
|
||||
else
|
||||
IMAGE_TAG="$SOURCE_TAG"
|
||||
fi
|
||||
|
||||
echo "Docker image tag: '$IMAGE_TAG'."
|
||||
echo "IMAGE_TAG=$IMAGE_TAG" >>${GITHUB_ENV}
|
||||
|
||||
LATEST=false
|
||||
if [[ "${{ github.event_name }}" == "release" && "${{ github.event.release.prerelease }}" == "false" ]] || [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ github.event.inputs.latest }}" == "true" ]]; then
|
||||
LATEST=true
|
||||
fi
|
||||
|
||||
echo "Latest: '$LATEST'."
|
||||
echo "LATEST=$LATEST" >>${GITHUB_ENV}
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Build and push
|
||||
|
||||
- name: Build Docker image (main architectures)
|
||||
id: build_main_arches
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: .github/docker/Dockerfile
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm64
|
||||
linux/loong64
|
||||
linux/riscv64
|
||||
linux/arm/v7
|
||||
linux/arm64/v8
|
||||
linux/ppc64le
|
||||
linux/s390x
|
||||
provenance: false
|
||||
file: .github/docker/Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
- name: Build and push Loyalsoldier flavor
|
||||
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
- name: Build Docker image (additional architectures)
|
||||
id: build_additional_arches
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: .github/docker/Dockerfile.usa
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm64
|
||||
linux/loong64
|
||||
linux/386
|
||||
linux/arm/v6
|
||||
linux/riscv64
|
||||
linux/loong64
|
||||
provenance: false
|
||||
file: .github/docker/Dockerfile
|
||||
build-args: flavor=loyalsoldier
|
||||
push: true
|
||||
tags: |
|
||||
${{ steps.loyalsoldier.outputs.tags }}
|
||||
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
- name: Create manifest list and push
|
||||
run: |
|
||||
echo "Creating multi-arch manifest with tag: '${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}'."
|
||||
docker buildx imagetools create \
|
||||
--tag ${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }} \
|
||||
${{ env.FULL_IMAGE_NAME }}@${{ steps.build_main_arches.outputs.digest }} \
|
||||
${{ env.FULL_IMAGE_NAME }}@${{ steps.build_additional_arches.outputs.digest }}
|
||||
|
||||
if [[ "${{ env.LATEST }}" == "true" ]]; then
|
||||
echo "Adding 'latest' tag to manifest: '${{ env.FULL_IMAGE_NAME }}:latest'."
|
||||
docker buildx imagetools create \
|
||||
--tag ${{ env.FULL_IMAGE_NAME }}:latest \
|
||||
${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
||||
fi
|
||||
|
||||
- name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
||||
|
||||
if [[ "${{ env.LATEST }}" == "true" ]]; then
|
||||
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:latest
|
||||
fi
|
||||
|
33
.github/workflows/release-win7.yml
vendored
33
.github/workflows/release-win7.yml
vendored
@@ -9,7 +9,38 @@ on:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
check-assets:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Restore Geodat Cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: resources
|
||||
key: xray-geodat-
|
||||
|
||||
- name: Check Assets Existence
|
||||
id: check-assets
|
||||
run: |
|
||||
[ -d 'resources' ] || mkdir resources
|
||||
LIST=('geoip.dat' 'geosite.dat')
|
||||
for FILE_NAME in "${LIST[@]}"
|
||||
do
|
||||
echo -e "Checking ${FILE_NAME}..."
|
||||
if [ -s "./resources/${FILE_NAME}" ]; then
|
||||
echo -e "${FILE_NAME} exists."
|
||||
else
|
||||
echo -e "${FILE_NAME} does not exist."
|
||||
echo "missing=true" >> $GITHUB_OUTPUT
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Sleep for 90 seconds if Assets Missing
|
||||
if: steps.check-assets.outputs.missing == 'true'
|
||||
run: sleep 90
|
||||
|
||||
build:
|
||||
needs: check-assets
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
@@ -51,7 +82,7 @@ jobs:
|
||||
GOSDK=$(go env GOROOT)
|
||||
rm -r $GOSDK/*
|
||||
cd $GOSDK
|
||||
curl -O -L https://github.com/XTLS/go-win7/releases/latest/download/go-for-win7-linux-amd64.zip
|
||||
curl -O -L -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://github.com/XTLS/go-win7/releases/latest/download/go-for-win7-linux-amd64.zip
|
||||
unzip ./go-for-win7-linux-amd64.zip -d $GOSDK
|
||||
rm ./go-for-win7-linux-amd64.zip
|
||||
|
||||
|
66
.github/workflows/release.yml
vendored
66
.github/workflows/release.yml
vendored
@@ -9,7 +9,53 @@ on:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
check-assets:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Restore Geodat Cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: resources
|
||||
key: xray-geodat-
|
||||
|
||||
- name: Check Assets Existence
|
||||
id: check-assets
|
||||
run: |
|
||||
[ -d 'resources' ] || mkdir resources
|
||||
LIST=('geoip.dat' 'geosite.dat')
|
||||
for FILE_NAME in "${LIST[@]}"
|
||||
do
|
||||
echo -e "Checking ${FILE_NAME}..."
|
||||
if [ -s "./resources/${FILE_NAME}" ]; then
|
||||
echo -e "${FILE_NAME} exists."
|
||||
else
|
||||
echo -e "${FILE_NAME} does not exist."
|
||||
echo "missing=true" >> $GITHUB_OUTPUT
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Trigger Asset Update Workflow if Assets Missing
|
||||
if: steps.check-assets.outputs.missing == 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const { owner, repo } = context.repo;
|
||||
await github.rest.actions.createWorkflowDispatch({
|
||||
owner,
|
||||
repo,
|
||||
workflow_id: 'scheduled-assets-update.yml',
|
||||
ref: context.ref
|
||||
});
|
||||
console.log('Triggered scheduled-assets-update.yml due to missing assets on branch:', context.ref);
|
||||
|
||||
- name: Sleep for 90 seconds if Assets Missing
|
||||
if: steps.check-assets.outputs.missing == 'true'
|
||||
run: sleep 90
|
||||
|
||||
build:
|
||||
needs: check-assets
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
@@ -42,6 +88,11 @@ jobs:
|
||||
- goos: android
|
||||
goarch: arm64
|
||||
# END Android ARM 8
|
||||
# BEGIN Android AMD64
|
||||
- goos: android
|
||||
goarch: amd64
|
||||
patch-assetname: android-amd64
|
||||
# END Android AMD64
|
||||
# Windows ARM
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
@@ -104,6 +155,19 @@ jobs:
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up NDK
|
||||
if: matrix.goos == 'android'
|
||||
run: |
|
||||
wget -qO android-ndk.zip https://dl.google.com/android/repository/android-ndk-r28b-linux.zip
|
||||
unzip android-ndk.zip
|
||||
rm android-ndk.zip
|
||||
declare -A arches=(
|
||||
["amd64"]="x86_64-linux-android24-clang"
|
||||
["arm64"]="aarch64-linux-android24-clang"
|
||||
)
|
||||
echo CC="$(realpath android-ndk-*/toolchains/llvm/prebuilt/linux-x86_64/bin)/${arches[${{ matrix.goarch }}]}" >> $GITHUB_ENV
|
||||
echo CGO_ENABLED=1 >> $GITHUB_ENV
|
||||
|
||||
- name: Show workflow information
|
||||
run: |
|
||||
_NAME=${{ matrix.patch-assetname }}
|
||||
@@ -119,7 +183,7 @@ jobs:
|
||||
|
||||
- name: Get project dependencies
|
||||
run: go mod download
|
||||
|
||||
|
||||
- name: Build Xray
|
||||
run: |
|
||||
mkdir -p build_assets
|
||||
|
@@ -1,6 +1,6 @@
|
||||
name: Scheduled assets update
|
||||
|
||||
# NOTE: This Github Actions is required by other actions, for preparing other packaging assets in a
|
||||
# NOTE: This Github Actions is required by other actions, for preparing other packaging assets in a
|
||||
# routine manner, for example: GeoIP/GeoSite.
|
||||
# Currently updating:
|
||||
# - Geodat (GeoIP/Geosite)
|
||||
@@ -9,7 +9,7 @@ on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# Update GeoData on every day (22:30 UTC)
|
||||
- cron: '30 22 * * *'
|
||||
- cron: "30 22 * * *"
|
||||
push:
|
||||
# Prevent triggering update request storm
|
||||
paths:
|
||||
@@ -45,12 +45,12 @@ jobs:
|
||||
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3,$4}'))
|
||||
FILE_NAME="${INFO[3]}.dat"
|
||||
echo -e "Verifying HASH key..."
|
||||
HASH="$(curl -sL "https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
|
||||
HASH="$(curl -sL -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
|
||||
if [ -s "./resources/${FILE_NAME}" ] && [ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ]; then
|
||||
continue
|
||||
else
|
||||
echo -e "Downloading https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat..."
|
||||
curl -L "https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat" -o ./resources/${FILE_NAME}
|
||||
curl -L -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat" -o ./resources/${FILE_NAME}
|
||||
echo -e "Verifying HASH key..."
|
||||
[ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ] || { echo -e "The HASH key of ${FILE_NAME} does not match cloud one."; exit 1; }
|
||||
echo "unhit=true" >> $GITHUB_OUTPUT
|
||||
|
29
.github/workflows/test.yml
vendored
29
.github/workflows/test.yml
vendored
@@ -6,7 +6,36 @@ on:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
check-assets:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Restore Geodat Cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: resources
|
||||
key: xray-geodat-
|
||||
- name: Check Assets Existence
|
||||
id: check-assets
|
||||
run: |
|
||||
[ -d 'resources' ] || mkdir resources
|
||||
LIST=('geoip.dat' 'geosite.dat')
|
||||
for FILE_NAME in "${LIST[@]}"
|
||||
do
|
||||
echo -e "Checking ${FILE_NAME}..."
|
||||
if [ -s "./resources/${FILE_NAME}" ]; then
|
||||
echo -e "${FILE_NAME} exists."
|
||||
else
|
||||
echo -e "${FILE_NAME} does not exist."
|
||||
echo "missing=true" >> $GITHUB_OUTPUT
|
||||
break
|
||||
fi
|
||||
done
|
||||
- name: Sleep for 90 seconds if Assets Missing
|
||||
if: steps.check-assets.outputs.missing == 'true'
|
||||
run: sleep 90
|
||||
|
||||
test:
|
||||
needs: check-assets
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
41
README.md
41
README.md
@@ -6,9 +6,13 @@
|
||||
|
||||
## Donation & NFTs
|
||||
|
||||
### [Collect a Project X NFT to support the development of Project X!](https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1)
|
||||
|
||||
[<img alt="Project X NFT" width="150px" src="https://raw2.seadn.io/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/7fa9ce900fb39b44226348db330e32/8b7fa9ce900fb39b44226348db330e32.svg" />](https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1)
|
||||
|
||||
- **ETH/USDT/USDC: `0xDc3Fe44F0f25D13CACb1C4896CD0D321df3146Ee`**
|
||||
- **Project X NFT: [Announcement of NFTs by Project X](https://github.com/XTLS/Xray-core/discussions/3633)**
|
||||
- **REALITY NFT: [XHTTP: Beyond REALITY](https://github.com/XTLS/Xray-core/discussions/4113)**
|
||||
- **REALITY NFT: https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/2**
|
||||
- **Related links: https://opensea.io/collection/xtls, [Announcement of NFTs by Project X](https://github.com/XTLS/Xray-core/discussions/3633), [XHTTP: Beyond REALITY](https://github.com/XTLS/Xray-core/discussions/4113)**
|
||||
|
||||
## License
|
||||
|
||||
@@ -44,7 +48,7 @@
|
||||
- [Hiddify](https://github.com/hiddify/Hiddify-Manager)
|
||||
- One Click
|
||||
- [Xray-REALITY](https://github.com/zxcvos/Xray-script), [xray-reality](https://github.com/sajjaddg/xray-reality), [reality-ezpz](https://github.com/aleskxyz/reality-ezpz)
|
||||
- [Xray_bash_onekey](https://github.com/hello-yunshu/Xray_bash_onekey), [XTool](https://github.com/LordPenguin666/XTool)
|
||||
- [Xray_bash_onekey](https://github.com/hello-yunshu/Xray_bash_onekey), [XTool](https://github.com/LordPenguin666/XTool), [VPainLess](https://github.com/vpainless/vpainless)
|
||||
- [v2ray-agent](https://github.com/mack-a/v2ray-agent), [Xray_onekey](https://github.com/wulabing/Xray_onekey), [ProxySU](https://github.com/proxysu/ProxySU)
|
||||
- Magisk
|
||||
- [Xray4Magisk](https://github.com/Asterisk4Magisk/Xray4Magisk)
|
||||
@@ -81,32 +85,43 @@
|
||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
- Android
|
||||
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
||||
- [X-flutter](https://github.com/XTLS/X-flutter)
|
||||
- [SaeedDev94/Xray](https://github.com/SaeedDev94/Xray)
|
||||
- iOS & macOS arm64
|
||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215)
|
||||
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
|
||||
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
- iOS & macOS arm64 & tvOS
|
||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215) ([tvOS](https://apps.apple.com/us/app/happ-proxy-utility-for-tv/id6748297274))
|
||||
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)
|
||||
- [OneXray](https://github.com/OneXray/OneXray)
|
||||
- macOS arm64 & x64
|
||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215)
|
||||
- [V2rayU](https://github.com/yanue/V2rayU)
|
||||
- [V2RayXS](https://github.com/tzmax/V2RayXS)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
|
||||
- [OneXray](https://github.com/OneXray/OneXray)
|
||||
- [GoXRay](https://github.com/goxray/desktop)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
- Linux
|
||||
- [v2rayA](https://github.com/v2rayA/v2rayA)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
- [GorzRay](https://github.com/ketetefid/GorzRay)
|
||||
- [GoXRay](https://github.com/goxray/desktop)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
|
||||
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
||||
|
||||
- iOS & macOS arm64
|
||||
- iOS & macOS arm64 & tvOS
|
||||
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
||||
- [Loon](https://apps.apple.com/us/app/loon/id1373567447)
|
||||
- Xray Tools
|
||||
- [xray-knife](https://github.com/lilendian0x00/xray-knife)
|
||||
- [xray-checker](https://github.com/kutovoys/xray-checker)
|
||||
- Xray Wrapper
|
||||
- [XTLS/libXray](https://github.com/XTLS/libXray)
|
||||
- [xtls-sdk](https://github.com/remnawave/xtls-sdk)
|
||||
- [xtlsapi](https://github.com/hiddify/xtlsapi)
|
||||
- [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite)
|
||||
- [Xray-core-python](https://github.com/LorenEteval/Xray-core-python)
|
||||
@@ -114,15 +129,17 @@
|
||||
- [XrayR](https://github.com/XrayR-project/XrayR)
|
||||
- [XrayR-release](https://github.com/XrayR-project/XrayR-release)
|
||||
- [XrayR-V2Board](https://github.com/missuo/XrayR-V2Board)
|
||||
- [Clash.Meta](https://github.com/MetaCubeX/Clash.Meta)
|
||||
- [clashN](https://github.com/2dust/clashN)
|
||||
- [Clash Meta for Android](https://github.com/MetaCubeX/ClashMetaForAndroid)
|
||||
- [sing-box](https://github.com/SagerNet/sing-box)
|
||||
- Cores
|
||||
- [Amnezia VPN](https://github.com/amnezia-vpn)
|
||||
- [mihomo](https://github.com/MetaCubeX/mihomo)
|
||||
- [sing-box](https://github.com/SagerNet/sing-box)
|
||||
|
||||
## Contributing
|
||||
|
||||
[Code of Conduct](https://github.com/XTLS/Xray-core/blob/main/CODE_OF_CONDUCT.md)
|
||||
|
||||
[](https://deepwiki.com/XTLS/Xray-core)
|
||||
|
||||
## Credits
|
||||
|
||||
- [Xray-core v1.0.0](https://github.com/XTLS/Xray-core/releases/tag/v1.0.0) was forked from [v2fly-core 9a03cc5](https://github.com/v2fly/v2ray-core/commit/9a03cc5c98d04cc28320fcee26dbc236b3291256), and we have made & accumulated a huge number of enhancements over time, check [the release notes for each version](https://github.com/XTLS/Xray-core/releases).
|
||||
|
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/net/cnc"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/signal/done"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
)
|
||||
@@ -108,3 +109,13 @@ func (co *Outbound) Close() error {
|
||||
co.closed = true
|
||||
return co.listener.Close()
|
||||
}
|
||||
|
||||
// SenderSettings implements outbound.Handler.
|
||||
func (co *Outbound) SenderSettings() *serial.TypedMessage {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProxySettings implements outbound.Handler.
|
||||
func (co *Outbound) ProxySettings() *serial.TypedMessage {
|
||||
return nil
|
||||
}
|
||||
|
@@ -33,23 +33,21 @@ type cachedReader struct {
|
||||
cache buf.MultiBuffer
|
||||
}
|
||||
|
||||
func (r *cachedReader) Cache(b *buf.Buffer) {
|
||||
mb, _ := r.reader.ReadMultiBufferTimeout(time.Millisecond * 100)
|
||||
func (r *cachedReader) Cache(b *buf.Buffer, deadline time.Duration) error {
|
||||
mb, err := r.reader.ReadMultiBufferTimeout(deadline)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Lock()
|
||||
if !mb.IsEmpty() {
|
||||
r.cache, _ = buf.MergeMulti(r.cache, mb)
|
||||
}
|
||||
cacheLen := r.cache.Len()
|
||||
if cacheLen <= b.Cap() {
|
||||
b.Clear()
|
||||
} else {
|
||||
b.Release()
|
||||
*b = *buf.NewWithSize(cacheLen)
|
||||
}
|
||||
rawBytes := b.Extend(cacheLen)
|
||||
b.Clear()
|
||||
rawBytes := b.Extend(min(r.cache.Len(), b.Cap()))
|
||||
n := r.cache.Copy(rawBytes)
|
||||
b.Resize(0, int32(n))
|
||||
r.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *cachedReader) readInternal() buf.MultiBuffer {
|
||||
@@ -98,7 +96,6 @@ type DefaultDispatcher struct {
|
||||
router routing.Router
|
||||
policy policy.Manager
|
||||
stats stats.Manager
|
||||
dns dns.Client
|
||||
fdns dns.FakeDNSEngine
|
||||
}
|
||||
|
||||
@@ -109,7 +106,7 @@ func init() {
|
||||
core.OptionalFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||
d.fdns = fdns
|
||||
})
|
||||
return d.Init(config.(*Config), om, router, pm, sm, dc)
|
||||
return d.Init(config.(*Config), om, router, pm, sm)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -118,12 +115,11 @@ func init() {
|
||||
}
|
||||
|
||||
// Init initializes DefaultDispatcher.
|
||||
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dns dns.Client) error {
|
||||
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager) error {
|
||||
d.ohm = om
|
||||
d.router = router
|
||||
d.policy = pm
|
||||
d.stats = sm
|
||||
d.dns = dns
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -355,7 +351,7 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
||||
}
|
||||
|
||||
func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, network net.Network) (SniffResult, error) {
|
||||
payload := buf.New()
|
||||
payload := buf.NewWithSize(32767)
|
||||
defer payload.Release()
|
||||
|
||||
sniffer := NewSniffer(ctx)
|
||||
@@ -367,26 +363,36 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
|
||||
}
|
||||
|
||||
contentResult, contentErr := func() (SniffResult, error) {
|
||||
cacheDeadline := 200 * time.Millisecond
|
||||
totalAttempt := 0
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
totalAttempt++
|
||||
if totalAttempt > 2 {
|
||||
return nil, errSniffingTimeout
|
||||
cachingStartingTimeStamp := time.Now()
|
||||
err := cReader.Cache(payload, cacheDeadline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cachingTimeElapsed := time.Since(cachingStartingTimeStamp)
|
||||
cacheDeadline -= cachingTimeElapsed
|
||||
|
||||
cReader.Cache(payload)
|
||||
if !payload.IsEmpty() {
|
||||
result, err := sniffer.Sniff(ctx, payload.Bytes(), network)
|
||||
if err != common.ErrNoClue {
|
||||
switch err {
|
||||
case common.ErrNoClue: // No Clue: protocol not matches, and sniffer cannot determine whether there will be a match or not
|
||||
totalAttempt++
|
||||
case protocol.ErrProtoNeedMoreData: // Protocol Need More Data: protocol matches, but need more data to complete sniffing
|
||||
// in this case, do not add totalAttempt(allow to read until timeout)
|
||||
default:
|
||||
return result, err
|
||||
}
|
||||
} else {
|
||||
totalAttempt++
|
||||
}
|
||||
if payload.IsFull() {
|
||||
return nil, errUnknownContent
|
||||
if totalAttempt >= 2 || cacheDeadline <= 0 {
|
||||
return nil, errSniffingTimeout
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -402,18 +408,6 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
|
||||
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
if hosts, ok := d.dns.(dns.HostsLookup); ok && destination.Address.Family().IsDomain() {
|
||||
proxied := hosts.LookupHosts(ob.Target.String())
|
||||
if proxied != nil {
|
||||
ro := ob.RouteTarget == destination
|
||||
destination.Address = *proxied
|
||||
if ro {
|
||||
ob.RouteTarget = destination
|
||||
} else {
|
||||
ob.Target = destination
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var handler outbound.Handler
|
||||
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/protocol/bittorrent"
|
||||
"github.com/xtls/xray-core/common/protocol/http"
|
||||
"github.com/xtls/xray-core/common/protocol/quic"
|
||||
@@ -58,14 +59,17 @@ var errUnknownContent = errors.New("unknown content")
|
||||
func (s *Sniffer) Sniff(c context.Context, payload []byte, network net.Network) (SniffResult, error) {
|
||||
var pendingSniffer []protocolSnifferWithMetadata
|
||||
for _, si := range s.sniffer {
|
||||
s := si.protocolSniffer
|
||||
protocolSniffer := si.protocolSniffer
|
||||
if si.metadataSniffer || si.network != network {
|
||||
continue
|
||||
}
|
||||
result, err := s(c, payload)
|
||||
result, err := protocolSniffer(c, payload)
|
||||
if err == common.ErrNoClue {
|
||||
pendingSniffer = append(pendingSniffer, si)
|
||||
continue
|
||||
} else if err == protocol.ErrProtoNeedMoreData { // Sniffer protocol matched, but need more data to complete sniffing
|
||||
s.sniffer = []protocolSnifferWithMetadata{si}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err == nil && result != nil {
|
||||
|
188
app/dns/cache_controller.go
Normal file
188
app/dns/cache_controller.go
Normal file
@@ -0,0 +1,188 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
go_errors "errors"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CacheController struct {
|
||||
sync.RWMutex
|
||||
ips map[string]*record
|
||||
pub *pubsub.Service
|
||||
cacheCleanup *task.Periodic
|
||||
name string
|
||||
disableCache bool
|
||||
}
|
||||
|
||||
func NewCacheController(name string, disableCache bool) *CacheController {
|
||||
c := &CacheController{
|
||||
name: name,
|
||||
disableCache: disableCache,
|
||||
ips: make(map[string]*record),
|
||||
pub: pubsub.NewService(),
|
||||
}
|
||||
|
||||
c.cacheCleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
Execute: c.CacheCleanup,
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// CacheCleanup clears expired items from cache
|
||||
func (c *CacheController) CacheCleanup() error {
|
||||
now := time.Now()
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
if len(c.ips) == 0 {
|
||||
return errors.New("nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for domain, record := range c.ips {
|
||||
if record.A != nil && record.A.Expire.Before(now) {
|
||||
record.A = nil
|
||||
}
|
||||
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
||||
record.AAAA = nil
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
errors.LogDebug(context.Background(), c.name, "cache cleanup ", domain)
|
||||
delete(c.ips, domain)
|
||||
} else {
|
||||
c.ips[domain] = record
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.ips) == 0 {
|
||||
c.ips = make(map[string]*record)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CacheController) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
elapsed := time.Since(req.start)
|
||||
|
||||
c.Lock()
|
||||
rec, found := c.ips[req.domain]
|
||||
if !found {
|
||||
rec = &record{}
|
||||
}
|
||||
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
rec.A = ipRec
|
||||
case dnsmessage.TypeAAAA:
|
||||
rec.AAAA = ipRec
|
||||
}
|
||||
|
||||
errors.LogInfo(context.Background(), c.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||
c.ips[req.domain] = rec
|
||||
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
c.pub.Publish(req.domain+"4", nil)
|
||||
if !c.disableCache {
|
||||
_, _, err := rec.AAAA.getIPs()
|
||||
if !go_errors.Is(err, errRecordNotFound) {
|
||||
c.pub.Publish(req.domain+"6", nil)
|
||||
}
|
||||
}
|
||||
case dnsmessage.TypeAAAA:
|
||||
c.pub.Publish(req.domain+"6", nil)
|
||||
if !c.disableCache {
|
||||
_, _, err := rec.A.getIPs()
|
||||
if !go_errors.Is(err, errRecordNotFound) {
|
||||
c.pub.Publish(req.domain+"4", nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.Unlock()
|
||||
common.Must(c.cacheCleanup.Start())
|
||||
}
|
||||
|
||||
func (c *CacheController) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||
c.RLock()
|
||||
record, found := c.ips[domain]
|
||||
c.RUnlock()
|
||||
|
||||
if !found {
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
|
||||
var errs []error
|
||||
var allIPs []net.IP
|
||||
var rTTL uint32 = dns_feature.DefaultTTL
|
||||
|
||||
mergeReq := option.IPv4Enable && option.IPv6Enable
|
||||
|
||||
if option.IPv4Enable {
|
||||
ips, ttl, err := record.A.getIPs()
|
||||
if !mergeReq || go_errors.Is(err, errRecordNotFound) {
|
||||
return ips, ttl, err
|
||||
}
|
||||
if ttl < rTTL {
|
||||
rTTL = ttl
|
||||
}
|
||||
if len(ips) > 0 {
|
||||
allIPs = append(allIPs, ips...)
|
||||
} else {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if option.IPv6Enable {
|
||||
ips, ttl, err := record.AAAA.getIPs()
|
||||
if !mergeReq || go_errors.Is(err, errRecordNotFound) {
|
||||
return ips, ttl, err
|
||||
}
|
||||
if ttl < rTTL {
|
||||
rTTL = ttl
|
||||
}
|
||||
if len(ips) > 0 {
|
||||
allIPs = append(allIPs, ips...)
|
||||
} else {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(allIPs) > 0 {
|
||||
return allIPs, rTTL, nil
|
||||
}
|
||||
if go_errors.Is(errs[0], errs[1]) {
|
||||
return nil, rTTL, errs[0]
|
||||
}
|
||||
return nil, rTTL, errors.Combine(errs...)
|
||||
}
|
||||
|
||||
func (c *CacheController) registerSubscribers(domain string, option dns_feature.IPOption) (sub4 *pubsub.Subscriber, sub6 *pubsub.Subscriber) {
|
||||
// ipv4 and ipv6 belong to different subscription groups
|
||||
if option.IPv4Enable {
|
||||
sub4 = c.pub.Subscribe(domain + "4")
|
||||
}
|
||||
if option.IPv6Enable {
|
||||
sub6 = c.pub.Subscribe(domain + "6")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func closeSubscribers(sub4 *pubsub.Subscriber, sub6 *pubsub.Subscriber) {
|
||||
if sub4 != nil {
|
||||
sub4.Close()
|
||||
}
|
||||
if sub6 != nil {
|
||||
sub6.Close()
|
||||
}
|
||||
}
|
@@ -80,6 +80,7 @@ const (
|
||||
QueryStrategy_USE_IP QueryStrategy = 0
|
||||
QueryStrategy_USE_IP4 QueryStrategy = 1
|
||||
QueryStrategy_USE_IP6 QueryStrategy = 2
|
||||
QueryStrategy_USE_SYS QueryStrategy = 3
|
||||
)
|
||||
|
||||
// Enum value maps for QueryStrategy.
|
||||
@@ -88,11 +89,13 @@ var (
|
||||
0: "USE_IP",
|
||||
1: "USE_IP4",
|
||||
2: "USE_IP6",
|
||||
3: "USE_SYS",
|
||||
}
|
||||
QueryStrategy_value = map[string]int32{
|
||||
"USE_IP": 0,
|
||||
"USE_IP4": 1,
|
||||
"USE_IP6": 2,
|
||||
"USE_SYS": 3,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -128,16 +131,20 @@ type NameServer struct {
|
||||
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"`
|
||||
SkipFallback bool `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"`
|
||||
PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
|
||||
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"`
|
||||
QueryStrategy QueryStrategy `protobuf:"varint,7,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
||||
AllowUnexpectedIPs bool `protobuf:"varint,8,opt,name=allowUnexpectedIPs,proto3" json:"allowUnexpectedIPs,omitempty"`
|
||||
Tag string `protobuf:"bytes,9,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
TimeoutMs uint64 `protobuf:"varint,10,opt,name=timeoutMs,proto3" json:"timeoutMs,omitempty"`
|
||||
Address *net.Endpoint `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
|
||||
ClientIp []byte `protobuf:"bytes,5,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
|
||||
SkipFallback bool `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"`
|
||||
PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
|
||||
ExpectedGeoip []*router.GeoIP `protobuf:"bytes,3,rep,name=expected_geoip,json=expectedGeoip,proto3" json:"expected_geoip,omitempty"`
|
||||
OriginalRules []*NameServer_OriginalRule `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
|
||||
QueryStrategy QueryStrategy `protobuf:"varint,7,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
||||
ActPrior bool `protobuf:"varint,8,opt,name=actPrior,proto3" json:"actPrior,omitempty"`
|
||||
Tag string `protobuf:"bytes,9,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
TimeoutMs uint64 `protobuf:"varint,10,opt,name=timeoutMs,proto3" json:"timeoutMs,omitempty"`
|
||||
DisableCache bool `protobuf:"varint,11,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
|
||||
FinalQuery bool `protobuf:"varint,12,opt,name=finalQuery,proto3" json:"finalQuery,omitempty"`
|
||||
UnexpectedGeoip []*router.GeoIP `protobuf:"bytes,13,rep,name=unexpected_geoip,json=unexpectedGeoip,proto3" json:"unexpected_geoip,omitempty"`
|
||||
ActUnprior bool `protobuf:"varint,14,opt,name=actUnprior,proto3" json:"actUnprior,omitempty"`
|
||||
}
|
||||
|
||||
func (x *NameServer) Reset() {
|
||||
@@ -198,9 +205,9 @@ func (x *NameServer) GetPrioritizedDomain() []*NameServer_PriorityDomain {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *NameServer) GetGeoip() []*router.GeoIP {
|
||||
func (x *NameServer) GetExpectedGeoip() []*router.GeoIP {
|
||||
if x != nil {
|
||||
return x.Geoip
|
||||
return x.ExpectedGeoip
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -219,9 +226,9 @@ func (x *NameServer) GetQueryStrategy() QueryStrategy {
|
||||
return QueryStrategy_USE_IP
|
||||
}
|
||||
|
||||
func (x *NameServer) GetAllowUnexpectedIPs() bool {
|
||||
func (x *NameServer) GetActPrior() bool {
|
||||
if x != nil {
|
||||
return x.AllowUnexpectedIPs
|
||||
return x.ActPrior
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -240,6 +247,34 @@ func (x *NameServer) GetTimeoutMs() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *NameServer) GetDisableCache() bool {
|
||||
if x != nil {
|
||||
return x.DisableCache
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *NameServer) GetFinalQuery() bool {
|
||||
if x != nil {
|
||||
return x.FinalQuery
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *NameServer) GetUnexpectedGeoip() []*router.GeoIP {
|
||||
if x != nil {
|
||||
return x.UnexpectedGeoip
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *NameServer) GetActUnprior() bool {
|
||||
if x != nil {
|
||||
return x.ActUnprior
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -532,7 +567,7 @@ var file_app_dns_config_proto_rawDesc = []byte{
|
||||
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, 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, 0x92, 0x05, 0x0a, 0x0a,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb6, 0x06, 0x0a, 0x0a,
|
||||
0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64,
|
||||
0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e,
|
||||
@@ -546,81 +581,92 @@ var file_app_dns_config_proto_rawDesc = []byte{
|
||||
0x72, 0x61, 0x79, 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, 0x2c, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69,
|
||||
0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52,
|
||||
0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e,
|
||||
0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25,
|
||||
0x2e, 0x78, 0x72, 0x61, 0x79, 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, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74,
|
||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72,
|
||||
0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79,
|
||||
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x2e, 0x0a, 0x12, 0x61, 0x6c, 0x6c, 0x6f,
|
||||
0x77, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x49, 0x50, 0x73, 0x18, 0x08,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x55, 0x6e, 0x65, 0x78, 0x70,
|
||||
0x65, 0x63, 0x74, 0x65, 0x64, 0x49, 0x50, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18,
|
||||
0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69,
|
||||
0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4d, 0x73, 0x1a, 0x5e, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f,
|
||||
0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79,
|
||||
0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 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, 0x9c, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0b, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 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, 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, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x68, 0x6f,
|
||||
0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
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, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69,
|
||||
0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x42,
|
||||
0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||
0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74,
|
||||
0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||
0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c,
|
||||
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x69, 0x73,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x36, 0x0a, 0x16,
|
||||
0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49,
|
||||
0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x64, 0x69,
|
||||
0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d,
|
||||
0x61, 0x74, 0x63, 0x68, 0x1a, 0x92, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70,
|
||||
0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 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, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 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, 0x2a, 0x35, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49,
|
||||
0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x01,
|
||||
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x02, 0x42, 0x46, 0x0a,
|
||||
0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e,
|
||||
0x73, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61,
|
||||
0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70,
|
||||
0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3d, 0x0a, 0x0e, 0x65, 0x78, 0x70, 0x65,
|
||||
0x63, 0x74, 0x65, 0x64, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0d, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74,
|
||||
0x65, 0x64, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69,
|
||||
0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 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, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65,
|
||||
0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72,
|
||||
0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x74,
|
||||
0x50, 0x72, 0x69, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x63, 0x74,
|
||||
0x50, 0x72, 0x69, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x09, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x6f,
|
||||
0x75, 0x74, 0x4d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
|
||||
0x6f, 0x75, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
|
||||
0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6e,
|
||||
0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66,
|
||||
0x69, 0x6e, 0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x41, 0x0a, 0x10, 0x75, 0x6e, 0x65,
|
||||
0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0d, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0f, 0x75, 0x6e, 0x65,
|
||||
0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a,
|
||||
0x61, 0x63, 0x74, 0x55, 0x6e, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x0a, 0x61, 0x63, 0x74, 0x55, 0x6e, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x1a, 0x5e, 0x0a, 0x0e,
|
||||
0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34,
|
||||
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 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, 0x9c, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
||||
0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 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, 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, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69,
|
||||
0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 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, 0x12, 0x22,
|
||||
0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63,
|
||||
0x68, 0x65, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61,
|
||||
0x74, 0x65, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74,
|
||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
|
||||
0x12, 0x36, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62,
|
||||
0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
|
||||
0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x1a, 0x92, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73,
|
||||
0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 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, 0x4a, 0x04, 0x08,
|
||||
0x07, 0x10, 0x08, 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, 0x2a, 0x42, 0x0a, 0x0d, 0x51, 0x75,
|
||||
0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55,
|
||||
0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49,
|
||||
0x50, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10,
|
||||
0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x53, 0x59, 0x53, 0x10, 0x03, 0x42, 0x46,
|
||||
0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64,
|
||||
0x6e, 0x73, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f,
|
||||
0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41,
|
||||
0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -651,19 +697,20 @@ var file_app_dns_config_proto_goTypes = []any{
|
||||
var file_app_dns_config_proto_depIdxs = []int32{
|
||||
7, // 0: xray.app.dns.NameServer.address:type_name -> xray.common.net.Endpoint
|
||||
4, // 1: xray.app.dns.NameServer.prioritized_domain:type_name -> xray.app.dns.NameServer.PriorityDomain
|
||||
8, // 2: xray.app.dns.NameServer.geoip:type_name -> xray.app.router.GeoIP
|
||||
8, // 2: xray.app.dns.NameServer.expected_geoip:type_name -> xray.app.router.GeoIP
|
||||
5, // 3: xray.app.dns.NameServer.original_rules:type_name -> xray.app.dns.NameServer.OriginalRule
|
||||
1, // 4: xray.app.dns.NameServer.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
||||
2, // 5: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer
|
||||
6, // 6: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
||||
1, // 7: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
||||
0, // 8: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
|
||||
0, // 9: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType
|
||||
10, // [10:10] is the sub-list for method output_type
|
||||
10, // [10:10] is the sub-list for method input_type
|
||||
10, // [10:10] is the sub-list for extension type_name
|
||||
10, // [10:10] is the sub-list for extension extendee
|
||||
0, // [0:10] is the sub-list for field type_name
|
||||
8, // 5: xray.app.dns.NameServer.unexpected_geoip:type_name -> xray.app.router.GeoIP
|
||||
2, // 6: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer
|
||||
6, // 7: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
||||
1, // 8: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
||||
0, // 9: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
|
||||
0, // 10: xray.app.dns.Config.HostMapping.type:type_name -> xray.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() }
|
||||
|
@@ -25,12 +25,16 @@ message NameServer {
|
||||
}
|
||||
|
||||
repeated PriorityDomain prioritized_domain = 2;
|
||||
repeated xray.app.router.GeoIP geoip = 3;
|
||||
repeated xray.app.router.GeoIP expected_geoip = 3;
|
||||
repeated OriginalRule original_rules = 4;
|
||||
QueryStrategy query_strategy = 7;
|
||||
bool allowUnexpectedIPs = 8;
|
||||
bool actPrior = 8;
|
||||
string tag = 9;
|
||||
uint64 timeoutMs = 10;
|
||||
bool disableCache = 11;
|
||||
bool finalQuery = 12;
|
||||
repeated xray.app.router.GeoIP unexpected_geoip = 13;
|
||||
bool actUnprior = 14;
|
||||
}
|
||||
|
||||
enum DomainMatchingType {
|
||||
@@ -44,6 +48,7 @@ enum QueryStrategy {
|
||||
USE_IP = 0;
|
||||
USE_IP4 = 1;
|
||||
USE_IP6 = 2;
|
||||
USE_SYS = 3;
|
||||
}
|
||||
|
||||
message Config {
|
||||
|
183
app/dns/dns.go
183
app/dns/dns.go
@@ -3,12 +3,12 @@ package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
go_errors "errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
@@ -20,8 +20,6 @@ import (
|
||||
// DNS is a DNS rely server.
|
||||
type DNS struct {
|
||||
sync.Mutex
|
||||
tag string
|
||||
disableCache bool
|
||||
disableFallback bool
|
||||
disableFallbackIfMatch bool
|
||||
ipOption *dns.IPOption
|
||||
@@ -30,6 +28,7 @@ type DNS struct {
|
||||
ctx context.Context
|
||||
domainMatcher strmatcher.IndexMatcher
|
||||
matcherInfos []*DomainMatcherInfo
|
||||
checkSystem bool
|
||||
}
|
||||
|
||||
// DomainMatcherInfo contains information attached to index returned by Server.domainMatcher
|
||||
@@ -40,13 +39,6 @@ type DomainMatcherInfo struct {
|
||||
|
||||
// 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:
|
||||
@@ -55,26 +47,36 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
return nil, errors.New("unexpected client IP length ", len(config.ClientIp))
|
||||
}
|
||||
|
||||
var ipOption *dns.IPOption
|
||||
var ipOption dns.IPOption
|
||||
checkSystem := false
|
||||
switch config.QueryStrategy {
|
||||
case QueryStrategy_USE_IP:
|
||||
ipOption = &dns.IPOption{
|
||||
ipOption = dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
}
|
||||
case QueryStrategy_USE_SYS:
|
||||
ipOption = dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
}
|
||||
checkSystem = true
|
||||
case QueryStrategy_USE_IP4:
|
||||
ipOption = &dns.IPOption{
|
||||
ipOption = dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: false,
|
||||
FakeEnable: false,
|
||||
}
|
||||
case QueryStrategy_USE_IP6:
|
||||
ipOption = &dns.IPOption{
|
||||
ipOption = dns.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("unexpected query strategy ", config.QueryStrategy)
|
||||
}
|
||||
|
||||
hosts, err := NewStaticHosts(config.StaticHosts)
|
||||
@@ -82,8 +84,14 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
return nil, errors.New("failed to create hosts").Base(err)
|
||||
}
|
||||
|
||||
clients := []*Client{}
|
||||
var clients []*Client
|
||||
domainRuleCount := 0
|
||||
|
||||
var defaultTag = config.Tag
|
||||
if len(config.Tag) == 0 {
|
||||
defaultTag = generateRandomTag()
|
||||
}
|
||||
|
||||
for _, ns := range config.NameServer {
|
||||
domainRuleCount += len(ns.PrioritizedDomain)
|
||||
}
|
||||
@@ -91,7 +99,6 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
// MatcherInfos is ensured to cover the maximum index domainMatcher could return, where matcher's index starts from 1
|
||||
matcherInfos := make([]*DomainMatcherInfo, domainRuleCount+1)
|
||||
domainMatcher := &strmatcher.MatcherGroup{}
|
||||
geoipContainer := router.GeoIPMatcherContainer{}
|
||||
|
||||
for _, ns := range config.NameServer {
|
||||
clientIdx := len(clients)
|
||||
@@ -109,7 +116,19 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
case net.IPv4len, net.IPv6len:
|
||||
myClientIP = net.IP(ns.ClientIp)
|
||||
}
|
||||
client, err := NewClient(ctx, ns, myClientIP, geoipContainer, &matcherInfos, updateDomain)
|
||||
|
||||
disableCache := config.DisableCache || ns.DisableCache
|
||||
|
||||
var tag = defaultTag
|
||||
if len(ns.Tag) > 0 {
|
||||
tag = ns.Tag
|
||||
}
|
||||
clientIPOption := ResolveIpOptionOverride(ns.QueryStrategy, ipOption)
|
||||
if !clientIPOption.IPv4Enable && !clientIPOption.IPv6Enable {
|
||||
return nil, errors.New("no QueryStrategy available for ", ns.Address)
|
||||
}
|
||||
|
||||
client, err := NewClient(ctx, ns, myClientIP, disableCache, tag, clientIPOption, &matcherInfos, updateDomain)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to create client").Base(err)
|
||||
}
|
||||
@@ -118,20 +137,19 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
|
||||
// If there is no DNS client in config, add a `localhost` DNS client
|
||||
if len(clients) == 0 {
|
||||
clients = append(clients, NewLocalDNSClient())
|
||||
clients = append(clients, NewLocalDNSClient(ipOption))
|
||||
}
|
||||
|
||||
return &DNS{
|
||||
tag: tag,
|
||||
hosts: hosts,
|
||||
ipOption: ipOption,
|
||||
ipOption: &ipOption,
|
||||
clients: clients,
|
||||
ctx: ctx,
|
||||
domainMatcher: domainMatcher,
|
||||
matcherInfos: matcherInfos,
|
||||
disableCache: config.DisableCache,
|
||||
disableFallback: config.DisableFallback,
|
||||
disableFallbackIfMatch: config.DisableFallbackIfMatch,
|
||||
checkSystem: checkSystem,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -153,27 +171,45 @@ func (s *DNS) Close() error {
|
||||
// IsOwnLink implements proxy.dns.ownLinkVerifier
|
||||
func (s *DNS) IsOwnLink(ctx context.Context) bool {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
return inbound != nil && inbound.Tag == s.tag
|
||||
if inbound == nil {
|
||||
return false
|
||||
}
|
||||
for _, client := range s.clients {
|
||||
if client.tag == inbound.Tag {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// LookupIP implements dns.Client.
|
||||
func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
||||
// Normalize the FQDN form query
|
||||
domain = strings.TrimSuffix(domain, ".")
|
||||
if domain == "" {
|
||||
return nil, 0, errors.New("empty domain name")
|
||||
}
|
||||
|
||||
option.IPv4Enable = option.IPv4Enable && s.ipOption.IPv4Enable
|
||||
option.IPv6Enable = option.IPv6Enable && s.ipOption.IPv6Enable
|
||||
if s.checkSystem {
|
||||
supportIPv4, supportIPv6 := checkSystemNetwork()
|
||||
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
||||
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
||||
} else {
|
||||
option.IPv4Enable = option.IPv4Enable && s.ipOption.IPv4Enable
|
||||
option.IPv6Enable = option.IPv6Enable && s.ipOption.IPv6Enable
|
||||
}
|
||||
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
}
|
||||
|
||||
// Normalize the FQDN form query
|
||||
domain = strings.TrimSuffix(domain, ".")
|
||||
|
||||
// Static host lookup
|
||||
switch addrs := s.hosts.Lookup(domain, option); {
|
||||
switch addrs, err := s.hosts.Lookup(domain, option); {
|
||||
case err != nil:
|
||||
if go_errors.Is(err, dns.ErrEmptyResponse) {
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
}
|
||||
return nil, 0, errors.New("returning nil for domain ", domain).Base(err)
|
||||
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)
|
||||
@@ -184,64 +220,52 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, er
|
||||
default: // Successfully found ip records in static host
|
||||
errors.LogInfo(s.ctx, "returning ", len(addrs), " IP(s) for domain ", domain, " -> ", addrs)
|
||||
ips, err := toNetIP(addrs)
|
||||
return ips, 10, err // Hosts ttl is 10
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return ips, 10, nil // Hosts ttl is 10
|
||||
}
|
||||
|
||||
// Name servers lookup
|
||||
errs := []error{}
|
||||
ctx := session.ContextWithInbound(s.ctx, &session.Inbound{Tag: s.tag})
|
||||
var errs []error
|
||||
for _, client := range s.sortClients(domain) {
|
||||
if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
|
||||
errors.LogDebug(s.ctx, "skip DNS resolution for domain ", domain, " at server ", client.Name())
|
||||
continue
|
||||
}
|
||||
ips, ttl, err := client.QueryIP(ctx, domain, option, s.disableCache)
|
||||
|
||||
ips, ttl, err := client.QueryIP(s.ctx, domain, option)
|
||||
|
||||
if len(ips) > 0 {
|
||||
if ttl == 0 {
|
||||
ttl = 1
|
||||
}
|
||||
return ips, ttl, nil
|
||||
}
|
||||
if err != nil {
|
||||
errors.LogInfoInner(s.ctx, err, "failed to lookup ip for domain ", domain, " at server ", client.Name())
|
||||
errs = append(errs, err)
|
||||
|
||||
errors.LogInfoInner(s.ctx, err, "failed to lookup ip for domain ", domain, " at server ", client.Name())
|
||||
if err == nil {
|
||||
err = dns.ErrEmptyResponse
|
||||
}
|
||||
// 5 for RcodeRefused in miekg/dns, hardcode to reduce binary size
|
||||
if err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch && err != dns.ErrEmptyResponse && dns.RCodeFromError(err) != 5 {
|
||||
return nil, 0, err
|
||||
errs = append(errs, err)
|
||||
|
||||
if client.IsFinalQuery() {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil, 0, errors.New("returning nil for domain ", domain).Base(errors.Combine(errs...))
|
||||
}
|
||||
|
||||
// LookupHosts implements dns.HostsLookup.
|
||||
func (s *DNS) LookupHosts(domain string) *net.Address {
|
||||
domain = strings.TrimSuffix(domain, ".")
|
||||
if domain == "" {
|
||||
return nil
|
||||
if len(errs) > 0 {
|
||||
allErrs := errors.Combine(errs...)
|
||||
err0 := errs[0]
|
||||
if errors.AllEqual(err0, allErrs) {
|
||||
if go_errors.Is(err0, dns.ErrEmptyResponse) {
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
}
|
||||
return nil, 0, errors.New("returning nil for domain ", domain).Base(err0)
|
||||
}
|
||||
return nil, 0, errors.New("returning nil for domain ", domain).Base(allErrs)
|
||||
}
|
||||
// Normalize the FQDN form query
|
||||
addrs := s.hosts.Lookup(domain, *s.ipOption)
|
||||
if len(addrs) > 0 {
|
||||
errors.LogInfo(s.ctx, "domain replaced: ", domain, " -> ", addrs[0].String())
|
||||
return &addrs[0]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetIPOption implements ClientWithIPOption.
|
||||
func (s *DNS) GetIPOption() *dns.IPOption {
|
||||
return s.ipOption
|
||||
}
|
||||
|
||||
// SetQueryOption implements ClientWithIPOption.
|
||||
func (s *DNS) SetQueryOption(isIPv4Enable, isIPv6Enable bool) {
|
||||
s.ipOption.IPv4Enable = isIPv4Enable
|
||||
s.ipOption.IPv6Enable = isIPv6Enable
|
||||
}
|
||||
|
||||
// SetFakeDNSOption implements ClientWithIPOption.
|
||||
func (s *DNS) SetFakeDNSOption(isFakeEnable bool) {
|
||||
s.ipOption.FakeEnable = isFakeEnable
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
}
|
||||
|
||||
func (s *DNS) sortClients(domain string) []*Client {
|
||||
@@ -303,3 +327,22 @@ func init() {
|
||||
return New(ctx, config.(*Config))
|
||||
}))
|
||||
}
|
||||
|
||||
func checkSystemNetwork() (supportIPv4 bool, supportIPv6 bool) {
|
||||
conn4, err4 := net.Dial("udp4", "8.8.8.8:53")
|
||||
if err4 != nil {
|
||||
supportIPv4 = false
|
||||
} else {
|
||||
supportIPv4 = true
|
||||
conn4.Close()
|
||||
}
|
||||
|
||||
conn6, err6 := net.Dial("udp6", "[2001:4860:4860::8888]:53")
|
||||
if err6 != nil {
|
||||
supportIPv6 = false
|
||||
} else {
|
||||
supportIPv6 = true
|
||||
conn6.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@@ -76,6 +76,9 @@ func (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
||||
case q.Name == "notexist.google.com." && q.Qtype == dns.TypeAAAA:
|
||||
ans.MsgHdr.Rcode = dns.RcodeNameError
|
||||
|
||||
case q.Name == "notexist.google.com." && q.Qtype == dns.TypeA:
|
||||
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)
|
||||
@@ -117,7 +120,6 @@ func TestUDPServerSubnet(t *testing.T) {
|
||||
Handler: &staticHandler{},
|
||||
UDPSize: 1200,
|
||||
}
|
||||
|
||||
go dnsServer.ListenAndServe()
|
||||
time.Sleep(time.Second)
|
||||
|
||||
@@ -537,7 +539,7 @@ func TestIPMatch(t *testing.T) {
|
||||
},
|
||||
Port: uint32(port),
|
||||
},
|
||||
Geoip: []*router.GeoIP{
|
||||
ExpectedGeoip: []*router.GeoIP{
|
||||
{
|
||||
CountryCode: "local",
|
||||
Cidr: []*router.CIDR{
|
||||
@@ -561,7 +563,7 @@ func TestIPMatch(t *testing.T) {
|
||||
},
|
||||
Port: uint32(port),
|
||||
},
|
||||
Geoip: []*router.GeoIP{
|
||||
ExpectedGeoip: []*router.GeoIP{
|
||||
{
|
||||
CountryCode: "test",
|
||||
Cidr: []*router.CIDR{
|
||||
@@ -665,7 +667,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
// Equivalent of dotless:localhost
|
||||
{Type: DomainMatchingType_Regex, Domain: "^[^.]*localhost[^.]*$"},
|
||||
},
|
||||
Geoip: []*router.GeoIP{
|
||||
ExpectedGeoip: []*router.GeoIP{
|
||||
{ // Will match localhost, localhost-a and localhost-b,
|
||||
CountryCode: "local",
|
||||
Cidr: []*router.CIDR{
|
||||
@@ -895,7 +897,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
Domain: "google.com",
|
||||
},
|
||||
},
|
||||
Geoip: []*router.GeoIP{
|
||||
ExpectedGeoip: []*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},
|
||||
@@ -920,7 +922,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
Domain: "google.com",
|
||||
},
|
||||
},
|
||||
Geoip: []*router.GeoIP{
|
||||
ExpectedGeoip: []*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},
|
||||
@@ -944,7 +946,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
Domain: "api.google.com",
|
||||
},
|
||||
},
|
||||
Geoip: []*router.GeoIP{
|
||||
ExpectedGeoip: []*router.GeoIP{
|
||||
{ // Will only match 8.8.7.7 (api.google.com)
|
||||
Cidr: []*router.CIDR{
|
||||
{Ip: []byte{8, 8, 7, 7}, Prefix: 32},
|
||||
@@ -968,7 +970,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
Domain: "v2.api.google.com",
|
||||
},
|
||||
},
|
||||
Geoip: []*router.GeoIP{
|
||||
ExpectedGeoip: []*router.GeoIP{
|
||||
{ // Will only match 8.8.7.8 (v2.api.google.com)
|
||||
Cidr: []*router.CIDR{
|
||||
{Ip: []byte{8, 8, 7, 8}, Prefix: 32},
|
||||
|
@@ -32,31 +32,30 @@ type record struct {
|
||||
// IPRecord is a cacheable item for a resolved domain
|
||||
type IPRecord struct {
|
||||
ReqID uint16
|
||||
IP []net.Address
|
||||
IP []net.IP
|
||||
Expire time.Time
|
||||
RCode dnsmessage.RCode
|
||||
RawHeader *dnsmessage.Header
|
||||
}
|
||||
|
||||
func (r *IPRecord) getIPs() ([]net.Address, uint32, error) {
|
||||
if r == nil || r.Expire.Before(time.Now()) {
|
||||
func (r *IPRecord) getIPs() ([]net.IP, uint32, error) {
|
||||
if r == nil {
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
if r.RCode != dnsmessage.RCodeSuccess {
|
||||
return nil, 0, dns_feature.RCodeError(r.RCode)
|
||||
untilExpire := time.Until(r.Expire)
|
||||
if untilExpire <= 0 {
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
ttl := uint32(time.Until(r.Expire) / time.Second)
|
||||
return r.IP, ttl, nil
|
||||
}
|
||||
|
||||
func isNewer(baseRec *IPRecord, newRec *IPRecord) bool {
|
||||
if newRec == nil {
|
||||
return false
|
||||
ttl := uint32(untilExpire/time.Second) + uint32(1)
|
||||
if r.RCode != dnsmessage.RCodeSuccess {
|
||||
return nil, ttl, dns_feature.RCodeError(r.RCode)
|
||||
}
|
||||
if baseRec == nil {
|
||||
return true
|
||||
if len(r.IP) == 0 {
|
||||
return nil, ttl, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
return baseRec.Expire.Before(newRec.Expire)
|
||||
|
||||
return r.IP, ttl, nil
|
||||
}
|
||||
|
||||
var errRecordNotFound = errors.New("record not found")
|
||||
@@ -193,7 +192,7 @@ func parseResponse(payload []byte) (*IPRecord, error) {
|
||||
ipRecord := &IPRecord{
|
||||
ReqID: h.ID,
|
||||
RCode: h.RCode,
|
||||
Expire: now.Add(time.Second * 600),
|
||||
Expire: now.Add(time.Second * dns_feature.DefaultTTL),
|
||||
RawHeader: &h,
|
||||
}
|
||||
|
||||
@@ -209,7 +208,7 @@ L:
|
||||
|
||||
ttl := ah.TTL
|
||||
if ttl == 0 {
|
||||
ttl = 600
|
||||
ttl = 1
|
||||
}
|
||||
expire := now.Add(time.Duration(ttl) * time.Second)
|
||||
if ipRecord.Expire.After(expire) {
|
||||
@@ -223,14 +222,17 @@ L:
|
||||
errors.LogInfoInner(context.Background(), err, "failed to parse A record for domain: ", ah.Name)
|
||||
break L
|
||||
}
|
||||
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.A[:]))
|
||||
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.A[:]).IP())
|
||||
case dnsmessage.TypeAAAA:
|
||||
ans, err := parser.AAAAResource()
|
||||
if err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "failed to parse AAAA record for domain: ", ah.Name)
|
||||
break L
|
||||
}
|
||||
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.AAAA[:]))
|
||||
newIP := net.IPAddress(ans.AAAA[:]).IP()
|
||||
if len(newIP) == net.IPv6len {
|
||||
ipRecord.IP = append(ipRecord.IP, newIP)
|
||||
}
|
||||
default:
|
||||
if err := parser.SkipAnswer(); err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "failed to skip answer")
|
||||
|
@@ -18,31 +18,31 @@ func Test_parseResponse(t *testing.T) {
|
||||
|
||||
ans := new(dns.Msg)
|
||||
ans.Id = 0
|
||||
p = append(p, common.Must2(ans.Pack()).([]byte))
|
||||
p = append(p, common.Must2(ans.Pack()))
|
||||
|
||||
p = append(p, []byte{})
|
||||
|
||||
ans = new(dns.Msg)
|
||||
ans.Id = 1
|
||||
ans.Answer = append(ans.Answer,
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN A 8.8.8.8")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN A 8.8.4.4")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")),
|
||||
common.Must2(dns.NewRR("google.com. IN A 8.8.8.8")),
|
||||
common.Must2(dns.NewRR("google.com. IN A 8.8.4.4")),
|
||||
)
|
||||
p = append(p, common.Must2(ans.Pack()).([]byte))
|
||||
p = append(p, common.Must2(ans.Pack()))
|
||||
|
||||
ans = new(dns.Msg)
|
||||
ans.Id = 2
|
||||
ans.Answer = append(ans.Answer,
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME test.google.com")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8888")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8844")).(dns.RR),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
|
||||
common.Must2(dns.NewRR("google.com. IN CNAME test.google.com")),
|
||||
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8888")),
|
||||
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8844")),
|
||||
)
|
||||
p = append(p, common.Must2(ans.Pack()).([]byte))
|
||||
p = append(p, common.Must2(ans.Pack()))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -51,7 +51,7 @@ func Test_parseResponse(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
"empty",
|
||||
&IPRecord{0, []net.Address(nil), time.Time{}, dnsmessage.RCodeSuccess, nil},
|
||||
&IPRecord{0, []net.IP(nil), time.Time{}, dnsmessage.RCodeSuccess, nil},
|
||||
false,
|
||||
},
|
||||
{
|
||||
@@ -63,7 +63,7 @@ func Test_parseResponse(t *testing.T) {
|
||||
"a record",
|
||||
&IPRecord{
|
||||
1,
|
||||
[]net.Address{net.ParseAddress("8.8.8.8"), net.ParseAddress("8.8.4.4")},
|
||||
[]net.IP{net.ParseIP("8.8.8.8"), net.ParseIP("8.8.4.4")},
|
||||
time.Time{},
|
||||
dnsmessage.RCodeSuccess,
|
||||
nil,
|
||||
@@ -72,7 +72,7 @@ func Test_parseResponse(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"aaaa record",
|
||||
&IPRecord{2, []net.Address{net.ParseAddress("2001::123:8888"), net.ParseAddress("2001::123:8844")}, time.Time{}, dnsmessage.RCodeSuccess, nil},
|
||||
&IPRecord{2, []net.IP{net.ParseIP("2001::123:8888"), net.ParseIP("2001::123:8844")}, time.Time{}, dnsmessage.RCodeSuccess, nil},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
@@ -32,7 +33,15 @@ func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
|
||||
ips := make([]net.Address, 0, len(mapping.Ip)+1)
|
||||
switch {
|
||||
case len(mapping.ProxiedDomain) > 0:
|
||||
ips = append(ips, net.DomainAddress(mapping.ProxiedDomain))
|
||||
if mapping.ProxiedDomain[0] == '#' {
|
||||
rcode, err := strconv.Atoi(mapping.ProxiedDomain[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ips = append(ips, dns.RCodeError(rcode))
|
||||
} else {
|
||||
ips = append(ips, net.DomainAddress(mapping.ProxiedDomain))
|
||||
}
|
||||
case len(mapping.Ip) > 0:
|
||||
for _, ip := range mapping.Ip {
|
||||
addr := net.IPAddress(ip)
|
||||
@@ -41,8 +50,6 @@ func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
|
||||
}
|
||||
ips = append(ips, addr)
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("neither IP address nor proxied domain specified for domain: ", mapping.Domain).AtWarning()
|
||||
}
|
||||
|
||||
sh.ips[id] = ips
|
||||
@@ -61,33 +68,51 @@ func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
|
||||
return filtered
|
||||
}
|
||||
|
||||
func (h *StaticHosts) lookupInternal(domain string) []net.Address {
|
||||
var ips []net.Address
|
||||
func (h *StaticHosts) lookupInternal(domain string) ([]net.Address, error) {
|
||||
ips := make([]net.Address, 0)
|
||||
found := false
|
||||
for _, id := range h.matchers.Match(domain) {
|
||||
for _, v := range h.ips[id] {
|
||||
if err, ok := v.(dns.RCodeError); ok {
|
||||
if uint16(err) == 0 {
|
||||
return nil, dns.ErrEmptyResponse
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ips = append(ips, h.ips[id]...)
|
||||
found = true
|
||||
}
|
||||
return ips
|
||||
if !found {
|
||||
return nil, nil
|
||||
}
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) []net.Address {
|
||||
switch addrs := h.lookupInternal(domain); {
|
||||
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) ([]net.Address, error) {
|
||||
switch addrs, err := h.lookupInternal(domain); {
|
||||
case err != nil:
|
||||
return nil, err
|
||||
case len(addrs) == 0: // Not recorded in static hosts, return nil
|
||||
return nil
|
||||
return addrs, nil
|
||||
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Try to unwrap domain
|
||||
errors.LogDebug(context.Background(), "found replaced domain: ", domain, " -> ", addrs[0].Domain(), ". Try to unwrap it")
|
||||
if maxDepth > 0 {
|
||||
unwrapped := h.lookup(addrs[0].Domain(), option, maxDepth-1)
|
||||
unwrapped, err := h.lookup(addrs[0].Domain(), option, maxDepth-1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if unwrapped != nil {
|
||||
return unwrapped
|
||||
return unwrapped, nil
|
||||
}
|
||||
}
|
||||
return addrs
|
||||
return addrs, nil
|
||||
default: // IP record found, return a non-nil IP array
|
||||
return filterIP(addrs, option)
|
||||
return filterIP(addrs, option), nil
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup returns IP addresses or proxied domain for the given domain, if exists in this StaticHosts.
|
||||
func (h *StaticHosts) Lookup(domain string, option dns.IPOption) []net.Address {
|
||||
func (h *StaticHosts) Lookup(domain string, option dns.IPOption) ([]net.Address, error) {
|
||||
return h.lookup(domain, option, 5)
|
||||
}
|
||||
|
@@ -12,6 +12,11 @@ import (
|
||||
|
||||
func TestStaticHosts(t *testing.T) {
|
||||
pb := []*Config_HostMapping{
|
||||
{
|
||||
Type: DomainMatchingType_Subdomain,
|
||||
Domain: "lan",
|
||||
ProxiedDomain: "#3",
|
||||
},
|
||||
{
|
||||
Type: DomainMatchingType_Full,
|
||||
Domain: "example.com",
|
||||
@@ -54,7 +59,14 @@ func TestStaticHosts(t *testing.T) {
|
||||
common.Must(err)
|
||||
|
||||
{
|
||||
ips := hosts.Lookup("example.com", dns.IPOption{
|
||||
_, err := hosts.Lookup("example.com.lan", dns.IPOption{})
|
||||
if dns.RCodeFromError(err) != 3 {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ips, _ := hosts.Lookup("example.com", dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
@@ -67,7 +79,7 @@ func TestStaticHosts(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
domain := hosts.Lookup("proxy.xray.com", dns.IPOption{
|
||||
domain, _ := hosts.Lookup("proxy.xray.com", dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: false,
|
||||
})
|
||||
@@ -80,7 +92,7 @@ func TestStaticHosts(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
domain := hosts.Lookup("proxy2.xray.com", dns.IPOption{
|
||||
domain, _ := hosts.Lookup("proxy2.xray.com", dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: false,
|
||||
})
|
||||
@@ -93,7 +105,7 @@ func TestStaticHosts(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
ips := hosts.Lookup("www.example.cn", dns.IPOption{
|
||||
ips, _ := hosts.Lookup("www.example.cn", dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
@@ -106,7 +118,7 @@ func TestStaticHosts(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
ips := hosts.Lookup("baidu.com", dns.IPOption{
|
||||
ips, _ := hosts.Lookup("baidu.com", dns.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
|
@@ -21,25 +21,27 @@ 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 dns.IPOption, disableCache bool) ([]net.IP, uint32, error)
|
||||
QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, uint32, error)
|
||||
}
|
||||
|
||||
// Client is the interface for DNS client.
|
||||
type Client struct {
|
||||
server Server
|
||||
clientIP net.IP
|
||||
skipFallback bool
|
||||
domains []string
|
||||
expectedIPs []*router.GeoIPMatcher
|
||||
allowUnexpectedIPs bool
|
||||
tag string
|
||||
timeoutMs time.Duration
|
||||
server Server
|
||||
skipFallback bool
|
||||
domains []string
|
||||
expectedIPs []*router.GeoIPMatcher
|
||||
unexpectedIPs []*router.GeoIPMatcher
|
||||
actPrior bool
|
||||
actUnprior bool
|
||||
tag string
|
||||
timeoutMs time.Duration
|
||||
finalQuery bool
|
||||
ipOption *dns.IPOption
|
||||
checkSystem bool
|
||||
}
|
||||
|
||||
var errExpectedIPNonMatch = errors.New("expectedIPs not match")
|
||||
|
||||
// NewServer creates a name server object according to the network destination url.
|
||||
func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (Server, error) {
|
||||
func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dispatcher, disableCache bool, clientIP net.IP) (Server, error) {
|
||||
if address := dest.Address; address.Family().IsDomain() {
|
||||
u, err := url.Parse(address.Domain())
|
||||
if err != nil {
|
||||
@@ -47,26 +49,29 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis
|
||||
}
|
||||
switch {
|
||||
case strings.EqualFold(u.String(), "localhost"):
|
||||
return NewLocalNameServer(queryStrategy), nil
|
||||
return NewLocalNameServer(), nil
|
||||
case strings.EqualFold(u.Scheme, "https"): // DNS-over-HTTPS Remote mode
|
||||
return NewDoHNameServer(u, queryStrategy, dispatcher, false), nil
|
||||
return NewDoHNameServer(u, dispatcher, false, disableCache, clientIP), nil
|
||||
case strings.EqualFold(u.Scheme, "h2c"): // DNS-over-HTTPS h2c Remote mode
|
||||
return NewDoHNameServer(u, queryStrategy, dispatcher, true), nil
|
||||
return NewDoHNameServer(u, dispatcher, true, disableCache, clientIP), nil
|
||||
case strings.EqualFold(u.Scheme, "https+local"): // DNS-over-HTTPS Local mode
|
||||
return NewDoHNameServer(u, queryStrategy, nil, false), nil
|
||||
return NewDoHNameServer(u, nil, false, disableCache, clientIP), nil
|
||||
case strings.EqualFold(u.Scheme, "h2c+local"): // DNS-over-HTTPS h2c Local mode
|
||||
return NewDoHNameServer(u, queryStrategy, nil, true), nil
|
||||
return NewDoHNameServer(u, nil, true, disableCache, clientIP), nil
|
||||
case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode
|
||||
return NewQUICNameServer(u, queryStrategy)
|
||||
return NewQUICNameServer(u, disableCache, clientIP)
|
||||
case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode
|
||||
return NewTCPNameServer(u, dispatcher, queryStrategy)
|
||||
return NewTCPNameServer(u, dispatcher, disableCache, clientIP)
|
||||
case strings.EqualFold(u.Scheme, "tcp+local"): // DNS-over-TCP Local mode
|
||||
return NewTCPLocalNameServer(u, queryStrategy)
|
||||
return NewTCPLocalNameServer(u, disableCache, clientIP)
|
||||
case strings.EqualFold(u.String(), "fakedns"):
|
||||
var fd dns.FakeDNSEngine
|
||||
core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||
err = core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||
fd = fdns
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewFakeDNSServer(fd), nil
|
||||
}
|
||||
}
|
||||
@@ -74,7 +79,7 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis
|
||||
dest.Network = net.Network_UDP
|
||||
}
|
||||
if dest.Network == net.Network_UDP { // UDP classic DNS mode
|
||||
return NewClassicNameServer(dest, dispatcher, queryStrategy), nil
|
||||
return NewClassicNameServer(dest, dispatcher, disableCache, clientIP), nil
|
||||
}
|
||||
return nil, errors.New("No available name server could be created from ", dest).AtWarning()
|
||||
}
|
||||
@@ -84,7 +89,9 @@ func NewClient(
|
||||
ctx context.Context,
|
||||
ns *NameServer,
|
||||
clientIP net.IP,
|
||||
container router.GeoIPMatcherContainer,
|
||||
disableCache bool,
|
||||
tag string,
|
||||
ipOption dns.IPOption,
|
||||
matcherInfos *[]*DomainMatcherInfo,
|
||||
updateDomainRule func(strmatcher.Matcher, int, []*DomainMatcherInfo) error,
|
||||
) (*Client, error) {
|
||||
@@ -92,7 +99,7 @@ func NewClient(
|
||||
|
||||
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
|
||||
// Create a new server for each client for now
|
||||
server, err := NewServer(ctx, ns.Address.AsDestination(), dispatcher, ns.GetQueryStrategy())
|
||||
server, err := NewServer(ctx, ns.Address.AsDestination(), dispatcher, disableCache, clientIP)
|
||||
if err != nil {
|
||||
return errors.New("failed to create nameserver").Base(err).AtWarning()
|
||||
}
|
||||
@@ -147,13 +154,23 @@ func NewClient(
|
||||
}
|
||||
|
||||
// Establish expected IPs
|
||||
var matchers []*router.GeoIPMatcher
|
||||
for _, geoip := range ns.Geoip {
|
||||
matcher, err := container.Add(geoip)
|
||||
var expectedMatchers []*router.GeoIPMatcher
|
||||
for _, geoip := range ns.ExpectedGeoip {
|
||||
matcher, err := router.GlobalGeoIPContainer.Add(geoip)
|
||||
if err != nil {
|
||||
return errors.New("failed to create ip matcher").Base(err).AtWarning()
|
||||
return errors.New("failed to create expected ip matcher").Base(err).AtWarning()
|
||||
}
|
||||
matchers = append(matchers, matcher)
|
||||
expectedMatchers = append(expectedMatchers, matcher)
|
||||
}
|
||||
|
||||
// Establish unexpected IPs
|
||||
var unexpectedMatchers []*router.GeoIPMatcher
|
||||
for _, geoip := range ns.UnexpectedGeoip {
|
||||
matcher, err := router.GlobalGeoIPContainer.Add(geoip)
|
||||
if err != nil {
|
||||
return errors.New("failed to create unexpected ip matcher").Base(err).AtWarning()
|
||||
}
|
||||
unexpectedMatchers = append(unexpectedMatchers, matcher)
|
||||
}
|
||||
|
||||
if len(clientIP) > 0 {
|
||||
@@ -161,7 +178,7 @@ func NewClient(
|
||||
case *net.IPOrDomain_Domain:
|
||||
errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetDomain(), " uses clientIP ", clientIP.String())
|
||||
case *net.IPOrDomain_Ip:
|
||||
errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetIp(), " uses clientIP ", clientIP.String())
|
||||
errors.LogInfo(ctx, "DNS: client ", net.IP(ns.Address.Address.GetIp()), " uses clientIP ", clientIP.String())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,15 +186,21 @@ func NewClient(
|
||||
if ns.TimeoutMs > 0 {
|
||||
timeoutMs = time.Duration(ns.TimeoutMs) * time.Millisecond
|
||||
}
|
||||
|
||||
|
||||
checkSystem := ns.QueryStrategy == QueryStrategy_USE_SYS
|
||||
|
||||
client.server = server
|
||||
client.clientIP = clientIP
|
||||
client.skipFallback = ns.SkipFallback
|
||||
client.domains = rules
|
||||
client.expectedIPs = matchers
|
||||
client.allowUnexpectedIPs = ns.AllowUnexpectedIPs
|
||||
client.tag = ns.Tag
|
||||
client.expectedIPs = expectedMatchers
|
||||
client.unexpectedIPs = unexpectedMatchers
|
||||
client.actPrior = ns.ActPrior
|
||||
client.actUnprior = ns.ActUnprior
|
||||
client.tag = tag
|
||||
client.timeoutMs = timeoutMs
|
||||
client.finalQuery = ns.FinalQuery
|
||||
client.ipOption = &ipOption
|
||||
client.checkSystem = checkSystem
|
||||
return nil
|
||||
})
|
||||
return client, err
|
||||
@@ -188,54 +211,79 @@ func (c *Client) Name() string {
|
||||
return c.server.Name()
|
||||
}
|
||||
|
||||
func (c *Client) IsFinalQuery() bool {
|
||||
return c.finalQuery
|
||||
}
|
||||
|
||||
// QueryIP sends DNS query to the name server with the client's IP.
|
||||
func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption, disableCache bool) ([]net.IP, uint32, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.timeoutMs)
|
||||
if len(c.tag) != 0 {
|
||||
content := session.InboundFromContext(ctx)
|
||||
errors.LogDebug(ctx, "DNS: client override tag from ", content.Tag, " to ", c.tag)
|
||||
// create a new context to override the tag
|
||||
// do not direct set *content.Tag, it might be used by other clients
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{Tag: c.tag})
|
||||
func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
||||
if c.checkSystem {
|
||||
supportIPv4, supportIPv6 := checkSystemNetwork()
|
||||
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
||||
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
||||
} else {
|
||||
option.IPv4Enable = option.IPv4Enable && c.ipOption.IPv4Enable
|
||||
option.IPv6Enable = option.IPv6Enable && c.ipOption.IPv6Enable
|
||||
}
|
||||
ips, ttl, err := c.server.QueryIP(ctx, domain, c.clientIP, option, disableCache)
|
||||
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, c.timeoutMs)
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{Tag: c.tag})
|
||||
ips, ttl, err := c.server.QueryIP(ctx, domain, option)
|
||||
cancel()
|
||||
|
||||
if err != nil {
|
||||
return ips, ttl, err
|
||||
return nil, 0, err
|
||||
}
|
||||
netips, err := c.MatchExpectedIPs(domain, ips)
|
||||
return netips, ttl, err
|
||||
}
|
||||
|
||||
// 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.expectedIPs) == 0 {
|
||||
return ips, nil
|
||||
if len(ips) == 0 {
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
}
|
||||
newIps := []net.IP{}
|
||||
for _, ip := range ips {
|
||||
for _, matcher := range c.expectedIPs {
|
||||
if matcher.Match(ip) {
|
||||
newIps = append(newIps, ip)
|
||||
break
|
||||
}
|
||||
|
||||
if len(c.expectedIPs) > 0 && !c.actPrior {
|
||||
ips = router.MatchIPs(c.expectedIPs, ips, false)
|
||||
errors.LogDebug(context.Background(), "domain ", domain, " expectedIPs ", ips, " matched at server ", c.Name())
|
||||
if len(ips) == 0 {
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
}
|
||||
}
|
||||
if len(newIps) == 0 {
|
||||
if c.allowUnexpectedIPs {
|
||||
return ips, nil
|
||||
|
||||
if len(c.unexpectedIPs) > 0 && !c.actUnprior {
|
||||
ips = router.MatchIPs(c.unexpectedIPs, ips, true)
|
||||
errors.LogDebug(context.Background(), "domain ", domain, " unexpectedIPs ", ips, " matched at server ", c.Name())
|
||||
if len(ips) == 0 {
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
}
|
||||
return nil, errExpectedIPNonMatch
|
||||
}
|
||||
errors.LogDebug(context.Background(), "domain ", domain, " expectedIPs ", newIps, " matched at server ", c.Name())
|
||||
return newIps, nil
|
||||
|
||||
if len(c.expectedIPs) > 0 && c.actPrior {
|
||||
ipsNew := router.MatchIPs(c.expectedIPs, ips, false)
|
||||
if len(ipsNew) > 0 {
|
||||
ips = ipsNew
|
||||
errors.LogDebug(context.Background(), "domain ", domain, " priorIPs ", ips, " matched at server ", c.Name())
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.unexpectedIPs) > 0 && c.actUnprior {
|
||||
ipsNew := router.MatchIPs(c.unexpectedIPs, ips, true)
|
||||
if len(ipsNew) > 0 {
|
||||
ips = ipsNew
|
||||
errors.LogDebug(context.Background(), "domain ", domain, " unpriorIPs ", ips, " matched at server ", c.Name())
|
||||
}
|
||||
}
|
||||
|
||||
return ips, ttl, nil
|
||||
}
|
||||
|
||||
func ResolveIpOptionOverride(queryStrategy QueryStrategy, ipOption dns.IPOption) dns.IPOption {
|
||||
switch queryStrategy {
|
||||
case QueryStrategy_USE_IP:
|
||||
return ipOption
|
||||
case QueryStrategy_USE_SYS:
|
||||
return ipOption
|
||||
case QueryStrategy_USE_IP4:
|
||||
return dns.IPOption{
|
||||
IPv4Enable: ipOption.IPv4Enable,
|
||||
|
@@ -4,12 +4,12 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
go_errors "errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
utls "github.com/refraction-networking/utls"
|
||||
@@ -21,12 +21,9 @@ import (
|
||||
"github.com/xtls/xray-core/common/net/cnc"
|
||||
"github.com/xtls/xray-core/common/protocol/dns"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
@@ -34,18 +31,14 @@ import (
|
||||
// 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
|
||||
httpClient *http.Client
|
||||
dohURL string
|
||||
name string
|
||||
queryStrategy QueryStrategy
|
||||
cacheController *CacheController
|
||||
httpClient *http.Client
|
||||
dohURL string
|
||||
clientIP net.IP
|
||||
}
|
||||
|
||||
// NewDoHNameServer creates DOH/DOHL client object for remote/local resolving.
|
||||
func NewDoHNameServer(url *url.URL, queryStrategy QueryStrategy, dispatcher routing.Dispatcher, h2c bool) *DoHNameServer {
|
||||
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, h2c bool, disableCache bool, clientIP net.IP) *DoHNameServer {
|
||||
url.Scheme = "https"
|
||||
mode := "DOH"
|
||||
if dispatcher == nil {
|
||||
@@ -53,15 +46,9 @@ func NewDoHNameServer(url *url.URL, queryStrategy QueryStrategy, dispatcher rout
|
||||
}
|
||||
errors.LogInfo(context.Background(), "DNS: created ", mode, " client for ", url.String(), ", with h2c ", h2c)
|
||||
s := &DoHNameServer{
|
||||
ips: make(map[string]*record),
|
||||
pub: pubsub.NewService(),
|
||||
name: mode + "//" + url.Host,
|
||||
dohURL: url.String(),
|
||||
queryStrategy: queryStrategy,
|
||||
}
|
||||
s.cleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
Execute: s.Cleanup,
|
||||
cacheController: NewCacheController(mode+"//"+url.Host, disableCache),
|
||||
dohURL: url.String(),
|
||||
clientIP: clientIP,
|
||||
}
|
||||
s.httpClient = &http.Client{
|
||||
Transport: &http2.Transport{
|
||||
@@ -127,101 +114,25 @@ func NewDoHNameServer(url *url.URL, queryStrategy QueryStrategy, dispatcher rout
|
||||
|
||||
// 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 errors.New("nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for domain, record := range s.ips {
|
||||
if record.A != nil && record.A.Expire.Before(now) {
|
||||
record.A = nil
|
||||
}
|
||||
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
||||
record.AAAA = nil
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||
delete(s.ips, domain)
|
||||
} else {
|
||||
s.ips[domain] = record
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
s.ips = make(map[string]*record)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *DoHNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
elapsed := time.Since(req.start)
|
||||
|
||||
s.Lock()
|
||||
rec, found := s.ips[req.domain]
|
||||
if !found {
|
||||
rec = &record{}
|
||||
}
|
||||
updated := false
|
||||
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
if isNewer(rec.A, ipRec) {
|
||||
rec.A = ipRec
|
||||
updated = true
|
||||
}
|
||||
case dnsmessage.TypeAAAA:
|
||||
addr := make([]net.Address, 0, len(ipRec.IP))
|
||||
for _, ip := range ipRec.IP {
|
||||
if len(ip.IP()) == net.IPv6len {
|
||||
addr = append(addr, ip)
|
||||
}
|
||||
}
|
||||
ipRec.IP = addr
|
||||
if isNewer(rec.AAAA, ipRec) {
|
||||
rec.AAAA = ipRec
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||
|
||||
if updated {
|
||||
s.ips[req.domain] = rec
|
||||
}
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
s.pub.Publish(req.domain+"4", nil)
|
||||
case dnsmessage.TypeAAAA:
|
||||
s.pub.Publish(req.domain+"6", nil)
|
||||
}
|
||||
s.Unlock()
|
||||
common.Must(s.cleanup.Start())
|
||||
return s.cacheController.name
|
||||
}
|
||||
|
||||
func (s *DoHNameServer) newReqID() uint16 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||
errors.LogInfo(ctx, s.name, " querying: ", domain)
|
||||
func (s *DoHNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
||||
errors.LogInfo(ctx, s.Name(), " querying: ", domain)
|
||||
|
||||
if s.name+"." == "DOH//"+domain {
|
||||
errors.LogError(ctx, s.name, " tries to resolve itself! Use IP or set \"hosts\" instead.")
|
||||
if s.Name()+"." == "DOH//"+domain {
|
||||
errors.LogError(ctx, s.Name(), " tries to resolve itself! Use IP or set \"hosts\" instead.")
|
||||
noResponseErrCh <- errors.New("tries to resolve itself!", s.Name())
|
||||
return
|
||||
}
|
||||
|
||||
// As we don't want our traffic pattern looks like DoH, we use Random-Length Padding instead of Block-Length Padding recommended in RFC 8467
|
||||
// Although DoH server like 1.1.1.1 will pad the response to Block-Length 468, at least it is better than no padding for response at all
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP, int(crypto.RandBetween(100, 300))))
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, int(crypto.RandBetween(100, 300))))
|
||||
|
||||
var deadline time.Time
|
||||
if d, ok := ctx.Deadline(); ok {
|
||||
@@ -256,19 +167,22 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP n
|
||||
b, err := dns.PackMessage(r.msg)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to pack dns query for ", domain)
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
resp, err := s.dohHTTPSContext(dnsCtx, b.Bytes())
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to retrieve response for ", domain)
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
rec, err := parseResponse(resp)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to handle DOH response for ", domain)
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
s.updateIP(r, rec)
|
||||
s.cacheController.updateIP(r, rec)
|
||||
}(req)
|
||||
}
|
||||
}
|
||||
@@ -301,109 +215,50 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
func (s *DoHNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||
s.RLock()
|
||||
record, found := s.ips[domain]
|
||||
s.RUnlock()
|
||||
|
||||
if !found {
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
|
||||
var err4 error
|
||||
var err6 error
|
||||
var ips []net.Address
|
||||
var ip6 []net.Address
|
||||
var ttl uint32
|
||||
|
||||
if option.IPv4Enable {
|
||||
ips, ttl, err4 = record.A.getIPs()
|
||||
}
|
||||
|
||||
if option.IPv6Enable {
|
||||
ip6, ttl, err6 = record.AAAA.getIPs()
|
||||
ips = append(ips, ip6...)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
netips, err := toNetIP(ips)
|
||||
return netips, ttl, err
|
||||
}
|
||||
|
||||
if err4 != nil {
|
||||
return nil, 0, err4
|
||||
}
|
||||
|
||||
if err6 != nil {
|
||||
return nil, 0, err6
|
||||
}
|
||||
|
||||
if (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {
|
||||
return nil, 0, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
|
||||
// QueryIP implements Server.
|
||||
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, uint32, error) { // nolint: dupl
|
||||
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) { // nolint: dupl
|
||||
fqdn := Fqdn(domain)
|
||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, 0, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
||||
defer closeSubscribers(sub4, sub6)
|
||||
|
||||
if disableCache {
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
||||
if s.cacheController.disableCache {
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
||||
} else {
|
||||
ips, ttl, err := s.findIPsForDomain(fqdn, option)
|
||||
if err == nil || err == dns_feature.ErrEmptyResponse || dns_feature.RCodeFromError(err) == 3 {
|
||||
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
||||
if !go_errors.Is(err, errRecordNotFound) {
|
||||
errors.LogDebugInner(ctx, err, s.Name(), " cache HIT ", domain, " -> ", ips)
|
||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||
return ips, ttl, 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)
|
||||
noResponseErrCh := make(chan error, 2)
|
||||
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
||||
start := time.Now()
|
||||
|
||||
for {
|
||||
ips, ttl, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, ttl, err
|
||||
}
|
||||
|
||||
if sub4 != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, 0, ctx.Err()
|
||||
case <-done:
|
||||
case err := <-noResponseErrCh:
|
||||
return nil, 0, err
|
||||
case <-sub4.Wait():
|
||||
sub4.Close()
|
||||
}
|
||||
}
|
||||
if sub6 != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, 0, ctx.Err()
|
||||
case err := <-noResponseErrCh:
|
||||
return nil, 0, err
|
||||
case <-sub6.Wait():
|
||||
sub6.Close()
|
||||
}
|
||||
}
|
||||
|
||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, ttl, err
|
||||
|
||||
}
|
||||
|
@@ -17,12 +17,12 @@ func TestDOHNameServer(t *testing.T) {
|
||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHNameServer(url, QueryStrategy_USE_IP, nil, false)
|
||||
s := NewDoHNameServer(url, nil, false, false, net.IP(nil))
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
@@ -34,12 +34,12 @@ func TestDOHNameServerWithCache(t *testing.T) {
|
||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHNameServer(url, QueryStrategy_USE_IP, nil, false)
|
||||
s := NewDoHNameServer(url, nil, false, false, net.IP(nil))
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
@@ -47,10 +47,10 @@ func TestDOHNameServerWithCache(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips2, _, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
ips2, _, err := s.QueryIP(ctx2, "google.com", dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, true)
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if r := cmp.Diff(ips2, ips); r != "" {
|
||||
@@ -62,12 +62,12 @@ func TestDOHNameServerWithIPv4Override(t *testing.T) {
|
||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHNameServer(url, QueryStrategy_USE_IP4, nil, false)
|
||||
s := NewDoHNameServer(url, nil, false, false, net.IP(nil))
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
IPv6Enable: false,
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
@@ -85,12 +85,12 @@ func TestDOHNameServerWithIPv6Override(t *testing.T) {
|
||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHNameServer(url, QueryStrategy_USE_IP6, nil, false)
|
||||
s := NewDoHNameServer(url, nil, false, false, net.IP(nil))
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
|
@@ -20,7 +20,7 @@ func (FakeDNSServer) Name() string {
|
||||
return "FakeDNS"
|
||||
}
|
||||
|
||||
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, opt dns.IPOption, _ bool) ([]net.IP, uint32, error) {
|
||||
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, opt dns.IPOption) ([]net.IP, uint32, error) {
|
||||
if f.fakeDNSEngine == nil {
|
||||
return nil, 0, errors.New("Unable to locate a fake DNS Engine").AtError()
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
@@ -14,26 +13,15 @@ import (
|
||||
|
||||
// LocalNameServer is an wrapper over local DNS feature.
|
||||
type LocalNameServer struct {
|
||||
client *localdns.Client
|
||||
queryStrategy QueryStrategy
|
||||
client *localdns.Client
|
||||
}
|
||||
|
||||
const errEmptyResponse = "No address associated with hostname"
|
||||
|
||||
// QueryIP implements Server.
|
||||
func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, _ net.IP, option dns.IPOption, _ bool) (ips []net.IP, ttl uint32, err error) {
|
||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
}
|
||||
func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, option dns.IPOption) (ips []net.IP, ttl uint32, err error) {
|
||||
|
||||
start := time.Now()
|
||||
ips, ttl, err = s.client.LookupIP(domain, option)
|
||||
|
||||
if err != nil && strings.HasSuffix(err.Error(), errEmptyResponse) {
|
||||
err = dns.ErrEmptyResponse
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
errors.LogInfo(ctx, "Localhost got answer: ", domain, " -> ", ips)
|
||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
@@ -48,15 +36,14 @@ func (s *LocalNameServer) Name() string {
|
||||
}
|
||||
|
||||
// NewLocalNameServer creates localdns server object for directly lookup in system DNS.
|
||||
func NewLocalNameServer(queryStrategy QueryStrategy) *LocalNameServer {
|
||||
func NewLocalNameServer() *LocalNameServer {
|
||||
errors.LogInfo(context.Background(), "DNS: created localhost client")
|
||||
return &LocalNameServer{
|
||||
queryStrategy: queryStrategy,
|
||||
client: localdns.New(),
|
||||
client: localdns.New(),
|
||||
}
|
||||
}
|
||||
|
||||
// NewLocalDNSClient creates localdns client object for directly lookup in system DNS.
|
||||
func NewLocalDNSClient() *Client {
|
||||
return &Client{server: NewLocalNameServer(QueryStrategy_USE_IP)}
|
||||
func NewLocalDNSClient(ipOption dns.IPOption) *Client {
|
||||
return &Client{server: NewLocalNameServer(), ipOption: &ipOption}
|
||||
}
|
||||
|
@@ -7,18 +7,17 @@ import (
|
||||
|
||||
. "github.com/xtls/xray-core/app/dns"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
)
|
||||
|
||||
func TestLocalNameServer(t *testing.T) {
|
||||
s := NewLocalNameServer(QueryStrategy_USE_IP)
|
||||
s := NewLocalNameServer()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", net.IP{}, dns.IPOption{
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
}, false)
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
|
@@ -4,23 +4,20 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
go_errors "errors"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/log"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol/dns"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
@@ -33,17 +30,14 @@ 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
|
||||
name string
|
||||
destination *net.Destination
|
||||
connection quic.Connection
|
||||
queryStrategy QueryStrategy
|
||||
cacheController *CacheController
|
||||
destination *net.Destination
|
||||
connection *quic.Conn
|
||||
clientIP net.IP
|
||||
}
|
||||
|
||||
// NewQUICNameServer creates DNS-over-QUIC client object for local resolving
|
||||
func NewQUICNameServer(url *url.URL, queryStrategy QueryStrategy) (*QUICNameServer, error) {
|
||||
func NewQUICNameServer(url *url.URL, disableCache bool, clientIP net.IP) (*QUICNameServer, error) {
|
||||
errors.LogInfo(context.Background(), "DNS: created Local DNS-over-QUIC client for ", url.String())
|
||||
|
||||
var err error
|
||||
@@ -57,15 +51,9 @@ func NewQUICNameServer(url *url.URL, queryStrategy QueryStrategy) (*QUICNameServ
|
||||
dest := net.UDPDestination(net.ParseAddress(url.Hostname()), port)
|
||||
|
||||
s := &QUICNameServer{
|
||||
ips: make(map[string]*record),
|
||||
pub: pubsub.NewService(),
|
||||
name: url.String(),
|
||||
destination: &dest,
|
||||
queryStrategy: queryStrategy,
|
||||
}
|
||||
s.cleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
Execute: s.Cleanup,
|
||||
cacheController: NewCacheController(url.String(), disableCache),
|
||||
destination: &dest,
|
||||
clientIP: clientIP,
|
||||
}
|
||||
|
||||
return s, nil
|
||||
@@ -73,94 +61,17 @@ func NewQUICNameServer(url *url.URL, queryStrategy QueryStrategy) (*QUICNameServ
|
||||
|
||||
// Name returns client name
|
||||
func (s *QUICNameServer) Name() string {
|
||||
return s.name
|
||||
}
|
||||
|
||||
// Cleanup clears expired items from cache
|
||||
func (s *QUICNameServer) Cleanup() error {
|
||||
now := time.Now()
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
return errors.New("nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for domain, record := range s.ips {
|
||||
if record.A != nil && record.A.Expire.Before(now) {
|
||||
record.A = nil
|
||||
}
|
||||
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
||||
record.AAAA = nil
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||
delete(s.ips, domain)
|
||||
} else {
|
||||
s.ips[domain] = record
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
s.ips = make(map[string]*record)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
elapsed := time.Since(req.start)
|
||||
|
||||
s.Lock()
|
||||
rec, found := s.ips[req.domain]
|
||||
if !found {
|
||||
rec = &record{}
|
||||
}
|
||||
updated := false
|
||||
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
if isNewer(rec.A, ipRec) {
|
||||
rec.A = ipRec
|
||||
updated = true
|
||||
}
|
||||
case dnsmessage.TypeAAAA:
|
||||
addr := make([]net.Address, 0)
|
||||
for _, ip := range ipRec.IP {
|
||||
if len(ip.IP()) == net.IPv6len {
|
||||
addr = append(addr, ip)
|
||||
}
|
||||
}
|
||||
ipRec.IP = addr
|
||||
if isNewer(rec.AAAA, ipRec) {
|
||||
rec.AAAA = ipRec
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||
|
||||
if updated {
|
||||
s.ips[req.domain] = rec
|
||||
}
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
s.pub.Publish(req.domain+"4", nil)
|
||||
case dnsmessage.TypeAAAA:
|
||||
s.pub.Publish(req.domain+"6", nil)
|
||||
}
|
||||
s.Unlock()
|
||||
common.Must(s.cleanup.Start())
|
||||
return s.cacheController.name
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) newReqID() uint16 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||
errors.LogInfo(ctx, s.name, " querying: ", domain)
|
||||
func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
||||
errors.LogInfo(ctx, s.Name(), " querying: ", domain)
|
||||
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP, 0))
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||
|
||||
var deadline time.Time
|
||||
if d, ok := ctx.Deadline(); ok {
|
||||
@@ -192,23 +103,36 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP
|
||||
b, err := dns.PackMessage(r.msg)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
dnsReqBuf := buf.New()
|
||||
binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
||||
dnsReqBuf.Write(b.Bytes())
|
||||
err = binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "binary write failed")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
_, err = dnsReqBuf.Write(b.Bytes())
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "buffer write failed")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
b.Release()
|
||||
|
||||
conn, err := s.openStream(dnsCtx)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to open quic connection")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
_, err = conn.Write(dnsReqBuf.Bytes())
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to send query")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
@@ -219,139 +143,84 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP
|
||||
n, err := respBuf.ReadFullFrom(conn, 2)
|
||||
if err != nil && n == 0 {
|
||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
var length int16
|
||||
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
respBuf.Clear()
|
||||
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
||||
if err != nil && n == 0 {
|
||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
rec, err := parseResponse(respBuf.Bytes())
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to handle response")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
s.updateIP(r, rec)
|
||||
s.cacheController.updateIP(r, rec)
|
||||
}(req)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||
s.RLock()
|
||||
record, found := s.ips[domain]
|
||||
s.RUnlock()
|
||||
|
||||
if !found {
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
|
||||
var err4 error
|
||||
var err6 error
|
||||
var ips []net.Address
|
||||
var ip6 []net.Address
|
||||
var ttl uint32
|
||||
|
||||
if option.IPv4Enable {
|
||||
ips, ttl, err4 = record.A.getIPs()
|
||||
}
|
||||
|
||||
if option.IPv6Enable {
|
||||
ip6, ttl, err6 = record.AAAA.getIPs()
|
||||
ips = append(ips, ip6...)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
netips, err := toNetIP(ips)
|
||||
return netips, ttl, err
|
||||
}
|
||||
|
||||
if err4 != nil {
|
||||
return nil, 0, err4
|
||||
}
|
||||
|
||||
if err6 != nil {
|
||||
return nil, 0, err6
|
||||
}
|
||||
|
||||
if (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {
|
||||
return nil, 0, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
|
||||
// QueryIP is called from dns.Server->queryIPTimeout
|
||||
func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, uint32, error) {
|
||||
func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||
fqdn := Fqdn(domain)
|
||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, 0, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
||||
defer closeSubscribers(sub4, sub6)
|
||||
|
||||
if disableCache {
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
||||
if s.cacheController.disableCache {
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
||||
} else {
|
||||
ips, ttl, err := s.findIPsForDomain(fqdn, option)
|
||||
if err == nil || err == dns_feature.ErrEmptyResponse || dns_feature.RCodeFromError(err) == 3 {
|
||||
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
||||
if !go_errors.Is(err, errRecordNotFound) {
|
||||
errors.LogDebugInner(ctx, err, s.Name(), " cache HIT ", domain, " -> ", ips)
|
||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||
return ips, ttl, 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)
|
||||
noResponseErrCh := make(chan error, 2)
|
||||
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
||||
start := time.Now()
|
||||
|
||||
for {
|
||||
ips, ttl, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, ttl, err
|
||||
}
|
||||
|
||||
if sub4 != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, 0, ctx.Err()
|
||||
case <-done:
|
||||
case err := <-noResponseErrCh:
|
||||
return nil, 0, err
|
||||
case <-sub4.Wait():
|
||||
sub4.Close()
|
||||
}
|
||||
}
|
||||
if sub6 != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, 0, ctx.Err()
|
||||
case err := <-noResponseErrCh:
|
||||
return nil, 0, err
|
||||
case <-sub6.Wait():
|
||||
sub6.Close()
|
||||
}
|
||||
}
|
||||
|
||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, ttl, err
|
||||
|
||||
}
|
||||
|
||||
func isActive(s quic.Connection) bool {
|
||||
func isActive(s *quic.Conn) bool {
|
||||
select {
|
||||
case <-s.Context().Done():
|
||||
return false
|
||||
@@ -360,8 +229,8 @@ func isActive(s quic.Connection) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) getConnection() (quic.Connection, error) {
|
||||
var conn quic.Connection
|
||||
func (s *QUICNameServer) getConnection() (*quic.Conn, error) {
|
||||
var conn *quic.Conn
|
||||
s.RLock()
|
||||
conn = s.connection
|
||||
if conn != nil && isActive(conn) {
|
||||
@@ -394,7 +263,7 @@ func (s *QUICNameServer) getConnection() (quic.Connection, error) {
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) openConnection() (quic.Connection, error) {
|
||||
func (s *QUICNameServer) openConnection() (*quic.Conn, error) {
|
||||
tlsConfig := tls.Config{}
|
||||
quicConfig := &quic.Config{
|
||||
HandshakeIdleTimeout: handshakeTimeout,
|
||||
@@ -414,7 +283,7 @@ func (s *QUICNameServer) openConnection() (quic.Connection, error) {
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) openStream(ctx context.Context) (quic.Stream, error) {
|
||||
func (s *QUICNameServer) openStream(ctx context.Context) (*quic.Stream, error) {
|
||||
conn, err := s.getConnection()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -16,24 +16,23 @@ import (
|
||||
func TestQUICNameServer(t *testing.T) {
|
||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
||||
common.Must(err)
|
||||
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP)
|
||||
s, err := NewQUICNameServer(url, false, net.IP(nil))
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
t.Error("expect some ips, but got 0")
|
||||
}
|
||||
|
||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips2, _, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns.IPOption{
|
||||
ips2, _, err := s.QueryIP(ctx2, "google.com", dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, true)
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if r := cmp.Diff(ips2, ips); r != "" {
|
||||
@@ -44,13 +43,13 @@ func TestQUICNameServer(t *testing.T) {
|
||||
func TestQUICNameServerWithIPv4Override(t *testing.T) {
|
||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
||||
common.Must(err)
|
||||
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP4)
|
||||
s, err := NewQUICNameServer(url, false, net.IP(nil))
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
IPv6Enable: false,
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
@@ -67,13 +66,13 @@ func TestQUICNameServerWithIPv4Override(t *testing.T) {
|
||||
func TestQUICNameServerWithIPv6Override(t *testing.T) {
|
||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
||||
common.Must(err)
|
||||
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP6)
|
||||
s, err := NewQUICNameServer(url, false, net.IP(nil))
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
|
@@ -4,12 +4,11 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
go_errors "errors"
|
||||
"net/url"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/log"
|
||||
@@ -17,34 +16,28 @@ import (
|
||||
"github.com/xtls/xray-core/common/net/cnc"
|
||||
"github.com/xtls/xray-core/common/protocol/dns"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
)
|
||||
|
||||
// TCPNameServer implemented DNS over TCP (RFC7766).
|
||||
type TCPNameServer struct {
|
||||
sync.RWMutex
|
||||
name string
|
||||
destination *net.Destination
|
||||
ips map[string]*record
|
||||
pub *pubsub.Service
|
||||
cleanup *task.Periodic
|
||||
reqID uint32
|
||||
dial func(context.Context) (net.Conn, error)
|
||||
queryStrategy QueryStrategy
|
||||
cacheController *CacheController
|
||||
destination *net.Destination
|
||||
reqID uint32
|
||||
dial func(context.Context) (net.Conn, error)
|
||||
clientIP net.IP
|
||||
}
|
||||
|
||||
// NewTCPNameServer creates DNS over TCP server object for remote resolving.
|
||||
func NewTCPNameServer(
|
||||
url *url.URL,
|
||||
dispatcher routing.Dispatcher,
|
||||
queryStrategy QueryStrategy,
|
||||
disableCache bool,
|
||||
clientIP net.IP,
|
||||
) (*TCPNameServer, error) {
|
||||
s, err := baseTCPNameServer(url, "TCP", queryStrategy)
|
||||
s, err := baseTCPNameServer(url, "TCP", disableCache, clientIP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -65,8 +58,8 @@ func NewTCPNameServer(
|
||||
}
|
||||
|
||||
// NewTCPLocalNameServer creates DNS over TCP client object for local resolving
|
||||
func NewTCPLocalNameServer(url *url.URL, queryStrategy QueryStrategy) (*TCPNameServer, error) {
|
||||
s, err := baseTCPNameServer(url, "TCPL", queryStrategy)
|
||||
func NewTCPLocalNameServer(url *url.URL, disableCache bool, clientIP net.IP) (*TCPNameServer, error) {
|
||||
s, err := baseTCPNameServer(url, "TCPL", disableCache, clientIP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -78,7 +71,7 @@ func NewTCPLocalNameServer(url *url.URL, queryStrategy QueryStrategy) (*TCPNameS
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func baseTCPNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) (*TCPNameServer, error) {
|
||||
func baseTCPNameServer(url *url.URL, prefix string, disableCache bool, clientIP net.IP) (*TCPNameServer, error) {
|
||||
port := net.Port(53)
|
||||
if url.Port() != "" {
|
||||
var err error
|
||||
@@ -89,15 +82,9 @@ func baseTCPNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy)
|
||||
dest := net.TCPDestination(net.ParseAddress(url.Hostname()), port)
|
||||
|
||||
s := &TCPNameServer{
|
||||
destination: &dest,
|
||||
ips: make(map[string]*record),
|
||||
pub: pubsub.NewService(),
|
||||
name: prefix + "//" + dest.NetAddr(),
|
||||
queryStrategy: queryStrategy,
|
||||
}
|
||||
s.cleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
Execute: s.Cleanup,
|
||||
cacheController: NewCacheController(prefix+"//"+dest.NetAddr(), disableCache),
|
||||
destination: &dest,
|
||||
clientIP: clientIP,
|
||||
}
|
||||
|
||||
return s, nil
|
||||
@@ -105,94 +92,17 @@ func baseTCPNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy)
|
||||
|
||||
// Name implements Server.
|
||||
func (s *TCPNameServer) Name() string {
|
||||
return s.name
|
||||
}
|
||||
|
||||
// Cleanup clears expired items from cache
|
||||
func (s *TCPNameServer) Cleanup() error {
|
||||
now := time.Now()
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
return errors.New("nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for domain, record := range s.ips {
|
||||
if record.A != nil && record.A.Expire.Before(now) {
|
||||
record.A = nil
|
||||
}
|
||||
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
||||
record.AAAA = nil
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||
delete(s.ips, domain)
|
||||
} else {
|
||||
s.ips[domain] = record
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
s.ips = make(map[string]*record)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TCPNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
elapsed := time.Since(req.start)
|
||||
|
||||
s.Lock()
|
||||
rec, found := s.ips[req.domain]
|
||||
if !found {
|
||||
rec = &record{}
|
||||
}
|
||||
updated := false
|
||||
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
if isNewer(rec.A, ipRec) {
|
||||
rec.A = ipRec
|
||||
updated = true
|
||||
}
|
||||
case dnsmessage.TypeAAAA:
|
||||
addr := make([]net.Address, 0)
|
||||
for _, ip := range ipRec.IP {
|
||||
if len(ip.IP()) == net.IPv6len {
|
||||
addr = append(addr, ip)
|
||||
}
|
||||
}
|
||||
ipRec.IP = addr
|
||||
if isNewer(rec.AAAA, ipRec) {
|
||||
rec.AAAA = ipRec
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||
|
||||
if updated {
|
||||
s.ips[req.domain] = rec
|
||||
}
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
s.pub.Publish(req.domain+"4", nil)
|
||||
case dnsmessage.TypeAAAA:
|
||||
s.pub.Publish(req.domain+"6", nil)
|
||||
}
|
||||
s.Unlock()
|
||||
common.Must(s.cleanup.Start())
|
||||
return s.cacheController.name
|
||||
}
|
||||
|
||||
func (s *TCPNameServer) newReqID() uint16 {
|
||||
return uint16(atomic.AddUint32(&s.reqID, 1))
|
||||
}
|
||||
|
||||
func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||
errors.LogDebug(ctx, s.name, " querying DNS for: ", domain)
|
||||
func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
||||
errors.LogDebug(ctx, s.Name(), " querying DNS for: ", domain)
|
||||
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP, 0))
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||
|
||||
var deadline time.Time
|
||||
if d, ok := ctx.Deadline(); ok {
|
||||
@@ -221,23 +131,36 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP n
|
||||
b, err := dns.PackMessage(r.msg)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := s.dial(dnsCtx)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to dial namesever")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
dnsReqBuf := buf.New()
|
||||
binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
||||
dnsReqBuf.Write(b.Bytes())
|
||||
err = binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "binary write failed")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
_, err = dnsReqBuf.Write(b.Bytes())
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "buffer write failed")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
b.Release()
|
||||
|
||||
_, err = conn.Write(dnsReqBuf.Bytes())
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to send query")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
dnsReqBuf.Release()
|
||||
@@ -247,131 +170,80 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP n
|
||||
n, err := respBuf.ReadFullFrom(conn, 2)
|
||||
if err != nil && n == 0 {
|
||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
var length int16
|
||||
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
respBuf.Clear()
|
||||
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
||||
if err != nil && n == 0 {
|
||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
rec, err := parseResponse(respBuf.Bytes())
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to parse DNS over TCP response")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
s.updateIP(r, rec)
|
||||
s.cacheController.updateIP(r, rec)
|
||||
}(req)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TCPNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||
s.RLock()
|
||||
record, found := s.ips[domain]
|
||||
s.RUnlock()
|
||||
|
||||
if !found {
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
|
||||
var err4 error
|
||||
var err6 error
|
||||
var ips []net.Address
|
||||
var ip6 []net.Address
|
||||
var ttl uint32
|
||||
|
||||
if option.IPv4Enable {
|
||||
ips, ttl, err4 = record.A.getIPs()
|
||||
}
|
||||
|
||||
if option.IPv6Enable {
|
||||
ip6, ttl, err6 = record.AAAA.getIPs()
|
||||
ips = append(ips, ip6...)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
netips, err := toNetIP(ips)
|
||||
return netips, ttl, err
|
||||
}
|
||||
|
||||
if err4 != nil {
|
||||
return nil, 0, err4
|
||||
}
|
||||
|
||||
if err6 != nil {
|
||||
return nil, 0, err6
|
||||
}
|
||||
|
||||
return nil, 0, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
// QueryIP implements Server.
|
||||
func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, uint32, error) {
|
||||
func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||
fqdn := Fqdn(domain)
|
||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, 0, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
||||
defer closeSubscribers(sub4, sub6)
|
||||
|
||||
if disableCache {
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
||||
if s.cacheController.disableCache {
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
||||
} else {
|
||||
ips, ttl, err := s.findIPsForDomain(fqdn, option)
|
||||
if err == nil || err == dns_feature.ErrEmptyResponse || dns_feature.RCodeFromError(err) == 3 {
|
||||
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
||||
if !go_errors.Is(err, errRecordNotFound) {
|
||||
errors.LogDebugInner(ctx, err, s.Name(), " cache HIT ", domain, " -> ", ips)
|
||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||
return ips, ttl, 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)
|
||||
noResponseErrCh := make(chan error, 2)
|
||||
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
||||
start := time.Now()
|
||||
|
||||
for {
|
||||
ips, ttl, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, ttl, err
|
||||
}
|
||||
|
||||
if sub4 != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, 0, ctx.Err()
|
||||
case <-done:
|
||||
case err := <-noResponseErrCh:
|
||||
return nil, 0, err
|
||||
case <-sub4.Wait():
|
||||
sub4.Close()
|
||||
}
|
||||
}
|
||||
if sub6 != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, 0, ctx.Err()
|
||||
case err := <-noResponseErrCh:
|
||||
return nil, 0, err
|
||||
case <-sub6.Wait():
|
||||
sub6.Close()
|
||||
}
|
||||
}
|
||||
|
||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, ttl, err
|
||||
|
||||
}
|
||||
|
@@ -16,13 +16,13 @@ import (
|
||||
func TestTCPLocalNameServer(t *testing.T) {
|
||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||
common.Must(err)
|
||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP)
|
||||
s, err := NewTCPLocalNameServer(url, false, net.IP(nil))
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
@@ -33,13 +33,13 @@ func TestTCPLocalNameServer(t *testing.T) {
|
||||
func TestTCPLocalNameServerWithCache(t *testing.T) {
|
||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||
common.Must(err)
|
||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP)
|
||||
s, err := NewTCPLocalNameServer(url, false, net.IP(nil))
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
@@ -47,10 +47,10 @@ func TestTCPLocalNameServerWithCache(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips2, _, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
ips2, _, err := s.QueryIP(ctx2, "google.com", dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, true)
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if r := cmp.Diff(ips2, ips); r != "" {
|
||||
@@ -61,13 +61,13 @@ func TestTCPLocalNameServerWithCache(t *testing.T) {
|
||||
func TestTCPLocalNameServerWithIPv4Override(t *testing.T) {
|
||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||
common.Must(err)
|
||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP4)
|
||||
s, err := NewTCPLocalNameServer(url, false, net.IP(nil))
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
IPv6Enable: false,
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
|
||||
@@ -85,13 +85,13 @@ func TestTCPLocalNameServerWithIPv4Override(t *testing.T) {
|
||||
func TestTCPLocalNameServerWithIPv6Override(t *testing.T) {
|
||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||
common.Must(err)
|
||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP6)
|
||||
s, err := NewTCPLocalNameServer(url, false, net.IP(nil))
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
|
||||
|
@@ -2,6 +2,7 @@ package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
go_errors "errors"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -13,7 +14,6 @@ import (
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol/dns"
|
||||
udp_proto "github.com/xtls/xray-core/common/protocol/udp"
|
||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
@@ -24,15 +24,13 @@ import (
|
||||
// ClassicNameServer implemented traditional UDP DNS.
|
||||
type ClassicNameServer struct {
|
||||
sync.RWMutex
|
||||
name string
|
||||
address *net.Destination
|
||||
ips map[string]*record
|
||||
requests map[uint16]*udpDnsRequest
|
||||
pub *pubsub.Service
|
||||
udpServer *udp.Dispatcher
|
||||
cleanup *task.Periodic
|
||||
reqID uint32
|
||||
queryStrategy QueryStrategy
|
||||
cacheController *CacheController
|
||||
address *net.Destination
|
||||
requests map[uint16]*udpDnsRequest
|
||||
udpServer *udp.Dispatcher
|
||||
requestsCleanup *task.Periodic
|
||||
reqID uint32
|
||||
clientIP net.IP
|
||||
}
|
||||
|
||||
type udpDnsRequest struct {
|
||||
@@ -41,23 +39,21 @@ type udpDnsRequest struct {
|
||||
}
|
||||
|
||||
// NewClassicNameServer creates udp server object for remote resolving.
|
||||
func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) *ClassicNameServer {
|
||||
func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher, disableCache bool, clientIP net.IP) *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]*udpDnsRequest),
|
||||
pub: pubsub.NewService(),
|
||||
name: strings.ToUpper(address.String()),
|
||||
queryStrategy: queryStrategy,
|
||||
cacheController: NewCacheController(strings.ToUpper(address.String()), disableCache),
|
||||
address: &address,
|
||||
requests: make(map[uint16]*udpDnsRequest),
|
||||
clientIP: clientIP,
|
||||
}
|
||||
s.cleanup = &task.Periodic{
|
||||
s.requestsCleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
Execute: s.Cleanup,
|
||||
Execute: s.RequestsCleanup,
|
||||
}
|
||||
s.udpServer = udp.NewDispatcher(dispatcher, s.HandleResponse)
|
||||
errors.LogInfo(context.Background(), "DNS: created UDP client initialized for ", address.NetAddr())
|
||||
@@ -66,37 +62,17 @@ func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher
|
||||
|
||||
// Name implements Server.
|
||||
func (s *ClassicNameServer) Name() string {
|
||||
return s.name
|
||||
return s.cacheController.name
|
||||
}
|
||||
|
||||
// Cleanup clears expired items from cache
|
||||
func (s *ClassicNameServer) Cleanup() error {
|
||||
// RequestsCleanup clears expired items from cache
|
||||
func (s *ClassicNameServer) RequestsCleanup() error {
|
||||
now := time.Now()
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if len(s.ips) == 0 && len(s.requests) == 0 {
|
||||
return errors.New(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 {
|
||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||
delete(s.ips, domain)
|
||||
} else {
|
||||
s.ips[domain] = record
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
s.ips = make(map[string]*record)
|
||||
if len(s.requests) == 0 {
|
||||
return errors.New(s.Name(), " nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for id, req := range s.requests {
|
||||
@@ -116,7 +92,7 @@ func (s *ClassicNameServer) Cleanup() error {
|
||||
func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_proto.Packet) {
|
||||
ipRec, err := parseResponse(packet.Payload.Bytes())
|
||||
if err != nil {
|
||||
errors.LogError(ctx, s.name, " fail to parse responded DNS udp")
|
||||
errors.LogError(ctx, s.Name(), " fail to parse responded DNS udp")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -129,14 +105,14 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
||||
}
|
||||
s.Unlock()
|
||||
if !ok {
|
||||
errors.LogError(ctx, s.name, " cannot find the pending request")
|
||||
errors.LogError(ctx, s.Name(), " cannot find the pending request")
|
||||
return
|
||||
}
|
||||
|
||||
// if truncated, retry with EDNS0 option(udp payload size: 1350)
|
||||
if ipRec.RawHeader.Truncated {
|
||||
// if already has EDNS0 option, no need to retry
|
||||
if ok && len(req.msg.Additionals) == 0 {
|
||||
if len(req.msg.Additionals) == 0 {
|
||||
// copy necessary meta data from original request
|
||||
// and add EDNS0 option
|
||||
opt := new(dnsmessage.Resource)
|
||||
@@ -154,51 +130,7 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
||||
}
|
||||
}
|
||||
|
||||
var rec record
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
rec.A = ipRec
|
||||
case dnsmessage.TypeAAAA:
|
||||
rec.AAAA = ipRec
|
||||
}
|
||||
|
||||
elapsed := time.Since(req.start)
|
||||
errors.LogInfo(ctx, s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||
if len(req.domain) > 0 && (rec.A != nil || rec.AAAA != nil) {
|
||||
s.updateIP(req.domain, &rec)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ClassicNameServer) updateIP(domain string, newRec *record) {
|
||||
s.Lock()
|
||||
|
||||
rec, found := s.ips[domain]
|
||||
if !found {
|
||||
rec = &record{}
|
||||
}
|
||||
|
||||
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 {
|
||||
errors.LogDebug(context.Background(), s.name, " updating IP records for domain:", domain)
|
||||
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())
|
||||
s.cacheController.updateIP(&req.dnsRequest, ipRec)
|
||||
}
|
||||
|
||||
func (s *ClassicNameServer) newReqID() uint16 {
|
||||
@@ -207,17 +139,17 @@ func (s *ClassicNameServer) newReqID() uint16 {
|
||||
|
||||
func (s *ClassicNameServer) addPendingRequest(req *udpDnsRequest) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
id := req.msg.ID
|
||||
req.expire = time.Now().Add(time.Second * 8)
|
||||
s.requests[id] = req
|
||||
s.Unlock()
|
||||
common.Must(s.requestsCleanup.Start())
|
||||
}
|
||||
|
||||
func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||
errors.LogDebug(ctx, s.name, " querying DNS for: ", domain)
|
||||
func (s *ClassicNameServer) sendQuery(ctx context.Context, _ chan<- error, domain string, option dns_feature.IPOption) {
|
||||
errors.LogDebug(ctx, s.Name(), " querying DNS for: ", domain)
|
||||
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP, 0))
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||
|
||||
for _, req := range reqs {
|
||||
udpReq := &udpDnsRequest{
|
||||
@@ -230,105 +162,50 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, client
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ClassicNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||
s.RLock()
|
||||
record, found := s.ips[domain]
|
||||
s.RUnlock()
|
||||
|
||||
if !found {
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
|
||||
var err4 error
|
||||
var err6 error
|
||||
var ips []net.Address
|
||||
var ip6 []net.Address
|
||||
var ttl uint32
|
||||
|
||||
if option.IPv4Enable {
|
||||
ips, ttl, err4 = record.A.getIPs()
|
||||
}
|
||||
|
||||
if option.IPv6Enable {
|
||||
ip6, ttl, err6 = record.AAAA.getIPs()
|
||||
ips = append(ips, ip6...)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
netips, err := toNetIP(ips)
|
||||
return netips, ttl, err
|
||||
}
|
||||
|
||||
if err4 != nil {
|
||||
return nil, 0, err4
|
||||
}
|
||||
|
||||
if err6 != nil {
|
||||
return nil, 0, err6
|
||||
}
|
||||
|
||||
return nil, 0, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
// QueryIP implements Server.
|
||||
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, uint32, error) {
|
||||
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||
fqdn := Fqdn(domain)
|
||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, 0, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
||||
defer closeSubscribers(sub4, sub6)
|
||||
|
||||
if disableCache {
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
||||
if s.cacheController.disableCache {
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
||||
} else {
|
||||
ips, ttl, err := s.findIPsForDomain(fqdn, option)
|
||||
if err == nil || err == dns_feature.ErrEmptyResponse || dns_feature.RCodeFromError(err) == 3 {
|
||||
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
||||
if !go_errors.Is(err, errRecordNotFound) {
|
||||
errors.LogDebugInner(ctx, err, s.Name(), " cache HIT ", domain, " -> ", ips)
|
||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||
return ips, ttl, 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)
|
||||
noResponseErrCh := make(chan error, 2)
|
||||
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
||||
start := time.Now()
|
||||
|
||||
for {
|
||||
ips, ttl, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, ttl, err
|
||||
}
|
||||
|
||||
if sub4 != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, 0, ctx.Err()
|
||||
case <-done:
|
||||
case err := <-noResponseErrCh:
|
||||
return nil, 0, err
|
||||
case <-sub4.Wait():
|
||||
sub4.Close()
|
||||
}
|
||||
}
|
||||
if sub6 != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, 0, ctx.Err()
|
||||
case err := <-noResponseErrCh:
|
||||
return nil, 0, err
|
||||
case <-sub6.Wait():
|
||||
sub6.Close()
|
||||
}
|
||||
}
|
||||
|
||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, ttl, err
|
||||
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/net/cnc"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/signal/done"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
)
|
||||
@@ -108,3 +109,13 @@ func (co *Outbound) Close() error {
|
||||
co.closed = true
|
||||
return co.listener.Close()
|
||||
}
|
||||
|
||||
// SenderSettings implements outbound.Handler.
|
||||
func (co *Outbound) SenderSettings() *serial.TypedMessage {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProxySettings implements outbound.Handler.
|
||||
func (co *Outbound) ProxySettings() *serial.TypedMessage {
|
||||
return nil
|
||||
}
|
||||
|
@@ -90,6 +90,8 @@ type HealthPingConfig struct {
|
||||
SamplingCount int32 `protobuf:"varint,4,opt,name=samplingCount,proto3" json:"samplingCount,omitempty"`
|
||||
// ping timeout, int64 values of time.Duration
|
||||
Timeout int64 `protobuf:"varint,5,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
||||
// http method to make request
|
||||
HttpMethod string `protobuf:"bytes,6,opt,name=httpMethod,proto3" json:"httpMethod,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HealthPingConfig) Reset() {
|
||||
@@ -157,6 +159,13 @@ func (x *HealthPingConfig) GetTimeout() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HealthPingConfig) GetHttpMethod() string {
|
||||
if x != nil {
|
||||
return x.HttpMethod
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_app_observatory_burst_config_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
||||
@@ -173,7 +182,7 @@ var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
||||
0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x62, 0x75, 0x72,
|
||||
0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22,
|
||||
0xb4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
||||
0xd4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69,
|
||||
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
@@ -184,7 +193,9 @@ var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
||||
0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73,
|
||||
0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07,
|
||||
0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
|
||||
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x4d, 0x65,
|
||||
0x74, 0x68, 0x6f, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x68, 0x74, 0x74, 0x70,
|
||||
0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
|
||||
0x72, 0x79, 0x2e, 0x62, 0x75, 0x72, 0x73, 0x74, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68,
|
||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
||||
|
@@ -26,4 +26,7 @@ message HealthPingConfig {
|
||||
int32 samplingCount = 4;
|
||||
// ping timeout, int64 values of time.Duration
|
||||
int64 timeout = 5;
|
||||
// http method to make request
|
||||
string httpMethod = 6;
|
||||
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ type HealthPingSettings struct {
|
||||
Interval time.Duration `json:"interval"`
|
||||
SamplingCount int `json:"sampling"`
|
||||
Timeout time.Duration `json:"timeout"`
|
||||
HttpMethod string `json:"httpMethod"`
|
||||
}
|
||||
|
||||
// HealthPing is the health checker for balancers
|
||||
@@ -37,12 +38,21 @@ type HealthPing struct {
|
||||
func NewHealthPing(ctx context.Context, dispatcher routing.Dispatcher, config *HealthPingConfig) *HealthPing {
|
||||
settings := &HealthPingSettings{}
|
||||
if config != nil {
|
||||
|
||||
var httpMethod string
|
||||
if config.HttpMethod == "" {
|
||||
httpMethod = "HEAD"
|
||||
} else {
|
||||
httpMethod = strings.TrimSpace(config.HttpMethod)
|
||||
}
|
||||
|
||||
settings = &HealthPingSettings{
|
||||
Connectivity: strings.TrimSpace(config.Connectivity),
|
||||
Destination: strings.TrimSpace(config.Destination),
|
||||
Interval: time.Duration(config.Interval),
|
||||
SamplingCount: int(config.SamplingCount),
|
||||
Timeout: time.Duration(config.Timeout),
|
||||
HttpMethod: httpMethod,
|
||||
}
|
||||
}
|
||||
if settings.Destination == "" {
|
||||
@@ -164,7 +174,7 @@ func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int)
|
||||
}
|
||||
time.AfterFunc(delay, func() {
|
||||
errors.LogDebug(h.ctx, "checking ", handler)
|
||||
delay, err := client.MeasureDelay()
|
||||
delay, err := client.MeasureDelay(h.Settings.HttpMethod)
|
||||
if err == nil {
|
||||
ch <- &rtt{
|
||||
handler: handler,
|
||||
@@ -251,7 +261,7 @@ func (h *HealthPing) checkConnectivity() bool {
|
||||
h.Settings.Connectivity,
|
||||
h.Settings.Timeout,
|
||||
)
|
||||
if _, err := tester.MeasureDelay(); err != nil {
|
||||
if _, err := tester.MeasureDelay(h.Settings.HttpMethod); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
@@ -2,6 +2,7 @@ package burst
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@@ -51,20 +52,28 @@ func newHTTPClient(ctxv context.Context, dispatcher routing.Dispatcher, handler
|
||||
}
|
||||
|
||||
// MeasureDelay returns the delay time of the request to dest
|
||||
func (s *pingClient) MeasureDelay() (time.Duration, error) {
|
||||
func (s *pingClient) MeasureDelay(httpMethod string) (time.Duration, error) {
|
||||
if s.httpClient == nil {
|
||||
panic("pingClient not initialized")
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodHead, s.destination, nil)
|
||||
|
||||
req, err := http.NewRequest(httpMethod, s.destination, nil)
|
||||
if err != nil {
|
||||
return rttFailed, err
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
resp, err := s.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return rttFailed, err
|
||||
}
|
||||
// don't wait for body
|
||||
if httpMethod == http.MethodGet {
|
||||
_, err = io.Copy(io.Discard, resp.Body)
|
||||
if err != nil {
|
||||
return rttFailed, err
|
||||
}
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return time.Since(start), nil
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package command
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/app/commander"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
@@ -99,6 +100,28 @@ func (s *handlerServer) AlterInbound(ctx context.Context, request *AlterInboundR
|
||||
return &AlterInboundResponse{}, operation.ApplyInbound(ctx, handler)
|
||||
}
|
||||
|
||||
func (s *handlerServer) ListInbounds(ctx context.Context, request *ListInboundsRequest) (*ListInboundsResponse, error) {
|
||||
handlers := s.ihm.ListHandlers(ctx)
|
||||
response := &ListInboundsResponse{}
|
||||
if request.GetIsOnlyTags() {
|
||||
for _, handler := range handlers {
|
||||
response.Inbounds = append(response.Inbounds, &core.InboundHandlerConfig{
|
||||
Tag: handler.Tag(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
for _, handler := range handlers {
|
||||
response.Inbounds = append(response.Inbounds, &core.InboundHandlerConfig{
|
||||
Tag: handler.Tag(),
|
||||
ReceiverSettings: handler.ReceiverSettings(),
|
||||
ProxySettings: handler.ProxySettings(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *handlerServer) GetInboundUsers(ctx context.Context, request *GetInboundUserRequest) (*GetInboundUserResponse, error) {
|
||||
handler, err := s.ihm.GetHandler(ctx, request.Tag)
|
||||
if err != nil {
|
||||
@@ -164,6 +187,23 @@ func (s *handlerServer) AlterOutbound(ctx context.Context, request *AlterOutboun
|
||||
return &AlterOutboundResponse{}, operation.ApplyOutbound(ctx, handler)
|
||||
}
|
||||
|
||||
func (s *handlerServer) ListOutbounds(ctx context.Context, request *ListOutboundsRequest) (*ListOutboundsResponse, error) {
|
||||
handlers := s.ohm.ListHandlers(ctx)
|
||||
response := &ListOutboundsResponse{}
|
||||
for _, handler := range handlers {
|
||||
// Ignore gRPC outbound
|
||||
if _, ok := handler.(*commander.Outbound); ok {
|
||||
continue
|
||||
}
|
||||
response.Outbounds = append(response.Outbounds, &core.OutboundHandlerConfig{
|
||||
Tag: handler.Tag(),
|
||||
SenderSettings: handler.SenderSettings(),
|
||||
ProxySettings: handler.ProxySettings(),
|
||||
})
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *handlerServer) mustEmbedUnimplementedHandlerServiceServer() {}
|
||||
|
||||
type service struct {
|
||||
|
@@ -364,6 +364,96 @@ func (*AlterInboundResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
type ListInboundsRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
IsOnlyTags bool `protobuf:"varint,1,opt,name=isOnlyTags,proto3" json:"isOnlyTags,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ListInboundsRequest) Reset() {
|
||||
*x = ListInboundsRequest{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListInboundsRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListInboundsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ListInboundsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListInboundsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ListInboundsRequest) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *ListInboundsRequest) GetIsOnlyTags() bool {
|
||||
if x != nil {
|
||||
return x.IsOnlyTags
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ListInboundsResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Inbounds []*core.InboundHandlerConfig `protobuf:"bytes,1,rep,name=inbounds,proto3" json:"inbounds,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ListInboundsResponse) Reset() {
|
||||
*x = ListInboundsResponse{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListInboundsResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListInboundsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ListInboundsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListInboundsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ListInboundsResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *ListInboundsResponse) GetInbounds() []*core.InboundHandlerConfig {
|
||||
if x != nil {
|
||||
return x.Inbounds
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type GetInboundUserRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -375,7 +465,7 @@ type GetInboundUserRequest struct {
|
||||
|
||||
func (x *GetInboundUserRequest) Reset() {
|
||||
*x = GetInboundUserRequest{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -387,7 +477,7 @@ func (x *GetInboundUserRequest) String() string {
|
||||
func (*GetInboundUserRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetInboundUserRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -400,7 +490,7 @@ func (x *GetInboundUserRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetInboundUserRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetInboundUserRequest) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{8}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{10}
|
||||
}
|
||||
|
||||
func (x *GetInboundUserRequest) GetTag() string {
|
||||
@@ -427,7 +517,7 @@ type GetInboundUserResponse struct {
|
||||
|
||||
func (x *GetInboundUserResponse) Reset() {
|
||||
*x = GetInboundUserResponse{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -439,7 +529,7 @@ func (x *GetInboundUserResponse) String() string {
|
||||
func (*GetInboundUserResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetInboundUserResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -452,7 +542,7 @@ func (x *GetInboundUserResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetInboundUserResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetInboundUserResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{9}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{11}
|
||||
}
|
||||
|
||||
func (x *GetInboundUserResponse) GetUsers() []*protocol.User {
|
||||
@@ -472,7 +562,7 @@ type GetInboundUsersCountResponse struct {
|
||||
|
||||
func (x *GetInboundUsersCountResponse) Reset() {
|
||||
*x = GetInboundUsersCountResponse{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -484,7 +574,7 @@ func (x *GetInboundUsersCountResponse) String() string {
|
||||
func (*GetInboundUsersCountResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetInboundUsersCountResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -497,7 +587,7 @@ func (x *GetInboundUsersCountResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetInboundUsersCountResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetInboundUsersCountResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{10}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{12}
|
||||
}
|
||||
|
||||
func (x *GetInboundUsersCountResponse) GetCount() int64 {
|
||||
@@ -517,7 +607,7 @@ type AddOutboundRequest struct {
|
||||
|
||||
func (x *AddOutboundRequest) Reset() {
|
||||
*x = AddOutboundRequest{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -529,7 +619,7 @@ func (x *AddOutboundRequest) String() string {
|
||||
func (*AddOutboundRequest) ProtoMessage() {}
|
||||
|
||||
func (x *AddOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -542,7 +632,7 @@ func (x *AddOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use AddOutboundRequest.ProtoReflect.Descriptor instead.
|
||||
func (*AddOutboundRequest) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{11}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{13}
|
||||
}
|
||||
|
||||
func (x *AddOutboundRequest) GetOutbound() *core.OutboundHandlerConfig {
|
||||
@@ -560,7 +650,7 @@ type AddOutboundResponse struct {
|
||||
|
||||
func (x *AddOutboundResponse) Reset() {
|
||||
*x = AddOutboundResponse{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -572,7 +662,7 @@ func (x *AddOutboundResponse) String() string {
|
||||
func (*AddOutboundResponse) ProtoMessage() {}
|
||||
|
||||
func (x *AddOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -585,7 +675,7 @@ func (x *AddOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use AddOutboundResponse.ProtoReflect.Descriptor instead.
|
||||
func (*AddOutboundResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{12}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{14}
|
||||
}
|
||||
|
||||
type RemoveOutboundRequest struct {
|
||||
@@ -598,7 +688,7 @@ type RemoveOutboundRequest struct {
|
||||
|
||||
func (x *RemoveOutboundRequest) Reset() {
|
||||
*x = RemoveOutboundRequest{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[15]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -610,7 +700,7 @@ func (x *RemoveOutboundRequest) String() string {
|
||||
func (*RemoveOutboundRequest) ProtoMessage() {}
|
||||
|
||||
func (x *RemoveOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[15]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -623,7 +713,7 @@ func (x *RemoveOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use RemoveOutboundRequest.ProtoReflect.Descriptor instead.
|
||||
func (*RemoveOutboundRequest) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{13}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{15}
|
||||
}
|
||||
|
||||
func (x *RemoveOutboundRequest) GetTag() string {
|
||||
@@ -641,7 +731,7 @@ type RemoveOutboundResponse struct {
|
||||
|
||||
func (x *RemoveOutboundResponse) Reset() {
|
||||
*x = RemoveOutboundResponse{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[16]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -653,7 +743,7 @@ func (x *RemoveOutboundResponse) String() string {
|
||||
func (*RemoveOutboundResponse) ProtoMessage() {}
|
||||
|
||||
func (x *RemoveOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[16]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -666,7 +756,7 @@ func (x *RemoveOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use RemoveOutboundResponse.ProtoReflect.Descriptor instead.
|
||||
func (*RemoveOutboundResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{14}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{16}
|
||||
}
|
||||
|
||||
type AlterOutboundRequest struct {
|
||||
@@ -680,7 +770,7 @@ type AlterOutboundRequest struct {
|
||||
|
||||
func (x *AlterOutboundRequest) Reset() {
|
||||
*x = AlterOutboundRequest{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[15]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[17]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -692,7 +782,7 @@ func (x *AlterOutboundRequest) String() string {
|
||||
func (*AlterOutboundRequest) ProtoMessage() {}
|
||||
|
||||
func (x *AlterOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[15]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[17]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -705,7 +795,7 @@ func (x *AlterOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use AlterOutboundRequest.ProtoReflect.Descriptor instead.
|
||||
func (*AlterOutboundRequest) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{15}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{17}
|
||||
}
|
||||
|
||||
func (x *AlterOutboundRequest) GetTag() string {
|
||||
@@ -730,7 +820,7 @@ type AlterOutboundResponse struct {
|
||||
|
||||
func (x *AlterOutboundResponse) Reset() {
|
||||
*x = AlterOutboundResponse{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[16]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[18]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -742,7 +832,7 @@ func (x *AlterOutboundResponse) String() string {
|
||||
func (*AlterOutboundResponse) ProtoMessage() {}
|
||||
|
||||
func (x *AlterOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[16]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[18]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -755,7 +845,88 @@ func (x *AlterOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use AlterOutboundResponse.ProtoReflect.Descriptor instead.
|
||||
func (*AlterOutboundResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{16}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{18}
|
||||
}
|
||||
|
||||
type ListOutboundsRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *ListOutboundsRequest) Reset() {
|
||||
*x = ListOutboundsRequest{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[19]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListOutboundsRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListOutboundsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ListOutboundsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[19]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListOutboundsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ListOutboundsRequest) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{19}
|
||||
}
|
||||
|
||||
type ListOutboundsResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Outbounds []*core.OutboundHandlerConfig `protobuf:"bytes,1,rep,name=outbounds,proto3" json:"outbounds,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ListOutboundsResponse) Reset() {
|
||||
*x = ListOutboundsResponse{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[20]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListOutboundsResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListOutboundsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ListOutboundsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[20]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListOutboundsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ListOutboundsResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{20}
|
||||
}
|
||||
|
||||
func (x *ListOutboundsResponse) GetOutbounds() []*core.OutboundHandlerConfig {
|
||||
if x != nil {
|
||||
return x.Outbounds
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
@@ -766,7 +937,7 @@ type Config struct {
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[17]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[21]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -778,7 +949,7 @@ func (x *Config) String() string {
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[17]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[21]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -791,7 +962,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{17}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{21}
|
||||
}
|
||||
|
||||
var File_app_proxyman_command_command_proto protoreflect.FileDescriptor
|
||||
@@ -831,61 +1002,84 @@ var file_app_proxyman_command_command_proto_rawDesc = []byte{
|
||||
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, 0x3f, 0x0a, 0x15,
|
||||
0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 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, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x4a, 0x0a,
|
||||
0x16, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73,
|
||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 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, 0x22, 0x34, 0x0a, 0x1c, 0x47, 0x65, 0x74,
|
||||
0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x43, 0x6f, 0x75, 0x6e,
|
||||
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75,
|
||||
0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22,
|
||||
0x52, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 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,
|
||||
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x35, 0x0a, 0x13,
|
||||
0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x54, 0x61, 0x67,
|
||||
0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x54,
|
||||
0x61, 0x67, 0x73, 0x22, 0x53, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75,
|
||||
0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x69,
|
||||
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e,
|
||||
0x78, 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, 0x08,
|
||||
0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x22, 0x3f, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x49,
|
||||
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 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, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x4a, 0x0a, 0x16, 0x47, 0x65, 0x74,
|
||||
0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 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, 0x22, 0x34, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f,
|
||||
0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x52, 0x0a, 0x12, 0x41,
|
||||
0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x12, 0x3c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 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, 0x68, 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, 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,
|
||||
0x68, 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, 0x3e, 0x0a, 0x09, 0x6f, 0x70, 0x65,
|
||||
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61,
|
||||
0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 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, 0xc5, 0x07, 0x0a,
|
||||
0x0e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||
0x6b, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2c, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 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, 0x2d, 0x2e, 0x78, 0x72,
|
||||
0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x3e, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79,
|
||||
0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 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, 0x16,
|
||||
0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x57, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75,
|
||||
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x3e, 0x0a, 0x09, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 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, 0x09, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x22,
|
||||
0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0xae, 0x09, 0x0a, 0x0e, 0x48, 0x61,
|
||||
0x6e, 0x64, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6b, 0x0a, 0x0a,
|
||||
0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2c, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 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, 0x2d, 0x2e, 0x78, 0x72, 0x61, 0x79, 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, 0x74, 0x0a, 0x0d, 0x52, 0x65, 0x6d,
|
||||
0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2f, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 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, 0x30, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 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, 0x74, 0x0a, 0x0d,
|
||||
0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2f, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 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, 0x30,
|
||||
0x2e, 0x78, 0x72, 0x61, 0x79, 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, 0x71, 0x0a, 0x0c, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75,
|
||||
0x6e, 0x64, 0x12, 0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 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,
|
||||
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,
|
||||
0x71, 0x0a, 0x0c, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12,
|
||||
0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 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,
|
||||
0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 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, 0x71, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
|
||||
0x64, 0x73, 0x12, 0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 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,
|
||||
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x78, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f,
|
||||
0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
@@ -924,14 +1118,22 @@ var file_app_proxyman_command_command_proto_rawDesc = []byte{
|
||||
0x1a, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 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, 0x6d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f,
|
||||
0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x19, 0x58, 0x72, 0x61, 0x79, 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,
|
||||
0x73, 0x65, 0x22, 0x00, 0x12, 0x74, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x62,
|
||||
0x6f, 0x75, 0x6e, 0x64, 0x73, 0x12, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
||||
0x64, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
||||
0x6e, 0x64, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f,
|
||||
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||
0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2e, 0x67,
|
||||
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f,
|
||||
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x19,
|
||||
0x58, 0x72, 0x61, 0x79, 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 (
|
||||
@@ -946,7 +1148,7 @@ func file_app_proxyman_command_command_proto_rawDescGZIP() []byte {
|
||||
return file_app_proxyman_command_command_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_app_proxyman_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 18)
|
||||
var file_app_proxyman_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 22)
|
||||
var file_app_proxyman_command_command_proto_goTypes = []any{
|
||||
(*AddUserOperation)(nil), // 0: xray.app.proxyman.command.AddUserOperation
|
||||
(*RemoveUserOperation)(nil), // 1: xray.app.proxyman.command.RemoveUserOperation
|
||||
@@ -956,49 +1158,59 @@ var file_app_proxyman_command_command_proto_goTypes = []any{
|
||||
(*RemoveInboundResponse)(nil), // 5: xray.app.proxyman.command.RemoveInboundResponse
|
||||
(*AlterInboundRequest)(nil), // 6: xray.app.proxyman.command.AlterInboundRequest
|
||||
(*AlterInboundResponse)(nil), // 7: xray.app.proxyman.command.AlterInboundResponse
|
||||
(*GetInboundUserRequest)(nil), // 8: xray.app.proxyman.command.GetInboundUserRequest
|
||||
(*GetInboundUserResponse)(nil), // 9: xray.app.proxyman.command.GetInboundUserResponse
|
||||
(*GetInboundUsersCountResponse)(nil), // 10: xray.app.proxyman.command.GetInboundUsersCountResponse
|
||||
(*AddOutboundRequest)(nil), // 11: xray.app.proxyman.command.AddOutboundRequest
|
||||
(*AddOutboundResponse)(nil), // 12: xray.app.proxyman.command.AddOutboundResponse
|
||||
(*RemoveOutboundRequest)(nil), // 13: xray.app.proxyman.command.RemoveOutboundRequest
|
||||
(*RemoveOutboundResponse)(nil), // 14: xray.app.proxyman.command.RemoveOutboundResponse
|
||||
(*AlterOutboundRequest)(nil), // 15: xray.app.proxyman.command.AlterOutboundRequest
|
||||
(*AlterOutboundResponse)(nil), // 16: xray.app.proxyman.command.AlterOutboundResponse
|
||||
(*Config)(nil), // 17: xray.app.proxyman.command.Config
|
||||
(*protocol.User)(nil), // 18: xray.common.protocol.User
|
||||
(*core.InboundHandlerConfig)(nil), // 19: xray.core.InboundHandlerConfig
|
||||
(*serial.TypedMessage)(nil), // 20: xray.common.serial.TypedMessage
|
||||
(*core.OutboundHandlerConfig)(nil), // 21: xray.core.OutboundHandlerConfig
|
||||
(*ListInboundsRequest)(nil), // 8: xray.app.proxyman.command.ListInboundsRequest
|
||||
(*ListInboundsResponse)(nil), // 9: xray.app.proxyman.command.ListInboundsResponse
|
||||
(*GetInboundUserRequest)(nil), // 10: xray.app.proxyman.command.GetInboundUserRequest
|
||||
(*GetInboundUserResponse)(nil), // 11: xray.app.proxyman.command.GetInboundUserResponse
|
||||
(*GetInboundUsersCountResponse)(nil), // 12: xray.app.proxyman.command.GetInboundUsersCountResponse
|
||||
(*AddOutboundRequest)(nil), // 13: xray.app.proxyman.command.AddOutboundRequest
|
||||
(*AddOutboundResponse)(nil), // 14: xray.app.proxyman.command.AddOutboundResponse
|
||||
(*RemoveOutboundRequest)(nil), // 15: xray.app.proxyman.command.RemoveOutboundRequest
|
||||
(*RemoveOutboundResponse)(nil), // 16: xray.app.proxyman.command.RemoveOutboundResponse
|
||||
(*AlterOutboundRequest)(nil), // 17: xray.app.proxyman.command.AlterOutboundRequest
|
||||
(*AlterOutboundResponse)(nil), // 18: xray.app.proxyman.command.AlterOutboundResponse
|
||||
(*ListOutboundsRequest)(nil), // 19: xray.app.proxyman.command.ListOutboundsRequest
|
||||
(*ListOutboundsResponse)(nil), // 20: xray.app.proxyman.command.ListOutboundsResponse
|
||||
(*Config)(nil), // 21: xray.app.proxyman.command.Config
|
||||
(*protocol.User)(nil), // 22: xray.common.protocol.User
|
||||
(*core.InboundHandlerConfig)(nil), // 23: xray.core.InboundHandlerConfig
|
||||
(*serial.TypedMessage)(nil), // 24: xray.common.serial.TypedMessage
|
||||
(*core.OutboundHandlerConfig)(nil), // 25: xray.core.OutboundHandlerConfig
|
||||
}
|
||||
var file_app_proxyman_command_command_proto_depIdxs = []int32{
|
||||
18, // 0: xray.app.proxyman.command.AddUserOperation.user:type_name -> xray.common.protocol.User
|
||||
19, // 1: xray.app.proxyman.command.AddInboundRequest.inbound:type_name -> xray.core.InboundHandlerConfig
|
||||
20, // 2: xray.app.proxyman.command.AlterInboundRequest.operation:type_name -> xray.common.serial.TypedMessage
|
||||
18, // 3: xray.app.proxyman.command.GetInboundUserResponse.users:type_name -> xray.common.protocol.User
|
||||
21, // 4: xray.app.proxyman.command.AddOutboundRequest.outbound:type_name -> xray.core.OutboundHandlerConfig
|
||||
20, // 5: xray.app.proxyman.command.AlterOutboundRequest.operation:type_name -> xray.common.serial.TypedMessage
|
||||
2, // 6: xray.app.proxyman.command.HandlerService.AddInbound:input_type -> xray.app.proxyman.command.AddInboundRequest
|
||||
4, // 7: xray.app.proxyman.command.HandlerService.RemoveInbound:input_type -> xray.app.proxyman.command.RemoveInboundRequest
|
||||
6, // 8: xray.app.proxyman.command.HandlerService.AlterInbound:input_type -> xray.app.proxyman.command.AlterInboundRequest
|
||||
8, // 9: xray.app.proxyman.command.HandlerService.GetInboundUsers:input_type -> xray.app.proxyman.command.GetInboundUserRequest
|
||||
8, // 10: xray.app.proxyman.command.HandlerService.GetInboundUsersCount:input_type -> xray.app.proxyman.command.GetInboundUserRequest
|
||||
11, // 11: xray.app.proxyman.command.HandlerService.AddOutbound:input_type -> xray.app.proxyman.command.AddOutboundRequest
|
||||
13, // 12: xray.app.proxyman.command.HandlerService.RemoveOutbound:input_type -> xray.app.proxyman.command.RemoveOutboundRequest
|
||||
15, // 13: xray.app.proxyman.command.HandlerService.AlterOutbound:input_type -> xray.app.proxyman.command.AlterOutboundRequest
|
||||
3, // 14: xray.app.proxyman.command.HandlerService.AddInbound:output_type -> xray.app.proxyman.command.AddInboundResponse
|
||||
5, // 15: xray.app.proxyman.command.HandlerService.RemoveInbound:output_type -> xray.app.proxyman.command.RemoveInboundResponse
|
||||
7, // 16: xray.app.proxyman.command.HandlerService.AlterInbound:output_type -> xray.app.proxyman.command.AlterInboundResponse
|
||||
9, // 17: xray.app.proxyman.command.HandlerService.GetInboundUsers:output_type -> xray.app.proxyman.command.GetInboundUserResponse
|
||||
10, // 18: xray.app.proxyman.command.HandlerService.GetInboundUsersCount:output_type -> xray.app.proxyman.command.GetInboundUsersCountResponse
|
||||
12, // 19: xray.app.proxyman.command.HandlerService.AddOutbound:output_type -> xray.app.proxyman.command.AddOutboundResponse
|
||||
14, // 20: xray.app.proxyman.command.HandlerService.RemoveOutbound:output_type -> xray.app.proxyman.command.RemoveOutboundResponse
|
||||
16, // 21: xray.app.proxyman.command.HandlerService.AlterOutbound:output_type -> xray.app.proxyman.command.AlterOutboundResponse
|
||||
14, // [14:22] is the sub-list for method output_type
|
||||
6, // [6:14] is the sub-list for method input_type
|
||||
6, // [6:6] is the sub-list for extension type_name
|
||||
6, // [6:6] is the sub-list for extension extendee
|
||||
0, // [0:6] is the sub-list for field type_name
|
||||
22, // 0: xray.app.proxyman.command.AddUserOperation.user:type_name -> xray.common.protocol.User
|
||||
23, // 1: xray.app.proxyman.command.AddInboundRequest.inbound:type_name -> xray.core.InboundHandlerConfig
|
||||
24, // 2: xray.app.proxyman.command.AlterInboundRequest.operation:type_name -> xray.common.serial.TypedMessage
|
||||
23, // 3: xray.app.proxyman.command.ListInboundsResponse.inbounds:type_name -> xray.core.InboundHandlerConfig
|
||||
22, // 4: xray.app.proxyman.command.GetInboundUserResponse.users:type_name -> xray.common.protocol.User
|
||||
25, // 5: xray.app.proxyman.command.AddOutboundRequest.outbound:type_name -> xray.core.OutboundHandlerConfig
|
||||
24, // 6: xray.app.proxyman.command.AlterOutboundRequest.operation:type_name -> xray.common.serial.TypedMessage
|
||||
25, // 7: xray.app.proxyman.command.ListOutboundsResponse.outbounds:type_name -> xray.core.OutboundHandlerConfig
|
||||
2, // 8: xray.app.proxyman.command.HandlerService.AddInbound:input_type -> xray.app.proxyman.command.AddInboundRequest
|
||||
4, // 9: xray.app.proxyman.command.HandlerService.RemoveInbound:input_type -> xray.app.proxyman.command.RemoveInboundRequest
|
||||
6, // 10: xray.app.proxyman.command.HandlerService.AlterInbound:input_type -> xray.app.proxyman.command.AlterInboundRequest
|
||||
8, // 11: xray.app.proxyman.command.HandlerService.ListInbounds:input_type -> xray.app.proxyman.command.ListInboundsRequest
|
||||
10, // 12: xray.app.proxyman.command.HandlerService.GetInboundUsers:input_type -> xray.app.proxyman.command.GetInboundUserRequest
|
||||
10, // 13: xray.app.proxyman.command.HandlerService.GetInboundUsersCount:input_type -> xray.app.proxyman.command.GetInboundUserRequest
|
||||
13, // 14: xray.app.proxyman.command.HandlerService.AddOutbound:input_type -> xray.app.proxyman.command.AddOutboundRequest
|
||||
15, // 15: xray.app.proxyman.command.HandlerService.RemoveOutbound:input_type -> xray.app.proxyman.command.RemoveOutboundRequest
|
||||
17, // 16: xray.app.proxyman.command.HandlerService.AlterOutbound:input_type -> xray.app.proxyman.command.AlterOutboundRequest
|
||||
19, // 17: xray.app.proxyman.command.HandlerService.ListOutbounds:input_type -> xray.app.proxyman.command.ListOutboundsRequest
|
||||
3, // 18: xray.app.proxyman.command.HandlerService.AddInbound:output_type -> xray.app.proxyman.command.AddInboundResponse
|
||||
5, // 19: xray.app.proxyman.command.HandlerService.RemoveInbound:output_type -> xray.app.proxyman.command.RemoveInboundResponse
|
||||
7, // 20: xray.app.proxyman.command.HandlerService.AlterInbound:output_type -> xray.app.proxyman.command.AlterInboundResponse
|
||||
9, // 21: xray.app.proxyman.command.HandlerService.ListInbounds:output_type -> xray.app.proxyman.command.ListInboundsResponse
|
||||
11, // 22: xray.app.proxyman.command.HandlerService.GetInboundUsers:output_type -> xray.app.proxyman.command.GetInboundUserResponse
|
||||
12, // 23: xray.app.proxyman.command.HandlerService.GetInboundUsersCount:output_type -> xray.app.proxyman.command.GetInboundUsersCountResponse
|
||||
14, // 24: xray.app.proxyman.command.HandlerService.AddOutbound:output_type -> xray.app.proxyman.command.AddOutboundResponse
|
||||
16, // 25: xray.app.proxyman.command.HandlerService.RemoveOutbound:output_type -> xray.app.proxyman.command.RemoveOutboundResponse
|
||||
18, // 26: xray.app.proxyman.command.HandlerService.AlterOutbound:output_type -> xray.app.proxyman.command.AlterOutboundResponse
|
||||
20, // 27: xray.app.proxyman.command.HandlerService.ListOutbounds:output_type -> xray.app.proxyman.command.ListOutboundsResponse
|
||||
18, // [18:28] is the sub-list for method output_type
|
||||
8, // [8:18] is the sub-list for method input_type
|
||||
8, // [8:8] is the sub-list for extension type_name
|
||||
8, // [8:8] is the sub-list for extension extendee
|
||||
0, // [0:8] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_app_proxyman_command_command_proto_init() }
|
||||
@@ -1012,7 +1224,7 @@ func file_app_proxyman_command_command_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_app_proxyman_command_command_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 18,
|
||||
NumMessages: 22,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
@@ -37,6 +37,14 @@ message AlterInboundRequest {
|
||||
|
||||
message AlterInboundResponse {}
|
||||
|
||||
message ListInboundsRequest {
|
||||
bool isOnlyTags = 1;
|
||||
}
|
||||
|
||||
message ListInboundsResponse {
|
||||
repeated core.InboundHandlerConfig inbounds = 1;
|
||||
}
|
||||
|
||||
message GetInboundUserRequest {
|
||||
string tag = 1;
|
||||
string email = 2;
|
||||
@@ -69,6 +77,12 @@ message AlterOutboundRequest {
|
||||
|
||||
message AlterOutboundResponse {}
|
||||
|
||||
message ListOutboundsRequest {}
|
||||
|
||||
message ListOutboundsResponse {
|
||||
repeated core.OutboundHandlerConfig outbounds = 1;
|
||||
}
|
||||
|
||||
service HandlerService {
|
||||
rpc AddInbound(AddInboundRequest) returns (AddInboundResponse) {}
|
||||
|
||||
@@ -76,6 +90,8 @@ service HandlerService {
|
||||
|
||||
rpc AlterInbound(AlterInboundRequest) returns (AlterInboundResponse) {}
|
||||
|
||||
rpc ListInbounds(ListInboundsRequest) returns (ListInboundsResponse) {}
|
||||
|
||||
rpc GetInboundUsers(GetInboundUserRequest) returns (GetInboundUserResponse) {}
|
||||
|
||||
rpc GetInboundUsersCount(GetInboundUserRequest) returns (GetInboundUsersCountResponse) {}
|
||||
@@ -85,6 +101,8 @@ service HandlerService {
|
||||
rpc RemoveOutbound(RemoveOutboundRequest) returns (RemoveOutboundResponse) {}
|
||||
|
||||
rpc AlterOutbound(AlterOutboundRequest) returns (AlterOutboundResponse) {}
|
||||
|
||||
rpc ListOutbounds(ListOutboundsRequest) returns (ListOutboundsResponse) {}
|
||||
}
|
||||
|
||||
message Config {}
|
||||
|
@@ -22,11 +22,13 @@ const (
|
||||
HandlerService_AddInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AddInbound"
|
||||
HandlerService_RemoveInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/RemoveInbound"
|
||||
HandlerService_AlterInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AlterInbound"
|
||||
HandlerService_ListInbounds_FullMethodName = "/xray.app.proxyman.command.HandlerService/ListInbounds"
|
||||
HandlerService_GetInboundUsers_FullMethodName = "/xray.app.proxyman.command.HandlerService/GetInboundUsers"
|
||||
HandlerService_GetInboundUsersCount_FullMethodName = "/xray.app.proxyman.command.HandlerService/GetInboundUsersCount"
|
||||
HandlerService_AddOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AddOutbound"
|
||||
HandlerService_RemoveOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/RemoveOutbound"
|
||||
HandlerService_AlterOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AlterOutbound"
|
||||
HandlerService_ListOutbounds_FullMethodName = "/xray.app.proxyman.command.HandlerService/ListOutbounds"
|
||||
)
|
||||
|
||||
// HandlerServiceClient is the client API for HandlerService service.
|
||||
@@ -36,11 +38,13 @@ 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)
|
||||
ListInbounds(ctx context.Context, in *ListInboundsRequest, opts ...grpc.CallOption) (*ListInboundsResponse, error)
|
||||
GetInboundUsers(ctx context.Context, in *GetInboundUserRequest, opts ...grpc.CallOption) (*GetInboundUserResponse, error)
|
||||
GetInboundUsersCount(ctx context.Context, in *GetInboundUserRequest, opts ...grpc.CallOption) (*GetInboundUsersCountResponse, 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)
|
||||
ListOutbounds(ctx context.Context, in *ListOutboundsRequest, opts ...grpc.CallOption) (*ListOutboundsResponse, error)
|
||||
}
|
||||
|
||||
type handlerServiceClient struct {
|
||||
@@ -81,6 +85,16 @@ func (c *handlerServiceClient) AlterInbound(ctx context.Context, in *AlterInboun
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *handlerServiceClient) ListInbounds(ctx context.Context, in *ListInboundsRequest, opts ...grpc.CallOption) (*ListInboundsResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListInboundsResponse)
|
||||
err := c.cc.Invoke(ctx, HandlerService_ListInbounds_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *handlerServiceClient) GetInboundUsers(ctx context.Context, in *GetInboundUserRequest, opts ...grpc.CallOption) (*GetInboundUserResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetInboundUserResponse)
|
||||
@@ -131,6 +145,16 @@ func (c *handlerServiceClient) AlterOutbound(ctx context.Context, in *AlterOutbo
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *handlerServiceClient) ListOutbounds(ctx context.Context, in *ListOutboundsRequest, opts ...grpc.CallOption) (*ListOutboundsResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListOutboundsResponse)
|
||||
err := c.cc.Invoke(ctx, HandlerService_ListOutbounds_FullMethodName, in, out, cOpts...)
|
||||
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.
|
||||
@@ -138,11 +162,13 @@ type HandlerServiceServer interface {
|
||||
AddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error)
|
||||
RemoveInbound(context.Context, *RemoveInboundRequest) (*RemoveInboundResponse, error)
|
||||
AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error)
|
||||
ListInbounds(context.Context, *ListInboundsRequest) (*ListInboundsResponse, error)
|
||||
GetInboundUsers(context.Context, *GetInboundUserRequest) (*GetInboundUserResponse, error)
|
||||
GetInboundUsersCount(context.Context, *GetInboundUserRequest) (*GetInboundUsersCountResponse, error)
|
||||
AddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error)
|
||||
RemoveOutbound(context.Context, *RemoveOutboundRequest) (*RemoveOutboundResponse, error)
|
||||
AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error)
|
||||
ListOutbounds(context.Context, *ListOutboundsRequest) (*ListOutboundsResponse, error)
|
||||
mustEmbedUnimplementedHandlerServiceServer()
|
||||
}
|
||||
|
||||
@@ -162,6 +188,9 @@ func (UnimplementedHandlerServiceServer) RemoveInbound(context.Context, *RemoveI
|
||||
func (UnimplementedHandlerServiceServer) AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AlterInbound not implemented")
|
||||
}
|
||||
func (UnimplementedHandlerServiceServer) ListInbounds(context.Context, *ListInboundsRequest) (*ListInboundsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListInbounds not implemented")
|
||||
}
|
||||
func (UnimplementedHandlerServiceServer) GetInboundUsers(context.Context, *GetInboundUserRequest) (*GetInboundUserResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetInboundUsers not implemented")
|
||||
}
|
||||
@@ -177,6 +206,9 @@ func (UnimplementedHandlerServiceServer) RemoveOutbound(context.Context, *Remove
|
||||
func (UnimplementedHandlerServiceServer) AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AlterOutbound not implemented")
|
||||
}
|
||||
func (UnimplementedHandlerServiceServer) ListOutbounds(context.Context, *ListOutboundsRequest) (*ListOutboundsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListOutbounds not implemented")
|
||||
}
|
||||
func (UnimplementedHandlerServiceServer) mustEmbedUnimplementedHandlerServiceServer() {}
|
||||
func (UnimplementedHandlerServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
@@ -252,6 +284,24 @@ func _HandlerService_AlterInbound_Handler(srv interface{}, ctx context.Context,
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _HandlerService_ListInbounds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListInboundsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(HandlerServiceServer).ListInbounds(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: HandlerService_ListInbounds_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(HandlerServiceServer).ListInbounds(ctx, req.(*ListInboundsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _HandlerService_GetInboundUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetInboundUserRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@@ -342,6 +392,24 @@ func _HandlerService_AlterOutbound_Handler(srv interface{}, ctx context.Context,
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _HandlerService_ListOutbounds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListOutboundsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(HandlerServiceServer).ListOutbounds(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: HandlerService_ListOutbounds_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(HandlerServiceServer).ListOutbounds(ctx, req.(*ListOutboundsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// HandlerService_ServiceDesc is the grpc.ServiceDesc for HandlerService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@@ -361,6 +429,10 @@ var HandlerService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "AlterInbound",
|
||||
Handler: _HandlerService_AlterInbound_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListInbounds",
|
||||
Handler: _HandlerService_ListInbounds_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetInboundUsers",
|
||||
Handler: _HandlerService_GetInboundUsers_Handler,
|
||||
@@ -381,6 +453,10 @@ var HandlerService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "AlterOutbound",
|
||||
Handler: _HandlerService_AlterOutbound_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListOutbounds",
|
||||
Handler: _HandlerService_ListOutbounds_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "app/proxyman/command/command.proto",
|
||||
|
@@ -9,11 +9,13 @@ import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/policy"
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {
|
||||
@@ -42,10 +44,12 @@ func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter)
|
||||
}
|
||||
|
||||
type AlwaysOnInboundHandler struct {
|
||||
proxy proxy.Inbound
|
||||
workers []worker
|
||||
mux *mux.Server
|
||||
tag string
|
||||
proxyConfig interface{}
|
||||
receiverConfig *proxyman.ReceiverConfig
|
||||
proxy proxy.Inbound
|
||||
workers []worker
|
||||
mux *mux.Server
|
||||
tag string
|
||||
}
|
||||
|
||||
func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*AlwaysOnInboundHandler, error) {
|
||||
@@ -59,9 +63,11 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
||||
}
|
||||
|
||||
h := &AlwaysOnInboundHandler{
|
||||
proxy: p,
|
||||
mux: mux.NewServer(ctx),
|
||||
tag: tag,
|
||||
receiverConfig: receiverConfig,
|
||||
proxyConfig: proxyConfig,
|
||||
proxy: p,
|
||||
mux: mux.NewServer(ctx),
|
||||
tag: tag,
|
||||
}
|
||||
|
||||
uplinkCounter, downlinkCounter := getStatCounter(core.MustFromContext(ctx), tag)
|
||||
@@ -187,3 +193,16 @@ func (h *AlwaysOnInboundHandler) Tag() string {
|
||||
func (h *AlwaysOnInboundHandler) GetInbound() proxy.Inbound {
|
||||
return h.proxy
|
||||
}
|
||||
|
||||
// ReceiverSettings implements inbound.Handler.
|
||||
func (h *AlwaysOnInboundHandler) ReceiverSettings() *serial.TypedMessage {
|
||||
return serial.ToTypedMessage(h.receiverConfig)
|
||||
}
|
||||
|
||||
// ProxySettings implements inbound.Handler.
|
||||
func (h *AlwaysOnInboundHandler) ProxySettings() *serial.TypedMessage {
|
||||
if v, ok := h.proxyConfig.(proto.Message); ok {
|
||||
return serial.ToTypedMessage(v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -10,10 +10,12 @@ import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type DynamicInboundHandler struct {
|
||||
@@ -205,3 +207,16 @@ func (h *DynamicInboundHandler) GetRandomInboundProxy() (interface{}, net.Port,
|
||||
func (h *DynamicInboundHandler) Tag() string {
|
||||
return h.tag
|
||||
}
|
||||
|
||||
// ReceiverSettings implements inbound.Handler.
|
||||
func (h *DynamicInboundHandler) ReceiverSettings() *serial.TypedMessage {
|
||||
return serial.ToTypedMessage(h.receiverConfig)
|
||||
}
|
||||
|
||||
// ProxySettings implements inbound.Handler.
|
||||
func (h *DynamicInboundHandler) ProxySettings() *serial.TypedMessage {
|
||||
if v, ok := h.proxyConfig.(proto.Message); ok {
|
||||
return serial.ToTypedMessage(v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ import (
|
||||
// Manager manages all inbound handlers.
|
||||
type Manager struct {
|
||||
access sync.RWMutex
|
||||
untaggedHandler []inbound.Handler
|
||||
untaggedHandlers []inbound.Handler
|
||||
taggedHandlers map[string]inbound.Handler
|
||||
running bool
|
||||
}
|
||||
@@ -47,7 +47,7 @@ func (m *Manager) AddHandler(ctx context.Context, handler inbound.Handler) error
|
||||
}
|
||||
m.taggedHandlers[tag] = handler
|
||||
} else {
|
||||
m.untaggedHandler = append(m.untaggedHandler, handler)
|
||||
m.untaggedHandlers = append(m.untaggedHandlers, handler)
|
||||
}
|
||||
|
||||
if m.running {
|
||||
@@ -89,6 +89,21 @@ func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
|
||||
return common.ErrNoClue
|
||||
}
|
||||
|
||||
// ListHandlers implements inbound.Manager.
|
||||
func (m *Manager) ListHandlers(ctx context.Context) []inbound.Handler {
|
||||
m.access.RLock()
|
||||
defer m.access.RUnlock()
|
||||
|
||||
response := make([]inbound.Handler, len(m.untaggedHandlers))
|
||||
copy(response, m.untaggedHandlers)
|
||||
|
||||
for _, v := range m.taggedHandlers {
|
||||
response = append(response, v)
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
// Start implements common.Runnable.
|
||||
func (m *Manager) Start() error {
|
||||
m.access.Lock()
|
||||
@@ -102,7 +117,7 @@ func (m *Manager) Start() error {
|
||||
}
|
||||
}
|
||||
|
||||
for _, handler := range m.untaggedHandler {
|
||||
for _, handler := range m.untaggedHandlers {
|
||||
if err := handler.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -123,7 +138,7 @@ func (m *Manager) Close() error {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
for _, handler := range m.untaggedHandler {
|
||||
for _, handler := range m.untaggedHandlers {
|
||||
if err := handler.Close(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
@@ -91,6 +91,7 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
||||
}
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||
Source: net.DestinationFromAddr(conn.RemoteAddr()),
|
||||
Local: net.DestinationFromAddr(conn.LocalAddr()),
|
||||
Gateway: net.TCPDestination(w.address, w.port),
|
||||
Tag: w.tag,
|
||||
Conn: conn,
|
||||
@@ -161,6 +162,7 @@ type udpConn struct {
|
||||
uplink stats.Counter
|
||||
downlink stats.Counter
|
||||
inactive bool
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (c *udpConn) setInactive() {
|
||||
@@ -203,6 +205,9 @@ func (c *udpConn) Write(buf []byte) (int, error) {
|
||||
}
|
||||
|
||||
func (c *udpConn) Close() error {
|
||||
if c.cancel != nil {
|
||||
c.cancel()
|
||||
}
|
||||
common.Must(c.done.Close())
|
||||
common.Must(common.Close(c.writer))
|
||||
return nil
|
||||
@@ -259,6 +264,7 @@ func (w *udpWorker) getConnection(id connID) (*udpConn, bool) {
|
||||
defer w.Unlock()
|
||||
|
||||
if conn, found := w.activeConn[id]; found && !conn.done.Done() {
|
||||
conn.updateActivity()
|
||||
return conn, true
|
||||
}
|
||||
|
||||
@@ -306,7 +312,8 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
||||
common.Must(w.checker.Start())
|
||||
|
||||
go func() {
|
||||
ctx := w.ctx
|
||||
ctx, cancel := context.WithCancel(w.ctx)
|
||||
conn.cancel = cancel
|
||||
sid := session.NewID()
|
||||
ctx = c.ContextWithID(ctx, sid)
|
||||
|
||||
@@ -315,8 +322,10 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
||||
outbounds[0].Target = originalDest
|
||||
}
|
||||
ctx = session.ContextWithOutbounds(ctx, outbounds)
|
||||
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||
Source: source,
|
||||
Local: net.DestinationFromAddr(w.hub.Addr()),
|
||||
Gateway: net.UDPDestination(w.address, w.port),
|
||||
Tag: w.tag,
|
||||
})
|
||||
@@ -466,6 +475,7 @@ func (w *dsWorker) callback(conn stat.Connection) {
|
||||
}
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||
Source: net.DestinationFromAddr(conn.RemoteAddr()),
|
||||
Local: net.DestinationFromAddr(conn.LocalAddr()),
|
||||
Gateway: net.UnixDestination(w.address),
|
||||
Tag: w.tag,
|
||||
Conn: conn,
|
||||
|
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/net/cnc"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
@@ -27,6 +28,7 @@ import (
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
"github.com/xtls/xray-core/transport/pipe"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {
|
||||
@@ -59,6 +61,7 @@ type Handler struct {
|
||||
tag string
|
||||
senderSettings *proxyman.SenderConfig
|
||||
streamSettings *internet.MemoryStreamConfig
|
||||
proxyConfig proto.Message
|
||||
proxy proxy.Outbound
|
||||
outboundManager outbound.Manager
|
||||
mux *mux.ClientManager
|
||||
@@ -101,6 +104,7 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.proxyConfig = proxyConfig
|
||||
|
||||
rawProxyHandler, err := common.CreateObject(ctx, proxyConfig)
|
||||
if err != nil {
|
||||
@@ -241,7 +245,9 @@ func (h *Handler) DestIpAddress() net.IP {
|
||||
// Dial implements internet.Dialer.
|
||||
func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connection, error) {
|
||||
if h.senderSettings != nil {
|
||||
|
||||
if h.senderSettings.ProxySettings.HasTag() {
|
||||
|
||||
tag := h.senderSettings.ProxySettings.Tag
|
||||
handler := h.outboundManager.GetHandler(tag)
|
||||
if handler != nil {
|
||||
@@ -270,22 +276,44 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
||||
}
|
||||
|
||||
if h.senderSettings.Via != nil {
|
||||
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
if h.senderSettings.ViaCidr == "" {
|
||||
if h.senderSettings.Via.AsAddress().Family().IsDomain() && h.senderSettings.Via.AsAddress().Domain() == "origin" {
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
var domain string
|
||||
addr := h.senderSettings.Via.AsAddress()
|
||||
domain = h.senderSettings.Via.GetDomain()
|
||||
switch {
|
||||
case h.senderSettings.ViaCidr != "":
|
||||
ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr)
|
||||
|
||||
case domain == "origin":
|
||||
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if inbound.Conn != nil {
|
||||
origin, _, err := net.SplitHostPort(inbound.Conn.LocalAddr().String())
|
||||
if err == nil {
|
||||
ob.Gateway = net.ParseAddress(origin)
|
||||
errors.LogDebug(ctx, "use receive package ip as snedthrough: ", origin)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ob.Gateway = h.senderSettings.Via.AsAddress()
|
||||
}
|
||||
} else { //Get a random address.
|
||||
ob.Gateway = ParseRandomIPv6(h.senderSettings.Via.AsAddress(), h.senderSettings.ViaCidr)
|
||||
case domain == "srcip":
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if inbound.Conn != nil {
|
||||
clientaddr, _, err := net.SplitHostPort(inbound.Conn.RemoteAddr().String())
|
||||
if err == nil {
|
||||
ob.Gateway = net.ParseAddress(clientaddr)
|
||||
errors.LogDebug(ctx, "use client src ip as snedthrough: ", clientaddr)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//case addr.Family().IsDomain():
|
||||
default:
|
||||
ob.Gateway = addr
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,23 +353,35 @@ func (h *Handler) Start() error {
|
||||
// Close implements common.Closable.
|
||||
func (h *Handler) Close() error {
|
||||
common.Close(h.mux)
|
||||
common.Close(h.proxy)
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseRandomIPv6(address net.Address, prefix string) net.Address {
|
||||
_, network, _ := gonet.ParseCIDR(address.IP().String() + "/" + prefix)
|
||||
|
||||
maskSize, totalBits := network.Mask.Size()
|
||||
subnetSize := big.NewInt(1).Lsh(big.NewInt(1), uint(totalBits-maskSize))
|
||||
|
||||
// random
|
||||
randomBigInt, _ := rand.Int(rand.Reader, subnetSize)
|
||||
|
||||
startIPBigInt := big.NewInt(0).SetBytes(network.IP.To16())
|
||||
randomIPBigInt := big.NewInt(0).Add(startIPBigInt, randomBigInt)
|
||||
|
||||
randomIPBytes := randomIPBigInt.Bytes()
|
||||
randomIPBytes = append(make([]byte, 16-len(randomIPBytes)), randomIPBytes...)
|
||||
|
||||
return net.ParseAddress(gonet.IP(randomIPBytes).String())
|
||||
// SenderSettings implements outbound.Handler.
|
||||
func (h *Handler) SenderSettings() *serial.TypedMessage {
|
||||
return serial.ToTypedMessage(h.senderSettings)
|
||||
}
|
||||
|
||||
// ProxySettings implements outbound.Handler.
|
||||
func (h *Handler) ProxySettings() *serial.TypedMessage {
|
||||
return serial.ToTypedMessage(h.proxyConfig)
|
||||
}
|
||||
|
||||
func ParseRandomIP(addr net.Address, prefix string) net.Address {
|
||||
|
||||
_, ipnet, _ := gonet.ParseCIDR(addr.IP().String() + "/" + prefix)
|
||||
|
||||
ones, bits := ipnet.Mask.Size()
|
||||
subnetSize := new(big.Int).Lsh(big.NewInt(1), uint(bits-ones))
|
||||
|
||||
rnd, _ := rand.Int(rand.Reader, subnetSize)
|
||||
|
||||
startInt := new(big.Int).SetBytes(ipnet.IP)
|
||||
rndInt := new(big.Int).Add(startInt, rnd)
|
||||
|
||||
rndBytes := rndInt.Bytes()
|
||||
padded := make([]byte, len(ipnet.IP))
|
||||
copy(padded[len(padded)-len(rndBytes):], rndBytes)
|
||||
|
||||
return net.ParseAddress(gonet.IP(padded).String())
|
||||
}
|
||||
|
@@ -145,6 +145,21 @@ func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListHandlers implements outbound.Manager.
|
||||
func (m *Manager) ListHandlers(ctx context.Context) []outbound.Handler {
|
||||
m.access.RLock()
|
||||
defer m.access.RUnlock()
|
||||
|
||||
response := make([]outbound.Handler, len(m.untaggedHandlers))
|
||||
copy(response, m.untaggedHandlers)
|
||||
|
||||
for _, v := range m.taggedHandler {
|
||||
response = append(response, v)
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
// Select implements outbound.HandlerSelector.
|
||||
func (m *Manager) Select(selectors []string) []string {
|
||||
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
func (c *Control) FillInRandom() {
|
||||
randomLength := dice.Roll(64)
|
||||
randomLength++
|
||||
c.Random = make([]byte, randomLength)
|
||||
io.ReadFull(rand.Reader, c.Random)
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
@@ -111,6 +112,16 @@ func (o *Outbound) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SenderSettings implements outbound.Handler.
|
||||
func (o *Outbound) SenderSettings() *serial.TypedMessage {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProxySettings implements outbound.Handler.
|
||||
func (o *Outbound) ProxySettings() *serial.TypedMessage {
|
||||
return nil
|
||||
}
|
||||
|
||||
type StaticMuxPicker struct {
|
||||
access sync.Mutex
|
||||
workers []*PortalWorker
|
||||
@@ -159,7 +170,7 @@ func (p *StaticMuxPicker) PickAvailable() (*mux.ClientWorker, error) {
|
||||
if w.draining {
|
||||
continue
|
||||
}
|
||||
if w.client.Closed() {
|
||||
if w.IsFull() {
|
||||
continue
|
||||
}
|
||||
if w.client.ActiveConnections() < minConn {
|
||||
@@ -200,6 +211,7 @@ type PortalWorker struct {
|
||||
writer buf.Writer
|
||||
reader buf.Reader
|
||||
draining bool
|
||||
counter uint32
|
||||
}
|
||||
|
||||
func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
||||
@@ -233,7 +245,7 @@ func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
||||
}
|
||||
|
||||
func (w *PortalWorker) heartbeat() error {
|
||||
if w.client.Closed() {
|
||||
if w.Closed() {
|
||||
return errors.New("client worker stopped")
|
||||
}
|
||||
|
||||
@@ -249,16 +261,21 @@ func (w *PortalWorker) heartbeat() error {
|
||||
msg.State = Control_DRAIN
|
||||
|
||||
defer func() {
|
||||
w.client.GetTimer().Reset(time.Second * 16)
|
||||
common.Close(w.writer)
|
||||
common.Interrupt(w.reader)
|
||||
w.writer = nil
|
||||
}()
|
||||
}
|
||||
|
||||
b, err := proto.Marshal(msg)
|
||||
common.Must(err)
|
||||
mb := buf.MergeBytes(nil, b)
|
||||
return w.writer.WriteMultiBuffer(mb)
|
||||
w.counter = (w.counter + 1) % 5
|
||||
if w.draining || w.counter == 1 {
|
||||
b, err := proto.Marshal(msg)
|
||||
common.Must(err)
|
||||
mb := buf.MergeBytes(nil, b)
|
||||
return w.writer.WriteMultiBuffer(mb)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *PortalWorker) IsFull() bool {
|
||||
|
@@ -42,6 +42,8 @@ type RoutingContext struct {
|
||||
Attributes map[string]string `protobuf:"bytes,10,rep,name=Attributes,proto3" json:"Attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
OutboundGroupTags []string `protobuf:"bytes,11,rep,name=OutboundGroupTags,proto3" json:"OutboundGroupTags,omitempty"`
|
||||
OutboundTag string `protobuf:"bytes,12,opt,name=OutboundTag,proto3" json:"OutboundTag,omitempty"`
|
||||
LocalIPs [][]byte `protobuf:"bytes,13,rep,name=LocalIPs,proto3" json:"LocalIPs,omitempty"`
|
||||
LocalPort uint32 `protobuf:"varint,14,opt,name=LocalPort,proto3" json:"LocalPort,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RoutingContext) Reset() {
|
||||
@@ -158,6 +160,20 @@ func (x *RoutingContext) GetOutboundTag() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RoutingContext) GetLocalIPs() [][]byte {
|
||||
if x != nil {
|
||||
return x.LocalIPs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *RoutingContext) GetLocalPort() uint32 {
|
||||
if x != nil {
|
||||
return x.LocalPort
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// SubscribeRoutingStatsRequest subscribes to routing statistics channel if
|
||||
// opened by xray-core.
|
||||
// * FieldSelectors selects a subset of fields in routing statistics to return.
|
||||
@@ -827,7 +843,7 @@ var file_app_router_command_command_proto_rawDesc = []byte{
|
||||
0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65,
|
||||
0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9c, 0x04, 0x0a, 0x0e, 0x52, 0x6f, 0x75,
|
||||
0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd6, 0x04, 0x0a, 0x0e, 0x52, 0x6f, 0x75,
|
||||
0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x49,
|
||||
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0a, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x32, 0x0a, 0x07, 0x4e,
|
||||
@@ -857,123 +873,127 @@ var file_app_router_command_command_proto_rawDesc = []byte{
|
||||
0x03, 0x28, 0x09, 0x52, 0x11, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x47, 0x72, 0x6f,
|
||||
0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75,
|
||||
0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x75, 0x74,
|
||||
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72,
|
||||
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
|
||||
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
|
||||
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x46, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x73, 0x63,
|
||||
0x72, 0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64,
|
||||
0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||
0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22,
|
||||
0xb1, 0x01, 0x0a, 0x10, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x4f, 0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43,
|
||||
0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
||||
0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
||||
0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65,
|
||||
0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46,
|
||||
0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x24, 0x0a,
|
||||
0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73,
|
||||
0x75, 0x6c, 0x74, 0x22, 0x27, 0x0a, 0x13, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65,
|
||||
0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
|
||||
0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x26, 0x0a, 0x0c,
|
||||
0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x22, 0xa9, 0x01, 0x0a, 0x0b, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65,
|
||||
0x72, 0x4d, 0x73, 0x67, 0x12, 0x41, 0x0a, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61,
|
||||
0x6c, 0x49, 0x50, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x4c, 0x6f, 0x63, 0x61,
|
||||
0x6c, 0x49, 0x50, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72,
|
||||
0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f,
|
||||
0x72, 0x74, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
|
||||
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
|
||||
0x01, 0x22, 0x46, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f,
|
||||
0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74,
|
||||
0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64,
|
||||
0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xb1, 0x01, 0x0a, 0x10, 0x54, 0x65,
|
||||
0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4f,
|
||||
0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6f,
|
||||
0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x57, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x6e, 0x63,
|
||||
0x69, 0x70, 0x6c, 0x65, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
|
||||
0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x72, 0x69, 0x6e,
|
||||
0x63, 0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52,
|
||||
0x0f, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x22, 0x2a, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49,
|
||||
0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
|
||||
0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x5b, 0x0a, 0x17,
|
||||
0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x52,
|
||||
0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x22, 0x59, 0x0a, 0x1d, 0x4f, 0x76, 0x65,
|
||||
0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72,
|
||||
0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61,
|
||||
0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0b, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x22, 0x20, 0x0a, 0x1e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
|
||||
0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6e, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c,
|
||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79,
|
||||
0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x41, 0x70, 0x70, 0x65,
|
||||
0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64,
|
||||
0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x22, 0x11, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c,
|
||||
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2d, 0x0a, 0x11, 0x52, 0x65, 0x6d,
|
||||
0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x07, 0x72, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x67, 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f,
|
||||
0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08,
|
||||
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0xbf, 0x05, 0x0a, 0x0e, 0x52, 0x6f, 0x75,
|
||||
0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7b, 0x0a, 0x15, 0x53,
|
||||
0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53,
|
||||
0x74, 0x61, 0x74, 0x73, 0x12, 0x35, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53,
|
||||
0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53,
|
||||
0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x78, 0x72,
|
||||
0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52,
|
||||
0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12,
|
||||
0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72,
|
||||
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65,
|
||||
0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69,
|
||||
0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d,
|
||||
0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x27, 0x0a,
|
||||
0x13, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28,
|
||||
0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x26, 0x0a, 0x0c, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
||||
0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0xa9,
|
||||
0x01, 0x0a, 0x0b, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x41,
|
||||
0x0a, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72,
|
||||
0x69, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
|
||||
0x65, 0x12, 0x57, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x74,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
|
||||
0x74, 0x65, 0x78, 0x74, 0x22, 0x00, 0x30, 0x01, 0x12, 0x61, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74,
|
||||
0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
||||
0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00, 0x12, 0x76, 0x0a, 0x0f, 0x47,
|
||||
0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2f,
|
||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x54,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x70, 0x72, 0x69, 0x6e, 0x63,
|
||||
0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x2a, 0x0a, 0x16, 0x47, 0x65,
|
||||
0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x5b, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c,
|
||||
0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x00, 0x12, 0x8b, 0x01, 0x0a, 0x16, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
|
||||
0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x36,
|
||||
0x65, 0x12, 0x40, 0x0a, 0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x42, 0x61,
|
||||
0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x52, 0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x72, 0x22, 0x59, 0x0a, 0x1d, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42,
|
||||
0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72,
|
||||
0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x72, 0x54, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x20,
|
||||
0x0a, 0x1e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x6e, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x38, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x22, 0x0a, 0x0c,
|
||||
0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x08, 0x52, 0x0c, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64,
|
||||
0x22, 0x11, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x22, 0x2d, 0x0a, 0x11, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c,
|
||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65,
|
||||
0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x54,
|
||||
0x61, 0x67, 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x32, 0xbf, 0x05, 0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7b, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
|
||||
0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x35,
|
||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
|
||||
0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65,
|
||||
0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x00, 0x12, 0x5e, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x27, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
|
||||
0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
||||
0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x00, 0x12, 0x67, 0x0a, 0x0a, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x12,
|
||||
0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
||||
0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f,
|
||||
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74,
|
||||
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00,
|
||||
0x30, 0x01, 0x12, 0x61, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12,
|
||||
0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f,
|
||||
0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74,
|
||||
0x65, 0x78, 0x74, 0x22, 0x00, 0x12, 0x76, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
||||
0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49, 0x6e,
|
||||
0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x49,
|
||||
0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x8b, 0x01,
|
||||
0x0a, 0x16, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x36, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
||||
0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x37, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72,
|
||||
0x69, 0x64, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x07, 0x41,
|
||||
0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x2e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x75, 0x6c,
|
||||
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x67, 0x0a, 0x0a, 0x52,
|
||||
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
||||
0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x00, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65,
|
||||
0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@@ -25,6 +25,8 @@ message RoutingContext {
|
||||
map<string, string> Attributes = 10;
|
||||
repeated string OutboundGroupTags = 11;
|
||||
string OutboundTag = 12;
|
||||
repeated bytes LocalIPs = 13;
|
||||
uint32 LocalPort = 14;
|
||||
}
|
||||
|
||||
// SubscribeRoutingStatsRequest subscribes to routing statistics channel if
|
||||
|
@@ -28,6 +28,14 @@ func (c routingContext) GetTargetPort() net.Port {
|
||||
return net.Port(c.RoutingContext.GetTargetPort())
|
||||
}
|
||||
|
||||
func (c routingContext) GetLocalIPs() []net.IP {
|
||||
return mapBytesToIPs(c.RoutingContext.GetLocalIPs())
|
||||
}
|
||||
|
||||
func (c routingContext) GetLocalPort() net.Port {
|
||||
return net.Port(c.RoutingContext.GetLocalPort())
|
||||
}
|
||||
|
||||
func (c routingContext) GetRuleTag() string {
|
||||
return ""
|
||||
}
|
||||
@@ -54,8 +62,10 @@ var fieldMap = map[string]func(*RoutingContext, routing.Route){
|
||||
"network": func(s *RoutingContext, r routing.Route) { s.Network = r.GetNetwork() },
|
||||
"ip_source": func(s *RoutingContext, r routing.Route) { s.SourceIPs = mapIPsToBytes(r.GetSourceIPs()) },
|
||||
"ip_target": func(s *RoutingContext, r routing.Route) { s.TargetIPs = mapIPsToBytes(r.GetTargetIPs()) },
|
||||
"ip_local": func(s *RoutingContext, r routing.Route) { s.LocalIPs = mapIPsToBytes(r.GetLocalIPs()) },
|
||||
"port_source": func(s *RoutingContext, r routing.Route) { s.SourcePort = uint32(r.GetSourcePort()) },
|
||||
"port_target": func(s *RoutingContext, r routing.Route) { s.TargetPort = uint32(r.GetTargetPort()) },
|
||||
"port_local": func(s *RoutingContext, r routing.Route) { s.LocalPort = uint32(r.GetLocalPort()) },
|
||||
"domain": func(s *RoutingContext, r routing.Route) { s.TargetDomain = r.GetTargetDomain() },
|
||||
"protocol": func(s *RoutingContext, r routing.Route) { s.Protocol = r.GetProtocol() },
|
||||
"user": func(s *RoutingContext, r routing.Route) { s.User = r.GetUser() },
|
||||
|
@@ -113,13 +113,13 @@ func (m *DomainMatcher) Apply(ctx routing.Context) bool {
|
||||
|
||||
type MultiGeoIPMatcher struct {
|
||||
matchers []*GeoIPMatcher
|
||||
onSource bool
|
||||
asType string // local, source, target
|
||||
}
|
||||
|
||||
func NewMultiGeoIPMatcher(geoips []*GeoIP, onSource bool) (*MultiGeoIPMatcher, error) {
|
||||
func NewMultiGeoIPMatcher(geoips []*GeoIP, asType string) (*MultiGeoIPMatcher, error) {
|
||||
var matchers []*GeoIPMatcher
|
||||
for _, geoip := range geoips {
|
||||
matcher, err := globalGeoIPContainer.Add(geoip)
|
||||
matcher, err := GlobalGeoIPContainer.Add(geoip)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -128,7 +128,7 @@ func NewMultiGeoIPMatcher(geoips []*GeoIP, onSource bool) (*MultiGeoIPMatcher, e
|
||||
|
||||
matcher := &MultiGeoIPMatcher{
|
||||
matchers: matchers,
|
||||
onSource: onSource,
|
||||
asType: asType,
|
||||
}
|
||||
|
||||
return matcher, nil
|
||||
@@ -137,11 +137,18 @@ func NewMultiGeoIPMatcher(geoips []*GeoIP, onSource bool) (*MultiGeoIPMatcher, e
|
||||
// Apply implements Condition.
|
||||
func (m *MultiGeoIPMatcher) Apply(ctx routing.Context) bool {
|
||||
var ips []net.IP
|
||||
if m.onSource {
|
||||
|
||||
switch m.asType {
|
||||
case "local":
|
||||
ips = ctx.GetLocalIPs()
|
||||
case "source":
|
||||
ips = ctx.GetSourceIPs()
|
||||
} else {
|
||||
case "target":
|
||||
ips = ctx.GetTargetIPs()
|
||||
default:
|
||||
panic("unreachable, asType should be local or source or target")
|
||||
}
|
||||
|
||||
for _, ip := range ips {
|
||||
for _, matcher := range m.matchers {
|
||||
if matcher.Match(ip) {
|
||||
@@ -153,25 +160,31 @@ func (m *MultiGeoIPMatcher) Apply(ctx routing.Context) bool {
|
||||
}
|
||||
|
||||
type PortMatcher struct {
|
||||
port net.MemoryPortList
|
||||
onSource bool
|
||||
port net.MemoryPortList
|
||||
asType string // local, source, target
|
||||
}
|
||||
|
||||
// NewPortMatcher create a new port matcher that can match source or destination port
|
||||
func NewPortMatcher(list *net.PortList, onSource bool) *PortMatcher {
|
||||
// NewPortMatcher create a new port matcher that can match source or local or destination port
|
||||
func NewPortMatcher(list *net.PortList, asType string) *PortMatcher {
|
||||
return &PortMatcher{
|
||||
port: net.PortListFromProto(list),
|
||||
onSource: onSource,
|
||||
port: net.PortListFromProto(list),
|
||||
asType: asType,
|
||||
}
|
||||
}
|
||||
|
||||
// Apply implements Condition.
|
||||
func (v *PortMatcher) Apply(ctx routing.Context) bool {
|
||||
if v.onSource {
|
||||
switch v.asType {
|
||||
case "local":
|
||||
return v.port.Contains(ctx.GetLocalPort())
|
||||
case "source":
|
||||
return v.port.Contains(ctx.GetSourcePort())
|
||||
} else {
|
||||
case "target":
|
||||
return v.port.Contains(ctx.GetTargetPort())
|
||||
default:
|
||||
panic("unreachable, asType should be local or source or target")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type NetworkMatcher struct {
|
||||
|
@@ -115,4 +115,30 @@ func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
var globalGeoIPContainer GeoIPMatcherContainer
|
||||
var GlobalGeoIPContainer GeoIPMatcherContainer
|
||||
|
||||
func MatchIPs(matchers []*GeoIPMatcher, ips []net.IP, reverse bool) []net.IP {
|
||||
if len(matchers) == 0 {
|
||||
panic("GeoIP matchers should not be empty to avoid ambiguity")
|
||||
}
|
||||
newIPs := make([]net.IP, 0, len(ips))
|
||||
var isFound bool
|
||||
for _, ip := range ips {
|
||||
isFound = false
|
||||
for _, matcher := range matchers {
|
||||
if matcher.Match(ip) {
|
||||
isFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if isFound && !reverse {
|
||||
newIPs = append(newIPs, ip)
|
||||
continue
|
||||
}
|
||||
if !isFound && reverse {
|
||||
newIPs = append(newIPs, ip)
|
||||
continue
|
||||
}
|
||||
}
|
||||
return newIPs
|
||||
}
|
||||
|
@@ -495,7 +495,7 @@ func BenchmarkMultiGeoIPMatcher(b *testing.B) {
|
||||
})
|
||||
}
|
||||
|
||||
matcher, err := NewMultiGeoIPMatcher(geoips, false)
|
||||
matcher, err := NewMultiGeoIPMatcher(geoips, "target")
|
||||
common.Must(err)
|
||||
|
||||
ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)})
|
||||
|
@@ -61,11 +61,15 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||
}
|
||||
|
||||
if rr.PortList != nil {
|
||||
conds.Add(NewPortMatcher(rr.PortList, false))
|
||||
conds.Add(NewPortMatcher(rr.PortList, "target"))
|
||||
}
|
||||
|
||||
if rr.SourcePortList != nil {
|
||||
conds.Add(NewPortMatcher(rr.SourcePortList, true))
|
||||
conds.Add(NewPortMatcher(rr.SourcePortList, "source"))
|
||||
}
|
||||
|
||||
if rr.LocalPortList != nil {
|
||||
conds.Add(NewPortMatcher(rr.LocalPortList, "local"))
|
||||
}
|
||||
|
||||
if len(rr.Networks) > 0 {
|
||||
@@ -73,7 +77,7 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||
}
|
||||
|
||||
if len(rr.Geoip) > 0 {
|
||||
cond, err := NewMultiGeoIPMatcher(rr.Geoip, false)
|
||||
cond, err := NewMultiGeoIPMatcher(rr.Geoip, "target")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -81,13 +85,22 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||
}
|
||||
|
||||
if len(rr.SourceGeoip) > 0 {
|
||||
cond, err := NewMultiGeoIPMatcher(rr.SourceGeoip, true)
|
||||
cond, err := NewMultiGeoIPMatcher(rr.SourceGeoip, "source")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conds.Add(cond)
|
||||
}
|
||||
|
||||
if len(rr.LocalGeoip) > 0 {
|
||||
cond, err := NewMultiGeoIPMatcher(rr.LocalGeoip, "local")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conds.Add(cond)
|
||||
errors.LogWarning(context.Background(), "Due to some limitations, in UDP connections, localIP is always equal to listen interface IP, so \"localIP\" rule condition does not work properly on UDP inbound connections that listen on all interfaces")
|
||||
}
|
||||
|
||||
if len(rr.Protocol) > 0 {
|
||||
conds.Add(NewProtocolMatcher(rr.Protocol))
|
||||
}
|
||||
|
@@ -470,7 +470,7 @@ type RoutingRule struct {
|
||||
// *RoutingRule_Tag
|
||||
// *RoutingRule_BalancingTag
|
||||
TargetTag isRoutingRule_TargetTag `protobuf_oneof:"target_tag"`
|
||||
RuleTag string `protobuf:"bytes,18,opt,name=rule_tag,json=ruleTag,proto3" json:"rule_tag,omitempty"`
|
||||
RuleTag string `protobuf:"bytes,20,opt,name=rule_tag,json=ruleTag,proto3" json:"rule_tag,omitempty"`
|
||||
// List of domains for target domain matching.
|
||||
Domain []*Domain `protobuf:"bytes,2,rep,name=domain,proto3" json:"domain,omitempty"`
|
||||
// List of GeoIPs for target IP address matching. If this entry exists, the
|
||||
@@ -492,6 +492,8 @@ type RoutingRule struct {
|
||||
Protocol []string `protobuf:"bytes,9,rep,name=protocol,proto3" json:"protocol,omitempty"`
|
||||
Attributes map[string]string `protobuf:"bytes,15,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
DomainMatcher string `protobuf:"bytes,17,opt,name=domain_matcher,json=domainMatcher,proto3" json:"domain_matcher,omitempty"`
|
||||
LocalGeoip []*GeoIP `protobuf:"bytes,18,rep,name=local_geoip,json=localGeoip,proto3" json:"local_geoip,omitempty"`
|
||||
LocalPortList *net.PortList `protobuf:"bytes,19,opt,name=local_port_list,json=localPortList,proto3" json:"local_port_list,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RoutingRule) Reset() {
|
||||
@@ -629,6 +631,20 @@ func (x *RoutingRule) GetDomainMatcher() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RoutingRule) GetLocalGeoip() []*GeoIP {
|
||||
if x != nil {
|
||||
return x.LocalGeoip
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *RoutingRule) GetLocalPortList() *net.PortList {
|
||||
if x != nil {
|
||||
return x.LocalPortList
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type isRoutingRule_TargetTag interface {
|
||||
isRoutingRule_TargetTag()
|
||||
}
|
||||
@@ -1069,13 +1085,13 @@ var file_app_router_config_proto_rawDesc = []byte{
|
||||
0x6f, 0x53, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x05, 0x65, 0x6e, 0x74,
|
||||
0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x53, 0x69,
|
||||
0x74, 0x65, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xce, 0x05, 0x0a, 0x0b, 0x52, 0x6f,
|
||||
0x74, 0x65, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 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, 0x19, 0x0a, 0x08, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x61, 0x67,
|
||||
0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x67, 0x12,
|
||||
0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x67, 0x12,
|
||||
0x2f, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x17, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
@@ -1109,67 +1125,75 @@ var file_app_router_config_proto_rawDesc = []byte{
|
||||
0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72,
|
||||
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
|
||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x1a, 0x3d, 0x0a,
|
||||
0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
|
||||
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
|
||||
0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0c, 0x0a, 0x0a,
|
||||
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x22, 0xdc, 0x01, 0x0a, 0x0d, 0x42,
|
||||
0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03,
|
||||
0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b,
|
||||
0x0a, 0x11, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63,
|
||||
0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f,
|
||||
0x75, 0x6e, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4d, 0x0a, 0x11, 0x73, 0x74, 0x72, 0x61, 0x74,
|
||||
0x65, 0x67, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x52, 0x10, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x53, 0x65,
|
||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61,
|
||||
0x63, 0x6b, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x66, 0x61,
|
||||
0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x54, 0x61, 0x67, 0x22, 0x54, 0x0a, 0x0e, 0x53, 0x74, 0x72,
|
||||
0x61, 0x74, 0x65, 0x67, 0x79, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72,
|
||||
0x65, 0x67, 0x65, 0x78, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x67,
|
||||
0x65, 0x78, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,
|
||||
0xc0, 0x01, 0x0a, 0x17, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x4c, 0x65, 0x61, 0x73,
|
||||
0x74, 0x4c, 0x6f, 0x61, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x05, 0x63,
|
||||
0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x72,
|
||||
0x61, 0x74, 0x65, 0x67, 0x79, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x05, 0x63, 0x6f, 0x73,
|
||||
0x74, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18,
|
||||
0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x09, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73,
|
||||
0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x05, 0x52, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x6d, 0x61, 0x78, 0x52, 0x54, 0x54, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6d, 0x61,
|
||||
0x78, 0x52, 0x54, 0x54, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x22, 0x9b, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4f, 0x0a,
|
||||
0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
|
||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e,
|
||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x30,
|
||||
0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52,
|
||||
0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65,
|
||||
0x12, 0x45, 0x0a, 0x0e, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75,
|
||||
0x6c, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63,
|
||||
0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x22, 0x47, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49,
|
||||
0x73, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x49, 0x70, 0x10, 0x01, 0x12, 0x10,
|
||||
0x0a, 0x0c, 0x49, 0x70, 0x49, 0x66, 0x4e, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x02,
|
||||
0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x70, 0x4f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x10, 0x03,
|
||||
0x42, 0x4f, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d,
|
||||
0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0xaa,
|
||||
0x02, 0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x37, 0x0a,
|
||||
0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x12, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
|
||||
0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61,
|
||||
0x6c, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x41, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f,
|
||||
0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
|
||||
0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x61,
|
||||
0x6c, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74,
|
||||
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
|
||||
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
|
||||
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76,
|
||||
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67,
|
||||
0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x22, 0xdc, 0x01, 0x0a, 0x0d, 0x42, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x75,
|
||||
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18,
|
||||
0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53,
|
||||
0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74,
|
||||
0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74,
|
||||
0x65, 0x67, 0x79, 0x12, 0x4d, 0x0a, 0x11, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x5f,
|
||||
0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20,
|
||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x52, 0x10, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
||||
0x67, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x74,
|
||||
0x61, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61,
|
||||
0x63, 0x6b, 0x54, 0x61, 0x67, 0x22, 0x54, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
|
||||
0x79, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x65, 0x78,
|
||||
0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x12,
|
||||
0x14, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
|
||||
0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xc0, 0x01, 0x0a, 0x17,
|
||||
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x4c, 0x6f, 0x61,
|
||||
0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x05, 0x63, 0x6f, 0x73, 0x74, 0x73,
|
||||
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
|
||||
0x79, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x05, 0x63, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1c,
|
||||
0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
|
||||
0x03, 0x52, 0x09, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08,
|
||||
0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08,
|
||||
0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x78, 0x52,
|
||||
0x54, 0x54, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6d, 0x61, 0x78, 0x52, 0x54, 0x54,
|
||||
0x12, 0x1c, 0x0a, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20,
|
||||
0x01, 0x28, 0x02, 0x52, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x9b,
|
||||
0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4f, 0x0a, 0x0f, 0x64, 0x6f, 0x6d,
|
||||
0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0e, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
|
||||
0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61,
|
||||
0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61,
|
||||
0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x30, 0x0a, 0x04, 0x72, 0x75,
|
||||
0x6c, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x45, 0x0a, 0x0e,
|
||||
0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x03,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67,
|
||||
0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52,
|
||||
0x75, 0x6c, 0x65, 0x22, 0x47, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72,
|
||||
0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49, 0x73, 0x10, 0x00, 0x12,
|
||||
0x09, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x49, 0x70, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x70,
|
||||
0x49, 0x66, 0x4e, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a,
|
||||
0x49, 0x70, 0x4f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x10, 0x03, 0x42, 0x4f, 0x0a, 0x13,
|
||||
0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
|
||||
0x74, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65,
|
||||
0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0xaa, 0x02, 0x0f, 0x58, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -1220,16 +1244,18 @@ var file_app_router_config_proto_depIdxs = []int32{
|
||||
4, // 10: xray.app.router.RoutingRule.source_geoip:type_name -> xray.app.router.GeoIP
|
||||
15, // 11: xray.app.router.RoutingRule.source_port_list:type_name -> xray.common.net.PortList
|
||||
14, // 12: xray.app.router.RoutingRule.attributes:type_name -> xray.app.router.RoutingRule.AttributesEntry
|
||||
17, // 13: xray.app.router.BalancingRule.strategy_settings:type_name -> xray.common.serial.TypedMessage
|
||||
10, // 14: xray.app.router.StrategyLeastLoadConfig.costs:type_name -> xray.app.router.StrategyWeight
|
||||
1, // 15: xray.app.router.Config.domain_strategy:type_name -> xray.app.router.Config.DomainStrategy
|
||||
8, // 16: xray.app.router.Config.rule:type_name -> xray.app.router.RoutingRule
|
||||
9, // 17: xray.app.router.Config.balancing_rule:type_name -> xray.app.router.BalancingRule
|
||||
18, // [18:18] is the sub-list for method output_type
|
||||
18, // [18:18] is the sub-list for method input_type
|
||||
18, // [18:18] is the sub-list for extension type_name
|
||||
18, // [18:18] is the sub-list for extension extendee
|
||||
0, // [0:18] is the sub-list for field type_name
|
||||
4, // 13: xray.app.router.RoutingRule.local_geoip:type_name -> xray.app.router.GeoIP
|
||||
15, // 14: xray.app.router.RoutingRule.local_port_list:type_name -> xray.common.net.PortList
|
||||
17, // 15: xray.app.router.BalancingRule.strategy_settings:type_name -> xray.common.serial.TypedMessage
|
||||
10, // 16: xray.app.router.StrategyLeastLoadConfig.costs:type_name -> xray.app.router.StrategyWeight
|
||||
1, // 17: xray.app.router.Config.domain_strategy:type_name -> xray.app.router.Config.DomainStrategy
|
||||
8, // 18: xray.app.router.Config.rule:type_name -> xray.app.router.RoutingRule
|
||||
9, // 19: xray.app.router.Config.balancing_rule:type_name -> xray.app.router.BalancingRule
|
||||
20, // [20:20] is the sub-list for method output_type
|
||||
20, // [20:20] is the sub-list for method input_type
|
||||
20, // [20:20] is the sub-list for extension type_name
|
||||
20, // [20:20] is the sub-list for extension extendee
|
||||
0, // [0:20] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_app_router_config_proto_init() }
|
||||
|
@@ -79,7 +79,7 @@ message RoutingRule {
|
||||
// Tag of routing balancer.
|
||||
string balancing_tag = 12;
|
||||
}
|
||||
string rule_tag = 18;
|
||||
string rule_tag = 20;
|
||||
|
||||
// List of domains for target domain matching.
|
||||
repeated Domain domain = 2;
|
||||
@@ -110,6 +110,9 @@ message RoutingRule {
|
||||
map<string, string> attributes = 15;
|
||||
|
||||
string domain_matcher = 17;
|
||||
|
||||
repeated GeoIP local_geoip = 18;
|
||||
xray.common.net.PortList local_port_list = 19;
|
||||
}
|
||||
|
||||
message BalancingRule {
|
||||
|
@@ -12,6 +12,8 @@ import (
|
||||
"github.com/xtls/xray-core/core"
|
||||
feature_stats "github.com/xtls/xray-core/features/stats"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// statsServer is an implementation of StatsService.
|
||||
@@ -30,7 +32,7 @@ func NewStatsServer(manager feature_stats.Manager) StatsServiceServer {
|
||||
func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {
|
||||
c := s.stats.GetCounter(request.Name)
|
||||
if c == nil {
|
||||
return nil, errors.New(request.Name, " not found.")
|
||||
return nil, status.Error(codes.NotFound, request.Name+" not found.")
|
||||
}
|
||||
var value int64
|
||||
if request.Reset_ {
|
||||
@@ -49,7 +51,7 @@ func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*
|
||||
func (s *statsServer) GetStatsOnline(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {
|
||||
c := s.stats.GetOnlineMap(request.Name)
|
||||
if c == nil {
|
||||
return nil, errors.New(request.Name, " not found.")
|
||||
return nil, status.Error(codes.NotFound, request.Name+" not found.")
|
||||
}
|
||||
value := int64(c.Count())
|
||||
return &GetStatsResponse{
|
||||
@@ -64,7 +66,7 @@ func (s *statsServer) GetStatsOnlineIpList(ctx context.Context, request *GetStat
|
||||
c := s.stats.GetOnlineMap(request.Name)
|
||||
|
||||
if c == nil {
|
||||
return nil, errors.New(request.Name, " not found.")
|
||||
return nil, status.Error(codes.NotFound, request.Name+" not found.")
|
||||
}
|
||||
|
||||
ips := make(map[string]int64)
|
||||
|
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
// OnlineMap is an implementation of stats.OnlineMap.
|
||||
type OnlineMap struct {
|
||||
value int
|
||||
ipList map[string]time.Time
|
||||
access sync.RWMutex
|
||||
lastCleanup time.Time
|
||||
@@ -25,7 +24,10 @@ func NewOnlineMap() *OnlineMap {
|
||||
|
||||
// Count implements stats.OnlineMap.
|
||||
func (c *OnlineMap) Count() int {
|
||||
return c.value
|
||||
c.access.RLock()
|
||||
defer c.access.RUnlock()
|
||||
|
||||
return len(c.ipList)
|
||||
}
|
||||
|
||||
// List implements stats.OnlineMap.
|
||||
@@ -35,23 +37,18 @@ func (c *OnlineMap) List() []string {
|
||||
|
||||
// AddIP implements stats.OnlineMap.
|
||||
func (c *OnlineMap) AddIP(ip string) {
|
||||
list := c.ipList
|
||||
|
||||
if ip == "127.0.0.1" {
|
||||
return
|
||||
}
|
||||
|
||||
c.access.Lock()
|
||||
if _, ok := list[ip]; !ok {
|
||||
list[ip] = time.Now()
|
||||
}
|
||||
c.ipList[ip] = time.Now()
|
||||
c.access.Unlock()
|
||||
|
||||
if time.Since(c.lastCleanup) > c.cleanupPeriod {
|
||||
list = c.RemoveExpiredIPs(list)
|
||||
c.RemoveExpiredIPs()
|
||||
c.lastCleanup = time.Now()
|
||||
}
|
||||
|
||||
c.value = len(list)
|
||||
c.ipList = list
|
||||
}
|
||||
|
||||
func (c *OnlineMap) GetKeys() []string {
|
||||
@@ -65,24 +62,22 @@ func (c *OnlineMap) GetKeys() []string {
|
||||
return keys
|
||||
}
|
||||
|
||||
func (c *OnlineMap) RemoveExpiredIPs(list map[string]time.Time) map[string]time.Time {
|
||||
func (c *OnlineMap) RemoveExpiredIPs() {
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
for k, t := range list {
|
||||
for k, t := range c.ipList {
|
||||
diff := now.Sub(t)
|
||||
if diff.Seconds() > 20 {
|
||||
delete(list, k)
|
||||
delete(c.ipList, k)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func (c *OnlineMap) IpTimeMap() map[string]time.Time {
|
||||
list := c.ipList
|
||||
if time.Since(c.lastCleanup) > c.cleanupPeriod {
|
||||
list = c.RemoveExpiredIPs(list)
|
||||
c.RemoveExpiredIPs()
|
||||
c.lastCleanup = time.Now()
|
||||
}
|
||||
|
||||
|
152
app/version/config.pb.go
Normal file
152
app/version/config.pb.go
Normal file
@@ -0,0 +1,152 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.35.1
|
||||
// protoc v5.28.2
|
||||
// source: app/version/config.proto
|
||||
|
||||
package version
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
CoreVersion string `protobuf:"bytes,1,opt,name=core_version,json=coreVersion,proto3" json:"core_version,omitempty"`
|
||||
MinVersion string `protobuf:"bytes,2,opt,name=min_version,json=minVersion,proto3" json:"min_version,omitempty"`
|
||||
MaxVersion string `protobuf:"bytes,3,opt,name=max_version,json=maxVersion,proto3" json:"max_version,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
mi := &file_app_version_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_version_config_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_app_version_config_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Config) GetCoreVersion() string {
|
||||
if x != nil {
|
||||
return x.CoreVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Config) GetMinVersion() string {
|
||||
if x != nil {
|
||||
return x.MinVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Config) GetMaxVersion() string {
|
||||
if x != nil {
|
||||
return x.MaxVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_app_version_config_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_app_version_config_proto_rawDesc = []byte{
|
||||
0x0a, 0x18, 0x61, 0x70, 0x70, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x6d, 0x0a, 0x06,
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x72, 0x65, 0x5f, 0x76,
|
||||
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f,
|
||||
0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x69, 0x6e,
|
||||
0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
|
||||
0x6d, 0x69, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x61,
|
||||
0x78, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0a, 0x6d, 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x52, 0x0a, 0x14, 0x63,
|
||||
0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65,
|
||||
0x2f, 0x61, 0x70, 0x70, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0xaa, 0x02, 0x10, 0x58,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_app_version_config_proto_rawDescOnce sync.Once
|
||||
file_app_version_config_proto_rawDescData = file_app_version_config_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_app_version_config_proto_rawDescGZIP() []byte {
|
||||
file_app_version_config_proto_rawDescOnce.Do(func() {
|
||||
file_app_version_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_version_config_proto_rawDescData)
|
||||
})
|
||||
return file_app_version_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_app_version_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_app_version_config_proto_goTypes = []any{
|
||||
(*Config)(nil), // 0: xray.app.version.Config
|
||||
}
|
||||
var file_app_version_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_version_config_proto_init() }
|
||||
func file_app_version_config_proto_init() {
|
||||
if File_app_version_config_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_app_version_config_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_app_version_config_proto_goTypes,
|
||||
DependencyIndexes: file_app_version_config_proto_depIdxs,
|
||||
MessageInfos: file_app_version_config_proto_msgTypes,
|
||||
}.Build()
|
||||
File_app_version_config_proto = out.File
|
||||
file_app_version_config_proto_rawDesc = nil
|
||||
file_app_version_config_proto_goTypes = nil
|
||||
file_app_version_config_proto_depIdxs = nil
|
||||
}
|
14
app/version/config.proto
Normal file
14
app/version/config.proto
Normal file
@@ -0,0 +1,14 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package xray.app.version;
|
||||
option csharp_namespace = "Xray.App.Version";
|
||||
option go_package = "github.com/xtls/xray-core/app/version";
|
||||
option java_package = "com.xray.app.version";
|
||||
option java_multiple_files = true;
|
||||
|
||||
|
||||
message Config {
|
||||
string core_version = 1;
|
||||
string min_version = 2;
|
||||
string max_version = 3;
|
||||
}
|
77
app/version/version.go
Normal file
77
app/version/version.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Version struct {
|
||||
config *Config
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func New(ctx context.Context, config *Config) (*Version, error) {
|
||||
if config.MinVersion != "" {
|
||||
result, err := compareVersions(config.MinVersion, config.CoreVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result > 0 {
|
||||
return nil, errors.New("this config must be run on version ", config.MinVersion, " or higher")
|
||||
}
|
||||
}
|
||||
if config.MaxVersion != "" {
|
||||
result, err := compareVersions(config.MaxVersion, config.CoreVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result < 0 {
|
||||
return nil, errors.New("this config should be run on version ", config.MaxVersion, " or lower")
|
||||
}
|
||||
}
|
||||
return &Version{config: config, ctx: ctx}, nil
|
||||
}
|
||||
|
||||
func compareVersions(v1, v2 string) (int, error) {
|
||||
// Split version strings into components
|
||||
v1Parts := strings.Split(v1, ".")
|
||||
v2Parts := strings.Split(v2, ".")
|
||||
|
||||
// Pad shorter versions with zeros
|
||||
for len(v1Parts) < len(v2Parts) {
|
||||
v1Parts = append(v1Parts, "0")
|
||||
}
|
||||
for len(v2Parts) < len(v1Parts) {
|
||||
v2Parts = append(v2Parts, "0")
|
||||
}
|
||||
|
||||
// Compare each part
|
||||
for i := 0; i < len(v1Parts); i++ {
|
||||
// Convert parts to integers
|
||||
n1, err := strconv.Atoi(v1Parts[i])
|
||||
if err != nil {
|
||||
return 0, errors.New("invalid version component ", v1Parts[i], " in ", v1)
|
||||
}
|
||||
n2, err := strconv.Atoi(v2Parts[i])
|
||||
if err != nil {
|
||||
return 0, errors.New("invalid version component ", v2Parts[i], " in ", v2)
|
||||
}
|
||||
|
||||
if n1 < n2 {
|
||||
return -1, nil // v1 < v2
|
||||
}
|
||||
if n1 > n2 {
|
||||
return 1, nil // v1 > v2
|
||||
}
|
||||
}
|
||||
return 0, nil // v1 == v2
|
||||
}
|
||||
|
||||
func init() {
|
||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||
return New(ctx, config.(*Config))
|
||||
}))
|
||||
}
|
@@ -13,8 +13,19 @@ const (
|
||||
Size = 8192
|
||||
)
|
||||
|
||||
var zero = [Size * 10]byte{0}
|
||||
|
||||
var pool = bytespool.GetPool(Size)
|
||||
|
||||
// ownership represents the data owner of the buffer.
|
||||
type ownership uint8
|
||||
|
||||
const (
|
||||
managed ownership = iota
|
||||
unmanaged
|
||||
bytespools
|
||||
)
|
||||
|
||||
// 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.
|
||||
@@ -22,11 +33,11 @@ type Buffer struct {
|
||||
v []byte
|
||||
start int32
|
||||
end int32
|
||||
unmanaged bool
|
||||
ownership ownership
|
||||
UDP *net.Destination
|
||||
}
|
||||
|
||||
// New creates a Buffer with 0 length and 8K capacity.
|
||||
// New creates a Buffer with 0 length and 8K capacity, managed.
|
||||
func New() *Buffer {
|
||||
buf := pool.Get().([]byte)
|
||||
if cap(buf) >= Size {
|
||||
@@ -40,7 +51,7 @@ func New() *Buffer {
|
||||
}
|
||||
}
|
||||
|
||||
// NewExisted creates a managed, standard size Buffer with an existed bytearray
|
||||
// NewExisted creates a standard size Buffer with an existed bytearray, managed.
|
||||
func NewExisted(b []byte) *Buffer {
|
||||
if cap(b) < Size {
|
||||
panic("Invalid buffer")
|
||||
@@ -57,16 +68,16 @@ func NewExisted(b []byte) *Buffer {
|
||||
}
|
||||
}
|
||||
|
||||
// FromBytes creates a Buffer with an existed bytearray
|
||||
// FromBytes creates a Buffer with an existed bytearray, unmanaged.
|
||||
func FromBytes(b []byte) *Buffer {
|
||||
return &Buffer{
|
||||
v: b,
|
||||
end: int32(len(b)),
|
||||
unmanaged: true,
|
||||
ownership: unmanaged,
|
||||
}
|
||||
}
|
||||
|
||||
// StackNew creates a new Buffer object on stack.
|
||||
// StackNew creates a new Buffer object on stack, managed.
|
||||
// This method is for buffers that is released in the same function.
|
||||
func StackNew() Buffer {
|
||||
buf := pool.Get().([]byte)
|
||||
@@ -81,9 +92,17 @@ func StackNew() Buffer {
|
||||
}
|
||||
}
|
||||
|
||||
// NewWithSize creates a Buffer with 0 length and capacity with at least the given size, bytespool's.
|
||||
func NewWithSize(size int32) *Buffer {
|
||||
return &Buffer{
|
||||
v: bytespool.Alloc(size),
|
||||
ownership: bytespools,
|
||||
}
|
||||
}
|
||||
|
||||
// Release recycles the buffer into an internal buffer pool.
|
||||
func (b *Buffer) Release() {
|
||||
if b == nil || b.v == nil || b.unmanaged {
|
||||
if b == nil || b.v == nil || b.ownership == unmanaged {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -91,8 +110,13 @@ func (b *Buffer) Release() {
|
||||
b.v = nil
|
||||
b.Clear()
|
||||
|
||||
if cap(p) == Size {
|
||||
pool.Put(p)
|
||||
switch b.ownership {
|
||||
case managed:
|
||||
if cap(p) == Size {
|
||||
pool.Put(p)
|
||||
}
|
||||
case bytespools:
|
||||
bytespool.Free(p)
|
||||
}
|
||||
b.UDP = nil
|
||||
}
|
||||
@@ -128,6 +152,7 @@ func (b *Buffer) Extend(n int32) []byte {
|
||||
}
|
||||
ext := b.v[b.end:end]
|
||||
b.end = end
|
||||
copy(ext, zero[:])
|
||||
return ext
|
||||
}
|
||||
|
||||
@@ -176,6 +201,7 @@ func (b *Buffer) Check() {
|
||||
|
||||
// Resize cuts the buffer at the given position.
|
||||
func (b *Buffer) Resize(from, to int32) {
|
||||
oldEnd := b.end
|
||||
if from < 0 {
|
||||
from += b.Len()
|
||||
}
|
||||
@@ -188,6 +214,9 @@ func (b *Buffer) Resize(from, to int32) {
|
||||
b.end = b.start + to
|
||||
b.start += from
|
||||
b.Check()
|
||||
if b.end > oldEnd {
|
||||
copy(b.v[oldEnd:b.end], zero[:])
|
||||
}
|
||||
}
|
||||
|
||||
// Advance cuts the buffer at the given position.
|
||||
@@ -215,13 +244,6 @@ func (b *Buffer) Cap() int32 {
|
||||
return int32(len(b.v))
|
||||
}
|
||||
|
||||
// NewWithSize creates a Buffer with 0 length and capacity with at least the given size.
|
||||
func NewWithSize(size int32) *Buffer {
|
||||
return &Buffer{
|
||||
v: bytespool.Alloc(size),
|
||||
}
|
||||
}
|
||||
|
||||
// IsEmpty returns true if the buffer is empty.
|
||||
func (b *Buffer) IsEmpty() bool {
|
||||
return b.Len() == 0
|
||||
|
@@ -23,7 +23,9 @@ func Must(err error) {
|
||||
}
|
||||
|
||||
// Must2 panics if the second parameter is not nil, otherwise returns the first parameter.
|
||||
func Must2(v interface{}, err error) interface{} {
|
||||
// This is useful when function returned "sth, err" and avoid many "if err != nil"
|
||||
// Internal usage only, if user input can cause err, it must be handled
|
||||
func Must2[T any](v T, err error) T {
|
||||
Must(err)
|
||||
return v
|
||||
}
|
||||
|
@@ -32,9 +32,7 @@ func NewAesCTRStream(key []byte, iv []byte) cipher.Stream {
|
||||
|
||||
// NewAesGcm creates a AEAD cipher based on AES-GCM.
|
||||
func NewAesGcm(key []byte) cipher.AEAD {
|
||||
block, err := aes.NewCipher(key)
|
||||
common.Must(err)
|
||||
aead, err := cipher.NewGCM(block)
|
||||
common.Must(err)
|
||||
block := common.Must2(aes.NewCipher(key))
|
||||
aead := common.Must2(cipher.NewGCM(block))
|
||||
return aead
|
||||
}
|
||||
|
@@ -2,8 +2,6 @@ package crypto_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"testing"
|
||||
@@ -18,11 +16,8 @@ import (
|
||||
func TestAuthenticationReaderWriter(t *testing.T) {
|
||||
key := make([]byte, 16)
|
||||
rand.Read(key)
|
||||
block, err := aes.NewCipher(key)
|
||||
common.Must(err)
|
||||
|
||||
aead, err := cipher.NewGCM(block)
|
||||
common.Must(err)
|
||||
aead := NewAesGcm(key)
|
||||
|
||||
const payloadSize = 1024 * 80
|
||||
rawPayload := make([]byte, payloadSize)
|
||||
@@ -71,7 +66,7 @@ func TestAuthenticationReaderWriter(t *testing.T) {
|
||||
t.Error(r)
|
||||
}
|
||||
|
||||
_, err = reader.ReadMultiBuffer()
|
||||
_, err := reader.ReadMultiBuffer()
|
||||
if err != io.EOF {
|
||||
t.Error("error: ", err)
|
||||
}
|
||||
@@ -80,11 +75,8 @@ func TestAuthenticationReaderWriter(t *testing.T) {
|
||||
func TestAuthenticationReaderWriterPacket(t *testing.T) {
|
||||
key := make([]byte, 16)
|
||||
common.Must2(rand.Read(key))
|
||||
block, err := aes.NewCipher(key)
|
||||
common.Must(err)
|
||||
|
||||
aead, err := cipher.NewGCM(block)
|
||||
common.Must(err)
|
||||
aead := NewAesGcm(key)
|
||||
|
||||
cache := buf.New()
|
||||
iv := make([]byte, 12)
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -36,12 +37,12 @@ func AllEqual(expected error, actual error) bool {
|
||||
return false
|
||||
}
|
||||
for _, err := range errs {
|
||||
if err != expected {
|
||||
if !errors.Is(err, expected) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
return errs == expected
|
||||
return errors.Is(errs, expected)
|
||||
}
|
||||
}
|
||||
|
@@ -173,6 +173,7 @@ type ClientWorker struct {
|
||||
sessionManager *SessionManager
|
||||
link transport.Link
|
||||
done *done.Instance
|
||||
timer *time.Ticker
|
||||
strategy ClientStrategy
|
||||
}
|
||||
|
||||
@@ -187,6 +188,7 @@ func NewClientWorker(stream transport.Link, s ClientStrategy) (*ClientWorker, er
|
||||
sessionManager: NewSessionManager(),
|
||||
link: stream,
|
||||
done: done.New(),
|
||||
timer: time.NewTicker(time.Second * 16),
|
||||
strategy: s,
|
||||
}
|
||||
|
||||
@@ -209,9 +211,12 @@ func (m *ClientWorker) Closed() bool {
|
||||
return m.done.Done()
|
||||
}
|
||||
|
||||
func (m *ClientWorker) GetTimer() *time.Ticker {
|
||||
return m.timer
|
||||
}
|
||||
|
||||
func (m *ClientWorker) monitor() {
|
||||
timer := time.NewTicker(time.Second * 16)
|
||||
defer timer.Stop()
|
||||
defer m.timer.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
@@ -220,7 +225,7 @@ func (m *ClientWorker) monitor() {
|
||||
common.Close(m.link.Writer)
|
||||
common.Interrupt(m.link.Reader)
|
||||
return
|
||||
case <-timer.C:
|
||||
case <-m.timer.C:
|
||||
size := m.sessionManager.Size()
|
||||
if size == 0 && m.sessionManager.CloseIfNoSession() {
|
||||
common.Must(m.done.Close())
|
||||
@@ -276,6 +281,8 @@ func (m *ClientWorker) IsClosing() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsFull returns true if this ClientWorker is unable to accept more connections.
|
||||
// it might be because it is closing, or the number of connections has reached the limit.
|
||||
func (m *ClientWorker) IsFull() bool {
|
||||
if m.IsClosing() || m.Closed() {
|
||||
return true
|
||||
@@ -289,12 +296,12 @@ func (m *ClientWorker) IsFull() bool {
|
||||
}
|
||||
|
||||
func (m *ClientWorker) Dispatch(ctx context.Context, link *transport.Link) bool {
|
||||
if m.IsFull() || m.Closed() {
|
||||
if m.IsFull() {
|
||||
return false
|
||||
}
|
||||
|
||||
sm := m.sessionManager
|
||||
s := sm.Allocate()
|
||||
s := sm.Allocate(&m.strategy)
|
||||
if s == nil {
|
||||
return false
|
||||
}
|
||||
|
@@ -201,11 +201,12 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
|
||||
transferType: protocol.TransferTypePacket,
|
||||
XUDP: x,
|
||||
}
|
||||
go handle(ctx, x.Mux, w.link.Writer)
|
||||
x.Status = Active
|
||||
if !w.sessionManager.Add(x.Mux) {
|
||||
x.Mux.Close(false)
|
||||
return errors.New("failed to add new session")
|
||||
}
|
||||
go handle(ctx, x.Mux, w.link.Writer)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -226,18 +227,23 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
|
||||
if meta.Target.Network == net.Network_UDP {
|
||||
s.transferType = protocol.TransferTypePacket
|
||||
}
|
||||
w.sessionManager.Add(s)
|
||||
if !w.sessionManager.Add(s) {
|
||||
s.Close(false)
|
||||
return errors.New("failed to add new session")
|
||||
}
|
||||
go handle(ctx, s, w.link.Writer)
|
||||
if !meta.Option.Has(OptionData) {
|
||||
return nil
|
||||
}
|
||||
|
||||
rr := s.NewReader(reader, &meta.Target)
|
||||
if err := buf.Copy(rr, s.output); err != nil {
|
||||
buf.Copy(rr, buf.Discard)
|
||||
return s.Close(false)
|
||||
err = buf.Copy(rr, s.output)
|
||||
|
||||
if err != nil && buf.IsWriteError(err) {
|
||||
s.Close(false)
|
||||
return buf.Copy(rr, buf.Discard)
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||
@@ -304,10 +310,11 @@ func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedRead
|
||||
}
|
||||
|
||||
func (w *ServerWorker) run(ctx context.Context) {
|
||||
input := w.link.Reader
|
||||
reader := &buf.BufferedReader{Reader: input}
|
||||
reader := &buf.BufferedReader{Reader: w.link.Reader}
|
||||
|
||||
defer w.sessionManager.Close()
|
||||
defer common.Close(w.link.Writer)
|
||||
defer common.Interrupt(w.link.Reader)
|
||||
|
||||
for {
|
||||
select {
|
||||
@@ -318,7 +325,6 @@ func (w *ServerWorker) run(ctx context.Context) {
|
||||
if err != nil {
|
||||
if errors.Cause(err) != io.EOF {
|
||||
errors.LogInfoInner(ctx, err, "unexpected EOF")
|
||||
common.Interrupt(input)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@@ -50,11 +50,14 @@ func (m *SessionManager) Count() int {
|
||||
return int(m.count)
|
||||
}
|
||||
|
||||
func (m *SessionManager) Allocate() *Session {
|
||||
func (m *SessionManager) Allocate(Strategy *ClientStrategy) *Session {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
MaxConcurrency := int(Strategy.MaxConcurrency)
|
||||
MaxConnection := uint16(Strategy.MaxConnection)
|
||||
|
||||
if m.closed {
|
||||
if m.closed || (MaxConcurrency > 0 && len(m.sessions) >= MaxConcurrency) || (MaxConnection > 0 && m.count >= MaxConnection) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -9,7 +9,7 @@ import (
|
||||
func TestSessionManagerAdd(t *testing.T) {
|
||||
m := NewSessionManager()
|
||||
|
||||
s := m.Allocate()
|
||||
s := m.Allocate(&ClientStrategy{})
|
||||
if s.ID != 1 {
|
||||
t.Error("id: ", s.ID)
|
||||
}
|
||||
@@ -17,7 +17,7 @@ func TestSessionManagerAdd(t *testing.T) {
|
||||
t.Error("size: ", m.Size())
|
||||
}
|
||||
|
||||
s = m.Allocate()
|
||||
s = m.Allocate(&ClientStrategy{})
|
||||
if s.ID != 2 {
|
||||
t.Error("id: ", s.ID)
|
||||
}
|
||||
@@ -39,7 +39,7 @@ func TestSessionManagerAdd(t *testing.T) {
|
||||
|
||||
func TestSessionManagerClose(t *testing.T) {
|
||||
m := NewSessionManager()
|
||||
s := m.Allocate()
|
||||
s := m.Allocate(&ClientStrategy{})
|
||||
|
||||
if m.CloseIfNoSession() {
|
||||
t.Error("able to close")
|
||||
|
@@ -1 +1,7 @@
|
||||
package protocol // import "github.com/xtls/xray-core/common/protocol"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var ErrProtoNeedMoreData = errors.New("protocol matches, but need more data to complete sniffing")
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/tls"
|
||||
@@ -11,8 +10,8 @@ import (
|
||||
"github.com/quic-go/quic-go/quicvarint"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/bytespool"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
ptls "github.com/xtls/xray-core/common/protocol/tls"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
@@ -47,22 +46,17 @@ var (
|
||||
errNotQuicInitial = errors.New("not initial packet")
|
||||
)
|
||||
|
||||
func SniffQUIC(b []byte) (resultReturn *SniffHeader, errorReturn error) {
|
||||
// In extremely rare cases, this sniffer may cause slice error
|
||||
// and we set recover() here to prevent crash.
|
||||
// TODO: Thoroughly fix this panic
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
errors.LogError(context.Background(), "Failed to sniff QUIC: ", r)
|
||||
resultReturn = nil
|
||||
errorReturn = common.ErrNoClue
|
||||
}
|
||||
}()
|
||||
func SniffQUIC(b []byte) (*SniffHeader, error) {
|
||||
if len(b) == 0 {
|
||||
return nil, common.ErrNoClue
|
||||
}
|
||||
|
||||
// Crypto data separated across packets
|
||||
cryptoLen := 0
|
||||
cryptoData := bytespool.Alloc(int32(len(b)))
|
||||
defer bytespool.Free(cryptoData)
|
||||
cryptoLen := int32(0)
|
||||
cryptoDataBuf := buf.NewWithSize(32767)
|
||||
defer cryptoDataBuf.Release()
|
||||
cache := buf.New()
|
||||
defer cache.Release()
|
||||
|
||||
// Parse QUIC packets
|
||||
for len(b) > 0 {
|
||||
@@ -105,19 +99,25 @@ func SniffQUIC(b []byte) (resultReturn *SniffHeader, errorReturn error) {
|
||||
return nil, errNotQuic
|
||||
}
|
||||
|
||||
tokenLen, err := quicvarint.Read(buffer)
|
||||
if err != nil || tokenLen > uint64(len(b)) {
|
||||
return nil, errNotQuic
|
||||
}
|
||||
if isQuicInitial { // Only initial packets have token, see https://datatracker.ietf.org/doc/html/rfc9000#section-17.2.2
|
||||
tokenLen, err := quicvarint.Read(buffer)
|
||||
if err != nil || tokenLen > uint64(len(b)) {
|
||||
return nil, errNotQuic
|
||||
}
|
||||
|
||||
if _, err = buffer.ReadBytes(int32(tokenLen)); err != nil {
|
||||
return nil, errNotQuic
|
||||
if _, err = buffer.ReadBytes(int32(tokenLen)); err != nil {
|
||||
return nil, errNotQuic
|
||||
}
|
||||
}
|
||||
|
||||
packetLen, err := quicvarint.Read(buffer)
|
||||
if err != nil {
|
||||
return nil, errNotQuic
|
||||
}
|
||||
// packetLen is impossible to be shorter than this
|
||||
if packetLen < 4 {
|
||||
return nil, errNotQuic
|
||||
}
|
||||
|
||||
hdrLen := len(b) - int(buffer.Len())
|
||||
if len(b) < hdrLen+int(packetLen) {
|
||||
@@ -130,9 +130,6 @@ func SniffQUIC(b []byte) (resultReturn *SniffHeader, errorReturn error) {
|
||||
continue
|
||||
}
|
||||
|
||||
origPNBytes := make([]byte, 4)
|
||||
copy(origPNBytes, b[hdrLen:hdrLen+4])
|
||||
|
||||
var salt []byte
|
||||
if versionNumber == version1 {
|
||||
salt = quicSalt
|
||||
@@ -147,44 +144,34 @@ func SniffQUIC(b []byte) (resultReturn *SniffHeader, errorReturn error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cache := buf.New()
|
||||
defer cache.Release()
|
||||
|
||||
cache.Clear()
|
||||
mask := cache.Extend(int32(block.BlockSize()))
|
||||
block.Encrypt(mask, b[hdrLen+4:hdrLen+4+16])
|
||||
block.Encrypt(mask, b[hdrLen+4:hdrLen+4+len(mask)])
|
||||
b[0] ^= mask[0] & 0xf
|
||||
for i := range b[hdrLen : hdrLen+4] {
|
||||
packetNumberLength := int(b[0]&0x3 + 1)
|
||||
for i := range packetNumberLength {
|
||||
b[hdrLen+i] ^= mask[i+1]
|
||||
}
|
||||
packetNumberLength := b[0]&0x3 + 1
|
||||
if packetNumberLength != 1 {
|
||||
return nil, errNotQuicInitial
|
||||
}
|
||||
var packetNumber uint32
|
||||
{
|
||||
n, err := buffer.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
packetNumber = uint32(n)
|
||||
}
|
||||
|
||||
extHdrLen := hdrLen + int(packetNumberLength)
|
||||
copy(b[extHdrLen:hdrLen+4], origPNBytes[packetNumberLength:])
|
||||
data := b[extHdrLen : int(packetLen)+hdrLen]
|
||||
|
||||
key := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic key", 16)
|
||||
iv := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic iv", 12)
|
||||
cipher := AEADAESGCMTLS13(key, iv)
|
||||
|
||||
nonce := cache.Extend(int32(cipher.NonceSize()))
|
||||
binary.BigEndian.PutUint64(nonce[len(nonce)-8:], uint64(packetNumber))
|
||||
_, err = buffer.Read(nonce[len(nonce)-packetNumberLength:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
extHdrLen := hdrLen + packetNumberLength
|
||||
data := b[extHdrLen : int(packetLen)+hdrLen]
|
||||
decrypted, err := cipher.Open(b[extHdrLen:extHdrLen], nonce, data, b[:extHdrLen])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buffer = buf.FromBytes(decrypted)
|
||||
for i := 0; !buffer.IsEmpty(); i++ {
|
||||
frameType := byte(0x0) // Default to PADDING frame
|
||||
for !buffer.IsEmpty() {
|
||||
frameType, _ := buffer.ReadByte()
|
||||
for frameType == 0x0 && !buffer.IsEmpty() {
|
||||
frameType, _ = buffer.ReadByte()
|
||||
}
|
||||
@@ -233,16 +220,15 @@ func SniffQUIC(b []byte) (resultReturn *SniffHeader, errorReturn error) {
|
||||
if err != nil || length > uint64(buffer.Len()) {
|
||||
return nil, io.ErrUnexpectedEOF
|
||||
}
|
||||
if cryptoLen < int(offset+length) {
|
||||
cryptoLen = int(offset + length)
|
||||
if len(cryptoData) < cryptoLen {
|
||||
newCryptoData := bytespool.Alloc(int32(cryptoLen))
|
||||
copy(newCryptoData, cryptoData)
|
||||
bytespool.Free(cryptoData)
|
||||
cryptoData = newCryptoData
|
||||
currentCryptoLen := int32(offset + length)
|
||||
if cryptoLen < currentCryptoLen {
|
||||
if cryptoDataBuf.Cap() < currentCryptoLen {
|
||||
return nil, io.ErrShortBuffer
|
||||
}
|
||||
cryptoDataBuf.Extend(currentCryptoLen - cryptoLen)
|
||||
cryptoLen = currentCryptoLen
|
||||
}
|
||||
if _, err := buffer.Read(cryptoData[offset : offset+length]); err != nil { // Field: Crypto Data
|
||||
if _, err := buffer.Read(cryptoDataBuf.BytesRange(int32(offset), currentCryptoLen)); err != nil { // Field: Crypto Data
|
||||
return nil, io.ErrUnexpectedEOF
|
||||
}
|
||||
case 0x1c: // CONNECTION_CLOSE frame, only 0x1c is permitted in initial packet
|
||||
@@ -267,7 +253,7 @@ func SniffQUIC(b []byte) (resultReturn *SniffHeader, errorReturn error) {
|
||||
}
|
||||
|
||||
tlsHdr := &ptls.SniffHeader{}
|
||||
err = ptls.ReadClientHello(cryptoData[:cryptoLen], tlsHdr)
|
||||
err = ptls.ReadClientHello(cryptoDataBuf.BytesRange(0, cryptoLen), tlsHdr)
|
||||
if err != nil {
|
||||
// The crypto data may have not been fully recovered in current packets,
|
||||
// So we continue to sniff rest packets.
|
||||
@@ -276,7 +262,8 @@ func SniffQUIC(b []byte) (resultReturn *SniffHeader, errorReturn error) {
|
||||
}
|
||||
return &SniffHeader{domain: tlsHdr.Domain()}, nil
|
||||
}
|
||||
return nil, common.ErrNoClue
|
||||
// All payload is parsed as valid QUIC packets, but we need more packets for crypto data to read client hello.
|
||||
return nil, protocol.ErrProtoNeedMoreData
|
||||
}
|
||||
|
||||
func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, length int) []byte {
|
||||
|
File diff suppressed because one or more lines are too long
@@ -3,9 +3,9 @@ package tls
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
)
|
||||
|
||||
type SniffHeader struct {
|
||||
@@ -59,9 +59,6 @@ func ReadClientHello(data []byte, h *SniffHeader) error {
|
||||
}
|
||||
data = data[1+compressionMethodsLen:]
|
||||
|
||||
if len(data) == 0 {
|
||||
return errNotClientHello
|
||||
}
|
||||
if len(data) < 2 {
|
||||
return errNotClientHello
|
||||
}
|
||||
@@ -104,13 +101,21 @@ func ReadClientHello(data []byte, h *SniffHeader) error {
|
||||
return errNotClientHello
|
||||
}
|
||||
if nameType == 0 {
|
||||
serverName := string(d[:nameLen])
|
||||
// QUIC separated across packets
|
||||
// May cause the serverName to be incomplete
|
||||
b := byte(0)
|
||||
for _, b = range d[:nameLen] {
|
||||
if b <= ' ' {
|
||||
return protocol.ErrProtoNeedMoreData
|
||||
}
|
||||
}
|
||||
// An SNI value may not include a
|
||||
// trailing dot. See
|
||||
// https://tools.ietf.org/html/rfc6066#section-3.
|
||||
if strings.HasSuffix(serverName, ".") {
|
||||
if b == '.' {
|
||||
return errNotClientHello
|
||||
}
|
||||
serverName := string(d[:nameLen])
|
||||
h.domain = serverName
|
||||
return nil
|
||||
}
|
||||
|
@@ -36,6 +36,8 @@ func ExportIDToError(ctx context.Context) errors.ExportOption {
|
||||
type Inbound struct {
|
||||
// Source address of the inbound connection.
|
||||
Source net.Destination
|
||||
// Local address of the inbound connection.
|
||||
Local net.Destination
|
||||
// Gateway address.
|
||||
Gateway net.Destination
|
||||
// Tag of the inbound proxy that handles the connection.
|
||||
|
@@ -67,9 +67,9 @@ func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
|
||||
t.checkTask.Close()
|
||||
}
|
||||
t.checkTask = checkTask
|
||||
t.Unlock()
|
||||
t.Update()
|
||||
common.Must(checkTask.Start())
|
||||
t.Unlock()
|
||||
}
|
||||
|
||||
func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
|
||||
|
112
common/utils/typed_sync_map.go
Normal file
112
common/utils/typed_sync_map.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// TypedSyncMap is a wrapper of sync.Map that provides type-safe for keys and values.
|
||||
// No need to use type assertions every time, so you can have more time to enjoy other things like GochiUsa
|
||||
// If sync.Map methods returned nil, it will return the zero value of the type V.
|
||||
type TypedSyncMap[K, V any] struct {
|
||||
syncMap *sync.Map
|
||||
}
|
||||
|
||||
// NewTypedSyncMap creates a new TypedSyncMap
|
||||
// K is key type, V is value type
|
||||
// It is recommended to use pointer types for V because sync.Map might return nil
|
||||
// If sync.Map methods really returned nil, it will return the zero value of the type V
|
||||
func NewTypedSyncMap[K any, V any]() *TypedSyncMap[K, V] {
|
||||
return &TypedSyncMap[K, V]{
|
||||
syncMap: &sync.Map{},
|
||||
}
|
||||
}
|
||||
|
||||
// Clear deletes all the entries, resulting in an empty Map.
|
||||
func (m *TypedSyncMap[K, V]) Clear() {
|
||||
m.syncMap.Clear()
|
||||
}
|
||||
|
||||
// CompareAndDelete deletes the entry for key if its value is equal to old.
|
||||
// The old value must be of a comparable type.
|
||||
//
|
||||
// If there is no current value for key in the map, CompareAndDelete
|
||||
// returns false (even if the old value is the nil interface value).
|
||||
func (m *TypedSyncMap[K, V]) CompareAndDelete(key K, old V) (deleted bool) {
|
||||
return m.syncMap.CompareAndDelete(key, old)
|
||||
}
|
||||
|
||||
// CompareAndSwap swaps the old and new values for key
|
||||
// if the value stored in the map is equal to old.
|
||||
// The old value must be of a comparable type.
|
||||
func (m *TypedSyncMap[K, V]) CompareAndSwap(key K, old V, new V) (swapped bool) {
|
||||
return m.syncMap.CompareAndSwap(key, old, new)
|
||||
}
|
||||
|
||||
// Delete deletes the value for a key.
|
||||
func (m *TypedSyncMap[K, V]) Delete(key K) {
|
||||
m.syncMap.Delete(key)
|
||||
}
|
||||
|
||||
// Load returns the value stored in the map for a key, or nil if no
|
||||
// value is present.
|
||||
// The ok result indicates whether value was found in the map.
|
||||
func (m *TypedSyncMap[K, V]) Load(key K) (value V, ok bool) {
|
||||
anyValue, ok := m.syncMap.Load(key)
|
||||
// anyValue might be nil
|
||||
if anyValue != nil {
|
||||
value = anyValue.(V)
|
||||
}
|
||||
return value, ok
|
||||
}
|
||||
|
||||
// LoadAndDelete deletes the value for a key, returning the previous value if any.
|
||||
// The loaded result reports whether the key was present.
|
||||
func (m *TypedSyncMap[K, V]) LoadAndDelete(key K) (value V, loaded bool) {
|
||||
anyValue, loaded := m.syncMap.LoadAndDelete(key)
|
||||
if anyValue != nil {
|
||||
value = anyValue.(V)
|
||||
}
|
||||
return value, loaded
|
||||
}
|
||||
|
||||
// LoadOrStore returns the existing value for the key if present.
|
||||
// Otherwise, it stores and returns the given value.
|
||||
// The loaded result is true if the value was loaded, false if stored.
|
||||
func (m *TypedSyncMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) {
|
||||
anyActual, loaded := m.syncMap.LoadOrStore(key, value)
|
||||
if anyActual != nil {
|
||||
actual = anyActual.(V)
|
||||
}
|
||||
return actual, loaded
|
||||
}
|
||||
|
||||
// Range calls f sequentially for each key and value present in the map.
|
||||
// If f returns false, range stops the iteration.
|
||||
//
|
||||
// Range does not necessarily correspond to any consistent snapshot of the Map's
|
||||
// contents: no key will be visited more than once, but if the value for any key
|
||||
// is stored or deleted concurrently (including by f), Range may reflect any
|
||||
// mapping for that key from any point during the Range call. Range does not
|
||||
// block other methods on the receiver; even f itself may call any method on m.
|
||||
//
|
||||
// Range may be O(N) with the number of elements in the map even if f returns
|
||||
// false after a constant number of calls.
|
||||
func (m *TypedSyncMap[K, V]) Range(f func(key K, value V) bool) {
|
||||
m.syncMap.Range(func(key, value any) bool {
|
||||
return f(key.(K), value.(V))
|
||||
})
|
||||
}
|
||||
|
||||
// Store sets the value for a key.
|
||||
func (m *TypedSyncMap[K, V]) Store(key K, value V) {
|
||||
m.syncMap.Store(key, value)
|
||||
}
|
||||
|
||||
// Swap swaps the value for a key and returns the previous value if any. The loaded result reports whether the key was present.
|
||||
func (m *TypedSyncMap[K, V]) Swap(key K, value V) (previous V, loaded bool) {
|
||||
anyPrevious, loaded := m.syncMap.Swap(key, value)
|
||||
if anyPrevious != nil {
|
||||
previous = anyPrevious.(V)
|
||||
}
|
||||
return previous, loaded
|
||||
}
|
@@ -18,8 +18,8 @@ import (
|
||||
|
||||
var (
|
||||
Version_x byte = 25
|
||||
Version_y byte = 3
|
||||
Version_z byte = 31
|
||||
Version_y byte = 8
|
||||
Version_z byte = 3
|
||||
)
|
||||
|
||||
var (
|
||||
|
@@ -90,6 +90,11 @@ type Instance struct {
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// Instance state
|
||||
func (server *Instance) IsRunning() bool {
|
||||
return server.running
|
||||
}
|
||||
|
||||
func AddInboundHandler(server *Instance, config *InboundHandlerConfig) error {
|
||||
inboundManager := server.GetFeature(inbound.ManagerType()).(inbound.Manager)
|
||||
rawHandler, err := CreateObject(server, config)
|
||||
|
@@ -24,10 +24,6 @@ type Client interface {
|
||||
LookupIP(domain string, option IPOption) ([]net.IP, uint32, error)
|
||||
}
|
||||
|
||||
type HostsLookup interface {
|
||||
LookupHosts(domain string) *net.Address
|
||||
}
|
||||
|
||||
// ClientType returns the type of Client interface. Can be used for implementing common.HasType.
|
||||
//
|
||||
// xray:api:beta
|
||||
@@ -38,12 +34,32 @@ func ClientType() interface{} {
|
||||
// ErrEmptyResponse indicates that DNS query succeeded but no answer was returned.
|
||||
var ErrEmptyResponse = errors.New("empty response")
|
||||
|
||||
const DefaultTTL = 300
|
||||
|
||||
type RCodeError uint16
|
||||
|
||||
func (e RCodeError) Error() string {
|
||||
return serial.Concat("rcode: ", uint16(e))
|
||||
}
|
||||
|
||||
func (RCodeError) IP() net.IP {
|
||||
panic("Calling IP() on a RCodeError.")
|
||||
}
|
||||
|
||||
func (RCodeError) Domain() string {
|
||||
panic("Calling Domain() on a RCodeError.")
|
||||
}
|
||||
|
||||
func (RCodeError) Family() net.AddressFamily {
|
||||
panic("Calling Family() on a RCodeError.")
|
||||
}
|
||||
|
||||
func (e RCodeError) String() string {
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
var _ net.Address = (*RCodeError)(nil)
|
||||
|
||||
func RCodeFromError(err error) uint16 {
|
||||
if err == nil {
|
||||
return 0
|
||||
|
@@ -30,29 +30,31 @@ func (*Client) LookupIP(host string, option dns.IPOption) ([]net.IP, uint32, err
|
||||
ipv6 := make([]net.IP, 0, len(ips))
|
||||
for _, ip := range ips {
|
||||
parsed := net.IPAddress(ip)
|
||||
if parsed != nil {
|
||||
parsedIPs = append(parsedIPs, parsed.IP())
|
||||
if parsed == nil {
|
||||
continue
|
||||
}
|
||||
if len(ip) == net.IPv4len {
|
||||
ipv4 = append(ipv4, ip)
|
||||
}
|
||||
if len(ip) == net.IPv6len {
|
||||
ipv6 = append(ipv6, ip)
|
||||
parsedIP := parsed.IP()
|
||||
parsedIPs = append(parsedIPs, parsedIP)
|
||||
|
||||
if len(parsedIP) == net.IPv4len {
|
||||
ipv4 = append(ipv4, parsedIP)
|
||||
} else {
|
||||
ipv6 = append(ipv6, parsedIP)
|
||||
}
|
||||
}
|
||||
// Local DNS ttl is 600
|
||||
|
||||
switch {
|
||||
case option.IPv4Enable && option.IPv6Enable:
|
||||
if len(parsedIPs) > 0 {
|
||||
return parsedIPs, 600, nil
|
||||
return parsedIPs, dns.DefaultTTL, nil
|
||||
}
|
||||
case option.IPv4Enable:
|
||||
if len(ipv4) > 0 {
|
||||
return ipv4, 600, nil
|
||||
return ipv4, dns.DefaultTTL, nil
|
||||
}
|
||||
case option.IPv6Enable:
|
||||
if len(ipv6) > 0 {
|
||||
return ipv6, 600, nil
|
||||
return ipv6, dns.DefaultTTL, nil
|
||||
}
|
||||
}
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/features"
|
||||
)
|
||||
|
||||
@@ -15,6 +16,10 @@ type Handler interface {
|
||||
common.Runnable
|
||||
// The tag of this handler.
|
||||
Tag() string
|
||||
// Returns the active receiver settings.
|
||||
ReceiverSettings() *serial.TypedMessage
|
||||
// Returns the active proxy settings.
|
||||
ProxySettings() *serial.TypedMessage
|
||||
|
||||
// Deprecated: Do not use in new code.
|
||||
GetRandomInboundProxy() (interface{}, net.Port, int)
|
||||
@@ -32,6 +37,9 @@ type Manager interface {
|
||||
|
||||
// RemoveHandler removes a handler from Manager.
|
||||
RemoveHandler(ctx context.Context, tag string) error
|
||||
|
||||
// ListHandlers returns a list of inbound.Handler.
|
||||
ListHandlers(ctx context.Context) []Handler
|
||||
}
|
||||
|
||||
// ManagerType returns the type of Manager interface. Can be used for implementing common.HasType.
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/features"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
)
|
||||
@@ -15,6 +16,8 @@ type Handler interface {
|
||||
common.Runnable
|
||||
Tag() string
|
||||
Dispatch(ctx context.Context, link *transport.Link)
|
||||
SenderSettings() *serial.TypedMessage
|
||||
ProxySettings() *serial.TypedMessage
|
||||
}
|
||||
|
||||
type HandlerSelector interface {
|
||||
@@ -35,6 +38,9 @@ type Manager interface {
|
||||
|
||||
// RemoveHandler removes a handler from outbound.Manager.
|
||||
RemoveHandler(ctx context.Context, tag string) error
|
||||
|
||||
// ListHandlers returns a list of outbound.Handler.
|
||||
ListHandlers(ctx context.Context) []Handler
|
||||
}
|
||||
|
||||
// ManagerType returns the type of Manager interface. Can be used to implement common.HasType.
|
||||
|
@@ -23,6 +23,12 @@ type Context interface {
|
||||
// GetTargetPort returns the target port of the connection.
|
||||
GetTargetPort() net.Port
|
||||
|
||||
// GetLocalIPs returns the local IPs bound to the connection.
|
||||
GetLocalIPs() []net.IP
|
||||
|
||||
// GetLocalPort returns the local port of the connection.
|
||||
GetLocalPort() net.Port
|
||||
|
||||
// GetTargetDomain returns the target domain of the connection, if exists.
|
||||
GetTargetDomain() string
|
||||
|
||||
|
@@ -28,12 +28,13 @@ func (ctx *Context) GetSourceIPs() []net.IP {
|
||||
if ctx.Inbound == nil || !ctx.Inbound.Source.IsValid() {
|
||||
return nil
|
||||
}
|
||||
dest := ctx.Inbound.Source
|
||||
if dest.Address.Family().IsDomain() {
|
||||
return nil
|
||||
|
||||
if ctx.Inbound.Source.Address.Family().IsIP() {
|
||||
return []net.IP{ctx.Inbound.Source.Address.IP()}
|
||||
}
|
||||
|
||||
return []net.IP{dest.Address.IP()}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// GetSourcePort implements routing.Context.
|
||||
@@ -65,6 +66,27 @@ func (ctx *Context) GetTargetPort() net.Port {
|
||||
return ctx.Outbound.Target.Port
|
||||
}
|
||||
|
||||
// GetLocalIPs implements routing.Context.
|
||||
func (ctx *Context) GetLocalIPs() []net.IP {
|
||||
if ctx.Inbound == nil || !ctx.Inbound.Local.IsValid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if ctx.Inbound.Local.Address.Family().IsIP() {
|
||||
return []net.IP{ctx.Inbound.Local.Address.IP()}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLocalPort implements routing.Context.
|
||||
func (ctx *Context) GetLocalPort() net.Port {
|
||||
if ctx.Inbound == nil || !ctx.Inbound.Local.IsValid() {
|
||||
return 0
|
||||
}
|
||||
return ctx.Inbound.Local.Port
|
||||
}
|
||||
|
||||
// GetTargetDomain implements routing.Context.
|
||||
func (ctx *Context) GetTargetDomain() string {
|
||||
if ctx.Outbound == nil || !ctx.Outbound.Target.IsValid() {
|
||||
|
55
go.mod
55
go.mod
@@ -3,59 +3,56 @@ module github.com/xtls/xray-core
|
||||
go 1.24
|
||||
|
||||
require (
|
||||
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0
|
||||
github.com/cloudflare/circl v1.6.0
|
||||
github.com/cloudflare/circl v1.6.1
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
||||
github.com/golang/mock v1.7.0-rc.1
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/miekg/dns v1.1.64
|
||||
github.com/miekg/dns v1.1.68
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/pires/go-proxyproto v0.8.0
|
||||
github.com/quic-go/quic-go v0.50.1
|
||||
github.com/refraction-networking/utls v1.6.7
|
||||
github.com/pires/go-proxyproto v0.8.1
|
||||
github.com/quic-go/quic-go v0.54.0
|
||||
github.com/refraction-networking/utls v1.8.0
|
||||
github.com/sagernet/sing v0.5.1
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
|
||||
github.com/vishvananda/netlink v1.3.0
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||
golang.org/x/crypto v0.36.0
|
||||
golang.org/x/net v0.38.0
|
||||
golang.org/x/sync v0.12.0
|
||||
golang.org/x/sys v0.31.0
|
||||
golang.org/x/crypto v0.41.0
|
||||
golang.org/x/net v0.43.0
|
||||
golang.org/x/sync v0.16.0
|
||||
golang.org/x/sys v0.35.0
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||
google.golang.org/grpc v1.71.0
|
||||
google.golang.org/protobuf v1.36.6
|
||||
gvisor.dev/gvisor v0.0.0-20240320123526-dc6abceb7ff0
|
||||
google.golang.org/grpc v1.74.2
|
||||
google.golang.org/protobuf v1.36.7
|
||||
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5
|
||||
h12.io/socks v1.0.3
|
||||
lukechampine.com/blake3 v1.4.0
|
||||
lukechampine.com/blake3 v1.4.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect
|
||||
github.com/klauspost/compress v1.17.8 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 // indirect
|
||||
github.com/juju/ratelimit v1.0.2 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect
|
||||
golang.org/x/mod v0.23.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
golang.org/x/mod v0.26.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
golang.org/x/tools v0.30.0 // indirect
|
||||
golang.org/x/tools v0.35.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
145
go.sum
145
go.sum
@@ -1,23 +1,19 @@
|
||||
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 h1:Wo41lDOevRJSGpevP+8Pk5bANX7fJacO2w04aqLiC5I=
|
||||
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
|
||||
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
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/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0=
|
||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=
|
||||
github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
@@ -26,40 +22,43 @@ github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
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/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/miekg/dns v1.1.64 h1:wuZgD9wwCE6XMT05UU/mlSko71eRSXEAm2EbjQXLKnQ=
|
||||
github.com/miekg/dns v1.1.64/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
|
||||
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
|
||||
github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI=
|
||||
github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
|
||||
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
|
||||
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
|
||||
github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||
github.com/pires/go-proxyproto v0.8.0 h1:5unRmEAPbHXHuLjDg01CxJWf91cw3lKHc/0xzKpXEe0=
|
||||
github.com/pires/go-proxyproto v0.8.0/go.mod h1:iknsfgnH8EkjrMeMyvfKByp9TiBZCKZM0jx2xmKqnVY=
|
||||
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
||||
github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
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/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.50.1 h1:unsgjFIUqW8a2oopkY7YNONpV1gYND6Nt9hnt1PN94Q=
|
||||
github.com/quic-go/quic-go v0.50.1/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E=
|
||||
github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
|
||||
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
|
||||
github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
|
||||
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
|
||||
github.com/refraction-networking/utls v1.8.0 h1:L38krhiTAyj9EeiQQa2sg+hYb4qwLCqdMcpZrRfbONE=
|
||||
github.com/refraction-networking/utls v1.8.0/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
||||
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||
@@ -72,70 +71,67 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
|
||||
github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
|
||||
github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
|
||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d h1:+B97uD9uHLgAAulhigmys4BVwZZypzK7gPN3WtpgRJg=
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE=
|
||||
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
|
||||
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
|
||||
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7 h1:Ript0vN+nSO33+Vj4n0mgNY5M+oOxFQJdrJ1VnwTBO0=
|
||||
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7/go.mod h1:XxvnCCgBee4WWE0bc4E+a7wbk8gkJ/rS0vNVNtC5qp0=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg=
|
||||
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
|
||||
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
|
||||
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
|
||||
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
|
||||
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
|
||||
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -143,14 +139,15 @@ golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeu
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50=
|
||||
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
|
||||
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
|
||||
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
@@ -158,9 +155,9 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gvisor.dev/gvisor v0.0.0-20240320123526-dc6abceb7ff0 h1:P+U/06iIKPQ3DLcg+zBfSCia1luZ2msPZrJ8jYDFPs0=
|
||||
gvisor.dev/gvisor v0.0.0-20240320123526-dc6abceb7ff0/go.mod h1:NQHVAzMwvZ+Qe3ElSiHmq9RUm1MdNHpUZ52fiEqvn+0=
|
||||
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5 h1:sfK5nHuG7lRFZ2FdTT3RimOqWBg8IrVm+/Vko1FVOsk=
|
||||
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5/go.mod h1:3r5CMtNQMKIvBlrmM9xWUNamjKBYPOWyXOjmg5Kts3g=
|
||||
h12.io/socks v1.0.3 h1:Ka3qaQewws4j4/eDQnOdpr4wXsC//dXtWvftlIcCQUo=
|
||||
h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
|
||||
lukechampine.com/blake3 v1.4.0 h1:xDbKOZCVbnZsfzM6mHSYcGRHZ3YrLDzqz8XnV4uaD5w=
|
||||
lukechampine.com/blake3 v1.4.0/go.mod h1:MQJNQCTnR+kwOP/JEZSxj3MaQjp80FOFSNMMHXcSeX0=
|
||||
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
|
||||
lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=
|
||||
|
@@ -8,11 +8,13 @@ import (
|
||||
|
||||
type Duration int64
|
||||
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (d *Duration) MarshalJSON() ([]byte, error) {
|
||||
dr := time.Duration(*d)
|
||||
return json.Marshal(dr.String())
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (d *Duration) UnmarshalJSON(b []byte) error {
|
||||
var v interface{}
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
|
@@ -23,6 +23,7 @@ func (v StringList) Len() int {
|
||||
return len(v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (v *StringList) UnmarshalJSON(data []byte) error {
|
||||
var strarray []string
|
||||
if err := json.Unmarshal(data, &strarray); err == nil {
|
||||
@@ -43,10 +44,12 @@ type Address struct {
|
||||
net.Address
|
||||
}
|
||||
|
||||
func (v Address) MarshalJSON() ([]byte, error) {
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (v *Address) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.Address.String())
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (v *Address) UnmarshalJSON(data []byte) error {
|
||||
var rawStr string
|
||||
if err := json.Unmarshal(data, &rawStr); err != nil {
|
||||
@@ -81,6 +84,7 @@ func (v Network) Build() net.Network {
|
||||
|
||||
type NetworkList []Network
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (v *NetworkList) UnmarshalJSON(data []byte) error {
|
||||
var strarray []Network
|
||||
if err := json.Unmarshal(data, &strarray); err == nil {
|
||||
@@ -169,6 +173,19 @@ func (v *PortRange) Build() *net.PortRange {
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (v *PortRange) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.String())
|
||||
}
|
||||
|
||||
func (port *PortRange) String() string {
|
||||
if port.From == port.To {
|
||||
return strconv.Itoa(int(port.From))
|
||||
} else {
|
||||
return fmt.Sprintf("%d-%d", port.From, port.To)
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (v *PortRange) UnmarshalJSON(data []byte) error {
|
||||
port, err := parseIntPort(data)
|
||||
@@ -203,20 +220,21 @@ func (list *PortList) Build() *net.PortList {
|
||||
return portList
|
||||
}
|
||||
|
||||
func (v PortList) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.String())
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (v *PortList) MarshalJSON() ([]byte, error) {
|
||||
portStr := v.String()
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err == nil {
|
||||
return json.Marshal(port)
|
||||
} else {
|
||||
return json.Marshal(portStr)
|
||||
}
|
||||
}
|
||||
|
||||
func (v PortList) String() string {
|
||||
ports := []string{}
|
||||
for _, port := range v.Range {
|
||||
if port.From == port.To {
|
||||
p := strconv.Itoa(int(port.From))
|
||||
ports = append(ports, p)
|
||||
} else {
|
||||
p := fmt.Sprintf("%d-%d", port.From, port.To)
|
||||
ports = append(ports, p)
|
||||
}
|
||||
ports = append(ports, port.String())
|
||||
}
|
||||
return strings.Join(ports, ",")
|
||||
}
|
||||
@@ -277,7 +295,8 @@ type Int32Range struct {
|
||||
To int32
|
||||
}
|
||||
|
||||
func (v Int32Range) MarshalJSON() ([]byte, error) {
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (v *Int32Range) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.String())
|
||||
}
|
||||
|
||||
@@ -289,6 +308,7 @@ func (v Int32Range) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (v *Int32Range) UnmarshalJSON(data []byte) error {
|
||||
defer v.ensureOrder()
|
||||
var str string
|
||||
|
@@ -1,7 +1,11 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@@ -12,19 +16,22 @@ import (
|
||||
)
|
||||
|
||||
type NameServerConfig struct {
|
||||
Address *Address `json:"address"`
|
||||
ClientIP *Address `json:"clientIp"`
|
||||
Port uint16 `json:"port"`
|
||||
SkipFallback bool `json:"skipFallback"`
|
||||
Domains []string `json:"domains"`
|
||||
ExpectedIPs StringList `json:"expectedIPs"`
|
||||
ExpectIPs StringList `json:"expectIPs"`
|
||||
QueryStrategy string `json:"queryStrategy"`
|
||||
AllowUnexpectedIPs bool `json:"allowUnexpectedIps"`
|
||||
Tag string `json:"tag"`
|
||||
TimeoutMs uint64 `json:"timeoutMs"`
|
||||
Address *Address `json:"address"`
|
||||
ClientIP *Address `json:"clientIp"`
|
||||
Port uint16 `json:"port"`
|
||||
SkipFallback bool `json:"skipFallback"`
|
||||
Domains []string `json:"domains"`
|
||||
ExpectedIPs StringList `json:"expectedIPs"`
|
||||
ExpectIPs StringList `json:"expectIPs"`
|
||||
QueryStrategy string `json:"queryStrategy"`
|
||||
Tag string `json:"tag"`
|
||||
TimeoutMs uint64 `json:"timeoutMs"`
|
||||
DisableCache bool `json:"disableCache"`
|
||||
FinalQuery bool `json:"finalQuery"`
|
||||
UnexpectedIPs StringList `json:"unexpectedIPs"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
|
||||
var address Address
|
||||
if err := json.Unmarshal(data, &address); err == nil {
|
||||
@@ -33,17 +40,19 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
|
||||
}
|
||||
|
||||
var advanced struct {
|
||||
Address *Address `json:"address"`
|
||||
ClientIP *Address `json:"clientIp"`
|
||||
Port uint16 `json:"port"`
|
||||
SkipFallback bool `json:"skipFallback"`
|
||||
Domains []string `json:"domains"`
|
||||
ExpectedIPs StringList `json:"expectedIPs"`
|
||||
ExpectIPs StringList `json:"expectIPs"`
|
||||
QueryStrategy string `json:"queryStrategy"`
|
||||
AllowUnexpectedIPs bool `json:"allowUnexpectedIps"`
|
||||
Tag string `json:"tag"`
|
||||
TimeoutMs uint64 `json:"timeoutMs"`
|
||||
Address *Address `json:"address"`
|
||||
ClientIP *Address `json:"clientIp"`
|
||||
Port uint16 `json:"port"`
|
||||
SkipFallback bool `json:"skipFallback"`
|
||||
Domains []string `json:"domains"`
|
||||
ExpectedIPs StringList `json:"expectedIPs"`
|
||||
ExpectIPs StringList `json:"expectIPs"`
|
||||
QueryStrategy string `json:"queryStrategy"`
|
||||
Tag string `json:"tag"`
|
||||
TimeoutMs uint64 `json:"timeoutMs"`
|
||||
DisableCache bool `json:"disableCache"`
|
||||
FinalQuery bool `json:"finalQuery"`
|
||||
UnexpectedIPs StringList `json:"unexpectedIPs"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &advanced); err == nil {
|
||||
c.Address = advanced.Address
|
||||
@@ -54,9 +63,11 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
|
||||
c.ExpectedIPs = advanced.ExpectedIPs
|
||||
c.ExpectIPs = advanced.ExpectIPs
|
||||
c.QueryStrategy = advanced.QueryStrategy
|
||||
c.AllowUnexpectedIPs = advanced.AllowUnexpectedIPs
|
||||
c.Tag = advanced.Tag
|
||||
c.TimeoutMs = advanced.TimeoutMs
|
||||
c.DisableCache = advanced.DisableCache
|
||||
c.FinalQuery = advanced.FinalQuery
|
||||
c.UnexpectedIPs = advanced.UnexpectedIPs
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -104,13 +115,38 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
|
||||
})
|
||||
}
|
||||
|
||||
var expectedIPs = c.ExpectedIPs
|
||||
if len(expectedIPs) == 0 {
|
||||
expectedIPs = c.ExpectIPs
|
||||
if len(c.ExpectedIPs) == 0 {
|
||||
c.ExpectedIPs = c.ExpectIPs
|
||||
}
|
||||
geoipList, err := ToCidrList(expectedIPs)
|
||||
|
||||
actPrior := false
|
||||
var newExpectedIPs StringList
|
||||
for _, s := range c.ExpectedIPs {
|
||||
if s == "*" {
|
||||
actPrior = true
|
||||
} else {
|
||||
newExpectedIPs = append(newExpectedIPs, s)
|
||||
}
|
||||
}
|
||||
|
||||
actUnprior := false
|
||||
var newUnexpectedIPs StringList
|
||||
for _, s := range c.UnexpectedIPs {
|
||||
if s == "*" {
|
||||
actUnprior = true
|
||||
} else {
|
||||
newUnexpectedIPs = append(newUnexpectedIPs, s)
|
||||
}
|
||||
}
|
||||
|
||||
expectedGeoipList, err := ToCidrList(newExpectedIPs)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid IP rule: ", expectedIPs).Base(err)
|
||||
return nil, errors.New("invalid expected IP rule: ", c.ExpectedIPs).Base(err)
|
||||
}
|
||||
|
||||
unexpectedGeoipList, err := ToCidrList(newUnexpectedIPs)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid unexpected IP rule: ", c.UnexpectedIPs).Base(err)
|
||||
}
|
||||
|
||||
var myClientIP []byte
|
||||
@@ -127,15 +163,19 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
|
||||
Address: c.Address.Build(),
|
||||
Port: uint32(c.Port),
|
||||
},
|
||||
ClientIp: myClientIP,
|
||||
SkipFallback: c.SkipFallback,
|
||||
PrioritizedDomain: domains,
|
||||
Geoip: geoipList,
|
||||
OriginalRules: originalRules,
|
||||
QueryStrategy: resolveQueryStrategy(c.QueryStrategy),
|
||||
AllowUnexpectedIPs: c.AllowUnexpectedIPs,
|
||||
Tag: c.Tag,
|
||||
TimeoutMs: c.TimeoutMs,
|
||||
ClientIp: myClientIP,
|
||||
SkipFallback: c.SkipFallback,
|
||||
PrioritizedDomain: domains,
|
||||
ExpectedGeoip: expectedGeoipList,
|
||||
OriginalRules: originalRules,
|
||||
QueryStrategy: resolveQueryStrategy(c.QueryStrategy),
|
||||
ActPrior: actPrior,
|
||||
Tag: c.Tag,
|
||||
TimeoutMs: c.TimeoutMs,
|
||||
DisableCache: c.DisableCache,
|
||||
FinalQuery: c.FinalQuery,
|
||||
UnexpectedGeoip: unexpectedGeoipList,
|
||||
ActUnprior: actUnprior,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -156,6 +196,7 @@ type DNSConfig struct {
|
||||
DisableCache bool `json:"disableCache"`
|
||||
DisableFallback bool `json:"disableFallback"`
|
||||
DisableFallbackIfMatch bool `json:"disableFallbackIfMatch"`
|
||||
UseSystemHosts bool `json:"useSystemHosts"`
|
||||
}
|
||||
|
||||
type HostAddress struct {
|
||||
@@ -163,6 +204,18 @@ type HostAddress struct {
|
||||
addrs []*Address
|
||||
}
|
||||
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (h *HostAddress) MarshalJSON() ([]byte, error) {
|
||||
if (h.addr != nil) != (h.addrs != nil) {
|
||||
if h.addr != nil {
|
||||
return json.Marshal(h.addr)
|
||||
} else if h.addrs != nil {
|
||||
return json.Marshal(h.addrs)
|
||||
}
|
||||
}
|
||||
return nil, errors.New("unexpected config state")
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (h *HostAddress) UnmarshalJSON(data []byte) error {
|
||||
addr := new(Address)
|
||||
@@ -208,6 +261,11 @@ func getHostMapping(ha *HostAddress) *dns.Config_HostMapping {
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (m *HostsWrapper) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(m.Hosts)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (m *HostsWrapper) UnmarshalJSON(data []byte) error {
|
||||
hosts := make(map[string]*HostAddress)
|
||||
@@ -360,6 +418,15 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
|
||||
}
|
||||
config.StaticHosts = append(config.StaticHosts, staticHosts...)
|
||||
}
|
||||
if c.UseSystemHosts {
|
||||
systemHosts, err := readSystemHosts()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to read system hosts").Base(err)
|
||||
}
|
||||
for domain, ips := range systemHosts {
|
||||
config.StaticHosts = append(config.StaticHosts, &dns.Config_HostMapping{Ip: ips, Domain: domain, Type: dns.DomainMatchingType_Full})
|
||||
}
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
@@ -372,7 +439,57 @@ func resolveQueryStrategy(queryStrategy string) dns.QueryStrategy {
|
||||
return dns.QueryStrategy_USE_IP4
|
||||
case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6":
|
||||
return dns.QueryStrategy_USE_IP6
|
||||
case "usesys", "usesystem", "use_sys", "use_system", "use-sys", "use-system":
|
||||
return dns.QueryStrategy_USE_SYS
|
||||
default:
|
||||
return dns.QueryStrategy_USE_IP
|
||||
}
|
||||
}
|
||||
|
||||
func readSystemHosts() (map[string][][]byte, error) {
|
||||
var hostsPath string
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
hostsPath = filepath.Join(os.Getenv("SystemRoot"), "System32", "drivers", "etc", "hosts")
|
||||
default:
|
||||
hostsPath = "/etc/hosts"
|
||||
}
|
||||
|
||||
file, err := os.Open(hostsPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
hostsMap := make(map[string][][]byte)
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if i := strings.IndexByte(line, '#'); i >= 0 {
|
||||
// Discard comments.
|
||||
line = line[0:i]
|
||||
}
|
||||
f := strings.Fields(line)
|
||||
if len(f) < 2 {
|
||||
continue
|
||||
}
|
||||
addr := net.ParseAddress(f[0])
|
||||
if addr.Family().IsDomain() {
|
||||
continue
|
||||
}
|
||||
ip := addr.IP()
|
||||
for i := 1; i < len(f); i++ {
|
||||
domain := strings.TrimSuffix(f[i], ".")
|
||||
domain = strings.ToLower(domain)
|
||||
if v, ok := hostsMap[domain]; ok {
|
||||
hostsMap[domain] = append(v, ip)
|
||||
} else {
|
||||
hostsMap[domain] = [][]byte{ip}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return hostsMap, nil
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ func (c *DNSOutboundConfig) Build() (proto.Message, error) {
|
||||
switch c.NonIPQuery {
|
||||
case "":
|
||||
c.NonIPQuery = "drop"
|
||||
case "drop", "skip":
|
||||
case "drop", "skip", "reject":
|
||||
default:
|
||||
return nil, errors.New(`unknown "nonIPQuery": `, c.NonIPQuery)
|
||||
}
|
||||
|
@@ -1,26 +1,35 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/proxy/dokodemo"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type DokodemoConfig struct {
|
||||
Host *Address `json:"address"`
|
||||
PortValue uint16 `json:"port"`
|
||||
NetworkList *NetworkList `json:"network"`
|
||||
Redirect bool `json:"followRedirect"`
|
||||
UserLevel uint32 `json:"userLevel"`
|
||||
Address *Address `json:"address"`
|
||||
Port uint16 `json:"port"`
|
||||
PortMap map[string]string `json:"portMap"`
|
||||
Network *NetworkList `json:"network"`
|
||||
FollowRedirect 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()
|
||||
if v.Address != nil {
|
||||
config.Address = v.Address.Build()
|
||||
}
|
||||
config.Port = uint32(v.PortValue)
|
||||
config.Networks = v.NetworkList.Build()
|
||||
config.FollowRedirect = v.Redirect
|
||||
config.Port = uint32(v.Port)
|
||||
config.PortMap = v.PortMap
|
||||
for _, v := range config.PortMap {
|
||||
if _, _, err := net.SplitHostPort(v); err != nil {
|
||||
return nil, errors.New("invalid portMap: ", v).Base(err)
|
||||
}
|
||||
}
|
||||
config.Networks = v.Network.Build()
|
||||
config.FollowRedirect = v.FollowRedirect
|
||||
config.UserLevel = v.UserLevel
|
||||
return config, nil
|
||||
}
|
||||
|
@@ -20,6 +20,18 @@ type FakeDNSConfig struct {
|
||||
pools []*FakeDNSPoolElementConfig
|
||||
}
|
||||
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (f *FakeDNSConfig) MarshalJSON() ([]byte, error) {
|
||||
if (f.pool != nil) != (f.pools != nil) {
|
||||
if f.pool != nil {
|
||||
return json.Marshal(f.pool)
|
||||
} else if f.pools != nil {
|
||||
return json.Marshal(f.pools)
|
||||
}
|
||||
}
|
||||
return nil, errors.New("unexpected config state")
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (f *FakeDNSConfig) UnmarshalJSON(data []byte) error {
|
||||
var pool FakeDNSPoolElementConfig
|
||||
|
@@ -27,12 +27,14 @@ type Fragment struct {
|
||||
Packets string `json:"packets"`
|
||||
Length *Int32Range `json:"length"`
|
||||
Interval *Int32Range `json:"interval"`
|
||||
MaxSplit *Int32Range `json:"maxSplit"`
|
||||
}
|
||||
|
||||
type Noise struct {
|
||||
Type string `json:"type"`
|
||||
Packet string `json:"packet"`
|
||||
Delay *Int32Range `json:"delay"`
|
||||
Type string `json:"type"`
|
||||
Packet string `json:"packet"`
|
||||
Delay *Int32Range `json:"delay"`
|
||||
ApplyTo string `json:"applyTo"`
|
||||
}
|
||||
|
||||
// Build implements Buildable
|
||||
@@ -108,6 +110,13 @@ func (c *FreedomConfig) Build() (proto.Message, error) {
|
||||
config.Fragment.IntervalMin = uint64(c.Fragment.Interval.From)
|
||||
config.Fragment.IntervalMax = uint64(c.Fragment.Interval.To)
|
||||
}
|
||||
|
||||
{
|
||||
if c.Fragment.MaxSplit != nil {
|
||||
config.Fragment.MaxSplitMin = uint64(c.Fragment.MaxSplit.From)
|
||||
config.Fragment.MaxSplitMax = uint64(c.Fragment.MaxSplit.To)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if c.Noise != nil {
|
||||
@@ -193,5 +202,15 @@ func ParseNoise(noise *Noise) (*freedom.Noise, error) {
|
||||
NConfig.DelayMin = uint64(noise.Delay.From)
|
||||
NConfig.DelayMax = uint64(noise.Delay.To)
|
||||
}
|
||||
switch strings.ToLower(noise.ApplyTo) {
|
||||
case "", "ip", "all":
|
||||
NConfig.ApplyTo = "ip"
|
||||
case "ipv4":
|
||||
NConfig.ApplyTo = "ipv4"
|
||||
case "ipv6":
|
||||
NConfig.ApplyTo = "ipv6"
|
||||
default:
|
||||
return nil, errors.New("Invalid applyTo, only ip/ipv4/ipv6 are supported")
|
||||
}
|
||||
return NConfig, nil
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/xtls/xray-core/app/observatory"
|
||||
"github.com/xtls/xray-core/app/observatory/burst"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/infra/conf/cfgcommon/duration"
|
||||
)
|
||||
|
||||
@@ -26,6 +27,9 @@ type BurstObservatoryConfig struct {
|
||||
}
|
||||
|
||||
func (b BurstObservatoryConfig) Build() (proto.Message, error) {
|
||||
if b.HealthCheck == nil {
|
||||
return nil, errors.New("BurstObservatory requires a valid pingConfig")
|
||||
}
|
||||
if result, err := b.HealthCheck.Build(); err == nil {
|
||||
return &burst.Config{SubjectSelector: b.SubjectSelector, PingConfig: result.(*burst.HealthPingConfig)}, nil
|
||||
} else {
|
||||
|
@@ -536,12 +536,15 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
|
||||
IP *StringList `json:"ip"`
|
||||
Port *PortList `json:"port"`
|
||||
Network *NetworkList `json:"network"`
|
||||
SourceIP *StringList `json:"source"`
|
||||
SourceIP *StringList `json:"sourceIP"`
|
||||
Source *StringList `json:"source"`
|
||||
SourcePort *PortList `json:"sourcePort"`
|
||||
User *StringList `json:"user"`
|
||||
InboundTag *StringList `json:"inboundTag"`
|
||||
Protocols *StringList `json:"protocol"`
|
||||
Attributes map[string]string `json:"attrs"`
|
||||
LocalIP *StringList `json:"localIP"`
|
||||
LocalPort *PortList `json:"localPort"`
|
||||
}
|
||||
rawFieldRule := new(RawFieldRule)
|
||||
err := json.Unmarshal(msg, rawFieldRule)
|
||||
@@ -604,6 +607,10 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
|
||||
rule.Networks = rawFieldRule.Network.Build()
|
||||
}
|
||||
|
||||
if rawFieldRule.SourceIP == nil {
|
||||
rawFieldRule.SourceIP = rawFieldRule.Source
|
||||
}
|
||||
|
||||
if rawFieldRule.SourceIP != nil {
|
||||
geoipList, err := ToCidrList(*rawFieldRule.SourceIP)
|
||||
if err != nil {
|
||||
@@ -616,6 +623,18 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
|
||||
rule.SourcePortList = rawFieldRule.SourcePort.Build()
|
||||
}
|
||||
|
||||
if rawFieldRule.LocalIP != nil {
|
||||
geoipList, err := ToCidrList(*rawFieldRule.LocalIP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule.LocalGeoip = geoipList
|
||||
}
|
||||
|
||||
if rawFieldRule.LocalPort != nil {
|
||||
rule.LocalPortList = rawFieldRule.LocalPort.Build()
|
||||
}
|
||||
|
||||
if rawFieldRule.User != nil {
|
||||
for _, s := range *rawFieldRule.User {
|
||||
rule.UserEmail = append(rule.UserEmail, s)
|
||||
|
@@ -2,6 +2,7 @@ package conf
|
||||
|
||||
import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/app/observatory/burst"
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
@@ -51,15 +52,23 @@ type healthCheckSettings struct {
|
||||
Interval duration.Duration `json:"interval"`
|
||||
SamplingCount int `json:"sampling"`
|
||||
Timeout duration.Duration `json:"timeout"`
|
||||
HttpMethod string `json:"httpMethod"`
|
||||
}
|
||||
|
||||
func (h healthCheckSettings) Build() (proto.Message, error) {
|
||||
var httpMethod string
|
||||
if h.HttpMethod == "" {
|
||||
httpMethod = "HEAD"
|
||||
} else {
|
||||
httpMethod = strings.TrimSpace(h.HttpMethod)
|
||||
}
|
||||
return &burst.HealthPingConfig{
|
||||
Destination: h.Destination,
|
||||
Connectivity: h.Connectivity,
|
||||
Interval: int64(h.Interval),
|
||||
Timeout: int64(h.Timeout),
|
||||
SamplingCount: int32(h.SamplingCount),
|
||||
HttpMethod: httpMethod,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@@ -412,6 +412,10 @@ type TLSConfig struct {
|
||||
MasterKeyLog string `json:"masterKeyLog"`
|
||||
ServerNameToVerify string `json:"serverNameToVerify"`
|
||||
VerifyPeerCertInNames []string `json:"verifyPeerCertInNames"`
|
||||
ECHServerKeys string `json:"echServerKeys"`
|
||||
ECHConfigList string `json:"echConfigList"`
|
||||
ECHForceQuery string `json:"echForceQuery"`
|
||||
ECHSocketSettings *SocketConfig `json:"echSockopt"`
|
||||
}
|
||||
|
||||
// Build implements Buildable.
|
||||
@@ -435,7 +439,7 @@ func (c *TLSConfig) Build() (proto.Message, error) {
|
||||
}
|
||||
if len(config.NextProtocol) > 1 {
|
||||
for _, p := range config.NextProtocol {
|
||||
if tcp.IsFromMitm(p) {
|
||||
if tls.IsFromMitm(p) {
|
||||
return nil, errors.New(`only one element is allowed in "alpn" when using "fromMitm" in it`)
|
||||
}
|
||||
}
|
||||
@@ -483,9 +487,38 @@ func (c *TLSConfig) Build() (proto.Message, error) {
|
||||
}
|
||||
config.VerifyPeerCertInNames = c.VerifyPeerCertInNames
|
||||
|
||||
if c.ECHServerKeys != "" {
|
||||
EchPrivateKey, err := base64.StdEncoding.DecodeString(c.ECHServerKeys)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid ECH Config", c.ECHServerKeys)
|
||||
}
|
||||
config.EchServerKeys = EchPrivateKey
|
||||
}
|
||||
switch c.ECHForceQuery {
|
||||
case "none", "half", "full", "":
|
||||
config.EchForceQuery = c.ECHForceQuery
|
||||
default:
|
||||
return nil, errors.New(`invalid "echForceQuery": `, c.ECHForceQuery)
|
||||
}
|
||||
config.EchForceQuery = c.ECHForceQuery
|
||||
config.EchConfigList = c.ECHConfigList
|
||||
if c.ECHSocketSettings != nil {
|
||||
ss, err := c.ECHSocketSettings.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("Failed to build ech sockopt.").Base(err)
|
||||
}
|
||||
config.EchSocketSettings = ss
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
type LimitFallback struct {
|
||||
AfterBytes uint64
|
||||
BytesPerSec uint64
|
||||
BurstBytesPerSec uint64
|
||||
}
|
||||
|
||||
type REALITYConfig struct {
|
||||
MasterKeyLog string `json:"masterKeyLog"`
|
||||
Show bool `json:"show"`
|
||||
@@ -499,13 +532,18 @@ type REALITYConfig struct {
|
||||
MaxClientVer string `json:"maxClientVer"`
|
||||
MaxTimeDiff uint64 `json:"maxTimeDiff"`
|
||||
ShortIds []string `json:"shortIds"`
|
||||
Mldsa65Seed string `json:"mldsa65Seed"`
|
||||
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
ServerName string `json:"serverName"`
|
||||
Password string `json:"password"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
ShortId string `json:"shortId"`
|
||||
SpiderX string `json:"spiderX"`
|
||||
LimitFallbackUpload LimitFallback `json:"limitFallbackUpload"`
|
||||
LimitFallbackDownload LimitFallback `json:"limitFallbackDownload"`
|
||||
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
ServerName string `json:"serverName"`
|
||||
Password string `json:"password"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
ShortId string `json:"shortId"`
|
||||
Mldsa65Verify string `json:"mldsa65Verify"`
|
||||
SpiderX string `json:"spiderX"`
|
||||
}
|
||||
|
||||
func (c *REALITYConfig) Build() (proto.Message, error) {
|
||||
@@ -535,7 +573,7 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
|
||||
}
|
||||
default:
|
||||
if _, err = strconv.Atoi(s); err == nil {
|
||||
s = "127.0.0.1:" + s
|
||||
s = "localhost:" + s
|
||||
}
|
||||
if _, _, err = net.SplitHostPort(s); err == nil {
|
||||
c.Type = "tcp"
|
||||
@@ -600,6 +638,24 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
|
||||
config.Xver = c.Xver
|
||||
config.ServerNames = c.ServerNames
|
||||
config.MaxTimeDiff = c.MaxTimeDiff
|
||||
|
||||
if c.Mldsa65Seed != "" {
|
||||
if c.Mldsa65Seed == c.PrivateKey {
|
||||
return nil, errors.New(`"mldsa65Seed" and "privateKey" can not be the same value: `, c.Mldsa65Seed)
|
||||
}
|
||||
if config.Mldsa65Seed, err = base64.RawURLEncoding.DecodeString(c.Mldsa65Seed); err != nil || len(config.Mldsa65Seed) != 32 {
|
||||
return nil, errors.New(`invalid "mldsa65Seed": `, c.Mldsa65Seed)
|
||||
}
|
||||
}
|
||||
|
||||
config.LimitFallbackUpload = new(reality.LimitFallback)
|
||||
config.LimitFallbackUpload.AfterBytes = c.LimitFallbackUpload.AfterBytes
|
||||
config.LimitFallbackUpload.BytesPerSec = c.LimitFallbackUpload.BytesPerSec
|
||||
config.LimitFallbackUpload.BurstBytesPerSec = c.LimitFallbackUpload.BurstBytesPerSec
|
||||
config.LimitFallbackDownload = new(reality.LimitFallback)
|
||||
config.LimitFallbackDownload.AfterBytes = c.LimitFallbackDownload.AfterBytes
|
||||
config.LimitFallbackDownload.BytesPerSec = c.LimitFallbackDownload.BytesPerSec
|
||||
config.LimitFallbackDownload.BurstBytesPerSec = c.LimitFallbackDownload.BurstBytesPerSec
|
||||
} else {
|
||||
config.Fingerprint = strings.ToLower(c.Fingerprint)
|
||||
if config.Fingerprint == "unsafe" || config.Fingerprint == "hellogolang" {
|
||||
@@ -627,6 +683,11 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
|
||||
if _, err = hex.Decode(config.ShortId, []byte(c.ShortId)); err != nil {
|
||||
return nil, errors.New(`invalid "shortId": `, c.ShortId)
|
||||
}
|
||||
if c.Mldsa65Verify != "" {
|
||||
if config.Mldsa65Verify, err = base64.RawURLEncoding.DecodeString(c.Mldsa65Verify); err != nil || len(config.Mldsa65Verify) != 1952 {
|
||||
return nil, errors.New(`invalid "mldsa65Verify": `, c.Mldsa65Verify)
|
||||
}
|
||||
}
|
||||
if c.SpiderX == "" {
|
||||
c.SpiderX = "/"
|
||||
}
|
||||
@@ -691,6 +752,7 @@ func (p TransportProtocol) Build() (string, error) {
|
||||
}
|
||||
|
||||
type CustomSockoptConfig struct {
|
||||
Syetem string `json:"system"`
|
||||
Network string `json:"network"`
|
||||
Level string `json:"level"`
|
||||
Opt string `json:"opt"`
|
||||
@@ -698,25 +760,50 @@ type CustomSockoptConfig struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type HappyEyeballsConfig struct {
|
||||
PrioritizeIPv6 bool `json:"prioritizeIPv6"`
|
||||
TryDelayMs uint64 `json:"tryDelayMs"`
|
||||
Interleave uint32 `json:"interleave"`
|
||||
MaxConcurrentTry uint32 `json:"maxConcurrentTry"`
|
||||
}
|
||||
|
||||
func (h *HappyEyeballsConfig) UnmarshalJSON(data []byte) error {
|
||||
var innerHappyEyeballsConfig = struct {
|
||||
PrioritizeIPv6 bool `json:"prioritizeIPv6"`
|
||||
TryDelayMs uint64 `json:"tryDelayMs"`
|
||||
Interleave uint32 `json:"interleave"`
|
||||
MaxConcurrentTry uint32 `json:"maxConcurrentTry"`
|
||||
}{PrioritizeIPv6: false, Interleave: 1, TryDelayMs: 0, MaxConcurrentTry: 4}
|
||||
if err := json.Unmarshal(data, &innerHappyEyeballsConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
h.PrioritizeIPv6 = innerHappyEyeballsConfig.PrioritizeIPv6
|
||||
h.TryDelayMs = innerHappyEyeballsConfig.TryDelayMs
|
||||
h.Interleave = innerHappyEyeballsConfig.Interleave
|
||||
h.MaxConcurrentTry = innerHappyEyeballsConfig.MaxConcurrentTry
|
||||
return nil
|
||||
}
|
||||
|
||||
type SocketConfig struct {
|
||||
Mark int32 `json:"mark"`
|
||||
TFO interface{} `json:"tcpFastOpen"`
|
||||
TProxy string `json:"tproxy"`
|
||||
AcceptProxyProtocol bool `json:"acceptProxyProtocol"`
|
||||
DomainStrategy string `json:"domainStrategy"`
|
||||
DialerProxy string `json:"dialerProxy"`
|
||||
TCPKeepAliveInterval int32 `json:"tcpKeepAliveInterval"`
|
||||
TCPKeepAliveIdle int32 `json:"tcpKeepAliveIdle"`
|
||||
TCPCongestion string `json:"tcpCongestion"`
|
||||
TCPWindowClamp int32 `json:"tcpWindowClamp"`
|
||||
TCPMaxSeg int32 `json:"tcpMaxSeg"`
|
||||
Penetrate bool `json:"penetrate"`
|
||||
TCPUserTimeout int32 `json:"tcpUserTimeout"`
|
||||
V6only bool `json:"v6only"`
|
||||
Interface string `json:"interface"`
|
||||
TcpMptcp bool `json:"tcpMptcp"`
|
||||
CustomSockopt []*CustomSockoptConfig `json:"customSockopt"`
|
||||
AddressPortStrategy string `json:"addressPortStrategy"`
|
||||
Mark int32 `json:"mark"`
|
||||
TFO interface{} `json:"tcpFastOpen"`
|
||||
TProxy string `json:"tproxy"`
|
||||
AcceptProxyProtocol bool `json:"acceptProxyProtocol"`
|
||||
DomainStrategy string `json:"domainStrategy"`
|
||||
DialerProxy string `json:"dialerProxy"`
|
||||
TCPKeepAliveInterval int32 `json:"tcpKeepAliveInterval"`
|
||||
TCPKeepAliveIdle int32 `json:"tcpKeepAliveIdle"`
|
||||
TCPCongestion string `json:"tcpCongestion"`
|
||||
TCPWindowClamp int32 `json:"tcpWindowClamp"`
|
||||
TCPMaxSeg int32 `json:"tcpMaxSeg"`
|
||||
Penetrate bool `json:"penetrate"`
|
||||
TCPUserTimeout int32 `json:"tcpUserTimeout"`
|
||||
V6only bool `json:"v6only"`
|
||||
Interface string `json:"interface"`
|
||||
TcpMptcp bool `json:"tcpMptcp"`
|
||||
CustomSockopt []*CustomSockoptConfig `json:"customSockopt"`
|
||||
AddressPortStrategy string `json:"addressPortStrategy"`
|
||||
HappyEyeballsSettings *HappyEyeballsConfig `json:"happyEyeballs"`
|
||||
}
|
||||
|
||||
// Build implements Buildable.
|
||||
@@ -778,6 +865,7 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
|
||||
|
||||
for _, copt := range c.CustomSockopt {
|
||||
customSockopt := &internet.CustomSockopt{
|
||||
System: copt.Syetem,
|
||||
Network: copt.Network,
|
||||
Level: copt.Level,
|
||||
Opt: copt.Opt,
|
||||
@@ -807,6 +895,14 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
|
||||
return nil, errors.New("unsupported address and port strategy: ", c.AddressPortStrategy)
|
||||
}
|
||||
|
||||
var happyEyeballs = &internet.HappyEyeballsConfig{Interleave: 1, PrioritizeIpv6: false, TryDelayMs: 0, MaxConcurrentTry: 4}
|
||||
if c.HappyEyeballsSettings != nil {
|
||||
happyEyeballs.PrioritizeIpv6 = c.HappyEyeballsSettings.PrioritizeIPv6
|
||||
happyEyeballs.Interleave = c.HappyEyeballsSettings.Interleave
|
||||
happyEyeballs.TryDelayMs = c.HappyEyeballsSettings.TryDelayMs
|
||||
happyEyeballs.MaxConcurrentTry = c.HappyEyeballsSettings.MaxConcurrentTry
|
||||
}
|
||||
|
||||
return &internet.SocketConfig{
|
||||
Mark: c.Mark,
|
||||
Tfo: tfo,
|
||||
@@ -826,6 +922,7 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
|
||||
TcpMptcp: c.TcpMptcp,
|
||||
CustomSockopt: customSockopts,
|
||||
AddressPortStrategy: addressPortStrategy,
|
||||
HappyEyeballs: happyEyeballs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user