mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-09-16 22:40:27 +00:00
Compare commits
10
Commits
obs-timeout
..
seed2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43779f379f | ||
|
|
082fecf334 | ||
|
|
7299cfc56f | ||
|
|
0e206b99bd | ||
|
|
45f677a538 | ||
|
|
b6afe68d84 | ||
|
|
51234fbe53 | ||
|
|
cba71f8cdc | ||
|
|
279abd4fc8 | ||
|
|
b1f4d32ef0 |
@@ -29,5 +29,6 @@
|
|||||||
"openbsd-arm7": { "friendlyName": "openbsd-arm32-v7a" },
|
"openbsd-arm7": { "friendlyName": "openbsd-arm32-v7a" },
|
||||||
"windows-386": { "friendlyName": "windows-32" },
|
"windows-386": { "friendlyName": "windows-32" },
|
||||||
"windows-amd64": { "friendlyName": "windows-64" },
|
"windows-amd64": { "friendlyName": "windows-64" },
|
||||||
"windows-arm64": { "friendlyName": "windows-arm64-v8a" }
|
"windows-arm64": { "friendlyName": "windows-arm64-v8a" },
|
||||||
|
"windows-arm7": { "friendlyName": "windows-arm32-v7a" }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
powershell.exe -ExecutionPolicy Bypass -File ".\xray_no_window.ps1"
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Start-Process -FilePath ".\xray.exe" -ArgumentList "-config .\config.json" -WindowStyle Hidden
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
CreateObject("Wscript.Shell").Run "xray.exe -config config.json",0
|
|
||||||
@@ -6,7 +6,7 @@ WORKDIR /src
|
|||||||
COPY . .
|
COPY . .
|
||||||
ARG TARGETOS
|
ARG TARGETOS
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags "-s -w -buildid=" ./main
|
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
|
||||||
|
|
||||||
# Download geodat into a staging directory
|
# 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/geoip.dat /tmp/geodat/geoip.dat
|
||||||
@@ -32,13 +32,9 @@ 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/04_policy.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/05_inbounds.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/06_outbounds.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/07_stats.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/07_transport.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/08_fakedns.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/08_stats.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/09_metrics.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/09_reverse.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/10_observatory.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/11_geodata.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/12_env.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/99_version.json
|
|
||||||
|
|
||||||
# Create log files
|
# Create log files
|
||||||
RUN mkdir -p /tmp/var/log/xray && touch \
|
RUN mkdir -p /tmp/var/log/xray && touch \
|
||||||
@@ -49,8 +45,8 @@ RUN mkdir -p /tmp/var/log/xray && touch \
|
|||||||
FROM gcr.io/distroless/static:nonroot
|
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 /src/xray /usr/local/bin/xray
|
||||||
COPY --from=build --chown=65532:65532 --chmod=755 /tmp/empty /usr/local/share/xray
|
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /usr/local/share/xray
|
||||||
COPY --from=build --chown=65532:65532 --chmod=644 /tmp/geodat/*.dat /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=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=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=0:0 --chmod=755 /tmp/empty /var/log/xray
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ WORKDIR /src
|
|||||||
COPY . .
|
COPY . .
|
||||||
ARG TARGETOS
|
ARG TARGETOS
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags "-s -w -buildid=" ./main
|
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
|
||||||
|
|
||||||
# Download geodat into a staging directory
|
# 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/geoip.dat /tmp/geodat/geoip.dat
|
||||||
@@ -32,13 +32,9 @@ 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/04_policy.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/05_inbounds.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/06_outbounds.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/07_stats.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/07_transport.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/08_fakedns.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/08_stats.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/09_metrics.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/09_reverse.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/10_observatory.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/11_geodata.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/12_env.json
|
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/99_version.json
|
|
||||||
|
|
||||||
# Create log files
|
# Create log files
|
||||||
RUN mkdir -p /tmp/var/log/xray && touch \
|
RUN mkdir -p /tmp/var/log/xray && touch \
|
||||||
@@ -58,8 +54,8 @@ RUN mkdir -p /tmp/var/log/xray && touch \
|
|||||||
FROM --platform=linux/amd64 gcr.io/distroless/static:nonroot
|
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 /src/xray /usr/local/bin/xray
|
||||||
COPY --from=build --chown=65532:65532 --chmod=755 /tmp/empty /usr/local/share/xray
|
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /usr/local/share/xray
|
||||||
COPY --from=build --chown=65532:65532 --chmod=644 /tmp/geodat/*.dat /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=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=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=0:0 --chmod=755 /tmp/empty /var/log/xray
|
||||||
|
|||||||
@@ -64,25 +64,17 @@ jobs:
|
|||||||
echo "Latest: '$LATEST'."
|
echo "Latest: '$LATEST'."
|
||||||
echo "LATEST=$LATEST" >>${GITHUB_ENV}
|
echo "LATEST=$LATEST" >>${GITHUB_ENV}
|
||||||
|
|
||||||
NEWEST=false
|
|
||||||
if [[ "${{ github.event_name }}" == "release" ]]; then
|
|
||||||
NEWEST=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Newest: '$NEWEST'."
|
|
||||||
echo "NEWEST=$NEWEST" >>${GITHUB_ENV}
|
|
||||||
|
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v4
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v4
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v4
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
@@ -90,7 +82,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build Docker image (main architectures)
|
- name: Build Docker image (main architectures)
|
||||||
id: build_main_arches
|
id: build_main_arches
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: .github/docker/Dockerfile
|
file: .github/docker/Dockerfile
|
||||||
@@ -105,7 +97,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build Docker image (additional architectures)
|
- name: Build Docker image (additional architectures)
|
||||||
id: build_additional_arches
|
id: build_additional_arches
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: .github/docker/Dockerfile.usa
|
file: .github/docker/Dockerfile.usa
|
||||||
@@ -132,13 +124,6 @@ jobs:
|
|||||||
${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${{ env.NEWEST }}" == "true" ]]; then
|
|
||||||
echo "Adding 'pre-release' tag to manifest: '${{ env.FULL_IMAGE_NAME }}:pre-release'."
|
|
||||||
docker buildx imagetools create \
|
|
||||||
--tag ${{ env.FULL_IMAGE_NAME }}:pre-release \
|
|
||||||
${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Inspect image
|
- name: Inspect image
|
||||||
run: |
|
run: |
|
||||||
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
||||||
@@ -146,7 +131,3 @@ jobs:
|
|||||||
if [[ "${{ env.LATEST }}" == "true" ]]; then
|
if [[ "${{ env.LATEST }}" == "true" ]]; then
|
||||||
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:latest
|
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:latest
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${{ env.NEWEST }}" == "true" ]]; then
|
|
||||||
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:pre-release
|
|
||||||
fi
|
|
||||||
|
|||||||
@@ -11,20 +11,13 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
check-assets:
|
check-assets:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
|
||||||
steps:
|
steps:
|
||||||
- name: Restore Geodat Cache
|
- name: Restore Geodat Cache
|
||||||
uses: actions/cache/restore@v6
|
uses: actions/cache/restore@v4
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-
|
key: xray-geodat-
|
||||||
|
|
||||||
- name: Restore Wintun Cache
|
|
||||||
uses: actions/cache/restore@v6
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-wintun-
|
|
||||||
|
|
||||||
- name: Check Assets Existence
|
- name: Check Assets Existence
|
||||||
id: check-assets
|
id: check-assets
|
||||||
run: |
|
run: |
|
||||||
@@ -41,18 +34,6 @@ jobs:
|
|||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
LIST=('amd64' 'x86')
|
|
||||||
for ARCHITECTURE in "${LIST[@]}"
|
|
||||||
do
|
|
||||||
echo -e "Checking wintun.dll for ${ARCHITECTURE}..."
|
|
||||||
if [ -s "./resources/wintun/bin/${ARCHITECTURE}/wintun.dll" ]; then
|
|
||||||
echo -e "wintun.dll for ${ARCHITECTURE} exists."
|
|
||||||
else
|
|
||||||
echo -e "wintun.dll for ${ARCHITECTURE} is missing."
|
|
||||||
echo "missing=true" >> $GITHUB_OUTPUT
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Sleep for 90 seconds if Assets Missing
|
- name: Sleep for 90 seconds if Assets Missing
|
||||||
if: steps.check-assets.outputs.missing == 'true'
|
if: steps.check-assets.outputs.missing == 'true'
|
||||||
@@ -76,14 +57,13 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
|
||||||
env:
|
env:
|
||||||
GOOS: ${{ matrix.goos}}
|
GOOS: ${{ matrix.goos}}
|
||||||
GOARCH: ${{ matrix.goarch }}
|
GOARCH: ${{ matrix.goarch }}
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codebase
|
- name: Checkout codebase
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Show workflow information
|
- name: Show workflow information
|
||||||
run: |
|
run: |
|
||||||
@@ -92,7 +72,7 @@ jobs:
|
|||||||
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v7
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -115,40 +95,20 @@ jobs:
|
|||||||
COMMID=$(git describe --always --dirty)
|
COMMID=$(git describe --always --dirty)
|
||||||
echo 'Building Xray for Windows 7...'
|
echo 'Building Xray for Windows 7...'
|
||||||
go build -o build_assets/xray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
go build -o build_assets/xray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||||
|
echo 'CreateObject("Wscript.Shell").Run "xray.exe -config config.json",0' > build_assets/xray_no_window.vbs
|
||||||
|
echo 'Start-Process -FilePath ".\xray.exe" -ArgumentList "-config .\config.json" -WindowStyle Hidden' > build_assets/xray_no_window.ps1
|
||||||
# The line below is for without running conhost.exe version. Commented for not being used. Provided for reference.
|
# The line below is for without running conhost.exe version. Commented for not being used. Provided for reference.
|
||||||
# go build -o build_assets/wxray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-H windowsgui -X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
# go build -o build_assets/wxray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-H windowsgui -X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||||
|
|
||||||
- name: Restore Geodat Cache
|
- name: Restore Geodat Cache
|
||||||
uses: actions/cache/restore@v6
|
uses: actions/cache/restore@v4
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-
|
key: xray-geodat-
|
||||||
|
|
||||||
- name: Restore Wintun Cache
|
|
||||||
uses: actions/cache/restore@v6
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-wintun-
|
|
||||||
|
|
||||||
- name: Add additional assets into package
|
|
||||||
run: |
|
|
||||||
mv -f resources/geo* build_assets/
|
|
||||||
if [[ ${GOOS} == 'windows' ]]; then
|
|
||||||
cp .github/build/windows/* build_assets/
|
|
||||||
fi
|
|
||||||
if [[ ${GOOS} == 'windows' ]]; then
|
|
||||||
echo 'Adding Wintun into packages'
|
|
||||||
if [[ ${GOARCH} == 'amd64' ]]; then
|
|
||||||
mv resources/wintun/bin/amd64/wintun.dll build_assets/
|
|
||||||
fi
|
|
||||||
if [[ ${GOARCH} == '386' ]]; then
|
|
||||||
mv resources/wintun/bin/x86/wintun.dll build_assets/
|
|
||||||
fi
|
|
||||||
mv resources/wintun/LICENSE.txt build_assets/LICENSE-Wintun
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Copy README.md & LICENSE
|
- name: Copy README.md & LICENSE
|
||||||
run: |
|
run: |
|
||||||
|
mv -f resources/* build_assets
|
||||||
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
|
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
|
||||||
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
|
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
|
||||||
|
|
||||||
@@ -167,6 +127,17 @@ jobs:
|
|||||||
openssl dgst -$METHOD $FILE | sed 's/([^)]*)//g' >>$DGST
|
openssl dgst -$METHOD $FILE | sed 's/([^)]*)//g' >>$DGST
|
||||||
done
|
done
|
||||||
|
|
||||||
|
- name: Change the name
|
||||||
|
run: |
|
||||||
|
mv build_assets Xray-${{ env.ASSET_NAME }}
|
||||||
|
|
||||||
|
- name: Upload files to Artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: Xray-${{ env.ASSET_NAME }}
|
||||||
|
path: |
|
||||||
|
./Xray-${{ env.ASSET_NAME }}/*
|
||||||
|
|
||||||
- name: Upload binaries to release
|
- name: Upload binaries to release
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: svenstaro/upload-release-action@v2
|
||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
@@ -175,10 +146,3 @@ jobs:
|
|||||||
file: ./Xray-${{ env.ASSET_NAME }}.zip*
|
file: ./Xray-${{ env.ASSET_NAME }}.zip*
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
file_glob: true
|
file_glob: true
|
||||||
|
|
||||||
- name: Upload files to Artifacts
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: Xray-${{ env.ASSET_NAME }}
|
|
||||||
path: |
|
|
||||||
./build_assets/*
|
|
||||||
|
|||||||
@@ -11,20 +11,13 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
check-assets:
|
check-assets:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
|
||||||
steps:
|
steps:
|
||||||
- name: Restore Geodat Cache
|
- name: Restore Geodat Cache
|
||||||
uses: actions/cache/restore@v6
|
uses: actions/cache/restore@v4
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-
|
key: xray-geodat-
|
||||||
|
|
||||||
- name: Restore Wintun Cache
|
|
||||||
uses: actions/cache/restore@v6
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-wintun-
|
|
||||||
|
|
||||||
- name: Check Assets Existence
|
- name: Check Assets Existence
|
||||||
id: check-assets
|
id: check-assets
|
||||||
run: |
|
run: |
|
||||||
@@ -41,22 +34,10 @@ jobs:
|
|||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
LIST=('amd64' 'x86' 'arm64')
|
|
||||||
for ARCHITECTURE in "${LIST[@]}"
|
|
||||||
do
|
|
||||||
echo -e "Checking wintun.dll for ${ARCHITECTURE}..."
|
|
||||||
if [ -s "./resources/wintun/bin/${ARCHITECTURE}/wintun.dll" ]; then
|
|
||||||
echo -e "wintun.dll for ${ARCHITECTURE} exists."
|
|
||||||
else
|
|
||||||
echo -e "wintun.dll for ${ARCHITECTURE} is missing."
|
|
||||||
echo "missing=true" >> $GITHUB_OUTPUT
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Trigger Asset Update Workflow if Assets Missing
|
- name: Trigger Asset Update Workflow if Assets Missing
|
||||||
if: steps.check-assets.outputs.missing == 'true'
|
if: steps.check-assets.outputs.missing == 'true'
|
||||||
uses: actions/github-script@v9
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
script: |
|
script: |
|
||||||
@@ -115,6 +96,9 @@ jobs:
|
|||||||
# Windows ARM
|
# Windows ARM
|
||||||
- goos: windows
|
- goos: windows
|
||||||
goarch: arm64
|
goarch: arm64
|
||||||
|
- goos: windows
|
||||||
|
goarch: arm
|
||||||
|
goarm: 7
|
||||||
# BEGIN Other architectures
|
# BEGIN Other architectures
|
||||||
# BEGIN riscv64 & ARM64 & LOONG64
|
# BEGIN riscv64 & ARM64 & LOONG64
|
||||||
- goos: linux
|
- goos: linux
|
||||||
@@ -162,7 +146,6 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
|
||||||
env:
|
env:
|
||||||
GOOS: ${{ matrix.goos }}
|
GOOS: ${{ matrix.goos }}
|
||||||
GOARCH: ${{ matrix.goarch }}
|
GOARCH: ${{ matrix.goarch }}
|
||||||
@@ -170,7 +153,7 @@ jobs:
|
|||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codebase
|
- name: Checkout codebase
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set up NDK
|
- name: Set up NDK
|
||||||
if: matrix.goos == 'android'
|
if: matrix.goos == 'android'
|
||||||
@@ -193,7 +176,7 @@ jobs:
|
|||||||
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v7
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -208,11 +191,10 @@ jobs:
|
|||||||
if [[ ${GOOS} == 'windows' ]]; then
|
if [[ ${GOOS} == 'windows' ]]; then
|
||||||
echo 'Building Xray for Windows...'
|
echo 'Building Xray for Windows...'
|
||||||
go build -o build_assets/xray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
go build -o build_assets/xray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||||
|
echo 'CreateObject("Wscript.Shell").Run "xray.exe -config config.json",0' > build_assets/xray_no_window.vbs
|
||||||
|
echo 'Start-Process -FilePath ".\xray.exe" -ArgumentList "-config .\config.json" -WindowStyle Hidden' > build_assets/xray_no_window.ps1
|
||||||
# The line below is for without running conhost.exe version. Commented for not being used. Provided for reference.
|
# The line below is for without running conhost.exe version. Commented for not being used. Provided for reference.
|
||||||
# go build -o build_assets/wxray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-H windowsgui -X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
# go build -o build_assets/wxray.exe -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-H windowsgui -X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
|
||||||
elif [[ ${GOOS} == 'android' ]]; then
|
|
||||||
echo 'Building Xray for Android...'
|
|
||||||
go build -o build_assets/xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid= -checklinkname=0" -v ./main
|
|
||||||
else
|
else
|
||||||
echo 'Building Xray...'
|
echo 'Building Xray...'
|
||||||
if [[ ${GOARCH} == 'mips' || ${GOARCH} == 'mipsle' ]]; then
|
if [[ ${GOARCH} == 'mips' || ${GOARCH} == 'mipsle' ]]; then
|
||||||
@@ -225,40 +207,14 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Restore Geodat Cache
|
- name: Restore Geodat Cache
|
||||||
uses: actions/cache/restore@v6
|
uses: actions/cache/restore@v4
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-
|
key: xray-geodat-
|
||||||
|
|
||||||
- name: Restore Wintun Cache
|
|
||||||
if: matrix.goos == 'windows'
|
|
||||||
uses: actions/cache/restore@v6
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-wintun-
|
|
||||||
|
|
||||||
- name: Add additional assets into package
|
|
||||||
run: |
|
|
||||||
mv -f resources/geo* build_assets/
|
|
||||||
if [[ ${GOOS} == 'windows' ]]; then
|
|
||||||
cp .github/build/windows/* build_assets/
|
|
||||||
fi
|
|
||||||
if [[ ${GOOS} == 'windows' ]]; then
|
|
||||||
echo 'Adding Wintun into packages'
|
|
||||||
if [[ ${GOARCH} == 'amd64' ]]; then
|
|
||||||
mv resources/wintun/bin/amd64/wintun.dll build_assets/
|
|
||||||
fi
|
|
||||||
if [[ ${GOARCH} == '386' ]]; then
|
|
||||||
mv resources/wintun/bin/x86/wintun.dll build_assets/
|
|
||||||
fi
|
|
||||||
if [[ ${GOARCH} == 'arm64' ]]; then
|
|
||||||
mv resources/wintun/bin/arm64/wintun.dll build_assets/
|
|
||||||
fi
|
|
||||||
mv resources/wintun/LICENSE.txt build_assets/LICENSE-Wintun
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Copy README.md & LICENSE
|
- name: Copy README.md & LICENSE
|
||||||
run: |
|
run: |
|
||||||
|
mv -f resources/* build_assets
|
||||||
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
|
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
|
||||||
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
|
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
|
||||||
|
|
||||||
@@ -277,6 +233,17 @@ jobs:
|
|||||||
openssl dgst -$METHOD $FILE | sed 's/([^)]*)//g' >>$DGST
|
openssl dgst -$METHOD $FILE | sed 's/([^)]*)//g' >>$DGST
|
||||||
done
|
done
|
||||||
|
|
||||||
|
- name: Change the name
|
||||||
|
run: |
|
||||||
|
mv build_assets Xray-${{ env.ASSET_NAME }}
|
||||||
|
|
||||||
|
- name: Upload files to Artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: Xray-${{ env.ASSET_NAME }}
|
||||||
|
path: |
|
||||||
|
./Xray-${{ env.ASSET_NAME }}/*
|
||||||
|
|
||||||
- name: Upload binaries to release
|
- name: Upload binaries to release
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: svenstaro/upload-release-action@v2
|
||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
@@ -285,10 +252,3 @@ jobs:
|
|||||||
file: ./Xray-${{ env.ASSET_NAME }}.zip*
|
file: ./Xray-${{ env.ASSET_NAME }}.zip*
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
file_glob: true
|
file_glob: true
|
||||||
|
|
||||||
- name: Upload files to Artifacts
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: Xray-${{ env.ASSET_NAME }}
|
|
||||||
path: |
|
|
||||||
./build_assets/*
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ name: Scheduled assets update
|
|||||||
# routine manner, for example: GeoIP/GeoSite.
|
# routine manner, for example: GeoIP/GeoSite.
|
||||||
# Currently updating:
|
# Currently updating:
|
||||||
# - Geodat (GeoIP/Geosite)
|
# - Geodat (GeoIP/Geosite)
|
||||||
# - Wintun (wintun.dll)
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -22,18 +21,18 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
geodat:
|
geodat:
|
||||||
if: github.event.schedule == '30 22 * * *' || github.event_name == 'push' || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
|
if: github.event.schedule == '30 22 * * *' || github.event_name == 'push'|| github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Restore Geodat Cache
|
- name: Restore Geodat Cache
|
||||||
uses: actions/cache/restore@v6
|
uses: actions/cache/restore@v4
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-
|
key: xray-geodat-
|
||||||
|
|
||||||
- name: Update Geodat
|
- name: Update Geodat
|
||||||
id: update
|
id: update
|
||||||
uses: nick-fields/retry@v4
|
uses: nick-fields/retry@v3
|
||||||
with:
|
with:
|
||||||
timeout_minutes: 60
|
timeout_minutes: 60
|
||||||
retry_wait_seconds: 60
|
retry_wait_seconds: 60
|
||||||
@@ -59,78 +58,8 @@ jobs:
|
|||||||
done
|
done
|
||||||
|
|
||||||
- name: Save Geodat Cache
|
- name: Save Geodat Cache
|
||||||
uses: actions/cache/save@v6
|
uses: actions/cache/save@v4
|
||||||
if: ${{ steps.update.outputs.unhit }}
|
if: ${{ steps.update.outputs.unhit }}
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-${{ github.sha }}-${{ github.run_number }}
|
key: xray-geodat-${{ github.sha }}-${{ github.run_number }}
|
||||||
|
|
||||||
wintun:
|
|
||||||
if: github.event.schedule == '30 22 * * *' || github.event_name == 'push' || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
ASSETVER: 0.14.1
|
|
||||||
ASSETHASH: 07c256185d6ee3652e09fa55c0b673e2624b565e02c4b9091c79ca7d2f24ef51
|
|
||||||
steps:
|
|
||||||
- name: Restore Wintun Cache
|
|
||||||
uses: actions/cache/restore@v6
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-wintun-
|
|
||||||
|
|
||||||
- name: Force downloading if run manually or on file update
|
|
||||||
if: github.event_name == 'workflow_dispatch' || github.event_name == 'push'
|
|
||||||
run: |
|
|
||||||
echo "FORCE_UPDATE=true" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Update Wintun
|
|
||||||
id: update
|
|
||||||
uses: nick-fields/retry@v4
|
|
||||||
with:
|
|
||||||
timeout_minutes: 60
|
|
||||||
retry_wait_seconds: 60
|
|
||||||
max_attempts: 60
|
|
||||||
command: |
|
|
||||||
[ -d 'resources' ] || mkdir resources
|
|
||||||
LIST=('amd64' 'x86' 'arm64')
|
|
||||||
for ARCHITECTURE in "${LIST[@]}"
|
|
||||||
do
|
|
||||||
FILE_PATH="resources/wintun/bin/${ARCHITECTURE}/wintun.dll"
|
|
||||||
echo -e "Checking if wintun.dll for ${ARCHITECTURE} exists..."
|
|
||||||
if [ -s "./resources/wintun/bin/${ARCHITECTURE}/wintun.dll" ]; then
|
|
||||||
echo -e "wintun.dll for ${ARCHITECTURE} exists"
|
|
||||||
else
|
|
||||||
echo -e "wintun.dll for ${ARCHITECTURE} is missing"
|
|
||||||
missing=true
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ -s "./resources/wintun/LICENSE.txt" ]; then
|
|
||||||
echo -e "LICENSE for Wintun exists"
|
|
||||||
else
|
|
||||||
echo -e "LICENSE for Wintun is missing"
|
|
||||||
missing=true
|
|
||||||
fi
|
|
||||||
if [[ -v FORCE_UPDATE ]]; then
|
|
||||||
missing=true
|
|
||||||
fi
|
|
||||||
if [[ "$missing" == true ]]; then
|
|
||||||
FILENAME=wintun.zip
|
|
||||||
DOWNLOAD_FILE=wintun-${ASSETVER}.zip
|
|
||||||
echo -e "Downloading https://www.wintun.net/builds/${DOWNLOAD_FILE}..."
|
|
||||||
curl -L "https://www.wintun.net/builds/${DOWNLOAD_FILE}" -o "${FILENAME}"
|
|
||||||
if [[ "$(sha256sum "./${FILENAME}" | awk -F ' ' '{print $1}')" == "${ASSETHASH}" ]]; then
|
|
||||||
echo -e "Unpacking wintun..."
|
|
||||||
unzip -u ${FILENAME} -d resources/
|
|
||||||
echo "unhit=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo -e "Digest of ${FILENAME} mismatch."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Save Wintun Cache
|
|
||||||
uses: actions/cache/save@v6
|
|
||||||
if: ${{ steps.update.outputs.unhit }}
|
|
||||||
with:
|
|
||||||
path: resources
|
|
||||||
key: xray-wintun-${{ github.sha }}-${{ github.run_number }}
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
name: Tests and Checkings
|
name: Test
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -8,10 +8,9 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
check-assets:
|
check-assets:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
|
||||||
steps:
|
steps:
|
||||||
- name: Restore Geodat Cache
|
- name: Restore Geodat Cache
|
||||||
uses: actions/cache/restore@v6
|
uses: actions/cache/restore@v4
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-
|
key: xray-geodat-
|
||||||
@@ -35,45 +34,8 @@ jobs:
|
|||||||
if: steps.check-assets.outputs.missing == 'true'
|
if: steps.check-assets.outputs.missing == 'true'
|
||||||
run: sleep 90
|
run: sleep 90
|
||||||
|
|
||||||
check-proto:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
|
||||||
steps:
|
|
||||||
- name: Checkout codebase
|
|
||||||
uses: actions/checkout@v7
|
|
||||||
- name: Check Proto Version Header
|
|
||||||
run: |
|
|
||||||
head -n 4 core/config.pb.go > ref.txt
|
|
||||||
find . -name "*.pb.go" ! -name "*_grpc.pb.go" -print0 | while IFS= read -r -d '' file; do
|
|
||||||
if ! cmp -s ref.txt <(head -n 4 "$file"); then
|
|
||||||
echo "Error: Header mismatch in $file"
|
|
||||||
head -n 4 "$file"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
check-format:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
steps:
|
|
||||||
- name: Checkout codebase
|
|
||||||
uses: actions/checkout@v7
|
|
||||||
- name: Set up Go
|
|
||||||
uses: actions/setup-go@v7
|
|
||||||
with:
|
|
||||||
go-version-file: go.mod
|
|
||||||
check-latest: true
|
|
||||||
cache: false
|
|
||||||
- name: Check Format
|
|
||||||
run: |
|
|
||||||
go install -v mvdan.cc/gofumpt@latest
|
|
||||||
go run ./infra/vformat/main.go -mode check -pwd ./
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
needs: check-assets
|
needs: check-assets
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
@@ -83,14 +45,14 @@ jobs:
|
|||||||
os: [windows-latest, ubuntu-latest, macos-latest]
|
os: [windows-latest, ubuntu-latest, macos-latest]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codebase
|
- name: Checkout codebase
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v5
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v7
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore Geodat Cache
|
- name: Restore Geodat Cache
|
||||||
uses: actions/cache/restore@v6
|
uses: actions/cache/restore@v4
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-
|
key: xray-geodat-
|
||||||
|
|||||||
@@ -4,27 +4,12 @@
|
|||||||
|
|
||||||
[README](https://github.com/XTLS/Xray-core#readme) is open, so feel free to submit your project [here](https://github.com/XTLS/Xray-core/pulls).
|
[README](https://github.com/XTLS/Xray-core#readme) is open, so feel free to submit your project [here](https://github.com/XTLS/Xray-core/pulls).
|
||||||
|
|
||||||
## Sponsors
|
|
||||||
|
|
||||||
[](https://docs.rw)
|
|
||||||
|
|
||||||
[](https://happ.su)
|
|
||||||
|
|
||||||
[](https://blanc.link/VMTSDqW)
|
|
||||||
|
|
||||||
[**Sponsor Xray-core**](https://github.com/XTLS/Xray-core/issues/3668)
|
|
||||||
|
|
||||||
## Donation & NFTs
|
## Donation & NFTs
|
||||||
|
|
||||||
### [Collect a Project X NFT to support the development of Project X!](https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1)
|
### [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)
|
[<img alt="Project X NFT" width="150px" src="https://raw2.seadn.io/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/7fa9ce900fb39b44226348db330e32/8b7fa9ce900fb39b44226348db330e32.svg" />](https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1)
|
||||||
|
|
||||||
- **TRX(Tron)/USDT/USDC: `TNrDh5VSfwd4RPrwsohr6poyNTfFefNYan`**
|
|
||||||
- **TON: `UQApeV-u2gm43aC1uP76xAC1m6vCylstaN1gpfBmre_5IyTH`**
|
|
||||||
- **BTC: `1JpqcziZZuqv3QQJhZGNGBVdCBrGgkL6cT`**
|
|
||||||
- **XMR: `4ABHQZ3yJZkBnLoqiKvb3f8eqUnX4iMPb6wdant5ZLGQELctcerceSGEfJnoCk6nnyRZm73wrwSgvZ2WmjYLng6R7sR67nq`**
|
|
||||||
- **SOL/USDT/USDC: `3x5NuXHzB5APG6vRinPZcsUv5ukWUY1tBGRSJiEJWtZa`**
|
|
||||||
- **ETH/USDT/USDC: `0xDc3Fe44F0f25D13CACb1C4896CD0D321df3146Ee`**
|
- **ETH/USDT/USDC: `0xDc3Fe44F0f25D13CACb1C4896CD0D321df3146Ee`**
|
||||||
- **Project X NFT: https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1**
|
- **Project X NFT: https://opensea.io/item/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1**
|
||||||
- **VLESS NFT: https://opensea.io/collection/vless**
|
- **VLESS NFT: https://opensea.io/collection/vless**
|
||||||
@@ -58,22 +43,17 @@
|
|||||||
- [ghcr.io/xtls/xray-core](https://ghcr.io/xtls/xray-core) (**Official**)
|
- [ghcr.io/xtls/xray-core](https://ghcr.io/xtls/xray-core) (**Official**)
|
||||||
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
|
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
|
||||||
- [wulabing/xray_docker](https://github.com/wulabing/xray_docker)
|
- [wulabing/xray_docker](https://github.com/wulabing/xray_docker)
|
||||||
- Web Panel
|
- Web Panel - **WARNING: Please DO NOT USE plain HTTP panels like 3X-UI**, as they are believed to be bribed by Iran GFW for supporting plain HTTP by default and refused to change (https://github.com/XTLS/Xray-core/pull/3884#issuecomment-2439595331), which has already put many users' data security in danger in the past few years. **If you are already using 3X-UI, please switch to the following panels, which are verified to support HTTPS and SSH port forwarding only:**
|
||||||
- [Remnawave](https://github.com/remnawave/panel)
|
- [Remnawave](https://github.com/remnawave/panel)
|
||||||
- [3X-UI](https://github.com/MHSanaei/3x-ui)
|
|
||||||
- [PasarGuard](https://github.com/PasarGuard/panel)
|
|
||||||
- [Xray-UI](https://github.com/qist/xray-ui)
|
|
||||||
- [X-Panel](https://github.com/xeefei/X-Panel)
|
|
||||||
- [Marzban](https://github.com/Gozargah/Marzban)
|
- [Marzban](https://github.com/Gozargah/Marzban)
|
||||||
|
- [Xray-UI](https://github.com/qist/xray-ui)
|
||||||
- [Hiddify](https://github.com/hiddify/Hiddify-Manager)
|
- [Hiddify](https://github.com/hiddify/Hiddify-Manager)
|
||||||
- [TX-UI](https://github.com/AghayeCoder/tx-ui)
|
|
||||||
- [CELERITY](https://github.com/ClickDevTech/CELERITY-panel)
|
|
||||||
- One Click
|
- 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-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), [VPainLess](https://github.com/vpainless/vpainless)
|
- [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)
|
- [v2ray-agent](https://github.com/mack-a/v2ray-agent), [Xray_onekey](https://github.com/wulabing/Xray_onekey), [ProxySU](https://github.com/proxysu/ProxySU)
|
||||||
- Magisk
|
- Magisk
|
||||||
- [Magic_V2Ray](https://github.com/vincentng295/Magic_V2Ray)
|
- [Xray4Magisk](https://github.com/Asterisk4Magisk/Xray4Magisk)
|
||||||
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
|
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
|
||||||
- Homebrew
|
- Homebrew
|
||||||
- `brew install xray`
|
- `brew install xray`
|
||||||
@@ -98,65 +78,46 @@
|
|||||||
## GUI Clients
|
## GUI Clients
|
||||||
|
|
||||||
- OpenWrt
|
- OpenWrt
|
||||||
- [PassWall](https://github.com/Openwrt-Passwall/openwrt-passwall), [PassWall 2](https://github.com/Openwrt-Passwall/openwrt-passwall2)
|
- [PassWall](https://github.com/xiaorouji/openwrt-passwall), [PassWall 2](https://github.com/xiaorouji/openwrt-passwall2)
|
||||||
- [ShadowSocksR Plus+](https://github.com/fw876/helloworld)
|
- [ShadowSocksR Plus+](https://github.com/fw876/helloworld)
|
||||||
- [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray))
|
- [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray))
|
||||||
- Asuswrt-Merlin
|
- Asuswrt-Merlin
|
||||||
- [XRAYUI](https://github.com/DanielLavrushin/asuswrt-merlin-xrayui)
|
- [XRAYUI](https://github.com/DanielLavrushin/asuswrt-merlin-xrayui)
|
||||||
- [fancyss](https://github.com/hq450/fancyss)
|
|
||||||
- Windows
|
- Windows
|
||||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
- [v2rayN](https://github.com/2dust/v2rayN)
|
||||||
- [Furious](https://github.com/LorenEteval/Furious)
|
- [Furious](https://github.com/LorenEteval/Furious)
|
||||||
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
|
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||||
- [GenyConnect](https://github.com/genyleap/GenyConnect)
|
|
||||||
- [OneXray](https://github.com/OneXray/OneXray)
|
|
||||||
- [XrayUI-dev](https://github.com/PhoenixNil/XrayUI-dev)
|
|
||||||
- Android
|
- Android
|
||||||
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
||||||
- [X-flutter](https://github.com/XTLS/X-flutter)
|
- [X-flutter](https://github.com/XTLS/X-flutter)
|
||||||
- [SaeedDev94/Xray](https://github.com/SaeedDev94/Xray)
|
- [SaeedDev94/Xray](https://github.com/SaeedDev94/Xray)
|
||||||
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
||||||
- [XrayFA](https://github.com/Q7DF1/XrayFA)
|
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||||
- [OneXray](https://github.com/OneXray/OneXray)
|
|
||||||
- [AsteriskNG](https://github.com/Asterisk4Magisk/AsteriskNG)
|
|
||||||
- iOS & macOS arm64 & tvOS
|
- iOS & macOS arm64 & tvOS
|
||||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215) | [Happ RU](https://apps.apple.com/ru/app/happ-proxy-utility-plus/id6746188973) | [Happ tvOS](https://apps.apple.com/us/app/happ-proxy-utility-for-tv/id6748297274)
|
- [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)
|
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)
|
||||||
- [OneXray](https://github.com/OneXray/OneXray)
|
- [OneXray](https://github.com/OneXray/OneXray)
|
||||||
- [INCY](https://apps.apple.com/en/app/incy/id6756943388)
|
|
||||||
- macOS arm64 & x64
|
- macOS arm64 & x64
|
||||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215) | [Happ RU](https://apps.apple.com/ru/app/happ-proxy-utility-plus/id6746188973)
|
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215)
|
||||||
- [V2rayU](https://github.com/yanue/V2rayU)
|
- [V2rayU](https://github.com/yanue/V2rayU)
|
||||||
- [V2RayXS](https://github.com/tzmax/V2RayXS)
|
- [V2RayXS](https://github.com/tzmax/V2RayXS)
|
||||||
- [Furious](https://github.com/LorenEteval/Furious)
|
- [Furious](https://github.com/LorenEteval/Furious)
|
||||||
- [OneXray](https://github.com/OneXray/OneXray)
|
- [OneXray](https://github.com/OneXray/OneXray)
|
||||||
- [GoXRay](https://github.com/goxray/desktop)
|
- [GoXRay](https://github.com/goxray/desktop)
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
|
||||||
- [GenyConnect](https://github.com/genyleap/GenyConnect)
|
|
||||||
- [INCY](https://apps.apple.com/en/app/incy/id6756943388)
|
|
||||||
- Linux
|
- Linux
|
||||||
- [v2rayA](https://github.com/v2rayA/v2rayA)
|
- [v2rayA](https://github.com/v2rayA/v2rayA)
|
||||||
- [Furious](https://github.com/LorenEteval/Furious)
|
- [Furious](https://github.com/LorenEteval/Furious)
|
||||||
- [GorzRay](https://github.com/ketetefid/GorzRay)
|
- [GorzRay](https://github.com/ketetefid/GorzRay)
|
||||||
- [GoXRay](https://github.com/goxray/desktop)
|
- [GoXRay](https://github.com/goxray/desktop)
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
|
||||||
- [GenyConnect](https://github.com/genyleap/GenyConnect)
|
|
||||||
- [OneXray](https://github.com/OneXray/OneXray)
|
|
||||||
- HarmonyOS
|
|
||||||
- [Hey](https://github.com/popsiclelmlm/Hey)
|
|
||||||
|
|
||||||
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
||||||
|
|
||||||
- iOS & macOS arm64 & tvOS
|
- iOS & macOS arm64 & tvOS
|
||||||
- [Anywhere](https://github.com/NodePassProject/Anywhere)
|
|
||||||
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
||||||
- [Loon](https://apps.apple.com/us/app/loon/id1373567447)
|
- [Loon](https://apps.apple.com/us/app/loon/id1373567447)
|
||||||
- [Egern](https://apps.apple.com/us/app/egern/id1616105820)
|
|
||||||
- [Quantumult X](https://apps.apple.com/us/app/quantumult-x/id1443988620)
|
|
||||||
- Xray Tools
|
- Xray Tools
|
||||||
- [xray-knife](https://github.com/lilendian0x00/xray-knife)
|
- [xray-knife](https://github.com/lilendian0x00/xray-knife)
|
||||||
- [xray-checker](https://github.com/kutovoys/xray-checker)
|
- [xray-checker](https://github.com/kutovoys/xray-checker)
|
||||||
@@ -165,7 +126,6 @@
|
|||||||
- [xtls-sdk](https://github.com/remnawave/xtls-sdk)
|
- [xtls-sdk](https://github.com/remnawave/xtls-sdk)
|
||||||
- [xtlsapi](https://github.com/hiddify/xtlsapi)
|
- [xtlsapi](https://github.com/hiddify/xtlsapi)
|
||||||
- [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite)
|
- [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite)
|
||||||
- [flutter_vless](https://github.com/XIIIFOX/flutter_vless)
|
|
||||||
- [Xray-core-python](https://github.com/LorenEteval/Xray-core-python)
|
- [Xray-core-python](https://github.com/LorenEteval/Xray-core-python)
|
||||||
- [xray-api](https://github.com/XVGuardian/xray-api)
|
- [xray-api](https://github.com/XVGuardian/xray-api)
|
||||||
- [XrayR](https://github.com/XrayR-project/XrayR)
|
- [XrayR](https://github.com/XrayR-project/XrayR)
|
||||||
@@ -187,27 +147,6 @@
|
|||||||
- [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).
|
- [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).
|
||||||
- For third-party projects used in [Xray-core](https://github.com/XTLS/Xray-core), check your local or [the latest go.mod](https://github.com/XTLS/Xray-core/blob/main/go.mod).
|
- For third-party projects used in [Xray-core](https://github.com/XTLS/Xray-core), check your local or [the latest go.mod](https://github.com/XTLS/Xray-core/blob/main/go.mod).
|
||||||
|
|
||||||
### Bundled Third-Party Components Redistribution
|
|
||||||
|
|
||||||
**Certain optional features dynamically load third-party components. These optional components are separate works distributed under their own licenses, and are bundled into the ZIP package for ease of use. Users may replace these components under the licenses from these components.**
|
|
||||||
|
|
||||||
These components include:
|
|
||||||
|
|
||||||
#### Wintun
|
|
||||||
|
|
||||||
This distribution contains unmodified official precompiled and pre-signed Wintun binaries.
|
|
||||||
|
|
||||||
- Project: Wintun
|
|
||||||
- Copyright: Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
|
|
||||||
- Redistribution License: Prebuilt Binaries License (PBL) bundled with official precompiled and pre-signed binaries from wintun.net
|
|
||||||
- Component(s): wintun.dll
|
|
||||||
- Source: https://www.wintun.net/
|
|
||||||
- Included in:
|
|
||||||
- Windows x86 (windows-32, win7-32)
|
|
||||||
- Windows x86-64 (windows-64, win7-64)
|
|
||||||
- Windows AArch64 (windows-arm64)
|
|
||||||
- Notes: Wintun is an optional runtime-loaded component only used for TUN inbound functionality on supported Windows platforms.
|
|
||||||
|
|
||||||
## One-line Compilation
|
## One-line Compilation
|
||||||
|
|
||||||
### Windows (PowerShell)
|
### Windows (PowerShell)
|
||||||
@@ -231,13 +170,6 @@ Make sure that you are using the same Go version, and remember to set the git co
|
|||||||
CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=REPLACE -s -w -buildid=" -v ./main
|
CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=REPLACE -s -w -buildid=" -v ./main
|
||||||
```
|
```
|
||||||
|
|
||||||
For Android:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
GOOS=android GOARCH=arm64 CGO_ENABLED=1 CC=/path/to/aarch64-linux-android24-clang go build -o xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=REPLACE -s -w -buildid= -checklinkname=0" -v ./main
|
|
||||||
GOOS=android GOARCH=amd64 CGO_ENABLED=1 CC=/path/to/x86_64-linux-android24-clang go build -o xray -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=REPLACE -s -w -buildid= -checklinkname=0" -v ./main
|
|
||||||
```
|
|
||||||
|
|
||||||
If you are compiling a 32-bit MIPS/MIPSLE target, use this command instead:
|
If you are compiling a 32-bit MIPS/MIPSLE target, use this command instead:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
# Security Policy
|
|
||||||
|
|
||||||
If you found an issue related to security vulnerability or protocol-identification problem, please report it to us via "[Report a vulnerability](https://github.com/XTLS/Xray-core/security/advisories/new)" privately, instead of publish it publicly before we release the fixed version.
|
|
||||||
|
|
||||||
Thanks for your contribution to the FREE Internet!
|
|
||||||
@@ -3,7 +3,6 @@ package commander
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
@@ -11,7 +10,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/signal/done"
|
"github.com/xtls/xray-core/common/signal/done"
|
||||||
core "github.com/xtls/xray-core/core"
|
core "github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/outbound"
|
"github.com/xtls/xray-core/features/outbound"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -69,32 +67,20 @@ func (c *Commander) Start() error {
|
|||||||
}
|
}
|
||||||
c.Unlock()
|
c.Unlock()
|
||||||
|
|
||||||
listen := func(listener net.Listener) {
|
var listen = func(listener net.Listener) {
|
||||||
if err := c.server.Serve(listener); err != nil {
|
if err := c.server.Serve(listener); err != nil {
|
||||||
errors.LogErrorInner(context.Background(), err, "failed to start grpc server")
|
errors.LogErrorInner(context.Background(), err, "failed to start grpc server")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.listen) > 0 {
|
if len(c.listen) > 0 {
|
||||||
var addr net.Addr
|
if l, err := net.Listen("tcp", c.listen); err != nil {
|
||||||
|
|
||||||
if strings.HasPrefix(c.listen, "/") || strings.HasPrefix(c.listen, "@") {
|
|
||||||
addr = &net.UnixAddr{Name: c.listen, Net: "unix"}
|
|
||||||
} else {
|
|
||||||
tcpAddr, err := net.ResolveTCPAddr("tcp", c.listen)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(context.Background(), err, "API server failed to parse listen address ", c.listen)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
addr = tcpAddr
|
|
||||||
}
|
|
||||||
l, err := internet.ListenSystem(context.Background(), addr, nil)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(context.Background(), err, "API server failed to listen on ", c.listen)
|
errors.LogErrorInner(context.Background(), err, "API server failed to listen on ", c.listen)
|
||||||
return err
|
return err
|
||||||
|
} else {
|
||||||
|
errors.LogInfo(context.Background(), "API server listening on ", l.Addr())
|
||||||
|
go listen(l)
|
||||||
}
|
}
|
||||||
errors.LogInfo(context.Background(), "API server listening on ", l.Addr())
|
|
||||||
go listen(l)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+35
-21
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/commander/config.proto
|
// source: app/commander/config.proto
|
||||||
|
|
||||||
package commander
|
package commander
|
||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -24,16 +23,17 @@ const (
|
|||||||
|
|
||||||
// Config is the settings for Commander.
|
// Config is the settings for Commander.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// Tag of the outbound handler that handles grpc connections.
|
// Tag of the outbound handler that handles grpc connections.
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
// Network address of commander grpc service.
|
// Network address of commander grpc service.
|
||||||
Listen string `protobuf:"bytes,3,opt,name=listen,proto3" json:"listen,omitempty"`
|
Listen string `protobuf:"bytes,3,opt,name=listen,proto3" json:"listen,omitempty"`
|
||||||
// Services that supported by this server. All services must implement Service
|
// Services that supported by this server. All services must implement Service
|
||||||
// interface.
|
// interface.
|
||||||
Service []*serial.TypedMessage `protobuf:"bytes,2,rep,name=service,proto3" json:"service,omitempty"`
|
Service []*serial.TypedMessage `protobuf:"bytes,2,rep,name=service,proto3" json:"service,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -89,9 +89,9 @@ func (x *Config) GetService() []*serial.TypedMessage {
|
|||||||
|
|
||||||
// ReflectionConfig is the placeholder config for ReflectionService.
|
// ReflectionConfig is the placeholder config for ReflectionService.
|
||||||
type ReflectionConfig struct {
|
type ReflectionConfig struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReflectionConfig) Reset() {
|
func (x *ReflectionConfig) Reset() {
|
||||||
@@ -126,24 +126,37 @@ func (*ReflectionConfig) Descriptor() ([]byte, []int) {
|
|||||||
|
|
||||||
var File_app_commander_config_proto protoreflect.FileDescriptor
|
var File_app_commander_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_commander_config_proto_rawDesc = "" +
|
var file_app_commander_config_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x1a, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x2f,
|
||||||
"\x1aapp/commander/config.proto\x12\x12xray.app.commander\x1a!common/serial/typed_message.proto\"n\n" +
|
0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x78, 0x72,
|
||||||
"\x06Config\x12\x10\n" +
|
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72,
|
||||||
"\x03tag\x18\x01 \x01(\tR\x03tag\x12\x16\n" +
|
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,
|
||||||
"\x06listen\x18\x03 \x01(\tR\x06listen\x12:\n" +
|
0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
|
||||||
"\aservice\x18\x02 \x03(\v2 .xray.common.serial.TypedMessageR\aservice\"\x12\n" +
|
0x6f, 0x74, 0x6f, 0x22, 0x6e, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a,
|
||||||
"\x10ReflectionConfigBX\n" +
|
0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12,
|
||||||
"\x16com.xray.app.commanderP\x01Z'github.com/xtls/xray-core/app/commander\xaa\x02\x12Xray.App.Commanderb\x06proto3"
|
0x16, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
|
0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x3a, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||||
|
0x63, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
|
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79,
|
||||||
|
0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76,
|
||||||
|
0x69, 0x63, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||||
|
0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
|
||||||
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65,
|
||||||
|
0x72, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||||
|
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61,
|
||||||
|
0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0xaa, 0x02, 0x12, 0x58,
|
||||||
|
0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65,
|
||||||
|
0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_app_commander_config_proto_rawDescOnce sync.Once
|
file_app_commander_config_proto_rawDescOnce sync.Once
|
||||||
file_app_commander_config_proto_rawDescData []byte
|
file_app_commander_config_proto_rawDescData = file_app_commander_config_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_commander_config_proto_rawDescGZIP() []byte {
|
func file_app_commander_config_proto_rawDescGZIP() []byte {
|
||||||
file_app_commander_config_proto_rawDescOnce.Do(func() {
|
file_app_commander_config_proto_rawDescOnce.Do(func() {
|
||||||
file_app_commander_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_commander_config_proto_rawDesc), len(file_app_commander_config_proto_rawDesc)))
|
file_app_commander_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_commander_config_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_commander_config_proto_rawDescData
|
return file_app_commander_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
@@ -172,7 +185,7 @@ func file_app_commander_config_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_commander_config_proto_rawDesc), len(file_app_commander_config_proto_rawDesc)),
|
RawDescriptor: file_app_commander_config_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 2,
|
NumMessages: 2,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
@@ -183,6 +196,7 @@ func file_app_commander_config_proto_init() {
|
|||||||
MessageInfos: file_app_commander_config_proto_msgTypes,
|
MessageInfos: file_app_commander_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_commander_config_proto = out.File
|
File_app_commander_config_proto = out.File
|
||||||
|
file_app_commander_config_proto_rawDesc = nil
|
||||||
file_app_commander_config_proto_goTypes = nil
|
file_app_commander_config_proto_goTypes = nil
|
||||||
file_app_commander_config_proto_depIdxs = nil
|
file_app_commander_config_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-18
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/dispatcher/config.proto
|
// source: app/dispatcher/config.proto
|
||||||
|
|
||||||
package dispatcher
|
package dispatcher
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -22,9 +21,9 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type SessionConfig struct {
|
type SessionConfig struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SessionConfig) Reset() {
|
func (x *SessionConfig) Reset() {
|
||||||
@@ -58,10 +57,11 @@ func (*SessionConfig) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Settings *SessionConfig `protobuf:"bytes,1,opt,name=settings,proto3" json:"settings,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Settings *SessionConfig `protobuf:"bytes,1,opt,name=settings,proto3" json:"settings,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -103,22 +103,33 @@ func (x *Config) GetSettings() *SessionConfig {
|
|||||||
|
|
||||||
var File_app_dispatcher_config_proto protoreflect.FileDescriptor
|
var File_app_dispatcher_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_dispatcher_config_proto_rawDesc = "" +
|
var file_app_dispatcher_config_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x1b, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,
|
||||||
"\x1bapp/dispatcher/config.proto\x12\x13xray.app.dispatcher\"\x15\n" +
|
0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x78,
|
||||||
"\rSessionConfigJ\x04\b\x01\x10\x02\"H\n" +
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68,
|
||||||
"\x06Config\x12>\n" +
|
0x65, 0x72, 0x22, 0x15, 0x0a, 0x0d, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e,
|
||||||
"\bsettings\x18\x01 \x01(\v2\".xray.app.dispatcher.SessionConfigR\bsettingsB[\n" +
|
0x66, 0x69, 0x67, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x48, 0x0a, 0x06, 0x43, 0x6f, 0x6e,
|
||||||
"\x17com.xray.app.dispatcherP\x01Z(github.com/xtls/xray-core/app/dispatcher\xaa\x02\x13Xray.App.Dispatcherb\x06proto3"
|
0x66, 0x69, 0x67, 0x12, 0x3e, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
|
||||||
|
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
|
0x2e, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73,
|
||||||
|
0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69,
|
||||||
|
0x6e, 0x67, 0x73, 0x42, 0x5b, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
|
0x61, 0x70, 0x70, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x50, 0x01,
|
||||||
|
0x5a, 0x28, 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, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0xaa, 0x02, 0x13, 0x58, 0x72, 0x61,
|
||||||
|
0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,
|
||||||
|
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_app_dispatcher_config_proto_rawDescOnce sync.Once
|
file_app_dispatcher_config_proto_rawDescOnce sync.Once
|
||||||
file_app_dispatcher_config_proto_rawDescData []byte
|
file_app_dispatcher_config_proto_rawDescData = file_app_dispatcher_config_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_dispatcher_config_proto_rawDescGZIP() []byte {
|
func file_app_dispatcher_config_proto_rawDescGZIP() []byte {
|
||||||
file_app_dispatcher_config_proto_rawDescOnce.Do(func() {
|
file_app_dispatcher_config_proto_rawDescOnce.Do(func() {
|
||||||
file_app_dispatcher_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_dispatcher_config_proto_rawDesc), len(file_app_dispatcher_config_proto_rawDesc)))
|
file_app_dispatcher_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_dispatcher_config_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_dispatcher_config_proto_rawDescData
|
return file_app_dispatcher_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
@@ -146,7 +157,7 @@ func file_app_dispatcher_config_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_dispatcher_config_proto_rawDesc), len(file_app_dispatcher_config_proto_rawDesc)),
|
RawDescriptor: file_app_dispatcher_config_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 2,
|
NumMessages: 2,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
@@ -157,6 +168,7 @@ func file_app_dispatcher_config_proto_init() {
|
|||||||
MessageInfos: file_app_dispatcher_config_proto_msgTypes,
|
MessageInfos: file_app_dispatcher_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_dispatcher_config_proto = out.File
|
File_app_dispatcher_config_proto = out.File
|
||||||
|
file_app_dispatcher_config_proto_rawDesc = nil
|
||||||
file_app_dispatcher_config_proto_goTypes = nil
|
file_app_dispatcher_config_proto_goTypes = nil
|
||||||
file_app_dispatcher_config_proto_depIdxs = nil
|
file_app_dispatcher_config_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-26
@@ -2,6 +2,7 @@ package dispatcher
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -162,7 +163,7 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
|
|||||||
p := d.policy.ForLevel(user.Level)
|
p := d.policy.ForLevel(user.Level)
|
||||||
if p.Stats.UserUplink {
|
if p.Stats.UserUplink {
|
||||||
name := "user>>>" + user.Email + ">>>traffic>>>uplink"
|
name := "user>>>" + user.Email + ">>>traffic>>>uplink"
|
||||||
if c, _ := d.stats.GetOrRegisterCounter(name); c != nil {
|
if c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
|
||||||
inboundLink.Writer = &SizeStatWriter{
|
inboundLink.Writer = &SizeStatWriter{
|
||||||
Counter: c,
|
Counter: c,
|
||||||
Writer: inboundLink.Writer,
|
Writer: inboundLink.Writer,
|
||||||
@@ -171,7 +172,7 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
|
|||||||
}
|
}
|
||||||
if p.Stats.UserDownlink {
|
if p.Stats.UserDownlink {
|
||||||
name := "user>>>" + user.Email + ">>>traffic>>>downlink"
|
name := "user>>>" + user.Email + ">>>traffic>>>downlink"
|
||||||
if c, _ := d.stats.GetOrRegisterCounter(name); c != nil {
|
if c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
|
||||||
outboundLink.Writer = &SizeStatWriter{
|
outboundLink.Writer = &SizeStatWriter{
|
||||||
Counter: c,
|
Counter: c,
|
||||||
Writer: outboundLink.Writer,
|
Writer: outboundLink.Writer,
|
||||||
@@ -180,14 +181,22 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
|
|||||||
}
|
}
|
||||||
|
|
||||||
if p.Stats.UserOnline {
|
if p.Stats.UserOnline {
|
||||||
trackOnlineIP(ctx, d.stats, user.Email, sessionInbound.Source.Address.String())
|
name := "user>>>" + user.Email + ">>>online"
|
||||||
|
if om, _ := stats.GetOrRegisterOnlineMap(d.stats, name); om != nil {
|
||||||
|
sessionInbounds := session.InboundFromContext(ctx)
|
||||||
|
userIP := sessionInbounds.Source.Address.String()
|
||||||
|
om.AddIP(userIP)
|
||||||
|
// log Online user with ips
|
||||||
|
// errors.LogDebug(ctx, "user>>>" + user.Email + ">>>online", om.Count(), om.List())
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return inboundLink, outboundLink
|
return inboundLink, outboundLink
|
||||||
}
|
}
|
||||||
|
|
||||||
func WrapLink(ctx context.Context, policyManager policy.Manager, statsManager stats.Manager, link *transport.Link) *transport.Link {
|
func (d *DefaultDispatcher) WrapLink(ctx context.Context, link *transport.Link) *transport.Link {
|
||||||
sessionInbound := session.InboundFromContext(ctx)
|
sessionInbound := session.InboundFromContext(ctx)
|
||||||
var user *protocol.MemoryUser
|
var user *protocol.MemoryUser
|
||||||
if sessionInbound != nil {
|
if sessionInbound != nil {
|
||||||
@@ -197,16 +206,16 @@ func WrapLink(ctx context.Context, policyManager policy.Manager, statsManager st
|
|||||||
link.Reader = &buf.TimeoutWrapperReader{Reader: link.Reader}
|
link.Reader = &buf.TimeoutWrapperReader{Reader: link.Reader}
|
||||||
|
|
||||||
if user != nil && len(user.Email) > 0 {
|
if user != nil && len(user.Email) > 0 {
|
||||||
p := policyManager.ForLevel(user.Level)
|
p := d.policy.ForLevel(user.Level)
|
||||||
if p.Stats.UserUplink {
|
if p.Stats.UserUplink {
|
||||||
name := "user>>>" + user.Email + ">>>traffic>>>uplink"
|
name := "user>>>" + user.Email + ">>>traffic>>>uplink"
|
||||||
if c, _ := statsManager.GetOrRegisterCounter(name); c != nil {
|
if c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
|
||||||
link.Reader.(*buf.TimeoutWrapperReader).Counter = c
|
link.Reader.(*buf.TimeoutWrapperReader).Counter = c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.Stats.UserDownlink {
|
if p.Stats.UserDownlink {
|
||||||
name := "user>>>" + user.Email + ">>>traffic>>>downlink"
|
name := "user>>>" + user.Email + ">>>traffic>>>downlink"
|
||||||
if c, _ := statsManager.GetOrRegisterCounter(name); c != nil {
|
if c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
|
||||||
link.Writer = &SizeStatWriter{
|
link.Writer = &SizeStatWriter{
|
||||||
Counter: c,
|
Counter: c,
|
||||||
Writer: link.Writer,
|
Writer: link.Writer,
|
||||||
@@ -214,31 +223,41 @@ func WrapLink(ctx context.Context, policyManager policy.Manager, statsManager st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.Stats.UserOnline {
|
if p.Stats.UserOnline {
|
||||||
trackOnlineIP(ctx, statsManager, user.Email, sessionInbound.Source.Address.String())
|
name := "user>>>" + user.Email + ">>>online"
|
||||||
|
if om, _ := stats.GetOrRegisterOnlineMap(d.stats, name); om != nil {
|
||||||
|
sessionInbounds := session.InboundFromContext(ctx)
|
||||||
|
userIP := sessionInbounds.Source.Address.String()
|
||||||
|
om.AddIP(userIP)
|
||||||
|
// log Online user with ips
|
||||||
|
// errors.LogDebug(ctx, "user>>>" + user.Email + ">>>online", om.Count(), om.List())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return link
|
return link
|
||||||
}
|
}
|
||||||
|
|
||||||
func trackOnlineIP(ctx context.Context, sm stats.Manager, email, ip string) {
|
|
||||||
name := "user>>>" + email + ">>>online"
|
|
||||||
if om, _ := sm.GetOrRegisterOnlineMap(name); om != nil {
|
|
||||||
om.AddIP(ip)
|
|
||||||
context.AfterFunc(ctx, func() { om.RemoveIP(ip) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
||||||
domain := result.Domain()
|
domain := result.Domain()
|
||||||
if domain == "" {
|
if domain == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if request.ExcludeForDomain != nil && request.ExcludeForDomain.MatchAny(strings.ToLower(domain)) {
|
for _, d := range request.ExcludeForDomain {
|
||||||
return false
|
if strings.HasPrefix(d, "regexp:") {
|
||||||
}
|
pattern := d[7:]
|
||||||
if request.ExcludeForIP != nil && destination.Address.Family().IsIP() && request.ExcludeForIP.Match(destination.Address.IP()) {
|
re, err := regexp.Compile(pattern)
|
||||||
return false
|
if err != nil {
|
||||||
|
errors.LogInfo(ctx, "Unable to compile regex")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if re.MatchString(domain) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if strings.ToLower(domain) == d {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
protocolString := result.Protocol()
|
protocolString := result.Protocol()
|
||||||
if resComp, ok := result.(SnifferResultComposite); ok {
|
if resComp, ok := result.(SnifferResultComposite); ok {
|
||||||
@@ -338,7 +357,7 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
|||||||
content = new(session.Content)
|
content = new(session.Content)
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
}
|
}
|
||||||
outbound = WrapLink(ctx, d.policy, d.stats, outbound)
|
outbound = d.WrapLink(ctx, outbound)
|
||||||
sniffingRequest := content.SniffingRequest
|
sniffingRequest := content.SniffingRequest
|
||||||
if !sniffingRequest.Enabled {
|
if !sniffingRequest.Enabled {
|
||||||
d.routedDispatch(ctx, outbound, destination)
|
d.routedDispatch(ctx, outbound, destination)
|
||||||
@@ -430,7 +449,6 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
|
|||||||
}
|
}
|
||||||
return contentResult, contentErr
|
return contentResult, contentErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
ob := outbounds[len(outbounds)-1]
|
ob := outbounds[len(outbounds)-1]
|
||||||
@@ -465,9 +483,6 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
|||||||
handler = h
|
handler = h
|
||||||
} else {
|
} else {
|
||||||
errors.LogWarning(ctx, "non existing outTag: ", outTag)
|
errors.LogWarning(ctx, "non existing outTag: ", outTag)
|
||||||
common.Close(link.Writer)
|
|
||||||
common.Interrupt(link.Reader)
|
|
||||||
return // DO NOT CHANGE: the traffic shouldn't be processed by default outbound if the specified outbound tag doesn't exist (yet), e.g., VLESS Reverse Proxy
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errors.LogInfo(ctx, "default route for ", destination)
|
errors.LogInfo(ctx, "default route for ", destination)
|
||||||
|
|||||||
+106
-258
@@ -3,55 +3,36 @@ package dns
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
go_errors "errors"
|
go_errors "errors"
|
||||||
"runtime"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"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/signal/pubsub"
|
||||||
"github.com/xtls/xray-core/common/task"
|
"github.com/xtls/xray-core/common/task"
|
||||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||||
|
|
||||||
"golang.org/x/net/dns/dnsmessage"
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
"golang.org/x/sync/singleflight"
|
"sync"
|
||||||
)
|
"time"
|
||||||
|
|
||||||
const (
|
|
||||||
minSizeForEmptyRebuild = 512
|
|
||||||
shrinkAbsoluteThreshold = 10240
|
|
||||||
shrinkRatioThreshold = 0.65
|
|
||||||
migrationBatchSize = 4096
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CacheController struct {
|
type CacheController struct {
|
||||||
name string
|
|
||||||
disableCache bool
|
|
||||||
serveStale bool
|
|
||||||
serveExpiredTTL int32
|
|
||||||
|
|
||||||
ips map[string]*record
|
|
||||||
dirtyips map[string]*record
|
|
||||||
|
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
pub *pubsub.Service
|
ips map[string]*record
|
||||||
cacheCleanup *task.Periodic
|
pub *pubsub.Service
|
||||||
highWatermark int
|
cacheCleanup *task.Periodic
|
||||||
requestGroup singleflight.Group
|
name string
|
||||||
|
disableCache bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCacheController(name string, disableCache bool, serveStale bool, serveExpiredTTL uint32) *CacheController {
|
func NewCacheController(name string, disableCache bool) *CacheController {
|
||||||
c := &CacheController{
|
c := &CacheController{
|
||||||
name: name,
|
name: name,
|
||||||
disableCache: disableCache,
|
disableCache: disableCache,
|
||||||
serveStale: serveStale,
|
ips: make(map[string]*record),
|
||||||
serveExpiredTTL: -int32(serveExpiredTTL),
|
pub: pubsub.NewService(),
|
||||||
ips: make(map[string]*record),
|
|
||||||
pub: pubsub.NewService(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.cacheCleanup = &task.Periodic{
|
c.cacheCleanup = &task.Periodic{
|
||||||
Interval: 300 * time.Second,
|
Interval: time.Minute,
|
||||||
Execute: c.CacheCleanup,
|
Execute: c.CacheCleanup,
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
@@ -59,264 +40,131 @@ func NewCacheController(name string, disableCache bool, serveStale bool, serveEx
|
|||||||
|
|
||||||
// CacheCleanup clears expired items from cache
|
// CacheCleanup clears expired items from cache
|
||||||
func (c *CacheController) CacheCleanup() error {
|
func (c *CacheController) CacheCleanup() error {
|
||||||
expiredKeys, err := c.collectExpiredKeys()
|
now := time.Now()
|
||||||
if err != nil {
|
c.Lock()
|
||||||
return err
|
defer c.Unlock()
|
||||||
|
|
||||||
|
if len(c.ips) == 0 {
|
||||||
|
return errors.New("nothing to do. stopping...")
|
||||||
}
|
}
|
||||||
if len(expiredKeys) == 0 {
|
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
c.writeAndShrink(expiredKeys)
|
|
||||||
|
if len(c.ips) == 0 {
|
||||||
|
c.ips = make(map[string]*record)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CacheController) collectExpiredKeys() ([]string, error) {
|
func (c *CacheController) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||||
c.RLock()
|
elapsed := time.Since(req.start)
|
||||||
defer c.RUnlock()
|
|
||||||
|
|
||||||
if len(c.ips) == 0 {
|
|
||||||
return nil, errors.New("nothing to do. stopping...")
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip collection if a migration is in progress
|
|
||||||
if c.dirtyips != nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
if c.serveStale && c.serveExpiredTTL != 0 {
|
|
||||||
now = now.Add(time.Duration(c.serveExpiredTTL) * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
expiredKeys := make([]string, 0, len(c.ips)/4) // pre-allocate
|
|
||||||
|
|
||||||
for domain, rec := range c.ips {
|
|
||||||
if (rec.A != nil && rec.A.Expire.Before(now)) ||
|
|
||||||
(rec.AAAA != nil && rec.AAAA.Expire.Before(now)) {
|
|
||||||
expiredKeys = append(expiredKeys, domain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return expiredKeys, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheController) writeAndShrink(expiredKeys []string) {
|
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
rec, found := c.ips[req.domain]
|
||||||
|
if !found {
|
||||||
// double check to prevent upper call multiple cleanup tasks
|
rec = &record{}
|
||||||
if c.dirtyips != nil {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lenBefore := len(c.ips)
|
switch req.reqType {
|
||||||
if lenBefore > c.highWatermark {
|
case dnsmessage.TypeA:
|
||||||
c.highWatermark = lenBefore
|
rec.A = ipRec
|
||||||
|
case dnsmessage.TypeAAAA:
|
||||||
|
rec.AAAA = ipRec
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
errors.LogInfo(context.Background(), c.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||||
if c.serveStale && c.serveExpiredTTL != 0 {
|
c.ips[req.domain] = rec
|
||||||
now = now.Add(time.Duration(c.serveExpiredTTL) * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, domain := range expiredKeys {
|
switch req.reqType {
|
||||||
rec := c.ips[domain]
|
case dnsmessage.TypeA:
|
||||||
if rec == nil {
|
c.pub.Publish(req.domain+"4", nil)
|
||||||
continue
|
if !c.disableCache {
|
||||||
|
_, _, err := rec.AAAA.getIPs()
|
||||||
|
if !go_errors.Is(err, errRecordNotFound) {
|
||||||
|
c.pub.Publish(req.domain+"6", nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if rec.A != nil && rec.A.Expire.Before(now) {
|
case dnsmessage.TypeAAAA:
|
||||||
rec.A = nil
|
c.pub.Publish(req.domain+"6", nil)
|
||||||
}
|
if !c.disableCache {
|
||||||
if rec.AAAA != nil && rec.AAAA.Expire.Before(now) {
|
_, _, err := rec.A.getIPs()
|
||||||
rec.AAAA = nil
|
if !go_errors.Is(err, errRecordNotFound) {
|
||||||
}
|
c.pub.Publish(req.domain+"4", nil)
|
||||||
if rec.A == nil && rec.AAAA == nil {
|
}
|
||||||
delete(c.ips, domain)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lenAfter := len(c.ips)
|
c.Unlock()
|
||||||
|
common.Must(c.cacheCleanup.Start())
|
||||||
if lenAfter == 0 {
|
|
||||||
if c.highWatermark >= minSizeForEmptyRebuild {
|
|
||||||
errors.LogDebug(
|
|
||||||
context.Background(), c.name,
|
|
||||||
" rebuilding empty cache map to reclaim memory.",
|
|
||||||
" size_before_cleanup=", lenBefore,
|
|
||||||
" peak_size_before_rebuild=", c.highWatermark,
|
|
||||||
)
|
|
||||||
|
|
||||||
c.ips = make(map[string]*record)
|
|
||||||
c.highWatermark = 0
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if reductionFromPeak := c.highWatermark - lenAfter; reductionFromPeak > shrinkAbsoluteThreshold &&
|
|
||||||
float64(reductionFromPeak) > float64(c.highWatermark)*shrinkRatioThreshold {
|
|
||||||
errors.LogDebug(
|
|
||||||
context.Background(), c.name,
|
|
||||||
" shrinking cache map to reclaim memory.",
|
|
||||||
" new_size=", lenAfter,
|
|
||||||
" peak_size_before_shrink=", c.highWatermark,
|
|
||||||
" reduction_since_peak=", reductionFromPeak,
|
|
||||||
)
|
|
||||||
|
|
||||||
c.dirtyips = c.ips
|
|
||||||
c.ips = make(map[string]*record, int(float64(lenAfter)*1.1))
|
|
||||||
c.highWatermark = lenAfter
|
|
||||||
go c.migrate()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type migrationEntry struct {
|
func (c *CacheController) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||||
key string
|
|
||||||
value *record
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheController) migrate() {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
errors.LogError(context.Background(), c.name, " panic during cache migration: ", r)
|
|
||||||
c.Lock()
|
|
||||||
c.dirtyips = nil
|
|
||||||
// c.ips = make(map[string]*record)
|
|
||||||
// c.highWatermark = 0
|
|
||||||
c.Unlock()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
c.RLock()
|
c.RLock()
|
||||||
dirtyips := c.dirtyips
|
record, found := c.ips[domain]
|
||||||
c.RUnlock()
|
c.RUnlock()
|
||||||
|
|
||||||
// double check to prevent upper call multiple cleanup tasks
|
if !found {
|
||||||
if dirtyips == nil {
|
return nil, 0, errRecordNotFound
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogDebug(context.Background(), c.name, " starting background cache migration for ", len(dirtyips), " items")
|
var errs []error
|
||||||
|
var allIPs []net.IP
|
||||||
|
var rTTL uint32 = dns_feature.DefaultTTL
|
||||||
|
|
||||||
batch := make([]migrationEntry, 0, migrationBatchSize)
|
mergeReq := option.IPv4Enable && option.IPv6Enable
|
||||||
for domain, recD := range dirtyips {
|
|
||||||
batch = append(batch, migrationEntry{domain, recD})
|
|
||||||
|
|
||||||
if len(batch) >= migrationBatchSize {
|
if option.IPv4Enable {
|
||||||
c.flush(batch)
|
ips, ttl, err := record.A.getIPs()
|
||||||
batch = batch[:0]
|
if !mergeReq || go_errors.Is(err, errRecordNotFound) {
|
||||||
runtime.Gosched()
|
return ips, ttl, err
|
||||||
}
|
}
|
||||||
}
|
if ttl < rTTL {
|
||||||
if len(batch) > 0 {
|
rTTL = ttl
|
||||||
c.flush(batch)
|
}
|
||||||
}
|
if len(ips) > 0 {
|
||||||
|
allIPs = append(allIPs, ips...)
|
||||||
c.Lock()
|
|
||||||
c.dirtyips = nil
|
|
||||||
c.Unlock()
|
|
||||||
|
|
||||||
errors.LogDebug(context.Background(), c.name, " cache migration completed")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheController) flush(batch []migrationEntry) {
|
|
||||||
c.Lock()
|
|
||||||
defer c.Unlock()
|
|
||||||
|
|
||||||
for _, dirty := range batch {
|
|
||||||
if cur := c.ips[dirty.key]; cur != nil {
|
|
||||||
merge := &record{}
|
|
||||||
if cur.A == nil {
|
|
||||||
merge.A = dirty.value.A
|
|
||||||
} else {
|
|
||||||
merge.A = cur.A
|
|
||||||
}
|
|
||||||
if cur.AAAA == nil {
|
|
||||||
merge.AAAA = dirty.value.AAAA
|
|
||||||
} else {
|
|
||||||
merge.AAAA = cur.AAAA
|
|
||||||
}
|
|
||||||
c.ips[dirty.key] = merge
|
|
||||||
} else {
|
} else {
|
||||||
c.ips[dirty.key] = dirty.value
|
errs = append(errs, err)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheController) updateRecord(req *dnsRequest, rep *IPRecord) {
|
|
||||||
rtt := time.Since(req.start)
|
|
||||||
|
|
||||||
switch req.reqType {
|
|
||||||
case dnsmessage.TypeA:
|
|
||||||
c.pub.Publish(req.domain+"4", rep)
|
|
||||||
case dnsmessage.TypeAAAA:
|
|
||||||
c.pub.Publish(req.domain+"6", rep)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.disableCache {
|
|
||||||
errors.LogInfo(context.Background(), c.name, " got answer: ", req.domain, " ", req.reqType, " -> ", rep.IP, ", rtt: ", rtt)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Lock()
|
|
||||||
lockWait := time.Since(req.start) - rtt
|
|
||||||
|
|
||||||
newRec := &record{}
|
|
||||||
oldRec := c.ips[req.domain]
|
|
||||||
var dirtyRec *record
|
|
||||||
if c.dirtyips != nil {
|
|
||||||
dirtyRec = c.dirtyips[req.domain]
|
|
||||||
}
|
|
||||||
|
|
||||||
var pubRecord *IPRecord
|
|
||||||
var pubSuffix string
|
|
||||||
|
|
||||||
switch req.reqType {
|
|
||||||
case dnsmessage.TypeA:
|
|
||||||
newRec.A = rep
|
|
||||||
if oldRec != nil && oldRec.AAAA != nil {
|
|
||||||
newRec.AAAA = oldRec.AAAA
|
|
||||||
pubRecord = oldRec.AAAA
|
|
||||||
} else if dirtyRec != nil && dirtyRec.AAAA != nil {
|
|
||||||
pubRecord = dirtyRec.AAAA
|
|
||||||
}
|
|
||||||
pubSuffix = "6"
|
|
||||||
case dnsmessage.TypeAAAA:
|
|
||||||
newRec.AAAA = rep
|
|
||||||
if oldRec != nil && oldRec.A != nil {
|
|
||||||
newRec.A = oldRec.A
|
|
||||||
pubRecord = oldRec.A
|
|
||||||
} else if dirtyRec != nil && dirtyRec.A != nil {
|
|
||||||
pubRecord = dirtyRec.A
|
|
||||||
}
|
|
||||||
pubSuffix = "4"
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ips[req.domain] = newRec
|
|
||||||
c.Unlock()
|
|
||||||
|
|
||||||
if pubRecord != nil {
|
|
||||||
_, ttl, err := pubRecord.getIPs()
|
|
||||||
if ttl > 0 && !go_errors.Is(err, errRecordNotFound) {
|
|
||||||
c.pub.Publish(req.domain+pubSuffix, pubRecord)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogInfo(context.Background(), c.name, " got answer: ", req.domain, " ", req.reqType, " -> ", rep.IP, ", rtt: ", rtt, ", lock: ", lockWait)
|
if option.IPv6Enable {
|
||||||
|
ips, ttl, err := record.AAAA.getIPs()
|
||||||
if !c.serveStale || c.serveExpiredTTL != 0 {
|
if !mergeReq || go_errors.Is(err, errRecordNotFound) {
|
||||||
common.Must(c.cacheCleanup.Start())
|
return ips, ttl, err
|
||||||
|
}
|
||||||
|
if ttl < rTTL {
|
||||||
|
rTTL = ttl
|
||||||
|
}
|
||||||
|
if len(ips) > 0 {
|
||||||
|
allIPs = append(allIPs, ips...)
|
||||||
|
} else {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheController) findRecords(domain string) *record {
|
if len(allIPs) > 0 {
|
||||||
c.RLock()
|
return allIPs, rTTL, nil
|
||||||
defer c.RUnlock()
|
|
||||||
|
|
||||||
rec := c.ips[domain]
|
|
||||||
if rec == nil && c.dirtyips != nil {
|
|
||||||
rec = c.dirtyips[domain]
|
|
||||||
}
|
}
|
||||||
return rec
|
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) {
|
func (c *CacheController) registerSubscribers(domain string, option dns_feature.IPOption) (sub4 *pubsub.Subscriber, sub6 *pubsub.Subscriber) {
|
||||||
|
|||||||
+35
-11
@@ -2,24 +2,48 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/geodata"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/common/strmatcher"
|
||||||
"github.com/xtls/xray-core/common/uuid"
|
"github.com/xtls/xray-core/common/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var typeMap = map[DomainMatchingType]strmatcher.Type{
|
||||||
|
DomainMatchingType_Full: strmatcher.Full,
|
||||||
|
DomainMatchingType_Subdomain: strmatcher.Domain,
|
||||||
|
DomainMatchingType_Keyword: strmatcher.Substr,
|
||||||
|
DomainMatchingType_Regex: strmatcher.Regex,
|
||||||
|
}
|
||||||
|
|
||||||
// References:
|
// References:
|
||||||
// https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml
|
// https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml
|
||||||
// https://unix.stackexchange.com/questions/92441/whats-the-difference-between-local-home-and-lan
|
// https://unix.stackexchange.com/questions/92441/whats-the-difference-between-local-home-and-lan
|
||||||
var localTLDsAndDotlessDomainsRules = []*geodata.DomainRule{
|
var localTLDsAndDotlessDomains = []*NameServer_PriorityDomain{
|
||||||
{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Regex, Value: "^[^.]+$"}}}, // This will only match domains without any dot
|
{Type: DomainMatchingType_Regex, Domain: "^[^.]+$"}, // This will only match domains without any dot
|
||||||
{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "local"}}},
|
{Type: DomainMatchingType_Subdomain, Domain: "local"},
|
||||||
{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "localdomain"}}},
|
{Type: DomainMatchingType_Subdomain, Domain: "localdomain"},
|
||||||
{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "localhost"}}},
|
{Type: DomainMatchingType_Subdomain, Domain: "localhost"},
|
||||||
{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "lan"}}},
|
{Type: DomainMatchingType_Subdomain, Domain: "lan"},
|
||||||
{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "home.arpa"}}},
|
{Type: DomainMatchingType_Subdomain, Domain: "home.arpa"},
|
||||||
{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "example"}}},
|
{Type: DomainMatchingType_Subdomain, Domain: "example"},
|
||||||
{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "invalid"}}},
|
{Type: DomainMatchingType_Subdomain, Domain: "invalid"},
|
||||||
{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "test"}}},
|
{Type: DomainMatchingType_Subdomain, Domain: "test"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var localTLDsAndDotlessDomainsRule = &NameServer_OriginalRule{
|
||||||
|
Rule: "geosite:private",
|
||||||
|
Size: uint32(len(localTLDsAndDotlessDomains)),
|
||||||
|
}
|
||||||
|
|
||||||
|
func toStrMatcher(t DomainMatchingType, domain string) (strmatcher.Matcher, error) {
|
||||||
|
strMType, f := typeMap[t]
|
||||||
|
if !f {
|
||||||
|
return nil, errors.New("unknown mapping type", t).AtWarning()
|
||||||
|
}
|
||||||
|
matcher, err := strMType.New(domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to create str matcher").Base(err)
|
||||||
|
}
|
||||||
|
return matcher, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func toNetIP(addrs []net.Address) ([]net.IP, error) {
|
func toNetIP(addrs []net.Address) ([]net.IP, error) {
|
||||||
|
|||||||
+355
-175
@@ -1,19 +1,18 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/dns/config.proto
|
// source: app/dns/config.proto
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
geodata "github.com/xtls/xray-core/common/geodata"
|
router "github.com/xtls/xray-core/app/router"
|
||||||
net "github.com/xtls/xray-core/common/net"
|
net "github.com/xtls/xray-core/common/net"
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -23,6 +22,58 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type DomainMatchingType int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
DomainMatchingType_Full DomainMatchingType = 0
|
||||||
|
DomainMatchingType_Subdomain DomainMatchingType = 1
|
||||||
|
DomainMatchingType_Keyword DomainMatchingType = 2
|
||||||
|
DomainMatchingType_Regex DomainMatchingType = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for DomainMatchingType.
|
||||||
|
var (
|
||||||
|
DomainMatchingType_name = map[int32]string{
|
||||||
|
0: "Full",
|
||||||
|
1: "Subdomain",
|
||||||
|
2: "Keyword",
|
||||||
|
3: "Regex",
|
||||||
|
}
|
||||||
|
DomainMatchingType_value = map[string]int32{
|
||||||
|
"Full": 0,
|
||||||
|
"Subdomain": 1,
|
||||||
|
"Keyword": 2,
|
||||||
|
"Regex": 3,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x DomainMatchingType) Enum() *DomainMatchingType {
|
||||||
|
p := new(DomainMatchingType)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x DomainMatchingType) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (DomainMatchingType) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_app_dns_config_proto_enumTypes[0].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (DomainMatchingType) Type() protoreflect.EnumType {
|
||||||
|
return &file_app_dns_config_proto_enumTypes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x DomainMatchingType) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use DomainMatchingType.Descriptor instead.
|
||||||
|
func (DomainMatchingType) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_app_dns_config_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
type QueryStrategy int32
|
type QueryStrategy int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -59,11 +110,11 @@ func (x QueryStrategy) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (QueryStrategy) Descriptor() protoreflect.EnumDescriptor {
|
func (QueryStrategy) Descriptor() protoreflect.EnumDescriptor {
|
||||||
return file_app_dns_config_proto_enumTypes[0].Descriptor()
|
return file_app_dns_config_proto_enumTypes[1].Descriptor()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (QueryStrategy) Type() protoreflect.EnumType {
|
func (QueryStrategy) Type() protoreflect.EnumType {
|
||||||
return &file_app_dns_config_proto_enumTypes[0]
|
return &file_app_dns_config_proto_enumTypes[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x QueryStrategy) Number() protoreflect.EnumNumber {
|
func (x QueryStrategy) Number() protoreflect.EnumNumber {
|
||||||
@@ -72,29 +123,28 @@ func (x QueryStrategy) Number() protoreflect.EnumNumber {
|
|||||||
|
|
||||||
// Deprecated: Use QueryStrategy.Descriptor instead.
|
// Deprecated: Use QueryStrategy.Descriptor instead.
|
||||||
func (QueryStrategy) EnumDescriptor() ([]byte, []int) {
|
func (QueryStrategy) EnumDescriptor() ([]byte, []int) {
|
||||||
return file_app_dns_config_proto_rawDescGZIP(), []int{0}
|
return file_app_dns_config_proto_rawDescGZIP(), []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
type NameServer struct {
|
type NameServer struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Address *net.Endpoint `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
|
sizeCache protoimpl.SizeCache
|
||||||
ClientIp []byte `protobuf:"bytes,5,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
|
unknownFields protoimpl.UnknownFields
|
||||||
SkipFallback bool `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"`
|
|
||||||
Domain []*geodata.DomainRule `protobuf:"bytes,2,rep,name=domain,proto3" json:"domain,omitempty"`
|
Address *net.Endpoint `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
|
||||||
ExpectedIp []*geodata.IPRule `protobuf:"bytes,3,rep,name=expected_ip,json=expectedIp,proto3" json:"expected_ip,omitempty"`
|
ClientIp []byte `protobuf:"bytes,5,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
|
||||||
QueryStrategy QueryStrategy `protobuf:"varint,7,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
SkipFallback bool `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"`
|
||||||
ActPrior bool `protobuf:"varint,8,opt,name=actPrior,proto3" json:"actPrior,omitempty"`
|
PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
|
||||||
Tag string `protobuf:"bytes,9,opt,name=tag,proto3" json:"tag,omitempty"`
|
ExpectedGeoip []*router.GeoIP `protobuf:"bytes,3,rep,name=expected_geoip,json=expectedGeoip,proto3" json:"expected_geoip,omitempty"`
|
||||||
TimeoutMs uint64 `protobuf:"varint,10,opt,name=timeoutMs,proto3" json:"timeoutMs,omitempty"`
|
OriginalRules []*NameServer_OriginalRule `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
|
||||||
DisableCache *bool `protobuf:"varint,11,opt,name=disableCache,proto3,oneof" json:"disableCache,omitempty"`
|
QueryStrategy QueryStrategy `protobuf:"varint,7,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
||||||
ServeStale *bool `protobuf:"varint,15,opt,name=serveStale,proto3,oneof" json:"serveStale,omitempty"`
|
ActPrior bool `protobuf:"varint,8,opt,name=actPrior,proto3" json:"actPrior,omitempty"`
|
||||||
ServeExpiredTTL *uint32 `protobuf:"varint,16,opt,name=serveExpiredTTL,proto3,oneof" json:"serveExpiredTTL,omitempty"`
|
Tag string `protobuf:"bytes,9,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
FinalQuery bool `protobuf:"varint,12,opt,name=finalQuery,proto3" json:"finalQuery,omitempty"`
|
TimeoutMs uint64 `protobuf:"varint,10,opt,name=timeoutMs,proto3" json:"timeoutMs,omitempty"`
|
||||||
UnexpectedIp []*geodata.IPRule `protobuf:"bytes,13,rep,name=unexpected_ip,json=unexpectedIp,proto3" json:"unexpected_ip,omitempty"`
|
DisableCache bool `protobuf:"varint,11,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
|
||||||
ActUnprior bool `protobuf:"varint,14,opt,name=actUnprior,proto3" json:"actUnprior,omitempty"`
|
FinalQuery bool `protobuf:"varint,12,opt,name=finalQuery,proto3" json:"finalQuery,omitempty"`
|
||||||
PolicyID uint32 `protobuf:"varint,17,opt,name=policyID,proto3" json:"policyID,omitempty"`
|
UnexpectedGeoip []*router.GeoIP `protobuf:"bytes,13,rep,name=unexpected_geoip,json=unexpectedGeoip,proto3" json:"unexpected_geoip,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
ActUnprior bool `protobuf:"varint,14,opt,name=actUnprior,proto3" json:"actUnprior,omitempty"`
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) Reset() {
|
func (x *NameServer) Reset() {
|
||||||
@@ -148,16 +198,23 @@ func (x *NameServer) GetSkipFallback() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) GetDomain() []*geodata.DomainRule {
|
func (x *NameServer) GetPrioritizedDomain() []*NameServer_PriorityDomain {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Domain
|
return x.PrioritizedDomain
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) GetExpectedIp() []*geodata.IPRule {
|
func (x *NameServer) GetExpectedGeoip() []*router.GeoIP {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.ExpectedIp
|
return x.ExpectedGeoip
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NameServer) GetOriginalRules() []*NameServer_OriginalRule {
|
||||||
|
if x != nil {
|
||||||
|
return x.OriginalRules
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -191,26 +248,12 @@ func (x *NameServer) GetTimeoutMs() uint64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) GetDisableCache() bool {
|
func (x *NameServer) GetDisableCache() bool {
|
||||||
if x != nil && x.DisableCache != nil {
|
if x != nil {
|
||||||
return *x.DisableCache
|
return x.DisableCache
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) GetServeStale() bool {
|
|
||||||
if x != nil && x.ServeStale != nil {
|
|
||||||
return *x.ServeStale
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *NameServer) GetServeExpiredTTL() uint32 {
|
|
||||||
if x != nil && x.ServeExpiredTTL != nil {
|
|
||||||
return *x.ServeExpiredTTL
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *NameServer) GetFinalQuery() bool {
|
func (x *NameServer) GetFinalQuery() bool {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.FinalQuery
|
return x.FinalQuery
|
||||||
@@ -218,9 +261,9 @@ func (x *NameServer) GetFinalQuery() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) GetUnexpectedIp() []*geodata.IPRule {
|
func (x *NameServer) GetUnexpectedGeoip() []*router.GeoIP {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.UnexpectedIp
|
return x.UnexpectedGeoip
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -232,15 +275,11 @@ func (x *NameServer) GetActUnprior() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) GetPolicyID() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.PolicyID
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// NameServer list used by this DNS client.
|
// NameServer list used by this DNS client.
|
||||||
// A special value 'localhost' as a domain address can be set to use DNS on local system.
|
// A special value 'localhost' as a domain address can be set to use DNS on local system.
|
||||||
NameServer []*NameServer `protobuf:"bytes,5,rep,name=name_server,json=nameServer,proto3" json:"name_server,omitempty"`
|
NameServer []*NameServer `protobuf:"bytes,5,rep,name=name_server,json=nameServer,proto3" json:"name_server,omitempty"`
|
||||||
@@ -252,14 +291,9 @@ type Config struct {
|
|||||||
Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
|
Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
// DisableCache disables DNS cache
|
// DisableCache disables DNS cache
|
||||||
DisableCache bool `protobuf:"varint,8,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
|
DisableCache bool `protobuf:"varint,8,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
|
||||||
ServeStale bool `protobuf:"varint,12,opt,name=serveStale,proto3" json:"serveStale,omitempty"`
|
|
||||||
ServeExpiredTTL uint32 `protobuf:"varint,13,opt,name=serveExpiredTTL,proto3" json:"serveExpiredTTL,omitempty"`
|
|
||||||
QueryStrategy QueryStrategy `protobuf:"varint,9,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
QueryStrategy QueryStrategy `protobuf:"varint,9,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
||||||
DisableFallback bool `protobuf:"varint,10,opt,name=disableFallback,proto3" json:"disableFallback,omitempty"`
|
DisableFallback bool `protobuf:"varint,10,opt,name=disableFallback,proto3" json:"disableFallback,omitempty"`
|
||||||
DisableFallbackIfMatch bool `protobuf:"varint,11,opt,name=disableFallbackIfMatch,proto3" json:"disableFallbackIfMatch,omitempty"`
|
DisableFallbackIfMatch bool `protobuf:"varint,11,opt,name=disableFallbackIfMatch,proto3" json:"disableFallbackIfMatch,omitempty"`
|
||||||
EnableParallelQuery bool `protobuf:"varint,14,opt,name=enableParallelQuery,proto3" json:"enableParallelQuery,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -327,20 +361,6 @@ func (x *Config) GetDisableCache() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetServeStale() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.ServeStale
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetServeExpiredTTL() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.ServeExpiredTTL
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetQueryStrategy() QueryStrategy {
|
func (x *Config) GetQueryStrategy() QueryStrategy {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.QueryStrategy
|
return x.QueryStrategy
|
||||||
@@ -362,27 +382,128 @@ func (x *Config) GetDisableFallbackIfMatch() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetEnableParallelQuery() bool {
|
type NameServer_PriorityDomain struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Type DomainMatchingType `protobuf:"varint,1,opt,name=type,proto3,enum=xray.app.dns.DomainMatchingType" json:"type,omitempty"`
|
||||||
|
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NameServer_PriorityDomain) Reset() {
|
||||||
|
*x = NameServer_PriorityDomain{}
|
||||||
|
mi := &file_app_dns_config_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NameServer_PriorityDomain) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*NameServer_PriorityDomain) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *NameServer_PriorityDomain) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_dns_config_proto_msgTypes[2]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.EnableParallelQuery
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
}
|
}
|
||||||
return false
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use NameServer_PriorityDomain.ProtoReflect.Descriptor instead.
|
||||||
|
func (*NameServer_PriorityDomain) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_dns_config_proto_rawDescGZIP(), []int{0, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NameServer_PriorityDomain) GetType() DomainMatchingType {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return DomainMatchingType_Full
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NameServer_PriorityDomain) GetDomain() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Domain
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type NameServer_OriginalRule struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Rule string `protobuf:"bytes,1,opt,name=rule,proto3" json:"rule,omitempty"`
|
||||||
|
Size uint32 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NameServer_OriginalRule) Reset() {
|
||||||
|
*x = NameServer_OriginalRule{}
|
||||||
|
mi := &file_app_dns_config_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NameServer_OriginalRule) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*NameServer_OriginalRule) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *NameServer_OriginalRule) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_dns_config_proto_msgTypes[3]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use NameServer_OriginalRule.ProtoReflect.Descriptor instead.
|
||||||
|
func (*NameServer_OriginalRule) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_dns_config_proto_rawDescGZIP(), []int{0, 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NameServer_OriginalRule) GetRule() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Rule
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NameServer_OriginalRule) GetSize() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Size
|
||||||
|
}
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config_HostMapping struct {
|
type Config_HostMapping struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Domain *geodata.DomainRule `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
|
sizeCache protoimpl.SizeCache
|
||||||
Ip [][]byte `protobuf:"bytes,3,rep,name=ip,proto3" json:"ip,omitempty"`
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Type DomainMatchingType `protobuf:"varint,1,opt,name=type,proto3,enum=xray.app.dns.DomainMatchingType" json:"type,omitempty"`
|
||||||
|
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
|
||||||
|
Ip [][]byte `protobuf:"bytes,3,rep,name=ip,proto3" json:"ip,omitempty"`
|
||||||
// ProxiedDomain indicates the mapped domain has the same IP address on this
|
// ProxiedDomain indicates the mapped domain has the same IP address on this
|
||||||
// domain. Xray will use this domain for IP queries.
|
// domain. Xray will use this domain for IP queries.
|
||||||
ProxiedDomain string `protobuf:"bytes,4,opt,name=proxied_domain,json=proxiedDomain,proto3" json:"proxied_domain,omitempty"`
|
ProxiedDomain string `protobuf:"bytes,4,opt,name=proxied_domain,json=proxiedDomain,proto3" json:"proxied_domain,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config_HostMapping) Reset() {
|
func (x *Config_HostMapping) Reset() {
|
||||||
*x = Config_HostMapping{}
|
*x = Config_HostMapping{}
|
||||||
mi := &file_app_dns_config_proto_msgTypes[2]
|
mi := &file_app_dns_config_proto_msgTypes[4]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -394,7 +515,7 @@ func (x *Config_HostMapping) String() string {
|
|||||||
func (*Config_HostMapping) ProtoMessage() {}
|
func (*Config_HostMapping) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Config_HostMapping) ProtoReflect() protoreflect.Message {
|
func (x *Config_HostMapping) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_dns_config_proto_msgTypes[2]
|
mi := &file_app_dns_config_proto_msgTypes[4]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -410,11 +531,18 @@ func (*Config_HostMapping) Descriptor() ([]byte, []int) {
|
|||||||
return file_app_dns_config_proto_rawDescGZIP(), []int{1, 0}
|
return file_app_dns_config_proto_rawDescGZIP(), []int{1, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config_HostMapping) GetDomain() *geodata.DomainRule {
|
func (x *Config_HostMapping) GetType() DomainMatchingType {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return DomainMatchingType_Full
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config_HostMapping) GetDomain() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Domain
|
return x.Domain
|
||||||
}
|
}
|
||||||
return nil
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config_HostMapping) GetIp() [][]byte {
|
func (x *Config_HostMapping) GetIp() [][]byte {
|
||||||
@@ -433,104 +561,156 @@ func (x *Config_HostMapping) GetProxiedDomain() string {
|
|||||||
|
|
||||||
var File_app_dns_config_proto protoreflect.FileDescriptor
|
var File_app_dns_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_dns_config_proto_rawDesc = "" +
|
var file_app_dns_config_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x14, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
"\x14app/dns/config.proto\x12\fxray.app.dns\x1a\x1ccommon/net/destination.proto\x1a\x1bcommon/geodata/geodat.proto\"\xde\x05\n" +
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
"\n" +
|
0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74,
|
||||||
"NameServer\x123\n" +
|
0x2f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
"\aaddress\x18\x01 \x01(\v2\x19.xray.common.net.EndpointR\aaddress\x12\x1b\n" +
|
0x74, 0x6f, 0x1a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63,
|
||||||
"\tclient_ip\x18\x05 \x01(\fR\bclientIp\x12\"\n" +
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb6, 0x06, 0x0a, 0x0a,
|
||||||
"\fskipFallback\x18\x06 \x01(\bR\fskipFallback\x127\n" +
|
0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64,
|
||||||
"\x06domain\x18\x02 \x03(\v2\x1f.xray.common.geodata.DomainRuleR\x06domain\x12<\n" +
|
0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72,
|
||||||
"\vexpected_ip\x18\x03 \x03(\v2\x1b.xray.common.geodata.IPRuleR\n" +
|
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e,
|
||||||
"expectedIp\x12B\n" +
|
0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12,
|
||||||
"\x0equery_strategy\x18\a \x01(\x0e2\x1b.xray.app.dns.QueryStrategyR\rqueryStrategy\x12\x1a\n" +
|
0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x05, 0x20, 0x01,
|
||||||
"\bactPrior\x18\b \x01(\bR\bactPrior\x12\x10\n" +
|
0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x22, 0x0a, 0x0c,
|
||||||
"\x03tag\x18\t \x01(\tR\x03tag\x12\x1c\n" +
|
0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01,
|
||||||
"\ttimeoutMs\x18\n" +
|
0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
|
||||||
" \x01(\x04R\ttimeoutMs\x12'\n" +
|
0x12, 0x56, 0x0a, 0x12, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x5f,
|
||||||
"\fdisableCache\x18\v \x01(\bH\x00R\fdisableCache\x88\x01\x01\x12#\n" +
|
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78,
|
||||||
"\n" +
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65,
|
||||||
"serveStale\x18\x0f \x01(\bH\x01R\n" +
|
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44,
|
||||||
"serveStale\x88\x01\x01\x12-\n" +
|
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x11, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a,
|
||||||
"\x0fserveExpiredTTL\x18\x10 \x01(\rH\x02R\x0fserveExpiredTTL\x88\x01\x01\x12\x1e\n" +
|
0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3d, 0x0a, 0x0e, 0x65, 0x78, 0x70, 0x65,
|
||||||
"\n" +
|
0x63, 0x74, 0x65, 0x64, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
|
||||||
"finalQuery\x18\f \x01(\bR\n" +
|
0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||||
"finalQuery\x12@\n" +
|
0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0d, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74,
|
||||||
"\runexpected_ip\x18\r \x03(\v2\x1b.xray.common.geodata.IPRuleR\funexpectedIp\x12\x1e\n" +
|
0x65, 0x64, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69,
|
||||||
"\n" +
|
0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||||
"actUnprior\x18\x0e \x01(\bR\n" +
|
0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e,
|
||||||
"actUnprior\x12\x1a\n" +
|
0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e,
|
||||||
"\bpolicyID\x18\x11 \x01(\rR\bpolicyIDB\x0f\n" +
|
0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
|
||||||
"\r_disableCacheB\r\n" +
|
0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73,
|
||||||
"\v_serveStaleB\x12\n" +
|
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e,
|
||||||
"\x10_serveExpiredTTLJ\x04\b\x04\x10\x05\"\x82\x05\n" +
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65,
|
||||||
"\x06Config\x129\n" +
|
0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72,
|
||||||
"\vname_server\x18\x05 \x03(\v2\x18.xray.app.dns.NameServerR\n" +
|
0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x74,
|
||||||
"nameServer\x12\x1b\n" +
|
0x50, 0x72, 0x69, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x63, 0x74,
|
||||||
"\tclient_ip\x18\x03 \x01(\fR\bclientIp\x12C\n" +
|
0x50, 0x72, 0x69, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x09, 0x20, 0x01,
|
||||||
"\fstatic_hosts\x18\x04 \x03(\v2 .xray.app.dns.Config.HostMappingR\vstaticHosts\x12\x10\n" +
|
0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x6f,
|
||||||
"\x03tag\x18\x06 \x01(\tR\x03tag\x12\"\n" +
|
0x75, 0x74, 0x4d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
|
||||||
"\fdisableCache\x18\b \x01(\bR\fdisableCache\x12\x1e\n" +
|
0x6f, 0x75, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
|
||||||
"\n" +
|
0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73,
|
||||||
"serveStale\x18\f \x01(\bR\n" +
|
0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6e,
|
||||||
"serveStale\x12(\n" +
|
0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66,
|
||||||
"\x0fserveExpiredTTL\x18\r \x01(\rR\x0fserveExpiredTTL\x12B\n" +
|
0x69, 0x6e, 0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x41, 0x0a, 0x10, 0x75, 0x6e, 0x65,
|
||||||
"\x0equery_strategy\x18\t \x01(\x0e2\x1b.xray.app.dns.QueryStrategyR\rqueryStrategy\x12(\n" +
|
0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0d, 0x20,
|
||||||
"\x0fdisableFallback\x18\n" +
|
0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
||||||
" \x01(\bR\x0fdisableFallback\x126\n" +
|
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0f, 0x75, 0x6e, 0x65,
|
||||||
"\x16disableFallbackIfMatch\x18\v \x01(\bR\x16disableFallbackIfMatch\x120\n" +
|
0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a,
|
||||||
"\x13enableParallelQuery\x18\x0e \x01(\bR\x13enableParallelQuery\x1a}\n" +
|
0x61, 0x63, 0x74, 0x55, 0x6e, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08,
|
||||||
"\vHostMapping\x127\n" +
|
0x52, 0x0a, 0x61, 0x63, 0x74, 0x55, 0x6e, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x1a, 0x5e, 0x0a, 0x0e,
|
||||||
"\x06domain\x18\x02 \x01(\v2\x1f.xray.common.geodata.DomainRuleR\x06domain\x12\x0e\n" +
|
0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34,
|
||||||
"\x02ip\x18\x03 \x03(\fR\x02ip\x12%\n" +
|
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78,
|
||||||
"\x0eproxied_domain\x18\x04 \x01(\tR\rproxiedDomainJ\x04\b\a\x10\b*B\n" +
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61,
|
||||||
"\rQueryStrategy\x12\n" +
|
0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04,
|
||||||
"\n" +
|
0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02,
|
||||||
"\x06USE_IP\x10\x00\x12\v\n" +
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c,
|
||||||
"\aUSE_IP4\x10\x01\x12\v\n" +
|
0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04,
|
||||||
"\aUSE_IP6\x10\x02\x12\v\n" +
|
0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65,
|
||||||
"\aUSE_SYS\x10\x03BF\n" +
|
0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04,
|
||||||
"\x10com.xray.app.dnsP\x01Z!github.com/xtls/xray-core/app/dns\xaa\x02\fXray.App.Dnsb\x06proto3"
|
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 (
|
var (
|
||||||
file_app_dns_config_proto_rawDescOnce sync.Once
|
file_app_dns_config_proto_rawDescOnce sync.Once
|
||||||
file_app_dns_config_proto_rawDescData []byte
|
file_app_dns_config_proto_rawDescData = file_app_dns_config_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_dns_config_proto_rawDescGZIP() []byte {
|
func file_app_dns_config_proto_rawDescGZIP() []byte {
|
||||||
file_app_dns_config_proto_rawDescOnce.Do(func() {
|
file_app_dns_config_proto_rawDescOnce.Do(func() {
|
||||||
file_app_dns_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_dns_config_proto_rawDesc), len(file_app_dns_config_proto_rawDesc)))
|
file_app_dns_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_dns_config_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_dns_config_proto_rawDescData
|
return file_app_dns_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_app_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
var file_app_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||||
var file_app_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
var file_app_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||||
var file_app_dns_config_proto_goTypes = []any{
|
var file_app_dns_config_proto_goTypes = []any{
|
||||||
(QueryStrategy)(0), // 0: xray.app.dns.QueryStrategy
|
(DomainMatchingType)(0), // 0: xray.app.dns.DomainMatchingType
|
||||||
(*NameServer)(nil), // 1: xray.app.dns.NameServer
|
(QueryStrategy)(0), // 1: xray.app.dns.QueryStrategy
|
||||||
(*Config)(nil), // 2: xray.app.dns.Config
|
(*NameServer)(nil), // 2: xray.app.dns.NameServer
|
||||||
(*Config_HostMapping)(nil), // 3: xray.app.dns.Config.HostMapping
|
(*Config)(nil), // 3: xray.app.dns.Config
|
||||||
(*net.Endpoint)(nil), // 4: xray.common.net.Endpoint
|
(*NameServer_PriorityDomain)(nil), // 4: xray.app.dns.NameServer.PriorityDomain
|
||||||
(*geodata.DomainRule)(nil), // 5: xray.common.geodata.DomainRule
|
(*NameServer_OriginalRule)(nil), // 5: xray.app.dns.NameServer.OriginalRule
|
||||||
(*geodata.IPRule)(nil), // 6: xray.common.geodata.IPRule
|
(*Config_HostMapping)(nil), // 6: xray.app.dns.Config.HostMapping
|
||||||
|
(*net.Endpoint)(nil), // 7: xray.common.net.Endpoint
|
||||||
|
(*router.GeoIP)(nil), // 8: xray.app.router.GeoIP
|
||||||
}
|
}
|
||||||
var file_app_dns_config_proto_depIdxs = []int32{
|
var file_app_dns_config_proto_depIdxs = []int32{
|
||||||
4, // 0: xray.app.dns.NameServer.address:type_name -> xray.common.net.Endpoint
|
7, // 0: xray.app.dns.NameServer.address:type_name -> xray.common.net.Endpoint
|
||||||
5, // 1: xray.app.dns.NameServer.domain:type_name -> xray.common.geodata.DomainRule
|
4, // 1: xray.app.dns.NameServer.prioritized_domain:type_name -> xray.app.dns.NameServer.PriorityDomain
|
||||||
6, // 2: xray.app.dns.NameServer.expected_ip:type_name -> xray.common.geodata.IPRule
|
8, // 2: xray.app.dns.NameServer.expected_geoip:type_name -> xray.app.router.GeoIP
|
||||||
0, // 3: xray.app.dns.NameServer.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
5, // 3: xray.app.dns.NameServer.original_rules:type_name -> xray.app.dns.NameServer.OriginalRule
|
||||||
6, // 4: xray.app.dns.NameServer.unexpected_ip:type_name -> xray.common.geodata.IPRule
|
1, // 4: xray.app.dns.NameServer.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
||||||
1, // 5: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer
|
8, // 5: xray.app.dns.NameServer.unexpected_geoip:type_name -> xray.app.router.GeoIP
|
||||||
3, // 6: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
2, // 6: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer
|
||||||
0, // 7: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
6, // 7: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
||||||
5, // 8: xray.app.dns.Config.HostMapping.domain:type_name -> xray.common.geodata.DomainRule
|
1, // 8: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
||||||
9, // [9:9] is the sub-list for method output_type
|
0, // 9: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
|
||||||
9, // [9:9] is the sub-list for method input_type
|
0, // 10: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType
|
||||||
9, // [9:9] is the sub-list for extension type_name
|
11, // [11:11] is the sub-list for method output_type
|
||||||
9, // [9:9] is the sub-list for extension extendee
|
11, // [11:11] is the sub-list for method input_type
|
||||||
0, // [0:9] is the sub-list for field type_name
|
11, // [11:11] is the sub-list for extension type_name
|
||||||
|
11, // [11:11] is the sub-list for extension extendee
|
||||||
|
0, // [0:11] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_dns_config_proto_init() }
|
func init() { file_app_dns_config_proto_init() }
|
||||||
@@ -538,14 +718,13 @@ func file_app_dns_config_proto_init() {
|
|||||||
if File_app_dns_config_proto != nil {
|
if File_app_dns_config_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
file_app_dns_config_proto_msgTypes[0].OneofWrappers = []any{}
|
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_dns_config_proto_rawDesc), len(file_app_dns_config_proto_rawDesc)),
|
RawDescriptor: file_app_dns_config_proto_rawDesc,
|
||||||
NumEnums: 1,
|
NumEnums: 2,
|
||||||
NumMessages: 3,
|
NumMessages: 5,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
@@ -555,6 +734,7 @@ func file_app_dns_config_proto_init() {
|
|||||||
MessageInfos: file_app_dns_config_proto_msgTypes,
|
MessageInfos: file_app_dns_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_dns_config_proto = out.File
|
File_app_dns_config_proto = out.File
|
||||||
|
file_app_dns_config_proto_rawDesc = nil
|
||||||
file_app_dns_config_proto_goTypes = nil
|
file_app_dns_config_proto_goTypes = nil
|
||||||
file_app_dns_config_proto_depIdxs = nil
|
file_app_dns_config_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-14
@@ -7,26 +7,41 @@ option java_package = "com.xray.app.dns";
|
|||||||
option java_multiple_files = true;
|
option java_multiple_files = true;
|
||||||
|
|
||||||
import "common/net/destination.proto";
|
import "common/net/destination.proto";
|
||||||
import "common/geodata/geodat.proto";
|
import "app/router/config.proto";
|
||||||
|
|
||||||
message NameServer {
|
message NameServer {
|
||||||
xray.common.net.Endpoint address = 1;
|
xray.common.net.Endpoint address = 1;
|
||||||
bytes client_ip = 5;
|
bytes client_ip = 5;
|
||||||
bool skipFallback = 6;
|
bool skipFallback = 6;
|
||||||
repeated xray.common.geodata.DomainRule domain = 2;
|
|
||||||
repeated xray.common.geodata.IPRule expected_ip = 3;
|
message PriorityDomain {
|
||||||
reserved 4;
|
DomainMatchingType type = 1;
|
||||||
|
string domain = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message OriginalRule {
|
||||||
|
string rule = 1;
|
||||||
|
uint32 size = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated PriorityDomain prioritized_domain = 2;
|
||||||
|
repeated xray.app.router.GeoIP expected_geoip = 3;
|
||||||
|
repeated OriginalRule original_rules = 4;
|
||||||
QueryStrategy query_strategy = 7;
|
QueryStrategy query_strategy = 7;
|
||||||
bool actPrior = 8;
|
bool actPrior = 8;
|
||||||
string tag = 9;
|
string tag = 9;
|
||||||
uint64 timeoutMs = 10;
|
uint64 timeoutMs = 10;
|
||||||
optional bool disableCache = 11;
|
bool disableCache = 11;
|
||||||
optional bool serveStale = 15;
|
|
||||||
optional uint32 serveExpiredTTL = 16;
|
|
||||||
bool finalQuery = 12;
|
bool finalQuery = 12;
|
||||||
repeated xray.common.geodata.IPRule unexpected_ip = 13;
|
repeated xray.app.router.GeoIP unexpected_geoip = 13;
|
||||||
bool actUnprior = 14;
|
bool actUnprior = 14;
|
||||||
uint32 policyID = 17;
|
}
|
||||||
|
|
||||||
|
enum DomainMatchingType {
|
||||||
|
Full = 0;
|
||||||
|
Subdomain = 1;
|
||||||
|
Keyword = 2;
|
||||||
|
Regex = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum QueryStrategy {
|
enum QueryStrategy {
|
||||||
@@ -46,7 +61,8 @@ message Config {
|
|||||||
bytes client_ip = 3;
|
bytes client_ip = 3;
|
||||||
|
|
||||||
message HostMapping {
|
message HostMapping {
|
||||||
xray.common.geodata.DomainRule domain = 2;
|
DomainMatchingType type = 1;
|
||||||
|
string domain = 2;
|
||||||
|
|
||||||
repeated bytes ip = 3;
|
repeated bytes ip = 3;
|
||||||
|
|
||||||
@@ -64,13 +80,9 @@ message Config {
|
|||||||
|
|
||||||
// DisableCache disables DNS cache
|
// DisableCache disables DNS cache
|
||||||
bool disableCache = 8;
|
bool disableCache = 8;
|
||||||
bool serveStale = 12;
|
|
||||||
uint32 serveExpiredTTL = 13;
|
|
||||||
|
|
||||||
QueryStrategy query_strategy = 9;
|
QueryStrategy query_strategy = 9;
|
||||||
|
|
||||||
bool disableFallback = 10;
|
bool disableFallback = 10;
|
||||||
bool disableFallbackIfMatch = 11;
|
bool disableFallbackIfMatch = 11;
|
||||||
|
|
||||||
bool enableParallelQuery = 14;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+107
-298
@@ -11,10 +11,9 @@ import (
|
|||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/geodata"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/common/utils"
|
"github.com/xtls/xray-core/common/strmatcher"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,20 +22,19 @@ type DNS struct {
|
|||||||
sync.Mutex
|
sync.Mutex
|
||||||
disableFallback bool
|
disableFallback bool
|
||||||
disableFallbackIfMatch bool
|
disableFallbackIfMatch bool
|
||||||
enableParallelQuery bool
|
|
||||||
ipOption *dns.IPOption
|
ipOption *dns.IPOption
|
||||||
hosts *StaticHosts
|
hosts *StaticHosts
|
||||||
clients []*Client
|
clients []*Client
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
domainMatcher geodata.DomainMatcher
|
domainMatcher strmatcher.IndexMatcher
|
||||||
matcherInfos []*DomainMatcherInfo
|
matcherInfos []*DomainMatcherInfo
|
||||||
checkSystem bool
|
checkSystem bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// DomainMatcherInfo contains information attached to index returned by Server.domainMatcher.
|
// DomainMatcherInfo contains information attached to index returned by Server.domainMatcher
|
||||||
type DomainMatcherInfo struct {
|
type DomainMatcherInfo struct {
|
||||||
clientIdx uint16
|
clientIdx uint16
|
||||||
domainRule string
|
domainRuleIdx uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new DNS server with given configuration.
|
// New creates a new DNS server with given configuration.
|
||||||
@@ -86,36 +84,31 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
|||||||
return nil, errors.New("failed to create hosts").Base(err)
|
return nil, errors.New("failed to create hosts").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultTag := config.Tag
|
var clients []*Client
|
||||||
|
domainRuleCount := 0
|
||||||
|
|
||||||
|
var defaultTag = config.Tag
|
||||||
if len(config.Tag) == 0 {
|
if len(config.Tag) == 0 {
|
||||||
defaultTag = generateRandomTag()
|
defaultTag = generateRandomTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
clients := make([]*Client, 0, len(config.NameServer))
|
for _, ns := range config.NameServer {
|
||||||
matcherInfos := make([]*DomainMatcherInfo, 0)
|
domainRuleCount += len(ns.PrioritizedDomain)
|
||||||
effectiveRules := make([]*geodata.DomainRule, 0)
|
}
|
||||||
|
|
||||||
|
// 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{}
|
||||||
|
|
||||||
for _, ns := range config.NameServer {
|
for _, ns := range config.NameServer {
|
||||||
clientIdx := len(clients)
|
clientIdx := len(clients)
|
||||||
updateRules := func(isLocalNameServer bool) {
|
updateDomain := func(domainRule strmatcher.Matcher, originalRuleIdx int, matcherInfos []*DomainMatcherInfo) error {
|
||||||
// Prioritize local domains with specific TLDs or those without any dot for the local DNS
|
midx := domainMatcher.Add(domainRule)
|
||||||
if isLocalNameServer {
|
matcherInfos[midx] = &DomainMatcherInfo{
|
||||||
effectiveRules = append(effectiveRules, localTLDsAndDotlessDomainsRules...)
|
clientIdx: uint16(clientIdx),
|
||||||
for _, rule := range localTLDsAndDotlessDomainsRules {
|
domainRuleIdx: uint16(originalRuleIdx),
|
||||||
matcherInfos = append(matcherInfos, &DomainMatcherInfo{
|
|
||||||
clientIdx: uint16(clientIdx),
|
|
||||||
domainRule: rule.String(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
effectiveRules = append(effectiveRules, ns.Domain...)
|
|
||||||
for _, rule := range ns.Domain {
|
|
||||||
matcherInfos = append(matcherInfos, &DomainMatcherInfo{
|
|
||||||
clientIdx: uint16(clientIdx),
|
|
||||||
domainRule: rule.String(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
myClientIP := clientIP
|
myClientIP := clientIP
|
||||||
@@ -124,46 +117,24 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
|||||||
myClientIP = net.IP(ns.ClientIp)
|
myClientIP = net.IP(ns.ClientIp)
|
||||||
}
|
}
|
||||||
|
|
||||||
disableCache := config.DisableCache
|
disableCache := config.DisableCache || ns.DisableCache
|
||||||
if ns.DisableCache != nil {
|
|
||||||
disableCache = *ns.DisableCache
|
|
||||||
}
|
|
||||||
|
|
||||||
serveStale := config.ServeStale
|
var tag = defaultTag
|
||||||
if ns.ServeStale != nil {
|
|
||||||
serveStale = *ns.ServeStale
|
|
||||||
}
|
|
||||||
|
|
||||||
serveExpiredTTL := config.ServeExpiredTTL
|
|
||||||
if ns.ServeExpiredTTL != nil {
|
|
||||||
serveExpiredTTL = *ns.ServeExpiredTTL
|
|
||||||
}
|
|
||||||
|
|
||||||
tag := defaultTag
|
|
||||||
if len(ns.Tag) > 0 {
|
if len(ns.Tag) > 0 {
|
||||||
tag = ns.Tag
|
tag = ns.Tag
|
||||||
}
|
}
|
||||||
|
|
||||||
clientIPOption := ResolveIpOptionOverride(ns.QueryStrategy, ipOption)
|
clientIPOption := ResolveIpOptionOverride(ns.QueryStrategy, ipOption)
|
||||||
if !clientIPOption.IPv4Enable && !clientIPOption.IPv6Enable {
|
if !clientIPOption.IPv4Enable && !clientIPOption.IPv6Enable {
|
||||||
return nil, errors.New("no QueryStrategy available for ", ns.Address)
|
return nil, errors.New("no QueryStrategy available for ", ns.Address)
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := NewClient(ctx, ns, myClientIP, disableCache, serveStale, serveExpiredTTL, tag, clientIPOption, updateRules)
|
client, err := NewClient(ctx, ns, myClientIP, disableCache, tag, clientIPOption, &matcherInfos, updateDomain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to create client").Base(err)
|
return nil, errors.New("failed to create client").Base(err)
|
||||||
}
|
}
|
||||||
clients = append(clients, client)
|
clients = append(clients, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
var domainMatcher geodata.DomainMatcher
|
|
||||||
if len(effectiveRules) > 0 {
|
|
||||||
domainMatcher, err = geodata.DomainReg.BuildDomainMatcher(effectiveRules)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is no DNS client in config, add a `localhost` DNS client
|
// If there is no DNS client in config, add a `localhost` DNS client
|
||||||
if len(clients) == 0 {
|
if len(clients) == 0 {
|
||||||
clients = append(clients, NewLocalDNSClient(ipOption))
|
clients = append(clients, NewLocalDNSClient(ipOption))
|
||||||
@@ -178,7 +149,6 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
|||||||
matcherInfos: matcherInfos,
|
matcherInfos: matcherInfos,
|
||||||
disableFallback: config.DisableFallback,
|
disableFallback: config.DisableFallback,
|
||||||
disableFallbackIfMatch: config.DisableFallbackIfMatch,
|
disableFallbackIfMatch: config.DisableFallbackIfMatch,
|
||||||
enableParallelQuery: config.EnableParallelQuery,
|
|
||||||
checkSystem: checkSystem,
|
checkSystem: checkSystem,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -221,7 +191,7 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
if s.checkSystem {
|
if s.checkSystem {
|
||||||
supportIPv4, supportIPv6 := utils.CheckRoutes()
|
supportIPv4, supportIPv6 := checkSystemNetwork()
|
||||||
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
||||||
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
||||||
} else {
|
} else {
|
||||||
@@ -257,11 +227,45 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Name servers lookup
|
// Name servers lookup
|
||||||
if s.enableParallelQuery {
|
var errs []error
|
||||||
return s.parallelQuery(domain, option)
|
for _, client := range s.sortClients(domain) {
|
||||||
} else {
|
if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
|
||||||
return s.serialQuery(domain, option)
|
errors.LogDebug(s.ctx, "skip DNS resolution for domain ", domain, " at server ", client.Name())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ips, ttl, err := client.QueryIP(s.ctx, domain, option)
|
||||||
|
|
||||||
|
if len(ips) > 0 {
|
||||||
|
if ttl == 0 {
|
||||||
|
ttl = 1
|
||||||
|
}
|
||||||
|
return ips, ttl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
errors.LogInfoInner(s.ctx, err, "failed to lookup ip for domain ", domain, " at server ", client.Name())
|
||||||
|
if err == nil {
|
||||||
|
err = dns.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
errs = append(errs, err)
|
||||||
|
|
||||||
|
if client.IsFinalQuery() {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
return nil, 0, dns.ErrEmptyResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DNS) sortClients(domain string) []*Client {
|
func (s *DNS) sortClients(domain string) []*Client {
|
||||||
@@ -272,28 +276,22 @@ func (s *DNS) sortClients(domain string) []*Client {
|
|||||||
|
|
||||||
// Priority domain matching
|
// Priority domain matching
|
||||||
hasMatch := false
|
hasMatch := false
|
||||||
if s.domainMatcher != nil {
|
MatchSlice := s.domainMatcher.Match(domain)
|
||||||
matchSlice := s.domainMatcher.Match(strings.ToLower(domain))
|
sort.Slice(MatchSlice, func(i, j int) bool {
|
||||||
sort.Slice(matchSlice, func(i, j int) bool {
|
return MatchSlice[i] < MatchSlice[j]
|
||||||
return matchSlice[i] < matchSlice[j]
|
})
|
||||||
})
|
for _, match := range MatchSlice {
|
||||||
for _, match := range matchSlice {
|
info := s.matcherInfos[match]
|
||||||
info := s.matcherInfos[match]
|
client := s.clients[info.clientIdx]
|
||||||
client := s.clients[info.clientIdx]
|
domainRule := client.domains[info.domainRuleIdx]
|
||||||
domainRule := info.domainRule
|
domainRules = append(domainRules, fmt.Sprintf("%s(DNS idx:%d)", domainRule, info.clientIdx))
|
||||||
domainRules = append(domainRules, fmt.Sprintf("%s(DNS idx:%d)", domainRule, info.clientIdx))
|
if clientUsed[info.clientIdx] {
|
||||||
if clientUsed[info.clientIdx] {
|
continue
|
||||||
continue
|
|
||||||
}
|
|
||||||
clientUsed[info.clientIdx] = true
|
|
||||||
clients = append(clients, client)
|
|
||||||
clientNames = append(clientNames, client.Name())
|
|
||||||
hasMatch = true
|
|
||||||
if client.finalQuery {
|
|
||||||
logDecision(s.ctx, domain, domainRules, clientNames)
|
|
||||||
return clients
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
clientUsed[info.clientIdx] = true
|
||||||
|
clients = append(clients, client)
|
||||||
|
clientNames = append(clientNames, client.Name())
|
||||||
|
hasMatch = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(s.disableFallback || s.disableFallbackIfMatch && hasMatch) {
|
if !(s.disableFallback || s.disableFallbackIfMatch && hasMatch) {
|
||||||
@@ -305,235 +303,46 @@ func (s *DNS) sortClients(domain string) []*Client {
|
|||||||
clientUsed[idx] = true
|
clientUsed[idx] = true
|
||||||
clients = append(clients, client)
|
clients = append(clients, client)
|
||||||
clientNames = append(clientNames, client.Name())
|
clientNames = append(clientNames, client.Name())
|
||||||
if client.finalQuery {
|
|
||||||
logDecision(s.ctx, domain, domainRules, clientNames)
|
|
||||||
return clients
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logDecision(s.ctx, domain, domainRules, clientNames)
|
if len(domainRules) > 0 {
|
||||||
|
errors.LogDebug(s.ctx, "domain ", domain, " matches following rules: ", domainRules)
|
||||||
|
}
|
||||||
|
if len(clientNames) > 0 {
|
||||||
|
errors.LogDebug(s.ctx, "domain ", domain, " will use DNS in order: ", clientNames)
|
||||||
|
}
|
||||||
|
|
||||||
if len(clients) == 0 {
|
if len(clients) == 0 {
|
||||||
if len(s.clients) > 0 {
|
clients = append(clients, s.clients[0])
|
||||||
clients = append(clients, s.clients[0])
|
clientNames = append(clientNames, s.clients[0].Name())
|
||||||
clientNames = append(clientNames, s.clients[0].Name())
|
errors.LogDebug(s.ctx, "domain ", domain, " will use the first DNS: ", clientNames)
|
||||||
errors.LogWarning(s.ctx, "domain ", domain, " will use the first DNS: ", clientNames)
|
|
||||||
} else {
|
|
||||||
errors.LogError(s.ctx, "no DNS clients available for domain ", domain, " and no default clients configured")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return clients
|
return clients
|
||||||
}
|
}
|
||||||
|
|
||||||
func logDecision(ctx context.Context, domain string, domainRules []string, clientNames []string) {
|
|
||||||
if len(domainRules) > 0 {
|
|
||||||
errors.LogDebug(ctx, "domain ", domain, " matches following rules: ", domainRules)
|
|
||||||
}
|
|
||||||
if len(clientNames) > 0 {
|
|
||||||
errors.LogDebug(ctx, "domain ", domain, " will use DNS in order: ", clientNames)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mergeQueryErrors(domain string, errs []error) error {
|
|
||||||
if len(errs) == 0 {
|
|
||||||
return dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
var noRNF error
|
|
||||||
for _, err := range errs {
|
|
||||||
if go_errors.Is(err, errRecordNotFound) {
|
|
||||||
continue // server no response, ignore
|
|
||||||
} else if noRNF == nil {
|
|
||||||
noRNF = err
|
|
||||||
} else if !go_errors.Is(err, noRNF) {
|
|
||||||
return errors.New("returning nil for domain ", domain).Base(errors.Combine(errs...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if go_errors.Is(noRNF, dns.ErrEmptyResponse) {
|
|
||||||
return dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
if noRNF == nil {
|
|
||||||
noRNF = errRecordNotFound
|
|
||||||
}
|
|
||||||
return errors.New("returning nil for domain ", domain).Base(noRNF)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DNS) serialQuery(domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
|
||||||
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(s.ctx, domain, option)
|
|
||||||
|
|
||||||
if len(ips) > 0 {
|
|
||||||
return ips, ttl, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
errors.LogInfoInner(s.ctx, err, "failed to lookup ip for domain ", domain, " at server ", client.Name(), " in serial query mode")
|
|
||||||
if err == nil {
|
|
||||||
err = dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
return nil, 0, mergeQueryErrors(domain, errs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DNS) parallelQuery(domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
|
||||||
var errs []error
|
|
||||||
clients := s.sortClients(domain)
|
|
||||||
|
|
||||||
resultsChan := asyncQueryAll(domain, option, clients, s.ctx)
|
|
||||||
|
|
||||||
groups, groupOf := makeGroups( /*s.ctx,*/ clients)
|
|
||||||
results := make([]*queryResult, len(clients))
|
|
||||||
pending := make([]int, len(groups))
|
|
||||||
for gi, g := range groups {
|
|
||||||
pending[gi] = g.end - g.start + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
nextGroup := 0
|
|
||||||
for range clients {
|
|
||||||
result := <-resultsChan
|
|
||||||
results[result.index] = &result
|
|
||||||
|
|
||||||
gi := groupOf[result.index]
|
|
||||||
pending[gi]--
|
|
||||||
|
|
||||||
for nextGroup < len(groups) {
|
|
||||||
g := groups[nextGroup]
|
|
||||||
|
|
||||||
// group race, minimum rtt -> return
|
|
||||||
for j := g.start; j <= g.end; j++ {
|
|
||||||
r := results[j]
|
|
||||||
if r != nil && r.err == nil && len(r.ips) > 0 {
|
|
||||||
return r.ips, r.ttl, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// current group is incomplete and no one success -> continue pending
|
|
||||||
if pending[nextGroup] > 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// all failed -> log and continue next group
|
|
||||||
for j := g.start; j <= g.end; j++ {
|
|
||||||
r := results[j]
|
|
||||||
e := r.err
|
|
||||||
if e == nil {
|
|
||||||
e = dns.ErrEmptyResponse
|
|
||||||
}
|
|
||||||
errors.LogInfoInner(s.ctx, e, "failed to lookup ip for domain ", domain, " at server ", clients[j].Name(), " in parallel query mode")
|
|
||||||
errs = append(errs, e)
|
|
||||||
}
|
|
||||||
nextGroup++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, 0, mergeQueryErrors(domain, errs)
|
|
||||||
}
|
|
||||||
|
|
||||||
type queryResult struct {
|
|
||||||
ips []net.IP
|
|
||||||
ttl uint32
|
|
||||||
err error
|
|
||||||
index int
|
|
||||||
}
|
|
||||||
|
|
||||||
func asyncQueryAll(domain string, option dns.IPOption, clients []*Client, ctx context.Context) chan queryResult {
|
|
||||||
if len(clients) == 0 {
|
|
||||||
ch := make(chan queryResult)
|
|
||||||
close(ch)
|
|
||||||
return ch
|
|
||||||
}
|
|
||||||
|
|
||||||
ch := make(chan queryResult, len(clients))
|
|
||||||
for i, client := range clients {
|
|
||||||
if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
|
|
||||||
errors.LogDebug(ctx, "skip DNS resolution for domain ", domain, " at server ", client.Name())
|
|
||||||
ch <- queryResult{err: dns.ErrEmptyResponse, index: i}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
go func(i int, c *Client) {
|
|
||||||
qctx := ctx
|
|
||||||
if !c.server.IsDisableCache() {
|
|
||||||
nctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), c.timeoutMs*2)
|
|
||||||
qctx = nctx
|
|
||||||
defer cancel()
|
|
||||||
}
|
|
||||||
ips, ttl, err := c.QueryIP(qctx, domain, option)
|
|
||||||
ch <- queryResult{ips: ips, ttl: ttl, err: err, index: i}
|
|
||||||
}(i, client)
|
|
||||||
}
|
|
||||||
return ch
|
|
||||||
}
|
|
||||||
|
|
||||||
type group struct{ start, end int }
|
|
||||||
|
|
||||||
// merge only adjacent and rule-equivalent Client into a single group
|
|
||||||
func makeGroups( /*ctx context.Context,*/ clients []*Client) ([]group, []int) {
|
|
||||||
n := len(clients)
|
|
||||||
if n == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
groups := make([]group, 0, n)
|
|
||||||
groupOf := make([]int, n)
|
|
||||||
|
|
||||||
s, e := 0, 0
|
|
||||||
for i := 1; i < n; i++ {
|
|
||||||
if clients[i-1].policyID == clients[i].policyID {
|
|
||||||
e = i
|
|
||||||
} else {
|
|
||||||
for k := s; k <= e; k++ {
|
|
||||||
groupOf[k] = len(groups)
|
|
||||||
}
|
|
||||||
groups = append(groups, group{start: s, end: e})
|
|
||||||
s, e = i, i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for k := s; k <= e; k++ {
|
|
||||||
groupOf[k] = len(groups)
|
|
||||||
}
|
|
||||||
groups = append(groups, group{start: s, end: e})
|
|
||||||
|
|
||||||
// var b strings.Builder
|
|
||||||
// b.WriteString("dns grouping: total clients=")
|
|
||||||
// b.WriteString(strconv.Itoa(n))
|
|
||||||
// b.WriteString(", groups=")
|
|
||||||
// b.WriteString(strconv.Itoa(len(groups)))
|
|
||||||
|
|
||||||
// for gi, g := range groups {
|
|
||||||
// b.WriteString("\n [")
|
|
||||||
// b.WriteString(strconv.Itoa(g.start))
|
|
||||||
// b.WriteString("..")
|
|
||||||
// b.WriteString(strconv.Itoa(g.end))
|
|
||||||
// b.WriteString("] gid=")
|
|
||||||
// b.WriteString(strconv.Itoa(gi))
|
|
||||||
// b.WriteString(" pid=")
|
|
||||||
// b.WriteString(strconv.FormatUint(uint64(clients[g.start].policyID), 10))
|
|
||||||
// b.WriteString(" members: ")
|
|
||||||
|
|
||||||
// for i := g.start; i <= g.end; i++ {
|
|
||||||
// if i > g.start {
|
|
||||||
// b.WriteString(", ")
|
|
||||||
// }
|
|
||||||
// b.WriteString(strconv.Itoa(i))
|
|
||||||
// b.WriteByte(':')
|
|
||||||
// b.WriteString(clients[i].Name())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// errors.LogDebug(ctx, b.String())
|
|
||||||
|
|
||||||
return groups, groupOf
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||||
return New(ctx, config.(*Config))
|
return New(ctx, config.(*Config))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkSystemNetwork() (supportIPv4 bool, supportIPv6 bool) {
|
||||||
|
conn4, err4 := net.Dial("udp4", "192.33.4.12:53")
|
||||||
|
if err4 != nil {
|
||||||
|
supportIPv4 = false
|
||||||
|
} else {
|
||||||
|
supportIPv4 = true
|
||||||
|
conn4.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
conn6, err6 := net.Dial("udp6", "[2001:500:2::c]:53")
|
||||||
|
if err6 != nil {
|
||||||
|
supportIPv6 = false
|
||||||
|
} else {
|
||||||
|
supportIPv6 = true
|
||||||
|
conn6.Close()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
+100
-68
@@ -11,9 +11,9 @@ import (
|
|||||||
"github.com/xtls/xray-core/app/policy"
|
"github.com/xtls/xray-core/app/policy"
|
||||||
"github.com/xtls/xray-core/app/proxyman"
|
"github.com/xtls/xray-core/app/proxyman"
|
||||||
_ "github.com/xtls/xray-core/app/proxyman/outbound"
|
_ "github.com/xtls/xray-core/app/proxyman/outbound"
|
||||||
|
"github.com/xtls/xray-core/app/router"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/geodata"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
@@ -147,9 +147,7 @@ func TestUDPServerSubnet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||||
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -209,9 +207,7 @@ func TestUDPServer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||||
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -335,9 +331,10 @@ func TestPrioritizedDomain(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Port: uint32(port),
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
Domain: []*geodata.DomainRule{
|
PrioritizedDomain: []*NameServer_PriorityDomain{
|
||||||
{
|
{
|
||||||
Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Full, Value: "google.com"}},
|
Type: DomainMatchingType_Full,
|
||||||
|
Domain: "google.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -349,9 +346,7 @@ func TestPrioritizedDomain(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||||
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -420,9 +415,7 @@ func TestUDPServerIPv6(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||||
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -478,7 +471,8 @@ func TestStaticHostDomain(t *testing.T) {
|
|||||||
},
|
},
|
||||||
StaticHosts: []*Config_HostMapping{
|
StaticHosts: []*Config_HostMapping{
|
||||||
{
|
{
|
||||||
Domain: &geodata.DomainRule{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Full, Value: "example.com"}}},
|
Type: DomainMatchingType_Full,
|
||||||
|
Domain: "example.com",
|
||||||
ProxiedDomain: "google.com",
|
ProxiedDomain: "google.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -489,9 +483,7 @@ func TestStaticHostDomain(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||||
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -547,9 +539,17 @@ func TestIPMatch(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Port: uint32(port),
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
ExpectedIp: []*geodata.IPRule{
|
ExpectedGeoip: []*router.GeoIP{
|
||||||
// inner ip, will not match
|
{
|
||||||
{Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{192, 168, 11, 1}, Prefix: 32}}}},
|
CountryCode: "local",
|
||||||
|
Cidr: []*router.CIDR{
|
||||||
|
{
|
||||||
|
// inner ip, will not match
|
||||||
|
Ip: []byte{192, 168, 11, 1},
|
||||||
|
Prefix: 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// second dns, match ip
|
// second dns, match ip
|
||||||
@@ -563,9 +563,25 @@ func TestIPMatch(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Port: uint32(port),
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
ExpectedIp: []*geodata.IPRule{
|
ExpectedGeoip: []*router.GeoIP{
|
||||||
{Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{8, 8, 8, 8}, Prefix: 32}}}},
|
{
|
||||||
{Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{8, 8, 8, 4}, Prefix: 32}}}},
|
CountryCode: "test",
|
||||||
|
Cidr: []*router.CIDR{
|
||||||
|
{
|
||||||
|
Ip: []byte{8, 8, 8, 8},
|
||||||
|
Prefix: 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
CountryCode: "test",
|
||||||
|
Cidr: []*router.CIDR{
|
||||||
|
{
|
||||||
|
Ip: []byte{8, 8, 8, 4},
|
||||||
|
Prefix: 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -576,9 +592,7 @@ func TestIPMatch(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||||
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -649,15 +663,19 @@ func TestLocalDomain(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Port: uint32(port),
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
Domain: []*geodata.DomainRule{
|
PrioritizedDomain: []*NameServer_PriorityDomain{
|
||||||
// Equivalent of dotless:localhost
|
// Equivalent of dotless:localhost
|
||||||
{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Regex, Value: "^[^.]*localhost[^.]*$"}}},
|
{Type: DomainMatchingType_Regex, Domain: "^[^.]*localhost[^.]*$"},
|
||||||
},
|
},
|
||||||
ExpectedIp: []*geodata.IPRule{
|
ExpectedGeoip: []*router.GeoIP{
|
||||||
// Will match localhost, localhost-a and localhost-b,
|
{ // Will match localhost, localhost-a and localhost-b,
|
||||||
{Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{127, 0, 0, 2}, Prefix: 32}}}},
|
CountryCode: "local",
|
||||||
{Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{127, 0, 0, 3}, Prefix: 32}}}},
|
Cidr: []*router.CIDR{
|
||||||
{Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{127, 0, 0, 4}, Prefix: 32}}}},
|
{Ip: []byte{127, 0, 0, 2}, Prefix: 32},
|
||||||
|
{Ip: []byte{127, 0, 0, 3}, Prefix: 32},
|
||||||
|
{Ip: []byte{127, 0, 0, 4}, Prefix: 32},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -670,21 +688,23 @@ func TestLocalDomain(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Port: uint32(port),
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
Domain: []*geodata.DomainRule{
|
PrioritizedDomain: []*NameServer_PriorityDomain{
|
||||||
// Equivalent of dotless: and domain:local
|
// Equivalent of dotless: and domain:local
|
||||||
{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Regex, Value: "^[^.]*$"}}},
|
{Type: DomainMatchingType_Regex, Domain: "^[^.]*$"},
|
||||||
{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "local"}}},
|
{Type: DomainMatchingType_Subdomain, Domain: "local"},
|
||||||
{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "localdomain"}}},
|
{Type: DomainMatchingType_Subdomain, Domain: "localdomain"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
StaticHosts: []*Config_HostMapping{
|
StaticHosts: []*Config_HostMapping{
|
||||||
{
|
{
|
||||||
Domain: &geodata.DomainRule{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Full, Value: "hostnamestatic"}}},
|
Type: DomainMatchingType_Full,
|
||||||
|
Domain: "hostnamestatic",
|
||||||
Ip: [][]byte{{127, 0, 0, 53}},
|
Ip: [][]byte{{127, 0, 0, 53}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Domain: &geodata.DomainRule{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Full, Value: "hostnamealias"}}},
|
Type: DomainMatchingType_Full,
|
||||||
|
Domain: "hostnamealias",
|
||||||
ProxiedDomain: "hostname.localdomain",
|
ProxiedDomain: "hostname.localdomain",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -695,9 +715,7 @@ func TestLocalDomain(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||||
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -873,15 +891,19 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Port: uint32(port),
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
Domain: []*geodata.DomainRule{
|
PrioritizedDomain: []*NameServer_PriorityDomain{
|
||||||
{
|
{
|
||||||
Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "google.com"}},
|
Type: DomainMatchingType_Subdomain,
|
||||||
|
Domain: "google.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedIp: []*geodata.IPRule{
|
ExpectedGeoip: []*router.GeoIP{
|
||||||
// Will only match 8.8.8.8 and 8.8.4.4
|
{ // Will only match 8.8.8.8 and 8.8.4.4
|
||||||
{Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{8, 8, 8, 8}, Prefix: 32}}}},
|
Cidr: []*router.CIDR{
|
||||||
{Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{8, 8, 4, 4}, Prefix: 32}}}},
|
{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
|
||||||
|
{Ip: []byte{8, 8, 4, 4}, Prefix: 32},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -894,14 +916,18 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Port: uint32(port),
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
Domain: []*geodata.DomainRule{
|
PrioritizedDomain: []*NameServer_PriorityDomain{
|
||||||
{
|
{
|
||||||
Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "google.com"}},
|
Type: DomainMatchingType_Subdomain,
|
||||||
|
Domain: "google.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedIp: []*geodata.IPRule{
|
ExpectedGeoip: []*router.GeoIP{
|
||||||
// Will match 8.8.8.8 and 8.8.8.7, etc
|
{ // Will match 8.8.8.8 and 8.8.8.7, etc
|
||||||
{Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{8, 8, 8, 7}, Prefix: 24}}}},
|
Cidr: []*router.CIDR{
|
||||||
|
{Ip: []byte{8, 8, 8, 7}, Prefix: 24},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -914,14 +940,18 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Port: uint32(port),
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
Domain: []*geodata.DomainRule{
|
PrioritizedDomain: []*NameServer_PriorityDomain{
|
||||||
{
|
{
|
||||||
Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "api.google.com"}},
|
Type: DomainMatchingType_Subdomain,
|
||||||
|
Domain: "api.google.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedIp: []*geodata.IPRule{
|
ExpectedGeoip: []*router.GeoIP{
|
||||||
// Will only match 8.8.7.7 (api.google.com)
|
{ // Will only match 8.8.7.7 (api.google.com)
|
||||||
{Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{8, 8, 7, 7}, Prefix: 32}}}},
|
Cidr: []*router.CIDR{
|
||||||
|
{Ip: []byte{8, 8, 7, 7}, Prefix: 32},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -934,14 +964,18 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Port: uint32(port),
|
Port: uint32(port),
|
||||||
},
|
},
|
||||||
Domain: []*geodata.DomainRule{
|
PrioritizedDomain: []*NameServer_PriorityDomain{
|
||||||
{
|
{
|
||||||
Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Full, Value: "v2.api.google.com"}},
|
Type: DomainMatchingType_Full,
|
||||||
|
Domain: "v2.api.google.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedIp: []*geodata.IPRule{
|
ExpectedGeoip: []*router.GeoIP{
|
||||||
// Will only match 8.8.7.8 (v2.api.google.com)
|
{ // Will only match 8.8.7.8 (v2.api.google.com)
|
||||||
{Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{8, 8, 7, 8}, Prefix: 32}}}},
|
Cidr: []*router.CIDR{
|
||||||
|
{Ip: []byte{8, 8, 7, 8}, Prefix: 32},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -952,9 +986,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||||
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-22
@@ -3,7 +3,6 @@ package dns
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"math"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -14,12 +13,10 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||||
|
|
||||||
"golang.org/x/net/dns/dnsmessage"
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fqdn normalizes domain make sure it ends with '.'
|
// Fqdn normalizes domain make sure it ends with '.'
|
||||||
// case-sensitive
|
|
||||||
func Fqdn(domain string) string {
|
func Fqdn(domain string) string {
|
||||||
if len(domain) > 0 && strings.HasSuffix(domain, ".") {
|
if len(domain) > 0 && strings.HasSuffix(domain, ".") {
|
||||||
return domain
|
return domain
|
||||||
@@ -41,14 +38,19 @@ type IPRecord struct {
|
|||||||
RawHeader *dnsmessage.Header
|
RawHeader *dnsmessage.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IPRecord) getIPs() ([]net.IP, int32, error) {
|
func (r *IPRecord) getIPs() ([]net.IP, uint32, error) {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return nil, 0, errRecordNotFound
|
return nil, 0, errRecordNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
untilExpire := time.Until(r.Expire).Seconds()
|
untilExpire := time.Until(r.Expire).Seconds()
|
||||||
ttl := int32(math.Ceil(untilExpire))
|
if untilExpire <= 0 {
|
||||||
|
return nil, 0, errRecordNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
ttl := uint32(untilExpire) + 1
|
||||||
|
if ttl == 1 {
|
||||||
|
r.Expire = time.Now().Add(time.Second) // To ensure that two consecutive requests get the same result
|
||||||
|
}
|
||||||
if r.RCode != dnsmessage.RCodeSuccess {
|
if r.RCode != dnsmessage.RCodeSuccess {
|
||||||
return nil, ttl, dns_feature.RCodeError(r.RCode)
|
return nil, ttl, dns_feature.RCodeError(r.RCode)
|
||||||
}
|
}
|
||||||
@@ -127,20 +129,15 @@ func genEDNS0Options(clientIP net.IP, padding int) *dnsmessage.Resource {
|
|||||||
return opt
|
return opt
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildReqMsgs(domain string, option dns_feature.IPOption, reqIDGen func() uint16, reqOpts *dnsmessage.Resource) ([]*dnsRequest, error) {
|
func buildReqMsgs(domain string, option dns_feature.IPOption, reqIDGen func() uint16, reqOpts *dnsmessage.Resource) []*dnsRequest {
|
||||||
name, err := dnsmessage.NewName(domain)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
qA := dnsmessage.Question{
|
qA := dnsmessage.Question{
|
||||||
Name: name,
|
Name: dnsmessage.MustNewName(domain),
|
||||||
Type: dnsmessage.TypeA,
|
Type: dnsmessage.TypeA,
|
||||||
Class: dnsmessage.ClassINET,
|
Class: dnsmessage.ClassINET,
|
||||||
}
|
}
|
||||||
|
|
||||||
qAAAA := dnsmessage.Question{
|
qAAAA := dnsmessage.Question{
|
||||||
Name: name,
|
Name: dnsmessage.MustNewName(domain),
|
||||||
Type: dnsmessage.TypeAAAA,
|
Type: dnsmessage.TypeAAAA,
|
||||||
Class: dnsmessage.ClassINET,
|
Class: dnsmessage.ClassINET,
|
||||||
}
|
}
|
||||||
@@ -180,7 +177,7 @@ func buildReqMsgs(domain string, option dns_feature.IPOption, reqIDGen func() ui
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return reqs, nil
|
return reqs
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseResponse parses DNS answers from the returned payload
|
// parseResponse parses DNS answers from the returned payload
|
||||||
@@ -198,14 +195,9 @@ func parseResponse(payload []byte) (*IPRecord, error) {
|
|||||||
ipRecord := &IPRecord{
|
ipRecord := &IPRecord{
|
||||||
ReqID: h.ID,
|
ReqID: h.ID,
|
||||||
RCode: h.RCode,
|
RCode: h.RCode,
|
||||||
|
Expire: now.Add(time.Second * dns_feature.DefaultTTL),
|
||||||
RawHeader: &h,
|
RawHeader: &h,
|
||||||
}
|
}
|
||||||
defer func() {
|
|
||||||
// set to default TTL if no valid TTL is found
|
|
||||||
if ipRecord.Expire.IsZero() {
|
|
||||||
ipRecord.Expire = now.Add(time.Second * dns_feature.DefaultTTL)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
L:
|
L:
|
||||||
for {
|
for {
|
||||||
@@ -222,7 +214,7 @@ L:
|
|||||||
ttl = 1
|
ttl = 1
|
||||||
}
|
}
|
||||||
expire := now.Add(time.Duration(ttl) * time.Second)
|
expire := now.Add(time.Duration(ttl) * time.Second)
|
||||||
if ipRecord.Expire.IsZero() || ipRecord.Expire.After(expire) {
|
if ipRecord.Expire.After(expire) {
|
||||||
ipRecord.Expire = expire
|
ipRecord.Expire = expire
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -25,8 +24,7 @@ func Test_parseResponse(t *testing.T) {
|
|||||||
|
|
||||||
ans = new(dns.Msg)
|
ans = new(dns.Msg)
|
||||||
ans.Id = 1
|
ans.Id = 1
|
||||||
ans.Answer = append(
|
ans.Answer = append(ans.Answer,
|
||||||
ans.Answer,
|
|
||||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
|
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 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.8.8")),
|
||||||
@@ -36,8 +34,7 @@ func Test_parseResponse(t *testing.T) {
|
|||||||
|
|
||||||
ans = new(dns.Msg)
|
ans = new(dns.Msg)
|
||||||
ans.Id = 2
|
ans.Id = 2
|
||||||
ans.Answer = append(
|
ans.Answer = append(ans.Answer,
|
||||||
ans.Answer,
|
|
||||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
|
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 fake.google.com")),
|
||||||
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
|
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
|
||||||
@@ -134,15 +131,10 @@ func Test_buildReqMsgs(t *testing.T) {
|
|||||||
IPv6Enable: false,
|
IPv6Enable: false,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
}, nil}, 0},
|
}, nil}, 0},
|
||||||
{"name too long", args{strings.Repeat("a", 256), dns_feature.IPOption{
|
|
||||||
IPv4Enable: true,
|
|
||||||
IPv6Enable: true,
|
|
||||||
FakeEnable: false,
|
|
||||||
}, nil}, 0},
|
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got, _ := buildReqMsgs(tt.args.domain, tt.args.option, stubID, tt.args.reqOpts); !(len(got) == tt.want) {
|
if got := buildReqMsgs(tt.args.domain, tt.args.option, stubID, tt.args.reqOpts); !(len(got) == tt.want) {
|
||||||
t.Errorf("buildReqMsgs() = %v, want %v", got, tt.want)
|
t.Errorf("buildReqMsgs() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+16
-11
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
gonet "net"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -16,8 +17,8 @@ import (
|
|||||||
|
|
||||||
type Holder struct {
|
type Holder struct {
|
||||||
domainToIP cache.Lru
|
domainToIP cache.Lru
|
||||||
ipRange *net.IPNet
|
ipRange *gonet.IPNet
|
||||||
mu sync.Mutex
|
mu *sync.Mutex
|
||||||
|
|
||||||
config *FakeDnsPool
|
config *FakeDnsPool
|
||||||
}
|
}
|
||||||
@@ -49,7 +50,9 @@ func (fkdns *Holder) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (fkdns *Holder) Close() error {
|
func (fkdns *Holder) Close() error {
|
||||||
// nothing to do for now, just wait GC
|
fkdns.domainToIP = nil
|
||||||
|
fkdns.ipRange = nil
|
||||||
|
fkdns.mu = nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +71,7 @@ func NewFakeDNSHolder() (*Holder, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewFakeDNSHolderConfigOnly(conf *FakeDnsPool) (*Holder, error) {
|
func NewFakeDNSHolderConfigOnly(conf *FakeDnsPool) (*Holder, error) {
|
||||||
return &Holder{config: conf}, nil
|
return &Holder{nil, nil, nil, conf}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fkdns *Holder) initializeFromConfig() error {
|
func (fkdns *Holder) initializeFromConfig() error {
|
||||||
@@ -76,10 +79,10 @@ func (fkdns *Holder) initializeFromConfig() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error {
|
func (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error {
|
||||||
var ipRange *net.IPNet
|
var ipRange *gonet.IPNet
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if _, ipRange, err = net.ParseCIDR(ipPoolCidr); err != nil {
|
if _, ipRange, err = gonet.ParseCIDR(ipPoolCidr); err != nil {
|
||||||
return errors.New("Unable to parse CIDR for Fake DNS IP assignment").Base(err).AtError()
|
return errors.New("Unable to parse CIDR for Fake DNS IP assignment").Base(err).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +93,7 @@ func (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error {
|
|||||||
}
|
}
|
||||||
fkdns.domainToIP = cache.NewLru(lruSize)
|
fkdns.domainToIP = cache.NewLru(lruSize)
|
||||||
fkdns.ipRange = ipRange
|
fkdns.ipRange = ipRange
|
||||||
|
fkdns.mu = new(sync.Mutex)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +104,7 @@ func (fkdns *Holder) GetFakeIPForDomain(domain string) []net.Address {
|
|||||||
if v, ok := fkdns.domainToIP.Get(domain); ok {
|
if v, ok := fkdns.domainToIP.Get(domain); ok {
|
||||||
return []net.Address{v.(net.Address)}
|
return []net.Address{v.(net.Address)}
|
||||||
}
|
}
|
||||||
currentTimeMillis := uint64(time.Now().UnixMilli())
|
currentTimeMillis := uint64(time.Now().UnixNano() / 1e6)
|
||||||
ones, bits := fkdns.ipRange.Mask.Size()
|
ones, bits := fkdns.ipRange.Mask.Size()
|
||||||
rooms := bits - ones
|
rooms := bits - ones
|
||||||
if rooms < 64 {
|
if rooms < 64 {
|
||||||
@@ -199,11 +203,12 @@ func (h *HolderMulti) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *HolderMulti) Close() error {
|
func (h *HolderMulti) Close() error {
|
||||||
var errs []error
|
|
||||||
for _, v := range h.holders {
|
for _, v := range h.holders {
|
||||||
errs = append(errs, v.Close())
|
if err := v.Close(); err != nil {
|
||||||
|
return errors.New("Cannot close all fake dns pools").Base(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return errors.Combine(errs...)
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HolderMulti) createHolderGroups() error {
|
func (h *HolderMulti) createHolderGroups() error {
|
||||||
@@ -218,7 +223,7 @@ func (h *HolderMulti) createHolderGroups() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewFakeDNSHolderMulti(conf *FakeDnsPoolMulti) (*HolderMulti, error) {
|
func NewFakeDNSHolderMulti(conf *FakeDnsPoolMulti) (*HolderMulti, error) {
|
||||||
holderMulti := &HolderMulti{config: conf}
|
holderMulti := &HolderMulti{nil, conf}
|
||||||
if err := holderMulti.createHolderGroups(); err != nil {
|
if err := holderMulti.createHolderGroups(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/dns/fakedns/fakedns.proto
|
// source: app/dns/fakedns/fakedns.proto
|
||||||
|
|
||||||
package fakedns
|
package fakedns
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -22,11 +21,12 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type FakeDnsPool struct {
|
type FakeDnsPool struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
IpPool string `protobuf:"bytes,1,opt,name=ip_pool,json=ipPool,proto3" json:"ip_pool,omitempty"` //CIDR of IP pool used as fake DNS IP
|
|
||||||
LruSize int64 `protobuf:"varint,2,opt,name=lruSize,proto3" json:"lruSize,omitempty"` //Size of Pool for remembering relationship between domain name and IP address
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
IpPool string `protobuf:"bytes,1,opt,name=ip_pool,json=ipPool,proto3" json:"ip_pool,omitempty"` //CIDR of IP pool used as fake DNS IP
|
||||||
|
LruSize int64 `protobuf:"varint,2,opt,name=lruSize,proto3" json:"lruSize,omitempty"` //Size of Pool for remembering relationship between domain name and IP address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *FakeDnsPool) Reset() {
|
func (x *FakeDnsPool) Reset() {
|
||||||
@@ -74,10 +74,11 @@ func (x *FakeDnsPool) GetLruSize() int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FakeDnsPoolMulti struct {
|
type FakeDnsPoolMulti struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Pools []*FakeDnsPool `protobuf:"bytes,1,rep,name=pools,proto3" json:"pools,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Pools []*FakeDnsPool `protobuf:"bytes,1,rep,name=pools,proto3" json:"pools,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *FakeDnsPoolMulti) Reset() {
|
func (x *FakeDnsPoolMulti) Reset() {
|
||||||
@@ -119,24 +120,36 @@ func (x *FakeDnsPoolMulti) GetPools() []*FakeDnsPool {
|
|||||||
|
|
||||||
var File_app_dns_fakedns_fakedns_proto protoreflect.FileDescriptor
|
var File_app_dns_fakedns_fakedns_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_dns_fakedns_fakedns_proto_rawDesc = "" +
|
var file_app_dns_fakedns_fakedns_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x1d, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
|
||||||
"\x1dapp/dns/fakedns/fakedns.proto\x12\x14xray.app.dns.fakedns\"@\n" +
|
0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
||||||
"\vFakeDnsPool\x12\x17\n" +
|
0x14, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61,
|
||||||
"\aip_pool\x18\x01 \x01(\tR\x06ipPool\x12\x18\n" +
|
0x6b, 0x65, 0x64, 0x6e, 0x73, 0x22, 0x40, 0x0a, 0x0b, 0x46, 0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73,
|
||||||
"\alruSize\x18\x02 \x01(\x03R\alruSize\"K\n" +
|
0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x70, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x18,
|
||||||
"\x10FakeDnsPoolMulti\x127\n" +
|
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x70, 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x18, 0x0a,
|
||||||
"\x05pools\x18\x01 \x03(\v2!.xray.app.dns.fakedns.FakeDnsPoolR\x05poolsB^\n" +
|
0x07, 0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07,
|
||||||
"\x18com.xray.app.dns.fakednsP\x01Z)github.com/xtls/xray-core/app/dns/fakedns\xaa\x02\x14Xray.App.Dns.Fakednsb\x06proto3"
|
0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x4b, 0x0a, 0x10, 0x46, 0x61, 0x6b, 0x65, 0x44,
|
||||||
|
0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x12, 0x37, 0x0a, 0x05, 0x70,
|
||||||
|
0x6f, 0x6f, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61,
|
||||||
|
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
|
||||||
|
0x73, 0x2e, 0x46, 0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x05, 0x70,
|
||||||
|
0x6f, 0x6f, 0x6c, 0x73, 0x42, 0x5e, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
|
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73,
|
||||||
|
0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
|
||||||
|
0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
|
||||||
|
0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x14,
|
||||||
|
0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6b,
|
||||||
|
0x65, 0x64, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_app_dns_fakedns_fakedns_proto_rawDescOnce sync.Once
|
file_app_dns_fakedns_fakedns_proto_rawDescOnce sync.Once
|
||||||
file_app_dns_fakedns_fakedns_proto_rawDescData []byte
|
file_app_dns_fakedns_fakedns_proto_rawDescData = file_app_dns_fakedns_fakedns_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_dns_fakedns_fakedns_proto_rawDescGZIP() []byte {
|
func file_app_dns_fakedns_fakedns_proto_rawDescGZIP() []byte {
|
||||||
file_app_dns_fakedns_fakedns_proto_rawDescOnce.Do(func() {
|
file_app_dns_fakedns_fakedns_proto_rawDescOnce.Do(func() {
|
||||||
file_app_dns_fakedns_fakedns_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_dns_fakedns_fakedns_proto_rawDesc), len(file_app_dns_fakedns_fakedns_proto_rawDesc)))
|
file_app_dns_fakedns_fakedns_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_dns_fakedns_fakedns_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_dns_fakedns_fakedns_proto_rawDescData
|
return file_app_dns_fakedns_fakedns_proto_rawDescData
|
||||||
}
|
}
|
||||||
@@ -164,7 +177,7 @@ func file_app_dns_fakedns_fakedns_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_dns_fakedns_fakedns_proto_rawDesc), len(file_app_dns_fakedns_fakedns_proto_rawDesc)),
|
RawDescriptor: file_app_dns_fakedns_fakedns_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 2,
|
NumMessages: 2,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
@@ -175,6 +188,7 @@ func file_app_dns_fakedns_fakedns_proto_init() {
|
|||||||
MessageInfos: file_app_dns_fakedns_fakedns_proto_msgTypes,
|
MessageInfos: file_app_dns_fakedns_fakedns_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_dns_fakedns_fakedns_proto = out.File
|
File_app_dns_fakedns_fakedns_proto = out.File
|
||||||
|
file_app_dns_fakedns_fakedns_proto_rawDesc = nil
|
||||||
file_app_dns_fakedns_fakedns_proto_goTypes = nil
|
file_app_dns_fakedns_fakedns_proto_goTypes = nil
|
||||||
file_app_dns_fakedns_fakedns_proto_depIdxs = nil
|
file_app_dns_fakedns_fakedns_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package fakedns
|
package fakedns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
gonet "net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -129,16 +130,15 @@ func TestFakeDnsHolderCreateMappingAndRollOver(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFakeDNSMulti(t *testing.T) {
|
func TestFakeDNSMulti(t *testing.T) {
|
||||||
fakeMulti, err := NewFakeDNSHolderMulti(
|
fakeMulti, err := NewFakeDNSHolderMulti(&FakeDnsPoolMulti{
|
||||||
&FakeDnsPoolMulti{
|
Pools: []*FakeDnsPool{{
|
||||||
Pools: []*FakeDnsPool{{
|
IpPool: "240.0.0.0/12",
|
||||||
IpPool: "240.0.0.0/12",
|
LruSize: 256,
|
||||||
LruSize: 256,
|
}, {
|
||||||
}, {
|
IpPool: "fddd:c5b4:ff5f:f4f0::/64",
|
||||||
IpPool: "fddd:c5b4:ff5f:f4f0::/64",
|
LruSize: 256,
|
||||||
LruSize: 256,
|
}},
|
||||||
}},
|
},
|
||||||
},
|
|
||||||
)
|
)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ func TestFakeDNSMulti(t *testing.T) {
|
|||||||
assert.True(t, inPool)
|
assert.True(t, inPool)
|
||||||
})
|
})
|
||||||
t.Run("ipv6", func(t *testing.T) {
|
t.Run("ipv6", func(t *testing.T) {
|
||||||
ip, err := net.ResolveIPAddr("ip", "fddd:c5b4:ff5f:f4f0::5")
|
ip, err := gonet.ResolveIPAddr("ip", "fddd:c5b4:ff5f:f4f0::5")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
inPool := fakeMulti.IsIPInIPPool(net.IPAddress(ip.IP))
|
inPool := fakeMulti.IsIPInIPPool(net.IPAddress(ip.IP))
|
||||||
assert.True(t, inPool)
|
assert.True(t, inPool)
|
||||||
@@ -165,7 +165,7 @@ func TestFakeDNSMulti(t *testing.T) {
|
|||||||
assert.False(t, inPool)
|
assert.False(t, inPool)
|
||||||
})
|
})
|
||||||
t.Run("ipv6_inverse", func(t *testing.T) {
|
t.Run("ipv6_inverse", func(t *testing.T) {
|
||||||
ip, err := net.ResolveIPAddr("ip", "fcdd:c5b4:ff5f:f4f0::5")
|
ip, err := gonet.ResolveIPAddr("ip", "fcdd:c5b4:ff5f:f4f0::5")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
inPool := fakeMulti.IsIPInIPPool(net.IPAddress(ip.IP))
|
inPool := fakeMulti.IsIPInIPPool(net.IPAddress(ip.IP))
|
||||||
assert.False(t, inPool)
|
assert.False(t, inPool)
|
||||||
|
|||||||
+26
-37
@@ -3,27 +3,34 @@ package dns
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/geodata"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/common/strmatcher"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StaticHosts represents static domain-ip mapping in DNS server.
|
// StaticHosts represents static domain-ip mapping in DNS server.
|
||||||
type StaticHosts struct {
|
type StaticHosts struct {
|
||||||
responses [][]net.Address
|
ips [][]net.Address
|
||||||
matcher geodata.DomainMatcher
|
matchers *strmatcher.MatcherGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStaticHosts creates a new StaticHosts instance.
|
// NewStaticHosts creates a new StaticHosts instance.
|
||||||
func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
|
func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
|
||||||
reps := make([][]net.Address, 0, len(hosts))
|
g := new(strmatcher.MatcherGroup)
|
||||||
rules := make([]*geodata.DomainRule, 0, len(hosts))
|
sh := &StaticHosts{
|
||||||
|
ips: make([][]net.Address, len(hosts)+16),
|
||||||
|
matchers: g,
|
||||||
|
}
|
||||||
|
|
||||||
for _, mapping := range hosts {
|
for _, mapping := range hosts {
|
||||||
rep := make([]net.Address, 0, len(mapping.Ip))
|
matcher, err := toStrMatcher(mapping.Type, mapping.Domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to create domain matcher").Base(err)
|
||||||
|
}
|
||||||
|
id := g.Add(matcher)
|
||||||
|
ips := make([]net.Address, 0, len(mapping.Ip)+1)
|
||||||
switch {
|
switch {
|
||||||
case len(mapping.ProxiedDomain) > 0:
|
case len(mapping.ProxiedDomain) > 0:
|
||||||
if mapping.ProxiedDomain[0] == '#' {
|
if mapping.ProxiedDomain[0] == '#' {
|
||||||
@@ -31,36 +38,24 @@ func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rep = append(rep, dns.RCodeError(rcode))
|
ips = append(ips, dns.RCodeError(rcode))
|
||||||
} else {
|
} else {
|
||||||
rep = append(rep, net.DomainAddress(mapping.ProxiedDomain))
|
ips = append(ips, net.DomainAddress(mapping.ProxiedDomain))
|
||||||
}
|
}
|
||||||
case len(mapping.Ip) > 0:
|
case len(mapping.Ip) > 0:
|
||||||
for _, ip := range mapping.Ip {
|
for _, ip := range mapping.Ip {
|
||||||
addr := net.IPAddress(ip)
|
addr := net.IPAddress(ip)
|
||||||
if addr == nil {
|
if addr == nil {
|
||||||
errors.LogError(context.Background(), "invalid IP address in static hosts: ", ip, ", ignore this ip for rule: ", mapping.Domain)
|
return nil, errors.New("invalid IP address in static hosts: ", ip).AtWarning()
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
rep = append(rep, addr)
|
ips = append(ips, addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reps = append(reps, rep)
|
|
||||||
rules = append(rules, mapping.Domain)
|
sh.ips[id] = ips
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rules) == 0 {
|
return sh, nil
|
||||||
return &StaticHosts{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
matcher, err := geodata.DomainReg.BuildDomainMatcher(rules)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &StaticHosts{
|
|
||||||
responses: reps,
|
|
||||||
matcher: matcher,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
|
func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
|
||||||
@@ -76,16 +71,16 @@ func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
|
|||||||
func (h *StaticHosts) lookupInternal(domain string) ([]net.Address, error) {
|
func (h *StaticHosts) lookupInternal(domain string) ([]net.Address, error) {
|
||||||
ips := make([]net.Address, 0)
|
ips := make([]net.Address, 0)
|
||||||
found := false
|
found := false
|
||||||
for _, idx := range h.matcher.Match(domain) {
|
for _, id := range h.matchers.Match(domain) {
|
||||||
for _, rep := range h.responses[idx] {
|
for _, v := range h.ips[id] {
|
||||||
if err, ok := rep.(dns.RCodeError); ok {
|
if err, ok := v.(dns.RCodeError); ok {
|
||||||
if uint16(err) == 0 {
|
if uint16(err) == 0 {
|
||||||
return nil, dns.ErrEmptyResponse
|
return nil, dns.ErrEmptyResponse
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ips = append(ips, h.responses[idx]...)
|
ips = append(ips, h.ips[id]...)
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
@@ -95,13 +90,10 @@ func (h *StaticHosts) lookupInternal(domain string) ([]net.Address, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) ([]net.Address, error) {
|
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) ([]net.Address, error) {
|
||||||
domain = strings.ToLower(domain)
|
|
||||||
switch addrs, err := h.lookupInternal(domain); {
|
switch addrs, err := h.lookupInternal(domain); {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return nil, err
|
return nil, err
|
||||||
case addrs == nil: // Not recorded in static hosts, return nil
|
case len(addrs) == 0: // Not recorded in static hosts, return nil
|
||||||
return nil, nil
|
|
||||||
case len(addrs) == 0: // Domain recorded, but no valid IP returned
|
|
||||||
return addrs, nil
|
return addrs, nil
|
||||||
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Try to unwrap domain
|
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")
|
errors.LogDebug(context.Background(), "found replaced domain: ", domain, " -> ", addrs[0].Domain(), ". Try to unwrap it")
|
||||||
@@ -122,8 +114,5 @@ func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) (
|
|||||||
|
|
||||||
// Lookup returns IP addresses or proxied domain for the given domain, if exists in this StaticHosts.
|
// 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, error) {
|
func (h *StaticHosts) Lookup(domain string, option dns.IPOption) ([]net.Address, error) {
|
||||||
if h.matcher == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return h.lookup(domain, option, 5)
|
return h.lookup(domain, option, 5)
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-7
@@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
. "github.com/xtls/xray-core/app/dns"
|
. "github.com/xtls/xray-core/app/dns"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/geodata"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
)
|
)
|
||||||
@@ -14,17 +13,20 @@ import (
|
|||||||
func TestStaticHosts(t *testing.T) {
|
func TestStaticHosts(t *testing.T) {
|
||||||
pb := []*Config_HostMapping{
|
pb := []*Config_HostMapping{
|
||||||
{
|
{
|
||||||
Domain: &geodata.DomainRule{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "lan"}}},
|
Type: DomainMatchingType_Subdomain,
|
||||||
|
Domain: "lan",
|
||||||
ProxiedDomain: "#3",
|
ProxiedDomain: "#3",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Domain: &geodata.DomainRule{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Full, Value: "example.com"}}},
|
Type: DomainMatchingType_Full,
|
||||||
|
Domain: "example.com",
|
||||||
Ip: [][]byte{
|
Ip: [][]byte{
|
||||||
{1, 1, 1, 1},
|
{1, 1, 1, 1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Domain: &geodata.DomainRule{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Full, Value: "proxy.xray.com"}}},
|
Type: DomainMatchingType_Full,
|
||||||
|
Domain: "proxy.xray.com",
|
||||||
Ip: [][]byte{
|
Ip: [][]byte{
|
||||||
{1, 2, 3, 4},
|
{1, 2, 3, 4},
|
||||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
@@ -32,17 +34,20 @@ func TestStaticHosts(t *testing.T) {
|
|||||||
ProxiedDomain: "another-proxy.xray.com",
|
ProxiedDomain: "another-proxy.xray.com",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Domain: &geodata.DomainRule{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Full, Value: "proxy2.xray.com"}}},
|
Type: DomainMatchingType_Full,
|
||||||
|
Domain: "proxy2.xray.com",
|
||||||
ProxiedDomain: "proxy.xray.com",
|
ProxiedDomain: "proxy.xray.com",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Domain: &geodata.DomainRule{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "example.cn"}}},
|
Type: DomainMatchingType_Subdomain,
|
||||||
|
Domain: "example.cn",
|
||||||
Ip: [][]byte{
|
Ip: [][]byte{
|
||||||
{2, 2, 2, 2},
|
{2, 2, 2, 2},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Domain: &geodata.DomainRule{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "baidu.com"}}},
|
Type: DomainMatchingType_Subdomain,
|
||||||
|
Domain: "baidu.com",
|
||||||
Ip: [][]byte{
|
Ip: [][]byte{
|
||||||
{127, 0, 0, 1},
|
{127, 0, 0, 1},
|
||||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
|||||||
+96
-45
@@ -6,11 +6,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/app/router"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/geodata"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/common/utils"
|
"github.com/xtls/xray-core/common/strmatcher"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
@@ -20,9 +20,6 @@ import (
|
|||||||
type Server interface {
|
type Server interface {
|
||||||
// Name of the Client.
|
// Name of the Client.
|
||||||
Name() string
|
Name() string
|
||||||
|
|
||||||
IsDisableCache() bool
|
|
||||||
|
|
||||||
// QueryIP sends IP queries to its configured server.
|
// QueryIP sends IP queries to its configured server.
|
||||||
QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, uint32, error)
|
QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, uint32, error)
|
||||||
}
|
}
|
||||||
@@ -31,8 +28,9 @@ type Server interface {
|
|||||||
type Client struct {
|
type Client struct {
|
||||||
server Server
|
server Server
|
||||||
skipFallback bool
|
skipFallback bool
|
||||||
expectedIPs geodata.IPMatcher
|
domains []string
|
||||||
unexpectedIPs geodata.IPMatcher
|
expectedIPs []*router.GeoIPMatcher
|
||||||
|
unexpectedIPs []*router.GeoIPMatcher
|
||||||
actPrior bool
|
actPrior bool
|
||||||
actUnprior bool
|
actUnprior bool
|
||||||
tag string
|
tag string
|
||||||
@@ -40,11 +38,10 @@ type Client struct {
|
|||||||
finalQuery bool
|
finalQuery bool
|
||||||
ipOption *dns.IPOption
|
ipOption *dns.IPOption
|
||||||
checkSystem bool
|
checkSystem bool
|
||||||
policyID uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServer creates a name server object according to the network destination url.
|
// NewServer creates a name server object according to the network destination url.
|
||||||
func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dispatcher, disableCache bool, serveStale bool, serveExpiredTTL uint32, clientIP net.IP) (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() {
|
if address := dest.Address; address.Family().IsDomain() {
|
||||||
u, err := url.Parse(address.Domain())
|
u, err := url.Parse(address.Domain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -54,19 +51,19 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis
|
|||||||
case strings.EqualFold(u.String(), "localhost"):
|
case strings.EqualFold(u.String(), "localhost"):
|
||||||
return NewLocalNameServer(), nil
|
return NewLocalNameServer(), nil
|
||||||
case strings.EqualFold(u.Scheme, "https"): // DNS-over-HTTPS Remote mode
|
case strings.EqualFold(u.Scheme, "https"): // DNS-over-HTTPS Remote mode
|
||||||
return NewDoHNameServer(u, dispatcher, false, disableCache, serveStale, serveExpiredTTL, clientIP), nil
|
return NewDoHNameServer(u, dispatcher, false, disableCache, clientIP), nil
|
||||||
case strings.EqualFold(u.Scheme, "h2c"): // DNS-over-HTTPS h2c Remote mode
|
case strings.EqualFold(u.Scheme, "h2c"): // DNS-over-HTTPS h2c Remote mode
|
||||||
return NewDoHNameServer(u, dispatcher, true, disableCache, serveStale, serveExpiredTTL, clientIP), nil
|
return NewDoHNameServer(u, dispatcher, true, disableCache, clientIP), nil
|
||||||
case strings.EqualFold(u.Scheme, "https+local"): // DNS-over-HTTPS Local mode
|
case strings.EqualFold(u.Scheme, "https+local"): // DNS-over-HTTPS Local mode
|
||||||
return NewDoHNameServer(u, nil, false, disableCache, serveStale, serveExpiredTTL, clientIP), nil
|
return NewDoHNameServer(u, nil, false, disableCache, clientIP), nil
|
||||||
case strings.EqualFold(u.Scheme, "h2c+local"): // DNS-over-HTTPS h2c Local mode
|
case strings.EqualFold(u.Scheme, "h2c+local"): // DNS-over-HTTPS h2c Local mode
|
||||||
return NewDoHNameServer(u, nil, true, disableCache, serveStale, serveExpiredTTL, clientIP), nil
|
return NewDoHNameServer(u, nil, true, disableCache, clientIP), nil
|
||||||
case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode
|
case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode
|
||||||
return NewQUICNameServer(u, disableCache, serveStale, serveExpiredTTL, clientIP)
|
return NewQUICNameServer(u, disableCache, clientIP)
|
||||||
case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode
|
case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode
|
||||||
return NewTCPNameServer(u, dispatcher, disableCache, serveStale, serveExpiredTTL, clientIP)
|
return NewTCPNameServer(u, dispatcher, disableCache, clientIP)
|
||||||
case strings.EqualFold(u.Scheme, "tcp+local"): // DNS-over-TCP Local mode
|
case strings.EqualFold(u.Scheme, "tcp+local"): // DNS-over-TCP Local mode
|
||||||
return NewTCPLocalNameServer(u, disableCache, serveStale, serveExpiredTTL, clientIP)
|
return NewTCPLocalNameServer(u, disableCache, clientIP)
|
||||||
case strings.EqualFold(u.String(), "fakedns"):
|
case strings.EqualFold(u.String(), "fakedns"):
|
||||||
var fd dns.FakeDNSEngine
|
var fd dns.FakeDNSEngine
|
||||||
err = core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
err = core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||||
@@ -82,7 +79,7 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis
|
|||||||
dest.Network = net.Network_UDP
|
dest.Network = net.Network_UDP
|
||||||
}
|
}
|
||||||
if dest.Network == net.Network_UDP { // UDP classic DNS mode
|
if dest.Network == net.Network_UDP { // UDP classic DNS mode
|
||||||
return NewClassicNameServer(dest, dispatcher, disableCache, serveStale, serveExpiredTTL, clientIP), nil
|
return NewClassicNameServer(dest, dispatcher, disableCache, clientIP), nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("No available name server could be created from ", dest).AtWarning()
|
return nil, errors.New("No available name server could be created from ", dest).AtWarning()
|
||||||
}
|
}
|
||||||
@@ -92,38 +89,88 @@ func NewClient(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
ns *NameServer,
|
ns *NameServer,
|
||||||
clientIP net.IP,
|
clientIP net.IP,
|
||||||
disableCache bool, serveStale bool, serveExpiredTTL uint32,
|
disableCache bool,
|
||||||
tag string,
|
tag string,
|
||||||
ipOption dns.IPOption,
|
ipOption dns.IPOption,
|
||||||
updateRules func(bool),
|
matcherInfos *[]*DomainMatcherInfo,
|
||||||
|
updateDomainRule func(strmatcher.Matcher, int, []*DomainMatcherInfo) error,
|
||||||
) (*Client, error) {
|
) (*Client, error) {
|
||||||
client := &Client{}
|
client := &Client{}
|
||||||
|
|
||||||
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
|
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
|
||||||
// Create a new server for each client for now
|
// Create a new server for each client for now
|
||||||
server, err := NewServer(ctx, ns.Address.AsDestination(), dispatcher, disableCache, serveStale, serveExpiredTTL, clientIP)
|
server, err := NewServer(ctx, ns.Address.AsDestination(), dispatcher, disableCache, clientIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create nameserver").Base(err).AtWarning()
|
return errors.New("failed to create nameserver").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
_, isLocalDNS := server.(*LocalNameServer)
|
// Prioritize local domains with specific TLDs or those without any dot for the local DNS
|
||||||
updateRules(isLocalDNS)
|
if _, isLocalDNS := server.(*LocalNameServer); isLocalDNS {
|
||||||
|
ns.PrioritizedDomain = append(ns.PrioritizedDomain, localTLDsAndDotlessDomains...)
|
||||||
// Establish expected IPs
|
ns.OriginalRules = append(ns.OriginalRules, localTLDsAndDotlessDomainsRule)
|
||||||
var expectedMatcher geodata.IPMatcher
|
// The following lines is a solution to avoid core panics(rule index out of range) when setting `localhost` DNS client in config.
|
||||||
if len(ns.ExpectedIp) > 0 {
|
// Because the `localhost` DNS client will append len(localTLDsAndDotlessDomains) rules into matcherInfos to match `geosite:private` default rule.
|
||||||
expectedMatcher, err = geodata.IPReg.BuildIPMatcher(ns.ExpectedIp)
|
// But `matcherInfos` has no enough length to add rules, which leads to core panics (rule index out of range).
|
||||||
if err != nil {
|
// To avoid this, the length of `matcherInfos` must be equal to the expected, so manually append it with Golang default zero value first for later modification.
|
||||||
return errors.New("failed to create expected ip matcher").Base(err).AtWarning()
|
// Related issues:
|
||||||
|
// https://github.com/v2fly/v2ray-core/issues/529
|
||||||
|
// https://github.com/v2fly/v2ray-core/issues/719
|
||||||
|
for i := 0; i < len(localTLDsAndDotlessDomains); i++ {
|
||||||
|
*matcherInfos = append(*matcherInfos, &DomainMatcherInfo{
|
||||||
|
clientIdx: uint16(0),
|
||||||
|
domainRuleIdx: uint16(0),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Establish domain rules
|
||||||
|
var rules []string
|
||||||
|
ruleCurr := 0
|
||||||
|
ruleIter := 0
|
||||||
|
for _, domain := range ns.PrioritizedDomain {
|
||||||
|
domainRule, err := toStrMatcher(domain.Type, domain.Domain)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("failed to create prioritized domain").Base(err).AtWarning()
|
||||||
|
}
|
||||||
|
originalRuleIdx := ruleCurr
|
||||||
|
if ruleCurr < len(ns.OriginalRules) {
|
||||||
|
rule := ns.OriginalRules[ruleCurr]
|
||||||
|
if ruleCurr >= len(rules) {
|
||||||
|
rules = append(rules, rule.Rule)
|
||||||
|
}
|
||||||
|
ruleIter++
|
||||||
|
if ruleIter >= int(rule.Size) {
|
||||||
|
ruleIter = 0
|
||||||
|
ruleCurr++
|
||||||
|
}
|
||||||
|
} else { // No original rule, generate one according to current domain matcher (majorly for compatibility with tests)
|
||||||
|
rules = append(rules, domainRule.String())
|
||||||
|
ruleCurr++
|
||||||
|
}
|
||||||
|
err = updateDomainRule(domainRule, originalRuleIdx, *matcherInfos)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("failed to create prioritized domain").Base(err).AtWarning()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Establish expected IPs
|
||||||
|
var expectedMatchers []*router.GeoIPMatcher
|
||||||
|
for _, geoip := range ns.ExpectedGeoip {
|
||||||
|
matcher, err := router.GlobalGeoIPContainer.Add(geoip)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("failed to create expected ip matcher").Base(err).AtWarning()
|
||||||
|
}
|
||||||
|
expectedMatchers = append(expectedMatchers, matcher)
|
||||||
|
}
|
||||||
|
|
||||||
// Establish unexpected IPs
|
// Establish unexpected IPs
|
||||||
var unexpectedMatcher geodata.IPMatcher
|
var unexpectedMatchers []*router.GeoIPMatcher
|
||||||
if len(ns.UnexpectedIp) > 0 {
|
for _, geoip := range ns.UnexpectedGeoip {
|
||||||
unexpectedMatcher, err = geodata.IPReg.BuildIPMatcher(ns.UnexpectedIp)
|
matcher, err := router.GlobalGeoIPContainer.Add(geoip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create unexpected ip matcher").Base(err).AtWarning()
|
return errors.New("failed to create unexpected ip matcher").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
unexpectedMatchers = append(unexpectedMatchers, matcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(clientIP) > 0 {
|
if len(clientIP) > 0 {
|
||||||
@@ -135,7 +182,7 @@ func NewClient(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timeoutMs := 4000 * time.Millisecond
|
var timeoutMs = 4000 * time.Millisecond
|
||||||
if ns.TimeoutMs > 0 {
|
if ns.TimeoutMs > 0 {
|
||||||
timeoutMs = time.Duration(ns.TimeoutMs) * time.Millisecond
|
timeoutMs = time.Duration(ns.TimeoutMs) * time.Millisecond
|
||||||
}
|
}
|
||||||
@@ -144,8 +191,9 @@ func NewClient(
|
|||||||
|
|
||||||
client.server = server
|
client.server = server
|
||||||
client.skipFallback = ns.SkipFallback
|
client.skipFallback = ns.SkipFallback
|
||||||
client.expectedIPs = expectedMatcher
|
client.domains = rules
|
||||||
client.unexpectedIPs = unexpectedMatcher
|
client.expectedIPs = expectedMatchers
|
||||||
|
client.unexpectedIPs = unexpectedMatchers
|
||||||
client.actPrior = ns.ActPrior
|
client.actPrior = ns.ActPrior
|
||||||
client.actUnprior = ns.ActUnprior
|
client.actUnprior = ns.ActUnprior
|
||||||
client.tag = tag
|
client.tag = tag
|
||||||
@@ -153,7 +201,6 @@ func NewClient(
|
|||||||
client.finalQuery = ns.FinalQuery
|
client.finalQuery = ns.FinalQuery
|
||||||
client.ipOption = &ipOption
|
client.ipOption = &ipOption
|
||||||
client.checkSystem = checkSystem
|
client.checkSystem = checkSystem
|
||||||
client.policyID = ns.PolicyID
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
return client, err
|
return client, err
|
||||||
@@ -164,10 +211,14 @@ func (c *Client) Name() string {
|
|||||||
return c.server.Name()
|
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.
|
// 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) ([]net.IP, uint32, error) {
|
func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
||||||
if c.checkSystem {
|
if c.checkSystem {
|
||||||
supportIPv4, supportIPv6 := utils.CheckRoutes()
|
supportIPv4, supportIPv6 := checkSystemNetwork()
|
||||||
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
||||||
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
||||||
} else {
|
} else {
|
||||||
@@ -192,32 +243,32 @@ func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption
|
|||||||
return nil, 0, dns.ErrEmptyResponse
|
return nil, 0, dns.ErrEmptyResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.expectedIPs != nil && !c.actPrior {
|
if len(c.expectedIPs) > 0 && !c.actPrior {
|
||||||
ips, _ = c.expectedIPs.FilterIPs(ips)
|
ips = router.MatchIPs(c.expectedIPs, ips, false)
|
||||||
errors.LogDebug(context.Background(), "domain ", domain, " expectedIPs ", ips, " matched at server ", c.Name())
|
errors.LogDebug(context.Background(), "domain ", domain, " expectedIPs ", ips, " matched at server ", c.Name())
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
return nil, 0, dns.ErrEmptyResponse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.unexpectedIPs != nil && !c.actUnprior {
|
if len(c.unexpectedIPs) > 0 && !c.actUnprior {
|
||||||
_, ips = c.unexpectedIPs.FilterIPs(ips)
|
ips = router.MatchIPs(c.unexpectedIPs, ips, true)
|
||||||
errors.LogDebug(context.Background(), "domain ", domain, " unexpectedIPs ", ips, " matched at server ", c.Name())
|
errors.LogDebug(context.Background(), "domain ", domain, " unexpectedIPs ", ips, " matched at server ", c.Name())
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
return nil, 0, dns.ErrEmptyResponse
|
return nil, 0, dns.ErrEmptyResponse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.expectedIPs != nil && c.actPrior {
|
if len(c.expectedIPs) > 0 && c.actPrior {
|
||||||
ipsNew, _ := c.expectedIPs.FilterIPs(ips)
|
ipsNew := router.MatchIPs(c.expectedIPs, ips, false)
|
||||||
if len(ipsNew) > 0 {
|
if len(ipsNew) > 0 {
|
||||||
ips = ipsNew
|
ips = ipsNew
|
||||||
errors.LogDebug(context.Background(), "domain ", domain, " priorIPs ", ips, " matched at server ", c.Name())
|
errors.LogDebug(context.Background(), "domain ", domain, " priorIPs ", ips, " matched at server ", c.Name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.unexpectedIPs != nil && c.actUnprior {
|
if len(c.unexpectedIPs) > 0 && c.actUnprior {
|
||||||
_, ipsNew := c.unexpectedIPs.FilterIPs(ips)
|
ipsNew := router.MatchIPs(c.unexpectedIPs, ips, true)
|
||||||
if len(ipsNew) > 0 {
|
if len(ipsNew) > 0 {
|
||||||
ips = ipsNew
|
ips = ipsNew
|
||||||
errors.LogDebug(context.Background(), "domain ", domain, " unpriorIPs ", ips, " matched at server ", c.Name())
|
errors.LogDebug(context.Background(), "domain ", domain, " unpriorIPs ", ips, " matched at server ", c.Name())
|
||||||
|
|||||||
@@ -1,173 +0,0 @@
|
|||||||
package dns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
go_errors "errors"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/log"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
|
||||||
"github.com/xtls/xray-core/features/dns"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CachedNameserver interface {
|
|
||||||
getCacheController() *CacheController
|
|
||||||
|
|
||||||
sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns.IPOption)
|
|
||||||
}
|
|
||||||
|
|
||||||
// queryIP is called from dns.Server->queryIPTimeout
|
|
||||||
func queryIP(ctx context.Context, s CachedNameserver, domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
|
||||||
fqdn := Fqdn(domain)
|
|
||||||
|
|
||||||
cache := s.getCacheController()
|
|
||||||
if !cache.disableCache {
|
|
||||||
if rec := cache.findRecords(fqdn); rec != nil {
|
|
||||||
ips, ttl, err := merge(option, rec.A, rec.AAAA)
|
|
||||||
if !go_errors.Is(err, errRecordNotFound) {
|
|
||||||
if ttl > 0 {
|
|
||||||
errors.LogDebugInner(ctx, err, cache.name, " cache HIT ", fqdn, " -> ", ips)
|
|
||||||
log.Record(&log.DNSLog{Server: cache.name, Domain: fqdn, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
|
||||||
return ips, uint32(ttl), err
|
|
||||||
}
|
|
||||||
if cache.serveStale && (cache.serveExpiredTTL == 0 || cache.serveExpiredTTL < ttl) {
|
|
||||||
errors.LogDebugInner(ctx, err, cache.name, " cache OPTIMISTE ", fqdn, " -> ", ips)
|
|
||||||
log.Record(&log.DNSLog{Server: cache.name, Domain: fqdn, Result: ips, Status: log.DNSCacheOptimiste, Elapsed: 0, Error: err})
|
|
||||||
go pull(ctx, s, fqdn, option)
|
|
||||||
return ips, 1, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", fqdn, " at ", cache.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fetch(ctx, s, fqdn, option)
|
|
||||||
}
|
|
||||||
|
|
||||||
func pull(ctx context.Context, s CachedNameserver, fqdn string, option dns.IPOption) {
|
|
||||||
nctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 8*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
fetch(nctx, s, fqdn, option)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetch(ctx context.Context, s CachedNameserver, fqdn string, option dns.IPOption) ([]net.IP, uint32, error) {
|
|
||||||
key := fqdn
|
|
||||||
switch {
|
|
||||||
case option.IPv4Enable && option.IPv6Enable:
|
|
||||||
key = key + "46"
|
|
||||||
case option.IPv4Enable:
|
|
||||||
key = key + "4"
|
|
||||||
case option.IPv6Enable:
|
|
||||||
key = key + "6"
|
|
||||||
}
|
|
||||||
|
|
||||||
v, _, _ := s.getCacheController().requestGroup.Do(key, func() (any, error) {
|
|
||||||
return doFetch(ctx, s, fqdn, option), nil
|
|
||||||
})
|
|
||||||
ret := v.(result)
|
|
||||||
|
|
||||||
return ret.ips, ret.ttl, ret.error
|
|
||||||
}
|
|
||||||
|
|
||||||
type result struct {
|
|
||||||
ips []net.IP
|
|
||||||
ttl uint32
|
|
||||||
error
|
|
||||||
}
|
|
||||||
|
|
||||||
func doFetch(ctx context.Context, s CachedNameserver, fqdn string, option dns.IPOption) result {
|
|
||||||
sub4, sub6 := s.getCacheController().registerSubscribers(fqdn, option)
|
|
||||||
defer closeSubscribers(sub4, sub6)
|
|
||||||
|
|
||||||
noResponseErrCh := make(chan error, 2)
|
|
||||||
onEvent := func(sub *pubsub.Subscriber) (*IPRecord, error) {
|
|
||||||
if sub == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, ctx.Err()
|
|
||||||
case err := <-noResponseErrCh:
|
|
||||||
return nil, err
|
|
||||||
case msg := <-sub.Wait():
|
|
||||||
sub.Close()
|
|
||||||
return msg.(*IPRecord), nil // should panic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
start := time.Now()
|
|
||||||
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
|
||||||
|
|
||||||
rec4, err4 := onEvent(sub4)
|
|
||||||
rec6, err6 := onEvent(sub6)
|
|
||||||
|
|
||||||
var errs []error
|
|
||||||
if err4 != nil {
|
|
||||||
errs = append(errs, err4)
|
|
||||||
}
|
|
||||||
if err6 != nil {
|
|
||||||
errs = append(errs, err6)
|
|
||||||
}
|
|
||||||
|
|
||||||
ips, ttl, err := merge(option, rec4, rec6, errs...)
|
|
||||||
var rTTL uint32
|
|
||||||
if ttl > 0 {
|
|
||||||
rTTL = uint32(ttl)
|
|
||||||
} else if ttl == 0 && go_errors.Is(err, errRecordNotFound) {
|
|
||||||
rTTL = 0
|
|
||||||
} else { // edge case: where a fast rep's ttl expires during the rtt of a slower, parallel query
|
|
||||||
rTTL = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Record(&log.DNSLog{Server: s.getCacheController().name, Domain: fqdn, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
|
||||||
return result{ips, rTTL, err}
|
|
||||||
}
|
|
||||||
|
|
||||||
func merge(option dns.IPOption, rec4 *IPRecord, rec6 *IPRecord, errs ...error) ([]net.IP, int32, error) {
|
|
||||||
var allIPs []net.IP
|
|
||||||
var rTTL int32 = dns.DefaultTTL
|
|
||||||
|
|
||||||
mergeReq := option.IPv4Enable && option.IPv6Enable
|
|
||||||
|
|
||||||
if option.IPv4Enable {
|
|
||||||
ips, ttl, err := rec4.getIPs() // it's safe
|
|
||||||
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 := rec6.getIPs() // it's safe
|
|
||||||
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 len(errs) == 2 && go_errors.Is(errs[0], errs[1]) {
|
|
||||||
return nil, rTTL, errs[0]
|
|
||||||
}
|
|
||||||
return nil, rTTL, errors.Combine(errs...)
|
|
||||||
}
|
|
||||||
+64
-57
@@ -4,10 +4,12 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
go_errors "errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
utls "github.com/refraction-networking/utls"
|
utls "github.com/refraction-networking/utls"
|
||||||
@@ -19,7 +21,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/net/cnc"
|
"github.com/xtls/xray-core/common/net/cnc"
|
||||||
"github.com/xtls/xray-core/common/protocol/dns"
|
"github.com/xtls/xray-core/common/protocol/dns"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/common/utils"
|
|
||||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
@@ -37,7 +38,7 @@ type DoHNameServer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewDoHNameServer creates DOH/DOHL client object for remote/local resolving.
|
// NewDoHNameServer creates DOH/DOHL client object for remote/local resolving.
|
||||||
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, h2c bool, disableCache bool, serveStale bool, serveExpiredTTL uint32, clientIP net.IP) *DoHNameServer {
|
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, h2c bool, disableCache bool, clientIP net.IP) *DoHNameServer {
|
||||||
url.Scheme = "https"
|
url.Scheme = "https"
|
||||||
mode := "DOH"
|
mode := "DOH"
|
||||||
if dispatcher == nil {
|
if dispatcher == nil {
|
||||||
@@ -45,7 +46,7 @@ func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, h2c bool, dis
|
|||||||
}
|
}
|
||||||
errors.LogInfo(context.Background(), "DNS: created ", mode, " client for ", url.String(), ", with h2c ", h2c)
|
errors.LogInfo(context.Background(), "DNS: created ", mode, " client for ", url.String(), ", with h2c ", h2c)
|
||||||
s := &DoHNameServer{
|
s := &DoHNameServer{
|
||||||
cacheController: NewCacheController(mode+"//"+url.Host, disableCache, serveStale, serveExpiredTTL),
|
cacheController: NewCacheController(mode+"//"+url.Host, disableCache),
|
||||||
dohURL: url.String(),
|
dohURL: url.String(),
|
||||||
clientIP: clientIP,
|
clientIP: clientIP,
|
||||||
}
|
}
|
||||||
@@ -116,53 +117,22 @@ func (s *DoHNameServer) Name() string {
|
|||||||
return s.cacheController.name
|
return s.cacheController.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDisableCache implements Server.
|
|
||||||
func (s *DoHNameServer) IsDisableCache() bool {
|
|
||||||
return s.cacheController.disableCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DoHNameServer) newReqID() uint16 {
|
func (s *DoHNameServer) newReqID() uint16 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCacheController implements CachedNameserver.
|
func (s *DoHNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
||||||
func (s *DoHNameServer) getCacheController() *CacheController {
|
errors.LogInfo(ctx, s.Name(), " querying: ", domain)
|
||||||
return s.cacheController
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendQuery implements CachedNameserver.
|
if s.Name()+"." == "DOH//"+domain {
|
||||||
func (s *DoHNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
errors.LogError(ctx, s.Name(), " tries to resolve itself! Use IP or set \"hosts\" instead.")
|
||||||
errors.LogInfo(ctx, s.Name(), " querying: ", fqdn)
|
noResponseErrCh <- errors.New("tries to resolve itself!", s.Name())
|
||||||
|
|
||||||
if s.Name()+"." == "DOH//"+fqdn {
|
|
||||||
errors.LogError(ctx, s.Name(), " tries to resolve itself! Use IP or set \"hosts\" instead")
|
|
||||||
if noResponseErrCh != nil {
|
|
||||||
err := errors.New("tries to resolve itself!", s.Name())
|
|
||||||
if option.IPv4Enable {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
if option.IPv6Enable {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
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
|
// 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
|
// 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, err := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, int(crypto.RandBetween(100, 300))))
|
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, int(crypto.RandBetween(100, 300))))
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to build dns query for ", fqdn)
|
|
||||||
if noResponseErrCh != nil {
|
|
||||||
if option.IPv4Enable {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
if option.IPv6Enable {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
@@ -196,29 +166,23 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- er
|
|||||||
|
|
||||||
b, err := dns.PackMessage(r.msg)
|
b, err := dns.PackMessage(r.msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to pack dns query for ", fqdn)
|
errors.LogErrorInner(ctx, err, "failed to pack dns query for ", domain)
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resp, err := s.dohHTTPSContext(dnsCtx, b.Bytes())
|
resp, err := s.dohHTTPSContext(dnsCtx, b.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to retrieve response for ", fqdn)
|
errors.LogErrorInner(ctx, err, "failed to retrieve response for ", domain)
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rec, err := parseResponse(resp)
|
rec, err := parseResponse(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to handle DOH response for ", fqdn)
|
errors.LogErrorInner(ctx, err, "failed to handle DOH response for ", domain)
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.cacheController.updateRecord(r, rec)
|
s.cacheController.updateIP(r, rec)
|
||||||
}(req)
|
}(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,8 +196,8 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
|
|||||||
|
|
||||||
req.Header.Add("Accept", "application/dns-message")
|
req.Header.Add("Accept", "application/dns-message")
|
||||||
req.Header.Add("Content-Type", "application/dns-message")
|
req.Header.Add("Content-Type", "application/dns-message")
|
||||||
utils.TryDefaultHeadersWith(req.Header, "fetch")
|
|
||||||
req.Header.Set("X-Padding", utils.H2Base62Pad(crypto.RandBetween(100, 1000)))
|
req.Header.Set("X-Padding", strings.Repeat("X", int(crypto.RandBetween(100, 1000))))
|
||||||
|
|
||||||
hc := s.httpClient
|
hc := s.httpClient
|
||||||
|
|
||||||
@@ -252,6 +216,49 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// QueryIP implements Server.
|
// QueryIP implements Server.
|
||||||
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) { // nolint: dupl
|
||||||
return queryIP(ctx, s, domain, option)
|
fqdn := Fqdn(domain)
|
||||||
|
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
||||||
|
defer closeSubscribers(sub4, sub6)
|
||||||
|
|
||||||
|
if s.cacheController.disableCache {
|
||||||
|
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
noResponseErrCh := make(chan error, 2)
|
||||||
|
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
if sub4 != nil {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, 0, ctx.Err()
|
||||||
|
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,7 +17,7 @@ func TestDOHNameServer(t *testing.T) {
|
|||||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
s := NewDoHNameServer(url, nil, false, false, false, 0, net.IP(nil))
|
s := NewDoHNameServer(url, nil, false, false, net.IP(nil))
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
@@ -34,7 +34,7 @@ func TestDOHNameServerWithCache(t *testing.T) {
|
|||||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
s := NewDoHNameServer(url, nil, false, false, false, 0, net.IP(nil))
|
s := NewDoHNameServer(url, nil, false, false, net.IP(nil))
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
@@ -62,7 +62,7 @@ func TestDOHNameServerWithIPv4Override(t *testing.T) {
|
|||||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
s := NewDoHNameServer(url, nil, false, false, false, 0, net.IP(nil))
|
s := NewDoHNameServer(url, nil, false, false, net.IP(nil))
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||||
IPv4Enable: true,
|
IPv4Enable: true,
|
||||||
@@ -85,7 +85,7 @@ func TestDOHNameServerWithIPv6Override(t *testing.T) {
|
|||||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
s := NewDoHNameServer(url, nil, false, false, false, 0, net.IP(nil))
|
s := NewDoHNameServer(url, nil, false, false, net.IP(nil))
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||||
IPv4Enable: false,
|
IPv4Enable: false,
|
||||||
|
|||||||
@@ -20,11 +20,6 @@ func (FakeDNSServer) Name() string {
|
|||||||
return "FakeDNS"
|
return "FakeDNS"
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDisableCache implements Server.
|
|
||||||
func (s *FakeDNSServer) IsDisableCache() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, opt dns.IPOption) ([]net.IP, uint32, error) {
|
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, opt dns.IPOption) ([]net.IP, uint32, error) {
|
||||||
if f.fakeDNSEngine == nil {
|
if f.fakeDNSEngine == nil {
|
||||||
return nil, 0, errors.New("Unable to locate a fake DNS Engine").AtError()
|
return nil, 0, errors.New("Unable to locate a fake DNS Engine").AtError()
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ type LocalNameServer struct {
|
|||||||
|
|
||||||
// QueryIP implements Server.
|
// QueryIP implements Server.
|
||||||
func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, option dns.IPOption) (ips []net.IP, ttl uint32, err error) {
|
func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, option dns.IPOption) (ips []net.IP, ttl uint32, err error) {
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
ips, ttl, err = s.client.LookupIP(domain, option)
|
ips, ttl, err = s.client.LookupIP(domain, option)
|
||||||
|
|
||||||
@@ -34,11 +35,6 @@ func (s *LocalNameServer) Name() string {
|
|||||||
return "localhost"
|
return "localhost"
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDisableCache implements Server.
|
|
||||||
func (s *LocalNameServer) IsDisableCache() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLocalNameServer creates localdns server object for directly lookup in system DNS.
|
// NewLocalNameServer creates localdns server object for directly lookup in system DNS.
|
||||||
func NewLocalNameServer() *LocalNameServer {
|
func NewLocalNameServer() *LocalNameServer {
|
||||||
errors.LogInfo(context.Background(), "DNS: created localhost client")
|
errors.LogInfo(context.Background(), "DNS: created localhost client")
|
||||||
|
|||||||
+66
-60
@@ -4,11 +4,12 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
go_errors "errors"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/apernet/quic-go"
|
"github.com/quic-go/quic-go"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/log"
|
"github.com/xtls/xray-core/common/log"
|
||||||
@@ -36,7 +37,9 @@ type QUICNameServer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewQUICNameServer creates DNS-over-QUIC client object for local resolving
|
// NewQUICNameServer creates DNS-over-QUIC client object for local resolving
|
||||||
func NewQUICNameServer(url *url.URL, disableCache bool, serveStale bool, serveExpiredTTL uint32, clientIP net.IP) (*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
|
var err error
|
||||||
port := net.Port(853)
|
port := net.Port(853)
|
||||||
if url.Port() != "" {
|
if url.Port() != "" {
|
||||||
@@ -48,49 +51,27 @@ func NewQUICNameServer(url *url.URL, disableCache bool, serveStale bool, serveEx
|
|||||||
dest := net.UDPDestination(net.ParseAddress(url.Hostname()), port)
|
dest := net.UDPDestination(net.ParseAddress(url.Hostname()), port)
|
||||||
|
|
||||||
s := &QUICNameServer{
|
s := &QUICNameServer{
|
||||||
cacheController: NewCacheController(url.String(), disableCache, serveStale, serveExpiredTTL),
|
cacheController: NewCacheController(url.String(), disableCache),
|
||||||
destination: &dest,
|
destination: &dest,
|
||||||
clientIP: clientIP,
|
clientIP: clientIP,
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogInfo(context.Background(), "DNS: created Local DNS-over-QUIC client for ", url.String())
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name implements Server.
|
// Name returns client name
|
||||||
func (s *QUICNameServer) Name() string {
|
func (s *QUICNameServer) Name() string {
|
||||||
return s.cacheController.name
|
return s.cacheController.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDisableCache implements Server.
|
|
||||||
func (s *QUICNameServer) IsDisableCache() bool {
|
|
||||||
return s.cacheController.disableCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *QUICNameServer) newReqID() uint16 {
|
func (s *QUICNameServer) newReqID() uint16 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCacheController implements CachedNameServer.
|
func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
||||||
func (s *QUICNameServer) getCacheController() *CacheController { return s.cacheController }
|
errors.LogInfo(ctx, s.Name(), " querying: ", domain)
|
||||||
|
|
||||||
// sendQuery implements CachedNameServer.
|
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||||
func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
|
||||||
errors.LogInfo(ctx, s.Name(), " querying: ", fqdn)
|
|
||||||
|
|
||||||
reqs, err := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to build dns query for ", fqdn)
|
|
||||||
if noResponseErrCh != nil {
|
|
||||||
if option.IPv4Enable {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
if option.IPv6Enable {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
@@ -122,9 +103,7 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- e
|
|||||||
b, err := dns.PackMessage(r.msg)
|
b, err := dns.PackMessage(r.msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,17 +111,13 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- e
|
|||||||
err = binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
err = binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "binary write failed")
|
errors.LogErrorInner(ctx, err, "binary write failed")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = dnsReqBuf.Write(b.Bytes())
|
_, err = dnsReqBuf.Write(b.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "buffer write failed")
|
errors.LogErrorInner(ctx, err, "buffer write failed")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b.Release()
|
b.Release()
|
||||||
@@ -150,18 +125,14 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- e
|
|||||||
conn, err := s.openStream(dnsCtx)
|
conn, err := s.openStream(dnsCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to open quic connection")
|
errors.LogErrorInner(ctx, err, "failed to open quic connection")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = conn.Write(dnsReqBuf.Bytes())
|
_, err = conn.Write(dnsReqBuf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to send query")
|
errors.LogErrorInner(ctx, err, "failed to send query")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,46 +143,81 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- e
|
|||||||
n, err := respBuf.ReadFullFrom(conn, 2)
|
n, err := respBuf.ReadFullFrom(conn, 2)
|
||||||
if err != nil && n == 0 {
|
if err != nil && n == 0 {
|
||||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var length uint16
|
var length int16
|
||||||
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
|
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
respBuf.Clear()
|
respBuf.Clear()
|
||||||
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
||||||
if err != nil && n == 0 {
|
if err != nil && n == 0 {
|
||||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rec, err := parseResponse(respBuf.Bytes())
|
rec, err := parseResponse(respBuf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to handle response")
|
errors.LogErrorInner(ctx, err, "failed to handle response")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.cacheController.updateRecord(r, rec)
|
s.cacheController.updateIP(r, rec)
|
||||||
}(req)
|
}(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryIP implements Server.
|
// QueryIP is called from dns.Server->queryIPTimeout
|
||||||
func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||||
return queryIP(ctx, s, domain, option)
|
fqdn := Fqdn(domain)
|
||||||
|
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
||||||
|
defer closeSubscribers(sub4, sub6)
|
||||||
|
|
||||||
|
if s.cacheController.disableCache {
|
||||||
|
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
noResponseErrCh := make(chan error, 2)
|
||||||
|
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
if sub4 != nil {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, 0, ctx.Err()
|
||||||
|
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.Conn) bool {
|
func isActive(s *quic.Conn) bool {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
func TestQUICNameServer(t *testing.T) {
|
func TestQUICNameServer(t *testing.T) {
|
||||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
url, err := url.Parse("quic://dns.adguard-dns.com")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
s, err := NewQUICNameServer(url, false, false, 0, net.IP(nil))
|
s, err := NewQUICNameServer(url, false, net.IP(nil))
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns.IPOption{
|
ips, _, err := s.QueryIP(ctx, "google.com", dns.IPOption{
|
||||||
@@ -43,7 +43,7 @@ func TestQUICNameServer(t *testing.T) {
|
|||||||
func TestQUICNameServerWithIPv4Override(t *testing.T) {
|
func TestQUICNameServerWithIPv4Override(t *testing.T) {
|
||||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
url, err := url.Parse("quic://dns.adguard-dns.com")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
s, err := NewQUICNameServer(url, false, false, 0, net.IP(nil))
|
s, err := NewQUICNameServer(url, false, net.IP(nil))
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns.IPOption{
|
ips, _, err := s.QueryIP(ctx, "google.com", dns.IPOption{
|
||||||
@@ -66,7 +66,7 @@ func TestQUICNameServerWithIPv4Override(t *testing.T) {
|
|||||||
func TestQUICNameServerWithIPv6Override(t *testing.T) {
|
func TestQUICNameServerWithIPv6Override(t *testing.T) {
|
||||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
url, err := url.Parse("quic://dns.adguard-dns.com")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
s, err := NewQUICNameServer(url, false, false, 0, net.IP(nil))
|
s, err := NewQUICNameServer(url, false, net.IP(nil))
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns.IPOption{
|
ips, _, err := s.QueryIP(ctx, "google.com", dns.IPOption{
|
||||||
|
|||||||
+66
-64
@@ -4,12 +4,14 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
go_errors "errors"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/common/log"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/net/cnc"
|
"github.com/xtls/xray-core/common/net/cnc"
|
||||||
"github.com/xtls/xray-core/common/protocol/dns"
|
"github.com/xtls/xray-core/common/protocol/dns"
|
||||||
@@ -32,10 +34,10 @@ type TCPNameServer struct {
|
|||||||
func NewTCPNameServer(
|
func NewTCPNameServer(
|
||||||
url *url.URL,
|
url *url.URL,
|
||||||
dispatcher routing.Dispatcher,
|
dispatcher routing.Dispatcher,
|
||||||
disableCache bool, serveStale bool, serveExpiredTTL uint32,
|
disableCache bool,
|
||||||
clientIP net.IP,
|
clientIP net.IP,
|
||||||
) (*TCPNameServer, error) {
|
) (*TCPNameServer, error) {
|
||||||
s, err := baseTCPNameServer(url, "TCP", disableCache, serveStale, serveExpiredTTL, clientIP)
|
s, err := baseTCPNameServer(url, "TCP", disableCache, clientIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -52,13 +54,12 @@ func NewTCPNameServer(
|
|||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogInfo(context.Background(), "DNS: created TCP client initialized for ", url.String())
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTCPLocalNameServer creates DNS over TCP client object for local resolving
|
// NewTCPLocalNameServer creates DNS over TCP client object for local resolving
|
||||||
func NewTCPLocalNameServer(url *url.URL, disableCache bool, serveStale bool, serveExpiredTTL uint32, clientIP net.IP) (*TCPNameServer, error) {
|
func NewTCPLocalNameServer(url *url.URL, disableCache bool, clientIP net.IP) (*TCPNameServer, error) {
|
||||||
s, err := baseTCPNameServer(url, "TCPL", disableCache, serveStale, serveExpiredTTL, clientIP)
|
s, err := baseTCPNameServer(url, "TCPL", disableCache, clientIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -67,11 +68,10 @@ func NewTCPLocalNameServer(url *url.URL, disableCache bool, serveStale bool, ser
|
|||||||
return internet.DialSystem(ctx, *s.destination, nil)
|
return internet.DialSystem(ctx, *s.destination, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogInfo(context.Background(), "DNS: created Local TCP client initialized for ", url.String())
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func baseTCPNameServer(url *url.URL, prefix string, disableCache bool, serveStale bool, serveExpiredTTL uint32, clientIP net.IP) (*TCPNameServer, error) {
|
func baseTCPNameServer(url *url.URL, prefix string, disableCache bool, clientIP net.IP) (*TCPNameServer, error) {
|
||||||
port := net.Port(53)
|
port := net.Port(53)
|
||||||
if url.Port() != "" {
|
if url.Port() != "" {
|
||||||
var err error
|
var err error
|
||||||
@@ -82,7 +82,7 @@ func baseTCPNameServer(url *url.URL, prefix string, disableCache bool, serveStal
|
|||||||
dest := net.TCPDestination(net.ParseAddress(url.Hostname()), port)
|
dest := net.TCPDestination(net.ParseAddress(url.Hostname()), port)
|
||||||
|
|
||||||
s := &TCPNameServer{
|
s := &TCPNameServer{
|
||||||
cacheController: NewCacheController(prefix+"//"+dest.NetAddr(), disableCache, serveStale, serveExpiredTTL),
|
cacheController: NewCacheController(prefix+"//"+dest.NetAddr(), disableCache),
|
||||||
destination: &dest,
|
destination: &dest,
|
||||||
clientIP: clientIP,
|
clientIP: clientIP,
|
||||||
}
|
}
|
||||||
@@ -95,37 +95,14 @@ func (s *TCPNameServer) Name() string {
|
|||||||
return s.cacheController.name
|
return s.cacheController.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDisableCache implements Server.
|
|
||||||
func (s *TCPNameServer) IsDisableCache() bool {
|
|
||||||
return s.cacheController.disableCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *TCPNameServer) newReqID() uint16 {
|
func (s *TCPNameServer) newReqID() uint16 {
|
||||||
return uint16(atomic.AddUint32(&s.reqID, 1))
|
return uint16(atomic.AddUint32(&s.reqID, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCacheController implements CachedNameserver.
|
func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
||||||
func (s *TCPNameServer) getCacheController() *CacheController {
|
errors.LogDebug(ctx, s.Name(), " querying DNS for: ", domain)
|
||||||
return s.cacheController
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendQuery implements CachedNameserver.
|
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||||
func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
|
||||||
errors.LogInfo(ctx, s.Name(), " querying DNS for: ", fqdn)
|
|
||||||
|
|
||||||
reqs, err := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to build dns query for ", fqdn)
|
|
||||||
if noResponseErrCh != nil {
|
|
||||||
if option.IPv4Enable {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
if option.IPv6Enable {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
@@ -154,18 +131,14 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- er
|
|||||||
b, err := dns.PackMessage(r.msg)
|
b, err := dns.PackMessage(r.msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := s.dial(dnsCtx)
|
conn, err := s.dial(dnsCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to dial namesever")
|
errors.LogErrorInner(ctx, err, "failed to dial namesever")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
@@ -173,17 +146,13 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- er
|
|||||||
err = binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
err = binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "binary write failed")
|
errors.LogErrorInner(ctx, err, "binary write failed")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = dnsReqBuf.Write(b.Bytes())
|
_, err = dnsReqBuf.Write(b.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "buffer write failed")
|
errors.LogErrorInner(ctx, err, "buffer write failed")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b.Release()
|
b.Release()
|
||||||
@@ -191,9 +160,7 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- er
|
|||||||
_, err = conn.Write(dnsReqBuf.Bytes())
|
_, err = conn.Write(dnsReqBuf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to send query")
|
errors.LogErrorInner(ctx, err, "failed to send query")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dnsReqBuf.Release()
|
dnsReqBuf.Release()
|
||||||
@@ -203,45 +170,80 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- er
|
|||||||
n, err := respBuf.ReadFullFrom(conn, 2)
|
n, err := respBuf.ReadFullFrom(conn, 2)
|
||||||
if err != nil && n == 0 {
|
if err != nil && n == 0 {
|
||||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var length uint16
|
var length int16
|
||||||
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
|
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
respBuf.Clear()
|
respBuf.Clear()
|
||||||
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
||||||
if err != nil && n == 0 {
|
if err != nil && n == 0 {
|
||||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rec, err := parseResponse(respBuf.Bytes())
|
rec, err := parseResponse(respBuf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, "failed to parse DNS over TCP response")
|
errors.LogErrorInner(ctx, err, "failed to parse DNS over TCP response")
|
||||||
if noResponseErrCh != nil {
|
noResponseErrCh <- err
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cacheController.updateRecord(r, rec)
|
s.cacheController.updateIP(r, rec)
|
||||||
}(req)
|
}(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryIP implements Server.
|
// QueryIP implements Server.
|
||||||
func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||||
return queryIP(ctx, s, domain, option)
|
fqdn := Fqdn(domain)
|
||||||
|
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
||||||
|
defer closeSubscribers(sub4, sub6)
|
||||||
|
|
||||||
|
if s.cacheController.disableCache {
|
||||||
|
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
noResponseErrCh := make(chan error, 2)
|
||||||
|
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
if sub4 != nil {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, 0, ctx.Err()
|
||||||
|
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,7 +16,7 @@ import (
|
|||||||
func TestTCPLocalNameServer(t *testing.T) {
|
func TestTCPLocalNameServer(t *testing.T) {
|
||||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
s, err := NewTCPLocalNameServer(url, false, false, 0, net.IP(nil))
|
s, err := NewTCPLocalNameServer(url, false, net.IP(nil))
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||||
@@ -33,7 +33,7 @@ func TestTCPLocalNameServer(t *testing.T) {
|
|||||||
func TestTCPLocalNameServerWithCache(t *testing.T) {
|
func TestTCPLocalNameServerWithCache(t *testing.T) {
|
||||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
s, err := NewTCPLocalNameServer(url, false, false, 0, net.IP(nil))
|
s, err := NewTCPLocalNameServer(url, false, net.IP(nil))
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||||
@@ -61,7 +61,7 @@ func TestTCPLocalNameServerWithCache(t *testing.T) {
|
|||||||
func TestTCPLocalNameServerWithIPv4Override(t *testing.T) {
|
func TestTCPLocalNameServerWithIPv4Override(t *testing.T) {
|
||||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
s, err := NewTCPLocalNameServer(url, false, false, 0, net.IP(nil))
|
s, err := NewTCPLocalNameServer(url, false, net.IP(nil))
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||||
@@ -85,7 +85,7 @@ func TestTCPLocalNameServerWithIPv4Override(t *testing.T) {
|
|||||||
func TestTCPLocalNameServerWithIPv6Override(t *testing.T) {
|
func TestTCPLocalNameServerWithIPv6Override(t *testing.T) {
|
||||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
s, err := NewTCPLocalNameServer(url, false, false, 0, net.IP(nil))
|
s, err := NewTCPLocalNameServer(url, false, net.IP(nil))
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||||
|
|||||||
+59
-41
@@ -2,6 +2,7 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
go_errors "errors"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -9,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/common/log"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol/dns"
|
"github.com/xtls/xray-core/common/protocol/dns"
|
||||||
udp_proto "github.com/xtls/xray-core/common/protocol/udp"
|
udp_proto "github.com/xtls/xray-core/common/protocol/udp"
|
||||||
@@ -37,14 +39,14 @@ type udpDnsRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewClassicNameServer creates udp server object for remote resolving.
|
// NewClassicNameServer creates udp server object for remote resolving.
|
||||||
func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher, disableCache bool, serveStale bool, serveExpiredTTL uint32, clientIP net.IP) *ClassicNameServer {
|
func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher, disableCache bool, clientIP net.IP) *ClassicNameServer {
|
||||||
// default to 53 if unspecific
|
// default to 53 if unspecific
|
||||||
if address.Port == 0 {
|
if address.Port == 0 {
|
||||||
address.Port = net.Port(53)
|
address.Port = net.Port(53)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := &ClassicNameServer{
|
s := &ClassicNameServer{
|
||||||
cacheController: NewCacheController(strings.ToUpper(address.String()), disableCache, serveStale, serveExpiredTTL),
|
cacheController: NewCacheController(strings.ToUpper(address.String()), disableCache),
|
||||||
address: &address,
|
address: &address,
|
||||||
requests: make(map[uint16]*udpDnsRequest),
|
requests: make(map[uint16]*udpDnsRequest),
|
||||||
clientIP: clientIP,
|
clientIP: clientIP,
|
||||||
@@ -54,7 +56,6 @@ func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher
|
|||||||
Execute: s.RequestsCleanup,
|
Execute: s.RequestsCleanup,
|
||||||
}
|
}
|
||||||
s.udpServer = udp.NewDispatcher(dispatcher, s.HandleResponse)
|
s.udpServer = udp.NewDispatcher(dispatcher, s.HandleResponse)
|
||||||
|
|
||||||
errors.LogInfo(context.Background(), "DNS: created UDP client initialized for ", address.NetAddr())
|
errors.LogInfo(context.Background(), "DNS: created UDP client initialized for ", address.NetAddr())
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
@@ -64,11 +65,6 @@ func (s *ClassicNameServer) Name() string {
|
|||||||
return s.cacheController.name
|
return s.cacheController.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDisableCache implements Server.
|
|
||||||
func (s *ClassicNameServer) IsDisableCache() bool {
|
|
||||||
return s.cacheController.disableCache
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestsCleanup clears expired items from cache
|
// RequestsCleanup clears expired items from cache
|
||||||
func (s *ClassicNameServer) RequestsCleanup() error {
|
func (s *ClassicNameServer) RequestsCleanup() error {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
@@ -98,7 +94,7 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
|||||||
ipRec, err := parseResponse(payload.Bytes())
|
ipRec, err := parseResponse(payload.Bytes())
|
||||||
payload.Release()
|
payload.Release()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(ctx, err, s.Name(), " fail to parse responded DNS udp")
|
errors.LogError(ctx, s.Name(), " fail to parse responded DNS udp")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +107,7 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
|||||||
}
|
}
|
||||||
s.Unlock()
|
s.Unlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
errors.LogErrorInner(ctx, err, s.Name(), " cannot find the pending request")
|
errors.LogError(ctx, s.Name(), " cannot find the pending request")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,12 +127,14 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
|||||||
newReq.msg = &newMsg
|
newReq.msg = &newMsg
|
||||||
s.addPendingRequest(&newReq)
|
s.addPendingRequest(&newReq)
|
||||||
b, _ := dns.PackMessage(newReq.msg)
|
b, _ := dns.PackMessage(newReq.msg)
|
||||||
|
copyDest := net.UDPDestination(s.address.Address, s.address.Port)
|
||||||
|
b.UDP = ©Dest
|
||||||
s.udpServer.Dispatch(toDnsContext(newReq.ctx, s.address.String()), *s.address, b)
|
s.udpServer.Dispatch(toDnsContext(newReq.ctx, s.address.String()), *s.address, b)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cacheController.updateRecord(&req.dnsRequest, ipRec)
|
s.cacheController.updateIP(&req.dnsRequest, ipRec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ClassicNameServer) newReqID() uint16 {
|
func (s *ClassicNameServer) newReqID() uint16 {
|
||||||
@@ -152,28 +150,10 @@ func (s *ClassicNameServer) addPendingRequest(req *udpDnsRequest) {
|
|||||||
common.Must(s.requestsCleanup.Start())
|
common.Must(s.requestsCleanup.Start())
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCacheController implements CachedNameserver.
|
func (s *ClassicNameServer) sendQuery(ctx context.Context, _ chan<- error, domain string, option dns_feature.IPOption) {
|
||||||
func (s *ClassicNameServer) getCacheController() *CacheController {
|
errors.LogDebug(ctx, s.Name(), " querying DNS for: ", domain)
|
||||||
return s.cacheController
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendQuery implements CachedNameserver.
|
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||||
func (s *ClassicNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
|
||||||
errors.LogInfo(ctx, s.Name(), " querying DNS for: ", fqdn)
|
|
||||||
|
|
||||||
reqs, err := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(ctx, err, "failed to build dns query for ", fqdn)
|
|
||||||
if noResponseErrCh != nil {
|
|
||||||
if option.IPv4Enable {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
if option.IPv6Enable {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, req := range reqs {
|
for _, req := range reqs {
|
||||||
udpReq := &udpDnsRequest{
|
udpReq := &udpDnsRequest{
|
||||||
@@ -181,19 +161,57 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<
|
|||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
s.addPendingRequest(udpReq)
|
s.addPendingRequest(udpReq)
|
||||||
b, err := dns.PackMessage(req.msg)
|
b, _ := dns.PackMessage(req.msg)
|
||||||
if err != nil {
|
copyDest := net.UDPDestination(s.address.Address, s.address.Port)
|
||||||
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
b.UDP = ©Dest
|
||||||
if noResponseErrCh != nil {
|
|
||||||
noResponseErrCh <- err
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b)
|
s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryIP implements Server.
|
// QueryIP implements Server.
|
||||||
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||||
return queryIP(ctx, s, domain, option)
|
fqdn := Fqdn(domain)
|
||||||
|
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
||||||
|
defer closeSubscribers(sub4, sub6)
|
||||||
|
|
||||||
|
if s.cacheController.disableCache {
|
||||||
|
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
noResponseErrCh := make(chan error, 2)
|
||||||
|
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
if sub4 != nil {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, 0, ctx.Err()
|
||||||
|
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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,198 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.36.11
|
|
||||||
// protoc v6.33.5
|
|
||||||
// source: app/geodata/config.proto
|
|
||||||
|
|
||||||
package geodata
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
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 Asset struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
|
|
||||||
File string `protobuf:"bytes,2,opt,name=file,proto3" json:"file,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Asset) Reset() {
|
|
||||||
*x = Asset{}
|
|
||||||
mi := &file_app_geodata_config_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Asset) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Asset) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Asset) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_geodata_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 Asset.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Asset) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_geodata_config_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Asset) GetUrl() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Url
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Asset) GetFile() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.File
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Cron string `protobuf:"bytes,1,opt,name=cron,proto3" json:"cron,omitempty"`
|
|
||||||
Outbound string `protobuf:"bytes,2,opt,name=outbound,proto3" json:"outbound,omitempty"`
|
|
||||||
Assets []*Asset `protobuf:"bytes,3,rep,name=assets,proto3" json:"assets,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
|
||||||
*x = Config{}
|
|
||||||
mi := &file_app_geodata_config_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Config) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_geodata_config_proto_msgTypes[1]
|
|
||||||
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_geodata_config_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetCron() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Cron
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetOutbound() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Outbound
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetAssets() []*Asset {
|
|
||||||
if x != nil {
|
|
||||||
return x.Assets
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_app_geodata_config_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
const file_app_geodata_config_proto_rawDesc = "" +
|
|
||||||
"\n" +
|
|
||||||
"\x18app/geodata/config.proto\x12\x10xray.app.geodata\"-\n" +
|
|
||||||
"\x05Asset\x12\x10\n" +
|
|
||||||
"\x03url\x18\x01 \x01(\tR\x03url\x12\x12\n" +
|
|
||||||
"\x04file\x18\x02 \x01(\tR\x04file\"i\n" +
|
|
||||||
"\x06Config\x12\x12\n" +
|
|
||||||
"\x04cron\x18\x01 \x01(\tR\x04cron\x12\x1a\n" +
|
|
||||||
"\boutbound\x18\x02 \x01(\tR\boutbound\x12/\n" +
|
|
||||||
"\x06assets\x18\x03 \x03(\v2\x17.xray.app.geodata.AssetR\x06assetsBR\n" +
|
|
||||||
"\x14com.xray.app.geodataP\x01Z%github.com/xtls/xray-core/app/geodata\xaa\x02\x10Xray.App.Geodatab\x06proto3"
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_app_geodata_config_proto_rawDescOnce sync.Once
|
|
||||||
file_app_geodata_config_proto_rawDescData []byte
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_app_geodata_config_proto_rawDescGZIP() []byte {
|
|
||||||
file_app_geodata_config_proto_rawDescOnce.Do(func() {
|
|
||||||
file_app_geodata_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_geodata_config_proto_rawDesc), len(file_app_geodata_config_proto_rawDesc)))
|
|
||||||
})
|
|
||||||
return file_app_geodata_config_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_app_geodata_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
|
||||||
var file_app_geodata_config_proto_goTypes = []any{
|
|
||||||
(*Asset)(nil), // 0: xray.app.geodata.Asset
|
|
||||||
(*Config)(nil), // 1: xray.app.geodata.Config
|
|
||||||
}
|
|
||||||
var file_app_geodata_config_proto_depIdxs = []int32{
|
|
||||||
0, // 0: xray.app.geodata.Config.assets:type_name -> xray.app.geodata.Asset
|
|
||||||
1, // [1:1] is the sub-list for method output_type
|
|
||||||
1, // [1:1] is the sub-list for method input_type
|
|
||||||
1, // [1:1] is the sub-list for extension type_name
|
|
||||||
1, // [1:1] is the sub-list for extension extendee
|
|
||||||
0, // [0:1] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_app_geodata_config_proto_init() }
|
|
||||||
func file_app_geodata_config_proto_init() {
|
|
||||||
if File_app_geodata_config_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_geodata_config_proto_rawDesc), len(file_app_geodata_config_proto_rawDesc)),
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 2,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_app_geodata_config_proto_goTypes,
|
|
||||||
DependencyIndexes: file_app_geodata_config_proto_depIdxs,
|
|
||||||
MessageInfos: file_app_geodata_config_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_app_geodata_config_proto = out.File
|
|
||||||
file_app_geodata_config_proto_goTypes = nil
|
|
||||||
file_app_geodata_config_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package xray.app.geodata;
|
|
||||||
option csharp_namespace = "Xray.App.Geodata";
|
|
||||||
option go_package = "github.com/xtls/xray-core/app/geodata";
|
|
||||||
option java_package = "com.xray.app.geodata";
|
|
||||||
option java_multiple_files = true;
|
|
||||||
|
|
||||||
message Asset {
|
|
||||||
string url = 1;
|
|
||||||
|
|
||||||
string file = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Config {
|
|
||||||
string cron = 1;
|
|
||||||
|
|
||||||
string outbound = 2;
|
|
||||||
|
|
||||||
repeated Asset assets = 3;
|
|
||||||
}
|
|
||||||
@@ -1,346 +0,0 @@
|
|||||||
package geodata
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
go_errors "errors"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
utls "github.com/refraction-networking/utls"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
|
||||||
"github.com/xtls/xray-core/common/task"
|
|
||||||
"github.com/xtls/xray-core/common/utils"
|
|
||||||
"github.com/xtls/xray-core/features/routing"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/tagged"
|
|
||||||
"golang.org/x/net/http2"
|
|
||||||
)
|
|
||||||
|
|
||||||
const idleTimeout = 30 * time.Second
|
|
||||||
|
|
||||||
type stage struct {
|
|
||||||
target string
|
|
||||||
temp string
|
|
||||||
}
|
|
||||||
|
|
||||||
type downloader struct {
|
|
||||||
ctx context.Context
|
|
||||||
httpClient *http.Client
|
|
||||||
httpsClient *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
type idleConn struct {
|
|
||||||
net.Conn
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *idleConn) Read(b []byte) (int, error) {
|
|
||||||
t := time.AfterFunc(idleTimeout, func() {
|
|
||||||
_ = c.Close()
|
|
||||||
})
|
|
||||||
|
|
||||||
n, err := c.Conn.Read(b)
|
|
||||||
if !t.Stop() {
|
|
||||||
_ = c.Close()
|
|
||||||
return n, errors.New("connection idle timeout")
|
|
||||||
}
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *idleConn) Write(b []byte) (int, error) {
|
|
||||||
return c.Conn.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newDownloader(ctx context.Context, dispatcher routing.Dispatcher, outbound string) *downloader {
|
|
||||||
return &downloader{
|
|
||||||
ctx: ctx,
|
|
||||||
httpClient: newClient(ctx, dispatcher, outbound, false),
|
|
||||||
httpsClient: newClient(ctx, dispatcher, outbound, true),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newClient(baseCtx context.Context, dispatcher routing.Dispatcher, outbound string, isHTTPS bool) *http.Client {
|
|
||||||
dial := func(ctx context.Context, network, address string) (net.Conn, error) {
|
|
||||||
var conn net.Conn
|
|
||||||
err := task.Run(ctx, func() error {
|
|
||||||
if tagged.Dialer == nil {
|
|
||||||
return errors.New("tagged dialer is not initialized")
|
|
||||||
}
|
|
||||||
dest, err := net.ParseDestination(network + ":" + address)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("cannot understand address").Base(err)
|
|
||||||
}
|
|
||||||
c, err := tagged.Dialer(baseCtx, dispatcher, dest, outbound)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("cannot dial remote address ", dest).Base(err)
|
|
||||||
}
|
|
||||||
conn = c
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("cannot finish connection").Base(err)
|
|
||||||
}
|
|
||||||
return &idleConn{
|
|
||||||
Conn: conn,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
if isHTTPS {
|
|
||||||
return &http.Client{
|
|
||||||
Transport: &http2.Transport{
|
|
||||||
DialTLSContext: func(ctx context.Context, network string, address string, cfg *tls.Config) (net.Conn, error) {
|
|
||||||
conn, err := dial(ctx, network, address)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
host, _, _ := net.SplitHostPort(address)
|
|
||||||
tlsConn := utls.UClient(conn, &utls.Config{ServerName: host}, utls.HelloChrome_Auto)
|
|
||||||
handshakeCtx, cancel := context.WithTimeout(ctx, idleTimeout)
|
|
||||||
defer cancel()
|
|
||||||
if err := tlsConn.HandshakeContext(handshakeCtx); err != nil {
|
|
||||||
conn.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return tlsConn, nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
||||||
if req.URL.Scheme != "https" {
|
|
||||||
return errors.New("redirected to non-https URL: ", req.URL.String())
|
|
||||||
}
|
|
||||||
if len(via) >= 10 {
|
|
||||||
return errors.New("stopped after 10 redirects")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
Proxy: nil,
|
|
||||||
DisableKeepAlives: true,
|
|
||||||
DialContext: dial,
|
|
||||||
ResponseHeaderTimeout: idleTimeout,
|
|
||||||
},
|
|
||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
||||||
if req.URL.Scheme != "https" {
|
|
||||||
return errors.New("redirected to non-https URL: ", req.URL.String())
|
|
||||||
}
|
|
||||||
if len(via) >= 10 {
|
|
||||||
return errors.New("stopped after 10 redirects")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *downloader) download(assets []*Asset) ([]stage, error) {
|
|
||||||
staged := make([]stage, 0, len(assets))
|
|
||||||
for _, asset := range assets {
|
|
||||||
stage, err := d.downloadOne(asset)
|
|
||||||
if err != nil {
|
|
||||||
clean(staged)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
staged = append(staged, stage)
|
|
||||||
}
|
|
||||||
return staged, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *downloader) downloadOne(asset *Asset) (stage, error) {
|
|
||||||
target, err := filesystem.ResolveAsset(asset.File)
|
|
||||||
if err != nil {
|
|
||||||
return stage{}, err
|
|
||||||
}
|
|
||||||
errors.LogInfo(d.ctx, "downloading geodata asset from ", asset.Url, " to ", target)
|
|
||||||
|
|
||||||
temp, err := tempFile(target, ".tmp")
|
|
||||||
if err != nil {
|
|
||||||
return stage{}, err
|
|
||||||
}
|
|
||||||
tempName := temp.Name()
|
|
||||||
keepTemp := false
|
|
||||||
defer func() {
|
|
||||||
if !keepTemp {
|
|
||||||
os.Remove(tempName)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := d.fetch(asset.Url, temp); err != nil {
|
|
||||||
temp.Close()
|
|
||||||
return stage{}, err
|
|
||||||
}
|
|
||||||
if err := temp.Chmod(0o644); err != nil {
|
|
||||||
temp.Close()
|
|
||||||
return stage{}, err
|
|
||||||
}
|
|
||||||
if err := temp.Close(); err != nil {
|
|
||||||
return stage{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
keepTemp = true
|
|
||||||
return stage{
|
|
||||||
target: target,
|
|
||||||
temp: tempName,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *downloader) fetch(rawURL string, writer io.Writer) error {
|
|
||||||
req, err := http.NewRequestWithContext(d.ctx, http.MethodGet, rawURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
utils.TryDefaultHeadersWith(req.Header, "nav")
|
|
||||||
|
|
||||||
var client *http.Client
|
|
||||||
if req.URL.Scheme == "https" {
|
|
||||||
client = d.httpsClient
|
|
||||||
} else {
|
|
||||||
client = d.httpClient
|
|
||||||
}
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
|
|
||||||
io.Copy(io.Discard, resp.Body)
|
|
||||||
return errors.New("unexpected status code: ", resp.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := io.Copy(writer, resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if n == 0 {
|
|
||||||
return errors.New("empty response body")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func clean(assets []stage) {
|
|
||||||
for _, asset := range assets {
|
|
||||||
if asset.temp != "" {
|
|
||||||
os.Remove(asset.temp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type tx struct {
|
|
||||||
swaps []swap
|
|
||||||
}
|
|
||||||
|
|
||||||
type swap struct {
|
|
||||||
target string
|
|
||||||
backup string
|
|
||||||
hadOriginal bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func swapAll(assets []stage) (*tx, error) {
|
|
||||||
t := &tx{}
|
|
||||||
for _, asset := range assets {
|
|
||||||
s, err := swapOne(asset)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Combine(err, t.rollback())
|
|
||||||
}
|
|
||||||
t.swaps = append(t.swaps, s)
|
|
||||||
}
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func swapOne(asset stage) (swap, error) {
|
|
||||||
backup, err := backupFile(asset.target)
|
|
||||||
if err != nil {
|
|
||||||
return swap{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
s := swap{
|
|
||||||
target: asset.target,
|
|
||||||
backup: backup,
|
|
||||||
}
|
|
||||||
if err := os.Rename(asset.target, backup); err != nil {
|
|
||||||
if !go_errors.Is(err, os.ErrNotExist) {
|
|
||||||
return swap{}, err
|
|
||||||
}
|
|
||||||
if err := os.Remove(backup); err != nil && !go_errors.Is(err, os.ErrNotExist) {
|
|
||||||
return swap{}, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
s.hadOriginal = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.Rename(asset.temp, asset.target); err != nil {
|
|
||||||
if s.hadOriginal {
|
|
||||||
if restoreErr := os.Rename(backup, asset.target); restoreErr != nil {
|
|
||||||
return swap{}, errors.Combine(err, restoreErr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return swap{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tx) rollback() error {
|
|
||||||
var errs []error
|
|
||||||
for i := len(t.swaps) - 1; i >= 0; i-- {
|
|
||||||
if err := t.swaps[i].rollback(); err != nil {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors.Combine(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s swap) rollback() error {
|
|
||||||
var errs []error
|
|
||||||
if err := os.Remove(s.target); err != nil && !go_errors.Is(err, os.ErrNotExist) {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
if s.hadOriginal {
|
|
||||||
if err := os.Rename(s.backup, s.target); err != nil {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
} else if err := os.Remove(s.backup); err != nil && !go_errors.Is(err, os.ErrNotExist) {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
return errors.Combine(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tx) commit() error {
|
|
||||||
var errs []error
|
|
||||||
for _, swap := range t.swaps {
|
|
||||||
if err := os.Remove(swap.backup); err != nil && !go_errors.Is(err, os.ErrNotExist) {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors.Combine(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func tempFile(target string, suffix string) (*os.File, error) {
|
|
||||||
dir := filepath.Dir(target)
|
|
||||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return os.CreateTemp(dir, "."+filepath.Base(target)+".*"+suffix)
|
|
||||||
}
|
|
||||||
|
|
||||||
func backupFile(target string) (string, error) {
|
|
||||||
file, err := tempFile(target, ".bak")
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
name := file.Name()
|
|
||||||
if err := file.Close(); err != nil {
|
|
||||||
os.Remove(name)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if err := os.Remove(name); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return name, nil
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
package geodata
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/robfig/cron/v3"
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
commongeodata "github.com/xtls/xray-core/common/geodata"
|
|
||||||
"github.com/xtls/xray-core/core"
|
|
||||||
"github.com/xtls/xray-core/features/routing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Instance struct {
|
|
||||||
assets []*Asset
|
|
||||||
downloader *downloader
|
|
||||||
tasker *cron.Cron
|
|
||||||
|
|
||||||
mu sync.Mutex
|
|
||||||
running bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(ctx context.Context, config *Config) (*Instance, error) {
|
|
||||||
if config.Cron == "" {
|
|
||||||
return &Instance{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
g := &Instance{
|
|
||||||
assets: config.Assets,
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(g.assets) > 0 {
|
|
||||||
var dispatcher routing.Dispatcher
|
|
||||||
if err := core.RequireFeatures(ctx, func(d routing.Dispatcher) {
|
|
||||||
dispatcher = d
|
|
||||||
}); err != nil {
|
|
||||||
return nil, errors.New("failed to get dispatcher for geodata downloader").Base(err)
|
|
||||||
}
|
|
||||||
g.downloader = newDownloader(ctx, dispatcher, config.Outbound)
|
|
||||||
}
|
|
||||||
|
|
||||||
g.tasker = cron.New(
|
|
||||||
cron.WithChain(cron.SkipIfStillRunning(cron.DiscardLogger)),
|
|
||||||
cron.WithLogger(cron.DiscardLogger),
|
|
||||||
)
|
|
||||||
if _, err := g.tasker.AddFunc(config.Cron, g.execute); err != nil {
|
|
||||||
return nil, errors.New("invalid geodata cron").Base(err)
|
|
||||||
}
|
|
||||||
errors.LogInfo(ctx, "scheduled geodata reload with cron: ", config.Cron)
|
|
||||||
|
|
||||||
return g, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Instance) execute() {
|
|
||||||
var err error
|
|
||||||
if g.downloader != nil {
|
|
||||||
err = g.reloadWithUpdate()
|
|
||||||
} else {
|
|
||||||
err = reload()
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
errors.LogErrorInner(context.Background(), err, "scheduled geodata reload failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Instance) reloadWithUpdate() error {
|
|
||||||
staged, err := g.downloader.download(g.assets)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer clean(staged)
|
|
||||||
|
|
||||||
tx, err := swapAll(staged)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := reload(); err != nil {
|
|
||||||
errors.LogErrorInner(context.Background(), err, "failed to reload geodata after downloading assets, rolling back")
|
|
||||||
rollbackErr := tx.rollback()
|
|
||||||
return errors.Combine(err, rollbackErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return tx.commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
func reload() error {
|
|
||||||
return errors.Combine(commongeodata.IPReg.Reload(), commongeodata.DomainReg.Reload())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Instance) Type() interface{} {
|
|
||||||
return (*Instance)(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Instance) Start() error {
|
|
||||||
g.mu.Lock()
|
|
||||||
defer g.mu.Unlock()
|
|
||||||
|
|
||||||
if g.running {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if g.tasker != nil {
|
|
||||||
g.tasker.Start()
|
|
||||||
}
|
|
||||||
|
|
||||||
g.running = true
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Instance) Close() error {
|
|
||||||
g.mu.Lock()
|
|
||||||
defer g.mu.Unlock()
|
|
||||||
|
|
||||||
if !g.running {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if g.tasker != nil {
|
|
||||||
<-g.tasker.Stop().Done()
|
|
||||||
}
|
|
||||||
|
|
||||||
g.running = false
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
|
|
||||||
return New(ctx, cfg.(*Config))
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/log/command/config.proto
|
// source: app/log/command/config.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -22,9 +21,9 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -58,9 +57,9 @@ func (*Config) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RestartLoggerRequest struct {
|
type RestartLoggerRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RestartLoggerRequest) Reset() {
|
func (x *RestartLoggerRequest) Reset() {
|
||||||
@@ -94,9 +93,9 @@ func (*RestartLoggerRequest) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RestartLoggerResponse struct {
|
type RestartLoggerResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RestartLoggerResponse) Reset() {
|
func (x *RestartLoggerResponse) Reset() {
|
||||||
@@ -131,24 +130,39 @@ func (*RestartLoggerResponse) Descriptor() ([]byte, []int) {
|
|||||||
|
|
||||||
var File_app_log_command_config_proto protoreflect.FileDescriptor
|
var File_app_log_command_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_log_command_config_proto_rawDesc = "" +
|
var file_app_log_command_config_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x1c, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
||||||
"\x1capp/log/command/config.proto\x12\x14xray.app.log.command\"\b\n" +
|
0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14,
|
||||||
"\x06Config\"\x16\n" +
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
"\x14RestartLoggerRequest\"\x17\n" +
|
0x6d, 0x61, 0x6e, 0x64, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x16,
|
||||||
"\x15RestartLoggerResponse2{\n" +
|
0x0a, 0x14, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x52,
|
||||||
"\rLoggerService\x12j\n" +
|
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x17, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72,
|
||||||
"\rRestartLogger\x12*.xray.app.log.command.RestartLoggerRequest\x1a+.xray.app.log.command.RestartLoggerResponse\"\x00B^\n" +
|
0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32,
|
||||||
"\x18com.xray.app.log.commandP\x01Z)github.com/xtls/xray-core/app/log/command\xaa\x02\x14Xray.App.Log.Commandb\x06proto3"
|
0x7b, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||||
|
0x12, 0x6a, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65,
|
||||||
|
0x72, 0x12, 0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67,
|
||||||
|
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74,
|
||||||
|
0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e,
|
||||||
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
|
0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f, 0x67, 0x67,
|
||||||
|
0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x5e, 0x0a, 0x18,
|
||||||
|
0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67,
|
||||||
|
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68,
|
||||||
|
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
||||||
|
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x63, 0x6f,
|
||||||
|
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x14, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70,
|
||||||
|
0x2e, 0x4c, 0x6f, 0x67, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72,
|
||||||
|
0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_app_log_command_config_proto_rawDescOnce sync.Once
|
file_app_log_command_config_proto_rawDescOnce sync.Once
|
||||||
file_app_log_command_config_proto_rawDescData []byte
|
file_app_log_command_config_proto_rawDescData = file_app_log_command_config_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_log_command_config_proto_rawDescGZIP() []byte {
|
func file_app_log_command_config_proto_rawDescGZIP() []byte {
|
||||||
file_app_log_command_config_proto_rawDescOnce.Do(func() {
|
file_app_log_command_config_proto_rawDescOnce.Do(func() {
|
||||||
file_app_log_command_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_log_command_config_proto_rawDesc), len(file_app_log_command_config_proto_rawDesc)))
|
file_app_log_command_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_log_command_config_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_log_command_config_proto_rawDescData
|
return file_app_log_command_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
@@ -178,7 +192,7 @@ func file_app_log_command_config_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_log_command_config_proto_rawDesc), len(file_app_log_command_config_proto_rawDesc)),
|
RawDescriptor: file_app_log_command_config_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 3,
|
NumMessages: 3,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
@@ -189,6 +203,7 @@ func file_app_log_command_config_proto_init() {
|
|||||||
MessageInfos: file_app_log_command_config_proto_msgTypes,
|
MessageInfos: file_app_log_command_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_log_command_config_proto = out.File
|
File_app_log_command_config_proto = out.File
|
||||||
|
file_app_log_command_config_proto_rawDesc = nil
|
||||||
file_app_log_command_config_proto_goTypes = nil
|
file_app_log_command_config_proto_goTypes = nil
|
||||||
file_app_log_command_config_proto_depIdxs = nil
|
file_app_log_command_config_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.6.0
|
// - protoc-gen-go-grpc v1.5.1
|
||||||
// - protoc v6.33.5
|
// - protoc v5.28.2
|
||||||
// source: app/log/command/config.proto
|
// source: app/log/command/config.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
@@ -63,7 +63,7 @@ type LoggerServiceServer interface {
|
|||||||
type UnimplementedLoggerServiceServer struct{}
|
type UnimplementedLoggerServiceServer struct{}
|
||||||
|
|
||||||
func (UnimplementedLoggerServiceServer) RestartLogger(context.Context, *RestartLoggerRequest) (*RestartLoggerResponse, error) {
|
func (UnimplementedLoggerServiceServer) RestartLogger(context.Context, *RestartLoggerRequest) (*RestartLoggerResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method RestartLogger not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method RestartLogger not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedLoggerServiceServer) mustEmbedUnimplementedLoggerServiceServer() {}
|
func (UnimplementedLoggerServiceServer) mustEmbedUnimplementedLoggerServiceServer() {}
|
||||||
func (UnimplementedLoggerServiceServer) testEmbeddedByValue() {}
|
func (UnimplementedLoggerServiceServer) testEmbeddedByValue() {}
|
||||||
@@ -76,7 +76,7 @@ type UnsafeLoggerServiceServer interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RegisterLoggerServiceServer(s grpc.ServiceRegistrar, srv LoggerServiceServer) {
|
func RegisterLoggerServiceServer(s grpc.ServiceRegistrar, srv LoggerServiceServer) {
|
||||||
// If the following call panics, it indicates UnimplementedLoggerServiceServer was
|
// If the following call pancis, it indicates UnimplementedLoggerServiceServer was
|
||||||
// embedded by pointer and is nil. This will cause panics if an
|
// embedded by pointer and is nil. This will cause panics if an
|
||||||
// unimplemented method is ever invoked, so we test this at initialization
|
// unimplemented method is ever invoked, so we test this at initialization
|
||||||
// time to prevent it from happening at runtime later due to I/O.
|
// time to prevent it from happening at runtime later due to I/O.
|
||||||
|
|||||||
+53
-32
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/log/config.proto
|
// source: app/log/config.proto
|
||||||
|
|
||||||
package log
|
package log
|
||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -75,16 +74,17 @@ func (LogType) EnumDescriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
ErrorLogType LogType `protobuf:"varint,1,opt,name=error_log_type,json=errorLogType,proto3,enum=xray.app.log.LogType" json:"error_log_type,omitempty"`
|
|
||||||
ErrorLogLevel log.Severity `protobuf:"varint,2,opt,name=error_log_level,json=errorLogLevel,proto3,enum=xray.common.log.Severity" json:"error_log_level,omitempty"`
|
|
||||||
ErrorLogPath string `protobuf:"bytes,3,opt,name=error_log_path,json=errorLogPath,proto3" json:"error_log_path,omitempty"`
|
|
||||||
AccessLogType LogType `protobuf:"varint,4,opt,name=access_log_type,json=accessLogType,proto3,enum=xray.app.log.LogType" json:"access_log_type,omitempty"`
|
|
||||||
AccessLogPath string `protobuf:"bytes,5,opt,name=access_log_path,json=accessLogPath,proto3" json:"access_log_path,omitempty"`
|
|
||||||
EnableDnsLog bool `protobuf:"varint,6,opt,name=enable_dns_log,json=enableDnsLog,proto3" json:"enable_dns_log,omitempty"`
|
|
||||||
MaskAddress string `protobuf:"bytes,7,opt,name=mask_address,json=maskAddress,proto3" json:"mask_address,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
ErrorLogType LogType `protobuf:"varint,1,opt,name=error_log_type,json=errorLogType,proto3,enum=xray.app.log.LogType" json:"error_log_type,omitempty"`
|
||||||
|
ErrorLogLevel log.Severity `protobuf:"varint,2,opt,name=error_log_level,json=errorLogLevel,proto3,enum=xray.common.log.Severity" json:"error_log_level,omitempty"`
|
||||||
|
ErrorLogPath string `protobuf:"bytes,3,opt,name=error_log_path,json=errorLogPath,proto3" json:"error_log_path,omitempty"`
|
||||||
|
AccessLogType LogType `protobuf:"varint,4,opt,name=access_log_type,json=accessLogType,proto3,enum=xray.app.log.LogType" json:"access_log_type,omitempty"`
|
||||||
|
AccessLogPath string `protobuf:"bytes,5,opt,name=access_log_path,json=accessLogPath,proto3" json:"access_log_path,omitempty"`
|
||||||
|
EnableDnsLog bool `protobuf:"varint,6,opt,name=enable_dns_log,json=enableDnsLog,proto3" json:"enable_dns_log,omitempty"`
|
||||||
|
MaskAddress string `protobuf:"bytes,7,opt,name=mask_address,json=maskAddress,proto3" json:"mask_address,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -168,32 +168,52 @@ func (x *Config) GetMaskAddress() string {
|
|||||||
|
|
||||||
var File_app_log_config_proto protoreflect.FileDescriptor
|
var File_app_log_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_log_config_proto_rawDesc = "" +
|
var file_app_log_config_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x14, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
"\x14app/log/config.proto\x12\fxray.app.log\x1a\x14common/log/log.proto\"\xde\x02\n" +
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
"\x06Config\x12;\n" +
|
0x2e, 0x6c, 0x6f, 0x67, 0x1a, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6c, 0x6f, 0x67,
|
||||||
"\x0eerror_log_type\x18\x01 \x01(\x0e2\x15.xray.app.log.LogTypeR\ferrorLogType\x12A\n" +
|
0x2f, 0x6c, 0x6f, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xde, 0x02, 0x0a, 0x06, 0x43,
|
||||||
"\x0ferror_log_level\x18\x02 \x01(\x0e2\x19.xray.common.log.SeverityR\rerrorLogLevel\x12$\n" +
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3b, 0x0a, 0x0e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6c,
|
||||||
"\x0eerror_log_path\x18\x03 \x01(\tR\ferrorLogPath\x12=\n" +
|
0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e,
|
||||||
"\x0faccess_log_type\x18\x04 \x01(\x0e2\x15.xray.app.log.LogTypeR\raccessLogType\x12&\n" +
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x4c, 0x6f, 0x67,
|
||||||
"\x0faccess_log_path\x18\x05 \x01(\tR\raccessLogPath\x12$\n" +
|
0x54, 0x79, 0x70, 0x65, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4c, 0x6f, 0x67, 0x54, 0x79,
|
||||||
"\x0eenable_dns_log\x18\x06 \x01(\bR\fenableDnsLog\x12!\n" +
|
0x70, 0x65, 0x12, 0x41, 0x0a, 0x0f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x5f,
|
||||||
"\fmask_address\x18\a \x01(\tR\vmaskAddress*5\n" +
|
0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x78, 0x72,
|
||||||
"\aLogType\x12\b\n" +
|
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x53, 0x65,
|
||||||
"\x04None\x10\x00\x12\v\n" +
|
0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4c, 0x6f, 0x67,
|
||||||
"\aConsole\x10\x01\x12\b\n" +
|
0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6c,
|
||||||
"\x04File\x10\x02\x12\t\n" +
|
0x6f, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65,
|
||||||
"\x05Event\x10\x03BF\n" +
|
0x72, 0x72, 0x6f, 0x72, 0x4c, 0x6f, 0x67, 0x50, 0x61, 0x74, 0x68, 0x12, 0x3d, 0x0a, 0x0f, 0x61,
|
||||||
"\x10com.xray.app.logP\x01Z!github.com/xtls/xray-core/app/log\xaa\x02\fXray.App.Logb\x06proto3"
|
0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04,
|
||||||
|
0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||||
|
0x6c, 0x6f, 0x67, 0x2e, 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0d, 0x61, 0x63, 0x63,
|
||||||
|
0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x61, 0x63,
|
||||||
|
0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20,
|
||||||
|
0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x50, 0x61,
|
||||||
|
0x74, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x6e, 0x73,
|
||||||
|
0x5f, 0x6c, 0x6f, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x65, 0x6e, 0x61, 0x62,
|
||||||
|
0x6c, 0x65, 0x44, 0x6e, 0x73, 0x4c, 0x6f, 0x67, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x73, 0x6b,
|
||||||
|
0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
|
||||||
|
0x6d, 0x61, 0x73, 0x6b, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2a, 0x35, 0x0a, 0x07, 0x4c,
|
||||||
|
0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00,
|
||||||
|
0x12, 0x0b, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x10, 0x01, 0x12, 0x08, 0x0a,
|
||||||
|
0x04, 0x46, 0x69, 0x6c, 0x65, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74,
|
||||||
|
0x10, 0x03, 0x42, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
|
||||||
|
0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 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, 0x6c, 0x6f, 0x67, 0xaa, 0x02, 0x0c, 0x58, 0x72,
|
||||||
|
0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4c, 0x6f, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_app_log_config_proto_rawDescOnce sync.Once
|
file_app_log_config_proto_rawDescOnce sync.Once
|
||||||
file_app_log_config_proto_rawDescData []byte
|
file_app_log_config_proto_rawDescData = file_app_log_config_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_log_config_proto_rawDescGZIP() []byte {
|
func file_app_log_config_proto_rawDescGZIP() []byte {
|
||||||
file_app_log_config_proto_rawDescOnce.Do(func() {
|
file_app_log_config_proto_rawDescOnce.Do(func() {
|
||||||
file_app_log_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_log_config_proto_rawDesc), len(file_app_log_config_proto_rawDesc)))
|
file_app_log_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_log_config_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_log_config_proto_rawDescData
|
return file_app_log_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
@@ -225,7 +245,7 @@ func file_app_log_config_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_log_config_proto_rawDesc), len(file_app_log_config_proto_rawDesc)),
|
RawDescriptor: file_app_log_config_proto_rawDesc,
|
||||||
NumEnums: 1,
|
NumEnums: 1,
|
||||||
NumMessages: 1,
|
NumMessages: 1,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
@@ -237,6 +257,7 @@ func file_app_log_config_proto_init() {
|
|||||||
MessageInfos: file_app_log_config_proto_msgTypes,
|
MessageInfos: file_app_log_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_log_config_proto = out.File
|
File_app_log_config_proto = out.File
|
||||||
|
file_app_log_config_proto_rawDesc = nil
|
||||||
file_app_log_config_proto_goTypes = nil
|
file_app_log_config_proto_goTypes = nil
|
||||||
file_app_log_config_proto_depIdxs = nil
|
file_app_log_config_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-83
@@ -2,9 +2,8 @@ package log
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -21,23 +20,14 @@ type Instance struct {
|
|||||||
errorLogger log.Handler
|
errorLogger log.Handler
|
||||||
active bool
|
active bool
|
||||||
dns bool
|
dns bool
|
||||||
mask4 int
|
|
||||||
mask6 int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new log.Instance based on the given config.
|
// New creates a new log.Instance based on the given config.
|
||||||
func New(ctx context.Context, config *Config) (*Instance, error) {
|
func New(ctx context.Context, config *Config) (*Instance, error) {
|
||||||
m4, m6, err := ParseMaskAddress(config.MaskAddress)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
g := &Instance{
|
g := &Instance{
|
||||||
config: config,
|
config: config,
|
||||||
active: false,
|
active: false,
|
||||||
dns: config.EnableDnsLog,
|
dns: config.EnableDnsLog,
|
||||||
mask4: m4,
|
|
||||||
mask6: m6,
|
|
||||||
}
|
}
|
||||||
log.RegisterHandler(g)
|
log.RegisterHandler(g)
|
||||||
|
|
||||||
@@ -114,11 +104,7 @@ func (g *Instance) Handle(msg log.Message) {
|
|||||||
|
|
||||||
var Msg log.Message
|
var Msg log.Message
|
||||||
if g.config.MaskAddress != "" {
|
if g.config.MaskAddress != "" {
|
||||||
Msg = &MaskedMsgWrapper{
|
Msg = &MaskedMsgWrapper{Message: msg, config: g.config}
|
||||||
Message: msg,
|
|
||||||
Mask4: g.mask4,
|
|
||||||
Mask6: g.mask6,
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Msg = msg
|
Msg = msg
|
||||||
}
|
}
|
||||||
@@ -163,87 +149,51 @@ func (g *Instance) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseMaskAddress(c string) (int, int, error) {
|
|
||||||
var m4, m6 int
|
|
||||||
switch c {
|
|
||||||
case "half":
|
|
||||||
m4, m6 = 16, 32
|
|
||||||
case "quarter":
|
|
||||||
m4, m6 = 8, 16
|
|
||||||
case "full":
|
|
||||||
m4, m6 = 0, 0
|
|
||||||
case "":
|
|
||||||
// do nothing
|
|
||||||
default:
|
|
||||||
if parts := strings.Split(c, "+"); len(parts) > 0 {
|
|
||||||
if len(parts) >= 1 && parts[0] != "" {
|
|
||||||
i, err := strconv.Atoi(strings.TrimPrefix(parts[0], "/"))
|
|
||||||
if err != nil {
|
|
||||||
return 32, 128, err
|
|
||||||
}
|
|
||||||
m4 = i
|
|
||||||
}
|
|
||||||
if len(parts) >= 2 && parts[1] != "" {
|
|
||||||
i, err := strconv.Atoi(strings.TrimPrefix(parts[1], "/"))
|
|
||||||
if err != nil {
|
|
||||||
return 32, 128, err
|
|
||||||
}
|
|
||||||
m6 = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if m4%8 != 0 || m4 > 32 || m4 < 0 {
|
|
||||||
return 32, 128, errors.New("Log Mask: ipv4 mask must be divisible by 8 and between 0-32")
|
|
||||||
}
|
|
||||||
|
|
||||||
return m4, m6, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaskedMsgWrapper is to wrap the string() method to mask IP addresses in the log.
|
// MaskedMsgWrapper is to wrap the string() method to mask IP addresses in the log.
|
||||||
type MaskedMsgWrapper struct {
|
type MaskedMsgWrapper struct {
|
||||||
log.Message
|
log.Message
|
||||||
Mask4 int
|
config *Config
|
||||||
Mask6 int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
ipv4Regex = regexp.MustCompile(`(\d{1,3}\.){3}\d{1,3}`)
|
|
||||||
ipv6Regex = regexp.MustCompile(`(?:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}){2,7}`)
|
|
||||||
)
|
|
||||||
|
|
||||||
func (m *MaskedMsgWrapper) String() string {
|
func (m *MaskedMsgWrapper) String() string {
|
||||||
str := m.Message.String()
|
str := m.Message.String()
|
||||||
|
|
||||||
// Process ipv4
|
ipv4Regex := regexp.MustCompile(`(\d{1,3}\.){3}\d{1,3}`)
|
||||||
maskedMsg := ipv4Regex.ReplaceAllStringFunc(str, func(s string) string {
|
ipv6Regex := regexp.MustCompile(`((?:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}){2,7})(?:[\/\\%](\d{1,3}))?`)
|
||||||
if m.Mask4 == 32 {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
if m.Mask4 == 0 {
|
|
||||||
return "[Masked IPv4]"
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := strings.Split(s, ".")
|
// Process ipv4
|
||||||
for i := m.Mask4 / 8; i < 4; i++ {
|
maskedMsg := ipv4Regex.ReplaceAllStringFunc(str, func(ip string) string {
|
||||||
parts[i] = "*"
|
parts := strings.Split(ip, ".")
|
||||||
|
switch m.config.MaskAddress {
|
||||||
|
case "half":
|
||||||
|
return fmt.Sprintf("%s.%s.*.*", parts[0], parts[1])
|
||||||
|
case "quarter":
|
||||||
|
return fmt.Sprintf("%s.*.*.*", parts[0])
|
||||||
|
case "full":
|
||||||
|
return "[Masked IPv4]"
|
||||||
|
default:
|
||||||
|
return ip
|
||||||
}
|
}
|
||||||
return strings.Join(parts, ".")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// process ipv6
|
// process ipv6
|
||||||
maskedMsg = ipv6Regex.ReplaceAllStringFunc(maskedMsg, func(s string) string {
|
maskedMsg = ipv6Regex.ReplaceAllStringFunc(maskedMsg, func(ip string) string {
|
||||||
if m.Mask6 == 128 {
|
parts := strings.Split(ip, ":")
|
||||||
return s
|
switch m.config.MaskAddress {
|
||||||
|
case "half":
|
||||||
|
if len(parts) >= 2 {
|
||||||
|
return fmt.Sprintf("%s:%s::/32", parts[0], parts[1])
|
||||||
|
}
|
||||||
|
case "quarter":
|
||||||
|
if len(parts) >= 1 {
|
||||||
|
return fmt.Sprintf("%s::/16", parts[0])
|
||||||
|
}
|
||||||
|
case "full":
|
||||||
|
return "Masked IPv6" // Do not use [Masked IPv6] like ipv4, or you will get "[[Masked IPv6]]" (v6 address already has [])
|
||||||
|
default:
|
||||||
|
return ip
|
||||||
}
|
}
|
||||||
if m.Mask6 == 0 {
|
return ip
|
||||||
return "Masked IPv6"
|
|
||||||
}
|
|
||||||
ip := net.ParseIP(s)
|
|
||||||
if ip == nil {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return ip.Mask(net.CIDRMask(m.Mask6, 128)).String() + "/" + strconv.Itoa(m.Mask6)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return maskedMsg
|
return maskedMsg
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package log_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
@@ -51,39 +50,3 @@ func TestCustomLogHandler(t *testing.T) {
|
|||||||
|
|
||||||
common.Must(logger.Close())
|
common.Must(logger.Close())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMaskAddress(t *testing.T) {
|
|
||||||
m4, m6, err := log.ParseMaskAddress("half")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
maskedAddr := log.MaskedMsgWrapper{
|
|
||||||
Mask4: m4,
|
|
||||||
Mask6: m6,
|
|
||||||
}
|
|
||||||
maskedAddr.Message = net.ParseIP("11.45.1.4")
|
|
||||||
if maskedAddr.String() != "11.45.*.*" {
|
|
||||||
t.Fatal("expected '11.45.*.*', but actually ", maskedAddr.String())
|
|
||||||
}
|
|
||||||
maskedAddr.Message = net.ParseIP("11:45:14:19:19:81:0::")
|
|
||||||
if maskedAddr.String() != "11:45::/32" {
|
|
||||||
t.Fatal("expected '11:45::/32', but actually", maskedAddr.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
m4, m6, err = log.ParseMaskAddress("/16+/64")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
maskedAddr = log.MaskedMsgWrapper{
|
|
||||||
Mask4: m4,
|
|
||||||
Mask6: m6,
|
|
||||||
}
|
|
||||||
maskedAddr.Message = net.ParseIP("11.45.1.4")
|
|
||||||
if maskedAddr.String() != "11.45.*.*" {
|
|
||||||
t.Fatal("expected '11.45.*.*', but actually ", maskedAddr.String())
|
|
||||||
}
|
|
||||||
maskedAddr.Message = net.ParseIP("11:45:14:19:19:81:0::")
|
|
||||||
if maskedAddr.String() != "11:45:14:19::/64" {
|
|
||||||
t.Fatal("expected '11:45:14:19::/64', but actually", maskedAddr.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+26
-18
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/metrics/config.proto
|
// source: app/metrics/config.proto
|
||||||
|
|
||||||
package metrics
|
package metrics
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -23,12 +22,13 @@ const (
|
|||||||
|
|
||||||
// Config is the settings for metrics.
|
// Config is the settings for metrics.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
// Tag of the outbound handler that handles metrics http connections.
|
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
Listen string `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
// Tag of the outbound handler that handles metrics http connections.
|
||||||
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
|
Listen string `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -77,22 +77,29 @@ func (x *Config) GetListen() string {
|
|||||||
|
|
||||||
var File_app_metrics_config_proto protoreflect.FileDescriptor
|
var File_app_metrics_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_metrics_config_proto_rawDesc = "" +
|
var file_app_metrics_config_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x18, 0x61, 0x70, 0x70, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x63, 0x6f,
|
||||||
"\x18app/metrics/config.proto\x12\x10xray.app.metrics\"2\n" +
|
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61, 0x79,
|
||||||
"\x06Config\x12\x10\n" +
|
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x32, 0x0a, 0x06,
|
||||||
"\x03tag\x18\x01 \x01(\tR\x03tag\x12\x16\n" +
|
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20,
|
||||||
"\x06listen\x18\x02 \x01(\tR\x06listenBR\n" +
|
0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74,
|
||||||
"\x14com.xray.app.metricsP\x01Z%github.com/xtls/xray-core/app/metrics\xaa\x02\x10Xray.App.Metricsb\x06proto3"
|
0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e,
|
||||||
|
0x42, 0x52, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
|
0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68,
|
||||||
|
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
||||||
|
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
|
||||||
|
0x73, 0xaa, 0x02, 0x10, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4d, 0x65, 0x74,
|
||||||
|
0x72, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_app_metrics_config_proto_rawDescOnce sync.Once
|
file_app_metrics_config_proto_rawDescOnce sync.Once
|
||||||
file_app_metrics_config_proto_rawDescData []byte
|
file_app_metrics_config_proto_rawDescData = file_app_metrics_config_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_metrics_config_proto_rawDescGZIP() []byte {
|
func file_app_metrics_config_proto_rawDescGZIP() []byte {
|
||||||
file_app_metrics_config_proto_rawDescOnce.Do(func() {
|
file_app_metrics_config_proto_rawDescOnce.Do(func() {
|
||||||
file_app_metrics_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_metrics_config_proto_rawDesc), len(file_app_metrics_config_proto_rawDesc)))
|
file_app_metrics_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_metrics_config_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_metrics_config_proto_rawDescData
|
return file_app_metrics_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
@@ -118,7 +125,7 @@ func file_app_metrics_config_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_metrics_config_proto_rawDesc), len(file_app_metrics_config_proto_rawDesc)),
|
RawDescriptor: file_app_metrics_config_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 1,
|
NumMessages: 1,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
@@ -129,6 +136,7 @@ func file_app_metrics_config_proto_init() {
|
|||||||
MessageInfos: file_app_metrics_config_proto_msgTypes,
|
MessageInfos: file_app_metrics_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_metrics_config_proto = out.File
|
File_app_metrics_config_proto = out.File
|
||||||
|
file_app_metrics_config_proto_rawDesc = nil
|
||||||
file_app_metrics_config_proto_goTypes = nil
|
file_app_metrics_config_proto_goTypes = nil
|
||||||
file_app_metrics_config_proto_depIdxs = nil
|
file_app_metrics_config_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
+64
-150
@@ -2,18 +2,16 @@ package metrics
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
stderrors "errors"
|
|
||||||
"expvar"
|
"expvar"
|
||||||
stdnet "net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/pprof"
|
_ "net/http/pprof"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/observatory"
|
"github.com/xtls/xray-core/app/observatory"
|
||||||
|
"github.com/xtls/xray-core/app/stats"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
xnet "github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/signal/done"
|
"github.com/xtls/xray-core/common/signal/done"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/extension"
|
"github.com/xtls/xray-core/features/extension"
|
||||||
@@ -24,17 +22,15 @@ import (
|
|||||||
type MetricsHandler struct {
|
type MetricsHandler struct {
|
||||||
ohm outbound.Manager
|
ohm outbound.Manager
|
||||||
statsManager feature_stats.Manager
|
statsManager feature_stats.Manager
|
||||||
ctx context.Context
|
observatory extension.Observatory
|
||||||
tag string
|
tag string
|
||||||
listen string
|
listen string
|
||||||
tcpListener xnet.Listener
|
tcpListener net.Listener
|
||||||
listener *OutboundListener
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMetricsHandler creates a new MetricsHandler based on the given config.
|
// NewMetricsHandler creates a new MetricsHandler based on the given config.
|
||||||
func NewMetricsHandler(ctx context.Context, config *Config) (*MetricsHandler, error) {
|
func NewMetricsHandler(ctx context.Context, config *Config) (*MetricsHandler, error) {
|
||||||
c := &MetricsHandler{
|
c := &MetricsHandler{
|
||||||
ctx: ctx,
|
|
||||||
tag: config.Tag,
|
tag: config.Tag,
|
||||||
listen: config.Listen,
|
listen: config.Listen,
|
||||||
}
|
}
|
||||||
@@ -42,6 +38,50 @@ func NewMetricsHandler(ctx context.Context, config *Config) (*MetricsHandler, er
|
|||||||
c.statsManager = sm
|
c.statsManager = sm
|
||||||
c.ohm = om
|
c.ohm = om
|
||||||
}))
|
}))
|
||||||
|
expvar.Publish("stats", expvar.Func(func() interface{} {
|
||||||
|
manager, ok := c.statsManager.(*stats.Manager)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
resp := map[string]map[string]map[string]int64{
|
||||||
|
"inbound": {},
|
||||||
|
"outbound": {},
|
||||||
|
"user": {},
|
||||||
|
}
|
||||||
|
manager.VisitCounters(func(name string, counter feature_stats.Counter) bool {
|
||||||
|
nameSplit := strings.Split(name, ">>>")
|
||||||
|
typeName, tagOrUser, direction := nameSplit[0], nameSplit[1], nameSplit[3]
|
||||||
|
if item, found := resp[typeName][tagOrUser]; found {
|
||||||
|
item[direction] = counter.Value()
|
||||||
|
} else {
|
||||||
|
resp[typeName][tagOrUser] = map[string]int64{
|
||||||
|
direction: counter.Value(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return resp
|
||||||
|
}))
|
||||||
|
expvar.Publish("observatory", expvar.Func(func() interface{} {
|
||||||
|
if c.observatory == nil {
|
||||||
|
common.Must(core.RequireFeatures(ctx, func(observatory extension.Observatory) error {
|
||||||
|
c.observatory = observatory
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
if c.observatory == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resp := map[string]*observatory.OutboundStatus{}
|
||||||
|
if o, err := c.observatory.GetObservation(context.Background()); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
for _, x := range o.(*observatory.ObservationResult).GetStatus() {
|
||||||
|
resp[x.OutboundTag] = x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resp
|
||||||
|
}))
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,172 +90,46 @@ func (p *MetricsHandler) Type() interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *MetricsHandler) Start() error {
|
func (p *MetricsHandler) Start() error {
|
||||||
handler := p.httpHandler()
|
|
||||||
|
|
||||||
// direct listen a port if listen is set
|
// direct listen a port if listen is set
|
||||||
if p.listen != "" {
|
if p.listen != "" {
|
||||||
TCPlistener, err := xnet.Listen("tcp", p.listen)
|
TCPlistener, err := net.Listen("tcp", p.listen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.tcpListener = TCPlistener
|
p.tcpListener = TCPlistener
|
||||||
errors.LogInfo(context.Background(), "Metrics server listening on ", p.listen)
|
errors.LogInfo(context.Background(), "Metrics server listening on ", p.listen)
|
||||||
|
|
||||||
go p.serve(TCPlistener, handler)
|
go func() {
|
||||||
}
|
if err := http.Serve(TCPlistener, http.DefaultServeMux); err != nil {
|
||||||
|
errors.LogErrorInner(context.Background(), err, "failed to start metrics server")
|
||||||
if p.tag == "" {
|
}
|
||||||
if p.tcpListener == nil {
|
}()
|
||||||
return errors.New("metrics must have a tag or listen address")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
listener := &OutboundListener{
|
listener := &OutboundListener{
|
||||||
buffer: make(chan xnet.Conn, 4),
|
buffer: make(chan net.Conn, 4),
|
||||||
done: done.New(),
|
done: done.New(),
|
||||||
}
|
}
|
||||||
p.listener = listener
|
|
||||||
|
|
||||||
go p.serve(listener, handler)
|
go func() {
|
||||||
|
if err := http.Serve(listener, http.DefaultServeMux); err != nil {
|
||||||
|
errors.LogErrorInner(context.Background(), err, "failed to start metrics server")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if err := p.ohm.RemoveHandler(context.Background(), p.tag); err != nil {
|
if err := p.ohm.RemoveHandler(context.Background(), p.tag); err != nil {
|
||||||
errors.LogInfo(context.Background(), "failed to remove existing handler")
|
errors.LogInfo(context.Background(), "failed to remove existing handler")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.ohm.AddHandler(context.Background(), &Outbound{
|
return p.ohm.AddHandler(context.Background(), &Outbound{
|
||||||
tag: p.tag,
|
tag: p.tag,
|
||||||
listener: listener,
|
listener: listener,
|
||||||
}); err != nil {
|
})
|
||||||
if closeErr := p.Close(); closeErr != nil {
|
|
||||||
errors.LogErrorInner(context.Background(), closeErr, "failed to close metrics server after start failure")
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MetricsHandler) Close() error {
|
func (p *MetricsHandler) Close() error {
|
||||||
var errs []error
|
return nil
|
||||||
if p.tcpListener != nil {
|
|
||||||
errs = append(errs, p.tcpListener.Close())
|
|
||||||
p.tcpListener = nil
|
|
||||||
}
|
|
||||||
if p.listener != nil {
|
|
||||||
errs = append(errs, p.listener.Close())
|
|
||||||
p.listener = nil
|
|
||||||
}
|
|
||||||
if p.ohm != nil && p.tag != "" {
|
|
||||||
if err := p.ohm.RemoveHandler(context.Background(), p.tag); err != nil {
|
|
||||||
errors.LogInfo(context.Background(), "failed to remove metrics handler")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors.Combine(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MetricsHandler) serve(listener xnet.Listener, handler http.Handler) {
|
|
||||||
if err := http.Serve(listener, handler); err != nil && !isClosedListenerError(err) {
|
|
||||||
errors.LogErrorInner(context.Background(), err, "failed to start metrics server")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isClosedListenerError(err error) bool {
|
|
||||||
if err == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if stderrors.Is(err, stdnet.ErrClosed) || stderrors.Is(err, http.ErrServerClosed) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
errText := err.Error()
|
|
||||||
return strings.Contains(errText, "listen closed") ||
|
|
||||||
strings.Contains(errText, "use of closed network connection")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MetricsHandler) httpHandler() http.Handler {
|
|
||||||
mux := http.NewServeMux()
|
|
||||||
mux.HandleFunc("/debug/vars", p.handleDebugVars)
|
|
||||||
mux.HandleFunc("/debug/pprof/", pprof.Index)
|
|
||||||
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
|
||||||
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
|
||||||
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
|
||||||
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
|
||||||
return mux
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MetricsHandler) handleDebugVars(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
||||||
vars := map[string]json.RawMessage{}
|
|
||||||
expvar.Do(func(kv expvar.KeyValue) {
|
|
||||||
value := json.RawMessage(kv.Value.String())
|
|
||||||
if !json.Valid(value) {
|
|
||||||
value = json.RawMessage("null")
|
|
||||||
}
|
|
||||||
vars[kv.Key] = value
|
|
||||||
})
|
|
||||||
vars["stats"] = marshalJSON(p.stats())
|
|
||||||
vars["observatory"] = marshalJSON(p.observatoryStatus())
|
|
||||||
|
|
||||||
payload, err := json.Marshal(vars)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Write(payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalJSON(value interface{}) json.RawMessage {
|
|
||||||
data, err := json.Marshal(value)
|
|
||||||
if err != nil {
|
|
||||||
return json.RawMessage("null")
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MetricsHandler) stats() map[string]map[string]map[string]int64 {
|
|
||||||
resp := map[string]map[string]map[string]int64{
|
|
||||||
"inbound": {},
|
|
||||||
"outbound": {},
|
|
||||||
"user": {},
|
|
||||||
}
|
|
||||||
p.statsManager.VisitCounters(func(name string, counter feature_stats.Counter) bool {
|
|
||||||
nameSplit := strings.Split(name, ">>>")
|
|
||||||
if len(nameSplit) < 4 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
typeName, tagOrUser, direction := nameSplit[0], nameSplit[1], nameSplit[3]
|
|
||||||
items, found := resp[typeName]
|
|
||||||
if !found {
|
|
||||||
items = map[string]map[string]int64{}
|
|
||||||
resp[typeName] = items
|
|
||||||
}
|
|
||||||
if item, found := items[tagOrUser]; found {
|
|
||||||
item[direction] = counter.Value()
|
|
||||||
} else {
|
|
||||||
items[tagOrUser] = map[string]int64{
|
|
||||||
direction: counter.Value(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return resp
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MetricsHandler) observatoryStatus() interface{} {
|
|
||||||
feature := core.MustFromContext(p.ctx).GetFeature(extension.ObservatoryType())
|
|
||||||
if feature == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
observatoryFeature := feature.(extension.Observatory)
|
|
||||||
resp := map[string]*observatory.OutboundStatus{}
|
|
||||||
if o, err := observatoryFeature.GetObservation(context.Background()); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
for _, x := range o.(*observatory.ObservationResult).GetStatus() {
|
|
||||||
resp[x.OutboundTag] = x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -1,161 +0,0 @@
|
|||||||
package metrics
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
stdnet "net"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/dispatcher"
|
|
||||||
"github.com/xtls/xray-core/app/proxyman"
|
|
||||||
_ "github.com/xtls/xray-core/app/proxyman/inbound"
|
|
||||||
_ "github.com/xtls/xray-core/app/proxyman/outbound"
|
|
||||||
appstats "github.com/xtls/xray-core/app/stats"
|
|
||||||
"github.com/xtls/xray-core/common/serial"
|
|
||||||
"github.com/xtls/xray-core/core"
|
|
||||||
feature_outbound "github.com/xtls/xray-core/features/outbound"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMetricsCanRestartInSameProcess(t *testing.T) {
|
|
||||||
for i := 0; i < 2; i++ {
|
|
||||||
server := startMetricsTestServer(t)
|
|
||||||
readMetricsVars(t, server)
|
|
||||||
readMetricsPprof(t, server)
|
|
||||||
if err := server.Close(); err != nil {
|
|
||||||
t.Fatalf("failed to close metrics server: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMetricsCanRunMultipleInstancesInSameProcess(t *testing.T) {
|
|
||||||
server1 := startMetricsTestServer(t)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
_ = server1.Close()
|
|
||||||
})
|
|
||||||
server2 := startMetricsTestServer(t)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
_ = server2.Close()
|
|
||||||
})
|
|
||||||
|
|
||||||
readMetricsVars(t, server1)
|
|
||||||
readMetricsVars(t, server2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMetricsListenOnlyWithoutTagDoesNotRegisterOutbound(t *testing.T) {
|
|
||||||
listen := pickMetricsListenAddress(t)
|
|
||||||
server := startMetricsTestServerWithMetricsConfig(t, &Config{
|
|
||||||
Listen: listen,
|
|
||||||
})
|
|
||||||
t.Cleanup(func() {
|
|
||||||
_ = server.Close()
|
|
||||||
})
|
|
||||||
|
|
||||||
response, err := http.Get("http://" + listen + "/debug/vars")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to read listen-only metrics: %v", err)
|
|
||||||
}
|
|
||||||
defer response.Body.Close()
|
|
||||||
if response.StatusCode != http.StatusOK {
|
|
||||||
t.Fatalf("unexpected listen-only metrics status: %d", response.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
outboundManager := server.GetFeature(feature_outbound.ManagerType()).(feature_outbound.Manager)
|
|
||||||
if handlers := outboundManager.ListHandlers(context.Background()); len(handlers) != 0 {
|
|
||||||
t.Fatalf("listen-only metrics registered outbound handlers: got %d, want 0", len(handlers))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func startMetricsTestServer(t *testing.T) *core.Instance {
|
|
||||||
return startMetricsTestServerWithMetricsConfig(t, &Config{
|
|
||||||
Tag: "metrics_out",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func startMetricsTestServerWithMetricsConfig(t *testing.T, metricsConfig *Config) *core.Instance {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
server, err := core.New(metricsTestConfig(metricsConfig))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to create metrics server: %v", err)
|
|
||||||
}
|
|
||||||
if err := server.Start(); err != nil {
|
|
||||||
_ = server.Close()
|
|
||||||
t.Fatalf("failed to start metrics server: %v", err)
|
|
||||||
}
|
|
||||||
return server
|
|
||||||
}
|
|
||||||
|
|
||||||
func metricsTestConfig(metricsConfig *Config) *core.Config {
|
|
||||||
return &core.Config{
|
|
||||||
App: []*serial.TypedMessage{
|
|
||||||
serial.ToTypedMessage(&dispatcher.Config{}),
|
|
||||||
serial.ToTypedMessage(&proxyman.InboundConfig{}),
|
|
||||||
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
|
|
||||||
serial.ToTypedMessage(&appstats.Config{}),
|
|
||||||
serial.ToTypedMessage(metricsConfig),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func pickMetricsListenAddress(t *testing.T) string {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
listener, err := stdnet.Listen("tcp", "127.0.0.1:0")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to pick metrics listen address: %v", err)
|
|
||||||
}
|
|
||||||
defer listener.Close()
|
|
||||||
return listener.Addr().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func readMetricsVars(t *testing.T, server *core.Instance) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
metricsHandler(t, server).httpHandler().ServeHTTP(
|
|
||||||
recorder,
|
|
||||||
httptest.NewRequest(http.MethodGet, "/debug/vars", nil),
|
|
||||||
)
|
|
||||||
|
|
||||||
if recorder.Code != http.StatusOK {
|
|
||||||
t.Fatalf("unexpected metrics vars status: %d", recorder.Code)
|
|
||||||
}
|
|
||||||
|
|
||||||
var payload map[string]interface{}
|
|
||||||
if err := json.NewDecoder(recorder.Body).Decode(&payload); err != nil {
|
|
||||||
t.Fatalf("failed to decode metrics vars: %v", err)
|
|
||||||
}
|
|
||||||
if _, found := payload["stats"]; !found {
|
|
||||||
t.Fatal("metrics vars missing stats")
|
|
||||||
}
|
|
||||||
if _, found := payload["observatory"]; !found {
|
|
||||||
t.Fatal("metrics vars missing observatory")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func readMetricsPprof(t *testing.T, server *core.Instance) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
metricsHandler(t, server).httpHandler().ServeHTTP(
|
|
||||||
recorder,
|
|
||||||
httptest.NewRequest(http.MethodGet, "/debug/pprof/goroutine?debug=1", nil),
|
|
||||||
)
|
|
||||||
|
|
||||||
if recorder.Code != http.StatusOK {
|
|
||||||
t.Fatalf("unexpected metrics pprof status: %d", recorder.Code)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func metricsHandler(t *testing.T, server *core.Instance) *MetricsHandler {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
feature := server.GetFeature((*MetricsHandler)(nil))
|
|
||||||
handler, ok := feature.(*MetricsHandler)
|
|
||||||
if !ok || handler == nil {
|
|
||||||
t.Fatal("metrics handler not registered")
|
|
||||||
}
|
|
||||||
return handler
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@ package burst
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/observatory"
|
"github.com/xtls/xray-core/app/observatory"
|
||||||
@@ -31,10 +32,6 @@ func (o *Observer) GetObservation(ctx context.Context) (proto.Message, error) {
|
|||||||
return &observatory.ObservationResult{Status: o.createResult()}, nil
|
return &observatory.ObservationResult{Status: o.createResult()}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Observer) Check(tag []string) {
|
|
||||||
o.hp.Check(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Observer) createResult() []*observatory.OutboundStatus {
|
func (o *Observer) createResult() []*observatory.OutboundStatus {
|
||||||
var result []*observatory.OutboundStatus
|
var result []*observatory.OutboundStatus
|
||||||
o.hp.access.Lock()
|
o.hp.access.Lock()
|
||||||
@@ -71,6 +68,7 @@ func (o *Observer) Start() error {
|
|||||||
o.hp.StartScheduler(func() ([]string, error) {
|
o.hp.StartScheduler(func() ([]string, error) {
|
||||||
hs, ok := o.ohm.(outbound.HandlerSelector)
|
hs, ok := o.ohm.(outbound.HandlerSelector)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
||||||
return nil, errors.New("outbound.Manager is not a HandlerSelector")
|
return nil, errors.New("outbound.Manager is not a HandlerSelector")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/observatory/burst/config.proto
|
// source: app/observatory/burst/config.proto
|
||||||
|
|
||||||
package burst
|
package burst
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -22,12 +21,13 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// @Document The selectors for outbound under observation
|
// @Document The selectors for outbound under observation
|
||||||
SubjectSelector []string `protobuf:"bytes,2,rep,name=subject_selector,json=subjectSelector,proto3" json:"subject_selector,omitempty"`
|
SubjectSelector []string `protobuf:"bytes,2,rep,name=subject_selector,json=subjectSelector,proto3" json:"subject_selector,omitempty"`
|
||||||
PingConfig *HealthPingConfig `protobuf:"bytes,3,opt,name=ping_config,json=pingConfig,proto3" json:"ping_config,omitempty"`
|
PingConfig *HealthPingConfig `protobuf:"bytes,3,opt,name=ping_config,json=pingConfig,proto3" json:"ping_config,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -75,7 +75,10 @@ func (x *Config) GetPingConfig() *HealthPingConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HealthPingConfig struct {
|
type HealthPingConfig struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// destination url, need 204 for success return
|
// destination url, need 204 for success return
|
||||||
// default https://connectivitycheck.gstatic.com/generate_204
|
// default https://connectivitycheck.gstatic.com/generate_204
|
||||||
Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"`
|
Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"`
|
||||||
@@ -88,9 +91,7 @@ type HealthPingConfig struct {
|
|||||||
// ping timeout, int64 values of time.Duration
|
// ping timeout, int64 values of time.Duration
|
||||||
Timeout int64 `protobuf:"varint,5,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
Timeout int64 `protobuf:"varint,5,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
||||||
// http method to make request
|
// http method to make request
|
||||||
HttpMethod string `protobuf:"bytes,6,opt,name=httpMethod,proto3" json:"httpMethod,omitempty"`
|
HttpMethod string `protobuf:"bytes,6,opt,name=httpMethod,proto3" json:"httpMethod,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *HealthPingConfig) Reset() {
|
func (x *HealthPingConfig) Reset() {
|
||||||
@@ -167,32 +168,51 @@ func (x *HealthPingConfig) GetHttpMethod() string {
|
|||||||
|
|
||||||
var File_app_observatory_burst_config_proto protoreflect.FileDescriptor
|
var File_app_observatory_burst_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_observatory_burst_config_proto_rawDesc = "" +
|
var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x22, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
|
||||||
"\"app/observatory/burst/config.proto\x12\x1fxray.core.app.observatory.burst\"\x87\x01\n" +
|
0x79, 0x2f, 0x62, 0x75, 0x72, 0x73, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70,
|
||||||
"\x06Config\x12)\n" +
|
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1f, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
||||||
"\x10subject_selector\x18\x02 \x03(\tR\x0fsubjectSelector\x12R\n" +
|
0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e,
|
||||||
"\vping_config\x18\x03 \x01(\v21.xray.core.app.observatory.burst.HealthPingConfigR\n" +
|
0x62, 0x75, 0x72, 0x73, 0x74, 0x22, 0x87, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
"pingConfig\"\xd4\x01\n" +
|
0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65,
|
||||||
"\x10HealthPingConfig\x12 \n" +
|
0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a,
|
||||||
"\vdestination\x18\x01 \x01(\tR\vdestination\x12\"\n" +
|
0x65, 0x63, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x52, 0x0a, 0x0b, 0x70,
|
||||||
"\fconnectivity\x18\x02 \x01(\tR\fconnectivity\x12\x1a\n" +
|
0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
|
||||||
"\binterval\x18\x03 \x01(\x03R\binterval\x12$\n" +
|
0x32, 0x31, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
|
||||||
"\rsamplingCount\x18\x04 \x01(\x05R\rsamplingCount\x12\x18\n" +
|
0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x62, 0x75, 0x72,
|
||||||
"\atimeout\x18\x05 \x01(\x03R\atimeout\x12\x1e\n" +
|
0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
|
||||||
"\n" +
|
0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22,
|
||||||
"httpMethod\x18\x06 \x01(\tR\n" +
|
0xd4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
||||||
"httpMethodBp\n" +
|
0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
|
||||||
"\x1ecom.xray.app.observatory.burstP\x01Z/github.com/xtls/xray-core/app/observatory/burst\xaa\x02\x1aXray.App.Observatory.Burstb\x06proto3"
|
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,
|
||||||
|
0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f,
|
||||||
|
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e,
|
||||||
|
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x6e,
|
||||||
|
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x69,
|
||||||
|
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, 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,
|
||||||
|
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76,
|
||||||
|
0x61, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x62, 0x75, 0x72, 0x73, 0x74, 0xaa, 0x02, 0x1a, 0x58, 0x72,
|
||||||
|
0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
|
||||||
|
0x72, 0x79, 0x2e, 0x42, 0x75, 0x72, 0x73, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_app_observatory_burst_config_proto_rawDescOnce sync.Once
|
file_app_observatory_burst_config_proto_rawDescOnce sync.Once
|
||||||
file_app_observatory_burst_config_proto_rawDescData []byte
|
file_app_observatory_burst_config_proto_rawDescData = file_app_observatory_burst_config_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_observatory_burst_config_proto_rawDescGZIP() []byte {
|
func file_app_observatory_burst_config_proto_rawDescGZIP() []byte {
|
||||||
file_app_observatory_burst_config_proto_rawDescOnce.Do(func() {
|
file_app_observatory_burst_config_proto_rawDescOnce.Do(func() {
|
||||||
file_app_observatory_burst_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_observatory_burst_config_proto_rawDesc), len(file_app_observatory_burst_config_proto_rawDesc)))
|
file_app_observatory_burst_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_observatory_burst_config_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_observatory_burst_config_proto_rawDescData
|
return file_app_observatory_burst_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
@@ -220,7 +240,7 @@ func file_app_observatory_burst_config_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_observatory_burst_config_proto_rawDesc), len(file_app_observatory_burst_config_proto_rawDesc)),
|
RawDescriptor: file_app_observatory_burst_config_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 2,
|
NumMessages: 2,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
@@ -231,6 +251,7 @@ func file_app_observatory_burst_config_proto_init() {
|
|||||||
MessageInfos: file_app_observatory_burst_config_proto_msgTypes,
|
MessageInfos: file_app_observatory_burst_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_observatory_burst_config_proto = out.File
|
File_app_observatory_burst_config_proto = out.File
|
||||||
|
file_app_observatory_burst_config_proto_rawDesc = nil
|
||||||
file_app_observatory_burst_config_proto_goTypes = nil
|
file_app_observatory_burst_config_proto_goTypes = nil
|
||||||
file_app_observatory_burst_config_proto_depIdxs = nil
|
file_app_observatory_burst_config_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/dice"
|
"github.com/xtls/xray-core/common/dice"
|
||||||
@@ -25,12 +24,11 @@ type HealthPingSettings struct {
|
|||||||
|
|
||||||
// HealthPing is the health checker for balancers
|
// HealthPing is the health checker for balancers
|
||||||
type HealthPing struct {
|
type HealthPing struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancelCtx context.CancelFunc
|
dispatcher routing.Dispatcher
|
||||||
cancelPending atomic.Pointer[context.CancelFunc]
|
access sync.Mutex
|
||||||
dispatcher routing.Dispatcher
|
ticker *time.Ticker
|
||||||
access sync.Mutex
|
tickerClose chan struct{}
|
||||||
ticker *time.Ticker
|
|
||||||
|
|
||||||
Settings *HealthPingSettings
|
Settings *HealthPingSettings
|
||||||
Results map[string]*HealthPingRTTS
|
Results map[string]*HealthPingRTTS
|
||||||
@@ -64,10 +62,10 @@ func NewHealthPing(ctx context.Context, dispatcher routing.Dispatcher, config *H
|
|||||||
settings.Destination = "https://connectivitycheck.gstatic.com/generate_204"
|
settings.Destination = "https://connectivitycheck.gstatic.com/generate_204"
|
||||||
}
|
}
|
||||||
if settings.Interval == 0 {
|
if settings.Interval == 0 {
|
||||||
settings.Interval = 1 * time.Minute
|
settings.Interval = time.Duration(1) * time.Minute
|
||||||
} else if settings.Interval < 10*time.Second {
|
} else if settings.Interval < 10 {
|
||||||
errors.LogWarning(ctx, "health check interval is too small, 10s is applied")
|
errors.LogWarning(ctx, "health check interval is too small, 10s is applied")
|
||||||
settings.Interval = 10 * time.Second
|
settings.Interval = time.Duration(10) * time.Second
|
||||||
}
|
}
|
||||||
if settings.SamplingCount <= 0 {
|
if settings.SamplingCount <= 0 {
|
||||||
settings.SamplingCount = 10
|
settings.SamplingCount = 10
|
||||||
@@ -75,12 +73,10 @@ func NewHealthPing(ctx context.Context, dispatcher routing.Dispatcher, config *H
|
|||||||
if settings.Timeout <= 0 {
|
if settings.Timeout <= 0 {
|
||||||
// results are saved after all health pings finish,
|
// results are saved after all health pings finish,
|
||||||
// a larger timeout could possibly makes checks run longer
|
// a larger timeout could possibly makes checks run longer
|
||||||
settings.Timeout = 5 * time.Second
|
settings.Timeout = time.Duration(5) * time.Second
|
||||||
}
|
}
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
|
||||||
return &HealthPing{
|
return &HealthPing{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancelCtx: cancel,
|
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
Settings: settings,
|
Settings: settings,
|
||||||
Results: nil,
|
Results: nil,
|
||||||
@@ -94,9 +90,9 @@ func (h *HealthPing) StartScheduler(selector func() ([]string, error)) {
|
|||||||
}
|
}
|
||||||
interval := h.Settings.Interval * time.Duration(h.Settings.SamplingCount)
|
interval := h.Settings.Interval * time.Duration(h.Settings.SamplingCount)
|
||||||
ticker := time.NewTicker(interval)
|
ticker := time.NewTicker(interval)
|
||||||
|
tickerClose := make(chan struct{})
|
||||||
h.ticker = ticker
|
h.ticker = ticker
|
||||||
|
h.tickerClose = tickerClose
|
||||||
// init run to get a fast check result
|
|
||||||
go func() {
|
go func() {
|
||||||
tags, err := selector()
|
tags, err := selector()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -114,20 +110,13 @@ func (h *HealthPing) StartScheduler(selector func() ([]string, error)) {
|
|||||||
errors.LogWarning(h.ctx, "error select outbounds for scheduled health check: ", err)
|
errors.LogWarning(h.ctx, "error select outbounds for scheduled health check: ", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
subCtx, cancel := context.WithCancel(h.ctx)
|
h.doCheck(tags, interval, h.Settings.SamplingCount)
|
||||||
old := h.cancelPending.Swap(&cancel)
|
|
||||||
if old != nil {
|
|
||||||
errors.LogDebug(h.ctx, "scheduled health check not finished before next round, canceling previous one")
|
|
||||||
(*old)()
|
|
||||||
}
|
|
||||||
h.doCheck(subCtx, tags, interval, h.Settings.SamplingCount)
|
|
||||||
h.cancelPending.CompareAndSwap(&cancel, nil)
|
|
||||||
h.Cleanup(tags)
|
h.Cleanup(tags)
|
||||||
}()
|
}()
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
continue
|
continue
|
||||||
case <-h.ctx.Done():
|
case <-tickerClose:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,7 +130,8 @@ func (h *HealthPing) StopScheduler() {
|
|||||||
}
|
}
|
||||||
h.ticker.Stop()
|
h.ticker.Stop()
|
||||||
h.ticker = nil
|
h.ticker = nil
|
||||||
h.cancelCtx()
|
close(h.tickerClose)
|
||||||
|
h.tickerClose = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check implements the HealthChecker
|
// Check implements the HealthChecker
|
||||||
@@ -150,7 +140,7 @@ func (h *HealthPing) Check(tags []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
errors.LogInfo(h.ctx, "perform one-time health check for tags ", tags)
|
errors.LogInfo(h.ctx, "perform one-time health check for tags ", tags)
|
||||||
h.doCheck(h.ctx, tags, 0, 1)
|
h.doCheck(tags, 0, 1)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,29 +151,28 @@ type rtt struct {
|
|||||||
|
|
||||||
// doCheck performs the 'rounds' amount checks in given 'duration'. You should make
|
// doCheck performs the 'rounds' amount checks in given 'duration'. You should make
|
||||||
// sure all tags are valid for current balancer
|
// sure all tags are valid for current balancer
|
||||||
// cancel ctx will stop all pending checks
|
func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int) {
|
||||||
func (h *HealthPing) doCheck(ctx context.Context, tags []string, duration time.Duration, rounds int) {
|
|
||||||
count := len(tags) * rounds
|
count := len(tags) * rounds
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ch := make(chan *rtt, count)
|
ch := make(chan *rtt, count)
|
||||||
timers := make([]*time.Timer, 0, count)
|
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
handler := tag
|
handler := tag
|
||||||
client := newPingClient(
|
client := newPingClient(
|
||||||
ctx,
|
h.ctx,
|
||||||
h.dispatcher,
|
h.dispatcher,
|
||||||
h.Settings.Destination,
|
h.Settings.Destination,
|
||||||
h.Settings.Timeout,
|
h.Settings.Timeout,
|
||||||
handler,
|
handler,
|
||||||
)
|
)
|
||||||
for range rounds {
|
for i := 0; i < rounds; i++ {
|
||||||
delay := time.Duration(0)
|
delay := time.Duration(0)
|
||||||
if duration > 0 {
|
if duration > 0 {
|
||||||
delay = time.Duration(dice.RollInt63n(int64(duration)))
|
delay = time.Duration(dice.RollInt63n(int64(duration)))
|
||||||
}
|
}
|
||||||
timers = append(timers, time.AfterFunc(delay, func() {
|
time.AfterFunc(delay, func() {
|
||||||
errors.LogDebug(h.ctx, "checking ", handler)
|
errors.LogDebug(h.ctx, "checking ", handler)
|
||||||
delay, err := client.MeasureDelay(h.Settings.HttpMethod)
|
delay, err := client.MeasureDelay(h.Settings.HttpMethod)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -211,21 +200,14 @@ func (h *HealthPing) doCheck(ctx context.Context, tags []string, duration time.D
|
|||||||
handler: handler,
|
handler: handler,
|
||||||
value: rttFailed,
|
value: rttFailed,
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
select {
|
rtt := <-ch
|
||||||
case rtt := <-ch:
|
if rtt.value > 0 {
|
||||||
if rtt.value > 0 {
|
// should not put results when network is down
|
||||||
// should not put results when network is down
|
h.PutResult(rtt.handler, rtt.value)
|
||||||
h.PutResult(rtt.handler, rtt.value)
|
|
||||||
}
|
|
||||||
case <-ctx.Done():
|
|
||||||
for _, timer := range timers {
|
|
||||||
timer.Stop()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ func (h *HealthPingRTTS) Put(d time.Duration) {
|
|||||||
if h.rtts == nil {
|
if h.rtts == nil {
|
||||||
h.rtts = make([]*pingRTT, h.cap)
|
h.rtts = make([]*pingRTT, h.cap)
|
||||||
for i := 0; i < h.cap; i++ {
|
for i := 0; i < h.cap; i++ {
|
||||||
h.rtts[i] = &pingRTT{value: rttUntested}
|
h.rtts[i] = &pingRTT{}
|
||||||
}
|
}
|
||||||
h.idx = -1
|
h.idx = -1
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ func (h *HealthPingRTTS) getStatistics() *HealthPingStats {
|
|||||||
validRTTs := make([]time.Duration, 0)
|
validRTTs := make([]time.Duration, 0)
|
||||||
for _, rtt := range h.rtts {
|
for _, rtt := range h.rtts {
|
||||||
switch {
|
switch {
|
||||||
case rtt.value == rttUntested || time.Since(rtt.time) > h.validity:
|
case rtt.value == 0 || time.Since(rtt.time) > h.validity:
|
||||||
continue
|
continue
|
||||||
case rtt.value == rttFailed:
|
case rtt.value == rttFailed:
|
||||||
stats.Fail++
|
stats.Fail++
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/utils"
|
|
||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
"github.com/xtls/xray-core/transport/internet/tagged"
|
"github.com/xtls/xray-core/transport/internet/tagged"
|
||||||
)
|
)
|
||||||
@@ -62,7 +61,6 @@ func (s *pingClient) MeasureDelay(httpMethod string) (time.Duration, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return rttFailed, err
|
return rttFailed, err
|
||||||
}
|
}
|
||||||
utils.TryDefaultHeadersWith(req.Header, "nav")
|
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
resp, err := s.httpClient.Do(req)
|
resp, err := s.httpClient.Do(req)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/observatory/command/command.proto
|
// source: app/observatory/command/command.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -23,9 +22,9 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type GetOutboundStatusRequest struct {
|
type GetOutboundStatusRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetOutboundStatusRequest) Reset() {
|
func (x *GetOutboundStatusRequest) Reset() {
|
||||||
@@ -59,10 +58,11 @@ func (*GetOutboundStatusRequest) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetOutboundStatusResponse struct {
|
type GetOutboundStatusResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Status *observatory.ObservationResult `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Status *observatory.ObservationResult `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetOutboundStatusResponse) Reset() {
|
func (x *GetOutboundStatusResponse) Reset() {
|
||||||
@@ -103,9 +103,9 @@ func (x *GetOutboundStatusResponse) GetStatus() *observatory.ObservationResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -140,25 +140,52 @@ func (*Config) Descriptor() ([]byte, []int) {
|
|||||||
|
|
||||||
var File_app_observatory_command_command_proto protoreflect.FileDescriptor
|
var File_app_observatory_command_command_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_observatory_command_command_proto_rawDesc = "" +
|
var file_app_observatory_command_command_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x25, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
|
||||||
"%app/observatory/command/command.proto\x12!xray.core.app.observatory.command\x1a\x1capp/observatory/config.proto\"\x1a\n" +
|
0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
||||||
"\x18GetOutboundStatusRequest\"a\n" +
|
0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x21, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||||
"\x19GetOutboundStatusResponse\x12D\n" +
|
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
|
||||||
"\x06status\x18\x01 \x01(\v2,.xray.core.app.observatory.ObservationResultR\x06status\"\b\n" +
|
0x72, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x1c, 0x61, 0x70, 0x70, 0x2f,
|
||||||
"\x06Config2\xa7\x01\n" +
|
0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x63, 0x6f, 0x6e, 0x66,
|
||||||
"\x12ObservatoryService\x12\x90\x01\n" +
|
0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1a, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x4f,
|
||||||
"\x11GetOutboundStatus\x12;.xray.core.app.observatory.command.GetOutboundStatusRequest\x1a<.xray.core.app.observatory.command.GetOutboundStatusResponse\"\x00B\x80\x01\n" +
|
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71,
|
||||||
"%com.xray.core.app.observatory.commandP\x01Z1github.com/xtls/xray-core/app/observatory/command\xaa\x02!Xray.Core.App.Observatory.Commandb\x06proto3"
|
0x75, 0x65, 0x73, 0x74, 0x22, 0x61, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f,
|
||||||
|
0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
|
0x65, 0x12, 0x44, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
|
0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
|
||||||
|
0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x4f, 0x62,
|
||||||
|
0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52,
|
||||||
|
0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||||
|
0x67, 0x32, 0xa7, 0x01, 0x0a, 0x12, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
|
||||||
|
0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x90, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74,
|
||||||
|
0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3b,
|
||||||
|
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f,
|
||||||
|
0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
||||||
|
0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74,
|
||||||
|
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3c, 0x2e, 0x78, 0x72,
|
||||||
|
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65,
|
||||||
|
0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
|
||||||
|
0x47, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75,
|
||||||
|
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x80, 0x01, 0x0a, 0x25,
|
||||||
|
0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
|
||||||
|
0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x6f,
|
||||||
|
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x31, 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, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
|
||||||
|
0x72, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x21, 0x58, 0x72, 0x61,
|
||||||
|
0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72,
|
||||||
|
0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06,
|
||||||
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_app_observatory_command_command_proto_rawDescOnce sync.Once
|
file_app_observatory_command_command_proto_rawDescOnce sync.Once
|
||||||
file_app_observatory_command_command_proto_rawDescData []byte
|
file_app_observatory_command_command_proto_rawDescData = file_app_observatory_command_command_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_observatory_command_command_proto_rawDescGZIP() []byte {
|
func file_app_observatory_command_command_proto_rawDescGZIP() []byte {
|
||||||
file_app_observatory_command_command_proto_rawDescOnce.Do(func() {
|
file_app_observatory_command_command_proto_rawDescOnce.Do(func() {
|
||||||
file_app_observatory_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_observatory_command_command_proto_rawDesc), len(file_app_observatory_command_command_proto_rawDesc)))
|
file_app_observatory_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_observatory_command_command_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_observatory_command_command_proto_rawDescData
|
return file_app_observatory_command_command_proto_rawDescData
|
||||||
}
|
}
|
||||||
@@ -190,7 +217,7 @@ func file_app_observatory_command_command_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_observatory_command_command_proto_rawDesc), len(file_app_observatory_command_command_proto_rawDesc)),
|
RawDescriptor: file_app_observatory_command_command_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 3,
|
NumMessages: 3,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
@@ -201,6 +228,7 @@ func file_app_observatory_command_command_proto_init() {
|
|||||||
MessageInfos: file_app_observatory_command_command_proto_msgTypes,
|
MessageInfos: file_app_observatory_command_command_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_observatory_command_command_proto = out.File
|
File_app_observatory_command_command_proto = out.File
|
||||||
|
file_app_observatory_command_command_proto_rawDesc = nil
|
||||||
file_app_observatory_command_command_proto_goTypes = nil
|
file_app_observatory_command_command_proto_goTypes = nil
|
||||||
file_app_observatory_command_command_proto_depIdxs = nil
|
file_app_observatory_command_command_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.6.0
|
// - protoc-gen-go-grpc v1.5.1
|
||||||
// - protoc v6.33.5
|
// - protoc v5.28.2
|
||||||
// source: app/observatory/command/command.proto
|
// source: app/observatory/command/command.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
@@ -63,7 +63,7 @@ type ObservatoryServiceServer interface {
|
|||||||
type UnimplementedObservatoryServiceServer struct{}
|
type UnimplementedObservatoryServiceServer struct{}
|
||||||
|
|
||||||
func (UnimplementedObservatoryServiceServer) GetOutboundStatus(context.Context, *GetOutboundStatusRequest) (*GetOutboundStatusResponse, error) {
|
func (UnimplementedObservatoryServiceServer) GetOutboundStatus(context.Context, *GetOutboundStatusRequest) (*GetOutboundStatusResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method GetOutboundStatus not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetOutboundStatus not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedObservatoryServiceServer) mustEmbedUnimplementedObservatoryServiceServer() {}
|
func (UnimplementedObservatoryServiceServer) mustEmbedUnimplementedObservatoryServiceServer() {}
|
||||||
func (UnimplementedObservatoryServiceServer) testEmbeddedByValue() {}
|
func (UnimplementedObservatoryServiceServer) testEmbeddedByValue() {}
|
||||||
@@ -76,7 +76,7 @@ type UnsafeObservatoryServiceServer interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RegisterObservatoryServiceServer(s grpc.ServiceRegistrar, srv ObservatoryServiceServer) {
|
func RegisterObservatoryServiceServer(s grpc.ServiceRegistrar, srv ObservatoryServiceServer) {
|
||||||
// If the following call panics, it indicates UnimplementedObservatoryServiceServer was
|
// If the following call pancis, it indicates UnimplementedObservatoryServiceServer was
|
||||||
// embedded by pointer and is nil. This will cause panics if an
|
// embedded by pointer and is nil. This will cause panics if an
|
||||||
// unimplemented method is ever invoked, so we test this at initialization
|
// unimplemented method is ever invoked, so we test this at initialization
|
||||||
// time to prevent it from happening at runtime later due to I/O.
|
// time to prevent it from happening at runtime later due to I/O.
|
||||||
|
|||||||
+104
-64
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/observatory/config.proto
|
// source: app/observatory/config.proto
|
||||||
|
|
||||||
package observatory
|
package observatory
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -22,10 +21,11 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ObservationResult struct {
|
type ObservationResult struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Status []*OutboundStatus `protobuf:"bytes,1,rep,name=status,proto3" json:"status,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Status []*OutboundStatus `protobuf:"bytes,1,rep,name=status,proto3" json:"status,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ObservationResult) Reset() {
|
func (x *ObservationResult) Reset() {
|
||||||
@@ -66,15 +66,16 @@ func (x *ObservationResult) GetStatus() []*OutboundStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HealthPingMeasurementResult struct {
|
type HealthPingMeasurementResult struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
All int64 `protobuf:"varint,1,opt,name=all,proto3" json:"all,omitempty"`
|
|
||||||
Fail int64 `protobuf:"varint,2,opt,name=fail,proto3" json:"fail,omitempty"`
|
|
||||||
Deviation int64 `protobuf:"varint,3,opt,name=deviation,proto3" json:"deviation,omitempty"`
|
|
||||||
Average int64 `protobuf:"varint,4,opt,name=average,proto3" json:"average,omitempty"`
|
|
||||||
Max int64 `protobuf:"varint,5,opt,name=max,proto3" json:"max,omitempty"`
|
|
||||||
Min int64 `protobuf:"varint,6,opt,name=min,proto3" json:"min,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
All int64 `protobuf:"varint,1,opt,name=all,proto3" json:"all,omitempty"`
|
||||||
|
Fail int64 `protobuf:"varint,2,opt,name=fail,proto3" json:"fail,omitempty"`
|
||||||
|
Deviation int64 `protobuf:"varint,3,opt,name=deviation,proto3" json:"deviation,omitempty"`
|
||||||
|
Average int64 `protobuf:"varint,4,opt,name=average,proto3" json:"average,omitempty"`
|
||||||
|
Max int64 `protobuf:"varint,5,opt,name=max,proto3" json:"max,omitempty"`
|
||||||
|
Min int64 `protobuf:"varint,6,opt,name=min,proto3" json:"min,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *HealthPingMeasurementResult) Reset() {
|
func (x *HealthPingMeasurementResult) Reset() {
|
||||||
@@ -150,7 +151,10 @@ func (x *HealthPingMeasurementResult) GetMin() int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OutboundStatus struct {
|
type OutboundStatus struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// @Document Whether this outbound is usable
|
// @Document Whether this outbound is usable
|
||||||
// @Restriction ReadOnlyForUser
|
// @Restriction ReadOnlyForUser
|
||||||
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
|
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
|
||||||
@@ -169,10 +173,8 @@ type OutboundStatus struct {
|
|||||||
LastSeenTime int64 `protobuf:"varint,5,opt,name=last_seen_time,json=lastSeenTime,proto3" json:"last_seen_time,omitempty"`
|
LastSeenTime int64 `protobuf:"varint,5,opt,name=last_seen_time,json=lastSeenTime,proto3" json:"last_seen_time,omitempty"`
|
||||||
// @Document The time this outbound is tried
|
// @Document The time this outbound is tried
|
||||||
// @Type id.outboundTag
|
// @Type id.outboundTag
|
||||||
LastTryTime int64 `protobuf:"varint,6,opt,name=last_try_time,json=lastTryTime,proto3" json:"last_try_time,omitempty"`
|
LastTryTime int64 `protobuf:"varint,6,opt,name=last_try_time,json=lastTryTime,proto3" json:"last_try_time,omitempty"`
|
||||||
HealthPing *HealthPingMeasurementResult `protobuf:"bytes,7,opt,name=health_ping,json=healthPing,proto3" json:"health_ping,omitempty"`
|
HealthPing *HealthPingMeasurementResult `protobuf:"bytes,7,opt,name=health_ping,json=healthPing,proto3" json:"health_ping,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OutboundStatus) Reset() {
|
func (x *OutboundStatus) Reset() {
|
||||||
@@ -255,7 +257,10 @@ func (x *OutboundStatus) GetHealthPing() *HealthPingMeasurementResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ProbeResult struct {
|
type ProbeResult struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// @Document Whether this outbound is usable
|
// @Document Whether this outbound is usable
|
||||||
// @Restriction ReadOnlyForUser
|
// @Restriction ReadOnlyForUser
|
||||||
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
|
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
|
||||||
@@ -266,8 +271,6 @@ type ProbeResult struct {
|
|||||||
// @Document The error caused this outbound failed to relay probe request
|
// @Document The error caused this outbound failed to relay probe request
|
||||||
// @Restriction NotMachineReadable
|
// @Restriction NotMachineReadable
|
||||||
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
|
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ProbeResult) Reset() {
|
func (x *ProbeResult) Reset() {
|
||||||
@@ -322,12 +325,13 @@ func (x *ProbeResult) GetLastErrorReason() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Intensity struct {
|
type Intensity struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// @Document The time interval for a probe request in ms.
|
// @Document The time interval for a probe request in ms.
|
||||||
// @Type time.ms
|
// @Type time.ms
|
||||||
ProbeInterval uint32 `protobuf:"varint,1,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
|
ProbeInterval uint32 `protobuf:"varint,1,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Intensity) Reset() {
|
func (x *Intensity) Reset() {
|
||||||
@@ -368,14 +372,15 @@ func (x *Intensity) GetProbeInterval() uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// @Document The selectors for outbound under observation
|
// @Document The selectors for outbound under observation
|
||||||
SubjectSelector []string `protobuf:"bytes,2,rep,name=subject_selector,json=subjectSelector,proto3" json:"subject_selector,omitempty"`
|
SubjectSelector []string `protobuf:"bytes,2,rep,name=subject_selector,json=subjectSelector,proto3" json:"subject_selector,omitempty"`
|
||||||
ProbeUrl string `protobuf:"bytes,3,opt,name=probe_url,json=probeUrl,proto3" json:"probe_url,omitempty"`
|
ProbeUrl string `protobuf:"bytes,3,opt,name=probe_url,json=probeUrl,proto3" json:"probe_url,omitempty"`
|
||||||
ProbeInterval int64 `protobuf:"varint,4,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
|
ProbeInterval int64 `protobuf:"varint,4,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
|
||||||
EnableConcurrency bool `protobuf:"varint,5,opt,name=enable_concurrency,json=enableConcurrency,proto3" json:"enable_concurrency,omitempty"`
|
EnableConcurrency bool `protobuf:"varint,5,opt,name=enable_concurrency,json=enableConcurrency,proto3" json:"enable_concurrency,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -438,48 +443,82 @@ func (x *Config) GetEnableConcurrency() bool {
|
|||||||
|
|
||||||
var File_app_observatory_config_proto protoreflect.FileDescriptor
|
var File_app_observatory_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_observatory_config_proto_rawDesc = "" +
|
var file_app_observatory_config_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x1c, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
|
||||||
"\x1capp/observatory/config.proto\x12\x19xray.core.app.observatory\"V\n" +
|
0x79, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19,
|
||||||
"\x11ObservationResult\x12A\n" +
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62,
|
||||||
"\x06status\x18\x01 \x03(\v2).xray.core.app.observatory.OutboundStatusR\x06status\"\x9f\x01\n" +
|
0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x22, 0x56, 0x0a, 0x11, 0x4f, 0x62, 0x73,
|
||||||
"\x1bHealthPingMeasurementResult\x12\x10\n" +
|
0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x41,
|
||||||
"\x03all\x18\x01 \x01(\x03R\x03all\x12\x12\n" +
|
0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29,
|
||||||
"\x04fail\x18\x02 \x01(\x03R\x04fail\x12\x1c\n" +
|
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f,
|
||||||
"\tdeviation\x18\x03 \x01(\x03R\tdeviation\x12\x18\n" +
|
0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f,
|
||||||
"\aaverage\x18\x04 \x01(\x03R\aaverage\x12\x10\n" +
|
0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
|
||||||
"\x03max\x18\x05 \x01(\x03R\x03max\x12\x10\n" +
|
0x73, 0x22, 0x9f, 0x01, 0x0a, 0x1b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67,
|
||||||
"\x03min\x18\x06 \x01(\x03R\x03min\"\xae\x02\n" +
|
0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c,
|
||||||
"\x0eOutboundStatus\x12\x14\n" +
|
0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03,
|
||||||
"\x05alive\x18\x01 \x01(\bR\x05alive\x12\x14\n" +
|
0x61, 0x6c, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||||
"\x05delay\x18\x02 \x01(\x03R\x05delay\x12*\n" +
|
0x03, 0x52, 0x04, 0x66, 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x61,
|
||||||
"\x11last_error_reason\x18\x03 \x01(\tR\x0flastErrorReason\x12!\n" +
|
0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69,
|
||||||
"\foutbound_tag\x18\x04 \x01(\tR\voutboundTag\x12$\n" +
|
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65,
|
||||||
"\x0elast_seen_time\x18\x05 \x01(\x03R\flastSeenTime\x12\"\n" +
|
0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65, 0x12,
|
||||||
"\rlast_try_time\x18\x06 \x01(\x03R\vlastTryTime\x12W\n" +
|
0x10, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6d, 0x61,
|
||||||
"\vhealth_ping\x18\a \x01(\v26.xray.core.app.observatory.HealthPingMeasurementResultR\n" +
|
0x78, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03,
|
||||||
"healthPing\"e\n" +
|
0x6d, 0x69, 0x6e, 0x22, 0xae, 0x02, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,
|
||||||
"\vProbeResult\x12\x14\n" +
|
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18,
|
||||||
"\x05alive\x18\x01 \x01(\bR\x05alive\x12\x14\n" +
|
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05,
|
||||||
"\x05delay\x18\x02 \x01(\x03R\x05delay\x12*\n" +
|
0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c,
|
||||||
"\x11last_error_reason\x18\x03 \x01(\tR\x0flastErrorReason\"2\n" +
|
0x61, 0x79, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
||||||
"\tIntensity\x12%\n" +
|
0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c,
|
||||||
"\x0eprobe_interval\x18\x01 \x01(\rR\rprobeInterval\"\xa6\x01\n" +
|
0x61, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21,
|
||||||
"\x06Config\x12)\n" +
|
0x0a, 0x0c, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x04,
|
||||||
"\x10subject_selector\x18\x02 \x03(\tR\x0fsubjectSelector\x12\x1b\n" +
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61,
|
||||||
"\tprobe_url\x18\x03 \x01(\tR\bprobeUrl\x12%\n" +
|
0x67, 0x12, 0x24, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x74,
|
||||||
"\x0eprobe_interval\x18\x04 \x01(\x03R\rprobeInterval\x12-\n" +
|
0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53,
|
||||||
"\x12enable_concurrency\x18\x05 \x01(\bR\x11enableConcurrencyB^\n" +
|
0x65, 0x65, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x5f,
|
||||||
"\x18com.xray.app.observatoryP\x01Z)github.com/xtls/xray-core/app/observatory\xaa\x02\x14Xray.App.Observatoryb\x06proto3"
|
0x74, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b,
|
||||||
|
0x6c, 0x61, 0x73, 0x74, 0x54, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x57, 0x0a, 0x0b, 0x68,
|
||||||
|
0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
|
||||||
|
0x32, 0x36, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
|
||||||
|
0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x48, 0x65, 0x61,
|
||||||
|
0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65,
|
||||||
|
0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0a, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68,
|
||||||
|
0x50, 0x69, 0x6e, 0x67, 0x22, 0x65, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x73,
|
||||||
|
0x75, 0x6c, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01,
|
||||||
|
0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c,
|
||||||
|
0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12,
|
||||||
|
0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x72, 0x65,
|
||||||
|
0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c, 0x61, 0x73, 0x74,
|
||||||
|
0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x32, 0x0a, 0x09, 0x49,
|
||||||
|
0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x62,
|
||||||
|
0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
|
||||||
|
0x52, 0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22,
|
||||||
|
0xa6, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75,
|
||||||
|
0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02,
|
||||||
|
0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, 0x6c,
|
||||||
|
0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x75,
|
||||||
|
0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x55,
|
||||||
|
0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65,
|
||||||
|
0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x62,
|
||||||
|
0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x2d, 0x0a, 0x12, 0x65, 0x6e, 0x61,
|
||||||
|
0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18,
|
||||||
|
0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6e,
|
||||||
|
0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x42, 0x5e, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e,
|
||||||
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61,
|
||||||
|
0x74, 0x6f, 0x72, 0x79, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
||||||
|
0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72,
|
||||||
|
0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
|
||||||
|
0x79, 0xaa, 0x02, 0x14, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4f, 0x62, 0x73,
|
||||||
|
0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_app_observatory_config_proto_rawDescOnce sync.Once
|
file_app_observatory_config_proto_rawDescOnce sync.Once
|
||||||
file_app_observatory_config_proto_rawDescData []byte
|
file_app_observatory_config_proto_rawDescData = file_app_observatory_config_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_observatory_config_proto_rawDescGZIP() []byte {
|
func file_app_observatory_config_proto_rawDescGZIP() []byte {
|
||||||
file_app_observatory_config_proto_rawDescOnce.Do(func() {
|
file_app_observatory_config_proto_rawDescOnce.Do(func() {
|
||||||
file_app_observatory_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_observatory_config_proto_rawDesc), len(file_app_observatory_config_proto_rawDesc)))
|
file_app_observatory_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_observatory_config_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_observatory_config_proto_rawDescData
|
return file_app_observatory_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
@@ -512,7 +551,7 @@ func file_app_observatory_config_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_observatory_config_proto_rawDesc), len(file_app_observatory_config_proto_rawDesc)),
|
RawDescriptor: file_app_observatory_config_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 6,
|
NumMessages: 6,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
@@ -523,6 +562,7 @@ func file_app_observatory_config_proto_init() {
|
|||||||
MessageInfos: file_app_observatory_config_proto_msgTypes,
|
MessageInfos: file_app_observatory_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_observatory_config_proto = out.File
|
File_app_observatory_config_proto = out.File
|
||||||
|
file_app_observatory_config_proto_rawDesc = nil
|
||||||
file_app_observatory_config_proto_goTypes = nil
|
file_app_observatory_config_proto_goTypes = nil
|
||||||
file_app_observatory_config_proto_depIdxs = nil
|
file_app_observatory_config_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"slices"
|
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -16,7 +15,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/common/signal/done"
|
"github.com/xtls/xray-core/common/signal/done"
|
||||||
"github.com/xtls/xray-core/common/task"
|
"github.com/xtls/xray-core/common/task"
|
||||||
"github.com/xtls/xray-core/common/utils"
|
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/extension"
|
"github.com/xtls/xray-core/features/extension"
|
||||||
"github.com/xtls/xray-core/features/outbound"
|
"github.com/xtls/xray-core/features/outbound"
|
||||||
@@ -71,7 +69,7 @@ func (o *Observer) background() {
|
|||||||
|
|
||||||
outbounds := hs.Select(o.config.SubjectSelector)
|
outbounds := hs.Select(o.config.SubjectSelector)
|
||||||
|
|
||||||
o.clearRemovedOutbounds(outbounds)
|
o.updateStatus(outbounds)
|
||||||
|
|
||||||
sleepTime := time.Second * 10
|
sleepTime := time.Second * 10
|
||||||
if o.config.ProbeInterval != 0 {
|
if o.config.ProbeInterval != 0 {
|
||||||
@@ -112,19 +110,11 @@ func (o *Observer) background() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Observer) clearRemovedOutbounds(outbounds []string) {
|
func (o *Observer) updateStatus(outbounds []string) {
|
||||||
o.statusLock.Lock()
|
o.statusLock.Lock()
|
||||||
defer o.statusLock.Unlock()
|
defer o.statusLock.Unlock()
|
||||||
if len(o.status) == 0 {
|
// TODO should remove old inbound that is removed
|
||||||
return
|
_ = outbounds
|
||||||
}
|
|
||||||
var pruned []*OutboundStatus
|
|
||||||
for _, status := range o.status {
|
|
||||||
if slices.Contains(outbounds, status.OutboundTag) {
|
|
||||||
pruned = append(pruned, status)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
o.status = pruned
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Observer) probe(outbound string) ProbeResult {
|
func (o *Observer) probe(outbound string) ProbeResult {
|
||||||
@@ -172,9 +162,7 @@ func (o *Observer) probe(outbound string) ProbeResult {
|
|||||||
if o.config.ProbeUrl != "" {
|
if o.config.ProbeUrl != "" {
|
||||||
probeURL = o.config.ProbeUrl
|
probeURL = o.config.ProbeUrl
|
||||||
}
|
}
|
||||||
req, _ := http.NewRequest(http.MethodGet, probeURL, nil)
|
response, err := httpClient.Get(probeURL)
|
||||||
utils.TryDefaultHeadersWith(req.Header, "nav")
|
|
||||||
response, err := httpClient.Do(req)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("outbound failed to relay connection").Base(err)
|
return errors.New("outbound failed to relay connection").Base(err)
|
||||||
}
|
}
|
||||||
@@ -186,7 +174,7 @@ func (o *Observer) probe(outbound string) ProbeResult {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorMessage := "the outbound " + outbound + " is dead: GET request failed:" + err.Error() + "with outbound handler report underlying connection failed"
|
var errorMessage = "the outbound " + outbound + " is dead: GET request failed:" + err.Error() + "with outbound handler report underlying connection failed"
|
||||||
errors.LogInfoInner(o.ctx, errorCollectorForRequest.UnderlyingError(), errorMessage)
|
errors.LogInfoInner(o.ctx, errorCollectorForRequest.UnderlyingError(), errorMessage)
|
||||||
return ProbeResult{Alive: false, LastErrorReason: errorMessage}
|
return ProbeResult{Alive: false, LastErrorReason: errorMessage}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
package observatory
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestObserverUpdateStatusPrunesStaleOutbounds(t *testing.T) {
|
|
||||||
observer := &Observer{
|
|
||||||
status: []*OutboundStatus{
|
|
||||||
{
|
|
||||||
OutboundTag: "keep",
|
|
||||||
Alive: true,
|
|
||||||
Delay: 42,
|
|
||||||
LastErrorReason: "",
|
|
||||||
LastSeenTime: 111,
|
|
||||||
LastTryTime: 222,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
OutboundTag: "drop",
|
|
||||||
Alive: false,
|
|
||||||
Delay: 99999999,
|
|
||||||
LastErrorReason: "probe failed",
|
|
||||||
LastSeenTime: 333,
|
|
||||||
LastTryTime: 444,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
observer.clearRemovedOutbounds([]string{"keep"})
|
|
||||||
|
|
||||||
if len(observer.status) != 1 {
|
|
||||||
t.Fatalf("expected 1 status after pruning, got %d", len(observer.status))
|
|
||||||
}
|
|
||||||
|
|
||||||
got := observer.status[0]
|
|
||||||
if got.OutboundTag != "keep" {
|
|
||||||
t.Fatalf("expected remaining status for keep, got %q", got.OutboundTag)
|
|
||||||
}
|
|
||||||
if !got.Alive {
|
|
||||||
t.Fatal("expected remaining status to preserve Alive field")
|
|
||||||
}
|
|
||||||
if got.Delay != 42 {
|
|
||||||
t.Fatalf("expected remaining status to preserve Delay, got %d", got.Delay)
|
|
||||||
}
|
|
||||||
if got.LastSeenTime != 111 {
|
|
||||||
t.Fatalf("expected remaining status to preserve LastSeenTime, got %d", got.LastSeenTime)
|
|
||||||
}
|
|
||||||
if got.LastTryTime != 222 {
|
|
||||||
t.Fatalf("expected remaining status to preserve LastTryTime, got %d", got.LastTryTime)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestObserverUpdateStatusClearsWhenNoOutboundsRemain(t *testing.T) {
|
|
||||||
observer := &Observer{
|
|
||||||
status: []*OutboundStatus{
|
|
||||||
{OutboundTag: "drop-1"},
|
|
||||||
{OutboundTag: "drop-2"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
observer.clearRemovedOutbounds(nil)
|
|
||||||
|
|
||||||
if len(observer.status) != 0 {
|
|
||||||
t.Fatalf("expected all statuses to be removed, got %d", len(observer.status))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+130
-84
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/policy/config.proto
|
// source: app/policy/config.proto
|
||||||
|
|
||||||
package policy
|
package policy
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -22,10 +21,11 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Second struct {
|
type Second struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Second) Reset() {
|
func (x *Second) Reset() {
|
||||||
@@ -66,12 +66,13 @@ func (x *Second) GetValue() uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Policy struct {
|
type Policy struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Timeout *Policy_Timeout `protobuf:"bytes,1,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
|
||||||
Stats *Policy_Stats `protobuf:"bytes,2,opt,name=stats,proto3" json:"stats,omitempty"`
|
|
||||||
Buffer *Policy_Buffer `protobuf:"bytes,3,opt,name=buffer,proto3" json:"buffer,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Timeout *Policy_Timeout `protobuf:"bytes,1,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
||||||
|
Stats *Policy_Stats `protobuf:"bytes,2,opt,name=stats,proto3" json:"stats,omitempty"`
|
||||||
|
Buffer *Policy_Buffer `protobuf:"bytes,3,opt,name=buffer,proto3" json:"buffer,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Policy) Reset() {
|
func (x *Policy) Reset() {
|
||||||
@@ -126,10 +127,11 @@ func (x *Policy) GetBuffer() *Policy_Buffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SystemPolicy struct {
|
type SystemPolicy struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Stats *SystemPolicy_Stats `protobuf:"bytes,1,opt,name=stats,proto3" json:"stats,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Stats *SystemPolicy_Stats `protobuf:"bytes,1,opt,name=stats,proto3" json:"stats,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SystemPolicy) Reset() {
|
func (x *SystemPolicy) Reset() {
|
||||||
@@ -170,11 +172,12 @@ func (x *SystemPolicy) GetStats() *SystemPolicy_Stats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Level map[uint32]*Policy `protobuf:"bytes,1,rep,name=level,proto3" json:"level,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
|
||||||
System *SystemPolicy `protobuf:"bytes,2,opt,name=system,proto3" json:"system,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Level map[uint32]*Policy `protobuf:"bytes,1,rep,name=level,proto3" json:"level,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
|
System *SystemPolicy `protobuf:"bytes,2,opt,name=system,proto3" json:"system,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -223,13 +226,14 @@ func (x *Config) GetSystem() *SystemPolicy {
|
|||||||
|
|
||||||
// Timeout is a message for timeout settings in various stages, in seconds.
|
// Timeout is a message for timeout settings in various stages, in seconds.
|
||||||
type Policy_Timeout struct {
|
type Policy_Timeout struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Handshake *Second `protobuf:"bytes,1,opt,name=handshake,proto3" json:"handshake,omitempty"`
|
sizeCache protoimpl.SizeCache
|
||||||
ConnectionIdle *Second `protobuf:"bytes,2,opt,name=connection_idle,json=connectionIdle,proto3" json:"connection_idle,omitempty"`
|
unknownFields protoimpl.UnknownFields
|
||||||
UplinkOnly *Second `protobuf:"bytes,3,opt,name=uplink_only,json=uplinkOnly,proto3" json:"uplink_only,omitempty"`
|
|
||||||
DownlinkOnly *Second `protobuf:"bytes,4,opt,name=downlink_only,json=downlinkOnly,proto3" json:"downlink_only,omitempty"`
|
Handshake *Second `protobuf:"bytes,1,opt,name=handshake,proto3" json:"handshake,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
ConnectionIdle *Second `protobuf:"bytes,2,opt,name=connection_idle,json=connectionIdle,proto3" json:"connection_idle,omitempty"`
|
||||||
sizeCache protoimpl.SizeCache
|
UplinkOnly *Second `protobuf:"bytes,3,opt,name=uplink_only,json=uplinkOnly,proto3" json:"uplink_only,omitempty"`
|
||||||
|
DownlinkOnly *Second `protobuf:"bytes,4,opt,name=downlink_only,json=downlinkOnly,proto3" json:"downlink_only,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Policy_Timeout) Reset() {
|
func (x *Policy_Timeout) Reset() {
|
||||||
@@ -291,12 +295,13 @@ func (x *Policy_Timeout) GetDownlinkOnly() *Second {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Policy_Stats struct {
|
type Policy_Stats struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
UserUplink bool `protobuf:"varint,1,opt,name=user_uplink,json=userUplink,proto3" json:"user_uplink,omitempty"`
|
|
||||||
UserDownlink bool `protobuf:"varint,2,opt,name=user_downlink,json=userDownlink,proto3" json:"user_downlink,omitempty"`
|
|
||||||
UserOnline bool `protobuf:"varint,3,opt,name=user_online,json=userOnline,proto3" json:"user_online,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
UserUplink bool `protobuf:"varint,1,opt,name=user_uplink,json=userUplink,proto3" json:"user_uplink,omitempty"`
|
||||||
|
UserDownlink bool `protobuf:"varint,2,opt,name=user_downlink,json=userDownlink,proto3" json:"user_downlink,omitempty"`
|
||||||
|
UserOnline bool `protobuf:"varint,3,opt,name=user_online,json=userOnline,proto3" json:"user_online,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Policy_Stats) Reset() {
|
func (x *Policy_Stats) Reset() {
|
||||||
@@ -351,11 +356,12 @@ func (x *Policy_Stats) GetUserOnline() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Policy_Buffer struct {
|
type Policy_Buffer struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
// Buffer size per connection, in bytes. -1 for unlimited buffer.
|
|
||||||
Connection int32 `protobuf:"varint,1,opt,name=connection,proto3" json:"connection,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
// Buffer size per connection, in bytes. -1 for unlimited buffer.
|
||||||
|
Connection int32 `protobuf:"varint,1,opt,name=connection,proto3" json:"connection,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Policy_Buffer) Reset() {
|
func (x *Policy_Buffer) Reset() {
|
||||||
@@ -396,13 +402,14 @@ func (x *Policy_Buffer) GetConnection() int32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SystemPolicy_Stats struct {
|
type SystemPolicy_Stats struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
InboundUplink bool `protobuf:"varint,1,opt,name=inbound_uplink,json=inboundUplink,proto3" json:"inbound_uplink,omitempty"`
|
sizeCache protoimpl.SizeCache
|
||||||
InboundDownlink bool `protobuf:"varint,2,opt,name=inbound_downlink,json=inboundDownlink,proto3" json:"inbound_downlink,omitempty"`
|
unknownFields protoimpl.UnknownFields
|
||||||
OutboundUplink bool `protobuf:"varint,3,opt,name=outbound_uplink,json=outboundUplink,proto3" json:"outbound_uplink,omitempty"`
|
|
||||||
OutboundDownlink bool `protobuf:"varint,4,opt,name=outbound_downlink,json=outboundDownlink,proto3" json:"outbound_downlink,omitempty"`
|
InboundUplink bool `protobuf:"varint,1,opt,name=inbound_uplink,json=inboundUplink,proto3" json:"inbound_uplink,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
InboundDownlink bool `protobuf:"varint,2,opt,name=inbound_downlink,json=inboundDownlink,proto3" json:"inbound_downlink,omitempty"`
|
||||||
sizeCache protoimpl.SizeCache
|
OutboundUplink bool `protobuf:"varint,3,opt,name=outbound_uplink,json=outboundUplink,proto3" json:"outbound_uplink,omitempty"`
|
||||||
|
OutboundDownlink bool `protobuf:"varint,4,opt,name=outbound_downlink,json=outboundDownlink,proto3" json:"outbound_downlink,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SystemPolicy_Stats) Reset() {
|
func (x *SystemPolicy_Stats) Reset() {
|
||||||
@@ -465,55 +472,93 @@ func (x *SystemPolicy_Stats) GetOutboundDownlink() bool {
|
|||||||
|
|
||||||
var File_app_policy_config_proto protoreflect.FileDescriptor
|
var File_app_policy_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_policy_config_proto_rawDesc = "" +
|
var file_app_policy_config_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2f, 0x63, 0x6f, 0x6e,
|
||||||
"\x17app/policy/config.proto\x12\x0fxray.app.policy\"\x1e\n" +
|
0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
"\x06Second\x12\x14\n" +
|
0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x1e, 0x0a, 0x06, 0x53, 0x65,
|
||||||
"\x05value\x18\x01 \x01(\rR\x05value\"\xc7\x04\n" +
|
0x63, 0x6f, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20,
|
||||||
"\x06Policy\x129\n" +
|
0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xc7, 0x04, 0x0a, 0x06, 0x50,
|
||||||
"\atimeout\x18\x01 \x01(\v2\x1f.xray.app.policy.Policy.TimeoutR\atimeout\x123\n" +
|
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x39, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
|
||||||
"\x05stats\x18\x02 \x01(\v2\x1d.xray.app.policy.Policy.StatsR\x05stats\x126\n" +
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||||
"\x06buffer\x18\x03 \x01(\v2\x1e.xray.app.policy.Policy.BufferR\x06buffer\x1a\xfa\x01\n" +
|
0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
|
||||||
"\aTimeout\x125\n" +
|
0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
|
||||||
"\thandshake\x18\x01 \x01(\v2\x17.xray.app.policy.SecondR\thandshake\x12@\n" +
|
0x12, 0x33, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||||
"\x0fconnection_idle\x18\x02 \x01(\v2\x17.xray.app.policy.SecondR\x0econnectionIdle\x128\n" +
|
0x1d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63,
|
||||||
"\vuplink_only\x18\x03 \x01(\v2\x17.xray.app.policy.SecondR\n" +
|
0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05,
|
||||||
"uplinkOnly\x12<\n" +
|
0x73, 0x74, 0x61, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x06, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x18,
|
||||||
"\rdownlink_only\x18\x04 \x01(\v2\x17.xray.app.policy.SecondR\fdownlinkOnly\x1an\n" +
|
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
"\x05Stats\x12\x1f\n" +
|
0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x42,
|
||||||
"\vuser_uplink\x18\x01 \x01(\bR\n" +
|
0x75, 0x66, 0x66, 0x65, 0x72, 0x52, 0x06, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x1a, 0xfa, 0x01,
|
||||||
"userUplink\x12#\n" +
|
0x0a, 0x07, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x68, 0x61, 0x6e,
|
||||||
"\ruser_downlink\x18\x02 \x01(\bR\fuserDownlink\x12\x1f\n" +
|
0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x78,
|
||||||
"\vuser_online\x18\x03 \x01(\bR\n" +
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53,
|
||||||
"userOnline\x1a(\n" +
|
0x65, 0x63, 0x6f, 0x6e, 0x64, 0x52, 0x09, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65,
|
||||||
"\x06Buffer\x12\x1e\n" +
|
0x12, 0x40, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69,
|
||||||
"\n" +
|
0x64, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
"connection\x18\x01 \x01(\x05R\n" +
|
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x63, 0x6f,
|
||||||
"connection\"\xfb\x01\n" +
|
0x6e, 0x64, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64,
|
||||||
"\fSystemPolicy\x129\n" +
|
0x6c, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6f, 0x6e, 0x6c,
|
||||||
"\x05stats\x18\x01 \x01(\v2#.xray.app.policy.SystemPolicy.StatsR\x05stats\x1a\xaf\x01\n" +
|
0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
|
||||||
"\x05Stats\x12%\n" +
|
0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64,
|
||||||
"\x0einbound_uplink\x18\x01 \x01(\bR\rinboundUplink\x12)\n" +
|
0x52, 0x0a, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x3c, 0x0a, 0x0d,
|
||||||
"\x10inbound_downlink\x18\x02 \x01(\bR\x0finboundDownlink\x12'\n" +
|
0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x04, 0x20,
|
||||||
"\x0foutbound_uplink\x18\x03 \x01(\bR\x0eoutboundUplink\x12+\n" +
|
0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
|
||||||
"\x11outbound_downlink\x18\x04 \x01(\bR\x10outboundDownlink\"\xcc\x01\n" +
|
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x52, 0x0c, 0x64, 0x6f,
|
||||||
"\x06Config\x128\n" +
|
0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4f, 0x6e, 0x6c, 0x79, 0x1a, 0x6e, 0x0a, 0x05, 0x53, 0x74,
|
||||||
"\x05level\x18\x01 \x03(\v2\".xray.app.policy.Config.LevelEntryR\x05level\x125\n" +
|
0x61, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x75, 0x70, 0x6c, 0x69,
|
||||||
"\x06system\x18\x02 \x01(\v2\x1d.xray.app.policy.SystemPolicyR\x06system\x1aQ\n" +
|
0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x55, 0x70,
|
||||||
"\n" +
|
0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x77,
|
||||||
"LevelEntry\x12\x10\n" +
|
0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x73, 0x65,
|
||||||
"\x03key\x18\x01 \x01(\rR\x03key\x12-\n" +
|
0x72, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65,
|
||||||
"\x05value\x18\x02 \x01(\v2\x17.xray.app.policy.PolicyR\x05value:\x028\x01BO\n" +
|
0x72, 0x5f, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a,
|
||||||
"\x13com.xray.app.policyP\x01Z$github.com/xtls/xray-core/app/policy\xaa\x02\x0fXray.App.Policyb\x06proto3"
|
0x75, 0x73, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x1a, 0x28, 0x0a, 0x06, 0x42, 0x75,
|
||||||
|
0x66, 0x66, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
|
||||||
|
0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||||
|
0x74, 0x69, 0x6f, 0x6e, 0x22, 0xfb, 0x01, 0x0a, 0x0c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x50,
|
||||||
|
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x39, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01,
|
||||||
|
0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||||
|
0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x50, 0x6f, 0x6c,
|
||||||
|
0x69, 0x63, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73,
|
||||||
|
0x1a, 0xaf, 0x01, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e,
|
||||||
|
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01,
|
||||||
|
0x28, 0x08, 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x70, 0x6c, 0x69, 0x6e,
|
||||||
|
0x6b, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x64, 0x6f, 0x77,
|
||||||
|
0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x6e, 0x62,
|
||||||
|
0x6f, 0x75, 0x6e, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x27, 0x0a, 0x0f,
|
||||||
|
0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x18,
|
||||||
|
0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55,
|
||||||
|
0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e,
|
||||||
|
0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08,
|
||||||
|
0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69,
|
||||||
|
0x6e, 0x6b, 0x22, 0xcc, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x38, 0x0a,
|
||||||
|
0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78,
|
||||||
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x43,
|
||||||
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79,
|
||||||
|
0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x35, 0x0a, 0x06, 0x73, 0x79, 0x73, 0x74, 0x65,
|
||||||
|
0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
|
||||||
|
0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d,
|
||||||
|
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x06, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x1a, 0x51,
|
||||||
|
0x0a, 0x0a, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
|
||||||
|
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d,
|
||||||
|
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
|
||||||
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
|
||||||
|
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
|
||||||
|
0x01, 0x42, 0x4f, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||||
|
0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 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, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
|
||||||
|
0xaa, 0x02, 0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x6f, 0x6c, 0x69,
|
||||||
|
0x63, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_app_policy_config_proto_rawDescOnce sync.Once
|
file_app_policy_config_proto_rawDescOnce sync.Once
|
||||||
file_app_policy_config_proto_rawDescData []byte
|
file_app_policy_config_proto_rawDescData = file_app_policy_config_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_policy_config_proto_rawDescGZIP() []byte {
|
func file_app_policy_config_proto_rawDescGZIP() []byte {
|
||||||
file_app_policy_config_proto_rawDescOnce.Do(func() {
|
file_app_policy_config_proto_rawDescOnce.Do(func() {
|
||||||
file_app_policy_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_policy_config_proto_rawDesc), len(file_app_policy_config_proto_rawDesc)))
|
file_app_policy_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_policy_config_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_policy_config_proto_rawDescData
|
return file_app_policy_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
@@ -558,7 +603,7 @@ func file_app_policy_config_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_policy_config_proto_rawDesc), len(file_app_policy_config_proto_rawDesc)),
|
RawDescriptor: file_app_policy_config_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 9,
|
NumMessages: 9,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
@@ -569,6 +614,7 @@ func file_app_policy_config_proto_init() {
|
|||||||
MessageInfos: file_app_policy_config_proto_msgTypes,
|
MessageInfos: file_app_policy_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_policy_config_proto = out.File
|
File_app_policy_config_proto = out.File
|
||||||
|
file_app_policy_config_proto_rawDesc = nil
|
||||||
file_app_policy_config_proto_goTypes = nil
|
file_app_policy_config_proto_goTypes = nil
|
||||||
file_app_policy_config_proto_depIdxs = nil
|
file_app_policy_config_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ func (s *handlerServer) GetInboundUsers(ctx context.Context, request *GetInbound
|
|||||||
if len(request.Email) > 0 {
|
if len(request.Email) > 0 {
|
||||||
return &GetInboundUserResponse{Users: []*protocol.User{protocol.ToProtoUser(um.GetUser(ctx, request.Email))}}, nil
|
return &GetInboundUserResponse{Users: []*protocol.User{protocol.ToProtoUser(um.GetUser(ctx, request.Email))}}, nil
|
||||||
}
|
}
|
||||||
result := make([]*protocol.User, 0, 100)
|
var result = make([]*protocol.User, 0, 100)
|
||||||
users := um.GetUsers(ctx)
|
users := um.GetUsers(ctx)
|
||||||
for _, u := range users {
|
for _, u := range users {
|
||||||
result = append(result, protocol.ToProtoUser(u))
|
result = append(result, protocol.ToProtoUser(u))
|
||||||
|
|||||||
+249
-124
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/proxyman/command/command.proto
|
// source: app/proxyman/command/command.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
@@ -14,7 +14,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -25,10 +24,11 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type AddUserOperation struct {
|
type AddUserOperation struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
User *protocol.User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
User *protocol.User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddUserOperation) Reset() {
|
func (x *AddUserOperation) Reset() {
|
||||||
@@ -69,10 +69,11 @@ func (x *AddUserOperation) GetUser() *protocol.User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RemoveUserOperation struct {
|
type RemoveUserOperation struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveUserOperation) Reset() {
|
func (x *RemoveUserOperation) Reset() {
|
||||||
@@ -113,10 +114,11 @@ func (x *RemoveUserOperation) GetEmail() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AddInboundRequest struct {
|
type AddInboundRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Inbound *core.InboundHandlerConfig `protobuf:"bytes,1,opt,name=inbound,proto3" json:"inbound,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Inbound *core.InboundHandlerConfig `protobuf:"bytes,1,opt,name=inbound,proto3" json:"inbound,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddInboundRequest) Reset() {
|
func (x *AddInboundRequest) Reset() {
|
||||||
@@ -157,9 +159,9 @@ func (x *AddInboundRequest) GetInbound() *core.InboundHandlerConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AddInboundResponse struct {
|
type AddInboundResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddInboundResponse) Reset() {
|
func (x *AddInboundResponse) Reset() {
|
||||||
@@ -193,10 +195,11 @@ func (*AddInboundResponse) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RemoveInboundRequest struct {
|
type RemoveInboundRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveInboundRequest) Reset() {
|
func (x *RemoveInboundRequest) Reset() {
|
||||||
@@ -237,9 +240,9 @@ func (x *RemoveInboundRequest) GetTag() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RemoveInboundResponse struct {
|
type RemoveInboundResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveInboundResponse) Reset() {
|
func (x *RemoveInboundResponse) Reset() {
|
||||||
@@ -273,11 +276,12 @@ func (*RemoveInboundResponse) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AlterInboundRequest struct {
|
type AlterInboundRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
Operation *serial.TypedMessage `protobuf:"bytes,2,opt,name=operation,proto3" json:"operation,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
|
Operation *serial.TypedMessage `protobuf:"bytes,2,opt,name=operation,proto3" json:"operation,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AlterInboundRequest) Reset() {
|
func (x *AlterInboundRequest) Reset() {
|
||||||
@@ -325,9 +329,9 @@ func (x *AlterInboundRequest) GetOperation() *serial.TypedMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AlterInboundResponse struct {
|
type AlterInboundResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AlterInboundResponse) Reset() {
|
func (x *AlterInboundResponse) Reset() {
|
||||||
@@ -361,10 +365,11 @@ func (*AlterInboundResponse) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ListInboundsRequest struct {
|
type ListInboundsRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
IsOnlyTags bool `protobuf:"varint,1,opt,name=isOnlyTags,proto3" json:"isOnlyTags,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
IsOnlyTags bool `protobuf:"varint,1,opt,name=isOnlyTags,proto3" json:"isOnlyTags,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ListInboundsRequest) Reset() {
|
func (x *ListInboundsRequest) Reset() {
|
||||||
@@ -405,10 +410,11 @@ func (x *ListInboundsRequest) GetIsOnlyTags() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ListInboundsResponse struct {
|
type ListInboundsResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Inbounds []*core.InboundHandlerConfig `protobuf:"bytes,1,rep,name=inbounds,proto3" json:"inbounds,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Inbounds []*core.InboundHandlerConfig `protobuf:"bytes,1,rep,name=inbounds,proto3" json:"inbounds,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ListInboundsResponse) Reset() {
|
func (x *ListInboundsResponse) Reset() {
|
||||||
@@ -449,11 +455,12 @@ func (x *ListInboundsResponse) GetInbounds() []*core.InboundHandlerConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetInboundUserRequest struct {
|
type GetInboundUserRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
|
Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetInboundUserRequest) Reset() {
|
func (x *GetInboundUserRequest) Reset() {
|
||||||
@@ -501,10 +508,11 @@ func (x *GetInboundUserRequest) GetEmail() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetInboundUserResponse struct {
|
type GetInboundUserResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Users []*protocol.User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Users []*protocol.User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetInboundUserResponse) Reset() {
|
func (x *GetInboundUserResponse) Reset() {
|
||||||
@@ -545,10 +553,11 @@ func (x *GetInboundUserResponse) GetUsers() []*protocol.User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetInboundUsersCountResponse struct {
|
type GetInboundUsersCountResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Count int64 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Count int64 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetInboundUsersCountResponse) Reset() {
|
func (x *GetInboundUsersCountResponse) Reset() {
|
||||||
@@ -589,10 +598,11 @@ func (x *GetInboundUsersCountResponse) GetCount() int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AddOutboundRequest struct {
|
type AddOutboundRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Outbound *core.OutboundHandlerConfig `protobuf:"bytes,1,opt,name=outbound,proto3" json:"outbound,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Outbound *core.OutboundHandlerConfig `protobuf:"bytes,1,opt,name=outbound,proto3" json:"outbound,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddOutboundRequest) Reset() {
|
func (x *AddOutboundRequest) Reset() {
|
||||||
@@ -633,9 +643,9 @@ func (x *AddOutboundRequest) GetOutbound() *core.OutboundHandlerConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AddOutboundResponse struct {
|
type AddOutboundResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddOutboundResponse) Reset() {
|
func (x *AddOutboundResponse) Reset() {
|
||||||
@@ -669,10 +679,11 @@ func (*AddOutboundResponse) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RemoveOutboundRequest struct {
|
type RemoveOutboundRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveOutboundRequest) Reset() {
|
func (x *RemoveOutboundRequest) Reset() {
|
||||||
@@ -713,9 +724,9 @@ func (x *RemoveOutboundRequest) GetTag() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RemoveOutboundResponse struct {
|
type RemoveOutboundResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveOutboundResponse) Reset() {
|
func (x *RemoveOutboundResponse) Reset() {
|
||||||
@@ -749,11 +760,12 @@ func (*RemoveOutboundResponse) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AlterOutboundRequest struct {
|
type AlterOutboundRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
Operation *serial.TypedMessage `protobuf:"bytes,2,opt,name=operation,proto3" json:"operation,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
|
Operation *serial.TypedMessage `protobuf:"bytes,2,opt,name=operation,proto3" json:"operation,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AlterOutboundRequest) Reset() {
|
func (x *AlterOutboundRequest) Reset() {
|
||||||
@@ -801,9 +813,9 @@ func (x *AlterOutboundRequest) GetOperation() *serial.TypedMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AlterOutboundResponse struct {
|
type AlterOutboundResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AlterOutboundResponse) Reset() {
|
func (x *AlterOutboundResponse) Reset() {
|
||||||
@@ -837,9 +849,9 @@ func (*AlterOutboundResponse) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ListOutboundsRequest struct {
|
type ListOutboundsRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ListOutboundsRequest) Reset() {
|
func (x *ListOutboundsRequest) Reset() {
|
||||||
@@ -873,10 +885,11 @@ func (*ListOutboundsRequest) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ListOutboundsResponse struct {
|
type ListOutboundsResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Outbounds []*core.OutboundHandlerConfig `protobuf:"bytes,1,rep,name=outbounds,proto3" json:"outbounds,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Outbounds []*core.OutboundHandlerConfig `protobuf:"bytes,1,rep,name=outbounds,proto3" json:"outbounds,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ListOutboundsResponse) Reset() {
|
func (x *ListOutboundsResponse) Reset() {
|
||||||
@@ -917,9 +930,9 @@ func (x *ListOutboundsResponse) GetOutbounds() []*core.OutboundHandlerConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -954,72 +967,183 @@ func (*Config) Descriptor() ([]byte, []int) {
|
|||||||
|
|
||||||
var File_app_proxyman_command_command_proto protoreflect.FileDescriptor
|
var File_app_proxyman_command_command_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_proxyman_command_command_proto_rawDesc = "" +
|
var file_app_proxyman_command_command_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x22, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f, 0x63,
|
||||||
"\"app/proxyman/command/command.proto\x12\x19xray.app.proxyman.command\x1a\x1acommon/protocol/user.proto\x1a!common/serial/typed_message.proto\x1a\x11core/config.proto\"B\n" +
|
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x70,
|
||||||
"\x10AddUserOperation\x12.\n" +
|
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
|
||||||
"\x04user\x18\x01 \x01(\v2\x1a.xray.common.protocol.UserR\x04user\"+\n" +
|
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a,
|
||||||
"\x13RemoveUserOperation\x12\x14\n" +
|
0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
|
||||||
"\x05email\x18\x01 \x01(\tR\x05email\"N\n" +
|
0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d,
|
||||||
"\x11AddInboundRequest\x129\n" +
|
0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64,
|
||||||
"\ainbound\x18\x01 \x01(\v2\x1f.xray.core.InboundHandlerConfigR\ainbound\"\x14\n" +
|
0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11,
|
||||||
"\x12AddInboundResponse\"(\n" +
|
0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
"\x14RemoveInboundRequest\x12\x10\n" +
|
0x6f, 0x22, 0x42, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72,
|
||||||
"\x03tag\x18\x01 \x01(\tR\x03tag\"\x17\n" +
|
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20,
|
||||||
"\x15RemoveInboundResponse\"g\n" +
|
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
|
||||||
"\x13AlterInboundRequest\x12\x10\n" +
|
0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52,
|
||||||
"\x03tag\x18\x01 \x01(\tR\x03tag\x12>\n" +
|
0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x2b, 0x0a, 0x13, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x55,
|
||||||
"\toperation\x18\x02 \x01(\v2 .xray.common.serial.TypedMessageR\toperation\"\x16\n" +
|
0x73, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05,
|
||||||
"\x14AlterInboundResponse\"5\n" +
|
0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61,
|
||||||
"\x13ListInboundsRequest\x12\x1e\n" +
|
0x69, 0x6c, 0x22, 0x4e, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
|
||||||
"\n" +
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75,
|
||||||
"isOnlyTags\x18\x01 \x01(\bR\n" +
|
0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
"isOnlyTags\"S\n" +
|
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64,
|
||||||
"\x14ListInboundsResponse\x12;\n" +
|
0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75,
|
||||||
"\binbounds\x18\x01 \x03(\v2\x1f.xray.core.InboundHandlerConfigR\binbounds\"?\n" +
|
0x6e, 0x64, 0x22, 0x14, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
|
||||||
"\x15GetInboundUserRequest\x12\x10\n" +
|
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x0a, 0x14, 0x52, 0x65, 0x6d, 0x6f,
|
||||||
"\x03tag\x18\x01 \x01(\tR\x03tag\x12\x14\n" +
|
0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
"\x05email\x18\x02 \x01(\tR\x05email\"J\n" +
|
0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74,
|
||||||
"\x16GetInboundUserResponse\x120\n" +
|
0x61, 0x67, 0x22, 0x17, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f,
|
||||||
"\x05users\x18\x01 \x03(\v2\x1a.xray.common.protocol.UserR\x05users\"4\n" +
|
0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x67, 0x0a, 0x13, 0x41,
|
||||||
"\x1cGetInboundUsersCountResponse\x12\x14\n" +
|
0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||||
"\x05count\x18\x01 \x01(\x03R\x05count\"R\n" +
|
0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
"\x12AddOutboundRequest\x12<\n" +
|
0x03, 0x74, 0x61, 0x67, 0x12, 0x3e, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
|
||||||
"\boutbound\x18\x01 \x01(\v2 .xray.core.OutboundHandlerConfigR\boutbound\"\x15\n" +
|
0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
||||||
"\x13AddOutboundResponse\")\n" +
|
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70,
|
||||||
"\x15RemoveOutboundRequest\x12\x10\n" +
|
0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61,
|
||||||
"\x03tag\x18\x01 \x01(\tR\x03tag\"\x18\n" +
|
0x74, 0x69, 0x6f, 0x6e, 0x22, 0x16, 0x0a, 0x14, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62,
|
||||||
"\x16RemoveOutboundResponse\"h\n" +
|
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x35, 0x0a, 0x13,
|
||||||
"\x14AlterOutboundRequest\x12\x10\n" +
|
0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75,
|
||||||
"\x03tag\x18\x01 \x01(\tR\x03tag\x12>\n" +
|
0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x54, 0x61, 0x67,
|
||||||
"\toperation\x18\x02 \x01(\v2 .xray.common.serial.TypedMessageR\toperation\"\x17\n" +
|
0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x54,
|
||||||
"\x15AlterOutboundResponse\"\x16\n" +
|
0x61, 0x67, 0x73, 0x22, 0x53, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75,
|
||||||
"\x14ListOutboundsRequest\"W\n" +
|
0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x69,
|
||||||
"\x15ListOutboundsResponse\x12>\n" +
|
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e,
|
||||||
"\toutbounds\x18\x01 \x03(\v2 .xray.core.OutboundHandlerConfigR\toutbounds\"\b\n" +
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
|
||||||
"\x06Config2\xae\t\n" +
|
0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08,
|
||||||
"\x0eHandlerService\x12k\n" +
|
0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x22, 0x3f, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x49,
|
||||||
"\n" +
|
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
"AddInbound\x12,.xray.app.proxyman.command.AddInboundRequest\x1a-.xray.app.proxyman.command.AddInboundResponse\"\x00\x12t\n" +
|
0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
|
||||||
"\rRemoveInbound\x12/.xray.app.proxyman.command.RemoveInboundRequest\x1a0.xray.app.proxyman.command.RemoveInboundResponse\"\x00\x12q\n" +
|
0x74, 0x61, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01,
|
||||||
"\fAlterInbound\x12..xray.app.proxyman.command.AlterInboundRequest\x1a/.xray.app.proxyman.command.AlterInboundResponse\"\x00\x12q\n" +
|
0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x4a, 0x0a, 0x16, 0x47, 0x65, 0x74,
|
||||||
"\fListInbounds\x12..xray.app.proxyman.command.ListInboundsRequest\x1a/.xray.app.proxyman.command.ListInboundsResponse\"\x00\x12x\n" +
|
0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
"\x0fGetInboundUsers\x120.xray.app.proxyman.command.GetInboundUserRequest\x1a1.xray.app.proxyman.command.GetInboundUserResponse\"\x00\x12\x83\x01\n" +
|
0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||||
"\x14GetInboundUsersCount\x120.xray.app.proxyman.command.GetInboundUserRequest\x1a7.xray.app.proxyman.command.GetInboundUsersCountResponse\"\x00\x12n\n" +
|
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||||
"\vAddOutbound\x12-.xray.app.proxyman.command.AddOutboundRequest\x1a..xray.app.proxyman.command.AddOutboundResponse\"\x00\x12w\n" +
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05,
|
||||||
"\x0eRemoveOutbound\x120.xray.app.proxyman.command.RemoveOutboundRequest\x1a1.xray.app.proxyman.command.RemoveOutboundResponse\"\x00\x12t\n" +
|
0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x34, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f,
|
||||||
"\rAlterOutbound\x12/.xray.app.proxyman.command.AlterOutboundRequest\x1a0.xray.app.proxyman.command.AlterOutboundResponse\"\x00\x12t\n" +
|
0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73,
|
||||||
"\rListOutbounds\x12/.xray.app.proxyman.command.ListOutboundsRequest\x1a0.xray.app.proxyman.command.ListOutboundsResponse\"\x00Bm\n" +
|
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01,
|
||||||
"\x1dcom.xray.app.proxyman.commandP\x01Z.github.com/xtls/xray-core/app/proxyman/command\xaa\x02\x19Xray.App.Proxyman.Commandb\x06proto3"
|
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, 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, 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, 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,
|
||||||
|
0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55,
|
||||||
|
0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 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, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
|
||||||
|
0x64, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
|
||||||
|
0x83, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73,
|
||||||
|
0x65, 0x72, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 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, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55,
|
||||||
|
0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 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, 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, 0x22, 0x00, 0x12, 0x6e, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62,
|
||||||
|
0x6f, 0x75, 0x6e, 0x64, 0x12, 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, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,
|
||||||
|
0x65, 0x73, 0x74, 0x1a, 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, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
|
0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x77, 0x0a, 0x0e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4f,
|
||||||
|
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 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, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75,
|
||||||
|
0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 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, 0x4f, 0x75, 0x74, 0x62,
|
||||||
|
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x74,
|
||||||
|
0x0a, 0x0d, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 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, 0x41, 0x6c, 0x74, 0x65,
|
||||||
|
0x72, 0x4f, 0x75, 0x74, 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, 0x6c, 0x74,
|
||||||
|
0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||||
|
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 (
|
var (
|
||||||
file_app_proxyman_command_command_proto_rawDescOnce sync.Once
|
file_app_proxyman_command_command_proto_rawDescOnce sync.Once
|
||||||
file_app_proxyman_command_command_proto_rawDescData []byte
|
file_app_proxyman_command_command_proto_rawDescData = file_app_proxyman_command_command_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_proxyman_command_command_proto_rawDescGZIP() []byte {
|
func file_app_proxyman_command_command_proto_rawDescGZIP() []byte {
|
||||||
file_app_proxyman_command_command_proto_rawDescOnce.Do(func() {
|
file_app_proxyman_command_command_proto_rawDescOnce.Do(func() {
|
||||||
file_app_proxyman_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_proxyman_command_command_proto_rawDesc), len(file_app_proxyman_command_command_proto_rawDesc)))
|
file_app_proxyman_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_proxyman_command_command_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_proxyman_command_command_proto_rawDescData
|
return file_app_proxyman_command_command_proto_rawDescData
|
||||||
}
|
}
|
||||||
@@ -1098,7 +1222,7 @@ func file_app_proxyman_command_command_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_proxyman_command_command_proto_rawDesc), len(file_app_proxyman_command_command_proto_rawDesc)),
|
RawDescriptor: file_app_proxyman_command_command_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 22,
|
NumMessages: 22,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
@@ -1109,6 +1233,7 @@ func file_app_proxyman_command_command_proto_init() {
|
|||||||
MessageInfos: file_app_proxyman_command_command_proto_msgTypes,
|
MessageInfos: file_app_proxyman_command_command_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_proxyman_command_command_proto = out.File
|
File_app_proxyman_command_command_proto = out.File
|
||||||
|
file_app_proxyman_command_command_proto_rawDesc = nil
|
||||||
file_app_proxyman_command_command_proto_goTypes = nil
|
file_app_proxyman_command_command_proto_goTypes = nil
|
||||||
file_app_proxyman_command_command_proto_depIdxs = nil
|
file_app_proxyman_command_command_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.6.0
|
// - protoc-gen-go-grpc v1.5.1
|
||||||
// - protoc v6.33.5
|
// - protoc v5.28.2
|
||||||
// source: app/proxyman/command/command.proto
|
// source: app/proxyman/command/command.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
@@ -180,34 +180,34 @@ type HandlerServiceServer interface {
|
|||||||
type UnimplementedHandlerServiceServer struct{}
|
type UnimplementedHandlerServiceServer struct{}
|
||||||
|
|
||||||
func (UnimplementedHandlerServiceServer) AddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error) {
|
func (UnimplementedHandlerServiceServer) AddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method AddInbound not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method AddInbound not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHandlerServiceServer) RemoveInbound(context.Context, *RemoveInboundRequest) (*RemoveInboundResponse, error) {
|
func (UnimplementedHandlerServiceServer) RemoveInbound(context.Context, *RemoveInboundRequest) (*RemoveInboundResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method RemoveInbound not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method RemoveInbound not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHandlerServiceServer) AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error) {
|
func (UnimplementedHandlerServiceServer) AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method AlterInbound not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method AlterInbound not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHandlerServiceServer) ListInbounds(context.Context, *ListInboundsRequest) (*ListInboundsResponse, error) {
|
func (UnimplementedHandlerServiceServer) ListInbounds(context.Context, *ListInboundsRequest) (*ListInboundsResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method ListInbounds not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method ListInbounds not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHandlerServiceServer) GetInboundUsers(context.Context, *GetInboundUserRequest) (*GetInboundUserResponse, error) {
|
func (UnimplementedHandlerServiceServer) GetInboundUsers(context.Context, *GetInboundUserRequest) (*GetInboundUserResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method GetInboundUsers not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetInboundUsers not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHandlerServiceServer) GetInboundUsersCount(context.Context, *GetInboundUserRequest) (*GetInboundUsersCountResponse, error) {
|
func (UnimplementedHandlerServiceServer) GetInboundUsersCount(context.Context, *GetInboundUserRequest) (*GetInboundUsersCountResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method GetInboundUsersCount not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetInboundUsersCount not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHandlerServiceServer) AddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error) {
|
func (UnimplementedHandlerServiceServer) AddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method AddOutbound not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method AddOutbound not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHandlerServiceServer) RemoveOutbound(context.Context, *RemoveOutboundRequest) (*RemoveOutboundResponse, error) {
|
func (UnimplementedHandlerServiceServer) RemoveOutbound(context.Context, *RemoveOutboundRequest) (*RemoveOutboundResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method RemoveOutbound not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method RemoveOutbound not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHandlerServiceServer) AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error) {
|
func (UnimplementedHandlerServiceServer) AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method AlterOutbound not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method AlterOutbound not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHandlerServiceServer) ListOutbounds(context.Context, *ListOutboundsRequest) (*ListOutboundsResponse, error) {
|
func (UnimplementedHandlerServiceServer) ListOutbounds(context.Context, *ListOutboundsRequest) (*ListOutboundsResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method ListOutbounds not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method ListOutbounds not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedHandlerServiceServer) mustEmbedUnimplementedHandlerServiceServer() {}
|
func (UnimplementedHandlerServiceServer) mustEmbedUnimplementedHandlerServiceServer() {}
|
||||||
func (UnimplementedHandlerServiceServer) testEmbeddedByValue() {}
|
func (UnimplementedHandlerServiceServer) testEmbeddedByValue() {}
|
||||||
@@ -220,7 +220,7 @@ type UnsafeHandlerServiceServer interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RegisterHandlerServiceServer(s grpc.ServiceRegistrar, srv HandlerServiceServer) {
|
func RegisterHandlerServiceServer(s grpc.ServiceRegistrar, srv HandlerServiceServer) {
|
||||||
// If the following call panics, it indicates UnimplementedHandlerServiceServer was
|
// If the following call pancis, it indicates UnimplementedHandlerServiceServer was
|
||||||
// embedded by pointer and is nil. This will cause panics if an
|
// embedded by pointer and is nil. This will cause panics if an
|
||||||
// unimplemented method is ever invoked, so we test this at initialization
|
// unimplemented method is ever invoked, so we test this at initialization
|
||||||
// time to prevent it from happening at runtime later due to I/O.
|
// time to prevent it from happening at runtime later due to I/O.
|
||||||
|
|||||||
+19
-30
@@ -1,34 +1,23 @@
|
|||||||
package proxyman
|
package proxyman
|
||||||
|
|
||||||
import (
|
func (s *AllocationStrategy) GetConcurrencyValue() uint32 {
|
||||||
"github.com/xtls/xray-core/common/geodata"
|
if s == nil || s.Concurrency == nil {
|
||||||
"github.com/xtls/xray-core/common/session"
|
return 3
|
||||||
)
|
|
||||||
|
|
||||||
func BuildSniffingRequest(config *SniffingConfig) (session.SniffingRequest, error) {
|
|
||||||
if config == nil {
|
|
||||||
return session.SniffingRequest{}, nil
|
|
||||||
}
|
}
|
||||||
|
return s.Concurrency.Value
|
||||||
request := session.SniffingRequest{
|
}
|
||||||
Enabled: config.Enabled,
|
|
||||||
OverrideDestinationForProtocol: config.DestinationOverride,
|
func (s *AllocationStrategy) GetRefreshValue() uint32 {
|
||||||
MetadataOnly: config.MetadataOnly,
|
if s == nil || s.Refresh == nil {
|
||||||
RouteOnly: config.RouteOnly,
|
return 5
|
||||||
}
|
}
|
||||||
if len(config.DomainsExcluded) > 0 {
|
return s.Refresh.Value
|
||||||
excludeForDomain, err := geodata.DomainReg.BuildDomainMatcher(config.DomainsExcluded)
|
}
|
||||||
if err != nil {
|
|
||||||
return session.SniffingRequest{}, err
|
func (c *ReceiverConfig) GetEffectiveSniffingSettings() *SniffingConfig {
|
||||||
}
|
if c.SniffingSettings != nil {
|
||||||
request.ExcludeForDomain = excludeForDomain
|
return c.SniffingSettings
|
||||||
}
|
}
|
||||||
if len(config.IpsExcluded) > 0 {
|
|
||||||
excludeForIP, err := geodata.IPReg.BuildIPMatcher(config.IpsExcluded)
|
return nil
|
||||||
if err != nil {
|
|
||||||
return session.SniffingRequest{}, err
|
|
||||||
}
|
|
||||||
request.ExcludeForIP = excludeForIP
|
|
||||||
}
|
|
||||||
return request, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
+453
-135
@@ -1,13 +1,12 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/proxyman/config.proto
|
// source: app/proxyman/config.proto
|
||||||
|
|
||||||
package proxyman
|
package proxyman
|
||||||
|
|
||||||
import (
|
import (
|
||||||
geodata "github.com/xtls/xray-core/common/geodata"
|
|
||||||
net "github.com/xtls/xray-core/common/net"
|
net "github.com/xtls/xray-core/common/net"
|
||||||
serial "github.com/xtls/xray-core/common/serial"
|
serial "github.com/xtls/xray-core/common/serial"
|
||||||
internet "github.com/xtls/xray-core/transport/internet"
|
internet "github.com/xtls/xray-core/transport/internet"
|
||||||
@@ -15,7 +14,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -25,10 +23,62 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type AllocationStrategy_Type int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Always allocate all connection handlers.
|
||||||
|
AllocationStrategy_Always AllocationStrategy_Type = 0
|
||||||
|
// Randomly allocate specific range of handlers.
|
||||||
|
AllocationStrategy_Random AllocationStrategy_Type = 1
|
||||||
|
// External. Not supported yet.
|
||||||
|
AllocationStrategy_External AllocationStrategy_Type = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for AllocationStrategy_Type.
|
||||||
|
var (
|
||||||
|
AllocationStrategy_Type_name = map[int32]string{
|
||||||
|
0: "Always",
|
||||||
|
1: "Random",
|
||||||
|
2: "External",
|
||||||
|
}
|
||||||
|
AllocationStrategy_Type_value = map[string]int32{
|
||||||
|
"Always": 0,
|
||||||
|
"Random": 1,
|
||||||
|
"External": 2,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x AllocationStrategy_Type) Enum() *AllocationStrategy_Type {
|
||||||
|
p := new(AllocationStrategy_Type)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x AllocationStrategy_Type) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (AllocationStrategy_Type) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_app_proxyman_config_proto_enumTypes[0].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (AllocationStrategy_Type) Type() protoreflect.EnumType {
|
||||||
|
return &file_app_proxyman_config_proto_enumTypes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x AllocationStrategy_Type) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use AllocationStrategy_Type.Descriptor instead.
|
||||||
|
func (AllocationStrategy_Type) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 0}
|
||||||
|
}
|
||||||
|
|
||||||
type InboundConfig struct {
|
type InboundConfig struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *InboundConfig) Reset() {
|
func (x *InboundConfig) Reset() {
|
||||||
@@ -61,27 +111,92 @@ func (*InboundConfig) Descriptor() ([]byte, []int) {
|
|||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{0}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AllocationStrategy struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Type AllocationStrategy_Type `protobuf:"varint,1,opt,name=type,proto3,enum=xray.app.proxyman.AllocationStrategy_Type" json:"type,omitempty"`
|
||||||
|
// Number of handlers (ports) running in parallel.
|
||||||
|
// Default value is 3 if unset.
|
||||||
|
Concurrency *AllocationStrategy_AllocationStrategyConcurrency `protobuf:"bytes,2,opt,name=concurrency,proto3" json:"concurrency,omitempty"`
|
||||||
|
// Number of minutes before a handler is regenerated.
|
||||||
|
// Default value is 5 if unset.
|
||||||
|
Refresh *AllocationStrategy_AllocationStrategyRefresh `protobuf:"bytes,3,opt,name=refresh,proto3" json:"refresh,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) Reset() {
|
||||||
|
*x = AllocationStrategy{}
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*AllocationStrategy) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use AllocationStrategy.ProtoReflect.Descriptor instead.
|
||||||
|
func (*AllocationStrategy) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) GetType() AllocationStrategy_Type {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return AllocationStrategy_Always
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) GetConcurrency() *AllocationStrategy_AllocationStrategyConcurrency {
|
||||||
|
if x != nil {
|
||||||
|
return x.Concurrency
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy) GetRefresh() *AllocationStrategy_AllocationStrategyRefresh {
|
||||||
|
if x != nil {
|
||||||
|
return x.Refresh
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type SniffingConfig struct {
|
type SniffingConfig struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// Whether or not to enable content sniffing on an inbound connection.
|
// Whether or not to enable content sniffing on an inbound connection.
|
||||||
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
||||||
// Override target destination if sniff'ed protocol is in the given list.
|
// Override target destination if sniff'ed protocol is in the given list.
|
||||||
// Supported values are "http", "tls", "fakedns".
|
// Supported values are "http", "tls", "fakedns".
|
||||||
DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
|
DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
|
||||||
DomainsExcluded []*geodata.DomainRule `protobuf:"bytes,3,rep,name=domains_excluded,json=domainsExcluded,proto3" json:"domains_excluded,omitempty"`
|
DomainsExcluded []string `protobuf:"bytes,3,rep,name=domains_excluded,json=domainsExcluded,proto3" json:"domains_excluded,omitempty"`
|
||||||
IpsExcluded []*geodata.IPRule `protobuf:"bytes,6,rep,name=ips_excluded,json=ipsExcluded,proto3" json:"ips_excluded,omitempty"`
|
|
||||||
// Whether should only try to sniff metadata without waiting for client input.
|
// Whether should only try to sniff metadata without waiting for client input.
|
||||||
// Can be used to support SMTP like protocol where server send the first
|
// Can be used to support SMTP like protocol where server send the first
|
||||||
// message.
|
// message.
|
||||||
MetadataOnly bool `protobuf:"varint,4,opt,name=metadata_only,json=metadataOnly,proto3" json:"metadata_only,omitempty"`
|
MetadataOnly bool `protobuf:"varint,4,opt,name=metadata_only,json=metadataOnly,proto3" json:"metadata_only,omitempty"`
|
||||||
RouteOnly bool `protobuf:"varint,5,opt,name=route_only,json=routeOnly,proto3" json:"route_only,omitempty"`
|
RouteOnly bool `protobuf:"varint,5,opt,name=route_only,json=routeOnly,proto3" json:"route_only,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SniffingConfig) Reset() {
|
func (x *SniffingConfig) Reset() {
|
||||||
*x = SniffingConfig{}
|
*x = SniffingConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -93,7 +208,7 @@ func (x *SniffingConfig) String() string {
|
|||||||
func (*SniffingConfig) ProtoMessage() {}
|
func (*SniffingConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *SniffingConfig) ProtoReflect() protoreflect.Message {
|
func (x *SniffingConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[1]
|
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -106,7 +221,7 @@ func (x *SniffingConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use SniffingConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use SniffingConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*SniffingConfig) Descriptor() ([]byte, []int) {
|
func (*SniffingConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SniffingConfig) GetEnabled() bool {
|
func (x *SniffingConfig) GetEnabled() bool {
|
||||||
@@ -123,20 +238,13 @@ func (x *SniffingConfig) GetDestinationOverride() []string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SniffingConfig) GetDomainsExcluded() []*geodata.DomainRule {
|
func (x *SniffingConfig) GetDomainsExcluded() []string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.DomainsExcluded
|
return x.DomainsExcluded
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SniffingConfig) GetIpsExcluded() []*geodata.IPRule {
|
|
||||||
if x != nil {
|
|
||||||
return x.IpsExcluded
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SniffingConfig) GetMetadataOnly() bool {
|
func (x *SniffingConfig) GetMetadataOnly() bool {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.MetadataOnly
|
return x.MetadataOnly
|
||||||
@@ -152,21 +260,23 @@ func (x *SniffingConfig) GetRouteOnly() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ReceiverConfig struct {
|
type ReceiverConfig struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// PortList specifies the ports which the Receiver should listen on.
|
// PortList specifies the ports which the Receiver should listen on.
|
||||||
PortList *net.PortList `protobuf:"bytes,1,opt,name=port_list,json=portList,proto3" json:"port_list,omitempty"`
|
PortList *net.PortList `protobuf:"bytes,1,opt,name=port_list,json=portList,proto3" json:"port_list,omitempty"`
|
||||||
// Listen specifies the IP address that the Receiver should listen on.
|
// Listen specifies the IP address that the Receiver should listen on.
|
||||||
Listen *net.IPOrDomain `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"`
|
Listen *net.IPOrDomain `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"`
|
||||||
StreamSettings *internet.StreamConfig `protobuf:"bytes,3,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy,proto3" json:"allocation_strategy,omitempty"`
|
||||||
ReceiveOriginalDestination bool `protobuf:"varint,4,opt,name=receive_original_destination,json=receiveOriginalDestination,proto3" json:"receive_original_destination,omitempty"`
|
StreamSettings *internet.StreamConfig `protobuf:"bytes,4,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
||||||
SniffingSettings *SniffingConfig `protobuf:"bytes,6,opt,name=sniffing_settings,json=sniffingSettings,proto3" json:"sniffing_settings,omitempty"`
|
ReceiveOriginalDestination bool `protobuf:"varint,5,opt,name=receive_original_destination,json=receiveOriginalDestination,proto3" json:"receive_original_destination,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
SniffingSettings *SniffingConfig `protobuf:"bytes,7,opt,name=sniffing_settings,json=sniffingSettings,proto3" json:"sniffing_settings,omitempty"`
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReceiverConfig) Reset() {
|
func (x *ReceiverConfig) Reset() {
|
||||||
*x = ReceiverConfig{}
|
*x = ReceiverConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -178,7 +288,7 @@ func (x *ReceiverConfig) String() string {
|
|||||||
func (*ReceiverConfig) ProtoMessage() {}
|
func (*ReceiverConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *ReceiverConfig) ProtoReflect() protoreflect.Message {
|
func (x *ReceiverConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[2]
|
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -191,7 +301,7 @@ func (x *ReceiverConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use ReceiverConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use ReceiverConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*ReceiverConfig) Descriptor() ([]byte, []int) {
|
func (*ReceiverConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{2}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{3}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReceiverConfig) GetPortList() *net.PortList {
|
func (x *ReceiverConfig) GetPortList() *net.PortList {
|
||||||
@@ -208,6 +318,13 @@ func (x *ReceiverConfig) GetListen() *net.IPOrDomain {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *ReceiverConfig) GetAllocationStrategy() *AllocationStrategy {
|
||||||
|
if x != nil {
|
||||||
|
return x.AllocationStrategy
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (x *ReceiverConfig) GetStreamSettings() *internet.StreamConfig {
|
func (x *ReceiverConfig) GetStreamSettings() *internet.StreamConfig {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.StreamSettings
|
return x.StreamSettings
|
||||||
@@ -230,17 +347,18 @@ func (x *ReceiverConfig) GetSniffingSettings() *SniffingConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type InboundHandlerConfig struct {
|
type InboundHandlerConfig struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
sizeCache protoimpl.SizeCache
|
||||||
ReceiverSettings *serial.TypedMessage `protobuf:"bytes,2,opt,name=receiver_settings,json=receiverSettings,proto3" json:"receiver_settings,omitempty"`
|
unknownFields protoimpl.UnknownFields
|
||||||
ProxySettings *serial.TypedMessage `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
sizeCache protoimpl.SizeCache
|
ReceiverSettings *serial.TypedMessage `protobuf:"bytes,2,opt,name=receiver_settings,json=receiverSettings,proto3" json:"receiver_settings,omitempty"`
|
||||||
|
ProxySettings *serial.TypedMessage `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *InboundHandlerConfig) Reset() {
|
func (x *InboundHandlerConfig) Reset() {
|
||||||
*x = InboundHandlerConfig{}
|
*x = InboundHandlerConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -252,7 +370,7 @@ func (x *InboundHandlerConfig) String() string {
|
|||||||
func (*InboundHandlerConfig) ProtoMessage() {}
|
func (*InboundHandlerConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
|
func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[3]
|
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -265,7 +383,7 @@ func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use InboundHandlerConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use InboundHandlerConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*InboundHandlerConfig) Descriptor() ([]byte, []int) {
|
func (*InboundHandlerConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{3}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{4}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *InboundHandlerConfig) GetTag() string {
|
func (x *InboundHandlerConfig) GetTag() string {
|
||||||
@@ -290,14 +408,14 @@ func (x *InboundHandlerConfig) GetProxySettings() *serial.TypedMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OutboundConfig struct {
|
type OutboundConfig struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OutboundConfig) Reset() {
|
func (x *OutboundConfig) Reset() {
|
||||||
*x = OutboundConfig{}
|
*x = OutboundConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -309,7 +427,7 @@ func (x *OutboundConfig) String() string {
|
|||||||
func (*OutboundConfig) ProtoMessage() {}
|
func (*OutboundConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *OutboundConfig) ProtoReflect() protoreflect.Message {
|
func (x *OutboundConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[4]
|
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -322,11 +440,14 @@ func (x *OutboundConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use OutboundConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use OutboundConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*OutboundConfig) Descriptor() ([]byte, []int) {
|
func (*OutboundConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{4}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{5}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SenderConfig struct {
|
type SenderConfig struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// Send traffic through the given IP. Only IP is allowed.
|
// Send traffic through the given IP. Only IP is allowed.
|
||||||
Via *net.IPOrDomain `protobuf:"bytes,1,opt,name=via,proto3" json:"via,omitempty"`
|
Via *net.IPOrDomain `protobuf:"bytes,1,opt,name=via,proto3" json:"via,omitempty"`
|
||||||
StreamSettings *internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
StreamSettings *internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
||||||
@@ -334,13 +455,11 @@ type SenderConfig struct {
|
|||||||
MultiplexSettings *MultiplexingConfig `protobuf:"bytes,4,opt,name=multiplex_settings,json=multiplexSettings,proto3" json:"multiplex_settings,omitempty"`
|
MultiplexSettings *MultiplexingConfig `protobuf:"bytes,4,opt,name=multiplex_settings,json=multiplexSettings,proto3" json:"multiplex_settings,omitempty"`
|
||||||
ViaCidr string `protobuf:"bytes,5,opt,name=via_cidr,json=viaCidr,proto3" json:"via_cidr,omitempty"`
|
ViaCidr string `protobuf:"bytes,5,opt,name=via_cidr,json=viaCidr,proto3" json:"via_cidr,omitempty"`
|
||||||
TargetStrategy internet.DomainStrategy `protobuf:"varint,6,opt,name=target_strategy,json=targetStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"target_strategy,omitempty"`
|
TargetStrategy internet.DomainStrategy `protobuf:"varint,6,opt,name=target_strategy,json=targetStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"target_strategy,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SenderConfig) Reset() {
|
func (x *SenderConfig) Reset() {
|
||||||
*x = SenderConfig{}
|
*x = SenderConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -352,7 +471,7 @@ func (x *SenderConfig) String() string {
|
|||||||
func (*SenderConfig) ProtoMessage() {}
|
func (*SenderConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *SenderConfig) ProtoReflect() protoreflect.Message {
|
func (x *SenderConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[5]
|
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -365,7 +484,7 @@ func (x *SenderConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use SenderConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use SenderConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*SenderConfig) Descriptor() ([]byte, []int) {
|
func (*SenderConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{5}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{6}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SenderConfig) GetVia() *net.IPOrDomain {
|
func (x *SenderConfig) GetVia() *net.IPOrDomain {
|
||||||
@@ -411,7 +530,10 @@ func (x *SenderConfig) GetTargetStrategy() internet.DomainStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MultiplexingConfig struct {
|
type MultiplexingConfig struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// Whether or not Mux is enabled.
|
// Whether or not Mux is enabled.
|
||||||
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
||||||
// Max number of concurrent connections that one Mux connection can handle.
|
// Max number of concurrent connections that one Mux connection can handle.
|
||||||
@@ -420,13 +542,11 @@ type MultiplexingConfig struct {
|
|||||||
XudpConcurrency int32 `protobuf:"varint,3,opt,name=xudpConcurrency,proto3" json:"xudpConcurrency,omitempty"`
|
XudpConcurrency int32 `protobuf:"varint,3,opt,name=xudpConcurrency,proto3" json:"xudpConcurrency,omitempty"`
|
||||||
// "reject" (default), "allow" or "skip".
|
// "reject" (default), "allow" or "skip".
|
||||||
XudpProxyUDP443 string `protobuf:"bytes,4,opt,name=xudpProxyUDP443,proto3" json:"xudpProxyUDP443,omitempty"`
|
XudpProxyUDP443 string `protobuf:"bytes,4,opt,name=xudpProxyUDP443,proto3" json:"xudpProxyUDP443,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *MultiplexingConfig) Reset() {
|
func (x *MultiplexingConfig) Reset() {
|
||||||
*x = MultiplexingConfig{}
|
*x = MultiplexingConfig{}
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
mi := &file_app_proxyman_config_proto_msgTypes[7]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -438,7 +558,7 @@ func (x *MultiplexingConfig) String() string {
|
|||||||
func (*MultiplexingConfig) ProtoMessage() {}
|
func (*MultiplexingConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {
|
func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_proxyman_config_proto_msgTypes[6]
|
mi := &file_app_proxyman_config_proto_msgTypes[7]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -451,7 +571,7 @@ func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use MultiplexingConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use MultiplexingConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*MultiplexingConfig) Descriptor() ([]byte, []int) {
|
func (*MultiplexingConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_app_proxyman_config_proto_rawDescGZIP(), []int{6}
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{7}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *MultiplexingConfig) GetEnabled() bool {
|
func (x *MultiplexingConfig) GetEnabled() bool {
|
||||||
@@ -482,94 +602,290 @@ func (x *MultiplexingConfig) GetXudpProxyUDP443() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AllocationStrategy_AllocationStrategyConcurrency struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) Reset() {
|
||||||
|
*x = AllocationStrategy_AllocationStrategyConcurrency{}
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[8]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*AllocationStrategy_AllocationStrategyConcurrency) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[8]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use AllocationStrategy_AllocationStrategyConcurrency.ProtoReflect.Descriptor instead.
|
||||||
|
func (*AllocationStrategy_AllocationStrategyConcurrency) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyConcurrency) GetValue() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type AllocationStrategy_AllocationStrategyRefresh struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyRefresh) Reset() {
|
||||||
|
*x = AllocationStrategy_AllocationStrategyRefresh{}
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[9]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyRefresh) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*AllocationStrategy_AllocationStrategyRefresh) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyRefresh) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_proxyman_config_proto_msgTypes[9]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use AllocationStrategy_AllocationStrategyRefresh.ProtoReflect.Descriptor instead.
|
||||||
|
func (*AllocationStrategy_AllocationStrategyRefresh) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AllocationStrategy_AllocationStrategyRefresh) GetValue() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
var File_app_proxyman_config_proto protoreflect.FileDescriptor
|
var File_app_proxyman_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_proxyman_config_proto_rawDesc = "" +
|
var file_app_proxyman_config_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x19, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f, 0x63,
|
||||||
"\x19app/proxyman/config.proto\x12\x11xray.app.proxyman\x1a\x18common/net/address.proto\x1a\x15common/net/port.proto\x1a\x1ftransport/internet/config.proto\x1a!common/serial/typed_message.proto\x1a\x1bcommon/geodata/geodat.proto\"\x0f\n" +
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x78, 0x72, 0x61,
|
||||||
"\rInboundConfig\"\xad\x02\n" +
|
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x1a, 0x18,
|
||||||
"\x0eSniffingConfig\x12\x18\n" +
|
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64, 0x72, 0x65,
|
||||||
"\aenabled\x18\x01 \x01(\bR\aenabled\x121\n" +
|
0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||||
"\x14destination_override\x18\x02 \x03(\tR\x13destinationOverride\x12J\n" +
|
0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
|
||||||
"\x10domains_excluded\x18\x03 \x03(\v2\x1f.xray.common.geodata.DomainRuleR\x0fdomainsExcluded\x12>\n" +
|
0x1f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72,
|
||||||
"\fips_excluded\x18\x06 \x03(\v2\x1b.xray.common.geodata.IPRuleR\vipsExcluded\x12#\n" +
|
0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
"\rmetadata_only\x18\x04 \x01(\bR\fmetadataOnly\x12\x1d\n" +
|
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,
|
||||||
"\n" +
|
0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
|
||||||
"route_only\x18\x05 \x01(\bR\trouteOnly\"\xe5\x02\n" +
|
0x6f, 0x74, 0x6f, 0x22, 0x0f, 0x0a, 0x0d, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f,
|
||||||
"\x0eReceiverConfig\x126\n" +
|
0x6e, 0x66, 0x69, 0x67, 0x22, 0xae, 0x03, 0x0a, 0x12, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74,
|
||||||
"\tport_list\x18\x01 \x01(\v2\x19.xray.common.net.PortListR\bportList\x123\n" +
|
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x3e, 0x0a, 0x04, 0x74,
|
||||||
"\x06listen\x18\x02 \x01(\v2\x1b.xray.common.net.IPOrDomainR\x06listen\x12N\n" +
|
0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
"\x0fstream_settings\x18\x03 \x01(\v2%.xray.transport.internet.StreamConfigR\x0estreamSettings\x12@\n" +
|
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c,
|
||||||
"\x1creceive_original_destination\x18\x04 \x01(\bR\x1areceiveOriginalDestination\x12N\n" +
|
0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||||
"\x11sniffing_settings\x18\x06 \x01(\v2!.xray.app.proxyman.SniffingConfigR\x10sniffingSettingsJ\x04\b\x05\x10\x06\"\xc0\x01\n" +
|
0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x65, 0x0a, 0x0b, 0x63,
|
||||||
"\x14InboundHandlerConfig\x12\x10\n" +
|
0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
|
||||||
"\x03tag\x18\x01 \x01(\tR\x03tag\x12M\n" +
|
0x32, 0x43, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
||||||
"\x11receiver_settings\x18\x02 \x01(\v2 .xray.common.serial.TypedMessageR\x10receiverSettings\x12G\n" +
|
0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
|
||||||
"\x0eproxy_settings\x18\x03 \x01(\v2 .xray.common.serial.TypedMessageR\rproxySettings\"\x10\n" +
|
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
||||||
"\x0eOutboundConfig\"\x9d\x03\n" +
|
0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72,
|
||||||
"\fSenderConfig\x12-\n" +
|
0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
|
||||||
"\x03via\x18\x01 \x01(\v2\x1b.xray.common.net.IPOrDomainR\x03via\x12N\n" +
|
0x63, 0x79, 0x12, 0x59, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x18, 0x03, 0x20,
|
||||||
"\x0fstream_settings\x18\x02 \x01(\v2%.xray.transport.internet.StreamConfigR\x0estreamSettings\x12K\n" +
|
0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
|
||||||
"\x0eproxy_settings\x18\x03 \x01(\v2$.xray.transport.internet.ProxyConfigR\rproxySettings\x12T\n" +
|
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
||||||
"\x12multiplex_settings\x18\x04 \x01(\v2%.xray.app.proxyman.MultiplexingConfigR\x11multiplexSettings\x12\x19\n" +
|
0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63,
|
||||||
"\bvia_cidr\x18\x05 \x01(\tR\aviaCidr\x12P\n" +
|
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x65, 0x66,
|
||||||
"\x0ftarget_strategy\x18\x06 \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0etargetStrategy\"\xa4\x01\n" +
|
0x72, 0x65, 0x73, 0x68, 0x52, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x1a, 0x35, 0x0a,
|
||||||
"\x12MultiplexingConfig\x12\x18\n" +
|
0x1d, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74,
|
||||||
"\aenabled\x18\x01 \x01(\bR\aenabled\x12 \n" +
|
0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x14,
|
||||||
"\vconcurrency\x18\x02 \x01(\x05R\vconcurrency\x12(\n" +
|
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76,
|
||||||
"\x0fxudpConcurrency\x18\x03 \x01(\x05R\x0fxudpConcurrency\x12(\n" +
|
0x61, 0x6c, 0x75, 0x65, 0x1a, 0x31, 0x0a, 0x19, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
||||||
"\x0fxudpProxyUDP443\x18\x04 \x01(\tR\x0fxudpProxyUDP443BU\n" +
|
0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73,
|
||||||
"\x15com.xray.app.proxymanP\x01Z&github.com/xtls/xray-core/app/proxyman\xaa\x02\x11Xray.App.Proxymanb\x06proto3"
|
0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
|
||||||
|
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12,
|
||||||
|
0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52,
|
||||||
|
0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72,
|
||||||
|
0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0xcc, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69,
|
||||||
|
0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62,
|
||||||
|
0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c,
|
||||||
|
0x65, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
|
||||||
|
0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
|
||||||
|
0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65,
|
||||||
|
0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73,
|
||||||
|
0x5f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||||
|
0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64,
|
||||||
|
0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6f, 0x6e, 0x6c,
|
||||||
|
0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
|
||||||
|
0x61, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f,
|
||||||
|
0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||||
|
0x4f, 0x6e, 0x6c, 0x79, 0x22, 0xbd, 0x03, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
|
||||||
|
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f,
|
||||||
|
0x6c, 0x69, 0x73, 0x74, 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, 0x50, 0x6f, 0x72,
|
||||||
|
0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12,
|
||||||
|
0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||||
|
0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
|
||||||
|
0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69,
|
||||||
|
0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
||||||
|
0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||||
|
0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
|
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||||
|
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61,
|
||||||
|
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4e, 0x0a, 0x0f,
|
||||||
|
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
|
||||||
|
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
|
||||||
|
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
|
||||||
|
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74,
|
||||||
|
0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x1c,
|
||||||
|
0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
|
||||||
|
0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01,
|
||||||
|
0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69,
|
||||||
|
0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e,
|
||||||
|
0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
|
||||||
|
0x6e, 0x67, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
|
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e,
|
||||||
|
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e,
|
||||||
|
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04,
|
||||||
|
0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
|
||||||
|
0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a,
|
||||||
|
0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12,
|
||||||
|
0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74,
|
||||||
|
0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 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, 0x72, 0x65,
|
||||||
|
0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47,
|
||||||
|
0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
||||||
|
0x18, 0x03, 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, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53,
|
||||||
|
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f,
|
||||||
|
0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x9d, 0x03, 0x0a, 0x0c, 0x53, 0x65,
|
||||||
|
0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x03, 0x76, 0x69,
|
||||||
|
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
||||||
|
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f,
|
||||||
|
0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72,
|
||||||
|
0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01,
|
||||||
|
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
|
||||||
|
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72,
|
||||||
|
0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61,
|
||||||
|
0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e, 0x70, 0x72, 0x6f,
|
||||||
|
0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||||
|
0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
|
||||||
|
0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78,
|
||||||
|
0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65,
|
||||||
|
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70,
|
||||||
|
0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01,
|
||||||
|
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
|
||||||
|
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78,
|
||||||
|
0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69,
|
||||||
|
0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08,
|
||||||
|
0x76, 0x69, 0x61, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||||
|
0x76, 0x69, 0x61, 0x43, 0x69, 0x64, 0x72, 0x12, 0x50, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||||
|
0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e,
|
||||||
|
0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
||||||
|
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||||
|
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||||
|
0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, 0xa4, 0x01, 0x0a, 0x12, 0x4d, 0x75,
|
||||||
|
0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
|
0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
|
0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f,
|
||||||
|
0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||||
|
0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f,
|
||||||
|
0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18,
|
||||||
|
0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75,
|
||||||
|
0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72,
|
||||||
|
0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
|
0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33,
|
||||||
|
0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||||
|
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74,
|
||||||
|
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
|
||||||
|
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||||
|
0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50,
|
||||||
|
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_app_proxyman_config_proto_rawDescOnce sync.Once
|
file_app_proxyman_config_proto_rawDescOnce sync.Once
|
||||||
file_app_proxyman_config_proto_rawDescData []byte
|
file_app_proxyman_config_proto_rawDescData = file_app_proxyman_config_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_proxyman_config_proto_rawDescGZIP() []byte {
|
func file_app_proxyman_config_proto_rawDescGZIP() []byte {
|
||||||
file_app_proxyman_config_proto_rawDescOnce.Do(func() {
|
file_app_proxyman_config_proto_rawDescOnce.Do(func() {
|
||||||
file_app_proxyman_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_proxyman_config_proto_rawDesc), len(file_app_proxyman_config_proto_rawDesc)))
|
file_app_proxyman_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_proxyman_config_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_proxyman_config_proto_rawDescData
|
return file_app_proxyman_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
var file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
|
var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||||
var file_app_proxyman_config_proto_goTypes = []any{
|
var file_app_proxyman_config_proto_goTypes = []any{
|
||||||
(*InboundConfig)(nil), // 0: xray.app.proxyman.InboundConfig
|
(AllocationStrategy_Type)(0), // 0: xray.app.proxyman.AllocationStrategy.Type
|
||||||
(*SniffingConfig)(nil), // 1: xray.app.proxyman.SniffingConfig
|
(*InboundConfig)(nil), // 1: xray.app.proxyman.InboundConfig
|
||||||
(*ReceiverConfig)(nil), // 2: xray.app.proxyman.ReceiverConfig
|
(*AllocationStrategy)(nil), // 2: xray.app.proxyman.AllocationStrategy
|
||||||
(*InboundHandlerConfig)(nil), // 3: xray.app.proxyman.InboundHandlerConfig
|
(*SniffingConfig)(nil), // 3: xray.app.proxyman.SniffingConfig
|
||||||
(*OutboundConfig)(nil), // 4: xray.app.proxyman.OutboundConfig
|
(*ReceiverConfig)(nil), // 4: xray.app.proxyman.ReceiverConfig
|
||||||
(*SenderConfig)(nil), // 5: xray.app.proxyman.SenderConfig
|
(*InboundHandlerConfig)(nil), // 5: xray.app.proxyman.InboundHandlerConfig
|
||||||
(*MultiplexingConfig)(nil), // 6: xray.app.proxyman.MultiplexingConfig
|
(*OutboundConfig)(nil), // 6: xray.app.proxyman.OutboundConfig
|
||||||
(*geodata.DomainRule)(nil), // 7: xray.common.geodata.DomainRule
|
(*SenderConfig)(nil), // 7: xray.app.proxyman.SenderConfig
|
||||||
(*geodata.IPRule)(nil), // 8: xray.common.geodata.IPRule
|
(*MultiplexingConfig)(nil), // 8: xray.app.proxyman.MultiplexingConfig
|
||||||
(*net.PortList)(nil), // 9: xray.common.net.PortList
|
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 9: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
|
||||||
(*net.IPOrDomain)(nil), // 10: xray.common.net.IPOrDomain
|
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
|
||||||
(*internet.StreamConfig)(nil), // 11: xray.transport.internet.StreamConfig
|
(*net.PortList)(nil), // 11: xray.common.net.PortList
|
||||||
(*serial.TypedMessage)(nil), // 12: xray.common.serial.TypedMessage
|
(*net.IPOrDomain)(nil), // 12: xray.common.net.IPOrDomain
|
||||||
(*internet.ProxyConfig)(nil), // 13: xray.transport.internet.ProxyConfig
|
(*internet.StreamConfig)(nil), // 13: xray.transport.internet.StreamConfig
|
||||||
(internet.DomainStrategy)(0), // 14: xray.transport.internet.DomainStrategy
|
(*serial.TypedMessage)(nil), // 14: xray.common.serial.TypedMessage
|
||||||
|
(*internet.ProxyConfig)(nil), // 15: xray.transport.internet.ProxyConfig
|
||||||
|
(internet.DomainStrategy)(0), // 16: xray.transport.internet.DomainStrategy
|
||||||
}
|
}
|
||||||
var file_app_proxyman_config_proto_depIdxs = []int32{
|
var file_app_proxyman_config_proto_depIdxs = []int32{
|
||||||
7, // 0: xray.app.proxyman.SniffingConfig.domains_excluded:type_name -> xray.common.geodata.DomainRule
|
0, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type
|
||||||
8, // 1: xray.app.proxyman.SniffingConfig.ips_excluded:type_name -> xray.common.geodata.IPRule
|
9, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
|
||||||
9, // 2: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList
|
10, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
|
||||||
10, // 3: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
|
11, // 3: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList
|
||||||
11, // 4: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
12, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
|
||||||
1, // 5: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
|
2, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy
|
||||||
12, // 6: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
|
13, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||||
12, // 7: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
|
3, // 7: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
|
||||||
10, // 8: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
|
14, // 8: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
|
||||||
11, // 9: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
14, // 9: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
|
||||||
13, // 10: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
|
12, // 10: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
|
||||||
6, // 11: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
13, // 11: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||||
14, // 12: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy
|
15, // 12: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
|
||||||
13, // [13:13] is the sub-list for method output_type
|
8, // 13: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
||||||
13, // [13:13] is the sub-list for method input_type
|
16, // 14: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||||
13, // [13:13] is the sub-list for extension type_name
|
15, // [15:15] is the sub-list for method output_type
|
||||||
13, // [13:13] is the sub-list for extension extendee
|
15, // [15:15] is the sub-list for method input_type
|
||||||
0, // [0:13] is the sub-list for field type_name
|
15, // [15:15] is the sub-list for extension type_name
|
||||||
|
15, // [15:15] is the sub-list for extension extendee
|
||||||
|
0, // [0:15] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_proxyman_config_proto_init() }
|
func init() { file_app_proxyman_config_proto_init() }
|
||||||
@@ -581,17 +897,19 @@ func file_app_proxyman_config_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_proxyman_config_proto_rawDesc), len(file_app_proxyman_config_proto_rawDesc)),
|
RawDescriptor: file_app_proxyman_config_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 1,
|
||||||
NumMessages: 7,
|
NumMessages: 10,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
GoTypes: file_app_proxyman_config_proto_goTypes,
|
GoTypes: file_app_proxyman_config_proto_goTypes,
|
||||||
DependencyIndexes: file_app_proxyman_config_proto_depIdxs,
|
DependencyIndexes: file_app_proxyman_config_proto_depIdxs,
|
||||||
|
EnumInfos: file_app_proxyman_config_proto_enumTypes,
|
||||||
MessageInfos: file_app_proxyman_config_proto_msgTypes,
|
MessageInfos: file_app_proxyman_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_proxyman_config_proto = out.File
|
File_app_proxyman_config_proto = out.File
|
||||||
|
file_app_proxyman_config_proto_rawDesc = nil
|
||||||
file_app_proxyman_config_proto_goTypes = nil
|
file_app_proxyman_config_proto_goTypes = nil
|
||||||
file_app_proxyman_config_proto_depIdxs = nil
|
file_app_proxyman_config_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,36 @@ import "common/net/address.proto";
|
|||||||
import "common/net/port.proto";
|
import "common/net/port.proto";
|
||||||
import "transport/internet/config.proto";
|
import "transport/internet/config.proto";
|
||||||
import "common/serial/typed_message.proto";
|
import "common/serial/typed_message.proto";
|
||||||
import "common/geodata/geodat.proto";
|
|
||||||
|
|
||||||
message InboundConfig {}
|
message InboundConfig {}
|
||||||
|
|
||||||
|
message AllocationStrategy {
|
||||||
|
enum Type {
|
||||||
|
// Always allocate all connection handlers.
|
||||||
|
Always = 0;
|
||||||
|
|
||||||
|
// Randomly allocate specific range of handlers.
|
||||||
|
Random = 1;
|
||||||
|
|
||||||
|
// External. Not supported yet.
|
||||||
|
External = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type type = 1;
|
||||||
|
|
||||||
|
message AllocationStrategyConcurrency { uint32 value = 1; }
|
||||||
|
|
||||||
|
// Number of handlers (ports) running in parallel.
|
||||||
|
// Default value is 3 if unset.
|
||||||
|
AllocationStrategyConcurrency concurrency = 2;
|
||||||
|
|
||||||
|
message AllocationStrategyRefresh { uint32 value = 1; }
|
||||||
|
|
||||||
|
// Number of minutes before a handler is regenerated.
|
||||||
|
// Default value is 5 if unset.
|
||||||
|
AllocationStrategyRefresh refresh = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message SniffingConfig {
|
message SniffingConfig {
|
||||||
// Whether or not to enable content sniffing on an inbound connection.
|
// Whether or not to enable content sniffing on an inbound connection.
|
||||||
bool enabled = 1;
|
bool enabled = 1;
|
||||||
@@ -21,10 +47,7 @@ message SniffingConfig {
|
|||||||
// Override target destination if sniff'ed protocol is in the given list.
|
// Override target destination if sniff'ed protocol is in the given list.
|
||||||
// Supported values are "http", "tls", "fakedns".
|
// Supported values are "http", "tls", "fakedns".
|
||||||
repeated string destination_override = 2;
|
repeated string destination_override = 2;
|
||||||
|
repeated string domains_excluded = 3;
|
||||||
repeated xray.common.geodata.DomainRule domains_excluded = 3;
|
|
||||||
|
|
||||||
repeated xray.common.geodata.IPRule ips_excluded = 6;
|
|
||||||
|
|
||||||
// Whether should only try to sniff metadata without waiting for client input.
|
// Whether should only try to sniff metadata without waiting for client input.
|
||||||
// Can be used to support SMTP like protocol where server send the first
|
// Can be used to support SMTP like protocol where server send the first
|
||||||
@@ -39,10 +62,11 @@ message ReceiverConfig {
|
|||||||
xray.common.net.PortList port_list = 1;
|
xray.common.net.PortList port_list = 1;
|
||||||
// Listen specifies the IP address that the Receiver should listen on.
|
// Listen specifies the IP address that the Receiver should listen on.
|
||||||
xray.common.net.IPOrDomain listen = 2;
|
xray.common.net.IPOrDomain listen = 2;
|
||||||
xray.transport.internet.StreamConfig stream_settings = 3;
|
AllocationStrategy allocation_strategy = 3;
|
||||||
bool receive_original_destination = 4;
|
xray.transport.internet.StreamConfig stream_settings = 4;
|
||||||
reserved 5;
|
bool receive_original_destination = 5;
|
||||||
SniffingConfig sniffing_settings = 6;
|
reserved 6;
|
||||||
|
SniffingConfig sniffing_settings = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
message InboundHandlerConfig {
|
message InboundHandlerConfig {
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import (
|
|||||||
|
|
||||||
"github.com/xtls/xray-core/app/proxyman"
|
"github.com/xtls/xray-core/app/proxyman"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
|
"github.com/xtls/xray-core/common/dice"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/mux"
|
"github.com/xtls/xray-core/common/mux"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"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/core"
|
||||||
"github.com/xtls/xray-core/features/policy"
|
"github.com/xtls/xray-core/features/policy"
|
||||||
"github.com/xtls/xray-core/features/stats"
|
"github.com/xtls/xray-core/features/stats"
|
||||||
@@ -26,7 +26,7 @@ func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter)
|
|||||||
if len(tag) > 0 && policy.ForSystem().Stats.InboundUplink {
|
if len(tag) > 0 && policy.ForSystem().Stats.InboundUplink {
|
||||||
statsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)
|
statsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)
|
||||||
name := "inbound>>>" + tag + ">>>traffic>>>uplink"
|
name := "inbound>>>" + tag + ">>>traffic>>>uplink"
|
||||||
c, _ := statsManager.GetOrRegisterCounter(name)
|
c, _ := stats.GetOrRegisterCounter(statsManager, name)
|
||||||
if c != nil {
|
if c != nil {
|
||||||
uplinkCounter = c
|
uplinkCounter = c
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter)
|
|||||||
if len(tag) > 0 && policy.ForSystem().Stats.InboundDownlink {
|
if len(tag) > 0 && policy.ForSystem().Stats.InboundDownlink {
|
||||||
statsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)
|
statsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)
|
||||||
name := "inbound>>>" + tag + ">>>traffic>>>downlink"
|
name := "inbound>>>" + tag + ">>>traffic>>>downlink"
|
||||||
c, _ := statsManager.GetOrRegisterCounter(name)
|
c, _ := stats.GetOrRegisterCounter(statsManager, name)
|
||||||
if c != nil {
|
if c != nil {
|
||||||
downlinkCounter = c
|
downlinkCounter = c
|
||||||
}
|
}
|
||||||
@@ -53,27 +53,7 @@ type AlwaysOnInboundHandler struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*AlwaysOnInboundHandler, error) {
|
func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*AlwaysOnInboundHandler, error) {
|
||||||
sniffingRequest, err := proxyman.BuildSniffingRequest(receiverConfig.SniffingSettings)
|
rawProxy, err := common.CreateObject(ctx, proxyConfig)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
src := net.TCPDestination(net.AnyIP, 0)
|
|
||||||
if receiverConfig.Listen != nil {
|
|
||||||
src.Address = receiverConfig.Listen.AsAddress()
|
|
||||||
}
|
|
||||||
if receiverConfig.PortList != nil && len(receiverConfig.PortList.Range) > 0 {
|
|
||||||
src.Port = net.Port(receiverConfig.PortList.Range[0].From)
|
|
||||||
}
|
|
||||||
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("failed to parse stream config").Base(err).AtWarning()
|
|
||||||
}
|
|
||||||
|
|
||||||
newCtx := session.ContextWithInbound(ctx, &session.Inbound{Tag: tag, Source: src})
|
|
||||||
newCtx = session.ContextWithContent(newCtx, &session.Content{SniffingRequest: sniffingRequest})
|
|
||||||
newCtx = session.ContextWithStreamSettings(newCtx, mss)
|
|
||||||
|
|
||||||
rawProxy, err := common.CreateObject(newCtx, proxyConfig)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -99,6 +79,11 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
address = net.AnyIP
|
address = net.AnyIP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to parse stream config").Base(err).AtWarning()
|
||||||
|
}
|
||||||
|
|
||||||
if receiverConfig.ReceiveOriginalDestination {
|
if receiverConfig.ReceiveOriginalDestination {
|
||||||
if mss.SocketSettings == nil {
|
if mss.SocketSettings == nil {
|
||||||
mss.SocketSettings = &internet.SocketConfig{}
|
mss.SocketSettings = &internet.SocketConfig{}
|
||||||
@@ -118,7 +103,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
stream: mss,
|
stream: mss,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
dispatcher: h.mux,
|
dispatcher: h.mux,
|
||||||
sniffingRequest: sniffingRequest,
|
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
uplinkCounter: uplinkCounter,
|
uplinkCounter: uplinkCounter,
|
||||||
downlinkCounter: downlinkCounter,
|
downlinkCounter: downlinkCounter,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
@@ -140,7 +125,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
recvOrigDest: receiverConfig.ReceiveOriginalDestination,
|
recvOrigDest: receiverConfig.ReceiveOriginalDestination,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
dispatcher: h.mux,
|
dispatcher: h.mux,
|
||||||
sniffingRequest: sniffingRequest,
|
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
uplinkCounter: uplinkCounter,
|
uplinkCounter: uplinkCounter,
|
||||||
downlinkCounter: downlinkCounter,
|
downlinkCounter: downlinkCounter,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
@@ -155,7 +140,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
address: address,
|
address: address,
|
||||||
port: net.Port(port),
|
port: net.Port(port),
|
||||||
dispatcher: h.mux,
|
dispatcher: h.mux,
|
||||||
sniffingRequest: sniffingRequest,
|
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
uplinkCounter: uplinkCounter,
|
uplinkCounter: uplinkCounter,
|
||||||
downlinkCounter: downlinkCounter,
|
downlinkCounter: downlinkCounter,
|
||||||
stream: mss,
|
stream: mss,
|
||||||
@@ -172,12 +157,6 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
|
|
||||||
// Start implements common.Runnable.
|
// Start implements common.Runnable.
|
||||||
func (h *AlwaysOnInboundHandler) Start() error {
|
func (h *AlwaysOnInboundHandler) Start() error {
|
||||||
// for inbound without worker (TUN)
|
|
||||||
if run, ok := h.proxy.(common.Runnable); ok {
|
|
||||||
if err := run.Start(); err != nil {
|
|
||||||
return errors.New("failed to start proxy").Base(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, worker := range h.workers {
|
for _, worker := range h.workers {
|
||||||
if err := worker.Start(); err != nil {
|
if err := worker.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -193,13 +172,20 @@ func (h *AlwaysOnInboundHandler) Close() error {
|
|||||||
errs = append(errs, worker.Close())
|
errs = append(errs, worker.Close())
|
||||||
}
|
}
|
||||||
errs = append(errs, h.mux.Close())
|
errs = append(errs, h.mux.Close())
|
||||||
errs = append(errs, common.Close(h.proxy))
|
|
||||||
if err := errors.Combine(errs...); err != nil {
|
if err := errors.Combine(errs...); err != nil {
|
||||||
return errors.New("failed to close all resources").Base(err)
|
return errors.New("failed to close all resources").Base(err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *AlwaysOnInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {
|
||||||
|
if len(h.workers) == 0 {
|
||||||
|
return nil, 0, 0
|
||||||
|
}
|
||||||
|
w := h.workers[dice.Roll(len(h.workers))]
|
||||||
|
return w.Proxy(), w.Port(), 9999
|
||||||
|
}
|
||||||
|
|
||||||
func (h *AlwaysOnInboundHandler) Tag() string {
|
func (h *AlwaysOnInboundHandler) Tag() string {
|
||||||
return h.tag
|
return h.tag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,222 @@
|
|||||||
|
package inbound
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/app/proxyman"
|
||||||
|
"github.com/xtls/xray-core/common/dice"
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/common/mux"
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/common/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 {
|
||||||
|
tag string
|
||||||
|
v *core.Instance
|
||||||
|
proxyConfig interface{}
|
||||||
|
receiverConfig *proxyman.ReceiverConfig
|
||||||
|
streamSettings *internet.MemoryStreamConfig
|
||||||
|
portMutex sync.Mutex
|
||||||
|
portsInUse map[net.Port]struct{}
|
||||||
|
workerMutex sync.RWMutex
|
||||||
|
worker []worker
|
||||||
|
lastRefresh time.Time
|
||||||
|
mux *mux.Server
|
||||||
|
task *task.Periodic
|
||||||
|
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*DynamicInboundHandler, error) {
|
||||||
|
v := core.MustFromContext(ctx)
|
||||||
|
h := &DynamicInboundHandler{
|
||||||
|
tag: tag,
|
||||||
|
proxyConfig: proxyConfig,
|
||||||
|
receiverConfig: receiverConfig,
|
||||||
|
portsInUse: make(map[net.Port]struct{}),
|
||||||
|
mux: mux.NewServer(ctx),
|
||||||
|
v: v,
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
|
||||||
|
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to parse stream settings").Base(err).AtWarning()
|
||||||
|
}
|
||||||
|
if receiverConfig.ReceiveOriginalDestination {
|
||||||
|
if mss.SocketSettings == nil {
|
||||||
|
mss.SocketSettings = &internet.SocketConfig{}
|
||||||
|
}
|
||||||
|
if mss.SocketSettings.Tproxy == internet.SocketConfig_Off {
|
||||||
|
mss.SocketSettings.Tproxy = internet.SocketConfig_Redirect
|
||||||
|
}
|
||||||
|
mss.SocketSettings.ReceiveOriginalDestAddress = true
|
||||||
|
}
|
||||||
|
|
||||||
|
h.streamSettings = mss
|
||||||
|
|
||||||
|
h.task = &task.Periodic{
|
||||||
|
Interval: time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()),
|
||||||
|
Execute: h.refresh,
|
||||||
|
}
|
||||||
|
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) allocatePort() net.Port {
|
||||||
|
allPorts := []int32{}
|
||||||
|
for _, pr := range h.receiverConfig.PortList.Range {
|
||||||
|
for i := pr.From; i <= pr.To; i++ {
|
||||||
|
allPorts = append(allPorts, int32(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h.portMutex.Lock()
|
||||||
|
defer h.portMutex.Unlock()
|
||||||
|
|
||||||
|
for {
|
||||||
|
r := dice.Roll(len(allPorts))
|
||||||
|
port := net.Port(allPorts[r])
|
||||||
|
_, used := h.portsInUse[port]
|
||||||
|
if !used {
|
||||||
|
h.portsInUse[port] = struct{}{}
|
||||||
|
return port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) closeWorkers(workers []worker) {
|
||||||
|
ports2Del := make([]net.Port, len(workers))
|
||||||
|
for idx, worker := range workers {
|
||||||
|
ports2Del[idx] = worker.Port()
|
||||||
|
if err := worker.Close(); err != nil {
|
||||||
|
errors.LogInfoInner(h.ctx, err, "failed to close worker")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.portMutex.Lock()
|
||||||
|
for _, port := range ports2Del {
|
||||||
|
delete(h.portsInUse, port)
|
||||||
|
}
|
||||||
|
h.portMutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) refresh() error {
|
||||||
|
h.lastRefresh = time.Now()
|
||||||
|
|
||||||
|
timeout := time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()) * 2
|
||||||
|
concurrency := h.receiverConfig.AllocationStrategy.GetConcurrencyValue()
|
||||||
|
workers := make([]worker, 0, concurrency)
|
||||||
|
|
||||||
|
address := h.receiverConfig.Listen.AsAddress()
|
||||||
|
if address == nil {
|
||||||
|
address = net.AnyIP
|
||||||
|
}
|
||||||
|
|
||||||
|
uplinkCounter, downlinkCounter := getStatCounter(h.v, h.tag)
|
||||||
|
|
||||||
|
for i := uint32(0); i < concurrency; i++ {
|
||||||
|
port := h.allocatePort()
|
||||||
|
rawProxy, err := core.CreateObject(h.v, h.proxyConfig)
|
||||||
|
if err != nil {
|
||||||
|
errors.LogWarningInner(h.ctx, err, "failed to create proxy instance")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p := rawProxy.(proxy.Inbound)
|
||||||
|
nl := p.Network()
|
||||||
|
if net.HasNetwork(nl, net.Network_TCP) {
|
||||||
|
worker := &tcpWorker{
|
||||||
|
tag: h.tag,
|
||||||
|
address: address,
|
||||||
|
port: port,
|
||||||
|
proxy: p,
|
||||||
|
stream: h.streamSettings,
|
||||||
|
recvOrigDest: h.receiverConfig.ReceiveOriginalDestination,
|
||||||
|
dispatcher: h.mux,
|
||||||
|
sniffingConfig: h.receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
|
uplinkCounter: uplinkCounter,
|
||||||
|
downlinkCounter: downlinkCounter,
|
||||||
|
ctx: h.ctx,
|
||||||
|
}
|
||||||
|
if err := worker.Start(); err != nil {
|
||||||
|
errors.LogWarningInner(h.ctx, err, "failed to create TCP worker")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
workers = append(workers, worker)
|
||||||
|
}
|
||||||
|
|
||||||
|
if net.HasNetwork(nl, net.Network_UDP) {
|
||||||
|
worker := &udpWorker{
|
||||||
|
tag: h.tag,
|
||||||
|
proxy: p,
|
||||||
|
address: address,
|
||||||
|
port: port,
|
||||||
|
dispatcher: h.mux,
|
||||||
|
sniffingConfig: h.receiverConfig.GetEffectiveSniffingSettings(),
|
||||||
|
uplinkCounter: uplinkCounter,
|
||||||
|
downlinkCounter: downlinkCounter,
|
||||||
|
stream: h.streamSettings,
|
||||||
|
ctx: h.ctx,
|
||||||
|
}
|
||||||
|
if err := worker.Start(); err != nil {
|
||||||
|
errors.LogWarningInner(h.ctx, err, "failed to create UDP worker")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
workers = append(workers, worker)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.workerMutex.Lock()
|
||||||
|
h.worker = workers
|
||||||
|
h.workerMutex.Unlock()
|
||||||
|
|
||||||
|
time.AfterFunc(timeout, func() {
|
||||||
|
h.closeWorkers(workers)
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) Start() error {
|
||||||
|
return h.task.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) Close() error {
|
||||||
|
return h.task.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {
|
||||||
|
h.workerMutex.RLock()
|
||||||
|
defer h.workerMutex.RUnlock()
|
||||||
|
|
||||||
|
if len(h.worker) == 0 {
|
||||||
|
return nil, 0, 0
|
||||||
|
}
|
||||||
|
w := h.worker[dice.Roll(len(h.worker))]
|
||||||
|
expire := h.receiverConfig.AllocationStrategy.GetRefreshValue() - uint32(time.Since(h.lastRefresh)/time.Minute)
|
||||||
|
return w.Proxy(), w.Port(), int(expire)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DynamicInboundHandler) Tag() string {
|
||||||
|
return h.tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
@@ -16,10 +16,10 @@ import (
|
|||||||
|
|
||||||
// Manager manages all inbound handlers.
|
// Manager manages all inbound handlers.
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
access sync.RWMutex
|
access sync.RWMutex
|
||||||
untaggedHandlers []inbound.Handler
|
untaggedHandlers []inbound.Handler
|
||||||
taggedHandlers map[string]inbound.Handler
|
taggedHandlers map[string]inbound.Handler
|
||||||
running bool
|
running bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new Manager for inbound handlers.
|
// New returns a new Manager for inbound handlers.
|
||||||
@@ -178,7 +178,15 @@ func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound
|
|||||||
ctx = session.ContextWithAllowedNetwork(ctx, net.Network_UDP)
|
ctx = session.ContextWithAllowedNetwork(ctx, net.Network_UDP)
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewAlwaysOnInboundHandler(ctx, tag, receiverSettings, proxySettings)
|
allocStrategy := receiverSettings.AllocationStrategy
|
||||||
|
if allocStrategy == nil || allocStrategy.Type == proxyman.AllocationStrategy_Always {
|
||||||
|
return NewAlwaysOnInboundHandler(ctx, tag, receiverSettings, proxySettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
if allocStrategy.Type == proxyman.AllocationStrategy_Random {
|
||||||
|
return NewDynamicInboundHandler(ctx, tag, receiverSettings, proxySettings)
|
||||||
|
}
|
||||||
|
return nil, errors.New("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/app/proxyman"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
c "github.com/xtls/xray-core/common/ctx"
|
c "github.com/xtls/xray-core/common/ctx"
|
||||||
@@ -18,9 +19,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
"github.com/xtls/xray-core/features/stats"
|
"github.com/xtls/xray-core/features/stats"
|
||||||
"github.com/xtls/xray-core/proxy"
|
"github.com/xtls/xray-core/proxy"
|
||||||
hysteria_proxy "github.com/xtls/xray-core/proxy/hysteria"
|
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"github.com/xtls/xray-core/transport/internet/hysteria"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
"github.com/xtls/xray-core/transport/internet/stat"
|
||||||
"github.com/xtls/xray-core/transport/internet/tcp"
|
"github.com/xtls/xray-core/transport/internet/tcp"
|
||||||
"github.com/xtls/xray-core/transport/internet/udp"
|
"github.com/xtls/xray-core/transport/internet/udp"
|
||||||
@@ -42,7 +41,7 @@ type tcpWorker struct {
|
|||||||
recvOrigDest bool
|
recvOrigDest bool
|
||||||
tag string
|
tag string
|
||||||
dispatcher routing.Dispatcher
|
dispatcher routing.Dispatcher
|
||||||
sniffingRequest session.SniffingRequest
|
sniffingConfig *proxyman.SniffingConfig
|
||||||
uplinkCounter stats.Counter
|
uplinkCounter stats.Counter
|
||||||
downlinkCounter stats.Counter
|
downlinkCounter stats.Counter
|
||||||
|
|
||||||
@@ -77,25 +76,7 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
|||||||
case internet.SocketConfig_TProxy:
|
case internet.SocketConfig_TProxy:
|
||||||
dest = net.DestinationFromAddr(conn.LocalAddr())
|
dest = net.DestinationFromAddr(conn.LocalAddr())
|
||||||
}
|
}
|
||||||
|
|
||||||
if dest.IsValid() {
|
if dest.IsValid() {
|
||||||
// Check if try to connect to this inbound itself (can cause loopback)
|
|
||||||
var isLoopBack bool
|
|
||||||
if w.address == net.AnyIP || w.address == net.AnyIPv6 {
|
|
||||||
if dest.Port.Value() == w.port.Value() && IsLocal(dest.Address.IP()) {
|
|
||||||
isLoopBack = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if w.hub.Addr().String() == dest.NetAddr() {
|
|
||||||
isLoopBack = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if isLoopBack {
|
|
||||||
cancel()
|
|
||||||
conn.Close()
|
|
||||||
errors.LogError(ctx, errors.New("loopback connection detected"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
outbounds[0].Target = dest
|
outbounds[0].Target = dest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,7 +98,13 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
content := new(session.Content)
|
content := new(session.Content)
|
||||||
content.SniffingRequest = w.sniffingRequest
|
if w.sniffingConfig != nil {
|
||||||
|
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
|
||||||
|
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
||||||
|
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
||||||
|
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||||
|
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
||||||
|
}
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
|
|
||||||
if err := w.proxy.Process(ctx, net.Network_TCP, conn, w.dispatcher); err != nil {
|
if err := w.proxy.Process(ctx, net.Network_TCP, conn, w.dispatcher); err != nil {
|
||||||
@@ -133,11 +120,6 @@ func (w *tcpWorker) Proxy() proxy.Inbound {
|
|||||||
|
|
||||||
func (w *tcpWorker) Start() error {
|
func (w *tcpWorker) Start() error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
if v, ok := w.proxy.(*hysteria_proxy.Server); ok {
|
|
||||||
ctx = hysteria.ContextWithValidator(ctx, v.HysteriaInboundValidator())
|
|
||||||
}
|
|
||||||
|
|
||||||
hub, err := internet.ListenTCP(ctx, w.address, w.port, w.stream, func(conn stat.Connection) {
|
hub, err := internet.ListenTCP(ctx, w.address, w.port, w.stream, func(conn stat.Connection) {
|
||||||
go w.callback(conn)
|
go w.callback(conn)
|
||||||
})
|
})
|
||||||
@@ -266,7 +248,7 @@ type udpWorker struct {
|
|||||||
tag string
|
tag string
|
||||||
stream *internet.MemoryStreamConfig
|
stream *internet.MemoryStreamConfig
|
||||||
dispatcher routing.Dispatcher
|
dispatcher routing.Dispatcher
|
||||||
sniffingRequest session.SniffingRequest
|
sniffingConfig *proxyman.SniffingConfig
|
||||||
uplinkCounter stats.Counter
|
uplinkCounter stats.Counter
|
||||||
downlinkCounter stats.Counter
|
downlinkCounter stats.Counter
|
||||||
|
|
||||||
@@ -356,7 +338,13 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
|||||||
Tag: w.tag,
|
Tag: w.tag,
|
||||||
})
|
})
|
||||||
content := new(session.Content)
|
content := new(session.Content)
|
||||||
content.SniffingRequest = w.sniffingRequest
|
if w.sniffingConfig != nil {
|
||||||
|
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
|
||||||
|
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
||||||
|
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
||||||
|
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||||
|
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
||||||
|
}
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
|
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
|
||||||
errors.LogInfoInner(ctx, err, "connection ends")
|
errors.LogInfoInner(ctx, err, "connection ends")
|
||||||
@@ -472,7 +460,7 @@ type dsWorker struct {
|
|||||||
stream *internet.MemoryStreamConfig
|
stream *internet.MemoryStreamConfig
|
||||||
tag string
|
tag string
|
||||||
dispatcher routing.Dispatcher
|
dispatcher routing.Dispatcher
|
||||||
sniffingRequest session.SniffingRequest
|
sniffingConfig *proxyman.SniffingConfig
|
||||||
uplinkCounter stats.Counter
|
uplinkCounter stats.Counter
|
||||||
downlinkCounter stats.Counter
|
downlinkCounter stats.Counter
|
||||||
|
|
||||||
@@ -502,7 +490,13 @@ func (w *dsWorker) callback(conn stat.Connection) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
content := new(session.Content)
|
content := new(session.Content)
|
||||||
content.SniffingRequest = w.sniffingRequest
|
if w.sniffingConfig != nil {
|
||||||
|
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
|
||||||
|
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
||||||
|
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
||||||
|
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||||
|
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
||||||
|
}
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
|
|
||||||
if err := w.proxy.Process(ctx, net.Network_UNIX, conn, w.dispatcher); err != nil {
|
if err := w.proxy.Process(ctx, net.Network_UNIX, conn, w.dispatcher); err != nil {
|
||||||
@@ -550,18 +544,3 @@ func (w *dsWorker) Close() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsLocal(ip net.IP) bool {
|
|
||||||
addrs, err := net.InterfaceAddrs()
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, addr := range addrs {
|
|
||||||
if ipnet, ok := addr.(*net.IPNet); ok {
|
|
||||||
if ipnet.IP.Equal(ip) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import (
|
|||||||
goerrors "errors"
|
goerrors "errors"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
gonet "net"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/dice"
|
"github.com/xtls/xray-core/common/dice"
|
||||||
|
|
||||||
@@ -39,7 +41,7 @@ func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter)
|
|||||||
if len(tag) > 0 && policy.ForSystem().Stats.OutboundUplink {
|
if len(tag) > 0 && policy.ForSystem().Stats.OutboundUplink {
|
||||||
statsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)
|
statsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)
|
||||||
name := "outbound>>>" + tag + ">>>traffic>>>uplink"
|
name := "outbound>>>" + tag + ">>>traffic>>>uplink"
|
||||||
c, _ := statsManager.GetOrRegisterCounter(name)
|
c, _ := stats.GetOrRegisterCounter(statsManager, name)
|
||||||
if c != nil {
|
if c != nil {
|
||||||
uplinkCounter = c
|
uplinkCounter = c
|
||||||
}
|
}
|
||||||
@@ -47,7 +49,7 @@ func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter)
|
|||||||
if len(tag) > 0 && policy.ForSystem().Stats.OutboundDownlink {
|
if len(tag) > 0 && policy.ForSystem().Stats.OutboundDownlink {
|
||||||
statsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)
|
statsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)
|
||||||
name := "outbound>>>" + tag + ">>>traffic>>>downlink"
|
name := "outbound>>>" + tag + ">>>traffic>>>downlink"
|
||||||
c, _ := statsManager.GetOrRegisterCounter(name)
|
c, _ := stats.GetOrRegisterCounter(statsManager, name)
|
||||||
if c != nil {
|
if c != nil {
|
||||||
downlinkCounter = c
|
downlinkCounter = c
|
||||||
}
|
}
|
||||||
@@ -106,11 +108,7 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
|||||||
}
|
}
|
||||||
h.proxyConfig = proxyConfig
|
h.proxyConfig = proxyConfig
|
||||||
|
|
||||||
ctx = session.ContextWithFullHandler(ctx, h)
|
rawProxyHandler, err := common.CreateObject(ctx, proxyConfig)
|
||||||
|
|
||||||
newCtx := session.ContextWithStreamSettings(ctx, h.streamSettings)
|
|
||||||
|
|
||||||
rawProxyHandler, err := common.CreateObject(newCtx, proxyConfig)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -307,17 +305,18 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
|||||||
ob := outbounds[len(outbounds)-1]
|
ob := outbounds[len(outbounds)-1]
|
||||||
h.SetOutboundGateway(ctx, ob)
|
h.SetOutboundGateway(ctx, ob)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if conn, err := h.getUoTConnection(ctx, dest); err != os.ErrInvalid {
|
||||||
|
return conn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := internet.Dial(ctx, dest, h.streamSettings)
|
conn, err := internet.Dial(ctx, dest, h.streamSettings)
|
||||||
conn = h.getStatCouterConnection(conn)
|
conn = h.getStatCouterConnection(conn)
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
if outbounds != nil {
|
ob := outbounds[len(outbounds)-1]
|
||||||
ob := outbounds[len(outbounds)-1]
|
ob.Conn = conn
|
||||||
ob.Conn = conn
|
|
||||||
} else {
|
|
||||||
// for Vision's pre-connect
|
|
||||||
}
|
|
||||||
return conn, err
|
return conn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,7 +343,7 @@ func (h *Handler) SetOutboundGateway(ctx context.Context, ob *session.Outbound)
|
|||||||
errors.LogDebug(ctx, "use inbound source ip as sendthrough: ", inbound.Source.Address.String())
|
errors.LogDebug(ctx, "use inbound source ip as sendthrough: ", inbound.Source.Address.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// case addr.Family().IsDomain():
|
//case addr.Family().IsDomain():
|
||||||
default:
|
default:
|
||||||
ob.Gateway = addr
|
ob.Gateway = addr
|
||||||
|
|
||||||
@@ -392,7 +391,8 @@ func (h *Handler) ProxySettings() *serial.TypedMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ParseRandomIP(addr net.Address, prefix string) net.Address {
|
func ParseRandomIP(addr net.Address, prefix string) net.Address {
|
||||||
_, ipnet, _ := net.ParseCIDR(addr.IP().String() + "/" + prefix)
|
|
||||||
|
_, ipnet, _ := gonet.ParseCIDR(addr.IP().String() + "/" + prefix)
|
||||||
|
|
||||||
ones, bits := ipnet.Mask.Size()
|
ones, bits := ipnet.Mask.Size()
|
||||||
subnetSize := new(big.Int).Lsh(big.NewInt(1), uint(bits-ones))
|
subnetSize := new(big.Int).Lsh(big.NewInt(1), uint(bits-ones))
|
||||||
@@ -406,5 +406,5 @@ func ParseRandomIP(addr net.Address, prefix string) net.Address {
|
|||||||
padded := make([]byte, len(ipnet.IP))
|
padded := make([]byte, len(ipnet.IP))
|
||||||
copy(padded[len(padded)-len(rndBytes):], rndBytes)
|
copy(padded[len(padded)-len(rndBytes):], rndBytes)
|
||||||
|
|
||||||
return net.ParseAddress(net.IP(padded).String())
|
return net.ParseAddress(gonet.IP(padded).String())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestInterfaces(t *testing.T) {
|
func TestInterfaces(t *testing.T) {
|
||||||
_ = outbound.Handler(new(Handler))
|
_ = (outbound.Handler)(new(Handler))
|
||||||
_ = outbound.Manager(new(Manager))
|
_ = (outbound.Manager)(new(Manager))
|
||||||
}
|
}
|
||||||
|
|
||||||
const xrayKey core.XrayKey = 1
|
const xrayKey core.XrayKey = 1
|
||||||
@@ -43,12 +43,12 @@ func TestOutboundWithoutStatCounter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
v, _ := core.New(config)
|
v, _ := core.New(config)
|
||||||
v.AddFeature(outbound.Manager(new(Manager)))
|
v.AddFeature((outbound.Manager)(new(Manager)))
|
||||||
ctx := context.WithValue(context.Background(), xrayKey, v)
|
ctx := context.WithValue(context.Background(), xrayKey, v)
|
||||||
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})
|
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})
|
||||||
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
|
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
|
||||||
Tag: "tag",
|
Tag: "tag",
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||||
})
|
})
|
||||||
conn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146))
|
conn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146))
|
||||||
_, ok := conn.(*stat.CounterConnection)
|
_, ok := conn.(*stat.CounterConnection)
|
||||||
@@ -73,12 +73,12 @@ func TestOutboundWithStatCounter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
v, _ := core.New(config)
|
v, _ := core.New(config)
|
||||||
v.AddFeature(outbound.Manager(new(Manager)))
|
v.AddFeature((outbound.Manager)(new(Manager)))
|
||||||
ctx := context.WithValue(context.Background(), xrayKey, v)
|
ctx := context.WithValue(context.Background(), xrayKey, v)
|
||||||
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})
|
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})
|
||||||
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
|
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
|
||||||
Tag: "tag",
|
Tag: "tag",
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||||
})
|
})
|
||||||
conn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146))
|
conn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146))
|
||||||
_, ok := conn.(*stat.CounterConnection)
|
_, ok := conn.(*stat.CounterConnection)
|
||||||
@@ -88,6 +88,7 @@ func TestOutboundWithStatCounter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTagsCache(t *testing.T) {
|
func TestTagsCache(t *testing.T) {
|
||||||
|
|
||||||
test_duration := 10 * time.Second
|
test_duration := 10 * time.Second
|
||||||
threads_num := 50
|
threads_num := 50
|
||||||
delay := 10 * time.Millisecond
|
delay := 10 * time.Millisecond
|
||||||
@@ -117,7 +118,7 @@ func TestTagsCache(t *testing.T) {
|
|||||||
tag := fmt.Sprintf("%s%d", tags_prefix, idx)
|
tag := fmt.Sprintf("%s%d", tags_prefix, idx)
|
||||||
cfg := &core.OutboundHandlerConfig{
|
cfg := &core.OutboundHandlerConfig{
|
||||||
Tag: tag,
|
Tag: tag,
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||||
}
|
}
|
||||||
if h, err := NewHandler(ctx, cfg); err == nil {
|
if h, err := NewHandler(ctx, cfg); err == nil {
|
||||||
if err := ohm.AddHandler(ctx, h); err == nil {
|
if err := ohm.AddHandler(ctx, h); err == nil {
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ func (m *Manager) ListHandlers(ctx context.Context) []outbound.Handler {
|
|||||||
|
|
||||||
// Select implements outbound.HandlerSelector.
|
// Select implements outbound.HandlerSelector.
|
||||||
func (m *Manager) Select(selectors []string) []string {
|
func (m *Manager) Select(selectors []string) []string {
|
||||||
|
|
||||||
key := strings.Join(selectors, ",")
|
key := strings.Join(selectors, ",")
|
||||||
if cache, ok := m.tagsCache.Load(key); ok {
|
if cache, ok := m.tagsCache.Load(key); ok {
|
||||||
return cache.([]string)
|
return cache.([]string)
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package outbound
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common/uot"
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
|
"github.com/xtls/xray-core/transport/internet/stat"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *Handler) getUoTConnection(ctx context.Context, dest net.Destination) (stat.Connection, error) {
|
||||||
|
if dest.Address == nil {
|
||||||
|
return nil, errors.New("nil destination address")
|
||||||
|
}
|
||||||
|
if !dest.Address.Family().IsDomain() {
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
||||||
|
var uotVersion int
|
||||||
|
if dest.Address.Domain() == uot.MagicAddress {
|
||||||
|
uotVersion = uot.Version
|
||||||
|
} else if dest.Address.Domain() == uot.LegacyMagicAddress {
|
||||||
|
uotVersion = uot.LegacyVersion
|
||||||
|
} else {
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
||||||
|
packetConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{IP: net.AnyIP.IP(), Port: 0}, h.streamSettings.SocketSettings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("unable to listen socket").Base(err)
|
||||||
|
}
|
||||||
|
conn := uot.NewServerConn(packetConn, uotVersion)
|
||||||
|
return h.getStatCouterConnection(conn), nil
|
||||||
|
}
|
||||||
+24
-53
@@ -4,11 +4,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/app/dispatcher"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/mux"
|
"github.com/xtls/xray-core/common/mux"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/common/signal"
|
|
||||||
"github.com/xtls/xray-core/common/task"
|
"github.com/xtls/xray-core/common/task"
|
||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
"github.com/xtls/xray-core/transport"
|
"github.com/xtls/xray-core/transport"
|
||||||
@@ -53,11 +53,6 @@ func (b *Bridge) cleanup() {
|
|||||||
if w.IsActive() {
|
if w.IsActive() {
|
||||||
activeWorkers = append(activeWorkers, w)
|
activeWorkers = append(activeWorkers, w)
|
||||||
}
|
}
|
||||||
if w.Closed() {
|
|
||||||
if w.Timer != nil {
|
|
||||||
w.Timer.SetTimeout(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(activeWorkers) != len(b.workers) {
|
if len(activeWorkers) != len(b.workers) {
|
||||||
@@ -99,11 +94,10 @@ func (b *Bridge) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BridgeWorker struct {
|
type BridgeWorker struct {
|
||||||
Tag string
|
tag string
|
||||||
Worker *mux.ServerWorker
|
worker *mux.ServerWorker
|
||||||
Dispatcher routing.Dispatcher
|
dispatcher routing.Dispatcher
|
||||||
State Control_State
|
state Control_State
|
||||||
Timer *signal.ActivityTimer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBridgeWorker(domain string, tag string, d routing.Dispatcher) (*BridgeWorker, error) {
|
func NewBridgeWorker(domain string, tag string, d routing.Dispatcher) (*BridgeWorker, error) {
|
||||||
@@ -121,20 +115,16 @@ func NewBridgeWorker(domain string, tag string, d routing.Dispatcher) (*BridgeWo
|
|||||||
}
|
}
|
||||||
|
|
||||||
w := &BridgeWorker{
|
w := &BridgeWorker{
|
||||||
Dispatcher: d,
|
dispatcher: d,
|
||||||
Tag: tag,
|
tag: tag,
|
||||||
}
|
}
|
||||||
|
|
||||||
worker, err := mux.NewServerWorker(context.Background(), w, link)
|
worker, err := mux.NewServerWorker(context.Background(), w, link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
w.Worker = worker
|
w.worker = worker
|
||||||
|
|
||||||
terminate := func() {
|
|
||||||
worker.Close()
|
|
||||||
}
|
|
||||||
w.Timer = signal.CancelAfterInactivity(ctx, terminate, 60*time.Second)
|
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,15 +141,11 @@ func (w *BridgeWorker) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *BridgeWorker) IsActive() bool {
|
func (w *BridgeWorker) IsActive() bool {
|
||||||
return w.State == Control_ACTIVE && !w.Worker.Closed()
|
return w.state == Control_ACTIVE && !w.worker.Closed()
|
||||||
}
|
|
||||||
|
|
||||||
func (w *BridgeWorker) Closed() bool {
|
|
||||||
return w.Worker.Closed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *BridgeWorker) Connections() uint32 {
|
func (w *BridgeWorker) Connections() uint32 {
|
||||||
return w.Worker.ActiveConnections()
|
return w.worker.ActiveConnections()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *BridgeWorker) handleInternalConn(link *transport.Link) {
|
func (w *BridgeWorker) handleInternalConn(link *transport.Link) {
|
||||||
@@ -167,29 +153,16 @@ func (w *BridgeWorker) handleInternalConn(link *transport.Link) {
|
|||||||
for {
|
for {
|
||||||
mb, err := reader.ReadMultiBuffer()
|
mb, err := reader.ReadMultiBuffer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if w.Timer != nil {
|
break
|
||||||
if w.Closed() {
|
|
||||||
w.Timer.SetTimeout(0)
|
|
||||||
} else {
|
|
||||||
w.Timer.SetTimeout(24 * time.Hour)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if w.Timer != nil {
|
|
||||||
w.Timer.Update()
|
|
||||||
}
|
}
|
||||||
for _, b := range mb {
|
for _, b := range mb {
|
||||||
var ctl Control
|
var ctl Control
|
||||||
if err := proto.Unmarshal(b.Bytes(), &ctl); err != nil {
|
if err := proto.Unmarshal(b.Bytes(), &ctl); err != nil {
|
||||||
errors.LogInfoInner(context.Background(), err, "failed to parse proto message")
|
errors.LogInfoInner(context.Background(), err, "failed to parse proto message")
|
||||||
if w.Timer != nil {
|
break
|
||||||
w.Timer.SetTimeout(0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if ctl.State != w.State {
|
if ctl.State != w.state {
|
||||||
w.State = ctl.State
|
w.state = ctl.State
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,12 +170,10 @@ func (w *BridgeWorker) handleInternalConn(link *transport.Link) {
|
|||||||
|
|
||||||
func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {
|
func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {
|
||||||
if !isInternalDomain(dest) {
|
if !isInternalDomain(dest) {
|
||||||
if session.InboundFromContext(ctx) == nil {
|
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
Tag: w.tag,
|
||||||
Tag: w.Tag,
|
})
|
||||||
})
|
return w.dispatcher.Dispatch(ctx, dest)
|
||||||
}
|
|
||||||
return w.Dispatcher.Dispatch(ctx, dest)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
opt := []pipe.Option{pipe.WithSizeLimit(16 * 1024)}
|
opt := []pipe.Option{pipe.WithSizeLimit(16 * 1024)}
|
||||||
@@ -222,13 +193,13 @@ func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*tra
|
|||||||
|
|
||||||
func (w *BridgeWorker) DispatchLink(ctx context.Context, dest net.Destination, link *transport.Link) error {
|
func (w *BridgeWorker) DispatchLink(ctx context.Context, dest net.Destination, link *transport.Link) error {
|
||||||
if !isInternalDomain(dest) {
|
if !isInternalDomain(dest) {
|
||||||
if session.InboundFromContext(ctx) == nil {
|
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
Tag: w.tag,
|
||||||
Tag: w.Tag,
|
})
|
||||||
})
|
return w.dispatcher.DispatchLink(ctx, dest, link)
|
||||||
}
|
|
||||||
return w.Dispatcher.DispatchLink(ctx, dest, link)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
link = w.dispatcher.(*dispatcher.DefaultDispatcher).WrapLink(ctx, link)
|
||||||
w.handleInternalConn(link)
|
w.handleInternalConn(link)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+61
-42
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/reverse/config.proto
|
// source: app/reverse/config.proto
|
||||||
|
|
||||||
package reverse
|
package reverse
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -68,11 +67,12 @@ func (Control_State) EnumDescriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Control struct {
|
type Control struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
State Control_State `protobuf:"varint,1,opt,name=state,proto3,enum=xray.app.reverse.Control_State" json:"state,omitempty"`
|
|
||||||
Random []byte `protobuf:"bytes,99,opt,name=random,proto3" json:"random,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
State Control_State `protobuf:"varint,1,opt,name=state,proto3,enum=xray.app.reverse.Control_State" json:"state,omitempty"`
|
||||||
|
Random []byte `protobuf:"bytes,99,opt,name=random,proto3" json:"random,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Control) Reset() {
|
func (x *Control) Reset() {
|
||||||
@@ -120,11 +120,12 @@ func (x *Control) GetRandom() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BridgeConfig struct {
|
type BridgeConfig struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
|
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *BridgeConfig) Reset() {
|
func (x *BridgeConfig) Reset() {
|
||||||
@@ -172,11 +173,12 @@ func (x *BridgeConfig) GetDomain() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PortalConfig struct {
|
type PortalConfig struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
|
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *PortalConfig) Reset() {
|
func (x *PortalConfig) Reset() {
|
||||||
@@ -224,11 +226,12 @@ func (x *PortalConfig) GetDomain() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
BridgeConfig []*BridgeConfig `protobuf:"bytes,1,rep,name=bridge_config,json=bridgeConfig,proto3" json:"bridge_config,omitempty"`
|
|
||||||
PortalConfig []*PortalConfig `protobuf:"bytes,2,rep,name=portal_config,json=portalConfig,proto3" json:"portal_config,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
BridgeConfig []*BridgeConfig `protobuf:"bytes,1,rep,name=bridge_config,json=bridgeConfig,proto3" json:"bridge_config,omitempty"`
|
||||||
|
PortalConfig []*PortalConfig `protobuf:"bytes,2,rep,name=portal_config,json=portalConfig,proto3" json:"portal_config,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -277,35 +280,50 @@ func (x *Config) GetPortalConfig() []*PortalConfig {
|
|||||||
|
|
||||||
var File_app_reverse_config_proto protoreflect.FileDescriptor
|
var File_app_reverse_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_reverse_config_proto_rawDesc = "" +
|
var file_app_reverse_config_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x18, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x2f, 0x63, 0x6f,
|
||||||
"\x18app/reverse/config.proto\x12\x10xray.app.reverse\"x\n" +
|
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61, 0x79,
|
||||||
"\aControl\x125\n" +
|
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x22, 0x78, 0x0a, 0x07,
|
||||||
"\x05state\x18\x01 \x01(\x0e2\x1f.xray.app.reverse.Control.StateR\x05state\x12\x16\n" +
|
0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x35, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65,
|
||||||
"\x06random\x18c \x01(\fR\x06random\"\x1e\n" +
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||||
"\x05State\x12\n" +
|
0x70, 0x2e, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||||
"\n" +
|
0x6c, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16,
|
||||||
"\x06ACTIVE\x10\x00\x12\t\n" +
|
0x0a, 0x06, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x18, 0x63, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06,
|
||||||
"\x05DRAIN\x10\x01\"8\n" +
|
0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x22, 0x1e, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12,
|
||||||
"\fBridgeConfig\x12\x10\n" +
|
0x0a, 0x0a, 0x06, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44,
|
||||||
"\x03tag\x18\x01 \x01(\tR\x03tag\x12\x16\n" +
|
0x52, 0x41, 0x49, 0x4e, 0x10, 0x01, 0x22, 0x38, 0x0a, 0x0c, 0x42, 0x72, 0x69, 0x64, 0x67, 0x65,
|
||||||
"\x06domain\x18\x02 \x01(\tR\x06domain\"8\n" +
|
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20,
|
||||||
"\fPortalConfig\x12\x10\n" +
|
0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61,
|
||||||
"\x03tag\x18\x01 \x01(\tR\x03tag\x12\x16\n" +
|
0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||||
"\x06domain\x18\x02 \x01(\tR\x06domain\"\x92\x01\n" +
|
0x22, 0x38, 0x0a, 0x0c, 0x50, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
"\x06Config\x12C\n" +
|
0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74,
|
||||||
"\rbridge_config\x18\x01 \x03(\v2\x1e.xray.app.reverse.BridgeConfigR\fbridgeConfig\x12C\n" +
|
0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01,
|
||||||
"\rportal_config\x18\x02 \x03(\v2\x1e.xray.app.reverse.PortalConfigR\fportalConfigBV\n" +
|
0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x92, 0x01, 0x0a, 0x06, 0x43,
|
||||||
"\x16com.xray.proxy.reverseP\x01Z%github.com/xtls/xray-core/app/reverse\xaa\x02\x12Xray.Proxy.Reverseb\x06proto3"
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x43, 0x0a, 0x0d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f,
|
||||||
|
0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x78,
|
||||||
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x2e,
|
||||||
|
0x42, 0x72, 0x69, 0x64, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0c, 0x62, 0x72,
|
||||||
|
0x69, 0x64, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x43, 0x0a, 0x0d, 0x70, 0x6f,
|
||||||
|
0x72, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x03, 0x28,
|
||||||
|
0x0b, 0x32, 0x1e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x65, 0x76,
|
||||||
|
0x65, 0x72, 0x73, 0x65, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||||
|
0x67, 0x52, 0x0c, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42,
|
||||||
|
0x56, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
||||||
|
0x79, 0x2e, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 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, 0x72, 0x65, 0x76, 0x65, 0x72,
|
||||||
|
0x73, 0x65, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e,
|
||||||
|
0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_app_reverse_config_proto_rawDescOnce sync.Once
|
file_app_reverse_config_proto_rawDescOnce sync.Once
|
||||||
file_app_reverse_config_proto_rawDescData []byte
|
file_app_reverse_config_proto_rawDescData = file_app_reverse_config_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_reverse_config_proto_rawDescGZIP() []byte {
|
func file_app_reverse_config_proto_rawDescGZIP() []byte {
|
||||||
file_app_reverse_config_proto_rawDescOnce.Do(func() {
|
file_app_reverse_config_proto_rawDescOnce.Do(func() {
|
||||||
file_app_reverse_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_reverse_config_proto_rawDesc), len(file_app_reverse_config_proto_rawDesc)))
|
file_app_reverse_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_reverse_config_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_reverse_config_proto_rawDescData
|
return file_app_reverse_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
@@ -339,7 +357,7 @@ func file_app_reverse_config_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_reverse_config_proto_rawDesc), len(file_app_reverse_config_proto_rawDesc)),
|
RawDescriptor: file_app_reverse_config_proto_rawDesc,
|
||||||
NumEnums: 1,
|
NumEnums: 1,
|
||||||
NumMessages: 4,
|
NumMessages: 4,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
@@ -351,6 +369,7 @@ func file_app_reverse_config_proto_init() {
|
|||||||
MessageInfos: file_app_reverse_config_proto_msgTypes,
|
MessageInfos: file_app_reverse_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_reverse_config_proto = out.File
|
File_app_reverse_config_proto = out.File
|
||||||
|
file_app_reverse_config_proto_rawDesc = nil
|
||||||
file_app_reverse_config_proto_goTypes = nil
|
file_app_reverse_config_proto_goTypes = nil
|
||||||
file_app_reverse_config_proto_depIdxs = nil
|
file_app_reverse_config_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-22
@@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/common/signal"
|
|
||||||
"github.com/xtls/xray-core/common/task"
|
"github.com/xtls/xray-core/common/task"
|
||||||
"github.com/xtls/xray-core/features/outbound"
|
"github.com/xtls/xray-core/features/outbound"
|
||||||
"github.com/xtls/xray-core/transport"
|
"github.com/xtls/xray-core/transport"
|
||||||
@@ -83,21 +82,9 @@ func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.picker.AddWorker(worker)
|
p.picker.AddWorker(worker)
|
||||||
|
|
||||||
if _, ok := link.Reader.(*pipe.Reader); !ok {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
case <-muxClient.WaitClosed():
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil && ob.OriginalTarget.Address != ob.Target.Address {
|
|
||||||
link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
|
||||||
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.client.Dispatch(ctx, link)
|
return p.client.Dispatch(ctx, link)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +101,6 @@ func (o *Outbound) Dispatch(ctx context.Context, link *transport.Link) {
|
|||||||
if err := o.portal.HandleConnection(ctx, link); err != nil {
|
if err := o.portal.HandleConnection(ctx, link); err != nil {
|
||||||
errors.LogInfoInner(ctx, err, "failed to process reverse connection")
|
errors.LogInfoInner(ctx, err, "failed to process reverse connection")
|
||||||
common.Interrupt(link.Writer)
|
common.Interrupt(link.Writer)
|
||||||
common.Interrupt(link.Reader)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,8 +146,6 @@ func (p *StaticMuxPicker) cleanup() error {
|
|||||||
for _, w := range p.workers {
|
for _, w := range p.workers {
|
||||||
if !w.Closed() {
|
if !w.Closed() {
|
||||||
activeWorkers = append(activeWorkers, w)
|
activeWorkers = append(activeWorkers, w)
|
||||||
} else {
|
|
||||||
w.timer.SetTimeout(0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +212,6 @@ type PortalWorker struct {
|
|||||||
reader buf.Reader
|
reader buf.Reader
|
||||||
draining bool
|
draining bool
|
||||||
counter uint32
|
counter uint32
|
||||||
timer *signal.ActivityTimer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
||||||
@@ -248,14 +231,10 @@ func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
|
|||||||
if !f {
|
if !f {
|
||||||
return nil, errors.New("unable to dispatch control connection")
|
return nil, errors.New("unable to dispatch control connection")
|
||||||
}
|
}
|
||||||
terminate := func() {
|
|
||||||
client.Close()
|
|
||||||
}
|
|
||||||
w := &PortalWorker{
|
w := &PortalWorker{
|
||||||
client: client,
|
client: client,
|
||||||
reader: downlinkReader,
|
reader: downlinkReader,
|
||||||
writer: uplinkWriter,
|
writer: uplinkWriter,
|
||||||
timer: signal.CancelAfterInactivity(ctx, terminate, 24*time.Hour), // // prevent leak
|
|
||||||
}
|
}
|
||||||
w.control = &task.Periodic{
|
w.control = &task.Periodic{
|
||||||
Execute: w.heartbeat,
|
Execute: w.heartbeat,
|
||||||
@@ -282,6 +261,7 @@ func (w *PortalWorker) heartbeat() error {
|
|||||||
msg.State = Control_DRAIN
|
msg.State = Control_DRAIN
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
w.client.GetTimer().Reset(time.Second * 16)
|
||||||
common.Close(w.writer)
|
common.Close(w.writer)
|
||||||
common.Interrupt(w.reader)
|
common.Interrupt(w.reader)
|
||||||
w.writer = nil
|
w.writer = nil
|
||||||
@@ -293,7 +273,6 @@ func (w *PortalWorker) heartbeat() error {
|
|||||||
b, err := proto.Marshal(msg)
|
b, err := proto.Marshal(msg)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
mb := buf.MergeBytes(nil, b)
|
mb := buf.MergeBytes(nil, b)
|
||||||
w.timer.Update()
|
|
||||||
return w.writer.WriteMultiBuffer(mb)
|
return w.writer.WriteMultiBuffer(mb)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
internalDomain = "reverse"
|
internalDomain = "reverse.internal.v2fly.org" // make reverse proxy compatible with v2fly
|
||||||
)
|
)
|
||||||
|
|
||||||
func isDomain(dest net.Destination, domain string) bool {
|
func isDomain(dest net.Destination, domain string) bool {
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ func (s *routingServer) AddRule(ctx context.Context, request *AddRuleRequest) (*
|
|||||||
return &AddRuleResponse{}, bo.AddRule(request.Config, request.ShouldAppend)
|
return &AddRuleResponse{}, bo.AddRule(request.Config, request.ShouldAppend)
|
||||||
}
|
}
|
||||||
return nil, errors.New("unsupported router implementation")
|
return nil, errors.New("unsupported router implementation")
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
func (s *routingServer) RemoveRule(ctx context.Context, request *RemoveRuleRequest) (*RemoveRuleResponse, error) {
|
func (s *routingServer) RemoveRule(ctx context.Context, request *RemoveRuleRequest) (*RemoveRuleResponse, error) {
|
||||||
if bo, ok := s.router.(routing.Router); ok {
|
if bo, ok := s.router.(routing.Router); ok {
|
||||||
return &RemoveRuleResponse{}, bo.RemoveRule(request.RuleTag)
|
return &RemoveRuleResponse{}, bo.RemoveRule(request.RuleTag)
|
||||||
@@ -67,20 +67,6 @@ func (s *routingServer) RemoveRule(ctx context.Context, request *RemoveRuleReque
|
|||||||
return nil, errors.New("unsupported router implementation")
|
return nil, errors.New("unsupported router implementation")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *routingServer) ListRule(ctx context.Context, request *ListRuleRequest) (*ListRuleResponse, error) {
|
|
||||||
if bo, ok := s.router.(routing.Router); ok {
|
|
||||||
response := &ListRuleResponse{}
|
|
||||||
for _, v := range bo.ListRule() {
|
|
||||||
response.Rules = append(response.Rules, &ListRuleItem{
|
|
||||||
Tag: v.GetOutboundTag(),
|
|
||||||
RuleTag: v.GetRuleTag(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return response, nil
|
|
||||||
}
|
|
||||||
return nil, errors.New("unsupported router implementation")
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRoutingServer creates a statistics service with statistics manager.
|
// NewRoutingServer creates a statistics service with statistics manager.
|
||||||
func NewRoutingServer(router routing.Router, routingStats stats.Channel) RoutingServiceServer {
|
func NewRoutingServer(router routing.Router, routingStats stats.Channel) RoutingServiceServer {
|
||||||
return &routingServer{
|
return &routingServer{
|
||||||
|
|||||||
+272
-315
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v6.33.5
|
// protoc v5.28.2
|
||||||
// source: app/router/command/command.proto
|
// source: app/router/command/command.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -27,24 +26,25 @@ const (
|
|||||||
// It conforms to the structure of xray.features.routing.Context and
|
// It conforms to the structure of xray.features.routing.Context and
|
||||||
// xray.features.routing.Route.
|
// xray.features.routing.Route.
|
||||||
type RoutingContext struct {
|
type RoutingContext struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
InboundTag string `protobuf:"bytes,1,opt,name=InboundTag,proto3" json:"InboundTag,omitempty"`
|
sizeCache protoimpl.SizeCache
|
||||||
Network net.Network `protobuf:"varint,2,opt,name=Network,proto3,enum=xray.common.net.Network" json:"Network,omitempty"`
|
unknownFields protoimpl.UnknownFields
|
||||||
SourceIPs [][]byte `protobuf:"bytes,3,rep,name=SourceIPs,proto3" json:"SourceIPs,omitempty"`
|
|
||||||
TargetIPs [][]byte `protobuf:"bytes,4,rep,name=TargetIPs,proto3" json:"TargetIPs,omitempty"`
|
InboundTag string `protobuf:"bytes,1,opt,name=InboundTag,proto3" json:"InboundTag,omitempty"`
|
||||||
SourcePort uint32 `protobuf:"varint,5,opt,name=SourcePort,proto3" json:"SourcePort,omitempty"`
|
Network net.Network `protobuf:"varint,2,opt,name=Network,proto3,enum=xray.common.net.Network" json:"Network,omitempty"`
|
||||||
TargetPort uint32 `protobuf:"varint,6,opt,name=TargetPort,proto3" json:"TargetPort,omitempty"`
|
SourceIPs [][]byte `protobuf:"bytes,3,rep,name=SourceIPs,proto3" json:"SourceIPs,omitempty"`
|
||||||
TargetDomain string `protobuf:"bytes,7,opt,name=TargetDomain,proto3" json:"TargetDomain,omitempty"`
|
TargetIPs [][]byte `protobuf:"bytes,4,rep,name=TargetIPs,proto3" json:"TargetIPs,omitempty"`
|
||||||
Protocol string `protobuf:"bytes,8,opt,name=Protocol,proto3" json:"Protocol,omitempty"`
|
SourcePort uint32 `protobuf:"varint,5,opt,name=SourcePort,proto3" json:"SourcePort,omitempty"`
|
||||||
User string `protobuf:"bytes,9,opt,name=User,proto3" json:"User,omitempty"`
|
TargetPort uint32 `protobuf:"varint,6,opt,name=TargetPort,proto3" json:"TargetPort,omitempty"`
|
||||||
Attributes map[string]string `protobuf:"bytes,10,rep,name=Attributes,proto3" json:"Attributes,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
TargetDomain string `protobuf:"bytes,7,opt,name=TargetDomain,proto3" json:"TargetDomain,omitempty"`
|
||||||
OutboundGroupTags []string `protobuf:"bytes,11,rep,name=OutboundGroupTags,proto3" json:"OutboundGroupTags,omitempty"`
|
Protocol string `protobuf:"bytes,8,opt,name=Protocol,proto3" json:"Protocol,omitempty"`
|
||||||
OutboundTag string `protobuf:"bytes,12,opt,name=OutboundTag,proto3" json:"OutboundTag,omitempty"`
|
User string `protobuf:"bytes,9,opt,name=User,proto3" json:"User,omitempty"`
|
||||||
LocalIPs [][]byte `protobuf:"bytes,13,rep,name=LocalIPs,proto3" json:"LocalIPs,omitempty"`
|
Attributes map[string]string `protobuf:"bytes,10,rep,name=Attributes,proto3" json:"Attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
LocalPort uint32 `protobuf:"varint,14,opt,name=LocalPort,proto3" json:"LocalPort,omitempty"`
|
OutboundGroupTags []string `protobuf:"bytes,11,rep,name=OutboundGroupTags,proto3" json:"OutboundGroupTags,omitempty"`
|
||||||
VlessRoute uint32 `protobuf:"varint,15,opt,name=VlessRoute,proto3" json:"VlessRoute,omitempty"`
|
OutboundTag string `protobuf:"bytes,12,opt,name=OutboundTag,proto3" json:"OutboundTag,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
LocalIPs [][]byte `protobuf:"bytes,13,rep,name=LocalIPs,proto3" json:"LocalIPs,omitempty"`
|
||||||
sizeCache protoimpl.SizeCache
|
LocalPort uint32 `protobuf:"varint,14,opt,name=LocalPort,proto3" json:"LocalPort,omitempty"`
|
||||||
|
VlessRoute uint32 `protobuf:"varint,15,opt,name=VlessRoute,proto3" json:"VlessRoute,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RoutingContext) Reset() {
|
func (x *RoutingContext) Reset() {
|
||||||
@@ -201,10 +201,11 @@ func (x *RoutingContext) GetVlessRoute() uint32 {
|
|||||||
//
|
//
|
||||||
// * If FieldSelectors is left empty, all fields will be returned.
|
// * If FieldSelectors is left empty, all fields will be returned.
|
||||||
type SubscribeRoutingStatsRequest struct {
|
type SubscribeRoutingStatsRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
FieldSelectors []string `protobuf:"bytes,1,rep,name=FieldSelectors,proto3" json:"FieldSelectors,omitempty"`
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
|
FieldSelectors []string `protobuf:"bytes,1,rep,name=FieldSelectors,proto3" json:"FieldSelectors,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SubscribeRoutingStatsRequest) Reset() {
|
func (x *SubscribeRoutingStatsRequest) Reset() {
|
||||||
@@ -252,12 +253,13 @@ func (x *SubscribeRoutingStatsRequest) GetFieldSelectors() []string {
|
|||||||
// * PublishResult broadcasts the routing result to routing statistics channel
|
// * PublishResult broadcasts the routing result to routing statistics channel
|
||||||
// if set true.
|
// if set true.
|
||||||
type TestRouteRequest struct {
|
type TestRouteRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
RoutingContext *RoutingContext `protobuf:"bytes,1,opt,name=RoutingContext,proto3" json:"RoutingContext,omitempty"`
|
sizeCache protoimpl.SizeCache
|
||||||
FieldSelectors []string `protobuf:"bytes,2,rep,name=FieldSelectors,proto3" json:"FieldSelectors,omitempty"`
|
unknownFields protoimpl.UnknownFields
|
||||||
PublishResult bool `protobuf:"varint,3,opt,name=PublishResult,proto3" json:"PublishResult,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
RoutingContext *RoutingContext `protobuf:"bytes,1,opt,name=RoutingContext,proto3" json:"RoutingContext,omitempty"`
|
||||||
sizeCache protoimpl.SizeCache
|
FieldSelectors []string `protobuf:"bytes,2,rep,name=FieldSelectors,proto3" json:"FieldSelectors,omitempty"`
|
||||||
|
PublishResult bool `protobuf:"varint,3,opt,name=PublishResult,proto3" json:"PublishResult,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *TestRouteRequest) Reset() {
|
func (x *TestRouteRequest) Reset() {
|
||||||
@@ -312,10 +314,11 @@ func (x *TestRouteRequest) GetPublishResult() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PrincipleTargetInfo struct {
|
type PrincipleTargetInfo struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Tag []string `protobuf:"bytes,1,rep,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Tag []string `protobuf:"bytes,1,rep,name=tag,proto3" json:"tag,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *PrincipleTargetInfo) Reset() {
|
func (x *PrincipleTargetInfo) Reset() {
|
||||||
@@ -356,10 +359,11 @@ func (x *PrincipleTargetInfo) GetTag() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OverrideInfo struct {
|
type OverrideInfo struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OverrideInfo) Reset() {
|
func (x *OverrideInfo) Reset() {
|
||||||
@@ -400,11 +404,12 @@ func (x *OverrideInfo) GetTarget() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BalancerMsg struct {
|
type BalancerMsg struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Override *OverrideInfo `protobuf:"bytes,5,opt,name=override,proto3" json:"override,omitempty"`
|
sizeCache protoimpl.SizeCache
|
||||||
PrincipleTarget *PrincipleTargetInfo `protobuf:"bytes,6,opt,name=principle_target,json=principleTarget,proto3" json:"principle_target,omitempty"`
|
unknownFields protoimpl.UnknownFields
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
Override *OverrideInfo `protobuf:"bytes,5,opt,name=override,proto3" json:"override,omitempty"`
|
||||||
|
PrincipleTarget *PrincipleTargetInfo `protobuf:"bytes,6,opt,name=principle_target,json=principleTarget,proto3" json:"principle_target,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *BalancerMsg) Reset() {
|
func (x *BalancerMsg) Reset() {
|
||||||
@@ -452,10 +457,11 @@ func (x *BalancerMsg) GetPrincipleTarget() *PrincipleTargetInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetBalancerInfoRequest struct {
|
type GetBalancerInfoRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetBalancerInfoRequest) Reset() {
|
func (x *GetBalancerInfoRequest) Reset() {
|
||||||
@@ -496,10 +502,11 @@ func (x *GetBalancerInfoRequest) GetTag() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetBalancerInfoResponse struct {
|
type GetBalancerInfoResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Balancer *BalancerMsg `protobuf:"bytes,1,opt,name=balancer,proto3" json:"balancer,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Balancer *BalancerMsg `protobuf:"bytes,1,opt,name=balancer,proto3" json:"balancer,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetBalancerInfoResponse) Reset() {
|
func (x *GetBalancerInfoResponse) Reset() {
|
||||||
@@ -540,11 +547,12 @@ func (x *GetBalancerInfoResponse) GetBalancer() *BalancerMsg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OverrideBalancerTargetRequest struct {
|
type OverrideBalancerTargetRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
BalancerTag string `protobuf:"bytes,1,opt,name=balancerTag,proto3" json:"balancerTag,omitempty"`
|
|
||||||
Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
BalancerTag string `protobuf:"bytes,1,opt,name=balancerTag,proto3" json:"balancerTag,omitempty"`
|
||||||
|
Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OverrideBalancerTargetRequest) Reset() {
|
func (x *OverrideBalancerTargetRequest) Reset() {
|
||||||
@@ -592,9 +600,9 @@ func (x *OverrideBalancerTargetRequest) GetTarget() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OverrideBalancerTargetResponse struct {
|
type OverrideBalancerTargetResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OverrideBalancerTargetResponse) Reset() {
|
func (x *OverrideBalancerTargetResponse) Reset() {
|
||||||
@@ -628,11 +636,12 @@ func (*OverrideBalancerTargetResponse) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AddRuleRequest struct {
|
type AddRuleRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
Config *serial.TypedMessage `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
|
|
||||||
ShouldAppend bool `protobuf:"varint,2,opt,name=shouldAppend,proto3" json:"shouldAppend,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Config *serial.TypedMessage `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
|
||||||
|
ShouldAppend bool `protobuf:"varint,2,opt,name=shouldAppend,proto3" json:"shouldAppend,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddRuleRequest) Reset() {
|
func (x *AddRuleRequest) Reset() {
|
||||||
@@ -680,9 +689,9 @@ func (x *AddRuleRequest) GetShouldAppend() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AddRuleResponse struct {
|
type AddRuleResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddRuleResponse) Reset() {
|
func (x *AddRuleResponse) Reset() {
|
||||||
@@ -716,10 +725,11 @@ func (*AddRuleResponse) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RemoveRuleRequest struct {
|
type RemoveRuleRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
RuleTag string `protobuf:"bytes,1,opt,name=ruleTag,proto3" json:"ruleTag,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
RuleTag string `protobuf:"bytes,1,opt,name=ruleTag,proto3" json:"ruleTag,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveRuleRequest) Reset() {
|
func (x *RemoveRuleRequest) Reset() {
|
||||||
@@ -760,9 +770,9 @@ func (x *RemoveRuleRequest) GetRuleTag() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RemoveRuleResponse struct {
|
type RemoveRuleResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveRuleResponse) Reset() {
|
func (x *RemoveRuleResponse) Reset() {
|
||||||
@@ -795,147 +805,15 @@ func (*RemoveRuleResponse) Descriptor() ([]byte, []int) {
|
|||||||
return file_app_router_command_command_proto_rawDescGZIP(), []int{13}
|
return file_app_router_command_command_proto_rawDescGZIP(), []int{13}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListRuleRequest struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListRuleRequest) Reset() {
|
|
||||||
*x = ListRuleRequest{}
|
|
||||||
mi := &file_app_router_command_command_proto_msgTypes[14]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListRuleRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*ListRuleRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *ListRuleRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_router_command_command_proto_msgTypes[14]
|
|
||||||
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 ListRuleRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*ListRuleRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_router_command_command_proto_rawDescGZIP(), []int{14}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListRuleItem struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
RuleTag string `protobuf:"bytes,2,opt,name=ruleTag,proto3" json:"ruleTag,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListRuleItem) Reset() {
|
|
||||||
*x = ListRuleItem{}
|
|
||||||
mi := &file_app_router_command_command_proto_msgTypes[15]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListRuleItem) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*ListRuleItem) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *ListRuleItem) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_router_command_command_proto_msgTypes[15]
|
|
||||||
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 ListRuleItem.ProtoReflect.Descriptor instead.
|
|
||||||
func (*ListRuleItem) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_router_command_command_proto_rawDescGZIP(), []int{15}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListRuleItem) GetTag() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Tag
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListRuleItem) GetRuleTag() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.RuleTag
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListRuleResponse struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Rules []*ListRuleItem `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListRuleResponse) Reset() {
|
|
||||||
*x = ListRuleResponse{}
|
|
||||||
mi := &file_app_router_command_command_proto_msgTypes[16]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListRuleResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*ListRuleResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *ListRuleResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_app_router_command_command_proto_msgTypes[16]
|
|
||||||
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 ListRuleResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*ListRuleResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_app_router_command_command_proto_rawDescGZIP(), []int{16}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ListRuleResponse) GetRules() []*ListRuleItem {
|
|
||||||
if x != nil {
|
|
||||||
return x.Rules
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
mi := &file_app_router_command_command_proto_msgTypes[17]
|
mi := &file_app_router_command_command_proto_msgTypes[14]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -947,7 +825,7 @@ func (x *Config) String() string {
|
|||||||
func (*Config) ProtoMessage() {}
|
func (*Config) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_router_command_command_proto_msgTypes[17]
|
mi := &file_app_router_command_command_proto_msgTypes[14]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -960,103 +838,187 @@ func (x *Config) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||||
func (*Config) Descriptor() ([]byte, []int) {
|
func (*Config) Descriptor() ([]byte, []int) {
|
||||||
return file_app_router_command_command_proto_rawDescGZIP(), []int{17}
|
return file_app_router_command_command_proto_rawDescGZIP(), []int{14}
|
||||||
}
|
}
|
||||||
|
|
||||||
var File_app_router_command_command_proto protoreflect.FileDescriptor
|
var File_app_router_command_command_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_router_command_command_proto_rawDesc = "" +
|
var file_app_router_command_command_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x20, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d,
|
||||||
" app/router/command/command.proto\x12\x17xray.app.router.command\x1a\x18common/net/network.proto\x1a!common/serial/typed_message.proto\"\xf6\x04\n" +
|
0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
"\x0eRoutingContext\x12\x1e\n" +
|
0x74, 0x6f, 0x12, 0x17, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
|
||||||
"\n" +
|
0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x18, 0x63, 0x6f, 0x6d,
|
||||||
"InboundTag\x18\x01 \x01(\tR\n" +
|
0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e,
|
||||||
"InboundTag\x122\n" +
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65,
|
||||||
"\aNetwork\x18\x02 \x01(\x0e2\x18.xray.common.net.NetworkR\aNetwork\x12\x1c\n" +
|
0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61,
|
||||||
"\tSourceIPs\x18\x03 \x03(\fR\tSourceIPs\x12\x1c\n" +
|
0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf6, 0x04, 0x0a, 0x0e, 0x52, 0x6f, 0x75,
|
||||||
"\tTargetIPs\x18\x04 \x03(\fR\tTargetIPs\x12\x1e\n" +
|
0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x49,
|
||||||
"\n" +
|
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
"SourcePort\x18\x05 \x01(\rR\n" +
|
0x0a, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x32, 0x0a, 0x07, 0x4e,
|
||||||
"SourcePort\x12\x1e\n" +
|
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78,
|
||||||
"\n" +
|
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e,
|
||||||
"TargetPort\x18\x06 \x01(\rR\n" +
|
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12,
|
||||||
"TargetPort\x12\"\n" +
|
0x1c, 0x0a, 0x09, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x50, 0x73, 0x18, 0x03, 0x20, 0x03,
|
||||||
"\fTargetDomain\x18\a \x01(\tR\fTargetDomain\x12\x1a\n" +
|
0x28, 0x0c, 0x52, 0x09, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x50, 0x73, 0x12, 0x1c, 0x0a,
|
||||||
"\bProtocol\x18\b \x01(\tR\bProtocol\x12\x12\n" +
|
0x09, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x50, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c,
|
||||||
"\x04User\x18\t \x01(\tR\x04User\x12W\n" +
|
0x52, 0x09, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x50, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x53,
|
||||||
"\n" +
|
0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
||||||
"Attributes\x18\n" +
|
0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x54,
|
||||||
" \x03(\v27.xray.app.router.command.RoutingContext.AttributesEntryR\n" +
|
0x61, 0x72, 0x67, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
||||||
"Attributes\x12,\n" +
|
0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x54,
|
||||||
"\x11OutboundGroupTags\x18\v \x03(\tR\x11OutboundGroupTags\x12 \n" +
|
0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28,
|
||||||
"\vOutboundTag\x18\f \x01(\tR\vOutboundTag\x12\x1a\n" +
|
0x09, 0x52, 0x0c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12,
|
||||||
"\bLocalIPs\x18\r \x03(\fR\bLocalIPs\x12\x1c\n" +
|
0x1a, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28,
|
||||||
"\tLocalPort\x18\x0e \x01(\rR\tLocalPort\x12\x1e\n" +
|
0x09, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x55,
|
||||||
"\n" +
|
0x73, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12,
|
||||||
"VlessRoute\x18\x0f \x01(\rR\n" +
|
0x57, 0x0a, 0x0a, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0a, 0x20,
|
||||||
"VlessRoute\x1a=\n" +
|
0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
||||||
"\x0fAttributesEntry\x12\x10\n" +
|
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f,
|
||||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x41, 0x74, 0x74,
|
||||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"F\n" +
|
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x41, 0x74,
|
||||||
"\x1cSubscribeRoutingStatsRequest\x12&\n" +
|
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x4f, 0x75, 0x74, 0x62,
|
||||||
"\x0eFieldSelectors\x18\x01 \x03(\tR\x0eFieldSelectors\"\xb1\x01\n" +
|
0x6f, 0x75, 0x6e, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x18, 0x0b, 0x20,
|
||||||
"\x10TestRouteRequest\x12O\n" +
|
0x03, 0x28, 0x09, 0x52, 0x11, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x47, 0x72, 0x6f,
|
||||||
"\x0eRoutingContext\x18\x01 \x01(\v2'.xray.app.router.command.RoutingContextR\x0eRoutingContext\x12&\n" +
|
0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75,
|
||||||
"\x0eFieldSelectors\x18\x02 \x03(\tR\x0eFieldSelectors\x12$\n" +
|
0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x75, 0x74,
|
||||||
"\rPublishResult\x18\x03 \x01(\bR\rPublishResult\"'\n" +
|
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61,
|
||||||
"\x13PrincipleTargetInfo\x12\x10\n" +
|
0x6c, 0x49, 0x50, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x4c, 0x6f, 0x63, 0x61,
|
||||||
"\x03tag\x18\x01 \x03(\tR\x03tag\"&\n" +
|
0x6c, 0x49, 0x50, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72,
|
||||||
"\fOverrideInfo\x12\x16\n" +
|
0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f,
|
||||||
"\x06target\x18\x02 \x01(\tR\x06target\"\xa9\x01\n" +
|
0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
||||||
"\vBalancerMsg\x12A\n" +
|
0x18, 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x75,
|
||||||
"\boverride\x18\x05 \x01(\v2%.xray.app.router.command.OverrideInfoR\boverride\x12W\n" +
|
0x74, 0x65, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
|
||||||
"\x10principle_target\x18\x06 \x01(\v2,.xray.app.router.command.PrincipleTargetInfoR\x0fprincipleTarget\"*\n" +
|
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
||||||
"\x16GetBalancerInfoRequest\x12\x10\n" +
|
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||||
"\x03tag\x18\x01 \x01(\tR\x03tag\"[\n" +
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
|
||||||
"\x17GetBalancerInfoResponse\x12@\n" +
|
0x01, 0x22, 0x46, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f,
|
||||||
"\bbalancer\x18\x01 \x01(\v2$.xray.app.router.command.BalancerMsgR\bbalancer\"Y\n" +
|
0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
"\x1dOverrideBalancerTargetRequest\x12 \n" +
|
0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74,
|
||||||
"\vbalancerTag\x18\x01 \x01(\tR\vbalancerTag\x12\x16\n" +
|
0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64,
|
||||||
"\x06target\x18\x02 \x01(\tR\x06target\" \n" +
|
0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xb1, 0x01, 0x0a, 0x10, 0x54, 0x65,
|
||||||
"\x1eOverrideBalancerTargetResponse\"n\n" +
|
0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4f,
|
||||||
"\x0eAddRuleRequest\x128\n" +
|
0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
|
||||||
"\x06config\x18\x01 \x01(\v2 .xray.common.serial.TypedMessageR\x06config\x12\"\n" +
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||||
"\fshouldAppend\x18\x02 \x01(\bR\fshouldAppend\"\x11\n" +
|
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||||
"\x0fAddRuleResponse\"-\n" +
|
0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52,
|
||||||
"\x11RemoveRuleRequest\x12\x18\n" +
|
0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12,
|
||||||
"\aruleTag\x18\x01 \x01(\tR\aruleTag\"\x14\n" +
|
0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72,
|
||||||
"\x12RemoveRuleResponse\"\x11\n" +
|
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65,
|
||||||
"\x0fListRuleRequest\":\n" +
|
0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69,
|
||||||
"\fListRuleItem\x12\x10\n" +
|
0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d,
|
||||||
"\x03tag\x18\x01 \x01(\tR\x03tag\x12\x18\n" +
|
0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x27, 0x0a,
|
||||||
"\aruleTag\x18\x02 \x01(\tR\aruleTag\"O\n" +
|
0x13, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||||
"\x10ListRuleResponse\x12;\n" +
|
0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28,
|
||||||
"\x05rules\x18\x01 \x03(\v2%.xray.app.router.command.ListRuleItemR\x05rules\"\b\n" +
|
0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x26, 0x0a, 0x0c, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
||||||
"\x06Config2\xa2\x06\n" +
|
0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||||
"\x0eRoutingService\x12{\n" +
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0xa9,
|
||||||
"\x15SubscribeRoutingStats\x125.xray.app.router.command.SubscribeRoutingStatsRequest\x1a'.xray.app.router.command.RoutingContext\"\x000\x01\x12a\n" +
|
0x01, 0x0a, 0x0b, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x41,
|
||||||
"\tTestRoute\x12).xray.app.router.command.TestRouteRequest\x1a'.xray.app.router.command.RoutingContext\"\x00\x12v\n" +
|
0x0a, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
|
||||||
"\x0fGetBalancerInfo\x12/.xray.app.router.command.GetBalancerInfoRequest\x1a0.xray.app.router.command.GetBalancerInfoResponse\"\x00\x12\x8b\x01\n" +
|
0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||||
"\x16OverrideBalancerTarget\x126.xray.app.router.command.OverrideBalancerTargetRequest\x1a7.xray.app.router.command.OverrideBalancerTargetResponse\"\x00\x12^\n" +
|
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72,
|
||||||
"\aAddRule\x12'.xray.app.router.command.AddRuleRequest\x1a(.xray.app.router.command.AddRuleResponse\"\x00\x12g\n" +
|
0x69, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
|
||||||
"\n" +
|
0x65, 0x12, 0x57, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x74,
|
||||||
"RemoveRule\x12*.xray.app.router.command.RemoveRuleRequest\x1a+.xray.app.router.command.RemoveRuleResponse\"\x00\x12a\n" +
|
0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72,
|
||||||
"\bListRule\x12(.xray.app.router.command.ListRuleRequest\x1a).xray.app.router.command.ListRuleResponse\"\x00Bg\n" +
|
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f,
|
||||||
"\x1bcom.xray.app.router.commandP\x01Z,github.com/xtls/xray-core/app/router/command\xaa\x02\x17Xray.App.Router.Commandb\x06proto3"
|
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, 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, 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 (
|
var (
|
||||||
file_app_router_command_command_proto_rawDescOnce sync.Once
|
file_app_router_command_command_proto_rawDescOnce sync.Once
|
||||||
file_app_router_command_command_proto_rawDescData []byte
|
file_app_router_command_command_proto_rawDescData = file_app_router_command_command_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_router_command_command_proto_rawDescGZIP() []byte {
|
func file_app_router_command_command_proto_rawDescGZIP() []byte {
|
||||||
file_app_router_command_command_proto_rawDescOnce.Do(func() {
|
file_app_router_command_command_proto_rawDescOnce.Do(func() {
|
||||||
file_app_router_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_router_command_command_proto_rawDesc), len(file_app_router_command_command_proto_rawDesc)))
|
file_app_router_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_router_command_command_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_app_router_command_command_proto_rawDescData
|
return file_app_router_command_command_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_app_router_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 19)
|
var file_app_router_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 16)
|
||||||
var file_app_router_command_command_proto_goTypes = []any{
|
var file_app_router_command_command_proto_goTypes = []any{
|
||||||
(*RoutingContext)(nil), // 0: xray.app.router.command.RoutingContext
|
(*RoutingContext)(nil), // 0: xray.app.router.command.RoutingContext
|
||||||
(*SubscribeRoutingStatsRequest)(nil), // 1: xray.app.router.command.SubscribeRoutingStatsRequest
|
(*SubscribeRoutingStatsRequest)(nil), // 1: xray.app.router.command.SubscribeRoutingStatsRequest
|
||||||
@@ -1072,42 +1034,36 @@ var file_app_router_command_command_proto_goTypes = []any{
|
|||||||
(*AddRuleResponse)(nil), // 11: xray.app.router.command.AddRuleResponse
|
(*AddRuleResponse)(nil), // 11: xray.app.router.command.AddRuleResponse
|
||||||
(*RemoveRuleRequest)(nil), // 12: xray.app.router.command.RemoveRuleRequest
|
(*RemoveRuleRequest)(nil), // 12: xray.app.router.command.RemoveRuleRequest
|
||||||
(*RemoveRuleResponse)(nil), // 13: xray.app.router.command.RemoveRuleResponse
|
(*RemoveRuleResponse)(nil), // 13: xray.app.router.command.RemoveRuleResponse
|
||||||
(*ListRuleRequest)(nil), // 14: xray.app.router.command.ListRuleRequest
|
(*Config)(nil), // 14: xray.app.router.command.Config
|
||||||
(*ListRuleItem)(nil), // 15: xray.app.router.command.ListRuleItem
|
nil, // 15: xray.app.router.command.RoutingContext.AttributesEntry
|
||||||
(*ListRuleResponse)(nil), // 16: xray.app.router.command.ListRuleResponse
|
(net.Network)(0), // 16: xray.common.net.Network
|
||||||
(*Config)(nil), // 17: xray.app.router.command.Config
|
(*serial.TypedMessage)(nil), // 17: xray.common.serial.TypedMessage
|
||||||
nil, // 18: xray.app.router.command.RoutingContext.AttributesEntry
|
|
||||||
(net.Network)(0), // 19: xray.common.net.Network
|
|
||||||
(*serial.TypedMessage)(nil), // 20: xray.common.serial.TypedMessage
|
|
||||||
}
|
}
|
||||||
var file_app_router_command_command_proto_depIdxs = []int32{
|
var file_app_router_command_command_proto_depIdxs = []int32{
|
||||||
19, // 0: xray.app.router.command.RoutingContext.Network:type_name -> xray.common.net.Network
|
16, // 0: xray.app.router.command.RoutingContext.Network:type_name -> xray.common.net.Network
|
||||||
18, // 1: xray.app.router.command.RoutingContext.Attributes:type_name -> xray.app.router.command.RoutingContext.AttributesEntry
|
15, // 1: xray.app.router.command.RoutingContext.Attributes:type_name -> xray.app.router.command.RoutingContext.AttributesEntry
|
||||||
0, // 2: xray.app.router.command.TestRouteRequest.RoutingContext:type_name -> xray.app.router.command.RoutingContext
|
0, // 2: xray.app.router.command.TestRouteRequest.RoutingContext:type_name -> xray.app.router.command.RoutingContext
|
||||||
4, // 3: xray.app.router.command.BalancerMsg.override:type_name -> xray.app.router.command.OverrideInfo
|
4, // 3: xray.app.router.command.BalancerMsg.override:type_name -> xray.app.router.command.OverrideInfo
|
||||||
3, // 4: xray.app.router.command.BalancerMsg.principle_target:type_name -> xray.app.router.command.PrincipleTargetInfo
|
3, // 4: xray.app.router.command.BalancerMsg.principle_target:type_name -> xray.app.router.command.PrincipleTargetInfo
|
||||||
5, // 5: xray.app.router.command.GetBalancerInfoResponse.balancer:type_name -> xray.app.router.command.BalancerMsg
|
5, // 5: xray.app.router.command.GetBalancerInfoResponse.balancer:type_name -> xray.app.router.command.BalancerMsg
|
||||||
20, // 6: xray.app.router.command.AddRuleRequest.config:type_name -> xray.common.serial.TypedMessage
|
17, // 6: xray.app.router.command.AddRuleRequest.config:type_name -> xray.common.serial.TypedMessage
|
||||||
15, // 7: xray.app.router.command.ListRuleResponse.rules:type_name -> xray.app.router.command.ListRuleItem
|
1, // 7: xray.app.router.command.RoutingService.SubscribeRoutingStats:input_type -> xray.app.router.command.SubscribeRoutingStatsRequest
|
||||||
1, // 8: xray.app.router.command.RoutingService.SubscribeRoutingStats:input_type -> xray.app.router.command.SubscribeRoutingStatsRequest
|
2, // 8: xray.app.router.command.RoutingService.TestRoute:input_type -> xray.app.router.command.TestRouteRequest
|
||||||
2, // 9: xray.app.router.command.RoutingService.TestRoute:input_type -> xray.app.router.command.TestRouteRequest
|
6, // 9: xray.app.router.command.RoutingService.GetBalancerInfo:input_type -> xray.app.router.command.GetBalancerInfoRequest
|
||||||
6, // 10: xray.app.router.command.RoutingService.GetBalancerInfo:input_type -> xray.app.router.command.GetBalancerInfoRequest
|
8, // 10: xray.app.router.command.RoutingService.OverrideBalancerTarget:input_type -> xray.app.router.command.OverrideBalancerTargetRequest
|
||||||
8, // 11: xray.app.router.command.RoutingService.OverrideBalancerTarget:input_type -> xray.app.router.command.OverrideBalancerTargetRequest
|
10, // 11: xray.app.router.command.RoutingService.AddRule:input_type -> xray.app.router.command.AddRuleRequest
|
||||||
10, // 12: xray.app.router.command.RoutingService.AddRule:input_type -> xray.app.router.command.AddRuleRequest
|
12, // 12: xray.app.router.command.RoutingService.RemoveRule:input_type -> xray.app.router.command.RemoveRuleRequest
|
||||||
12, // 13: xray.app.router.command.RoutingService.RemoveRule:input_type -> xray.app.router.command.RemoveRuleRequest
|
0, // 13: xray.app.router.command.RoutingService.SubscribeRoutingStats:output_type -> xray.app.router.command.RoutingContext
|
||||||
14, // 14: xray.app.router.command.RoutingService.ListRule:input_type -> xray.app.router.command.ListRuleRequest
|
0, // 14: xray.app.router.command.RoutingService.TestRoute:output_type -> xray.app.router.command.RoutingContext
|
||||||
0, // 15: xray.app.router.command.RoutingService.SubscribeRoutingStats:output_type -> xray.app.router.command.RoutingContext
|
7, // 15: xray.app.router.command.RoutingService.GetBalancerInfo:output_type -> xray.app.router.command.GetBalancerInfoResponse
|
||||||
0, // 16: xray.app.router.command.RoutingService.TestRoute:output_type -> xray.app.router.command.RoutingContext
|
9, // 16: xray.app.router.command.RoutingService.OverrideBalancerTarget:output_type -> xray.app.router.command.OverrideBalancerTargetResponse
|
||||||
7, // 17: xray.app.router.command.RoutingService.GetBalancerInfo:output_type -> xray.app.router.command.GetBalancerInfoResponse
|
11, // 17: xray.app.router.command.RoutingService.AddRule:output_type -> xray.app.router.command.AddRuleResponse
|
||||||
9, // 18: xray.app.router.command.RoutingService.OverrideBalancerTarget:output_type -> xray.app.router.command.OverrideBalancerTargetResponse
|
13, // 18: xray.app.router.command.RoutingService.RemoveRule:output_type -> xray.app.router.command.RemoveRuleResponse
|
||||||
11, // 19: xray.app.router.command.RoutingService.AddRule:output_type -> xray.app.router.command.AddRuleResponse
|
13, // [13:19] is the sub-list for method output_type
|
||||||
13, // 20: xray.app.router.command.RoutingService.RemoveRule:output_type -> xray.app.router.command.RemoveRuleResponse
|
7, // [7:13] is the sub-list for method input_type
|
||||||
16, // 21: xray.app.router.command.RoutingService.ListRule:output_type -> xray.app.router.command.ListRuleResponse
|
7, // [7:7] is the sub-list for extension type_name
|
||||||
15, // [15:22] is the sub-list for method output_type
|
7, // [7:7] is the sub-list for extension extendee
|
||||||
8, // [8:15] is the sub-list for method input_type
|
0, // [0:7] is the sub-list for field type_name
|
||||||
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_router_command_command_proto_init() }
|
func init() { file_app_router_command_command_proto_init() }
|
||||||
@@ -1119,9 +1075,9 @@ func file_app_router_command_command_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_router_command_command_proto_rawDesc), len(file_app_router_command_command_proto_rawDesc)),
|
RawDescriptor: file_app_router_command_command_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 19,
|
NumMessages: 16,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
@@ -1130,6 +1086,7 @@ func file_app_router_command_command_proto_init() {
|
|||||||
MessageInfos: file_app_router_command_command_proto_msgTypes,
|
MessageInfos: file_app_router_command_command_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_router_command_command_proto = out.File
|
File_app_router_command_command_proto = out.File
|
||||||
|
file_app_router_command_command_proto_rawDesc = nil
|
||||||
file_app_router_command_command_proto_goTypes = nil
|
file_app_router_command_command_proto_goTypes = nil
|
||||||
file_app_router_command_command_proto_depIdxs = nil
|
file_app_router_command_command_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,17 +104,6 @@ message RemoveRuleRequest {
|
|||||||
|
|
||||||
message RemoveRuleResponse {}
|
message RemoveRuleResponse {}
|
||||||
|
|
||||||
message ListRuleRequest {}
|
|
||||||
|
|
||||||
message ListRuleItem {
|
|
||||||
string tag = 1;
|
|
||||||
string ruleTag = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ListRuleResponse{
|
|
||||||
repeated ListRuleItem rules = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
service RoutingService {
|
service RoutingService {
|
||||||
rpc SubscribeRoutingStats(SubscribeRoutingStatsRequest)
|
rpc SubscribeRoutingStats(SubscribeRoutingStatsRequest)
|
||||||
returns (stream RoutingContext) {}
|
returns (stream RoutingContext) {}
|
||||||
@@ -125,8 +114,6 @@ service RoutingService {
|
|||||||
|
|
||||||
rpc AddRule(AddRuleRequest) returns (AddRuleResponse) {}
|
rpc AddRule(AddRuleRequest) returns (AddRuleResponse) {}
|
||||||
rpc RemoveRule(RemoveRuleRequest) returns (RemoveRuleResponse) {}
|
rpc RemoveRule(RemoveRuleRequest) returns (RemoveRuleResponse) {}
|
||||||
|
|
||||||
rpc ListRule(ListRuleRequest) returns (ListRuleResponse) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message Config {}
|
message Config {}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.6.0
|
// - protoc-gen-go-grpc v1.5.1
|
||||||
// - protoc v6.33.5
|
// - protoc v5.28.2
|
||||||
// source: app/router/command/command.proto
|
// source: app/router/command/command.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
@@ -25,7 +25,6 @@ const (
|
|||||||
RoutingService_OverrideBalancerTarget_FullMethodName = "/xray.app.router.command.RoutingService/OverrideBalancerTarget"
|
RoutingService_OverrideBalancerTarget_FullMethodName = "/xray.app.router.command.RoutingService/OverrideBalancerTarget"
|
||||||
RoutingService_AddRule_FullMethodName = "/xray.app.router.command.RoutingService/AddRule"
|
RoutingService_AddRule_FullMethodName = "/xray.app.router.command.RoutingService/AddRule"
|
||||||
RoutingService_RemoveRule_FullMethodName = "/xray.app.router.command.RoutingService/RemoveRule"
|
RoutingService_RemoveRule_FullMethodName = "/xray.app.router.command.RoutingService/RemoveRule"
|
||||||
RoutingService_ListRule_FullMethodName = "/xray.app.router.command.RoutingService/ListRule"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RoutingServiceClient is the client API for RoutingService service.
|
// RoutingServiceClient is the client API for RoutingService service.
|
||||||
@@ -38,7 +37,6 @@ type RoutingServiceClient interface {
|
|||||||
OverrideBalancerTarget(ctx context.Context, in *OverrideBalancerTargetRequest, opts ...grpc.CallOption) (*OverrideBalancerTargetResponse, error)
|
OverrideBalancerTarget(ctx context.Context, in *OverrideBalancerTargetRequest, opts ...grpc.CallOption) (*OverrideBalancerTargetResponse, error)
|
||||||
AddRule(ctx context.Context, in *AddRuleRequest, opts ...grpc.CallOption) (*AddRuleResponse, error)
|
AddRule(ctx context.Context, in *AddRuleRequest, opts ...grpc.CallOption) (*AddRuleResponse, error)
|
||||||
RemoveRule(ctx context.Context, in *RemoveRuleRequest, opts ...grpc.CallOption) (*RemoveRuleResponse, error)
|
RemoveRule(ctx context.Context, in *RemoveRuleRequest, opts ...grpc.CallOption) (*RemoveRuleResponse, error)
|
||||||
ListRule(ctx context.Context, in *ListRuleRequest, opts ...grpc.CallOption) (*ListRuleResponse, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type routingServiceClient struct {
|
type routingServiceClient struct {
|
||||||
@@ -118,16 +116,6 @@ func (c *routingServiceClient) RemoveRule(ctx context.Context, in *RemoveRuleReq
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *routingServiceClient) ListRule(ctx context.Context, in *ListRuleRequest, opts ...grpc.CallOption) (*ListRuleResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(ListRuleResponse)
|
|
||||||
err := c.cc.Invoke(ctx, RoutingService_ListRule_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RoutingServiceServer is the server API for RoutingService service.
|
// RoutingServiceServer is the server API for RoutingService service.
|
||||||
// All implementations must embed UnimplementedRoutingServiceServer
|
// All implementations must embed UnimplementedRoutingServiceServer
|
||||||
// for forward compatibility.
|
// for forward compatibility.
|
||||||
@@ -138,7 +126,6 @@ type RoutingServiceServer interface {
|
|||||||
OverrideBalancerTarget(context.Context, *OverrideBalancerTargetRequest) (*OverrideBalancerTargetResponse, error)
|
OverrideBalancerTarget(context.Context, *OverrideBalancerTargetRequest) (*OverrideBalancerTargetResponse, error)
|
||||||
AddRule(context.Context, *AddRuleRequest) (*AddRuleResponse, error)
|
AddRule(context.Context, *AddRuleRequest) (*AddRuleResponse, error)
|
||||||
RemoveRule(context.Context, *RemoveRuleRequest) (*RemoveRuleResponse, error)
|
RemoveRule(context.Context, *RemoveRuleRequest) (*RemoveRuleResponse, error)
|
||||||
ListRule(context.Context, *ListRuleRequest) (*ListRuleResponse, error)
|
|
||||||
mustEmbedUnimplementedRoutingServiceServer()
|
mustEmbedUnimplementedRoutingServiceServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,25 +137,22 @@ type RoutingServiceServer interface {
|
|||||||
type UnimplementedRoutingServiceServer struct{}
|
type UnimplementedRoutingServiceServer struct{}
|
||||||
|
|
||||||
func (UnimplementedRoutingServiceServer) SubscribeRoutingStats(*SubscribeRoutingStatsRequest, grpc.ServerStreamingServer[RoutingContext]) error {
|
func (UnimplementedRoutingServiceServer) SubscribeRoutingStats(*SubscribeRoutingStatsRequest, grpc.ServerStreamingServer[RoutingContext]) error {
|
||||||
return status.Error(codes.Unimplemented, "method SubscribeRoutingStats not implemented")
|
return status.Errorf(codes.Unimplemented, "method SubscribeRoutingStats not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedRoutingServiceServer) TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error) {
|
func (UnimplementedRoutingServiceServer) TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method TestRoute not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method TestRoute not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedRoutingServiceServer) GetBalancerInfo(context.Context, *GetBalancerInfoRequest) (*GetBalancerInfoResponse, error) {
|
func (UnimplementedRoutingServiceServer) GetBalancerInfo(context.Context, *GetBalancerInfoRequest) (*GetBalancerInfoResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method GetBalancerInfo not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetBalancerInfo not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedRoutingServiceServer) OverrideBalancerTarget(context.Context, *OverrideBalancerTargetRequest) (*OverrideBalancerTargetResponse, error) {
|
func (UnimplementedRoutingServiceServer) OverrideBalancerTarget(context.Context, *OverrideBalancerTargetRequest) (*OverrideBalancerTargetResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method OverrideBalancerTarget not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method OverrideBalancerTarget not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedRoutingServiceServer) AddRule(context.Context, *AddRuleRequest) (*AddRuleResponse, error) {
|
func (UnimplementedRoutingServiceServer) AddRule(context.Context, *AddRuleRequest) (*AddRuleResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method AddRule not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method AddRule not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedRoutingServiceServer) RemoveRule(context.Context, *RemoveRuleRequest) (*RemoveRuleResponse, error) {
|
func (UnimplementedRoutingServiceServer) RemoveRule(context.Context, *RemoveRuleRequest) (*RemoveRuleResponse, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method RemoveRule not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method RemoveRule not implemented")
|
||||||
}
|
|
||||||
func (UnimplementedRoutingServiceServer) ListRule(context.Context, *ListRuleRequest) (*ListRuleResponse, error) {
|
|
||||||
return nil, status.Error(codes.Unimplemented, "method ListRule not implemented")
|
|
||||||
}
|
}
|
||||||
func (UnimplementedRoutingServiceServer) mustEmbedUnimplementedRoutingServiceServer() {}
|
func (UnimplementedRoutingServiceServer) mustEmbedUnimplementedRoutingServiceServer() {}
|
||||||
func (UnimplementedRoutingServiceServer) testEmbeddedByValue() {}
|
func (UnimplementedRoutingServiceServer) testEmbeddedByValue() {}
|
||||||
@@ -181,7 +165,7 @@ type UnsafeRoutingServiceServer interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RegisterRoutingServiceServer(s grpc.ServiceRegistrar, srv RoutingServiceServer) {
|
func RegisterRoutingServiceServer(s grpc.ServiceRegistrar, srv RoutingServiceServer) {
|
||||||
// If the following call panics, it indicates UnimplementedRoutingServiceServer was
|
// If the following call pancis, it indicates UnimplementedRoutingServiceServer was
|
||||||
// embedded by pointer and is nil. This will cause panics if an
|
// embedded by pointer and is nil. This will cause panics if an
|
||||||
// unimplemented method is ever invoked, so we test this at initialization
|
// unimplemented method is ever invoked, so we test this at initialization
|
||||||
// time to prevent it from happening at runtime later due to I/O.
|
// time to prevent it from happening at runtime later due to I/O.
|
||||||
@@ -292,24 +276,6 @@ func _RoutingService_RemoveRule_Handler(srv interface{}, ctx context.Context, de
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _RoutingService_ListRule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(ListRuleRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(RoutingServiceServer).ListRule(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: RoutingService_ListRule_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(RoutingServiceServer).ListRule(ctx, req.(*ListRuleRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RoutingService_ServiceDesc is the grpc.ServiceDesc for RoutingService service.
|
// RoutingService_ServiceDesc is the grpc.ServiceDesc for RoutingService service.
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
// and not to be introspected or modified (even as a copy)
|
// and not to be introspected or modified (even as a copy)
|
||||||
@@ -337,10 +303,6 @@ var RoutingService_ServiceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "RemoveRule",
|
MethodName: "RemoveRule",
|
||||||
Handler: _RoutingService_RemoveRule_Handler,
|
Handler: _RoutingService_RemoveRule_Handler,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
MethodName: "ListRule",
|
|
||||||
Handler: _RoutingService_ListRule_Handler,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{
|
Streams: []grpc.StreamDesc{
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
. "github.com/xtls/xray-core/app/router/command"
|
. "github.com/xtls/xray-core/app/router/command"
|
||||||
"github.com/xtls/xray-core/app/stats"
|
"github.com/xtls/xray-core/app/stats"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/geodata"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
"github.com/xtls/xray-core/testing/mocks"
|
"github.com/xtls/xray-core/testing/mocks"
|
||||||
@@ -304,12 +303,12 @@ func TestServiceTestRoute(t *testing.T) {
|
|||||||
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
|
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Domain: []*geodata.DomainRule{{Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "com"}}}},
|
Domain: []*router.Domain{{Type: router.Domain_Domain, Value: "com"}},
|
||||||
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
|
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
SourceIp: []*geodata.IPRule{{Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{127, 0, 0, 0}, Prefix: 8}}}}},
|
SourceGeoip: []*router.GeoIP{{CountryCode: "private", Cidr: []*router.CIDR{{Ip: []byte{127, 0, 0, 0}, Prefix: 8}}}},
|
||||||
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
|
TargetTag: &router.RoutingRule_Tag{Tag: "out"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
UserEmail: []string{"example@example.com"},
|
UserEmail: []string{"example@example.com"},
|
||||||
|
|||||||
+81
-149
@@ -1,18 +1,13 @@
|
|||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"slices"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/geodata"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/common/strmatcher"
|
||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
"github.com/xtls/xray-core/features/routing/dns"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Condition interface {
|
type Condition interface {
|
||||||
@@ -45,18 +40,51 @@ func (v *ConditionChan) Len() int {
|
|||||||
return len(*v)
|
return len(*v)
|
||||||
}
|
}
|
||||||
|
|
||||||
type DomainMatcher struct{ geodata.DomainMatcher }
|
var matcherTypeMap = map[Domain_Type]strmatcher.Type{
|
||||||
|
Domain_Plain: strmatcher.Substr,
|
||||||
|
Domain_Regex: strmatcher.Regex,
|
||||||
|
Domain_Domain: strmatcher.Domain,
|
||||||
|
Domain_Full: strmatcher.Full,
|
||||||
|
}
|
||||||
|
|
||||||
func NewDomainMatcher(rules []*geodata.DomainRule) (*DomainMatcher, error) {
|
func domainToMatcher(domain *Domain) (strmatcher.Matcher, error) {
|
||||||
m, err := geodata.DomainReg.BuildDomainMatcher(rules)
|
matcherType, f := matcherTypeMap[domain.Type]
|
||||||
if err != nil {
|
if !f {
|
||||||
return nil, err
|
return nil, errors.New("unsupported domain type", domain.Type)
|
||||||
}
|
}
|
||||||
return &DomainMatcher{DomainMatcher: m}, nil
|
|
||||||
|
matcher, err := matcherType.New(domain.Value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to create domain matcher").Base(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return matcher, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type DomainMatcher struct {
|
||||||
|
matchers strmatcher.IndexMatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
|
||||||
|
g := strmatcher.NewMphMatcherGroup()
|
||||||
|
for _, d := range domains {
|
||||||
|
matcherType, f := matcherTypeMap[d.Type]
|
||||||
|
if !f {
|
||||||
|
return nil, errors.New("unsupported domain type", d.Type)
|
||||||
|
}
|
||||||
|
_, err := g.AddPattern(d.Value, matcherType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.Build()
|
||||||
|
return &DomainMatcher{
|
||||||
|
matchers: g,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *DomainMatcher) ApplyDomain(domain string) bool {
|
func (m *DomainMatcher) ApplyDomain(domain string) bool {
|
||||||
return m.DomainMatcher.MatchAny(strings.ToLower(domain))
|
return len(m.matchers.Match(strings.ToLower(domain))) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply implements Condition.
|
// Apply implements Condition.
|
||||||
@@ -65,56 +93,64 @@ func (m *DomainMatcher) Apply(ctx routing.Context) bool {
|
|||||||
if len(domain) == 0 {
|
if len(domain) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return m.DomainMatcher.MatchAny(strings.ToLower(domain))
|
return m.ApplyDomain(domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
type MatcherAsType byte
|
type MultiGeoIPMatcher struct {
|
||||||
|
matchers []*GeoIPMatcher
|
||||||
const (
|
asType string // local, source, target
|
||||||
MatcherAsType_Local MatcherAsType = iota
|
|
||||||
MatcherAsType_Source
|
|
||||||
MatcherAsType_Target
|
|
||||||
MatcherAsType_VlessRoute // for port
|
|
||||||
)
|
|
||||||
|
|
||||||
type IPMatcher struct {
|
|
||||||
matcher geodata.IPMatcher
|
|
||||||
asType MatcherAsType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIPMatcher(rules []*geodata.IPRule, asType MatcherAsType) (*IPMatcher, error) {
|
func NewMultiGeoIPMatcher(geoips []*GeoIP, asType string) (*MultiGeoIPMatcher, error) {
|
||||||
m, err := geodata.IPReg.BuildIPMatcher(rules)
|
var matchers []*GeoIPMatcher
|
||||||
if err != nil {
|
for _, geoip := range geoips {
|
||||||
return nil, err
|
matcher, err := GlobalGeoIPContainer.Add(geoip)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
matchers = append(matchers, matcher)
|
||||||
}
|
}
|
||||||
return &IPMatcher{matcher: m, asType: asType}, nil
|
|
||||||
|
matcher := &MultiGeoIPMatcher{
|
||||||
|
matchers: matchers,
|
||||||
|
asType: asType,
|
||||||
|
}
|
||||||
|
|
||||||
|
return matcher, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply implements Condition.
|
// Apply implements Condition.
|
||||||
func (m *IPMatcher) Apply(ctx routing.Context) bool {
|
func (m *MultiGeoIPMatcher) Apply(ctx routing.Context) bool {
|
||||||
var ips []net.IP
|
var ips []net.IP
|
||||||
|
|
||||||
switch m.asType {
|
switch m.asType {
|
||||||
case MatcherAsType_Local:
|
case "local":
|
||||||
ips = ctx.GetLocalIPs()
|
ips = ctx.GetLocalIPs()
|
||||||
case MatcherAsType_Source:
|
case "source":
|
||||||
ips = ctx.GetSourceIPs()
|
ips = ctx.GetSourceIPs()
|
||||||
case MatcherAsType_Target:
|
case "target":
|
||||||
ips = ctx.GetTargetIPs()
|
ips = ctx.GetTargetIPs()
|
||||||
default:
|
default:
|
||||||
panic("unk asType")
|
panic("unreachable, asType should be local or source or target")
|
||||||
}
|
}
|
||||||
|
|
||||||
return m.matcher.AnyMatch(ips)
|
for _, ip := range ips {
|
||||||
|
for _, matcher := range m.matchers {
|
||||||
|
if matcher.Match(ip) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type PortMatcher struct {
|
type PortMatcher struct {
|
||||||
port net.MemoryPortList
|
port net.MemoryPortList
|
||||||
asType MatcherAsType
|
asType string // local, source, target
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPortMatcher create a new port matcher that can match source or local or destination port
|
// NewPortMatcher create a new port matcher that can match source or local or destination port
|
||||||
func NewPortMatcher(list *net.PortList, asType MatcherAsType) *PortMatcher {
|
func NewPortMatcher(list *net.PortList, asType string) *PortMatcher {
|
||||||
return &PortMatcher{
|
return &PortMatcher{
|
||||||
port: net.PortListFromProto(list),
|
port: net.PortListFromProto(list),
|
||||||
asType: asType,
|
asType: asType,
|
||||||
@@ -124,17 +160,18 @@ func NewPortMatcher(list *net.PortList, asType MatcherAsType) *PortMatcher {
|
|||||||
// Apply implements Condition.
|
// Apply implements Condition.
|
||||||
func (v *PortMatcher) Apply(ctx routing.Context) bool {
|
func (v *PortMatcher) Apply(ctx routing.Context) bool {
|
||||||
switch v.asType {
|
switch v.asType {
|
||||||
case MatcherAsType_Local:
|
case "local":
|
||||||
return v.port.Contains(ctx.GetLocalPort())
|
return v.port.Contains(ctx.GetLocalPort())
|
||||||
case MatcherAsType_Source:
|
case "source":
|
||||||
return v.port.Contains(ctx.GetSourcePort())
|
return v.port.Contains(ctx.GetSourcePort())
|
||||||
case MatcherAsType_Target:
|
case "target":
|
||||||
return v.port.Contains(ctx.GetTargetPort())
|
return v.port.Contains(ctx.GetTargetPort())
|
||||||
case MatcherAsType_VlessRoute:
|
case "vlessRoute":
|
||||||
return v.port.Contains(ctx.GetVlessRoute())
|
return v.port.Contains(ctx.GetVlessRoute())
|
||||||
default:
|
default:
|
||||||
panic("unk asType")
|
panic("unreachable, asType should be local or source or target")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type NetworkMatcher struct {
|
type NetworkMatcher struct {
|
||||||
@@ -288,108 +325,3 @@ func (m *AttributeMatcher) Apply(ctx routing.Context) bool {
|
|||||||
}
|
}
|
||||||
return m.Match(attributes)
|
return m.Match(attributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProcessNameMatcher struct {
|
|
||||||
ProcessNames []string
|
|
||||||
AbsPaths []string
|
|
||||||
Folders []string
|
|
||||||
MatchXraySelf bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewProcessNameMatcher(names []string) *ProcessNameMatcher {
|
|
||||||
processNames := []string{}
|
|
||||||
folders := []string{}
|
|
||||||
absPaths := []string{}
|
|
||||||
matchXraySelf := false
|
|
||||||
for _, name := range names {
|
|
||||||
if name == "self/" {
|
|
||||||
matchXraySelf = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// replace xray/ with self executable path
|
|
||||||
if name == "xray/" {
|
|
||||||
xrayPath, err := os.Executable()
|
|
||||||
if err != nil {
|
|
||||||
errors.LogError(context.Background(), "Failed to get xray executable path: ", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
name = xrayPath
|
|
||||||
}
|
|
||||||
name := filepath.ToSlash(name)
|
|
||||||
// /usr/bin/
|
|
||||||
if strings.HasSuffix(name, "/") {
|
|
||||||
folders = append(folders, name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// /usr/bin/curl
|
|
||||||
if strings.Contains(name, "/") {
|
|
||||||
absPaths = append(absPaths, name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// curl.exe or curl
|
|
||||||
processNames = append(processNames, strings.TrimSuffix(name, ".exe"))
|
|
||||||
}
|
|
||||||
return &ProcessNameMatcher{
|
|
||||||
ProcessNames: processNames,
|
|
||||||
AbsPaths: absPaths,
|
|
||||||
Folders: folders,
|
|
||||||
MatchXraySelf: matchXraySelf,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *ProcessNameMatcher) Apply(ctx routing.Context) bool {
|
|
||||||
if len(ctx.GetSourceIPs()) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
srcPort := uint16(ctx.GetSourcePort())
|
|
||||||
srcIP := ctx.GetSourceIPs()[0].String()
|
|
||||||
|
|
||||||
var network string
|
|
||||||
switch ctx.GetNetwork() {
|
|
||||||
case net.Network_TCP:
|
|
||||||
network = "tcp"
|
|
||||||
case net.Network_UDP:
|
|
||||||
network = "udp"
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var dstIP string
|
|
||||||
var dstPort uint16 = 0
|
|
||||||
|
|
||||||
// do not use resolved IP because Android process lookup needs original dst ip
|
|
||||||
resolvableContext, ok := ctx.(*dns.ResolvableContext)
|
|
||||||
if ok && len(resolvableContext.Context.GetTargetIPs()) > 0 {
|
|
||||||
dstIP = resolvableContext.Context.GetTargetIPs()[0].String()
|
|
||||||
dstPort = uint16(resolvableContext.Context.GetTargetPort())
|
|
||||||
} else if len(ctx.GetTargetIPs()) > 0 {
|
|
||||||
dstIP = ctx.GetTargetIPs()[0].String()
|
|
||||||
dstPort = uint16(ctx.GetTargetPort())
|
|
||||||
}
|
|
||||||
|
|
||||||
pid, name, absPath, err := net.FindProcess(network, srcIP, uint16(srcPort), dstIP, uint16(dstPort))
|
|
||||||
if err != nil {
|
|
||||||
if err != net.ErrNotLocal {
|
|
||||||
errors.LogError(context.Background(), "Unables to find local process name: ", err)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if m.MatchXraySelf {
|
|
||||||
if pid == os.Getpid() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if slices.Contains(m.ProcessNames, name) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if slices.Contains(m.AbsPaths, absPath) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for _, f := range m.Folders {
|
|
||||||
if strings.HasPrefix(absPath, f) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/netip"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"go4.org/netipx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GeoIPMatcher struct {
|
||||||
|
countryCode string
|
||||||
|
reverseMatch bool
|
||||||
|
ip4 *netipx.IPSet
|
||||||
|
ip6 *netipx.IPSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GeoIPMatcher) Init(cidrs []*CIDR) error {
|
||||||
|
var builder4, builder6 netipx.IPSetBuilder
|
||||||
|
|
||||||
|
for _, cidr := range cidrs {
|
||||||
|
ip := net.IP(cidr.GetIp())
|
||||||
|
ipPrefixString := ip.String() + "/" + strconv.Itoa(int(cidr.GetPrefix()))
|
||||||
|
ipPrefix, err := netip.ParsePrefix(ipPrefixString)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch len(ip) {
|
||||||
|
case net.IPv4len:
|
||||||
|
builder4.AddPrefix(ipPrefix)
|
||||||
|
case net.IPv6len:
|
||||||
|
builder6.AddPrefix(ipPrefix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ip4, err := builder4.IPSet(); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
m.ip4 = ip4
|
||||||
|
}
|
||||||
|
|
||||||
|
if ip6, err := builder6.IPSet(); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
m.ip6 = ip6
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GeoIPMatcher) SetReverseMatch(isReverseMatch bool) {
|
||||||
|
m.reverseMatch = isReverseMatch
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GeoIPMatcher) match4(ip net.IP) bool {
|
||||||
|
nip, ok := netipx.FromStdIP(ip)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.ip4.Contains(nip)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GeoIPMatcher) match6(ip net.IP) bool {
|
||||||
|
nip, ok := netipx.FromStdIP(ip)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.ip6.Contains(nip)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match returns true if the given ip is included by the GeoIP.
|
||||||
|
func (m *GeoIPMatcher) Match(ip net.IP) bool {
|
||||||
|
isMatched := false
|
||||||
|
switch len(ip) {
|
||||||
|
case net.IPv4len:
|
||||||
|
isMatched = m.match4(ip)
|
||||||
|
case net.IPv6len:
|
||||||
|
isMatched = m.match6(ip)
|
||||||
|
}
|
||||||
|
if m.reverseMatch {
|
||||||
|
return !isMatched
|
||||||
|
}
|
||||||
|
return isMatched
|
||||||
|
}
|
||||||
|
|
||||||
|
// GeoIPMatcherContainer is a container for GeoIPMatchers. It keeps unique copies of GeoIPMatcher by country code.
|
||||||
|
type GeoIPMatcherContainer struct {
|
||||||
|
matchers []*GeoIPMatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds a new GeoIP set into the container.
|
||||||
|
// If the country code of GeoIP is not empty, GeoIPMatcherContainer will try to find an existing one, instead of adding a new one.
|
||||||
|
func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
|
||||||
|
if len(geoip.CountryCode) > 0 {
|
||||||
|
for _, m := range c.matchers {
|
||||||
|
if m.countryCode == geoip.CountryCode && m.reverseMatch == geoip.ReverseMatch {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m := &GeoIPMatcher{
|
||||||
|
countryCode: geoip.CountryCode,
|
||||||
|
reverseMatch: geoip.ReverseMatch,
|
||||||
|
}
|
||||||
|
if err := m.Init(geoip.Cidr); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(geoip.CountryCode) > 0 {
|
||||||
|
c.matchers = append(c.matchers, m)
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var GlobalGeoIPContainer GeoIPMatcherContainer
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
package router_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/app/router"
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/common/platform"
|
||||||
|
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getAssetPath(file string) (string, error) {
|
||||||
|
path := platform.GetAssetLocation(file)
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
path := filepath.Join("..", "..", "resources", file)
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return "", fmt.Errorf("can't find %s in standard asset locations or {project_root}/resources", file)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("can't stat %s: %v", path, err)
|
||||||
|
}
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("can't stat %s: %v", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGeoIPMatcherContainer(t *testing.T) {
|
||||||
|
container := &router.GeoIPMatcherContainer{}
|
||||||
|
|
||||||
|
m1, err := container.Add(&router.GeoIP{
|
||||||
|
CountryCode: "CN",
|
||||||
|
})
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
m2, err := container.Add(&router.GeoIP{
|
||||||
|
CountryCode: "US",
|
||||||
|
})
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
m3, err := container.Add(&router.GeoIP{
|
||||||
|
CountryCode: "CN",
|
||||||
|
})
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
if m1 != m3 {
|
||||||
|
t.Error("expect same matcher for same geoip, but not")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m1 == m2 {
|
||||||
|
t.Error("expect different matcher for different geoip, but actually same")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGeoIPMatcher(t *testing.T) {
|
||||||
|
cidrList := []*router.CIDR{
|
||||||
|
{Ip: []byte{0, 0, 0, 0}, Prefix: 8},
|
||||||
|
{Ip: []byte{10, 0, 0, 0}, Prefix: 8},
|
||||||
|
{Ip: []byte{100, 64, 0, 0}, Prefix: 10},
|
||||||
|
{Ip: []byte{127, 0, 0, 0}, Prefix: 8},
|
||||||
|
{Ip: []byte{169, 254, 0, 0}, Prefix: 16},
|
||||||
|
{Ip: []byte{172, 16, 0, 0}, Prefix: 12},
|
||||||
|
{Ip: []byte{192, 0, 0, 0}, Prefix: 24},
|
||||||
|
{Ip: []byte{192, 0, 2, 0}, Prefix: 24},
|
||||||
|
{Ip: []byte{192, 168, 0, 0}, Prefix: 16},
|
||||||
|
{Ip: []byte{192, 18, 0, 0}, Prefix: 15},
|
||||||
|
{Ip: []byte{198, 51, 100, 0}, Prefix: 24},
|
||||||
|
{Ip: []byte{203, 0, 113, 0}, Prefix: 24},
|
||||||
|
{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
|
||||||
|
{Ip: []byte{91, 108, 4, 0}, Prefix: 16},
|
||||||
|
}
|
||||||
|
|
||||||
|
matcher := &router.GeoIPMatcher{}
|
||||||
|
common.Must(matcher.Init(cidrList))
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
Input string
|
||||||
|
Output bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Input: "192.168.1.1",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: "192.0.0.0",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: "192.0.1.0",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: "0.1.0.0",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: "1.0.0.1",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: "8.8.8.7",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: "8.8.8.8",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: "2001:cdba::3257:9652",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: "91.108.255.254",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
ip := net.ParseAddress(testCase.Input).IP()
|
||||||
|
actual := matcher.Match(ip)
|
||||||
|
if actual != testCase.Output {
|
||||||
|
t.Error("expect input", testCase.Input, "to be", testCase.Output, ", but actually", actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGeoIPMatcherRegression(t *testing.T) {
|
||||||
|
cidrList := []*router.CIDR{
|
||||||
|
{Ip: []byte{98, 108, 20, 0}, Prefix: 22},
|
||||||
|
{Ip: []byte{98, 108, 20, 0}, Prefix: 23},
|
||||||
|
}
|
||||||
|
|
||||||
|
matcher := &router.GeoIPMatcher{}
|
||||||
|
common.Must(matcher.Init(cidrList))
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
Input string
|
||||||
|
Output bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Input: "98.108.22.11",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: "98.108.25.0",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
ip := net.ParseAddress(testCase.Input).IP()
|
||||||
|
actual := matcher.Match(ip)
|
||||||
|
if actual != testCase.Output {
|
||||||
|
t.Error("expect input", testCase.Input, "to be", testCase.Output, ", but actually", actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGeoIPReverseMatcher(t *testing.T) {
|
||||||
|
cidrList := []*router.CIDR{
|
||||||
|
{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
|
||||||
|
{Ip: []byte{91, 108, 4, 0}, Prefix: 16},
|
||||||
|
}
|
||||||
|
matcher := &router.GeoIPMatcher{}
|
||||||
|
matcher.SetReverseMatch(true) // Reverse match
|
||||||
|
common.Must(matcher.Init(cidrList))
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
Input string
|
||||||
|
Output bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Input: "8.8.8.8",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: "2001:cdba::3257:9652",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: "91.108.255.254",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
ip := net.ParseAddress(testCase.Input).IP()
|
||||||
|
actual := matcher.Match(ip)
|
||||||
|
if actual != testCase.Output {
|
||||||
|
t.Error("expect input", testCase.Input, "to be", testCase.Output, ", but actually", actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGeoIPMatcher4CN(t *testing.T) {
|
||||||
|
ips, err := loadGeoIP("CN")
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
matcher := &router.GeoIPMatcher{}
|
||||||
|
common.Must(matcher.Init(ips))
|
||||||
|
|
||||||
|
if matcher.Match([]byte{8, 8, 8, 8}) {
|
||||||
|
t.Error("expect CN geoip doesn't contain 8.8.8.8, but actually does")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGeoIPMatcher6US(t *testing.T) {
|
||||||
|
ips, err := loadGeoIP("US")
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
matcher := &router.GeoIPMatcher{}
|
||||||
|
common.Must(matcher.Init(ips))
|
||||||
|
|
||||||
|
if !matcher.Match(net.ParseAddress("2001:4860:4860::8888").IP()) {
|
||||||
|
t.Error("expect US geoip contain 2001:4860:4860::8888, but actually not")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadGeoIP(country string) ([]*router.CIDR, error) {
|
||||||
|
path, err := getAssetPath("geoip.dat")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
geoipBytes, err := filesystem.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var geoipList router.GeoIPList
|
||||||
|
if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, geoip := range geoipList.Entry {
|
||||||
|
if geoip.CountryCode == country {
|
||||||
|
return geoip.Cidr, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic("country not found: " + country)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkGeoIPMatcher4CN(b *testing.B) {
|
||||||
|
ips, err := loadGeoIP("CN")
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
matcher := &router.GeoIPMatcher{}
|
||||||
|
common.Must(matcher.Init(ips))
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = matcher.Match([]byte{8, 8, 8, 8})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkGeoIPMatcher6US(b *testing.B) {
|
||||||
|
ips, err := loadGeoIP("US")
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
|
matcher := &router.GeoIPMatcher{}
|
||||||
|
common.Must(matcher.Init(ips))
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = matcher.Match(net.ParseAddress("2001:4860:4860::8888").IP())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,20 @@
|
|||||||
package router_test
|
package router_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "github.com/xtls/xray-core/app/router"
|
. "github.com/xtls/xray-core/app/router"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/geodata"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/protocol/http"
|
"github.com/xtls/xray-core/common/protocol/http"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
routing_session "github.com/xtls/xray-core/features/routing/session"
|
routing_session "github.com/xtls/xray-core/features/routing/session"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func withBackground() routing.Context {
|
func withBackground() routing.Context {
|
||||||
@@ -44,15 +45,18 @@ func TestRoutingRule(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
rule: &RoutingRule{
|
rule: &RoutingRule{
|
||||||
Domain: []*geodata.DomainRule{
|
Domain: []*Domain{
|
||||||
{
|
{
|
||||||
Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Substr, Value: "example.com"}},
|
Value: "example.com",
|
||||||
|
Type: Domain_Plain,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Domain, Value: "google.com"}},
|
Value: "google.com",
|
||||||
|
Type: Domain_Domain,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Value: &geodata.DomainRule_Custom{Custom: &geodata.Domain{Type: geodata.Domain_Regex, Value: "^facebook\\.com$"}},
|
Value: "^facebook\\.com$",
|
||||||
|
Type: Domain_Regex,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -89,25 +93,20 @@ func TestRoutingRule(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
rule: &RoutingRule{
|
rule: &RoutingRule{
|
||||||
Ip: []*geodata.IPRule{
|
Geoip: []*GeoIP{
|
||||||
{
|
{
|
||||||
Value: &geodata.IPRule_Custom{
|
Cidr: []*CIDR{
|
||||||
Custom: &geodata.CIDRRule{
|
{
|
||||||
Cidr: &geodata.CIDR{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
|
Ip: []byte{8, 8, 8, 8},
|
||||||
|
Prefix: 32,
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
},
|
Ip: []byte{8, 8, 8, 8},
|
||||||
{
|
Prefix: 32,
|
||||||
Value: &geodata.IPRule_Custom{
|
|
||||||
Custom: &geodata.CIDRRule{
|
|
||||||
Cidr: &geodata.CIDR{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
},
|
Ip: net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334").IP(),
|
||||||
{
|
Prefix: 128,
|
||||||
Value: &geodata.IPRule_Custom{
|
|
||||||
Custom: &geodata.CIDRRule{
|
|
||||||
Cidr: &geodata.CIDR{Ip: net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334").IP(), Prefix: 128},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -134,11 +133,12 @@ func TestRoutingRule(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
rule: &RoutingRule{
|
rule: &RoutingRule{
|
||||||
SourceIp: []*geodata.IPRule{
|
SourceGeoip: []*GeoIP{
|
||||||
{
|
{
|
||||||
Value: &geodata.IPRule_Custom{
|
Cidr: []*CIDR{
|
||||||
Custom: &geodata.CIDRRule{
|
{
|
||||||
Cidr: &geodata.CIDR{Ip: []byte{192, 168, 0, 0}, Prefix: 16},
|
Ip: []byte{192, 168, 0, 0},
|
||||||
|
Prefix: 16,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -300,12 +300,35 @@ func TestRoutingRule(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadGeoSite(country string) ([]*Domain, error) {
|
||||||
|
path, err := getAssetPath("geosite.dat")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
geositeBytes, err := filesystem.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var geositeList GeoSiteList
|
||||||
|
if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, site := range geositeList.Entry {
|
||||||
|
if site.CountryCode == country {
|
||||||
|
return site.Domain, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("country not found: " + country)
|
||||||
|
}
|
||||||
|
|
||||||
func TestChinaSites(t *testing.T) {
|
func TestChinaSites(t *testing.T) {
|
||||||
t.Setenv("xray.location.asset", filepath.Join("..", "..", "resources"))
|
domains, err := loadGeoSite("CN")
|
||||||
rules, err := geodata.ParseDomainRules([]string{"geosite:cn"}, geodata.Domain_Substr)
|
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
matcher, err := NewDomainMatcher(rules)
|
acMatcher, err := NewMphMatcherGroup(domains)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
type TestCase struct {
|
type TestCase struct {
|
||||||
@@ -336,19 +359,18 @@ func TestChinaSites(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
r := matcher.ApplyDomain(testCase.Domain)
|
r := acMatcher.ApplyDomain(testCase.Domain)
|
||||||
if r != testCase.Output {
|
if r != testCase.Output {
|
||||||
t.Error("DomainMatcher expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r)
|
t.Error("ACDomainMatcher expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkMphDomainMatcher(b *testing.B) {
|
func BenchmarkMphDomainMatcher(b *testing.B) {
|
||||||
b.Setenv("xray.location.asset", filepath.Join("..", "..", "resources"))
|
domains, err := loadGeoSite("CN")
|
||||||
rules, err := geodata.ParseDomainRules([]string{"geosite:cn"}, geodata.Domain_Substr)
|
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
matcher, err := NewDomainMatcher(rules)
|
matcher, err := NewMphMatcherGroup(domains)
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
type TestCase struct {
|
type TestCase struct {
|
||||||
@@ -387,11 +409,45 @@ func BenchmarkMphDomainMatcher(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkMultiGeoIPMatcher(b *testing.B) {
|
func BenchmarkMultiGeoIPMatcher(b *testing.B) {
|
||||||
b.Setenv("xray.location.asset", filepath.Join("..", "..", "resources"))
|
var geoips []*GeoIP
|
||||||
rules, err := geodata.ParseIPRules([]string{"geoip:cn", "geoip:jp", "geoip:ca", "geoip:us"})
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
matcher, err := NewIPMatcher(rules, MatcherAsType_Target)
|
{
|
||||||
|
ips, err := loadGeoIP("CN")
|
||||||
|
common.Must(err)
|
||||||
|
geoips = append(geoips, &GeoIP{
|
||||||
|
CountryCode: "CN",
|
||||||
|
Cidr: ips,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ips, err := loadGeoIP("JP")
|
||||||
|
common.Must(err)
|
||||||
|
geoips = append(geoips, &GeoIP{
|
||||||
|
CountryCode: "JP",
|
||||||
|
Cidr: ips,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ips, err := loadGeoIP("CA")
|
||||||
|
common.Must(err)
|
||||||
|
geoips = append(geoips, &GeoIP{
|
||||||
|
CountryCode: "CA",
|
||||||
|
Cidr: ips,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ips, err := loadGeoIP("US")
|
||||||
|
common.Must(err)
|
||||||
|
geoips = append(geoips, &GeoIP{
|
||||||
|
CountryCode: "US",
|
||||||
|
Cidr: ips,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
matcher, err := NewMultiGeoIPMatcher(geoips, "target")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)})
|
ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)})
|
||||||
|
|||||||
+54
-58
@@ -15,7 +15,6 @@ type Rule struct {
|
|||||||
RuleTag string
|
RuleTag string
|
||||||
Balancer *Balancer
|
Balancer *Balancer
|
||||||
Condition Condition
|
Condition Condition
|
||||||
Webhook *WebhookNotifier
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Rule) GetTag() (string, error) {
|
func (r *Rule) GetTag() (string, error) {
|
||||||
@@ -33,38 +32,72 @@ func (r *Rule) Apply(ctx routing.Context) bool {
|
|||||||
func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||||
conds := NewConditionChan()
|
conds := NewConditionChan()
|
||||||
|
|
||||||
|
if len(rr.Domain) > 0 {
|
||||||
|
matcher, err := NewMphMatcherGroup(rr.Domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to build domain condition with MphDomainMatcher").Base(err)
|
||||||
|
}
|
||||||
|
errors.LogDebug(context.Background(), "MphDomainMatcher is enabled for ", len(rr.Domain), " domain rule(s)")
|
||||||
|
conds.Add(matcher)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rr.UserEmail) > 0 {
|
||||||
|
conds.Add(NewUserMatcher(rr.UserEmail))
|
||||||
|
}
|
||||||
|
|
||||||
|
if rr.VlessRouteList != nil {
|
||||||
|
conds.Add(NewPortMatcher(rr.VlessRouteList, "vlessRoute"))
|
||||||
|
}
|
||||||
|
|
||||||
if len(rr.InboundTag) > 0 {
|
if len(rr.InboundTag) > 0 {
|
||||||
conds.Add(NewInboundTagMatcher(rr.InboundTag))
|
conds.Add(NewInboundTagMatcher(rr.InboundTag))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if rr.PortList != nil {
|
||||||
|
conds.Add(NewPortMatcher(rr.PortList, "target"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if rr.SourcePortList != nil {
|
||||||
|
conds.Add(NewPortMatcher(rr.SourcePortList, "source"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if rr.LocalPortList != nil {
|
||||||
|
conds.Add(NewPortMatcher(rr.LocalPortList, "local"))
|
||||||
|
}
|
||||||
|
|
||||||
if len(rr.Networks) > 0 {
|
if len(rr.Networks) > 0 {
|
||||||
conds.Add(NewNetworkMatcher(rr.Networks))
|
conds.Add(NewNetworkMatcher(rr.Networks))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(rr.Geoip) > 0 {
|
||||||
|
cond, err := NewMultiGeoIPMatcher(rr.Geoip, "target")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conds.Add(cond)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rr.SourceGeoip) > 0 {
|
||||||
|
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 {
|
if len(rr.Protocol) > 0 {
|
||||||
conds.Add(NewProtocolMatcher(rr.Protocol))
|
conds.Add(NewProtocolMatcher(rr.Protocol))
|
||||||
}
|
}
|
||||||
|
|
||||||
if rr.PortList != nil {
|
|
||||||
conds.Add(NewPortMatcher(rr.PortList, MatcherAsType_Target))
|
|
||||||
}
|
|
||||||
|
|
||||||
if rr.SourcePortList != nil {
|
|
||||||
conds.Add(NewPortMatcher(rr.SourcePortList, MatcherAsType_Source))
|
|
||||||
}
|
|
||||||
|
|
||||||
if rr.LocalPortList != nil {
|
|
||||||
conds.Add(NewPortMatcher(rr.LocalPortList, MatcherAsType_Local))
|
|
||||||
}
|
|
||||||
|
|
||||||
if rr.VlessRouteList != nil {
|
|
||||||
conds.Add(NewPortMatcher(rr.VlessRouteList, MatcherAsType_VlessRoute))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rr.UserEmail) > 0 {
|
|
||||||
conds.Add(NewUserMatcher(rr.UserEmail))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rr.Attributes) > 0 {
|
if len(rr.Attributes) > 0 {
|
||||||
configuredKeys := make(map[string]*regexp.Regexp)
|
configuredKeys := make(map[string]*regexp.Regexp)
|
||||||
for key, value := range rr.Attributes {
|
for key, value := range rr.Attributes {
|
||||||
@@ -73,43 +106,6 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
|||||||
conds.Add(&AttributeMatcher{configuredKeys})
|
conds.Add(&AttributeMatcher{configuredKeys})
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rr.Ip) > 0 {
|
|
||||||
cond, err := NewIPMatcher(rr.Ip, MatcherAsType_Target)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conds.Add(cond)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rr.SourceIp) > 0 {
|
|
||||||
cond, err := NewIPMatcher(rr.SourceIp, MatcherAsType_Source)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conds.Add(cond)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rr.LocalIp) > 0 {
|
|
||||||
cond, err := NewIPMatcher(rr.LocalIp, MatcherAsType_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.Domain) > 0 {
|
|
||||||
cond, err := NewDomainMatcher(rr.Domain)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conds.Add(cond)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rr.Process) > 0 {
|
|
||||||
conds.Add(NewProcessNameMatcher(rr.Process))
|
|
||||||
}
|
|
||||||
|
|
||||||
if conds.Len() == 0 {
|
if conds.Len() == 0 {
|
||||||
return nil, errors.New("this rule has no effective fields").AtWarning()
|
return nil, errors.New("this rule has no effective fields").AtWarning()
|
||||||
}
|
}
|
||||||
|
|||||||
+774
-264
File diff suppressed because it is too large
Load Diff
+75
-23
@@ -9,7 +9,67 @@ option java_multiple_files = true;
|
|||||||
import "common/serial/typed_message.proto";
|
import "common/serial/typed_message.proto";
|
||||||
import "common/net/port.proto";
|
import "common/net/port.proto";
|
||||||
import "common/net/network.proto";
|
import "common/net/network.proto";
|
||||||
import "common/geodata/geodat.proto";
|
|
||||||
|
// Domain for routing decision.
|
||||||
|
message Domain {
|
||||||
|
// Type of domain value.
|
||||||
|
enum Type {
|
||||||
|
// The value is used as is.
|
||||||
|
Plain = 0;
|
||||||
|
// The value is used as a regular expression.
|
||||||
|
Regex = 1;
|
||||||
|
// The value is a root domain.
|
||||||
|
Domain = 2;
|
||||||
|
// The value is a domain.
|
||||||
|
Full = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Domain matching type.
|
||||||
|
Type type = 1;
|
||||||
|
|
||||||
|
// Domain value.
|
||||||
|
string value = 2;
|
||||||
|
|
||||||
|
message Attribute {
|
||||||
|
string key = 1;
|
||||||
|
|
||||||
|
oneof typed_value {
|
||||||
|
bool bool_value = 2;
|
||||||
|
int64 int_value = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attributes of this domain. May be used for filtering.
|
||||||
|
repeated Attribute attribute = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IP for routing decision, in CIDR form.
|
||||||
|
message CIDR {
|
||||||
|
// IP address, should be either 4 or 16 bytes.
|
||||||
|
bytes ip = 1;
|
||||||
|
|
||||||
|
// Number of leading ones in the network mask.
|
||||||
|
uint32 prefix = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GeoIP {
|
||||||
|
string country_code = 1;
|
||||||
|
repeated CIDR cidr = 2;
|
||||||
|
bool reverse_match = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GeoIPList {
|
||||||
|
repeated GeoIP entry = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GeoSite {
|
||||||
|
string country_code = 1;
|
||||||
|
repeated Domain domain = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GeoSiteList {
|
||||||
|
repeated GeoSite entry = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message RoutingRule {
|
message RoutingRule {
|
||||||
oneof target_tag {
|
oneof target_tag {
|
||||||
@@ -19,23 +79,26 @@ message RoutingRule {
|
|||||||
// Tag of routing balancer.
|
// Tag of routing balancer.
|
||||||
string balancing_tag = 12;
|
string balancing_tag = 12;
|
||||||
}
|
}
|
||||||
|
string rule_tag = 19;
|
||||||
string rule_tag = 19;
|
|
||||||
|
|
||||||
// List of domains for target domain matching.
|
// List of domains for target domain matching.
|
||||||
repeated xray.common.geodata.DomainRule domain = 2;
|
repeated Domain domain = 2;
|
||||||
|
|
||||||
// List of IPs for target IP address matching.
|
// List of GeoIPs for target IP address matching. If this entry exists, the
|
||||||
repeated xray.common.geodata.IPRule ip = 10;
|
// cidr above will have no effect. GeoIP fields with the same country code are
|
||||||
|
// supposed to contain exactly same content. They will be merged during
|
||||||
|
// runtime. For customized GeoIPs, please leave country code empty.
|
||||||
|
repeated GeoIP geoip = 10;
|
||||||
|
|
||||||
// List of ports for target port matching.
|
// List of ports.
|
||||||
xray.common.net.PortList port_list = 14;
|
xray.common.net.PortList port_list = 14;
|
||||||
|
|
||||||
// List of networks for matching.
|
// List of networks for matching.
|
||||||
repeated xray.common.net.Network networks = 13;
|
repeated xray.common.net.Network networks = 13;
|
||||||
|
|
||||||
// List of IPs for source IP address matching.
|
// List of GeoIPs for source IP address matching. If this entry exists, the
|
||||||
repeated xray.common.geodata.IPRule source_ip = 11;
|
// source_cidr above will have no effect.
|
||||||
|
repeated GeoIP source_geoip = 11;
|
||||||
|
|
||||||
// List of ports for source port matching.
|
// List of ports for source port matching.
|
||||||
xray.common.net.PortList source_port_list = 16;
|
xray.common.net.PortList source_port_list = 16;
|
||||||
@@ -46,22 +109,10 @@ message RoutingRule {
|
|||||||
|
|
||||||
map<string, string> attributes = 15;
|
map<string, string> attributes = 15;
|
||||||
|
|
||||||
// List of IPs for local IP address matching.
|
repeated GeoIP local_geoip = 17;
|
||||||
repeated xray.common.geodata.IPRule local_ip = 17;
|
|
||||||
|
|
||||||
// List of ports for local port matching.
|
|
||||||
xray.common.net.PortList local_port_list = 18;
|
xray.common.net.PortList local_port_list = 18;
|
||||||
|
|
||||||
xray.common.net.PortList vless_route_list = 20;
|
xray.common.net.PortList vless_route_list = 20;
|
||||||
|
|
||||||
repeated string process = 21;
|
|
||||||
WebhookConfig webhook = 22;
|
|
||||||
}
|
|
||||||
|
|
||||||
message WebhookConfig {
|
|
||||||
string url = 1;
|
|
||||||
uint32 deduplication = 2;
|
|
||||||
map<string, string> headers = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message BalancingRule {
|
message BalancingRule {
|
||||||
@@ -96,7 +147,8 @@ message Config {
|
|||||||
// Use domain as is.
|
// Use domain as is.
|
||||||
AsIs = 0;
|
AsIs = 0;
|
||||||
|
|
||||||
reserved 1;
|
// Always resolve IP for domains.
|
||||||
|
UseIp = 1;
|
||||||
|
|
||||||
// Resolve to IP if the domain doesn't match any rules.
|
// Resolve to IP if the domain doesn't match any rules.
|
||||||
IpIfNonMatch = 2;
|
IpIfNonMatch = 2;
|
||||||
|
|||||||
+2
-75
@@ -2,7 +2,7 @@ package router
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"sync"
|
sync "sync"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
@@ -57,7 +57,6 @@ func (r *Router) Init(ctx context.Context, config *Config, d dns.Client, ohm out
|
|||||||
for _, rule := range config.Rule {
|
for _, rule := range config.Rule {
|
||||||
cond, err := rule.BuildCondition()
|
cond, err := rule.BuildCondition()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.closeWebhooks()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rr := &Rule{
|
rr := &Rule{
|
||||||
@@ -65,22 +64,10 @@ func (r *Router) Init(ctx context.Context, config *Config, d dns.Client, ohm out
|
|||||||
Tag: rule.GetTag(),
|
Tag: rule.GetTag(),
|
||||||
RuleTag: rule.GetRuleTag(),
|
RuleTag: rule.GetRuleTag(),
|
||||||
}
|
}
|
||||||
if wh := rule.GetWebhook(); wh != nil {
|
|
||||||
notifier, err := NewWebhookNotifier(wh)
|
|
||||||
if err != nil {
|
|
||||||
r.closeWebhooks()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rr.Webhook = notifier
|
|
||||||
}
|
|
||||||
btag := rule.GetBalancingTag()
|
btag := rule.GetBalancingTag()
|
||||||
if len(btag) > 0 {
|
if len(btag) > 0 {
|
||||||
brule, found := r.balancers[btag]
|
brule, found := r.balancers[btag]
|
||||||
if !found {
|
if !found {
|
||||||
if rr.Webhook != nil {
|
|
||||||
rr.Webhook.Close()
|
|
||||||
}
|
|
||||||
r.closeWebhooks()
|
|
||||||
return errors.New("balancer ", btag, " not found")
|
return errors.New("balancer ", btag, " not found")
|
||||||
}
|
}
|
||||||
rr.Balancer = brule
|
rr.Balancer = brule
|
||||||
@@ -93,7 +80,6 @@ func (r *Router) Init(ctx context.Context, config *Config, d dns.Client, ohm out
|
|||||||
|
|
||||||
// PickRoute implements routing.Router.
|
// PickRoute implements routing.Router.
|
||||||
func (r *Router) PickRoute(ctx routing.Context) (routing.Route, error) {
|
func (r *Router) PickRoute(ctx routing.Context) (routing.Route, error) {
|
||||||
originalCtx := ctx
|
|
||||||
rule, ctx, err := r.pickRouteInternal(ctx)
|
rule, ctx, err := r.pickRouteInternal(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -102,14 +88,12 @@ func (r *Router) PickRoute(ctx routing.Context) (routing.Route, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if rule.Webhook != nil {
|
|
||||||
rule.Webhook.Fire(originalCtx, tag)
|
|
||||||
}
|
|
||||||
return &Route{Context: ctx, outboundTag: tag, ruleTag: rule.RuleTag}, nil
|
return &Route{Context: ctx, outboundTag: tag, ruleTag: rule.RuleTag}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddRule implements routing.Router.
|
// AddRule implements routing.Router.
|
||||||
func (r *Router) AddRule(config *serial.TypedMessage, shouldAppend bool) error {
|
func (r *Router) AddRule(config *serial.TypedMessage, shouldAppend bool) error {
|
||||||
|
|
||||||
inst, err := config.GetInstance()
|
inst, err := config.GetInstance()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -125,11 +109,6 @@ func (r *Router) ReloadRules(config *Config, shouldAppend bool) error {
|
|||||||
defer r.mu.Unlock()
|
defer r.mu.Unlock()
|
||||||
|
|
||||||
if !shouldAppend {
|
if !shouldAppend {
|
||||||
for _, rule := range r.rules {
|
|
||||||
if rule.Webhook != nil {
|
|
||||||
rule.Webhook.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r.balancers = make(map[string]*Balancer, len(config.BalancingRule))
|
r.balancers = make(map[string]*Balancer, len(config.BalancingRule))
|
||||||
r.rules = make([]*Rule, 0, len(config.Rule))
|
r.rules = make([]*Rule, 0, len(config.Rule))
|
||||||
}
|
}
|
||||||
@@ -146,24 +125,12 @@ func (r *Router) ReloadRules(config *Config, shouldAppend bool) error {
|
|||||||
r.balancers[rule.Tag] = balancer
|
r.balancers[rule.Tag] = balancer
|
||||||
}
|
}
|
||||||
|
|
||||||
startIdx := len(r.rules)
|
|
||||||
closeNewWebhooks := func() {
|
|
||||||
for i := startIdx; i < len(r.rules); i++ {
|
|
||||||
if r.rules[i].Webhook != nil {
|
|
||||||
r.rules[i].Webhook.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r.rules = r.rules[:startIdx]
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rule := range config.Rule {
|
for _, rule := range config.Rule {
|
||||||
if r.RuleExists(rule.GetRuleTag()) {
|
if r.RuleExists(rule.GetRuleTag()) {
|
||||||
closeNewWebhooks()
|
|
||||||
return errors.New("duplicate ruleTag ", rule.GetRuleTag())
|
return errors.New("duplicate ruleTag ", rule.GetRuleTag())
|
||||||
}
|
}
|
||||||
cond, err := rule.BuildCondition()
|
cond, err := rule.BuildCondition()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
closeNewWebhooks()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rr := &Rule{
|
rr := &Rule{
|
||||||
@@ -171,22 +138,10 @@ func (r *Router) ReloadRules(config *Config, shouldAppend bool) error {
|
|||||||
Tag: rule.GetTag(),
|
Tag: rule.GetTag(),
|
||||||
RuleTag: rule.GetRuleTag(),
|
RuleTag: rule.GetRuleTag(),
|
||||||
}
|
}
|
||||||
if wh := rule.GetWebhook(); wh != nil {
|
|
||||||
notifier, err := NewWebhookNotifier(wh)
|
|
||||||
if err != nil {
|
|
||||||
closeNewWebhooks()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rr.Webhook = notifier
|
|
||||||
}
|
|
||||||
btag := rule.GetBalancingTag()
|
btag := rule.GetBalancingTag()
|
||||||
if len(btag) > 0 {
|
if len(btag) > 0 {
|
||||||
brule, found := r.balancers[btag]
|
brule, found := r.balancers[btag]
|
||||||
if !found {
|
if !found {
|
||||||
if rr.Webhook != nil {
|
|
||||||
rr.Webhook.Close()
|
|
||||||
}
|
|
||||||
closeNewWebhooks()
|
|
||||||
return errors.New("balancer ", btag, " not found")
|
return errors.New("balancer ", btag, " not found")
|
||||||
}
|
}
|
||||||
rr.Balancer = brule
|
rr.Balancer = brule
|
||||||
@@ -218,30 +173,14 @@ func (r *Router) RemoveRule(tag string) error {
|
|||||||
for _, rule := range r.rules {
|
for _, rule := range r.rules {
|
||||||
if rule.RuleTag != tag {
|
if rule.RuleTag != tag {
|
||||||
newRules = append(newRules, rule)
|
newRules = append(newRules, rule)
|
||||||
} else if rule.Webhook != nil {
|
|
||||||
rule.Webhook.Close()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.rules = newRules
|
r.rules = newRules
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("empty tag name!")
|
return errors.New("empty tag name!")
|
||||||
}
|
|
||||||
|
|
||||||
// ListRule implements routing.Router
|
|
||||||
func (r *Router) ListRule() []routing.Route {
|
|
||||||
r.mu.Lock()
|
|
||||||
defer r.mu.Unlock()
|
|
||||||
ruleList := make([]routing.Route, 0)
|
|
||||||
for _, rule := range r.rules {
|
|
||||||
ruleList = append(ruleList, &Route{
|
|
||||||
outboundTag: rule.Tag,
|
|
||||||
ruleTag: rule.RuleTag,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return ruleList
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context, error) {
|
func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context, error) {
|
||||||
// SkipDNSResolve is set from DNS module.
|
// SkipDNSResolve is set from DNS module.
|
||||||
// the DOH remote server maybe a domain name,
|
// the DOH remote server maybe a domain name,
|
||||||
@@ -279,20 +218,8 @@ func (r *Router) Start() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// closeWebhooks closes all webhook notifiers in the current rule set.
|
|
||||||
func (r *Router) closeWebhooks() {
|
|
||||||
for _, rule := range r.rules {
|
|
||||||
if rule.Webhook != nil {
|
|
||||||
rule.Webhook.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close implements common.Closable.
|
// Close implements common.Closable.
|
||||||
func (r *Router) Close() error {
|
func (r *Router) Close() error {
|
||||||
r.mu.Lock()
|
|
||||||
defer r.mu.Unlock()
|
|
||||||
r.closeWebhooks()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-13
@@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
. "github.com/xtls/xray-core/app/router"
|
. "github.com/xtls/xray-core/app/router"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/geodata"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
@@ -156,11 +155,12 @@ func TestIPOnDemand(t *testing.T) {
|
|||||||
TargetTag: &RoutingRule_Tag{
|
TargetTag: &RoutingRule_Tag{
|
||||||
Tag: "test",
|
Tag: "test",
|
||||||
},
|
},
|
||||||
Ip: []*geodata.IPRule{
|
Geoip: []*GeoIP{
|
||||||
{
|
{
|
||||||
Value: &geodata.IPRule_Custom{
|
Cidr: []*CIDR{
|
||||||
Custom: &geodata.CIDRRule{
|
{
|
||||||
Cidr: &geodata.CIDR{Ip: []byte{192, 168, 0, 0}, Prefix: 16},
|
Ip: []byte{192, 168, 0, 0},
|
||||||
|
Prefix: 16,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -200,11 +200,12 @@ func TestIPIfNonMatchDomain(t *testing.T) {
|
|||||||
TargetTag: &RoutingRule_Tag{
|
TargetTag: &RoutingRule_Tag{
|
||||||
Tag: "test",
|
Tag: "test",
|
||||||
},
|
},
|
||||||
Ip: []*geodata.IPRule{
|
Geoip: []*GeoIP{
|
||||||
{
|
{
|
||||||
Value: &geodata.IPRule_Custom{
|
Cidr: []*CIDR{
|
||||||
Custom: &geodata.CIDRRule{
|
{
|
||||||
Cidr: &geodata.CIDR{Ip: []byte{192, 168, 0, 0}, Prefix: 16},
|
Ip: []byte{192, 168, 0, 0},
|
||||||
|
Prefix: 16,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -244,11 +245,12 @@ func TestIPIfNonMatchIP(t *testing.T) {
|
|||||||
TargetTag: &RoutingRule_Tag{
|
TargetTag: &RoutingRule_Tag{
|
||||||
Tag: "test",
|
Tag: "test",
|
||||||
},
|
},
|
||||||
Ip: []*geodata.IPRule{
|
Geoip: []*GeoIP{
|
||||||
{
|
{
|
||||||
Value: &geodata.IPRule_Custom{
|
Cidr: []*CIDR{
|
||||||
Custom: &geodata.CIDRRule{
|
{
|
||||||
Cidr: &geodata.CIDR{Ip: []byte{127, 0, 0, 0}, Prefix: 8},
|
Ip: []byte{127, 0, 0, 0},
|
||||||
|
Prefix: 8,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package router
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math"
|
"math"
|
||||||
"slices"
|
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -78,7 +77,7 @@ func (s *LeastLoadStrategy) PickOutbound(candidates []string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *LeastLoadStrategy) pickOutbounds(candidates []string) []*node {
|
func (s *LeastLoadStrategy) pickOutbounds(candidates []string) []*node {
|
||||||
qualified := s.getNodes(candidates)
|
qualified := s.getNodes(candidates, time.Duration(s.settings.MaxRTT))
|
||||||
selects := s.selectLeastLoad(qualified)
|
selects := s.selectLeastLoad(qualified)
|
||||||
return selects
|
return selects
|
||||||
}
|
}
|
||||||
@@ -139,7 +138,7 @@ func (s *LeastLoadStrategy) selectLeastLoad(nodes []*node) []*node {
|
|||||||
return nodes[:count]
|
return nodes[:count]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *LeastLoadStrategy) getNodes(candidates []string) []*node {
|
func (s *LeastLoadStrategy) getNodes(candidates []string, maxRTT time.Duration) []*node {
|
||||||
if s.observer == nil {
|
if s.observer == nil {
|
||||||
errors.LogError(s.ctx, "observer is nil")
|
errors.LogError(s.ctx, "observer is nil")
|
||||||
return make([]*node, 0)
|
return make([]*node, 0)
|
||||||
@@ -152,10 +151,12 @@ func (s *LeastLoadStrategy) getNodes(candidates []string) []*node {
|
|||||||
|
|
||||||
results := observeResult.(*observatory.ObservationResult)
|
results := observeResult.(*observatory.ObservationResult)
|
||||||
|
|
||||||
|
outboundlist := outboundList(candidates)
|
||||||
|
|
||||||
var ret []*node
|
var ret []*node
|
||||||
|
|
||||||
for _, v := range results.Status {
|
for _, v := range results.Status {
|
||||||
if s.shouldSelectNode(v, candidates) {
|
if v.Alive && (v.Delay < maxRTT.Milliseconds() || maxRTT == 0) && outboundlist.contains(v.OutboundTag) {
|
||||||
record := &node{
|
record := &node{
|
||||||
Tag: v.OutboundTag,
|
Tag: v.OutboundTag,
|
||||||
CountAll: 1,
|
CountAll: 1,
|
||||||
@@ -171,8 +172,8 @@ func (s *LeastLoadStrategy) getNodes(candidates []string) []*node {
|
|||||||
record.RTTDeviationCost = time.Duration(s.costs.Apply(v.OutboundTag, float64(v.HealthPing.Deviation)))
|
record.RTTDeviationCost = time.Duration(s.costs.Apply(v.OutboundTag, float64(v.HealthPing.Deviation)))
|
||||||
record.CountAll = int(v.HealthPing.All)
|
record.CountAll = int(v.HealthPing.All)
|
||||||
record.CountFail = int(v.HealthPing.Fail)
|
record.CountFail = int(v.HealthPing.Fail)
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
ret = append(ret, record)
|
ret = append(ret, record)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,23 +182,6 @@ func (s *LeastLoadStrategy) getNodes(candidates []string) []*node {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *LeastLoadStrategy) shouldSelectNode(v *observatory.OutboundStatus, candidates []string) bool {
|
|
||||||
maxRTT := time.Duration(s.settings.MaxRTT)
|
|
||||||
if !v.Alive {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if maxRTT != 0 && v.Delay >= maxRTT.Milliseconds() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !slices.Contains(candidates, v.OutboundTag) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if v.HealthPing != nil && v.HealthPing.All > 0 && s.settings.Tolerance > 0 && float64(v.HealthPing.Fail)/float64(v.HealthPing.All) > float64(s.settings.Tolerance) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func leastloadSort(nodes []*node) {
|
func leastloadSort(nodes []*node) {
|
||||||
sort.Slice(nodes, func(i, j int) bool {
|
sort.Slice(nodes, func(i, j int) bool {
|
||||||
left := nodes[i]
|
left := nodes[i]
|
||||||
|
|||||||
@@ -85,7 +85,6 @@ func TestSelectLeastExpected(t *testing.T) {
|
|||||||
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectLeastExpected2(t *testing.T) {
|
func TestSelectLeastExpected2(t *testing.T) {
|
||||||
strategy := &LeastLoadStrategy{
|
strategy := &LeastLoadStrategy{
|
||||||
settings: &StrategyLeastLoadConfig{
|
settings: &StrategyLeastLoadConfig{
|
||||||
@@ -103,7 +102,6 @@ func TestSelectLeastExpected2(t *testing.T) {
|
|||||||
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectLeastExpectedAndBaselines(t *testing.T) {
|
func TestSelectLeastExpectedAndBaselines(t *testing.T) {
|
||||||
strategy := &LeastLoadStrategy{
|
strategy := &LeastLoadStrategy{
|
||||||
settings: &StrategyLeastLoadConfig{
|
settings: &StrategyLeastLoadConfig{
|
||||||
@@ -124,7 +122,6 @@ func TestSelectLeastExpectedAndBaselines(t *testing.T) {
|
|||||||
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectLeastExpectedAndBaselines2(t *testing.T) {
|
func TestSelectLeastExpectedAndBaselines2(t *testing.T) {
|
||||||
strategy := &LeastLoadStrategy{
|
strategy := &LeastLoadStrategy{
|
||||||
settings: &StrategyLeastLoadConfig{
|
settings: &StrategyLeastLoadConfig{
|
||||||
@@ -145,7 +142,6 @@ func TestSelectLeastExpectedAndBaselines2(t *testing.T) {
|
|||||||
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectLeastLoadBaselines(t *testing.T) {
|
func TestSelectLeastLoadBaselines(t *testing.T) {
|
||||||
strategy := &LeastLoadStrategy{
|
strategy := &LeastLoadStrategy{
|
||||||
settings: &StrategyLeastLoadConfig{
|
settings: &StrategyLeastLoadConfig{
|
||||||
@@ -164,7 +160,6 @@ func TestSelectLeastLoadBaselines(t *testing.T) {
|
|||||||
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectLeastLoadBaselinesNoQualified(t *testing.T) {
|
func TestSelectLeastLoadBaselinesNoQualified(t *testing.T) {
|
||||||
strategy := &LeastLoadStrategy{
|
strategy := &LeastLoadStrategy{
|
||||||
settings: &StrategyLeastLoadConfig{
|
settings: &StrategyLeastLoadConfig{
|
||||||
|
|||||||
@@ -1,241 +0,0 @@
|
|||||||
package router
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/utils"
|
|
||||||
"github.com/xtls/xray-core/features/routing"
|
|
||||||
routing_session "github.com/xtls/xray-core/features/routing/session"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ptr[T any](v T) *T { return &v }
|
|
||||||
|
|
||||||
type event struct {
|
|
||||||
Email *string `json:"email"`
|
|
||||||
Level *uint32 `json:"level"`
|
|
||||||
Protocol *string `json:"protocol"`
|
|
||||||
Network *string `json:"network"`
|
|
||||||
Source *string `json:"source"`
|
|
||||||
Destination *string `json:"destination"`
|
|
||||||
OriginalTarget *string `json:"originalTarget"`
|
|
||||||
RouteTarget *string `json:"routeTarget"`
|
|
||||||
InboundTag *string `json:"inboundTag"`
|
|
||||||
InboundName *string `json:"inboundName"`
|
|
||||||
InboundLocal *string `json:"inboundLocal"`
|
|
||||||
OutboundTag *string `json:"outboundTag"`
|
|
||||||
Timestamp int64 `json:"ts"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type WebhookNotifier struct {
|
|
||||||
url string
|
|
||||||
headers map[string]string
|
|
||||||
deduplication uint32
|
|
||||||
client *http.Client
|
|
||||||
seen sync.Map
|
|
||||||
done chan struct{}
|
|
||||||
wg sync.WaitGroup
|
|
||||||
closeOnce sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewWebhookNotifier(cfg *WebhookConfig) (*WebhookNotifier, error) {
|
|
||||||
if cfg == nil || cfg.Url == "" {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
httpURL, socketPath := utils.SplitHTTPUnixURL(cfg.Url)
|
|
||||||
h := &WebhookNotifier{
|
|
||||||
url: httpURL,
|
|
||||||
deduplication: cfg.Deduplication,
|
|
||||||
client: &http.Client{
|
|
||||||
Timeout: 5 * time.Second,
|
|
||||||
},
|
|
||||||
done: make(chan struct{}),
|
|
||||||
}
|
|
||||||
|
|
||||||
if socketPath != "" {
|
|
||||||
dialAddr := utils.ResolveSocketPath(socketPath)
|
|
||||||
h.client.Transport = &http.Transport{
|
|
||||||
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
|
|
||||||
var d net.Dialer
|
|
||||||
return d.DialContext(ctx, "unix", dialAddr)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(cfg.Headers) > 0 {
|
|
||||||
h.headers = make(map[string]string, len(cfg.Headers))
|
|
||||||
for k, v := range cfg.Headers {
|
|
||||||
h.headers[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.deduplication > 0 {
|
|
||||||
h.wg.Add(1)
|
|
||||||
go h.cleanupLoop()
|
|
||||||
}
|
|
||||||
|
|
||||||
return h, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *WebhookNotifier) Fire(ctx routing.Context, outboundTag string) {
|
|
||||||
ev := buildEvent(ctx, outboundTag)
|
|
||||||
|
|
||||||
email := ""
|
|
||||||
if ev.Email != nil {
|
|
||||||
email = *ev.Email
|
|
||||||
}
|
|
||||||
if h.isDuplicate(email) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
h.wg.Add(1)
|
|
||||||
select {
|
|
||||||
case <-h.done:
|
|
||||||
h.wg.Done()
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
defer h.wg.Done()
|
|
||||||
h.post(ev)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildEvent(ctx routing.Context, outboundTag string) *event {
|
|
||||||
ev := &event{
|
|
||||||
Timestamp: time.Now().Unix(),
|
|
||||||
OutboundTag: ptr(outboundTag),
|
|
||||||
InboundTag: ptr(ctx.GetInboundTag()),
|
|
||||||
Protocol: ptr(ctx.GetProtocol()),
|
|
||||||
Network: ptr(ctx.GetNetwork().SystemString()),
|
|
||||||
}
|
|
||||||
|
|
||||||
if user := ctx.GetUser(); user != "" {
|
|
||||||
ev.Email = ptr(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
if srcIPs := ctx.GetSourceIPs(); len(srcIPs) > 0 {
|
|
||||||
srcPort := ctx.GetSourcePort()
|
|
||||||
ev.Source = ptr(net.JoinHostPort(srcIPs[0].String(), srcPort.String()))
|
|
||||||
}
|
|
||||||
|
|
||||||
targetPort := ctx.GetTargetPort()
|
|
||||||
if domain := ctx.GetTargetDomain(); domain != "" {
|
|
||||||
ev.Destination = ptr(net.JoinHostPort(domain, targetPort.String()))
|
|
||||||
} else if targetIPs := ctx.GetTargetIPs(); len(targetIPs) > 0 {
|
|
||||||
ev.Destination = ptr(net.JoinHostPort(targetIPs[0].String(), targetPort.String()))
|
|
||||||
}
|
|
||||||
|
|
||||||
if localIPs := ctx.GetLocalIPs(); len(localIPs) > 0 {
|
|
||||||
localPort := ctx.GetLocalPort()
|
|
||||||
ev.InboundLocal = ptr(net.JoinHostPort(localIPs[0].String(), localPort.String()))
|
|
||||||
}
|
|
||||||
|
|
||||||
if sctx, ok := ctx.(*routing_session.Context); ok {
|
|
||||||
enrichFromSession(ev, sctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ev
|
|
||||||
}
|
|
||||||
|
|
||||||
func enrichFromSession(ev *event, sctx *routing_session.Context) {
|
|
||||||
if sctx.Inbound != nil {
|
|
||||||
ev.InboundName = ptr(sctx.Inbound.Name)
|
|
||||||
if sctx.Inbound.User != nil {
|
|
||||||
ev.Level = ptr(sctx.Inbound.User.Level)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sctx.Outbound != nil {
|
|
||||||
if sctx.Outbound.OriginalTarget.Address != nil {
|
|
||||||
ev.OriginalTarget = ptr(sctx.Outbound.OriginalTarget.String())
|
|
||||||
}
|
|
||||||
if sctx.Outbound.RouteTarget.Address != nil {
|
|
||||||
ev.RouteTarget = ptr(sctx.Outbound.RouteTarget.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *WebhookNotifier) post(ev *event) {
|
|
||||||
body, err := json.Marshal(ev)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogWarning(context.Background(), "webhook: marshal failed: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, h.url, bytes.NewReader(body))
|
|
||||||
if err != nil {
|
|
||||||
errors.LogWarning(context.Background(), "webhook: request build failed: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
for k, v := range h.headers {
|
|
||||||
req.Header.Set(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := h.client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogInfo(context.Background(), "webhook: POST failed: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
io.Copy(io.Discard, resp.Body)
|
|
||||||
resp.Body.Close()
|
|
||||||
}()
|
|
||||||
if resp.StatusCode >= 400 {
|
|
||||||
errors.LogWarning(context.Background(), "webhook: POST returned status ", resp.StatusCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *WebhookNotifier) isDuplicate(email string) bool {
|
|
||||||
if h.deduplication == 0 || email == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
ttl := time.Duration(h.deduplication) * time.Second
|
|
||||||
now := time.Now()
|
|
||||||
if v, loaded := h.seen.LoadOrStore(email, now); loaded {
|
|
||||||
if now.Sub(v.(time.Time)) < ttl {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
h.seen.Store(email, now)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *WebhookNotifier) cleanupLoop() {
|
|
||||||
defer h.wg.Done()
|
|
||||||
ttl := time.Duration(h.deduplication) * time.Second
|
|
||||||
ticker := time.NewTicker(ttl)
|
|
||||||
defer ticker.Stop()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-h.done:
|
|
||||||
return
|
|
||||||
case <-ticker.C:
|
|
||||||
now := time.Now()
|
|
||||||
h.seen.Range(func(key, value any) bool {
|
|
||||||
if now.Sub(value.(time.Time)) >= ttl {
|
|
||||||
h.seen.Delete(key)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *WebhookNotifier) Close() error {
|
|
||||||
h.closeOnce.Do(func() {
|
|
||||||
close(h.done)
|
|
||||||
})
|
|
||||||
h.wg.Wait()
|
|
||||||
h.client.CloseIdleConnections()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -3,10 +3,12 @@ package command
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/app/stats"
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/common/strmatcher"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
feature_stats "github.com/xtls/xray-core/features/stats"
|
feature_stats "github.com/xtls/xray-core/features/stats"
|
||||||
grpc "google.golang.org/grpc"
|
grpc "google.golang.org/grpc"
|
||||||
@@ -68,10 +70,9 @@ func (s *statsServer) GetStatsOnlineIpList(ctx context.Context, request *GetStat
|
|||||||
}
|
}
|
||||||
|
|
||||||
ips := make(map[string]int64)
|
ips := make(map[string]int64)
|
||||||
c.ForEach(func(ip string, lastSeen int64) bool {
|
for ip, t := range c.IpTimeMap() {
|
||||||
ips[ip] = lastSeen
|
ips[ip] = t.Unix()
|
||||||
return true
|
}
|
||||||
})
|
|
||||||
|
|
||||||
return &GetStatsOnlineIpListResponse{
|
return &GetStatsOnlineIpListResponse{
|
||||||
Name: request.Name,
|
Name: request.Name,
|
||||||
@@ -79,93 +80,21 @@ func (s *statsServer) GetStatsOnlineIpList(ctx context.Context, request *GetStat
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *statsServer) GetAllOnlineUsers(ctx context.Context, request *GetAllOnlineUsersRequest) (*GetAllOnlineUsersResponse, error) {
|
|
||||||
return &GetAllOnlineUsersResponse{
|
|
||||||
Users: s.stats.GetAllOnlineUsers(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *statsServer) GetUsersStats(ctx context.Context, request *GetUsersStatsRequest) (*GetUsersStatsResponse, error) {
|
|
||||||
userMap := make(map[string]*UserStat)
|
|
||||||
|
|
||||||
s.stats.VisitOnlineMaps(func(name string, om feature_stats.OnlineMap) bool {
|
|
||||||
if om.Count() == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
_, rest, _ := strings.Cut(name, ">>>")
|
|
||||||
email, _, _ := strings.Cut(rest, ">>>")
|
|
||||||
|
|
||||||
user := &UserStat{Email: email}
|
|
||||||
om.ForEach(func(ip string, lastSeen int64) bool {
|
|
||||||
user.Ips = append(user.Ips, &OnlineIPEntry{
|
|
||||||
Ip: ip,
|
|
||||||
LastSeen: lastSeen,
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
if len(user.Ips) > 0 {
|
|
||||||
userMap[email] = user
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
if request.IncludeTraffic {
|
|
||||||
for _, u := range userMap {
|
|
||||||
u.Traffic = &TrafficUserStat{}
|
|
||||||
}
|
|
||||||
const (
|
|
||||||
prefixUser = "user>>>"
|
|
||||||
suffixUplink = ">>>traffic>>>uplink"
|
|
||||||
suffixDownlink = ">>>traffic>>>downlink"
|
|
||||||
)
|
|
||||||
s.stats.VisitCounters(func(name string, c feature_stats.Counter) bool {
|
|
||||||
var email string
|
|
||||||
var isUplink bool
|
|
||||||
|
|
||||||
if strings.HasSuffix(name, suffixUplink) {
|
|
||||||
email = name[len(prefixUser) : len(name)-len(suffixUplink)]
|
|
||||||
isUplink = true
|
|
||||||
} else if strings.HasSuffix(name, suffixDownlink) {
|
|
||||||
email = name[len(prefixUser) : len(name)-len(suffixDownlink)]
|
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
u, ok := userMap[email]
|
|
||||||
if !ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
var value int64
|
|
||||||
if request.Reset_ {
|
|
||||||
value = c.Set(0)
|
|
||||||
} else {
|
|
||||||
value = c.Value()
|
|
||||||
}
|
|
||||||
|
|
||||||
if isUplink {
|
|
||||||
u.Traffic.Uplink = value
|
|
||||||
} else {
|
|
||||||
u.Traffic.Downlink = value
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
resp := &GetUsersStatsResponse{}
|
|
||||||
for _, u := range userMap {
|
|
||||||
resp.Users = append(resp.Users, u)
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *statsServer) QueryStats(ctx context.Context, request *QueryStatsRequest) (*QueryStatsResponse, error) {
|
func (s *statsServer) QueryStats(ctx context.Context, request *QueryStatsRequest) (*QueryStatsResponse, error) {
|
||||||
|
matcher, err := strmatcher.Substr.New(request.Pattern)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
response := &QueryStatsResponse{}
|
response := &QueryStatsResponse{}
|
||||||
|
|
||||||
s.stats.VisitCounters(func(name string, c feature_stats.Counter) bool {
|
manager, ok := s.stats.(*stats.Manager)
|
||||||
if strings.Contains(name, request.Pattern) {
|
if !ok {
|
||||||
|
return nil, errors.New("QueryStats only works its own stats.Manager.")
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.VisitCounters(func(name string, c feature_stats.Counter) bool {
|
||||||
|
if matcher.Match(name) {
|
||||||
var value int64
|
var value int64
|
||||||
if request.Reset_ {
|
if request.Reset_ {
|
||||||
value = c.Set(0)
|
value = c.Set(0)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user