mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-09-27 09:28:01 +03:00
Compare commits
106
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a42dba13e | ||
|
|
cd8aab9544 | ||
|
|
59dc2cee2e | ||
|
|
5846f94784 | ||
|
|
e0ee2350fc | ||
|
|
48164c8267 | ||
|
|
2d2102f654 | ||
|
|
262770564f | ||
|
|
777e31302c | ||
|
|
30d6a5221b | ||
|
|
a778d3d273 | ||
|
|
e813a3744f | ||
|
|
66628943d8 | ||
|
|
7ff06f65ec | ||
|
|
1cf5662949 | ||
|
|
a6aca101d6 | ||
|
|
5836f36f69 | ||
|
|
6d6c045a5a | ||
|
|
cfc78b3ac1 | ||
|
|
5f7474120f | ||
|
|
09f619d67c | ||
|
|
760223ad70 | ||
|
|
d75b33a3a3 | ||
|
|
7c418486c8 | ||
|
|
a384be0f84 | ||
|
|
649e989fa2 | ||
|
|
0443de7798 | ||
|
|
9a121a489b | ||
|
|
4bdf6e5c92 | ||
|
|
ef2a967f12 | ||
|
|
92ada2dd1d | ||
|
|
8a9dbd407f | ||
|
|
de6be7c5a9 | ||
|
|
e742e84ded | ||
|
|
7726fbece0 | ||
|
|
0c09f4342b | ||
|
|
14e171ac8e | ||
|
|
07a0dafa41 | ||
|
|
0ca13452b8 | ||
|
|
36425d2a6e | ||
|
|
39ba1f7952 | ||
|
|
394e117998 | ||
|
|
446df149bd | ||
|
|
d9025857fe | ||
|
|
ced3e75bf3 | ||
|
|
961c352127 | ||
|
|
c715154309 | ||
|
|
b38a41249f | ||
|
|
7265b5ac3f | ||
|
|
e7c72c011f | ||
|
|
a54e1f2be4 | ||
|
|
5d94a62a83 | ||
|
|
ad468e462d | ||
|
|
6738ecf68e | ||
|
|
36968909a1 | ||
|
|
7f6ceb39f7 | ||
|
|
fa64775f07 | ||
|
|
a6792dda69 | ||
|
|
3572209cbd | ||
|
|
dd757ca27c | ||
|
|
04b433dd97 | ||
|
|
6bf0376773 | ||
|
|
74df63add2 | ||
|
|
c40326dfd7 | ||
|
|
a3ba3eefb6 | ||
|
|
9cf22114a1 | ||
|
|
a903e80356 | ||
|
|
a610a4c89a | ||
|
|
b451f8929d | ||
|
|
81f8f398c7 | ||
|
|
aea123842b | ||
|
|
bd7503d506 | ||
|
|
903214a0f0 | ||
|
|
e403abe360 | ||
|
|
c123f163c2 | ||
|
|
93312d29e5 | ||
|
|
36cb0f00bd | ||
|
|
cadcb47074 | ||
|
|
c6afcd5fb6 | ||
|
|
ed5f7e7af5 | ||
|
|
9d3401b6f0 | ||
|
|
d60ef656cc | ||
|
|
a83253f3d7 | ||
|
|
2969a189e6 | ||
|
|
d41840132a | ||
|
|
f14fd1cbee | ||
|
|
cd51f57535 | ||
|
|
4956e65824 | ||
|
|
2185a730d2 | ||
|
|
fcfb0a302a | ||
|
|
b40bf56e4e | ||
|
|
27ad487545 | ||
|
|
e914183996 | ||
|
|
acfda31e59 | ||
|
|
f9dd3aef72 | ||
|
|
b24ef88a80 | ||
|
|
b16a5f03fe | ||
|
|
2f1fabb318 | ||
|
|
1ec2966433 | ||
|
|
8a4b0a9eb0 | ||
|
|
4e8ee302a6 | ||
|
|
18a4104737 | ||
|
|
1a32d18c16 | ||
|
|
412bc17c12 | ||
|
|
9491b67f3c | ||
|
|
cb4f943f50 |
@@ -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 -ldflags "-s -w -buildid=" ./main
|
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -gcflags="all=-l=4" -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
|
||||||
|
|||||||
@@ -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 -ldflags "-s -w -buildid=" ./main
|
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -gcflags="all=-l=4" -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
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ jobs:
|
|||||||
echo "LATEST=$LATEST" >>${GITHUB_ENV}
|
echo "LATEST=$LATEST" >>${GITHUB_ENV}
|
||||||
|
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|||||||
@@ -13,11 +13,17 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Restore Geodat Cache
|
- name: Restore Geodat Cache
|
||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v5
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-
|
key: xray-geodat-
|
||||||
|
|
||||||
|
- name: Restore Wintun Cache
|
||||||
|
uses: actions/cache/restore@v5
|
||||||
|
with:
|
||||||
|
path: resources
|
||||||
|
key: xray-wintun-
|
||||||
|
|
||||||
- name: Check Assets Existence
|
- name: Check Assets Existence
|
||||||
id: check-assets
|
id: check-assets
|
||||||
run: |
|
run: |
|
||||||
@@ -34,6 +40,18 @@ 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'
|
||||||
@@ -63,7 +81,7 @@ jobs:
|
|||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codebase
|
- name: Checkout codebase
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Show workflow information
|
- name: Show workflow information
|
||||||
run: |
|
run: |
|
||||||
@@ -95,20 +113,38 @@ 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@v4
|
uses: actions/cache/restore@v5
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-
|
key: xray-geodat-
|
||||||
|
|
||||||
|
- name: Restore Wintun Cache
|
||||||
|
uses: actions/cache/restore@v5
|
||||||
|
with:
|
||||||
|
path: resources
|
||||||
|
key: xray-wintun-
|
||||||
|
|
||||||
|
- name: Add additional assets into package
|
||||||
|
run: |
|
||||||
|
mv -f resources/geo* build_assets/
|
||||||
|
if [[ ${GOOS} == 'windows' ]]; then
|
||||||
|
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
|
||||||
|
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.txt
|
||||||
|
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
|
||||||
|
|
||||||
@@ -127,17 +163,6 @@ 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'
|
||||||
@@ -146,3 +171,10 @@ 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@v6
|
||||||
|
with:
|
||||||
|
name: Xray-${{ env.ASSET_NAME }}
|
||||||
|
path: |
|
||||||
|
./build_assets/*
|
||||||
|
|||||||
@@ -13,11 +13,17 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Restore Geodat Cache
|
- name: Restore Geodat Cache
|
||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v5
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-
|
key: xray-geodat-
|
||||||
|
|
||||||
|
- name: Restore Wintun Cache
|
||||||
|
uses: actions/cache/restore@v5
|
||||||
|
with:
|
||||||
|
path: resources
|
||||||
|
key: xray-wintun-
|
||||||
|
|
||||||
- name: Check Assets Existence
|
- name: Check Assets Existence
|
||||||
id: check-assets
|
id: check-assets
|
||||||
run: |
|
run: |
|
||||||
@@ -34,6 +40,18 @@ jobs:
|
|||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
LIST=('amd64' 'x86' 'arm64' 'arm')
|
||||||
|
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'
|
||||||
@@ -153,7 +171,7 @@ jobs:
|
|||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codebase
|
- name: Checkout codebase
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Set up NDK
|
- name: Set up NDK
|
||||||
if: matrix.goos == 'android'
|
if: matrix.goos == 'android'
|
||||||
@@ -191,8 +209,6 @@ 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
|
||||||
else
|
else
|
||||||
@@ -207,14 +223,41 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Restore Geodat Cache
|
- name: Restore Geodat Cache
|
||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v5
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-
|
key: xray-geodat-
|
||||||
|
|
||||||
|
- name: Restore Wintun Cache
|
||||||
|
if: matrix.goos == 'windows'
|
||||||
|
uses: actions/cache/restore@v5
|
||||||
|
with:
|
||||||
|
path: resources
|
||||||
|
key: xray-wintun-
|
||||||
|
|
||||||
|
- name: Add additional assets into package
|
||||||
|
run: |
|
||||||
|
mv -f resources/geo* build_assets/
|
||||||
|
if [[ ${GOOS} == 'windows' ]]; then
|
||||||
|
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
|
||||||
|
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
|
||||||
|
if [[ ${GOARCH} == 'arm' ]]; then
|
||||||
|
mv resources/wintun/bin/arm/wintun.dll build_assets/
|
||||||
|
fi
|
||||||
|
mv resources/wintun/LICENSE.txt build_assets/LICENSE-wintun.txt
|
||||||
|
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
|
||||||
|
|
||||||
@@ -233,17 +276,6 @@ 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'
|
||||||
@@ -252,3 +284,10 @@ 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@v6
|
||||||
|
with:
|
||||||
|
name: Xray-${{ env.ASSET_NAME }}
|
||||||
|
path: |
|
||||||
|
./build_assets/*
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ 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:
|
||||||
@@ -21,11 +22,11 @@ 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@v4
|
uses: actions/cache/restore@v5
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-
|
key: xray-geodat-
|
||||||
@@ -58,8 +59,71 @@ jobs:
|
|||||||
done
|
done
|
||||||
|
|
||||||
- name: Save Geodat Cache
|
- name: Save Geodat Cache
|
||||||
uses: actions/cache/save@v4
|
uses: actions/cache/save@v5
|
||||||
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
|
||||||
|
steps:
|
||||||
|
- name: Restore Wintun Cache
|
||||||
|
uses: actions/cache/restore@v5
|
||||||
|
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@v3
|
||||||
|
with:
|
||||||
|
timeout_minutes: 60
|
||||||
|
retry_wait_seconds: 60
|
||||||
|
max_attempts: 60
|
||||||
|
command: |
|
||||||
|
[ -d 'resources' ] || mkdir resources
|
||||||
|
LIST=('amd64' 'x86' 'arm64' 'arm')
|
||||||
|
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"
|
||||||
|
continue
|
||||||
|
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-0.14.1.zip
|
||||||
|
echo -e "Downloading https://www.wintun.net/builds/${DOWNLOAD_FILE}..."
|
||||||
|
curl -L "https://www.wintun.net/builds/${DOWNLOAD_FILE}" -o "${FILENAME}"
|
||||||
|
echo -e "Unpacking wintun..."
|
||||||
|
unzip -u ${FILENAME} -d resources/
|
||||||
|
echo "unhit=true" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Save Wintun Cache
|
||||||
|
uses: actions/cache/save@v5
|
||||||
|
if: ${{ steps.update.outputs.unhit }}
|
||||||
|
with:
|
||||||
|
path: resources
|
||||||
|
key: xray-wintun-${{ github.sha }}-${{ github.run_number }}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Restore Geodat Cache
|
- name: Restore Geodat Cache
|
||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v5
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-
|
key: xray-geodat-
|
||||||
@@ -45,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@v5
|
uses: actions/checkout@v6
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v6
|
||||||
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@v4
|
uses: actions/cache/restore@v5
|
||||||
with:
|
with:
|
||||||
path: resources
|
path: resources
|
||||||
key: xray-geodat-
|
key: xray-geodat-
|
||||||
|
|||||||
@@ -4,12 +4,25 @@
|
|||||||
|
|
||||||
[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)
|
||||||
|
|
||||||
|
[**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**
|
||||||
@@ -43,13 +56,15 @@
|
|||||||
- [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 - **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:**
|
- Web Panel
|
||||||
- [X-Panel](https://github.com/xeefei/X-Panel)
|
|
||||||
- [PasarGuard](https://github.com/PasarGuard/panel)
|
|
||||||
- [Remnawave](https://github.com/remnawave/panel)
|
- [Remnawave](https://github.com/remnawave/panel)
|
||||||
- [Marzban](https://github.com/Gozargah/Marzban)
|
- [3X-UI](https://github.com/MHSanaei/3x-ui)
|
||||||
|
- [PasarGuard](https://github.com/PasarGuard/panel)
|
||||||
- [Xray-UI](https://github.com/qist/xray-ui)
|
- [Xray-UI](https://github.com/qist/xray-ui)
|
||||||
|
- [X-Panel](https://github.com/xeefei/X-Panel)
|
||||||
|
- [Marzban](https://github.com/Gozargah/Marzban)
|
||||||
- [Hiddify](https://github.com/hiddify/Hiddify-Manager)
|
- [Hiddify](https://github.com/hiddify/Hiddify-Manager)
|
||||||
|
- [TX-UI](https://github.com/AghayeCoder/tx-ui)
|
||||||
- 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)
|
||||||
@@ -80,11 +95,12 @@
|
|||||||
## GUI Clients
|
## GUI Clients
|
||||||
|
|
||||||
- OpenWrt
|
- OpenWrt
|
||||||
- [PassWall](https://github.com/xiaorouji/openwrt-passwall), [PassWall 2](https://github.com/xiaorouji/openwrt-passwall2)
|
- [PassWall](https://github.com/Openwrt-Passwall/openwrt-passwall), [PassWall 2](https://github.com/Openwrt-Passwall/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)
|
||||||
@@ -97,23 +113,25 @@
|
|||||||
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||||
- iOS & macOS arm64 & tvOS
|
- iOS & macOS arm64 & tvOS
|
||||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215) ([tvOS](https://apps.apple.com/us/app/happ-proxy-utility-for-tv/id6748297274))
|
- [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)
|
||||||
- [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)
|
||||||
- macOS arm64 & x64
|
- macOS arm64 & x64
|
||||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215)
|
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215) | [Happ RU](https://apps.apple.com/ru/app/happ-proxy-utility-plus/id6746188973)
|
||||||
- [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)
|
||||||
- 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)
|
||||||
|
|
||||||
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# 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!
|
||||||
@@ -196,7 +196,7 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
|
|||||||
return inboundLink, outboundLink
|
return inboundLink, outboundLink
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDispatcher) WrapLink(ctx context.Context, link *transport.Link) *transport.Link {
|
func WrapLink(ctx context.Context, policyManager policy.Manager, statsManager stats.Manager, 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 {
|
||||||
@@ -206,16 +206,16 @@ func (d *DefaultDispatcher) WrapLink(ctx context.Context, link *transport.Link)
|
|||||||
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 := d.policy.ForLevel(user.Level)
|
p := policyManager.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, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
|
if c, _ := stats.GetOrRegisterCounter(statsManager, 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, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
|
if c, _ := stats.GetOrRegisterCounter(statsManager, name); c != nil {
|
||||||
link.Writer = &SizeStatWriter{
|
link.Writer = &SizeStatWriter{
|
||||||
Counter: c,
|
Counter: c,
|
||||||
Writer: link.Writer,
|
Writer: link.Writer,
|
||||||
@@ -224,7 +224,7 @@ func (d *DefaultDispatcher) WrapLink(ctx context.Context, link *transport.Link)
|
|||||||
}
|
}
|
||||||
if p.Stats.UserOnline {
|
if p.Stats.UserOnline {
|
||||||
name := "user>>>" + user.Email + ">>>online"
|
name := "user>>>" + user.Email + ">>>online"
|
||||||
if om, _ := stats.GetOrRegisterOnlineMap(d.stats, name); om != nil {
|
if om, _ := stats.GetOrRegisterOnlineMap(statsManager, name); om != nil {
|
||||||
sessionInbounds := session.InboundFromContext(ctx)
|
sessionInbounds := session.InboundFromContext(ctx)
|
||||||
userIP := sessionInbounds.Source.Address.String()
|
userIP := sessionInbounds.Source.Address.String()
|
||||||
om.AddIP(userIP)
|
om.AddIP(userIP)
|
||||||
@@ -357,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 = d.WrapLink(ctx, outbound)
|
outbound = WrapLink(ctx, d.policy, d.stats, outbound)
|
||||||
sniffingRequest := content.SniffingRequest
|
sniffingRequest := content.SniffingRequest
|
||||||
if !sniffingRequest.Enabled {
|
if !sniffingRequest.Enabled {
|
||||||
d.routedDispatch(ctx, outbound, destination)
|
d.routedDispatch(ctx, outbound, destination)
|
||||||
@@ -449,6 +449,7 @@ 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]
|
||||||
|
|||||||
+259
-108
@@ -3,36 +3,55 @@ 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"
|
||||||
"sync"
|
"golang.org/x/sync/singleflight"
|
||||||
"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
|
||||||
ips map[string]*record
|
pub *pubsub.Service
|
||||||
pub *pubsub.Service
|
cacheCleanup *task.Periodic
|
||||||
cacheCleanup *task.Periodic
|
highWatermark int
|
||||||
name string
|
requestGroup singleflight.Group
|
||||||
disableCache bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCacheController(name string, disableCache bool) *CacheController {
|
func NewCacheController(name string, disableCache bool, serveStale bool, serveExpiredTTL uint32) *CacheController {
|
||||||
c := &CacheController{
|
c := &CacheController{
|
||||||
name: name,
|
name: name,
|
||||||
disableCache: disableCache,
|
disableCache: disableCache,
|
||||||
ips: make(map[string]*record),
|
serveStale: serveStale,
|
||||||
pub: pubsub.NewService(),
|
serveExpiredTTL: -int32(serveExpiredTTL),
|
||||||
|
ips: make(map[string]*record),
|
||||||
|
pub: pubsub.NewService(),
|
||||||
}
|
}
|
||||||
|
|
||||||
c.cacheCleanup = &task.Periodic{
|
c.cacheCleanup = &task.Periodic{
|
||||||
Interval: time.Minute,
|
Interval: 300 * time.Second,
|
||||||
Execute: c.CacheCleanup,
|
Execute: c.CacheCleanup,
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
@@ -40,131 +59,263 @@ func NewCacheController(name string, disableCache bool) *CacheController {
|
|||||||
|
|
||||||
// CacheCleanup clears expired items from cache
|
// CacheCleanup clears expired items from cache
|
||||||
func (c *CacheController) CacheCleanup() error {
|
func (c *CacheController) CacheCleanup() error {
|
||||||
now := time.Now()
|
expiredKeys, err := c.collectExpiredKeys()
|
||||||
c.Lock()
|
if err != nil {
|
||||||
defer c.Unlock()
|
return err
|
||||||
|
|
||||||
if len(c.ips) == 0 {
|
|
||||||
return errors.New("nothing to do. stopping...")
|
|
||||||
}
|
}
|
||||||
|
if len(expiredKeys) == 0 {
|
||||||
for domain, record := range c.ips {
|
return nil
|
||||||
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) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
func (c *CacheController) collectExpiredKeys() ([]string, error) {
|
||||||
elapsed := time.Since(req.start)
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
|
||||||
c.Lock()
|
if len(c.ips) == 0 {
|
||||||
rec, found := c.ips[req.domain]
|
return nil, errors.New("nothing to do. stopping...")
|
||||||
if !found {
|
|
||||||
rec = &record{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch req.reqType {
|
// skip collection if a migration is in progress
|
||||||
case dnsmessage.TypeA:
|
if c.dirtyips != nil {
|
||||||
rec.A = ipRec
|
return nil, nil
|
||||||
case dnsmessage.TypeAAAA:
|
|
||||||
rec.AAAA = ipRec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogInfo(context.Background(), c.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
now := time.Now()
|
||||||
c.ips[req.domain] = rec
|
if c.serveStale && c.serveExpiredTTL != 0 {
|
||||||
|
now = now.Add(time.Duration(c.serveExpiredTTL) * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
switch req.reqType {
|
expiredKeys := make([]string, 0, len(c.ips)/4) // pre-allocate
|
||||||
case dnsmessage.TypeA:
|
|
||||||
c.pub.Publish(req.domain+"4", nil)
|
for domain, rec := range c.ips {
|
||||||
if !c.disableCache {
|
if (rec.A != nil && rec.A.Expire.Before(now)) ||
|
||||||
_, _, err := rec.AAAA.getIPs()
|
(rec.AAAA != nil && rec.AAAA.Expire.Before(now)) {
|
||||||
if !go_errors.Is(err, errRecordNotFound) {
|
expiredKeys = append(expiredKeys, domain)
|
||||||
c.pub.Publish(req.domain+"6", nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case dnsmessage.TypeAAAA:
|
|
||||||
c.pub.Publish(req.domain+"6", nil)
|
|
||||||
if !c.disableCache {
|
|
||||||
_, _, err := rec.A.getIPs()
|
|
||||||
if !go_errors.Is(err, errRecordNotFound) {
|
|
||||||
c.pub.Publish(req.domain+"4", nil)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Unlock()
|
return expiredKeys, nil
|
||||||
common.Must(c.cacheCleanup.Start())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CacheController) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
func (c *CacheController) writeAndShrink(expiredKeys []string) {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
|
||||||
|
// double check to prevent upper call multiple cleanup tasks
|
||||||
|
if c.dirtyips != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lenBefore := len(c.ips)
|
||||||
|
if lenBefore > c.highWatermark {
|
||||||
|
c.highWatermark = lenBefore
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
if c.serveStale && c.serveExpiredTTL != 0 {
|
||||||
|
now = now.Add(time.Duration(c.serveExpiredTTL) * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, domain := range expiredKeys {
|
||||||
|
rec := c.ips[domain]
|
||||||
|
if rec == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if rec.A != nil && rec.A.Expire.Before(now) {
|
||||||
|
rec.A = nil
|
||||||
|
}
|
||||||
|
if rec.AAAA != nil && rec.AAAA.Expire.Before(now) {
|
||||||
|
rec.AAAA = nil
|
||||||
|
}
|
||||||
|
if rec.A == nil && rec.AAAA == nil {
|
||||||
|
delete(c.ips, domain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lenAfter := len(c.ips)
|
||||||
|
|
||||||
|
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 {
|
||||||
|
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()
|
||||||
record, found := c.ips[domain]
|
dirtyips := c.dirtyips
|
||||||
c.RUnlock()
|
c.RUnlock()
|
||||||
|
|
||||||
if !found {
|
// double check to prevent upper call multiple cleanup tasks
|
||||||
return nil, 0, errRecordNotFound
|
if dirtyips == nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var errs []error
|
errors.LogDebug(context.Background(), c.name, " starting background cache migration for ", len(dirtyips), " items")
|
||||||
var allIPs []net.IP
|
|
||||||
var rTTL uint32 = dns_feature.DefaultTTL
|
|
||||||
|
|
||||||
mergeReq := option.IPv4Enable && option.IPv6Enable
|
batch := make([]migrationEntry, 0, migrationBatchSize)
|
||||||
|
for domain, recD := range dirtyips {
|
||||||
|
batch = append(batch, migrationEntry{domain, recD})
|
||||||
|
|
||||||
if option.IPv4Enable {
|
if len(batch) >= migrationBatchSize {
|
||||||
ips, ttl, err := record.A.getIPs()
|
c.flush(batch)
|
||||||
if !mergeReq || go_errors.Is(err, errRecordNotFound) {
|
batch = batch[:0]
|
||||||
return ips, ttl, err
|
runtime.Gosched()
|
||||||
}
|
}
|
||||||
if ttl < rTTL {
|
}
|
||||||
rTTL = ttl
|
if len(batch) > 0 {
|
||||||
}
|
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 {
|
||||||
errs = append(errs, err)
|
c.ips[dirty.key] = dirty.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if option.IPv6Enable {
|
errors.LogInfo(context.Background(), c.name, " got answer: ", req.domain, " ", req.reqType, " -> ", rep.IP, ", rtt: ", rtt, ", lock: ", lockWait)
|
||||||
ips, ttl, err := record.AAAA.getIPs()
|
|
||||||
if !mergeReq || go_errors.Is(err, errRecordNotFound) {
|
|
||||||
return ips, ttl, err
|
|
||||||
}
|
|
||||||
if ttl < rTTL {
|
|
||||||
rTTL = ttl
|
|
||||||
}
|
|
||||||
if len(ips) > 0 {
|
|
||||||
allIPs = append(allIPs, ips...)
|
|
||||||
} else {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(allIPs) > 0 {
|
if !c.serveStale || c.serveExpiredTTL != 0 {
|
||||||
return allIPs, rTTL, nil
|
common.Must(c.cacheCleanup.Start())
|
||||||
}
|
}
|
||||||
if go_errors.Is(errs[0], errs[1]) {
|
}
|
||||||
return nil, rTTL, errs[0]
|
|
||||||
|
func (c *CacheController) findRecords(domain string) *record {
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
|
||||||
|
rec := c.ips[domain]
|
||||||
|
if rec == nil && c.dirtyips != nil {
|
||||||
|
rec = c.dirtyips[domain]
|
||||||
}
|
}
|
||||||
return nil, rTTL, errors.Combine(errs...)
|
return rec
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
|||||||
+140
-72
@@ -141,10 +141,13 @@ type NameServer struct {
|
|||||||
ActPrior bool `protobuf:"varint,8,opt,name=actPrior,proto3" json:"actPrior,omitempty"`
|
ActPrior bool `protobuf:"varint,8,opt,name=actPrior,proto3" json:"actPrior,omitempty"`
|
||||||
Tag string `protobuf:"bytes,9,opt,name=tag,proto3" json:"tag,omitempty"`
|
Tag string `protobuf:"bytes,9,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
TimeoutMs uint64 `protobuf:"varint,10,opt,name=timeoutMs,proto3" json:"timeoutMs,omitempty"`
|
TimeoutMs uint64 `protobuf:"varint,10,opt,name=timeoutMs,proto3" json:"timeoutMs,omitempty"`
|
||||||
DisableCache bool `protobuf:"varint,11,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
|
DisableCache *bool `protobuf:"varint,11,opt,name=disableCache,proto3,oneof" json:"disableCache,omitempty"`
|
||||||
|
ServeStale *bool `protobuf:"varint,15,opt,name=serveStale,proto3,oneof" json:"serveStale,omitempty"`
|
||||||
|
ServeExpiredTTL *uint32 `protobuf:"varint,16,opt,name=serveExpiredTTL,proto3,oneof" json:"serveExpiredTTL,omitempty"`
|
||||||
FinalQuery bool `protobuf:"varint,12,opt,name=finalQuery,proto3" json:"finalQuery,omitempty"`
|
FinalQuery bool `protobuf:"varint,12,opt,name=finalQuery,proto3" json:"finalQuery,omitempty"`
|
||||||
UnexpectedGeoip []*router.GeoIP `protobuf:"bytes,13,rep,name=unexpected_geoip,json=unexpectedGeoip,proto3" json:"unexpected_geoip,omitempty"`
|
UnexpectedGeoip []*router.GeoIP `protobuf:"bytes,13,rep,name=unexpected_geoip,json=unexpectedGeoip,proto3" json:"unexpected_geoip,omitempty"`
|
||||||
ActUnprior bool `protobuf:"varint,14,opt,name=actUnprior,proto3" json:"actUnprior,omitempty"`
|
ActUnprior bool `protobuf:"varint,14,opt,name=actUnprior,proto3" json:"actUnprior,omitempty"`
|
||||||
|
PolicyID uint32 `protobuf:"varint,17,opt,name=policyID,proto3" json:"policyID,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) Reset() {
|
func (x *NameServer) Reset() {
|
||||||
@@ -248,12 +251,26 @@ func (x *NameServer) GetTimeoutMs() uint64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (x *NameServer) GetDisableCache() bool {
|
func (x *NameServer) GetDisableCache() bool {
|
||||||
if x != nil {
|
if x != nil && x.DisableCache != 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
|
||||||
@@ -275,6 +292,13 @@ 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
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -291,9 +315,12 @@ 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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -361,6 +388,20 @@ 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
|
||||||
@@ -382,6 +423,13 @@ func (x *Config) GetDisableFallbackIfMatch() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetEnableParallelQuery() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.EnableParallelQuery
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type NameServer_PriorityDomain struct {
|
type NameServer_PriorityDomain struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -567,7 +615,7 @@ var file_app_dns_config_proto_rawDesc = []byte{
|
|||||||
0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74,
|
0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74,
|
||||||
0x2f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f,
|
0x2f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
0x74, 0x6f, 0x1a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63,
|
0x74, 0x6f, 0x1a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63,
|
||||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb6, 0x06, 0x0a, 0x0a,
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdf, 0x07, 0x0a, 0x0a,
|
||||||
0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64,
|
0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64,
|
||||||
0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72,
|
0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72,
|
||||||
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e,
|
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e,
|
||||||
@@ -599,74 +647,93 @@ var file_app_dns_config_proto_rawDesc = []byte{
|
|||||||
0x50, 0x72, 0x69, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x09, 0x20, 0x01,
|
0x50, 0x72, 0x69, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x09, 0x20, 0x01,
|
||||||
0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x6f,
|
0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x6f,
|
||||||
0x75, 0x74, 0x4d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
|
0x75, 0x74, 0x4d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
|
||||||
0x6f, 0x75, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
|
0x6f, 0x75, 0x74, 0x4d, 0x73, 0x12, 0x27, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
|
||||||
0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73,
|
0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0c, 0x64,
|
||||||
0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6e,
|
0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x88, 0x01, 0x01, 0x12, 0x23,
|
||||||
0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66,
|
0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x53, 0x74, 0x61, 0x6c, 0x65, 0x18, 0x0f, 0x20, 0x01,
|
||||||
0x69, 0x6e, 0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x41, 0x0a, 0x10, 0x75, 0x6e, 0x65,
|
0x28, 0x08, 0x48, 0x01, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x53, 0x74, 0x61, 0x6c, 0x65,
|
||||||
0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0d, 0x20,
|
0x88, 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x45, 0x78, 0x70, 0x69,
|
||||||
0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
0x72, 0x65, 0x64, 0x54, 0x54, 0x4c, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x02, 0x52, 0x0f,
|
||||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0f, 0x75, 0x6e, 0x65,
|
0x73, 0x65, 0x72, 0x76, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x54, 0x54, 0x4c, 0x88,
|
||||||
0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a,
|
0x01, 0x01, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79,
|
||||||
0x61, 0x63, 0x74, 0x55, 0x6e, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08,
|
0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x51, 0x75, 0x65,
|
||||||
0x52, 0x0a, 0x61, 0x63, 0x74, 0x55, 0x6e, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x1a, 0x5e, 0x0a, 0x0e,
|
0x72, 0x79, 0x12, 0x41, 0x0a, 0x10, 0x75, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64,
|
||||||
0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34,
|
0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78,
|
||||||
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78,
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61,
|
0x65, 0x6f, 0x49, 0x50, 0x52, 0x0f, 0x75, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64,
|
||||||
0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04,
|
0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x63, 0x74, 0x55, 0x6e, 0x70, 0x72,
|
||||||
0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02,
|
0x69, 0x6f, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x63, 0x74, 0x55, 0x6e,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c,
|
0x70, 0x72, 0x69, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49,
|
||||||
0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04,
|
0x44, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49,
|
||||||
0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65,
|
0x44, 0x1a, 0x5e, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d,
|
||||||
0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04,
|
0x61, 0x69, 0x6e, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x73, 0x69, 0x7a, 0x65, 0x22, 0x9c, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73,
|
||||||
0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05,
|
0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54,
|
||||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d,
|
||||||
0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a,
|
0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69,
|
||||||
0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c,
|
0x6e, 0x1a, 0x36, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c,
|
||||||
0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63,
|
0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69,
|
0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20,
|
||||||
0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e,
|
0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x64, 0x69,
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e,
|
0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x73,
|
||||||
0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52,
|
0x65, 0x72, 0x76, 0x65, 0x53, 0x74, 0x61, 0x6c, 0x65, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x73, 0x65,
|
||||||
0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03,
|
0x72, 0x76, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x54, 0x54, 0x4c, 0x22, 0x98, 0x05,
|
||||||
0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x22,
|
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65,
|
||||||
0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08,
|
0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e,
|
||||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63,
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d,
|
||||||
0x68, 0x65, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61,
|
0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72,
|
||||||
0x74, 0x65, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61,
|
0x76, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70,
|
||||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53,
|
0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70,
|
||||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74,
|
0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73,
|
||||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c,
|
0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||||
0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52,
|
0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73,
|
||||||
0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
|
0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63,
|
||||||
0x12, 0x36, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62,
|
0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01,
|
||||||
0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08,
|
0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62,
|
||||||
0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
|
0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64,
|
||||||
0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x1a, 0x92, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73,
|
0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73,
|
||||||
0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
|
0x65, 0x72, 0x76, 0x65, 0x53, 0x74, 0x61, 0x6c, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x53, 0x74, 0x61, 0x6c, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73,
|
||||||
0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63,
|
0x65, 0x72, 0x76, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x54, 0x54, 0x4c, 0x18, 0x0d,
|
||||||
0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16,
|
0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72,
|
||||||
0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
0x65, 0x64, 0x54, 0x54, 0x4c, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73,
|
||||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03,
|
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e,
|
||||||
0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65,
|
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65,
|
||||||
0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
|
0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72,
|
||||||
0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x04, 0x08,
|
0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73,
|
||||||
0x07, 0x10, 0x08, 0x2a, 0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74,
|
0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01,
|
||||||
0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c,
|
0x28, 0x08, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62,
|
||||||
0x6c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
0x61, 0x63, 0x6b, 0x12, 0x36, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61,
|
||||||
0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x10, 0x02, 0x12,
|
0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20,
|
||||||
0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x2a, 0x42, 0x0a, 0x0d, 0x51, 0x75,
|
0x01, 0x28, 0x08, 0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c,
|
||||||
0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55,
|
0x62, 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x30, 0x0a, 0x13, 0x65,
|
||||||
0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49,
|
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x51, 0x75, 0x65,
|
||||||
0x50, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10,
|
0x72, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
|
||||||
0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x53, 0x59, 0x53, 0x10, 0x03, 0x42, 0x46,
|
0x50, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x92, 0x01,
|
||||||
0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64,
|
0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a,
|
||||||
0x6e, 0x73, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72,
|
||||||
0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f,
|
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||||
0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41,
|
0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74,
|
||||||
0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
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 (
|
||||||
@@ -718,6 +785,7 @@ 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{
|
||||||
|
|||||||
@@ -31,10 +31,13 @@ message NameServer {
|
|||||||
bool actPrior = 8;
|
bool actPrior = 8;
|
||||||
string tag = 9;
|
string tag = 9;
|
||||||
uint64 timeoutMs = 10;
|
uint64 timeoutMs = 10;
|
||||||
bool disableCache = 11;
|
optional bool disableCache = 11;
|
||||||
|
optional bool serveStale = 15;
|
||||||
|
optional uint32 serveExpiredTTL = 16;
|
||||||
bool finalQuery = 12;
|
bool finalQuery = 12;
|
||||||
repeated xray.app.router.GeoIP unexpected_geoip = 13;
|
repeated xray.app.router.GeoIP unexpected_geoip = 13;
|
||||||
bool actUnprior = 14;
|
bool actUnprior = 14;
|
||||||
|
uint32 policyID = 17;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DomainMatchingType {
|
enum DomainMatchingType {
|
||||||
@@ -80,9 +83,13 @@ 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;
|
||||||
}
|
}
|
||||||
|
|||||||
+294
-60
@@ -5,9 +5,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
go_errors "errors"
|
go_errors "errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"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"
|
||||||
@@ -22,6 +25,7 @@ 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
|
||||||
@@ -102,13 +106,12 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
|||||||
|
|
||||||
for _, ns := range config.NameServer {
|
for _, ns := range config.NameServer {
|
||||||
clientIdx := len(clients)
|
clientIdx := len(clients)
|
||||||
updateDomain := func(domainRule strmatcher.Matcher, originalRuleIdx int, matcherInfos []*DomainMatcherInfo) error {
|
updateDomain := func(domainRule strmatcher.Matcher, originalRuleIdx int, matcherInfos []*DomainMatcherInfo) {
|
||||||
midx := domainMatcher.Add(domainRule)
|
midx := domainMatcher.Add(domainRule)
|
||||||
matcherInfos[midx] = &DomainMatcherInfo{
|
matcherInfos[midx] = &DomainMatcherInfo{
|
||||||
clientIdx: uint16(clientIdx),
|
clientIdx: uint16(clientIdx),
|
||||||
domainRuleIdx: uint16(originalRuleIdx),
|
domainRuleIdx: uint16(originalRuleIdx),
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
myClientIP := clientIP
|
myClientIP := clientIP
|
||||||
@@ -117,7 +120,20 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
|||||||
myClientIP = net.IP(ns.ClientIp)
|
myClientIP = net.IP(ns.ClientIp)
|
||||||
}
|
}
|
||||||
|
|
||||||
disableCache := config.DisableCache || ns.DisableCache
|
disableCache := config.DisableCache
|
||||||
|
if ns.DisableCache != nil {
|
||||||
|
disableCache = *ns.DisableCache
|
||||||
|
}
|
||||||
|
|
||||||
|
serveStale := config.ServeStale
|
||||||
|
if ns.ServeStale != nil {
|
||||||
|
serveStale = *ns.ServeStale
|
||||||
|
}
|
||||||
|
|
||||||
|
serveExpiredTTL := config.ServeExpiredTTL
|
||||||
|
if ns.ServeExpiredTTL != nil {
|
||||||
|
serveExpiredTTL = *ns.ServeExpiredTTL
|
||||||
|
}
|
||||||
|
|
||||||
var tag = defaultTag
|
var tag = defaultTag
|
||||||
if len(ns.Tag) > 0 {
|
if len(ns.Tag) > 0 {
|
||||||
@@ -128,7 +144,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
|||||||
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, tag, clientIPOption, &matcherInfos, updateDomain)
|
client, err := NewClient(ctx, ns, myClientIP, disableCache, serveStale, serveExpiredTTL, 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)
|
||||||
}
|
}
|
||||||
@@ -149,6 +165,7 @@ 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
|
||||||
}
|
}
|
||||||
@@ -191,7 +208,7 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
if s.checkSystem {
|
if s.checkSystem {
|
||||||
supportIPv4, supportIPv6 := checkSystemNetwork()
|
supportIPv4, supportIPv6 := checkRoutes()
|
||||||
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
||||||
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
||||||
} else {
|
} else {
|
||||||
@@ -227,45 +244,11 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Name servers lookup
|
// Name servers lookup
|
||||||
var errs []error
|
if s.enableParallelQuery {
|
||||||
for _, client := range s.sortClients(domain) {
|
return s.parallelQuery(domain, option)
|
||||||
if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
|
} else {
|
||||||
errors.LogDebug(s.ctx, "skip DNS resolution for domain ", domain, " at server ", client.Name())
|
return s.serialQuery(domain, option)
|
||||||
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 {
|
||||||
@@ -292,6 +275,9 @@ func (s *DNS) sortClients(domain string) []*Client {
|
|||||||
clients = append(clients, client)
|
clients = append(clients, client)
|
||||||
clientNames = append(clientNames, client.Name())
|
clientNames = append(clientNames, client.Name())
|
||||||
hasMatch = true
|
hasMatch = true
|
||||||
|
if client.finalQuery {
|
||||||
|
return clients
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(s.disableFallback || s.disableFallbackIfMatch && hasMatch) {
|
if !(s.disableFallback || s.disableFallbackIfMatch && hasMatch) {
|
||||||
@@ -303,6 +289,9 @@ 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 {
|
||||||
|
return clients
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,35 +303,280 @@ func (s *DNS) sortClients(domain string) []*Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(clients) == 0 {
|
if len(clients) == 0 {
|
||||||
clients = append(clients, s.clients[0])
|
if len(s.clients) > 0 {
|
||||||
clientNames = append(clientNames, s.clients[0].Name())
|
clients = append(clients, s.clients[0])
|
||||||
errors.LogDebug(s.ctx, "domain ", domain, " will use the first DNS: ", clientNames)
|
clientNames = append(clientNames, s.clients[0].Name())
|
||||||
|
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 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) {
|
func probeRoutes() (ipv4 bool, ipv6 bool) {
|
||||||
conn4, err4 := net.Dial("udp4", "192.33.4.12:53")
|
if conn, err := net.Dial("udp4", "192.33.4.12:53"); err == nil {
|
||||||
if err4 != nil {
|
ipv4 = true
|
||||||
supportIPv4 = false
|
conn.Close()
|
||||||
} else {
|
|
||||||
supportIPv4 = true
|
|
||||||
conn4.Close()
|
|
||||||
}
|
}
|
||||||
|
if conn, err := net.Dial("udp6", "[2001:500:2::c]:53"); err == nil {
|
||||||
conn6, err6 := net.Dial("udp6", "[2001:500:2::c]:53")
|
ipv6 = true
|
||||||
if err6 != nil {
|
conn.Close()
|
||||||
supportIPv6 = false
|
|
||||||
} else {
|
|
||||||
supportIPv6 = true
|
|
||||||
conn6.Close()
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var routeCache struct {
|
||||||
|
sync.Once
|
||||||
|
sync.RWMutex
|
||||||
|
expire time.Time
|
||||||
|
ipv4, ipv6 bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkRoutes() (bool, bool) {
|
||||||
|
if !isGUIPlatform {
|
||||||
|
routeCache.Once.Do(func() {
|
||||||
|
routeCache.ipv4, routeCache.ipv6 = probeRoutes()
|
||||||
|
})
|
||||||
|
return routeCache.ipv4, routeCache.ipv6
|
||||||
|
}
|
||||||
|
|
||||||
|
routeCache.RWMutex.RLock()
|
||||||
|
now := time.Now()
|
||||||
|
if routeCache.expire.After(now) {
|
||||||
|
routeCache.RWMutex.RUnlock()
|
||||||
|
return routeCache.ipv4, routeCache.ipv6
|
||||||
|
}
|
||||||
|
routeCache.RWMutex.RUnlock()
|
||||||
|
|
||||||
|
routeCache.RWMutex.Lock()
|
||||||
|
defer routeCache.RWMutex.Unlock()
|
||||||
|
|
||||||
|
now = time.Now()
|
||||||
|
if routeCache.expire.After(now) { // double-check
|
||||||
|
return routeCache.ipv4, routeCache.ipv6
|
||||||
|
}
|
||||||
|
routeCache.ipv4, routeCache.ipv6 = probeRoutes() // ~2ms
|
||||||
|
routeCache.expire = now.Add(100 * time.Millisecond) // ttl
|
||||||
|
return routeCache.ipv4, routeCache.ipv6
|
||||||
|
}
|
||||||
|
|
||||||
|
var isGUIPlatform = detectGUIPlatform()
|
||||||
|
|
||||||
|
func detectGUIPlatform() bool {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "android", "ios", "windows", "darwin":
|
||||||
|
return true
|
||||||
|
case "linux", "freebsd", "openbsd":
|
||||||
|
if t := os.Getenv("XDG_SESSION_TYPE"); t == "wayland" || t == "x11" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if os.Getenv("DISPLAY") != "" || os.Getenv("WAYLAND_DISPLAY") != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package dns
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -13,10 +14,12 @@ 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
|
||||||
@@ -38,19 +41,14 @@ type IPRecord struct {
|
|||||||
RawHeader *dnsmessage.Header
|
RawHeader *dnsmessage.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IPRecord) getIPs() ([]net.IP, uint32, error) {
|
func (r *IPRecord) getIPs() ([]net.IP, int32, error) {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return nil, 0, errRecordNotFound
|
return nil, 0, errRecordNotFound
|
||||||
}
|
}
|
||||||
untilExpire := time.Until(r.Expire).Seconds()
|
|
||||||
if untilExpire <= 0 {
|
|
||||||
return nil, 0, errRecordNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
ttl := uint32(untilExpire) + 1
|
untilExpire := time.Until(r.Expire).Seconds()
|
||||||
if ttl == 1 {
|
ttl := int32(math.Ceil(untilExpire))
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
gonet "net"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -17,7 +16,7 @@ import (
|
|||||||
|
|
||||||
type Holder struct {
|
type Holder struct {
|
||||||
domainToIP cache.Lru
|
domainToIP cache.Lru
|
||||||
ipRange *gonet.IPNet
|
ipRange *net.IPNet
|
||||||
mu *sync.Mutex
|
mu *sync.Mutex
|
||||||
|
|
||||||
config *FakeDnsPool
|
config *FakeDnsPool
|
||||||
@@ -79,10 +78,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 *gonet.IPNet
|
var ipRange *net.IPNet
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if _, ipRange, err = gonet.ParseCIDR(ipPoolCidr); err != nil {
|
if _, ipRange, err = net.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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package fakedns
|
package fakedns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gonet "net"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -155,7 +154,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 := gonet.ResolveIPAddr("ip", "fddd:c5b4:ff5f:f4f0::5")
|
ip, err := net.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 +164,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 := gonet.ResolveIPAddr("ip", "fcdd:c5b4:ff5f:f4f0::5")
|
ip, err := net.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)
|
||||||
|
|||||||
+7
-2
@@ -27,7 +27,8 @@ func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
|
|||||||
for _, mapping := range hosts {
|
for _, mapping := range hosts {
|
||||||
matcher, err := toStrMatcher(mapping.Type, mapping.Domain)
|
matcher, err := toStrMatcher(mapping.Type, mapping.Domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to create domain matcher").Base(err)
|
errors.LogErrorInner(context.Background(), err, "failed to create domain matcher, ignore domain rule [type: ", mapping.Type, ", domain: ", mapping.Domain, "]")
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
id := g.Add(matcher)
|
id := g.Add(matcher)
|
||||||
ips := make([]net.Address, 0, len(mapping.Ip)+1)
|
ips := make([]net.Address, 0, len(mapping.Ip)+1)
|
||||||
@@ -46,10 +47,14 @@ func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
|
|||||||
for _, ip := range mapping.Ip {
|
for _, ip := range mapping.Ip {
|
||||||
addr := net.IPAddress(ip)
|
addr := net.IPAddress(ip)
|
||||||
if addr == nil {
|
if addr == nil {
|
||||||
return nil, errors.New("invalid IP address in static hosts: ", ip).AtWarning()
|
errors.LogError(context.Background(), "invalid IP address in static hosts: ", ip, ", ignore this ip for rule [type: ", mapping.Type, ", domain: ", mapping.Domain, "]")
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
ips = append(ips, addr)
|
ips = append(ips, addr)
|
||||||
}
|
}
|
||||||
|
if len(ips) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sh.ips[id] = ips
|
sh.ips[id] = ips
|
||||||
|
|||||||
+39
-42
@@ -20,6 +20,9 @@ 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)
|
||||||
}
|
}
|
||||||
@@ -29,8 +32,8 @@ type Client struct {
|
|||||||
server Server
|
server Server
|
||||||
skipFallback bool
|
skipFallback bool
|
||||||
domains []string
|
domains []string
|
||||||
expectedIPs []*router.GeoIPMatcher
|
expectedIPs router.GeoIPMatcher
|
||||||
unexpectedIPs []*router.GeoIPMatcher
|
unexpectedIPs router.GeoIPMatcher
|
||||||
actPrior bool
|
actPrior bool
|
||||||
actUnprior bool
|
actUnprior bool
|
||||||
tag string
|
tag string
|
||||||
@@ -38,10 +41,11 @@ 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, clientIP net.IP) (Server, error) {
|
func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dispatcher, disableCache bool, serveStale bool, serveExpiredTTL uint32, 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 {
|
||||||
@@ -51,19 +55,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, clientIP), nil
|
return NewDoHNameServer(u, dispatcher, false, disableCache, serveStale, serveExpiredTTL, 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, clientIP), nil
|
return NewDoHNameServer(u, dispatcher, true, disableCache, serveStale, serveExpiredTTL, 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, clientIP), nil
|
return NewDoHNameServer(u, nil, false, disableCache, serveStale, serveExpiredTTL, 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, clientIP), nil
|
return NewDoHNameServer(u, nil, true, disableCache, serveStale, serveExpiredTTL, 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, clientIP)
|
return NewQUICNameServer(u, disableCache, serveStale, serveExpiredTTL, 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, clientIP)
|
return NewTCPNameServer(u, dispatcher, disableCache, serveStale, serveExpiredTTL, 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, clientIP)
|
return NewTCPLocalNameServer(u, disableCache, serveStale, serveExpiredTTL, 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) {
|
||||||
@@ -79,7 +83,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, clientIP), nil
|
return NewClassicNameServer(dest, dispatcher, disableCache, serveStale, serveExpiredTTL, 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()
|
||||||
}
|
}
|
||||||
@@ -89,17 +93,17 @@ func NewClient(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
ns *NameServer,
|
ns *NameServer,
|
||||||
clientIP net.IP,
|
clientIP net.IP,
|
||||||
disableCache bool,
|
disableCache bool, serveStale bool, serveExpiredTTL uint32,
|
||||||
tag string,
|
tag string,
|
||||||
ipOption dns.IPOption,
|
ipOption dns.IPOption,
|
||||||
matcherInfos *[]*DomainMatcherInfo,
|
matcherInfos *[]*DomainMatcherInfo,
|
||||||
updateDomainRule func(strmatcher.Matcher, int, []*DomainMatcherInfo) error,
|
updateDomainRule func(strmatcher.Matcher, int, []*DomainMatcherInfo),
|
||||||
) (*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, clientIP)
|
server, err := NewServer(ctx, ns.Address.AsDestination(), dispatcher, disableCache, serveStale, serveExpiredTTL, 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()
|
||||||
}
|
}
|
||||||
@@ -130,7 +134,8 @@ func NewClient(
|
|||||||
for _, domain := range ns.PrioritizedDomain {
|
for _, domain := range ns.PrioritizedDomain {
|
||||||
domainRule, err := toStrMatcher(domain.Type, domain.Domain)
|
domainRule, err := toStrMatcher(domain.Type, domain.Domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create prioritized domain").Base(err).AtWarning()
|
errors.LogErrorInner(ctx, err, "failed to create domain matcher, ignore domain rule [type: ", domain.Type, ", domain: ", domain.Domain, "]")
|
||||||
|
domainRule, _ = toStrMatcher(DomainMatchingType_Full, "hack.fix.index.for.illegal.domain.rule")
|
||||||
}
|
}
|
||||||
originalRuleIdx := ruleCurr
|
originalRuleIdx := ruleCurr
|
||||||
if ruleCurr < len(ns.OriginalRules) {
|
if ruleCurr < len(ns.OriginalRules) {
|
||||||
@@ -147,30 +152,25 @@ func NewClient(
|
|||||||
rules = append(rules, domainRule.String())
|
rules = append(rules, domainRule.String())
|
||||||
ruleCurr++
|
ruleCurr++
|
||||||
}
|
}
|
||||||
err = updateDomainRule(domainRule, originalRuleIdx, *matcherInfos)
|
updateDomainRule(domainRule, originalRuleIdx, *matcherInfos)
|
||||||
if err != nil {
|
|
||||||
return errors.New("failed to create prioritized domain").Base(err).AtWarning()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Establish expected IPs
|
// Establish expected IPs
|
||||||
var expectedMatchers []*router.GeoIPMatcher
|
var expectedMatcher router.GeoIPMatcher
|
||||||
for _, geoip := range ns.ExpectedGeoip {
|
if len(ns.ExpectedGeoip) > 0 {
|
||||||
matcher, err := router.GlobalGeoIPContainer.Add(geoip)
|
expectedMatcher, err = router.BuildOptimizedGeoIPMatcher(ns.ExpectedGeoip...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create expected ip matcher").Base(err).AtWarning()
|
return errors.New("failed to create expected ip matcher").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
expectedMatchers = append(expectedMatchers, matcher)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Establish unexpected IPs
|
// Establish unexpected IPs
|
||||||
var unexpectedMatchers []*router.GeoIPMatcher
|
var unexpectedMatcher router.GeoIPMatcher
|
||||||
for _, geoip := range ns.UnexpectedGeoip {
|
if len(ns.UnexpectedGeoip) > 0 {
|
||||||
matcher, err := router.GlobalGeoIPContainer.Add(geoip)
|
unexpectedMatcher, err = router.BuildOptimizedGeoIPMatcher(ns.UnexpectedGeoip...)
|
||||||
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 {
|
||||||
@@ -192,8 +192,8 @@ func NewClient(
|
|||||||
client.server = server
|
client.server = server
|
||||||
client.skipFallback = ns.SkipFallback
|
client.skipFallback = ns.SkipFallback
|
||||||
client.domains = rules
|
client.domains = rules
|
||||||
client.expectedIPs = expectedMatchers
|
client.expectedIPs = expectedMatcher
|
||||||
client.unexpectedIPs = unexpectedMatchers
|
client.unexpectedIPs = unexpectedMatcher
|
||||||
client.actPrior = ns.ActPrior
|
client.actPrior = ns.ActPrior
|
||||||
client.actUnprior = ns.ActUnprior
|
client.actUnprior = ns.ActUnprior
|
||||||
client.tag = tag
|
client.tag = tag
|
||||||
@@ -201,6 +201,7 @@ 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
|
||||||
@@ -211,14 +212,10 @@ 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 := checkSystemNetwork()
|
supportIPv4, supportIPv6 := checkRoutes()
|
||||||
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
||||||
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
||||||
} else {
|
} else {
|
||||||
@@ -243,32 +240,32 @@ func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption
|
|||||||
return nil, 0, dns.ErrEmptyResponse
|
return nil, 0, dns.ErrEmptyResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.expectedIPs) > 0 && !c.actPrior {
|
if c.expectedIPs != nil && !c.actPrior {
|
||||||
ips = router.MatchIPs(c.expectedIPs, ips, false)
|
ips, _ = c.expectedIPs.FilterIPs(ips)
|
||||||
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 len(c.unexpectedIPs) > 0 && !c.actUnprior {
|
if c.unexpectedIPs != nil && !c.actUnprior {
|
||||||
ips = router.MatchIPs(c.unexpectedIPs, ips, true)
|
_, ips = c.unexpectedIPs.FilterIPs(ips)
|
||||||
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 len(c.expectedIPs) > 0 && c.actPrior {
|
if c.expectedIPs != nil && c.actPrior {
|
||||||
ipsNew := router.MatchIPs(c.expectedIPs, ips, false)
|
ipsNew, _ := c.expectedIPs.FilterIPs(ips)
|
||||||
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 len(c.unexpectedIPs) > 0 && c.actUnprior {
|
if c.unexpectedIPs != nil && c.actUnprior {
|
||||||
ipsNew := router.MatchIPs(c.unexpectedIPs, ips, true)
|
_, ipsNew := c.unexpectedIPs.FilterIPs(ips)
|
||||||
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())
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
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...)
|
||||||
|
}
|
||||||
+36
-61
@@ -4,7 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
go_errors "errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -38,7 +37,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, clientIP net.IP) *DoHNameServer {
|
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, h2c bool, disableCache bool, serveStale bool, serveExpiredTTL uint32, clientIP net.IP) *DoHNameServer {
|
||||||
url.Scheme = "https"
|
url.Scheme = "https"
|
||||||
mode := "DOH"
|
mode := "DOH"
|
||||||
if dispatcher == nil {
|
if dispatcher == nil {
|
||||||
@@ -46,7 +45,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),
|
cacheController: NewCacheController(mode+"//"+url.Host, disableCache, serveStale, serveExpiredTTL),
|
||||||
dohURL: url.String(),
|
dohURL: url.String(),
|
||||||
clientIP: clientIP,
|
clientIP: clientIP,
|
||||||
}
|
}
|
||||||
@@ -117,22 +116,35 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DoHNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
// getCacheController implements CachedNameserver.
|
||||||
errors.LogInfo(ctx, s.Name(), " querying: ", domain)
|
func (s *DoHNameServer) getCacheController() *CacheController {
|
||||||
|
return s.cacheController
|
||||||
|
}
|
||||||
|
|
||||||
if s.Name()+"." == "DOH//"+domain {
|
// sendQuery implements CachedNameserver.
|
||||||
errors.LogError(ctx, s.Name(), " tries to resolve itself! Use IP or set \"hosts\" instead.")
|
func (s *DoHNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
||||||
noResponseErrCh <- errors.New("tries to resolve itself!", s.Name())
|
errors.LogInfo(ctx, s.Name(), " querying: ", fqdn)
|
||||||
|
|
||||||
|
if s.Name()+"." == "DOH//"+fqdn {
|
||||||
|
errors.LogError(ctx, s.Name(), " tries to resolve itself! Use IP or set \"hosts\" instead")
|
||||||
|
if noResponseErrCh != nil {
|
||||||
|
noResponseErrCh <- errors.New("tries to resolve itself!", s.Name())
|
||||||
|
}
|
||||||
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 := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, int(crypto.RandBetween(100, 300))))
|
reqs := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, int(crypto.RandBetween(100, 300))))
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
@@ -166,23 +178,29 @@ 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 ", domain)
|
errors.LogErrorInner(ctx, err, "failed to pack dns query for ", fqdn)
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
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 ", domain)
|
errors.LogErrorInner(ctx, err, "failed to retrieve response for ", fqdn)
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
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 ", domain)
|
errors.LogErrorInner(ctx, err, "failed to handle DOH response for ", fqdn)
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.cacheController.updateIP(r, rec)
|
s.cacheController.updateRecord(r, rec)
|
||||||
}(req)
|
}(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,49 +234,6 @@ 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) { // nolint: dupl
|
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||||
fqdn := Fqdn(domain)
|
return queryIP(ctx, s, domain, option)
|
||||||
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, net.IP(nil))
|
s := NewDoHNameServer(url, nil, false, false, false, 0, 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, net.IP(nil))
|
s := NewDoHNameServer(url, nil, false, false, false, 0, 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, net.IP(nil))
|
s := NewDoHNameServer(url, nil, false, false, false, 0, 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, net.IP(nil))
|
s := NewDoHNameServer(url, nil, false, false, false, 0, 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,6 +20,11 @@ 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()
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ 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")
|
||||||
|
|||||||
+48
-66
@@ -4,12 +4,11 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
go_errors "errors"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/quic-go/quic-go"
|
"github.com/apernet/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"
|
||||||
@@ -37,9 +36,7 @@ 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, clientIP net.IP) (*QUICNameServer, error) {
|
func NewQUICNameServer(url *url.URL, disableCache bool, serveStale bool, serveExpiredTTL uint32, 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() != "" {
|
||||||
@@ -51,27 +48,37 @@ func NewQUICNameServer(url *url.URL, disableCache bool, clientIP net.IP) (*QUICN
|
|||||||
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),
|
cacheController: NewCacheController(url.String(), disableCache, serveStale, serveExpiredTTL),
|
||||||
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 returns client name
|
// Name implements Server.
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
// getCacheController implements CachedNameServer.
|
||||||
errors.LogInfo(ctx, s.Name(), " querying: ", domain)
|
func (s *QUICNameServer) getCacheController() *CacheController { return s.cacheController }
|
||||||
|
|
||||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
// sendQuery implements CachedNameServer.
|
||||||
|
func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
||||||
|
errors.LogInfo(ctx, s.Name(), " querying: ", fqdn)
|
||||||
|
|
||||||
|
reqs := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
@@ -103,7 +110,9 @@ 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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,13 +120,17 @@ 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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b.Release()
|
b.Release()
|
||||||
@@ -125,14 +138,18 @@ 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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,81 +160,46 @@ 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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var length int16
|
var length uint16
|
||||||
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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.cacheController.updateIP(r, rec)
|
s.cacheController.updateRecord(r, rec)
|
||||||
}(req)
|
}(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryIP is called from dns.Server->queryIPTimeout
|
// QueryIP implements Server.
|
||||||
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) {
|
||||||
fqdn := Fqdn(domain)
|
return queryIP(ctx, s, domain, option)
|
||||||
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, net.IP(nil))
|
s, err := NewQUICNameServer(url, false, false, 0, 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, net.IP(nil))
|
s, err := NewQUICNameServer(url, false, false, 0, 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, net.IP(nil))
|
s, err := NewQUICNameServer(url, false, false, 0, 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{
|
||||||
|
|||||||
+52
-66
@@ -4,14 +4,12 @@ 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"
|
||||||
@@ -34,10 +32,10 @@ type TCPNameServer struct {
|
|||||||
func NewTCPNameServer(
|
func NewTCPNameServer(
|
||||||
url *url.URL,
|
url *url.URL,
|
||||||
dispatcher routing.Dispatcher,
|
dispatcher routing.Dispatcher,
|
||||||
disableCache bool,
|
disableCache bool, serveStale bool, serveExpiredTTL uint32,
|
||||||
clientIP net.IP,
|
clientIP net.IP,
|
||||||
) (*TCPNameServer, error) {
|
) (*TCPNameServer, error) {
|
||||||
s, err := baseTCPNameServer(url, "TCP", disableCache, clientIP)
|
s, err := baseTCPNameServer(url, "TCP", disableCache, serveStale, serveExpiredTTL, clientIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -54,12 +52,13 @@ 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, clientIP net.IP) (*TCPNameServer, error) {
|
func NewTCPLocalNameServer(url *url.URL, disableCache bool, serveStale bool, serveExpiredTTL uint32, clientIP net.IP) (*TCPNameServer, error) {
|
||||||
s, err := baseTCPNameServer(url, "TCPL", disableCache, clientIP)
|
s, err := baseTCPNameServer(url, "TCPL", disableCache, serveStale, serveExpiredTTL, clientIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -68,10 +67,11 @@ func NewTCPLocalNameServer(url *url.URL, disableCache bool, clientIP net.IP) (*T
|
|||||||
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, clientIP net.IP) (*TCPNameServer, error) {
|
func baseTCPNameServer(url *url.URL, prefix string, disableCache bool, serveStale bool, serveExpiredTTL uint32, 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, clientIP
|
|||||||
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),
|
cacheController: NewCacheController(prefix+"//"+dest.NetAddr(), disableCache, serveStale, serveExpiredTTL),
|
||||||
destination: &dest,
|
destination: &dest,
|
||||||
clientIP: clientIP,
|
clientIP: clientIP,
|
||||||
}
|
}
|
||||||
@@ -95,14 +95,25 @@ 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))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
// getCacheController implements CachedNameserver.
|
||||||
errors.LogDebug(ctx, s.Name(), " querying DNS for: ", domain)
|
func (s *TCPNameServer) getCacheController() *CacheController {
|
||||||
|
return s.cacheController
|
||||||
|
}
|
||||||
|
|
||||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
// sendQuery implements CachedNameserver.
|
||||||
|
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 := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
@@ -131,14 +142,18 @@ 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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
@@ -146,13 +161,17 @@ 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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b.Release()
|
b.Release()
|
||||||
@@ -160,7 +179,9 @@ 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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dnsReqBuf.Release()
|
dnsReqBuf.Release()
|
||||||
@@ -170,80 +191,45 @@ 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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var length int16
|
var length uint16
|
||||||
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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
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")
|
||||||
noResponseErrCh <- err
|
if noResponseErrCh != nil {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cacheController.updateIP(r, rec)
|
s.cacheController.updateRecord(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) {
|
||||||
fqdn := Fqdn(domain)
|
return queryIP(ctx, s, domain, option)
|
||||||
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, net.IP(nil))
|
s, err := NewTCPLocalNameServer(url, false, false, 0, 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, net.IP(nil))
|
s, err := NewTCPLocalNameServer(url, false, false, 0, 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, net.IP(nil))
|
s, err := NewTCPLocalNameServer(url, false, false, 0, 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, net.IP(nil))
|
s, err := NewTCPLocalNameServer(url, false, false, 0, 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{
|
||||||
|
|||||||
+29
-55
@@ -2,7 +2,6 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
go_errors "errors"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -10,7 +9,6 @@ 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"
|
||||||
@@ -39,14 +37,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, clientIP net.IP) *ClassicNameServer {
|
func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher, disableCache bool, serveStale bool, serveExpiredTTL uint32, 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),
|
cacheController: NewCacheController(strings.ToUpper(address.String()), disableCache, serveStale, serveExpiredTTL),
|
||||||
address: &address,
|
address: &address,
|
||||||
requests: make(map[uint16]*udpDnsRequest),
|
requests: make(map[uint16]*udpDnsRequest),
|
||||||
clientIP: clientIP,
|
clientIP: clientIP,
|
||||||
@@ -56,6 +54,7 @@ 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
|
||||||
}
|
}
|
||||||
@@ -65,6 +64,11 @@ 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()
|
||||||
@@ -94,7 +98,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.LogError(ctx, s.Name(), " fail to parse responded DNS udp")
|
errors.LogErrorInner(ctx, err, s.Name(), " fail to parse responded DNS udp")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +111,7 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
|||||||
}
|
}
|
||||||
s.Unlock()
|
s.Unlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
errors.LogError(ctx, s.Name(), " cannot find the pending request")
|
errors.LogErrorInner(ctx, err, s.Name(), " cannot find the pending request")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +138,7 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cacheController.updateIP(&req.dnsRequest, ipRec)
|
s.cacheController.updateRecord(&req.dnsRequest, ipRec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ClassicNameServer) newReqID() uint16 {
|
func (s *ClassicNameServer) newReqID() uint16 {
|
||||||
@@ -150,10 +154,16 @@ func (s *ClassicNameServer) addPendingRequest(req *udpDnsRequest) {
|
|||||||
common.Must(s.requestsCleanup.Start())
|
common.Must(s.requestsCleanup.Start())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ClassicNameServer) sendQuery(ctx context.Context, _ chan<- error, domain string, option dns_feature.IPOption) {
|
// getCacheController implements CachedNameserver.
|
||||||
errors.LogDebug(ctx, s.Name(), " querying DNS for: ", domain)
|
func (s *ClassicNameServer) getCacheController() *CacheController {
|
||||||
|
return s.cacheController
|
||||||
|
}
|
||||||
|
|
||||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
// sendQuery implements CachedNameserver.
|
||||||
|
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 := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||||
|
|
||||||
for _, req := range reqs {
|
for _, req := range reqs {
|
||||||
udpReq := &udpDnsRequest{
|
udpReq := &udpDnsRequest{
|
||||||
@@ -161,7 +171,14 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, _ chan<- error, domai
|
|||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
s.addPendingRequest(udpReq)
|
s.addPendingRequest(udpReq)
|
||||||
b, _ := dns.PackMessage(req.msg)
|
b, err := dns.PackMessage(req.msg)
|
||||||
|
if err != nil {
|
||||||
|
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
||||||
|
if noResponseErrCh != nil {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
copyDest := net.UDPDestination(s.address.Address, s.address.Port)
|
copyDest := net.UDPDestination(s.address.Address, s.address.Port)
|
||||||
b.UDP = ©Dest
|
b.UDP = ©Dest
|
||||||
s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b)
|
s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b)
|
||||||
@@ -170,48 +187,5 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, _ chan<- error, domai
|
|||||||
|
|
||||||
// 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) {
|
||||||
fqdn := Fqdn(domain)
|
return queryIP(ctx, s, domain, option)
|
||||||
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
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+83
-33
@@ -2,8 +2,9 @@ package log
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"net"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -20,14 +21,23 @@ 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)
|
||||||
|
|
||||||
@@ -104,7 +114,11 @@ 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{Message: msg, config: g.config}
|
Msg = &MaskedMsgWrapper{
|
||||||
|
Message: msg,
|
||||||
|
Mask4: g.mask4,
|
||||||
|
Mask6: g.mask6,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Msg = msg
|
Msg = msg
|
||||||
}
|
}
|
||||||
@@ -149,51 +163,87 @@ 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
|
||||||
config *Config
|
Mask4 int
|
||||||
|
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()
|
||||||
|
|
||||||
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})(?:[\/\\%](\d{1,3}))?`)
|
|
||||||
|
|
||||||
// Process ipv4
|
// Process ipv4
|
||||||
maskedMsg := ipv4Regex.ReplaceAllStringFunc(str, func(ip string) string {
|
maskedMsg := ipv4Regex.ReplaceAllStringFunc(str, func(s string) string {
|
||||||
parts := strings.Split(ip, ".")
|
if m.Mask4 == 32 {
|
||||||
switch m.config.MaskAddress {
|
return s
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
if m.Mask4 == 0 {
|
||||||
|
return "[Masked IPv4]"
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(s, ".")
|
||||||
|
for i := m.Mask4 / 8; i < 4; i++ {
|
||||||
|
parts[i] = "*"
|
||||||
|
}
|
||||||
|
return strings.Join(parts, ".")
|
||||||
})
|
})
|
||||||
|
|
||||||
// process ipv6
|
// process ipv6
|
||||||
maskedMsg = ipv6Regex.ReplaceAllStringFunc(maskedMsg, func(ip string) string {
|
maskedMsg = ipv6Regex.ReplaceAllStringFunc(maskedMsg, func(s string) string {
|
||||||
parts := strings.Split(ip, ":")
|
if m.Mask6 == 128 {
|
||||||
switch m.config.MaskAddress {
|
return s
|
||||||
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
|
|
||||||
}
|
}
|
||||||
return ip
|
if m.Mask6 == 0 {
|
||||||
|
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,6 +2,7 @@ package log_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
@@ -50,3 +51,39 @@ 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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"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"
|
||||||
@@ -52,6 +53,20 @@ 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) {
|
||||||
|
// Set tag and sniffing config in context before creating proxy
|
||||||
|
// This allows proxies like TUN to access these settings
|
||||||
|
ctx = session.ContextWithInbound(ctx, &session.Inbound{Tag: tag})
|
||||||
|
if receiverConfig.SniffingSettings != nil {
|
||||||
|
ctx = session.ContextWithContent(ctx, &session.Content{
|
||||||
|
SniffingRequest: session.SniffingRequest{
|
||||||
|
Enabled: receiverConfig.SniffingSettings.Enabled,
|
||||||
|
OverrideDestinationForProtocol: receiverConfig.SniffingSettings.DestinationOverride,
|
||||||
|
ExcludeForDomain: receiverConfig.SniffingSettings.DomainsExcluded,
|
||||||
|
MetadataOnly: receiverConfig.SniffingSettings.MetadataOnly,
|
||||||
|
RouteOnly: receiverConfig.SniffingSettings.RouteOnly,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
rawProxy, err := common.CreateObject(ctx, proxyConfig)
|
rawProxy, err := common.CreateObject(ctx, proxyConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package inbound
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
gonet "net"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@@ -565,12 +564,12 @@ func (w *dsWorker) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func IsLocal(ip net.IP) bool {
|
func IsLocal(ip net.IP) bool {
|
||||||
addrs, err := gonet.InterfaceAddrs()
|
addrs, err := net.InterfaceAddrs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
if ipnet, ok := addr.(*gonet.IPNet); ok {
|
if ipnet, ok := addr.(*net.IPNet); ok {
|
||||||
if ipnet.IP.Equal(ip) {
|
if ipnet.IP.Equal(ip) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
goerrors "errors"
|
goerrors "errors"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
gonet "net"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/dice"
|
"github.com/xtls/xray-core/common/dice"
|
||||||
@@ -317,8 +316,12 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
|||||||
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)
|
||||||
ob := outbounds[len(outbounds)-1]
|
if outbounds != nil {
|
||||||
ob.Conn = conn
|
ob := outbounds[len(outbounds)-1]
|
||||||
|
ob.Conn = conn
|
||||||
|
} else {
|
||||||
|
// for Vision's pre-connect
|
||||||
|
}
|
||||||
return conn, err
|
return conn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,7 +397,7 @@ 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, _ := gonet.ParseCIDR(addr.IP().String() + "/" + prefix)
|
_, ipnet, _ := net.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))
|
||||||
@@ -408,5 +411,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(gonet.IP(padded).String())
|
return net.ParseAddress(net.IP(padded).String())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ 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"
|
||||||
@@ -230,8 +229,6 @@ func (w *BridgeWorker) DispatchLink(ctx context.Context, dest net.Destination, l
|
|||||||
}
|
}
|
||||||
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
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ func (s *routingServer) AddRule(ctx context.Context, request *AddRuleRequest) (*
|
|||||||
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,6 +68,20 @@ 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{
|
||||||
|
|||||||
+316
-273
@@ -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.35.1
|
// protoc-gen-go v1.36.11
|
||||||
// protoc v5.28.2
|
// protoc v6.33.2
|
||||||
// source: app/router/command/command.proto
|
// source: app/router/command/command.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
@@ -13,6 +13,7 @@ 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 (
|
||||||
@@ -26,25 +27,24 @@ 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
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
InboundTag string `protobuf:"bytes,1,opt,name=InboundTag,proto3" json:"InboundTag,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
Network net.Network `protobuf:"varint,2,opt,name=Network,proto3,enum=xray.common.net.Network" json:"Network,omitempty"`
|
||||||
|
SourceIPs [][]byte `protobuf:"bytes,3,rep,name=SourceIPs,proto3" json:"SourceIPs,omitempty"`
|
||||||
InboundTag string `protobuf:"bytes,1,opt,name=InboundTag,proto3" json:"InboundTag,omitempty"`
|
TargetIPs [][]byte `protobuf:"bytes,4,rep,name=TargetIPs,proto3" json:"TargetIPs,omitempty"`
|
||||||
Network net.Network `protobuf:"varint,2,opt,name=Network,proto3,enum=xray.common.net.Network" json:"Network,omitempty"`
|
SourcePort uint32 `protobuf:"varint,5,opt,name=SourcePort,proto3" json:"SourcePort,omitempty"`
|
||||||
SourceIPs [][]byte `protobuf:"bytes,3,rep,name=SourceIPs,proto3" json:"SourceIPs,omitempty"`
|
TargetPort uint32 `protobuf:"varint,6,opt,name=TargetPort,proto3" json:"TargetPort,omitempty"`
|
||||||
TargetIPs [][]byte `protobuf:"bytes,4,rep,name=TargetIPs,proto3" json:"TargetIPs,omitempty"`
|
TargetDomain string `protobuf:"bytes,7,opt,name=TargetDomain,proto3" json:"TargetDomain,omitempty"`
|
||||||
SourcePort uint32 `protobuf:"varint,5,opt,name=SourcePort,proto3" json:"SourcePort,omitempty"`
|
Protocol string `protobuf:"bytes,8,opt,name=Protocol,proto3" json:"Protocol,omitempty"`
|
||||||
TargetPort uint32 `protobuf:"varint,6,opt,name=TargetPort,proto3" json:"TargetPort,omitempty"`
|
User string `protobuf:"bytes,9,opt,name=User,proto3" json:"User,omitempty"`
|
||||||
TargetDomain string `protobuf:"bytes,7,opt,name=TargetDomain,proto3" json:"TargetDomain,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"`
|
||||||
Protocol string `protobuf:"bytes,8,opt,name=Protocol,proto3" json:"Protocol,omitempty"`
|
OutboundGroupTags []string `protobuf:"bytes,11,rep,name=OutboundGroupTags,proto3" json:"OutboundGroupTags,omitempty"`
|
||||||
User string `protobuf:"bytes,9,opt,name=User,proto3" json:"User,omitempty"`
|
OutboundTag string `protobuf:"bytes,12,opt,name=OutboundTag,proto3" json:"OutboundTag,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"`
|
LocalIPs [][]byte `protobuf:"bytes,13,rep,name=LocalIPs,proto3" json:"LocalIPs,omitempty"`
|
||||||
OutboundGroupTags []string `protobuf:"bytes,11,rep,name=OutboundGroupTags,proto3" json:"OutboundGroupTags,omitempty"`
|
LocalPort uint32 `protobuf:"varint,14,opt,name=LocalPort,proto3" json:"LocalPort,omitempty"`
|
||||||
OutboundTag string `protobuf:"bytes,12,opt,name=OutboundTag,proto3" json:"OutboundTag,omitempty"`
|
VlessRoute uint32 `protobuf:"varint,15,opt,name=VlessRoute,proto3" json:"VlessRoute,omitempty"`
|
||||||
LocalIPs [][]byte `protobuf:"bytes,13,rep,name=LocalIPs,proto3" json:"LocalIPs,omitempty"`
|
unknownFields protoimpl.UnknownFields
|
||||||
LocalPort uint32 `protobuf:"varint,14,opt,name=LocalPort,proto3" json:"LocalPort,omitempty"`
|
sizeCache protoimpl.SizeCache
|
||||||
VlessRoute uint32 `protobuf:"varint,15,opt,name=VlessRoute,proto3" json:"VlessRoute,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RoutingContext) Reset() {
|
func (x *RoutingContext) Reset() {
|
||||||
@@ -201,11 +201,10 @@ 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
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
FieldSelectors []string `protobuf:"bytes,1,rep,name=FieldSelectors,proto3" json:"FieldSelectors,omitempty"`
|
||||||
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() {
|
||||||
@@ -253,13 +252,12 @@ 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
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
RoutingContext *RoutingContext `protobuf:"bytes,1,opt,name=RoutingContext,proto3" json:"RoutingContext,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
FieldSelectors []string `protobuf:"bytes,2,rep,name=FieldSelectors,proto3" json:"FieldSelectors,omitempty"`
|
||||||
|
PublishResult bool `protobuf:"varint,3,opt,name=PublishResult,proto3" json:"PublishResult,omitempty"`
|
||||||
RoutingContext *RoutingContext `protobuf:"bytes,1,opt,name=RoutingContext,proto3" json:"RoutingContext,omitempty"`
|
unknownFields protoimpl.UnknownFields
|
||||||
FieldSelectors []string `protobuf:"bytes,2,rep,name=FieldSelectors,proto3" json:"FieldSelectors,omitempty"`
|
sizeCache protoimpl.SizeCache
|
||||||
PublishResult bool `protobuf:"varint,3,opt,name=PublishResult,proto3" json:"PublishResult,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *TestRouteRequest) Reset() {
|
func (x *TestRouteRequest) Reset() {
|
||||||
@@ -314,11 +312,10 @@ func (x *TestRouteRequest) GetPublishResult() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PrincipleTargetInfo struct {
|
type PrincipleTargetInfo struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
Tag []string `protobuf:"bytes,1,rep,name=tag,proto3" json:"tag,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
Tag []string `protobuf:"bytes,1,rep,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *PrincipleTargetInfo) Reset() {
|
func (x *PrincipleTargetInfo) Reset() {
|
||||||
@@ -359,11 +356,10 @@ func (x *PrincipleTargetInfo) GetTag() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OverrideInfo struct {
|
type OverrideInfo struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OverrideInfo) Reset() {
|
func (x *OverrideInfo) Reset() {
|
||||||
@@ -404,12 +400,11 @@ func (x *OverrideInfo) GetTarget() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BalancerMsg struct {
|
type BalancerMsg struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
Override *OverrideInfo `protobuf:"bytes,5,opt,name=override,proto3" json:"override,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
PrincipleTarget *PrincipleTargetInfo `protobuf:"bytes,6,opt,name=principle_target,json=principleTarget,proto3" json:"principle_target,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
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"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *BalancerMsg) Reset() {
|
func (x *BalancerMsg) Reset() {
|
||||||
@@ -457,11 +452,10 @@ func (x *BalancerMsg) GetPrincipleTarget() *PrincipleTargetInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetBalancerInfoRequest struct {
|
type GetBalancerInfoRequest struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetBalancerInfoRequest) Reset() {
|
func (x *GetBalancerInfoRequest) Reset() {
|
||||||
@@ -502,11 +496,10 @@ func (x *GetBalancerInfoRequest) GetTag() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetBalancerInfoResponse struct {
|
type GetBalancerInfoResponse struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
Balancer *BalancerMsg `protobuf:"bytes,1,opt,name=balancer,proto3" json:"balancer,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
Balancer *BalancerMsg `protobuf:"bytes,1,opt,name=balancer,proto3" json:"balancer,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetBalancerInfoResponse) Reset() {
|
func (x *GetBalancerInfoResponse) Reset() {
|
||||||
@@ -547,12 +540,11 @@ func (x *GetBalancerInfoResponse) GetBalancer() *BalancerMsg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OverrideBalancerTargetRequest struct {
|
type OverrideBalancerTargetRequest struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
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
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
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() {
|
||||||
@@ -600,9 +592,9 @@ func (x *OverrideBalancerTargetRequest) GetTarget() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OverrideBalancerTargetResponse struct {
|
type OverrideBalancerTargetResponse struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OverrideBalancerTargetResponse) Reset() {
|
func (x *OverrideBalancerTargetResponse) Reset() {
|
||||||
@@ -636,12 +628,11 @@ func (*OverrideBalancerTargetResponse) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AddRuleRequest struct {
|
type AddRuleRequest struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
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
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
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() {
|
||||||
@@ -689,9 +680,9 @@ func (x *AddRuleRequest) GetShouldAppend() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AddRuleResponse struct {
|
type AddRuleResponse struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddRuleResponse) Reset() {
|
func (x *AddRuleResponse) Reset() {
|
||||||
@@ -725,11 +716,10 @@ func (*AddRuleResponse) Descriptor() ([]byte, []int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RemoveRuleRequest struct {
|
type RemoveRuleRequest struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
RuleTag string `protobuf:"bytes,1,opt,name=ruleTag,proto3" json:"ruleTag,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
RuleTag string `protobuf:"bytes,1,opt,name=ruleTag,proto3" json:"ruleTag,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveRuleRequest) Reset() {
|
func (x *RemoveRuleRequest) Reset() {
|
||||||
@@ -770,9 +760,9 @@ func (x *RemoveRuleRequest) GetRuleTag() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RemoveRuleResponse struct {
|
type RemoveRuleResponse struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveRuleResponse) Reset() {
|
func (x *RemoveRuleResponse) Reset() {
|
||||||
@@ -805,15 +795,147 @@ 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 Config struct {
|
type ListRuleRequest struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
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 {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
mi := &file_app_router_command_command_proto_msgTypes[14]
|
mi := &file_app_router_command_command_proto_msgTypes[17]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -825,7 +947,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[14]
|
mi := &file_app_router_command_command_proto_msgTypes[17]
|
||||||
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 {
|
||||||
@@ -838,187 +960,103 @@ 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{14}
|
return file_app_router_command_command_proto_rawDescGZIP(), []int{17}
|
||||||
}
|
}
|
||||||
|
|
||||||
var File_app_router_command_command_proto protoreflect.FileDescriptor
|
var File_app_router_command_command_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_app_router_command_command_proto_rawDesc = []byte{
|
const file_app_router_command_command_proto_rawDesc = "" +
|
||||||
0x0a, 0x20, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d,
|
"\n" +
|
||||||
0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f,
|
" app/router/command/command.proto\x12\x17xray.app.router.command\x1a\x18common/net/network.proto\x1a!common/serial/typed_message.proto\"\xf6\x04\n" +
|
||||||
0x74, 0x6f, 0x12, 0x17, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
|
"\x0eRoutingContext\x12\x1e\n" +
|
||||||
0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x18, 0x63, 0x6f, 0x6d,
|
"\n" +
|
||||||
0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e,
|
"InboundTag\x18\x01 \x01(\tR\n" +
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65,
|
"InboundTag\x122\n" +
|
||||||
0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61,
|
"\aNetwork\x18\x02 \x01(\x0e2\x18.xray.common.net.NetworkR\aNetwork\x12\x1c\n" +
|
||||||
0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf6, 0x04, 0x0a, 0x0e, 0x52, 0x6f, 0x75,
|
"\tSourceIPs\x18\x03 \x03(\fR\tSourceIPs\x12\x1c\n" +
|
||||||
0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x49,
|
"\tTargetIPs\x18\x04 \x03(\fR\tTargetIPs\x12\x1e\n" +
|
||||||
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
"\n" +
|
||||||
0x0a, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x32, 0x0a, 0x07, 0x4e,
|
"SourcePort\x18\x05 \x01(\rR\n" +
|
||||||
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78,
|
"SourcePort\x12\x1e\n" +
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e,
|
"\n" +
|
||||||
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12,
|
"TargetPort\x18\x06 \x01(\rR\n" +
|
||||||
0x1c, 0x0a, 0x09, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x50, 0x73, 0x18, 0x03, 0x20, 0x03,
|
"TargetPort\x12\"\n" +
|
||||||
0x28, 0x0c, 0x52, 0x09, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x50, 0x73, 0x12, 0x1c, 0x0a,
|
"\fTargetDomain\x18\a \x01(\tR\fTargetDomain\x12\x1a\n" +
|
||||||
0x09, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x50, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c,
|
"\bProtocol\x18\b \x01(\tR\bProtocol\x12\x12\n" +
|
||||||
0x52, 0x09, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x50, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x53,
|
"\x04User\x18\t \x01(\tR\x04User\x12W\n" +
|
||||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
"\n" +
|
||||||
0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x54,
|
"Attributes\x18\n" +
|
||||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
" \x03(\v27.xray.app.router.command.RoutingContext.AttributesEntryR\n" +
|
||||||
0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x54,
|
"Attributes\x12,\n" +
|
||||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28,
|
"\x11OutboundGroupTags\x18\v \x03(\tR\x11OutboundGroupTags\x12 \n" +
|
||||||
0x09, 0x52, 0x0c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12,
|
"\vOutboundTag\x18\f \x01(\tR\vOutboundTag\x12\x1a\n" +
|
||||||
0x1a, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28,
|
"\bLocalIPs\x18\r \x03(\fR\bLocalIPs\x12\x1c\n" +
|
||||||
0x09, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x55,
|
"\tLocalPort\x18\x0e \x01(\rR\tLocalPort\x12\x1e\n" +
|
||||||
0x73, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12,
|
"\n" +
|
||||||
0x57, 0x0a, 0x0a, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0a, 0x20,
|
"VlessRoute\x18\x0f \x01(\rR\n" +
|
||||||
0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
"VlessRoute\x1a=\n" +
|
||||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f,
|
"\x0fAttributesEntry\x12\x10\n" +
|
||||||
0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x41, 0x74, 0x74,
|
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||||
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x41, 0x74,
|
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"F\n" +
|
||||||
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x4f, 0x75, 0x74, 0x62,
|
"\x1cSubscribeRoutingStatsRequest\x12&\n" +
|
||||||
0x6f, 0x75, 0x6e, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x18, 0x0b, 0x20,
|
"\x0eFieldSelectors\x18\x01 \x03(\tR\x0eFieldSelectors\"\xb1\x01\n" +
|
||||||
0x03, 0x28, 0x09, 0x52, 0x11, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x47, 0x72, 0x6f,
|
"\x10TestRouteRequest\x12O\n" +
|
||||||
0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75,
|
"\x0eRoutingContext\x18\x01 \x01(\v2'.xray.app.router.command.RoutingContextR\x0eRoutingContext\x12&\n" +
|
||||||
0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x75, 0x74,
|
"\x0eFieldSelectors\x18\x02 \x03(\tR\x0eFieldSelectors\x12$\n" +
|
||||||
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61,
|
"\rPublishResult\x18\x03 \x01(\bR\rPublishResult\"'\n" +
|
||||||
0x6c, 0x49, 0x50, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x4c, 0x6f, 0x63, 0x61,
|
"\x13PrincipleTargetInfo\x12\x10\n" +
|
||||||
0x6c, 0x49, 0x50, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72,
|
"\x03tag\x18\x01 \x03(\tR\x03tag\"&\n" +
|
||||||
0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f,
|
"\fOverrideInfo\x12\x16\n" +
|
||||||
0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
"\x06target\x18\x02 \x01(\tR\x06target\"\xa9\x01\n" +
|
||||||
0x18, 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x75,
|
"\vBalancerMsg\x12A\n" +
|
||||||
0x74, 0x65, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
|
"\boverride\x18\x05 \x01(\v2%.xray.app.router.command.OverrideInfoR\boverride\x12W\n" +
|
||||||
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
"\x10principle_target\x18\x06 \x01(\v2,.xray.app.router.command.PrincipleTargetInfoR\x0fprincipleTarget\"*\n" +
|
||||||
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
"\x16GetBalancerInfoRequest\x12\x10\n" +
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
|
"\x03tag\x18\x01 \x01(\tR\x03tag\"[\n" +
|
||||||
0x01, 0x22, 0x46, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f,
|
"\x17GetBalancerInfoResponse\x12@\n" +
|
||||||
0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
"\bbalancer\x18\x01 \x01(\v2$.xray.app.router.command.BalancerMsgR\bbalancer\"Y\n" +
|
||||||
0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74,
|
"\x1dOverrideBalancerTargetRequest\x12 \n" +
|
||||||
0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64,
|
"\vbalancerTag\x18\x01 \x01(\tR\vbalancerTag\x12\x16\n" +
|
||||||
0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xb1, 0x01, 0x0a, 0x10, 0x54, 0x65,
|
"\x06target\x18\x02 \x01(\tR\x06target\" \n" +
|
||||||
0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4f,
|
"\x1eOverrideBalancerTargetResponse\"n\n" +
|
||||||
0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
|
"\x0eAddRuleRequest\x128\n" +
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
"\x06config\x18\x01 \x01(\v2 .xray.common.serial.TypedMessageR\x06config\x12\"\n" +
|
||||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
"\fshouldAppend\x18\x02 \x01(\bR\fshouldAppend\"\x11\n" +
|
||||||
0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52,
|
"\x0fAddRuleResponse\"-\n" +
|
||||||
0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12,
|
"\x11RemoveRuleRequest\x12\x18\n" +
|
||||||
0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72,
|
"\aruleTag\x18\x01 \x01(\tR\aruleTag\"\x14\n" +
|
||||||
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65,
|
"\x12RemoveRuleResponse\"\x11\n" +
|
||||||
0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69,
|
"\x0fListRuleRequest\":\n" +
|
||||||
0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d,
|
"\fListRuleItem\x12\x10\n" +
|
||||||
0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x27, 0x0a,
|
"\x03tag\x18\x01 \x01(\tR\x03tag\x12\x18\n" +
|
||||||
0x13, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
"\aruleTag\x18\x02 \x01(\tR\aruleTag\"O\n" +
|
||||||
0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28,
|
"\x10ListRuleResponse\x12;\n" +
|
||||||
0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x26, 0x0a, 0x0c, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
"\x05rules\x18\x01 \x03(\v2%.xray.app.router.command.ListRuleItemR\x05rules\"\b\n" +
|
||||||
0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
"\x06Config2\xa2\x06\n" +
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0xa9,
|
"\x0eRoutingService\x12{\n" +
|
||||||
0x01, 0x0a, 0x0b, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x41,
|
"\x15SubscribeRoutingStats\x125.xray.app.router.command.SubscribeRoutingStatsRequest\x1a'.xray.app.router.command.RoutingContext\"\x000\x01\x12a\n" +
|
||||||
0x0a, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
|
"\tTestRoute\x12).xray.app.router.command.TestRouteRequest\x1a'.xray.app.router.command.RoutingContext\"\x00\x12v\n" +
|
||||||
0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
"\x0fGetBalancerInfo\x12/.xray.app.router.command.GetBalancerInfoRequest\x1a0.xray.app.router.command.GetBalancerInfoResponse\"\x00\x12\x8b\x01\n" +
|
||||||
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4f, 0x76, 0x65, 0x72, 0x72,
|
"\x16OverrideBalancerTarget\x126.xray.app.router.command.OverrideBalancerTargetRequest\x1a7.xray.app.router.command.OverrideBalancerTargetResponse\"\x00\x12^\n" +
|
||||||
0x69, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
|
"\aAddRule\x12'.xray.app.router.command.AddRuleRequest\x1a(.xray.app.router.command.AddRuleResponse\"\x00\x12g\n" +
|
||||||
0x65, 0x12, 0x57, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x74,
|
"\n" +
|
||||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72,
|
"RemoveRule\x12*.xray.app.router.command.RemoveRuleRequest\x1a+.xray.app.router.command.RemoveRuleResponse\"\x00\x12a\n" +
|
||||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f,
|
"\bListRule\x12(.xray.app.router.command.ListRuleRequest\x1a).xray.app.router.command.ListRuleResponse\"\x00Bg\n" +
|
||||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x6c, 0x65, 0x54,
|
"\x1bcom.xray.app.router.commandP\x01Z,github.com/xtls/xray-core/app/router/command\xaa\x02\x17Xray.App.Router.Commandb\x06proto3"
|
||||||
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 = file_app_router_command_command_proto_rawDesc
|
file_app_router_command_command_proto_rawDescData []byte
|
||||||
)
|
)
|
||||||
|
|
||||||
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(file_app_router_command_command_proto_rawDescData)
|
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)))
|
||||||
})
|
})
|
||||||
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, 16)
|
var file_app_router_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 19)
|
||||||
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
|
||||||
@@ -1034,36 +1072,42 @@ 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
|
||||||
(*Config)(nil), // 14: xray.app.router.command.Config
|
(*ListRuleRequest)(nil), // 14: xray.app.router.command.ListRuleRequest
|
||||||
nil, // 15: xray.app.router.command.RoutingContext.AttributesEntry
|
(*ListRuleItem)(nil), // 15: xray.app.router.command.ListRuleItem
|
||||||
(net.Network)(0), // 16: xray.common.net.Network
|
(*ListRuleResponse)(nil), // 16: xray.app.router.command.ListRuleResponse
|
||||||
(*serial.TypedMessage)(nil), // 17: xray.common.serial.TypedMessage
|
(*Config)(nil), // 17: xray.app.router.command.Config
|
||||||
|
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{
|
||||||
16, // 0: xray.app.router.command.RoutingContext.Network:type_name -> xray.common.net.Network
|
19, // 0: xray.app.router.command.RoutingContext.Network:type_name -> xray.common.net.Network
|
||||||
15, // 1: xray.app.router.command.RoutingContext.Attributes:type_name -> xray.app.router.command.RoutingContext.AttributesEntry
|
18, // 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
|
||||||
17, // 6: xray.app.router.command.AddRuleRequest.config:type_name -> xray.common.serial.TypedMessage
|
20, // 6: xray.app.router.command.AddRuleRequest.config:type_name -> xray.common.serial.TypedMessage
|
||||||
1, // 7: xray.app.router.command.RoutingService.SubscribeRoutingStats:input_type -> xray.app.router.command.SubscribeRoutingStatsRequest
|
15, // 7: xray.app.router.command.ListRuleResponse.rules:type_name -> xray.app.router.command.ListRuleItem
|
||||||
2, // 8: xray.app.router.command.RoutingService.TestRoute:input_type -> xray.app.router.command.TestRouteRequest
|
1, // 8: xray.app.router.command.RoutingService.SubscribeRoutingStats:input_type -> xray.app.router.command.SubscribeRoutingStatsRequest
|
||||||
6, // 9: xray.app.router.command.RoutingService.GetBalancerInfo:input_type -> xray.app.router.command.GetBalancerInfoRequest
|
2, // 9: xray.app.router.command.RoutingService.TestRoute:input_type -> xray.app.router.command.TestRouteRequest
|
||||||
8, // 10: xray.app.router.command.RoutingService.OverrideBalancerTarget:input_type -> xray.app.router.command.OverrideBalancerTargetRequest
|
6, // 10: xray.app.router.command.RoutingService.GetBalancerInfo:input_type -> xray.app.router.command.GetBalancerInfoRequest
|
||||||
10, // 11: xray.app.router.command.RoutingService.AddRule:input_type -> xray.app.router.command.AddRuleRequest
|
8, // 11: xray.app.router.command.RoutingService.OverrideBalancerTarget:input_type -> xray.app.router.command.OverrideBalancerTargetRequest
|
||||||
12, // 12: xray.app.router.command.RoutingService.RemoveRule:input_type -> xray.app.router.command.RemoveRuleRequest
|
10, // 12: xray.app.router.command.RoutingService.AddRule:input_type -> xray.app.router.command.AddRuleRequest
|
||||||
0, // 13: xray.app.router.command.RoutingService.SubscribeRoutingStats:output_type -> xray.app.router.command.RoutingContext
|
12, // 13: xray.app.router.command.RoutingService.RemoveRule:input_type -> xray.app.router.command.RemoveRuleRequest
|
||||||
0, // 14: xray.app.router.command.RoutingService.TestRoute:output_type -> xray.app.router.command.RoutingContext
|
14, // 14: xray.app.router.command.RoutingService.ListRule:input_type -> xray.app.router.command.ListRuleRequest
|
||||||
7, // 15: xray.app.router.command.RoutingService.GetBalancerInfo:output_type -> xray.app.router.command.GetBalancerInfoResponse
|
0, // 15: xray.app.router.command.RoutingService.SubscribeRoutingStats:output_type -> xray.app.router.command.RoutingContext
|
||||||
9, // 16: xray.app.router.command.RoutingService.OverrideBalancerTarget:output_type -> xray.app.router.command.OverrideBalancerTargetResponse
|
0, // 16: xray.app.router.command.RoutingService.TestRoute:output_type -> xray.app.router.command.RoutingContext
|
||||||
11, // 17: xray.app.router.command.RoutingService.AddRule:output_type -> xray.app.router.command.AddRuleResponse
|
7, // 17: xray.app.router.command.RoutingService.GetBalancerInfo:output_type -> xray.app.router.command.GetBalancerInfoResponse
|
||||||
13, // 18: xray.app.router.command.RoutingService.RemoveRule:output_type -> xray.app.router.command.RemoveRuleResponse
|
9, // 18: xray.app.router.command.RoutingService.OverrideBalancerTarget:output_type -> xray.app.router.command.OverrideBalancerTargetResponse
|
||||||
13, // [13:19] is the sub-list for method output_type
|
11, // 19: xray.app.router.command.RoutingService.AddRule:output_type -> xray.app.router.command.AddRuleResponse
|
||||||
7, // [7:13] is the sub-list for method input_type
|
13, // 20: xray.app.router.command.RoutingService.RemoveRule:output_type -> xray.app.router.command.RemoveRuleResponse
|
||||||
7, // [7:7] is the sub-list for extension type_name
|
16, // 21: xray.app.router.command.RoutingService.ListRule:output_type -> xray.app.router.command.ListRuleResponse
|
||||||
7, // [7:7] is the sub-list for extension extendee
|
15, // [15:22] is the sub-list for method output_type
|
||||||
0, // [0:7] is the sub-list for field type_name
|
8, // [8:15] is the sub-list for method input_type
|
||||||
|
8, // [8:8] is the sub-list for extension type_name
|
||||||
|
8, // [8:8] is the sub-list for extension extendee
|
||||||
|
0, // [0:8] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_router_command_command_proto_init() }
|
func init() { file_app_router_command_command_proto_init() }
|
||||||
@@ -1075,9 +1119,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: file_app_router_command_command_proto_rawDesc,
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_router_command_command_proto_rawDesc), len(file_app_router_command_command_proto_rawDesc)),
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 16,
|
NumMessages: 19,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
@@ -1086,7 +1130,6 @@ 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,6 +104,17 @@ 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) {}
|
||||||
@@ -114,6 +125,8 @@ 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.5.1
|
// - protoc-gen-go-grpc v1.6.0
|
||||||
// - protoc v5.28.2
|
// - protoc v6.33.2
|
||||||
// source: app/router/command/command.proto
|
// source: app/router/command/command.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
@@ -25,6 +25,7 @@ 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.
|
||||||
@@ -37,6 +38,7 @@ 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 {
|
||||||
@@ -116,6 +118,16 @@ 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.
|
||||||
@@ -126,6 +138,7 @@ 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()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,22 +150,25 @@ 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.Errorf(codes.Unimplemented, "method SubscribeRoutingStats not implemented")
|
return status.Error(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.Errorf(codes.Unimplemented, "method TestRoute not implemented")
|
return nil, status.Error(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.Errorf(codes.Unimplemented, "method GetBalancerInfo not implemented")
|
return nil, status.Error(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.Errorf(codes.Unimplemented, "method OverrideBalancerTarget not implemented")
|
return nil, status.Error(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.Errorf(codes.Unimplemented, "method AddRule not implemented")
|
return nil, status.Error(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.Errorf(codes.Unimplemented, "method RemoveRule not implemented")
|
return nil, status.Error(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() {}
|
||||||
@@ -165,7 +181,7 @@ type UnsafeRoutingServiceServer interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RegisterRoutingServiceServer(s grpc.ServiceRegistrar, srv RoutingServiceServer) {
|
func RegisterRoutingServiceServer(s grpc.ServiceRegistrar, srv RoutingServiceServer) {
|
||||||
// If the following call pancis, it indicates UnimplementedRoutingServiceServer was
|
// If the following call panics, 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.
|
||||||
@@ -276,6 +292,24 @@ 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)
|
||||||
@@ -303,6 +337,10 @@ 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{
|
||||||
{
|
{
|
||||||
|
|||||||
+131
-55
@@ -1,7 +1,11 @@
|
|||||||
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"
|
||||||
@@ -47,20 +51,6 @@ var matcherTypeMap = map[Domain_Type]strmatcher.Type{
|
|||||||
Domain_Full: strmatcher.Full,
|
Domain_Full: strmatcher.Full,
|
||||||
}
|
}
|
||||||
|
|
||||||
func domainToMatcher(domain *Domain) (strmatcher.Matcher, error) {
|
|
||||||
matcherType, f := matcherTypeMap[domain.Type]
|
|
||||||
if !f {
|
|
||||||
return nil, errors.New("unsupported domain type", domain.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
type DomainMatcher struct {
|
||||||
matchers strmatcher.IndexMatcher
|
matchers strmatcher.IndexMatcher
|
||||||
}
|
}
|
||||||
@@ -70,11 +60,13 @@ func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
|
|||||||
for _, d := range domains {
|
for _, d := range domains {
|
||||||
matcherType, f := matcherTypeMap[d.Type]
|
matcherType, f := matcherTypeMap[d.Type]
|
||||||
if !f {
|
if !f {
|
||||||
return nil, errors.New("unsupported domain type", d.Type)
|
errors.LogError(context.Background(), "ignore unsupported domain type ", d.Type, " of rule ", d.Value)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
_, err := g.AddPattern(d.Value, matcherType)
|
_, err := g.AddPattern(d.Value, matcherType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
errors.LogErrorInner(context.Background(), err, "ignore domain rule ", d.Type, " ", d.Value)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.Build()
|
g.Build()
|
||||||
@@ -96,61 +88,53 @@ func (m *DomainMatcher) Apply(ctx routing.Context) bool {
|
|||||||
return m.ApplyDomain(domain)
|
return m.ApplyDomain(domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
type MultiGeoIPMatcher struct {
|
type MatcherAsType byte
|
||||||
matchers []*GeoIPMatcher
|
|
||||||
asType string // local, source, target
|
const (
|
||||||
|
MatcherAsType_Local MatcherAsType = iota
|
||||||
|
MatcherAsType_Source
|
||||||
|
MatcherAsType_Target
|
||||||
|
MatcherAsType_VlessRoute // for port
|
||||||
|
)
|
||||||
|
|
||||||
|
type IPMatcher struct {
|
||||||
|
matcher GeoIPMatcher
|
||||||
|
asType MatcherAsType
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMultiGeoIPMatcher(geoips []*GeoIP, asType string) (*MultiGeoIPMatcher, error) {
|
func NewIPMatcher(geoips []*GeoIP, asType MatcherAsType) (*IPMatcher, error) {
|
||||||
var matchers []*GeoIPMatcher
|
matcher, err := BuildOptimizedGeoIPMatcher(geoips...)
|
||||||
for _, geoip := range geoips {
|
if err != nil {
|
||||||
matcher, err := GlobalGeoIPContainer.Add(geoip)
|
return nil, err
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
matchers = append(matchers, matcher)
|
|
||||||
}
|
}
|
||||||
|
return &IPMatcher{matcher: matcher, asType: asType}, nil
|
||||||
matcher := &MultiGeoIPMatcher{
|
|
||||||
matchers: matchers,
|
|
||||||
asType: asType,
|
|
||||||
}
|
|
||||||
|
|
||||||
return matcher, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply implements Condition.
|
// Apply implements Condition.
|
||||||
func (m *MultiGeoIPMatcher) Apply(ctx routing.Context) bool {
|
func (m *IPMatcher) Apply(ctx routing.Context) bool {
|
||||||
var ips []net.IP
|
var ips []net.IP
|
||||||
|
|
||||||
switch m.asType {
|
switch m.asType {
|
||||||
case "local":
|
case MatcherAsType_Local:
|
||||||
ips = ctx.GetLocalIPs()
|
ips = ctx.GetLocalIPs()
|
||||||
case "source":
|
case MatcherAsType_Source:
|
||||||
ips = ctx.GetSourceIPs()
|
ips = ctx.GetSourceIPs()
|
||||||
case "target":
|
case MatcherAsType_Target:
|
||||||
ips = ctx.GetTargetIPs()
|
ips = ctx.GetTargetIPs()
|
||||||
default:
|
default:
|
||||||
panic("unreachable, asType should be local or source or target")
|
panic("unk asType")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ip := range ips {
|
return m.matcher.AnyMatch(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 string // local, source, target
|
asType MatcherAsType
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 string) *PortMatcher {
|
func NewPortMatcher(list *net.PortList, asType MatcherAsType) *PortMatcher {
|
||||||
return &PortMatcher{
|
return &PortMatcher{
|
||||||
port: net.PortListFromProto(list),
|
port: net.PortListFromProto(list),
|
||||||
asType: asType,
|
asType: asType,
|
||||||
@@ -160,18 +144,17 @@ func NewPortMatcher(list *net.PortList, asType string) *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 "local":
|
case MatcherAsType_Local:
|
||||||
return v.port.Contains(ctx.GetLocalPort())
|
return v.port.Contains(ctx.GetLocalPort())
|
||||||
case "source":
|
case MatcherAsType_Source:
|
||||||
return v.port.Contains(ctx.GetSourcePort())
|
return v.port.Contains(ctx.GetSourcePort())
|
||||||
case "target":
|
case MatcherAsType_Target:
|
||||||
return v.port.Contains(ctx.GetTargetPort())
|
return v.port.Contains(ctx.GetTargetPort())
|
||||||
case "vlessRoute":
|
case MatcherAsType_VlessRoute:
|
||||||
return v.port.Contains(ctx.GetVlessRoute())
|
return v.port.Contains(ctx.GetVlessRoute())
|
||||||
default:
|
default:
|
||||||
panic("unreachable, asType should be local or source or target")
|
panic("unk asType")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type NetworkMatcher struct {
|
type NetworkMatcher struct {
|
||||||
@@ -325,3 +308,96 @@ 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 := ctx.GetSourcePort().String()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
src, err := net.ParseDestination(strings.Join([]string{network, srcIP, srcPort}, ":"))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
pid, name, absPath, err := net.FindProcess(src)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|||||||
+911
-94
File diff suppressed because it is too large
Load Diff
@@ -35,33 +35,6 @@ func getAssetPath(file string) (string, error) {
|
|||||||
return path, nil
|
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) {
|
func TestGeoIPMatcher(t *testing.T) {
|
||||||
cidrList := []*router.CIDR{
|
cidrList := []*router.CIDR{
|
||||||
{Ip: []byte{0, 0, 0, 0}, Prefix: 8},
|
{Ip: []byte{0, 0, 0, 0}, Prefix: 8},
|
||||||
@@ -80,8 +53,10 @@ func TestGeoIPMatcher(t *testing.T) {
|
|||||||
{Ip: []byte{91, 108, 4, 0}, Prefix: 16},
|
{Ip: []byte{91, 108, 4, 0}, Prefix: 16},
|
||||||
}
|
}
|
||||||
|
|
||||||
matcher := &router.GeoIPMatcher{}
|
matcher, err := router.BuildOptimizedGeoIPMatcher(&router.GeoIP{
|
||||||
common.Must(matcher.Init(cidrList))
|
Cidr: cidrList,
|
||||||
|
})
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Input string
|
Input string
|
||||||
@@ -140,8 +115,10 @@ func TestGeoIPMatcherRegression(t *testing.T) {
|
|||||||
{Ip: []byte{98, 108, 20, 0}, Prefix: 23},
|
{Ip: []byte{98, 108, 20, 0}, Prefix: 23},
|
||||||
}
|
}
|
||||||
|
|
||||||
matcher := &router.GeoIPMatcher{}
|
matcher, err := router.BuildOptimizedGeoIPMatcher(&router.GeoIP{
|
||||||
common.Must(matcher.Init(cidrList))
|
Cidr: cidrList,
|
||||||
|
})
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Input string
|
Input string
|
||||||
@@ -171,9 +148,11 @@ func TestGeoIPReverseMatcher(t *testing.T) {
|
|||||||
{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
|
{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
|
||||||
{Ip: []byte{91, 108, 4, 0}, Prefix: 16},
|
{Ip: []byte{91, 108, 4, 0}, Prefix: 16},
|
||||||
}
|
}
|
||||||
matcher := &router.GeoIPMatcher{}
|
matcher, err := router.BuildOptimizedGeoIPMatcher(&router.GeoIP{
|
||||||
matcher.SetReverseMatch(true) // Reverse match
|
Cidr: cidrList,
|
||||||
common.Must(matcher.Init(cidrList))
|
})
|
||||||
|
common.Must(err)
|
||||||
|
matcher.SetReverse(true) // Reverse match
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Input string
|
Input string
|
||||||
@@ -206,8 +185,10 @@ func TestGeoIPMatcher4CN(t *testing.T) {
|
|||||||
ips, err := loadGeoIP("CN")
|
ips, err := loadGeoIP("CN")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
matcher := &router.GeoIPMatcher{}
|
matcher, err := router.BuildOptimizedGeoIPMatcher(&router.GeoIP{
|
||||||
common.Must(matcher.Init(ips))
|
Cidr: ips,
|
||||||
|
})
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
if matcher.Match([]byte{8, 8, 8, 8}) {
|
if matcher.Match([]byte{8, 8, 8, 8}) {
|
||||||
t.Error("expect CN geoip doesn't contain 8.8.8.8, but actually does")
|
t.Error("expect CN geoip doesn't contain 8.8.8.8, but actually does")
|
||||||
@@ -218,8 +199,10 @@ func TestGeoIPMatcher6US(t *testing.T) {
|
|||||||
ips, err := loadGeoIP("US")
|
ips, err := loadGeoIP("US")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
matcher := &router.GeoIPMatcher{}
|
matcher, err := router.BuildOptimizedGeoIPMatcher(&router.GeoIP{
|
||||||
common.Must(matcher.Init(ips))
|
Cidr: ips,
|
||||||
|
})
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
if !matcher.Match(net.ParseAddress("2001:4860:4860::8888").IP()) {
|
if !matcher.Match(net.ParseAddress("2001:4860:4860::8888").IP()) {
|
||||||
t.Error("expect US geoip contain 2001:4860:4860::8888, but actually not")
|
t.Error("expect US geoip contain 2001:4860:4860::8888, but actually not")
|
||||||
@@ -254,8 +237,10 @@ func BenchmarkGeoIPMatcher4CN(b *testing.B) {
|
|||||||
ips, err := loadGeoIP("CN")
|
ips, err := loadGeoIP("CN")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
matcher := &router.GeoIPMatcher{}
|
matcher, err := router.BuildOptimizedGeoIPMatcher(&router.GeoIP{
|
||||||
common.Must(matcher.Init(ips))
|
Cidr: ips,
|
||||||
|
})
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
||||||
@@ -268,8 +253,10 @@ func BenchmarkGeoIPMatcher6US(b *testing.B) {
|
|||||||
ips, err := loadGeoIP("US")
|
ips, err := loadGeoIP("US")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
matcher := &router.GeoIPMatcher{}
|
matcher, err := router.BuildOptimizedGeoIPMatcher(&router.GeoIP{
|
||||||
common.Must(matcher.Init(ips))
|
Cidr: ips,
|
||||||
|
})
|
||||||
|
common.Must(err)
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
||||||
|
|||||||
@@ -447,7 +447,7 @@ func BenchmarkMultiGeoIPMatcher(b *testing.B) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
matcher, err := NewMultiGeoIPMatcher(geoips, "target")
|
matcher, err := NewIPMatcher(geoips, MatcherAsType_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)})
|
||||||
|
|||||||
+67
-63
@@ -32,6 +32,71 @@ 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.InboundTag) > 0 {
|
||||||
|
conds.Add(NewInboundTagMatcher(rr.InboundTag))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rr.Networks) > 0 {
|
||||||
|
conds.Add(NewNetworkMatcher(rr.Networks))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rr.Protocol) > 0 {
|
||||||
|
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 {
|
||||||
|
configuredKeys := make(map[string]*regexp.Regexp)
|
||||||
|
for key, value := range rr.Attributes {
|
||||||
|
configuredKeys[strings.ToLower(key)] = regexp.MustCompile(value)
|
||||||
|
}
|
||||||
|
conds.Add(&AttributeMatcher{configuredKeys})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rr.Geoip) > 0 {
|
||||||
|
cond, err := NewIPMatcher(rr.Geoip, MatcherAsType_Target)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conds.Add(cond)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rr.SourceGeoip) > 0 {
|
||||||
|
cond, err := NewIPMatcher(rr.SourceGeoip, MatcherAsType_Source)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conds.Add(cond)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rr.LocalGeoip) > 0 {
|
||||||
|
cond, err := NewIPMatcher(rr.LocalGeoip, 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 {
|
if len(rr.Domain) > 0 {
|
||||||
matcher, err := NewMphMatcherGroup(rr.Domain)
|
matcher, err := NewMphMatcherGroup(rr.Domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -41,69 +106,8 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
|||||||
conds.Add(matcher)
|
conds.Add(matcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rr.UserEmail) > 0 {
|
if len(rr.Process) > 0 {
|
||||||
conds.Add(NewUserMatcher(rr.UserEmail))
|
conds.Add(NewProcessNameMatcher(rr.Process))
|
||||||
}
|
|
||||||
|
|
||||||
if rr.VlessRouteList != nil {
|
|
||||||
conds.Add(NewPortMatcher(rr.VlessRouteList, "vlessRoute"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rr.InboundTag) > 0 {
|
|
||||||
conds.Add(NewInboundTagMatcher(rr.InboundTag))
|
|
||||||
}
|
|
||||||
|
|
||||||
if rr.PortList != nil {
|
|
||||||
conds.Add(NewPortMatcher(rr.PortList, "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 {
|
|
||||||
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 {
|
|
||||||
conds.Add(NewProtocolMatcher(rr.Protocol))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rr.Attributes) > 0 {
|
|
||||||
configuredKeys := make(map[string]*regexp.Regexp)
|
|
||||||
for key, value := range rr.Attributes {
|
|
||||||
configuredKeys[strings.ToLower(key)] = regexp.MustCompile(value)
|
|
||||||
}
|
|
||||||
conds.Add(&AttributeMatcher{configuredKeys})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if conds.Len() == 0 {
|
if conds.Len() == 0 {
|
||||||
|
|||||||
+71
-66
@@ -84,8 +84,6 @@ type Config_DomainStrategy int32
|
|||||||
const (
|
const (
|
||||||
// Use domain as is.
|
// Use domain as is.
|
||||||
Config_AsIs Config_DomainStrategy = 0
|
Config_AsIs Config_DomainStrategy = 0
|
||||||
// Always resolve IP for domains.
|
|
||||||
Config_UseIp Config_DomainStrategy = 1
|
|
||||||
// Resolve to IP if the domain doesn't match any rules.
|
// Resolve to IP if the domain doesn't match any rules.
|
||||||
Config_IpIfNonMatch Config_DomainStrategy = 2
|
Config_IpIfNonMatch Config_DomainStrategy = 2
|
||||||
// Resolve to IP if any rule requires IP matching.
|
// Resolve to IP if any rule requires IP matching.
|
||||||
@@ -96,13 +94,11 @@ const (
|
|||||||
var (
|
var (
|
||||||
Config_DomainStrategy_name = map[int32]string{
|
Config_DomainStrategy_name = map[int32]string{
|
||||||
0: "AsIs",
|
0: "AsIs",
|
||||||
1: "UseIp",
|
|
||||||
2: "IpIfNonMatch",
|
2: "IpIfNonMatch",
|
||||||
3: "IpOnDemand",
|
3: "IpOnDemand",
|
||||||
}
|
}
|
||||||
Config_DomainStrategy_value = map[string]int32{
|
Config_DomainStrategy_value = map[string]int32{
|
||||||
"AsIs": 0,
|
"AsIs": 0,
|
||||||
"UseIp": 1,
|
|
||||||
"IpIfNonMatch": 2,
|
"IpIfNonMatch": 2,
|
||||||
"IpOnDemand": 3,
|
"IpOnDemand": 3,
|
||||||
}
|
}
|
||||||
@@ -494,6 +490,7 @@ type RoutingRule struct {
|
|||||||
LocalGeoip []*GeoIP `protobuf:"bytes,17,rep,name=local_geoip,json=localGeoip,proto3" json:"local_geoip,omitempty"`
|
LocalGeoip []*GeoIP `protobuf:"bytes,17,rep,name=local_geoip,json=localGeoip,proto3" json:"local_geoip,omitempty"`
|
||||||
LocalPortList *net.PortList `protobuf:"bytes,18,opt,name=local_port_list,json=localPortList,proto3" json:"local_port_list,omitempty"`
|
LocalPortList *net.PortList `protobuf:"bytes,18,opt,name=local_port_list,json=localPortList,proto3" json:"local_port_list,omitempty"`
|
||||||
VlessRouteList *net.PortList `protobuf:"bytes,20,opt,name=vless_route_list,json=vlessRouteList,proto3" json:"vless_route_list,omitempty"`
|
VlessRouteList *net.PortList `protobuf:"bytes,20,opt,name=vless_route_list,json=vlessRouteList,proto3" json:"vless_route_list,omitempty"`
|
||||||
|
Process []string `protobuf:"bytes,21,rep,name=process,proto3" json:"process,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RoutingRule) Reset() {
|
func (x *RoutingRule) Reset() {
|
||||||
@@ -645,6 +642,13 @@ func (x *RoutingRule) GetVlessRouteList() *net.PortList {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *RoutingRule) GetProcess() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Process
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type isRoutingRule_TargetTag interface {
|
type isRoutingRule_TargetTag interface {
|
||||||
isRoutingRule_TargetTag()
|
isRoutingRule_TargetTag()
|
||||||
}
|
}
|
||||||
@@ -1085,7 +1089,7 @@ var file_app_router_config_proto_rawDesc = []byte{
|
|||||||
0x6f, 0x53, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x05, 0x65, 0x6e, 0x74,
|
0x6f, 0x53, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x05, 0x65, 0x6e, 0x74,
|
||||||
0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x53, 0x69,
|
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x53, 0x69,
|
||||||
0x74, 0x65, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xe8, 0x06, 0x0a, 0x0b, 0x52, 0x6f,
|
0x74, 0x65, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x82, 0x07, 0x0a, 0x0b, 0x52, 0x6f,
|
||||||
0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x03, 0x74, 0x61, 0x67,
|
0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x03, 0x74, 0x61, 0x67,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x25, 0x0a,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x25, 0x0a,
|
||||||
0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x0c,
|
0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x0c,
|
||||||
@@ -1135,67 +1139,68 @@ var file_app_router_config_proto_rawDesc = []byte{
|
|||||||
0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78,
|
0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50,
|
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50,
|
||||||
0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x6f,
|
0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x6f,
|
||||||
0x75, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69,
|
0x75, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x63, 0x65,
|
||||||
0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
|
0x73, 0x73, 0x18, 0x15, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73,
|
||||||
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
|
0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45,
|
||||||
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
|
0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
|
||||||
0x5f, 0x74, 0x61, 0x67, 0x22, 0xdc, 0x01, 0x0a, 0x0d, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69,
|
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
|
||||||
0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20,
|
0x42, 0x0c, 0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x22, 0xdc,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x62,
|
0x01, 0x0a, 0x0d, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65,
|
||||||
0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20,
|
0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74,
|
||||||
0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x65, 0x6c,
|
0x61, 0x67, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73,
|
||||||
0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
|
0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x6f,
|
||||||
0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
|
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12,
|
||||||
0x79, 0x12, 0x4d, 0x0a, 0x11, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x5f, 0x73, 0x65,
|
0x1a, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78,
|
0x09, 0x52, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4d, 0x0a, 0x11, 0x73,
|
||||||
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61,
|
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
||||||
0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x10,
|
0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||||
0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65,
|
||||||
0x12, 0x21, 0x0a, 0x0c, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x61, 0x67,
|
0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x10, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
|
0x67, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x61,
|
||||||
0x54, 0x61, 0x67, 0x22, 0x54, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x57,
|
0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x18,
|
0x52, 0x0b, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x54, 0x61, 0x67, 0x22, 0x54, 0x0a,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x12, 0x14, 0x0a,
|
0x0e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12,
|
||||||
0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61,
|
0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||||
0x74, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01,
|
0x06, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68,
|
||||||
0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xc0, 0x01, 0x0a, 0x17, 0x53, 0x74,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x14, 0x0a,
|
||||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x4c, 0x6f, 0x61, 0x64, 0x43,
|
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x76, 0x61,
|
||||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x05, 0x63, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02,
|
0x6c, 0x75, 0x65, 0x22, 0xc0, 0x01, 0x0a, 0x17, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
0x4c, 0x65, 0x61, 0x73, 0x74, 0x4c, 0x6f, 0x61, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
||||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x57,
|
0x35, 0x0a, 0x05, 0x63, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f,
|
||||||
0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x05, 0x63, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1c, 0x0a, 0x09,
|
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
||||||
0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52,
|
0x2e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52,
|
||||||
0x09, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78,
|
0x05, 0x63, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69,
|
||||||
0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x65, 0x78,
|
0x6e, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x09, 0x62, 0x61, 0x73, 0x65, 0x6c,
|
||||||
0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x78, 0x52, 0x54, 0x54,
|
0x69, 0x6e, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64,
|
||||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6d, 0x61, 0x78, 0x52, 0x54, 0x54, 0x12, 0x1c,
|
0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64,
|
||||||
0x0a, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28,
|
0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x78, 0x52, 0x54, 0x54, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03,
|
||||||
0x02, 0x52, 0x09, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x9b, 0x02, 0x0a,
|
0x52, 0x06, 0x6d, 0x61, 0x78, 0x52, 0x54, 0x54, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x6f, 0x6c, 0x65,
|
||||||
0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4f, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69,
|
0x72, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x74, 0x6f, 0x6c,
|
||||||
0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
|
0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x90, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||||
0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
0x67, 0x12, 0x4f, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61,
|
||||||
0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61,
|
||||||
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e,
|
||||||
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x30, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65,
|
0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||||
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67,
|
0x67, 0x79, 0x12, 0x30, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
|
||||||
0x52, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x45, 0x0a, 0x0e, 0x62, 0x61,
|
0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||||
0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x03,
|
0x65, 0x72, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x04,
|
||||||
0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
|
0x72, 0x75, 0x6c, 0x65, 0x12, 0x45, 0x0a, 0x0e, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e,
|
||||||
0x75, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75,
|
0x67, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x78,
|
||||||
0x6c, 0x65, 0x52, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c,
|
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x42,
|
||||||
0x65, 0x22, 0x47, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74,
|
0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x62, 0x61,
|
||||||
0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49, 0x73, 0x10, 0x00, 0x12, 0x09, 0x0a,
|
0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x22, 0x3c, 0x0a, 0x0e, 0x44,
|
||||||
0x05, 0x55, 0x73, 0x65, 0x49, 0x70, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x70, 0x49, 0x66,
|
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a,
|
||||||
0x4e, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x70,
|
0x04, 0x41, 0x73, 0x49, 0x73, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x70, 0x49, 0x66, 0x4e,
|
||||||
0x4f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x10, 0x03, 0x42, 0x4f, 0x0a, 0x13, 0x63, 0x6f,
|
0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x70, 0x4f,
|
||||||
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x10, 0x03, 0x42, 0x4f, 0x0a, 0x13, 0x63, 0x6f, 0x6d,
|
||||||
0x72, 0x50, 0x01, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
||||||
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61,
|
0x50, 0x01, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
|
||||||
0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0xaa, 0x02, 0x0f, 0x58, 0x72, 0x61, 0x79,
|
0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
|
||||||
0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0xaa, 0x02, 0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x74, 0x6f, 0x33,
|
0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ message RoutingRule {
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
message BalancingRule {
|
message BalancingRule {
|
||||||
@@ -147,8 +148,8 @@ message Config {
|
|||||||
// Use domain as is.
|
// Use domain as is.
|
||||||
AsIs = 0;
|
AsIs = 0;
|
||||||
|
|
||||||
// Always resolve IP for domains.
|
// [Deprecated] Always resolve IP for domains.
|
||||||
UseIp = 1;
|
// 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;
|
||||||
|
|||||||
+16
-1
@@ -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"
|
||||||
@@ -181,6 +181,21 @@ func (r *Router) RemoveRule(tag string) error {
|
|||||||
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,
|
||||||
|
|||||||
@@ -80,6 +80,12 @@ 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) 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)
|
matcher, err := strmatcher.Substr.New(request.Pattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+245
-217
@@ -1,8 +1,8 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.35.1
|
// protoc-gen-go v1.36.8
|
||||||
// protoc v5.28.2
|
// protoc v6.32.0
|
||||||
// source: app/stats/command/command.proto
|
// source: command.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ 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 (
|
||||||
@@ -21,19 +22,18 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type GetStatsRequest struct {
|
type GetStatsRequest struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
// Name of the stat counter.
|
// Name of the stat counter.
|
||||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
// Whether or not to reset the counter to fetching its value.
|
// Whether or not to reset the counter to fetching its value.
|
||||||
Reset_ bool `protobuf:"varint,2,opt,name=reset,proto3" json:"reset,omitempty"`
|
Reset_ bool `protobuf:"varint,2,opt,name=reset,proto3" json:"reset,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetStatsRequest) Reset() {
|
func (x *GetStatsRequest) Reset() {
|
||||||
*x = GetStatsRequest{}
|
*x = GetStatsRequest{}
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[0]
|
mi := &file_command_proto_msgTypes[0]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ func (x *GetStatsRequest) String() string {
|
|||||||
func (*GetStatsRequest) ProtoMessage() {}
|
func (*GetStatsRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *GetStatsRequest) ProtoReflect() protoreflect.Message {
|
func (x *GetStatsRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[0]
|
mi := &file_command_proto_msgTypes[0]
|
||||||
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 {
|
||||||
@@ -58,7 +58,7 @@ func (x *GetStatsRequest) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use GetStatsRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use GetStatsRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*GetStatsRequest) Descriptor() ([]byte, []int) {
|
func (*GetStatsRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_app_stats_command_command_proto_rawDescGZIP(), []int{0}
|
return file_command_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetStatsRequest) GetName() string {
|
func (x *GetStatsRequest) GetName() string {
|
||||||
@@ -76,17 +76,16 @@ func (x *GetStatsRequest) GetReset_() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Stat struct {
|
type Stat struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
|
Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
|
||||||
Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Stat) Reset() {
|
func (x *Stat) Reset() {
|
||||||
*x = Stat{}
|
*x = Stat{}
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[1]
|
mi := &file_command_proto_msgTypes[1]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -98,7 +97,7 @@ func (x *Stat) String() string {
|
|||||||
func (*Stat) ProtoMessage() {}
|
func (*Stat) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Stat) ProtoReflect() protoreflect.Message {
|
func (x *Stat) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[1]
|
mi := &file_command_proto_msgTypes[1]
|
||||||
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 {
|
||||||
@@ -111,7 +110,7 @@ func (x *Stat) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Stat.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Stat.ProtoReflect.Descriptor instead.
|
||||||
func (*Stat) Descriptor() ([]byte, []int) {
|
func (*Stat) Descriptor() ([]byte, []int) {
|
||||||
return file_app_stats_command_command_proto_rawDescGZIP(), []int{1}
|
return file_command_proto_rawDescGZIP(), []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Stat) GetName() string {
|
func (x *Stat) GetName() string {
|
||||||
@@ -129,16 +128,15 @@ func (x *Stat) GetValue() int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetStatsResponse struct {
|
type GetStatsResponse struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
Stat *Stat `protobuf:"bytes,1,opt,name=stat,proto3" json:"stat,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
Stat *Stat `protobuf:"bytes,1,opt,name=stat,proto3" json:"stat,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetStatsResponse) Reset() {
|
func (x *GetStatsResponse) Reset() {
|
||||||
*x = GetStatsResponse{}
|
*x = GetStatsResponse{}
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[2]
|
mi := &file_command_proto_msgTypes[2]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -150,7 +148,7 @@ func (x *GetStatsResponse) String() string {
|
|||||||
func (*GetStatsResponse) ProtoMessage() {}
|
func (*GetStatsResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *GetStatsResponse) ProtoReflect() protoreflect.Message {
|
func (x *GetStatsResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[2]
|
mi := &file_command_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 {
|
||||||
@@ -163,7 +161,7 @@ func (x *GetStatsResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use GetStatsResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use GetStatsResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*GetStatsResponse) Descriptor() ([]byte, []int) {
|
func (*GetStatsResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_app_stats_command_command_proto_rawDescGZIP(), []int{2}
|
return file_command_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetStatsResponse) GetStat() *Stat {
|
func (x *GetStatsResponse) GetStat() *Stat {
|
||||||
@@ -174,17 +172,16 @@ func (x *GetStatsResponse) GetStat() *Stat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type QueryStatsRequest struct {
|
type QueryStatsRequest struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
Pattern string `protobuf:"bytes,1,opt,name=pattern,proto3" json:"pattern,omitempty"`
|
||||||
|
Reset_ bool `protobuf:"varint,2,opt,name=reset,proto3" json:"reset,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
Pattern string `protobuf:"bytes,1,opt,name=pattern,proto3" json:"pattern,omitempty"`
|
|
||||||
Reset_ bool `protobuf:"varint,2,opt,name=reset,proto3" json:"reset,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *QueryStatsRequest) Reset() {
|
func (x *QueryStatsRequest) Reset() {
|
||||||
*x = QueryStatsRequest{}
|
*x = QueryStatsRequest{}
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[3]
|
mi := &file_command_proto_msgTypes[3]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -196,7 +193,7 @@ func (x *QueryStatsRequest) String() string {
|
|||||||
func (*QueryStatsRequest) ProtoMessage() {}
|
func (*QueryStatsRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *QueryStatsRequest) ProtoReflect() protoreflect.Message {
|
func (x *QueryStatsRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[3]
|
mi := &file_command_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 {
|
||||||
@@ -209,7 +206,7 @@ func (x *QueryStatsRequest) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use QueryStatsRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use QueryStatsRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*QueryStatsRequest) Descriptor() ([]byte, []int) {
|
func (*QueryStatsRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_app_stats_command_command_proto_rawDescGZIP(), []int{3}
|
return file_command_proto_rawDescGZIP(), []int{3}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *QueryStatsRequest) GetPattern() string {
|
func (x *QueryStatsRequest) GetPattern() string {
|
||||||
@@ -227,16 +224,15 @@ func (x *QueryStatsRequest) GetReset_() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type QueryStatsResponse struct {
|
type QueryStatsResponse struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
Stat []*Stat `protobuf:"bytes,1,rep,name=stat,proto3" json:"stat,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
Stat []*Stat `protobuf:"bytes,1,rep,name=stat,proto3" json:"stat,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *QueryStatsResponse) Reset() {
|
func (x *QueryStatsResponse) Reset() {
|
||||||
*x = QueryStatsResponse{}
|
*x = QueryStatsResponse{}
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[4]
|
mi := &file_command_proto_msgTypes[4]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -248,7 +244,7 @@ func (x *QueryStatsResponse) String() string {
|
|||||||
func (*QueryStatsResponse) ProtoMessage() {}
|
func (*QueryStatsResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *QueryStatsResponse) ProtoReflect() protoreflect.Message {
|
func (x *QueryStatsResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[4]
|
mi := &file_command_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 {
|
||||||
@@ -261,7 +257,7 @@ func (x *QueryStatsResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use QueryStatsResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use QueryStatsResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*QueryStatsResponse) Descriptor() ([]byte, []int) {
|
func (*QueryStatsResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_app_stats_command_command_proto_rawDescGZIP(), []int{4}
|
return file_command_proto_rawDescGZIP(), []int{4}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *QueryStatsResponse) GetStat() []*Stat {
|
func (x *QueryStatsResponse) GetStat() []*Stat {
|
||||||
@@ -272,14 +268,14 @@ func (x *QueryStatsResponse) GetStat() []*Stat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SysStatsRequest struct {
|
type SysStatsRequest struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SysStatsRequest) Reset() {
|
func (x *SysStatsRequest) Reset() {
|
||||||
*x = SysStatsRequest{}
|
*x = SysStatsRequest{}
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[5]
|
mi := &file_command_proto_msgTypes[5]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -291,7 +287,7 @@ func (x *SysStatsRequest) String() string {
|
|||||||
func (*SysStatsRequest) ProtoMessage() {}
|
func (*SysStatsRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *SysStatsRequest) ProtoReflect() protoreflect.Message {
|
func (x *SysStatsRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[5]
|
mi := &file_command_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 {
|
||||||
@@ -304,29 +300,28 @@ func (x *SysStatsRequest) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use SysStatsRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use SysStatsRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*SysStatsRequest) Descriptor() ([]byte, []int) {
|
func (*SysStatsRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_app_stats_command_command_proto_rawDescGZIP(), []int{5}
|
return file_command_proto_rawDescGZIP(), []int{5}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SysStatsResponse struct {
|
type SysStatsResponse struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
NumGoroutine uint32 `protobuf:"varint,1,opt,name=NumGoroutine,proto3" json:"NumGoroutine,omitempty"`
|
||||||
|
NumGC uint32 `protobuf:"varint,2,opt,name=NumGC,proto3" json:"NumGC,omitempty"`
|
||||||
|
Alloc uint64 `protobuf:"varint,3,opt,name=Alloc,proto3" json:"Alloc,omitempty"`
|
||||||
|
TotalAlloc uint64 `protobuf:"varint,4,opt,name=TotalAlloc,proto3" json:"TotalAlloc,omitempty"`
|
||||||
|
Sys uint64 `protobuf:"varint,5,opt,name=Sys,proto3" json:"Sys,omitempty"`
|
||||||
|
Mallocs uint64 `protobuf:"varint,6,opt,name=Mallocs,proto3" json:"Mallocs,omitempty"`
|
||||||
|
Frees uint64 `protobuf:"varint,7,opt,name=Frees,proto3" json:"Frees,omitempty"`
|
||||||
|
LiveObjects uint64 `protobuf:"varint,8,opt,name=LiveObjects,proto3" json:"LiveObjects,omitempty"`
|
||||||
|
PauseTotalNs uint64 `protobuf:"varint,9,opt,name=PauseTotalNs,proto3" json:"PauseTotalNs,omitempty"`
|
||||||
|
Uptime uint32 `protobuf:"varint,10,opt,name=Uptime,proto3" json:"Uptime,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
NumGoroutine uint32 `protobuf:"varint,1,opt,name=NumGoroutine,proto3" json:"NumGoroutine,omitempty"`
|
|
||||||
NumGC uint32 `protobuf:"varint,2,opt,name=NumGC,proto3" json:"NumGC,omitempty"`
|
|
||||||
Alloc uint64 `protobuf:"varint,3,opt,name=Alloc,proto3" json:"Alloc,omitempty"`
|
|
||||||
TotalAlloc uint64 `protobuf:"varint,4,opt,name=TotalAlloc,proto3" json:"TotalAlloc,omitempty"`
|
|
||||||
Sys uint64 `protobuf:"varint,5,opt,name=Sys,proto3" json:"Sys,omitempty"`
|
|
||||||
Mallocs uint64 `protobuf:"varint,6,opt,name=Mallocs,proto3" json:"Mallocs,omitempty"`
|
|
||||||
Frees uint64 `protobuf:"varint,7,opt,name=Frees,proto3" json:"Frees,omitempty"`
|
|
||||||
LiveObjects uint64 `protobuf:"varint,8,opt,name=LiveObjects,proto3" json:"LiveObjects,omitempty"`
|
|
||||||
PauseTotalNs uint64 `protobuf:"varint,9,opt,name=PauseTotalNs,proto3" json:"PauseTotalNs,omitempty"`
|
|
||||||
Uptime uint32 `protobuf:"varint,10,opt,name=Uptime,proto3" json:"Uptime,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SysStatsResponse) Reset() {
|
func (x *SysStatsResponse) Reset() {
|
||||||
*x = SysStatsResponse{}
|
*x = SysStatsResponse{}
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[6]
|
mi := &file_command_proto_msgTypes[6]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -338,7 +333,7 @@ func (x *SysStatsResponse) String() string {
|
|||||||
func (*SysStatsResponse) ProtoMessage() {}
|
func (*SysStatsResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *SysStatsResponse) ProtoReflect() protoreflect.Message {
|
func (x *SysStatsResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[6]
|
mi := &file_command_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 {
|
||||||
@@ -351,7 +346,7 @@ func (x *SysStatsResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use SysStatsResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use SysStatsResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*SysStatsResponse) Descriptor() ([]byte, []int) {
|
func (*SysStatsResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_app_stats_command_command_proto_rawDescGZIP(), []int{6}
|
return file_command_proto_rawDescGZIP(), []int{6}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SysStatsResponse) GetNumGoroutine() uint32 {
|
func (x *SysStatsResponse) GetNumGoroutine() uint32 {
|
||||||
@@ -425,17 +420,16 @@ func (x *SysStatsResponse) GetUptime() uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetStatsOnlineIpListResponse struct {
|
type GetStatsOnlineIpListResponse struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
|
Ips map[string]int64 `protobuf:"bytes,2,rep,name=ips,proto3" json:"ips,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
|
||||||
Ips map[string]int64 `protobuf:"bytes,2,rep,name=ips,proto3" json:"ips,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetStatsOnlineIpListResponse) Reset() {
|
func (x *GetStatsOnlineIpListResponse) Reset() {
|
||||||
*x = GetStatsOnlineIpListResponse{}
|
*x = GetStatsOnlineIpListResponse{}
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[7]
|
mi := &file_command_proto_msgTypes[7]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -447,7 +441,7 @@ func (x *GetStatsOnlineIpListResponse) String() string {
|
|||||||
func (*GetStatsOnlineIpListResponse) ProtoMessage() {}
|
func (*GetStatsOnlineIpListResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *GetStatsOnlineIpListResponse) ProtoReflect() protoreflect.Message {
|
func (x *GetStatsOnlineIpListResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[7]
|
mi := &file_command_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 {
|
||||||
@@ -460,7 +454,7 @@ func (x *GetStatsOnlineIpListResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use GetStatsOnlineIpListResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use GetStatsOnlineIpListResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*GetStatsOnlineIpListResponse) Descriptor() ([]byte, []int) {
|
func (*GetStatsOnlineIpListResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_app_stats_command_command_proto_rawDescGZIP(), []int{7}
|
return file_command_proto_rawDescGZIP(), []int{7}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetStatsOnlineIpListResponse) GetName() string {
|
func (x *GetStatsOnlineIpListResponse) GetName() string {
|
||||||
@@ -477,15 +471,95 @@ func (x *GetStatsOnlineIpListResponse) GetIps() map[string]int64 {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type GetAllOnlineUsersRequest struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetAllOnlineUsersRequest) Reset() {
|
||||||
|
*x = GetAllOnlineUsersRequest{}
|
||||||
|
mi := &file_command_proto_msgTypes[8]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetAllOnlineUsersRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetAllOnlineUsersRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetAllOnlineUsersRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_command_proto_msgTypes[8]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetAllOnlineUsersRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetAllOnlineUsersRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_command_proto_rawDescGZIP(), []int{8}
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetAllOnlineUsersResponse struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Users []string `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetAllOnlineUsersResponse) Reset() {
|
||||||
|
*x = GetAllOnlineUsersResponse{}
|
||||||
|
mi := &file_command_proto_msgTypes[9]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetAllOnlineUsersResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetAllOnlineUsersResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetAllOnlineUsersResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_command_proto_msgTypes[9]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetAllOnlineUsersResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetAllOnlineUsersResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_command_proto_rawDescGZIP(), []int{9}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetAllOnlineUsersResponse) GetUsers() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Users
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
mi := &file_app_stats_command_command_proto_msgTypes[8]
|
mi := &file_command_proto_msgTypes[10]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -497,7 +571,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_stats_command_command_proto_msgTypes[8]
|
mi := &file_command_proto_msgTypes[10]
|
||||||
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 {
|
||||||
@@ -510,125 +584,76 @@ 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_stats_command_command_proto_rawDescGZIP(), []int{8}
|
return file_command_proto_rawDescGZIP(), []int{10}
|
||||||
}
|
}
|
||||||
|
|
||||||
var File_app_stats_command_command_proto protoreflect.FileDescriptor
|
var File_command_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_app_stats_command_command_proto_rawDesc = []byte{
|
const file_command_proto_rawDesc = "" +
|
||||||
0x0a, 0x1f, 0x61, 0x70, 0x70, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
|
"\n" +
|
||||||
0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
"\rcommand.proto\x12\x16xray.app.stats.command\";\n" +
|
||||||
0x6f, 0x12, 0x16, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74,
|
"\x0fGetStatsRequest\x12\x12\n" +
|
||||||
0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0x3b, 0x0a, 0x0f, 0x47, 0x65, 0x74,
|
"\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" +
|
||||||
0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,
|
"\x05reset\x18\x02 \x01(\bR\x05reset\"0\n" +
|
||||||
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
"\x04Stat\x12\x12\n" +
|
||||||
0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52,
|
"\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" +
|
||||||
0x05, 0x72, 0x65, 0x73, 0x65, 0x74, 0x22, 0x30, 0x0a, 0x04, 0x53, 0x74, 0x61, 0x74, 0x12, 0x12,
|
"\x05value\x18\x02 \x01(\x03R\x05value\"D\n" +
|
||||||
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
|
"\x10GetStatsResponse\x120\n" +
|
||||||
0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
"\x04stat\x18\x01 \x01(\v2\x1c.xray.app.stats.command.StatR\x04stat\"C\n" +
|
||||||
0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x44, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53,
|
"\x11QueryStatsRequest\x12\x18\n" +
|
||||||
0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x04,
|
"\apattern\x18\x01 \x01(\tR\apattern\x12\x14\n" +
|
||||||
0x73, 0x74, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61,
|
"\x05reset\x18\x02 \x01(\bR\x05reset\"F\n" +
|
||||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
"\x12QueryStatsResponse\x120\n" +
|
||||||
0x61, 0x6e, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x52, 0x04, 0x73, 0x74, 0x61, 0x74, 0x22, 0x43,
|
"\x04stat\x18\x01 \x03(\v2\x1c.xray.app.stats.command.StatR\x04stat\"\x11\n" +
|
||||||
0x0a, 0x11, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75,
|
"\x0fSysStatsRequest\"\xa2\x02\n" +
|
||||||
0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x01,
|
"\x10SysStatsResponse\x12\"\n" +
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x14, 0x0a,
|
"\fNumGoroutine\x18\x01 \x01(\rR\fNumGoroutine\x12\x14\n" +
|
||||||
0x05, 0x72, 0x65, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65,
|
"\x05NumGC\x18\x02 \x01(\rR\x05NumGC\x12\x14\n" +
|
||||||
0x73, 0x65, 0x74, 0x22, 0x46, 0x0a, 0x12, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74,
|
"\x05Alloc\x18\x03 \x01(\x04R\x05Alloc\x12\x1e\n" +
|
||||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x04, 0x73, 0x74, 0x61,
|
"\n" +
|
||||||
0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
|
"TotalAlloc\x18\x04 \x01(\x04R\n" +
|
||||||
0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
"TotalAlloc\x12\x10\n" +
|
||||||
0x2e, 0x53, 0x74, 0x61, 0x74, 0x52, 0x04, 0x73, 0x74, 0x61, 0x74, 0x22, 0x11, 0x0a, 0x0f, 0x53,
|
"\x03Sys\x18\x05 \x01(\x04R\x03Sys\x12\x18\n" +
|
||||||
0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xa2,
|
"\aMallocs\x18\x06 \x01(\x04R\aMallocs\x12\x14\n" +
|
||||||
0x02, 0x0a, 0x10, 0x53, 0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
"\x05Frees\x18\a \x01(\x04R\x05Frees\x12 \n" +
|
||||||
0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x4e, 0x75, 0x6d, 0x47, 0x6f, 0x72, 0x6f, 0x75, 0x74,
|
"\vLiveObjects\x18\b \x01(\x04R\vLiveObjects\x12\"\n" +
|
||||||
0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x4e, 0x75, 0x6d, 0x47, 0x6f,
|
"\fPauseTotalNs\x18\t \x01(\x04R\fPauseTotalNs\x12\x16\n" +
|
||||||
0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4e, 0x75, 0x6d, 0x47, 0x43,
|
"\x06Uptime\x18\n" +
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4e, 0x75, 0x6d, 0x47, 0x43, 0x12, 0x14, 0x0a,
|
" \x01(\rR\x06Uptime\"\xbb\x01\n" +
|
||||||
0x05, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x41, 0x6c,
|
"\x1cGetStatsOnlineIpListResponse\x12\x12\n" +
|
||||||
0x6c, 0x6f, 0x63, 0x12, 0x1e, 0x0a, 0x0a, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f,
|
"\x04name\x18\x01 \x01(\tR\x04name\x12O\n" +
|
||||||
0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c,
|
"\x03ips\x18\x02 \x03(\v2=.xray.app.stats.command.GetStatsOnlineIpListResponse.IpsEntryR\x03ips\x1a6\n" +
|
||||||
0x6c, 0x6f, 0x63, 0x12, 0x10, 0x0a, 0x03, 0x53, 0x79, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04,
|
"\bIpsEntry\x12\x10\n" +
|
||||||
0x52, 0x03, 0x53, 0x79, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x73,
|
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||||
0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x4d, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x73, 0x12,
|
"\x05value\x18\x02 \x01(\x03R\x05value:\x028\x01\"\x1a\n" +
|
||||||
0x14, 0x0a, 0x05, 0x46, 0x72, 0x65, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05,
|
"\x18GetAllOnlineUsersRequest\"1\n" +
|
||||||
0x46, 0x72, 0x65, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4c, 0x69, 0x76, 0x65, 0x4f, 0x62, 0x6a,
|
"\x19GetAllOnlineUsersResponse\x12\x14\n" +
|
||||||
0x65, 0x63, 0x74, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x4c, 0x69, 0x76, 0x65,
|
"\x05users\x18\x01 \x03(\tR\x05users\"\b\n" +
|
||||||
0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x50, 0x61, 0x75, 0x73, 0x65,
|
"\x06Config2\x96\x05\n" +
|
||||||
0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4e, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x50,
|
"\fStatsService\x12_\n" +
|
||||||
0x61, 0x75, 0x73, 0x65, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4e, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x55,
|
"\bGetStats\x12'.xray.app.stats.command.GetStatsRequest\x1a(.xray.app.stats.command.GetStatsResponse\"\x00\x12e\n" +
|
||||||
0x70, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x55, 0x70, 0x74,
|
"\x0eGetStatsOnline\x12'.xray.app.stats.command.GetStatsRequest\x1a(.xray.app.stats.command.GetStatsResponse\"\x00\x12e\n" +
|
||||||
0x69, 0x6d, 0x65, 0x22, 0xbb, 0x01, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73,
|
"\n" +
|
||||||
0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x49, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70,
|
"QueryStats\x12).xray.app.stats.command.QueryStatsRequest\x1a*.xray.app.stats.command.QueryStatsResponse\"\x00\x12b\n" +
|
||||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
|
"\vGetSysStats\x12'.xray.app.stats.command.SysStatsRequest\x1a(.xray.app.stats.command.SysStatsResponse\"\x00\x12w\n" +
|
||||||
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4f, 0x0a, 0x03, 0x69, 0x70, 0x73, 0x18,
|
"\x14GetStatsOnlineIpList\x12'.xray.app.stats.command.GetStatsRequest\x1a4.xray.app.stats.command.GetStatsOnlineIpListResponse\"\x00\x12z\n" +
|
||||||
0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
"\x11GetAllOnlineUsers\x120.xray.app.stats.command.GetAllOnlineUsersRequest\x1a1.xray.app.stats.command.GetAllOnlineUsersResponse\"\x00Bd\n" +
|
||||||
0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47,
|
"\x1acom.xray.app.stats.commandP\x01Z+github.com/xtls/xray-core/app/stats/command\xaa\x02\x16Xray.App.Stats.Commandb\x06proto3"
|
||||||
0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x49, 0x70, 0x4c,
|
|
||||||
0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x49, 0x70, 0x73, 0x45,
|
|
||||||
0x6e, 0x74, 0x72, 0x79, 0x52, 0x03, 0x69, 0x70, 0x73, 0x1a, 0x36, 0x0a, 0x08, 0x49, 0x70, 0x73,
|
|
||||||
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
|
||||||
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
|
|
||||||
0x01, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0x9a, 0x04, 0x0a, 0x0c,
|
|
||||||
0x53, 0x74, 0x61, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5f, 0x0a, 0x08,
|
|
||||||
0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
|
||||||
0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
|
||||||
0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
|
||||||
0x74, 0x1a, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61,
|
|
||||||
0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74,
|
|
||||||
0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x65, 0x0a,
|
|
||||||
0x0e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x12,
|
|
||||||
0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73,
|
|
||||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74,
|
|
||||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
|
||||||
0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
|
||||||
0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
|
||||||
0x73, 0x65, 0x22, 0x00, 0x12, 0x65, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61,
|
|
||||||
0x74, 0x73, 0x12, 0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74,
|
|
||||||
0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x51, 0x75, 0x65, 0x72,
|
|
||||||
0x79, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e,
|
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63,
|
|
||||||
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74,
|
|
||||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x62, 0x0a, 0x0b, 0x47,
|
|
||||||
0x65, 0x74, 0x53, 0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x27, 0x2e, 0x78, 0x72, 0x61,
|
|
||||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
|
||||||
0x61, 0x6e, 0x64, 0x2e, 0x53, 0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75,
|
|
||||||
0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73,
|
|
||||||
0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53, 0x79, 0x73,
|
|
||||||
0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
|
|
||||||
0x77, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x69, 0x6e,
|
|
||||||
0x65, 0x49, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
|
|
||||||
0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
|
||||||
0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
|
||||||
0x1a, 0x34, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74,
|
|
||||||
0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61,
|
|
||||||
0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x49, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65,
|
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x64, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e,
|
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63,
|
|
||||||
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2b, 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, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2f, 0x63, 0x6f,
|
|
||||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x16, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70,
|
|
||||||
0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06,
|
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_app_stats_command_command_proto_rawDescOnce sync.Once
|
file_command_proto_rawDescOnce sync.Once
|
||||||
file_app_stats_command_command_proto_rawDescData = file_app_stats_command_command_proto_rawDesc
|
file_command_proto_rawDescData []byte
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_app_stats_command_command_proto_rawDescGZIP() []byte {
|
func file_command_proto_rawDescGZIP() []byte {
|
||||||
file_app_stats_command_command_proto_rawDescOnce.Do(func() {
|
file_command_proto_rawDescOnce.Do(func() {
|
||||||
file_app_stats_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_stats_command_command_proto_rawDescData)
|
file_command_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_command_proto_rawDesc), len(file_command_proto_rawDesc)))
|
||||||
})
|
})
|
||||||
return file_app_stats_command_command_proto_rawDescData
|
return file_command_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_app_stats_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
var file_command_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
|
||||||
var file_app_stats_command_command_proto_goTypes = []any{
|
var file_command_proto_goTypes = []any{
|
||||||
(*GetStatsRequest)(nil), // 0: xray.app.stats.command.GetStatsRequest
|
(*GetStatsRequest)(nil), // 0: xray.app.stats.command.GetStatsRequest
|
||||||
(*Stat)(nil), // 1: xray.app.stats.command.Stat
|
(*Stat)(nil), // 1: xray.app.stats.command.Stat
|
||||||
(*GetStatsResponse)(nil), // 2: xray.app.stats.command.GetStatsResponse
|
(*GetStatsResponse)(nil), // 2: xray.app.stats.command.GetStatsResponse
|
||||||
@@ -637,51 +662,54 @@ var file_app_stats_command_command_proto_goTypes = []any{
|
|||||||
(*SysStatsRequest)(nil), // 5: xray.app.stats.command.SysStatsRequest
|
(*SysStatsRequest)(nil), // 5: xray.app.stats.command.SysStatsRequest
|
||||||
(*SysStatsResponse)(nil), // 6: xray.app.stats.command.SysStatsResponse
|
(*SysStatsResponse)(nil), // 6: xray.app.stats.command.SysStatsResponse
|
||||||
(*GetStatsOnlineIpListResponse)(nil), // 7: xray.app.stats.command.GetStatsOnlineIpListResponse
|
(*GetStatsOnlineIpListResponse)(nil), // 7: xray.app.stats.command.GetStatsOnlineIpListResponse
|
||||||
(*Config)(nil), // 8: xray.app.stats.command.Config
|
(*GetAllOnlineUsersRequest)(nil), // 8: xray.app.stats.command.GetAllOnlineUsersRequest
|
||||||
nil, // 9: xray.app.stats.command.GetStatsOnlineIpListResponse.IpsEntry
|
(*GetAllOnlineUsersResponse)(nil), // 9: xray.app.stats.command.GetAllOnlineUsersResponse
|
||||||
|
(*Config)(nil), // 10: xray.app.stats.command.Config
|
||||||
|
nil, // 11: xray.app.stats.command.GetStatsOnlineIpListResponse.IpsEntry
|
||||||
}
|
}
|
||||||
var file_app_stats_command_command_proto_depIdxs = []int32{
|
var file_command_proto_depIdxs = []int32{
|
||||||
1, // 0: xray.app.stats.command.GetStatsResponse.stat:type_name -> xray.app.stats.command.Stat
|
1, // 0: xray.app.stats.command.GetStatsResponse.stat:type_name -> xray.app.stats.command.Stat
|
||||||
1, // 1: xray.app.stats.command.QueryStatsResponse.stat:type_name -> xray.app.stats.command.Stat
|
1, // 1: xray.app.stats.command.QueryStatsResponse.stat:type_name -> xray.app.stats.command.Stat
|
||||||
9, // 2: xray.app.stats.command.GetStatsOnlineIpListResponse.ips:type_name -> xray.app.stats.command.GetStatsOnlineIpListResponse.IpsEntry
|
11, // 2: xray.app.stats.command.GetStatsOnlineIpListResponse.ips:type_name -> xray.app.stats.command.GetStatsOnlineIpListResponse.IpsEntry
|
||||||
0, // 3: xray.app.stats.command.StatsService.GetStats:input_type -> xray.app.stats.command.GetStatsRequest
|
0, // 3: xray.app.stats.command.StatsService.GetStats:input_type -> xray.app.stats.command.GetStatsRequest
|
||||||
0, // 4: xray.app.stats.command.StatsService.GetStatsOnline:input_type -> xray.app.stats.command.GetStatsRequest
|
0, // 4: xray.app.stats.command.StatsService.GetStatsOnline:input_type -> xray.app.stats.command.GetStatsRequest
|
||||||
3, // 5: xray.app.stats.command.StatsService.QueryStats:input_type -> xray.app.stats.command.QueryStatsRequest
|
3, // 5: xray.app.stats.command.StatsService.QueryStats:input_type -> xray.app.stats.command.QueryStatsRequest
|
||||||
5, // 6: xray.app.stats.command.StatsService.GetSysStats:input_type -> xray.app.stats.command.SysStatsRequest
|
5, // 6: xray.app.stats.command.StatsService.GetSysStats:input_type -> xray.app.stats.command.SysStatsRequest
|
||||||
0, // 7: xray.app.stats.command.StatsService.GetStatsOnlineIpList:input_type -> xray.app.stats.command.GetStatsRequest
|
0, // 7: xray.app.stats.command.StatsService.GetStatsOnlineIpList:input_type -> xray.app.stats.command.GetStatsRequest
|
||||||
2, // 8: xray.app.stats.command.StatsService.GetStats:output_type -> xray.app.stats.command.GetStatsResponse
|
8, // 8: xray.app.stats.command.StatsService.GetAllOnlineUsers:input_type -> xray.app.stats.command.GetAllOnlineUsersRequest
|
||||||
2, // 9: xray.app.stats.command.StatsService.GetStatsOnline:output_type -> xray.app.stats.command.GetStatsResponse
|
2, // 9: xray.app.stats.command.StatsService.GetStats:output_type -> xray.app.stats.command.GetStatsResponse
|
||||||
4, // 10: xray.app.stats.command.StatsService.QueryStats:output_type -> xray.app.stats.command.QueryStatsResponse
|
2, // 10: xray.app.stats.command.StatsService.GetStatsOnline:output_type -> xray.app.stats.command.GetStatsResponse
|
||||||
6, // 11: xray.app.stats.command.StatsService.GetSysStats:output_type -> xray.app.stats.command.SysStatsResponse
|
4, // 11: xray.app.stats.command.StatsService.QueryStats:output_type -> xray.app.stats.command.QueryStatsResponse
|
||||||
7, // 12: xray.app.stats.command.StatsService.GetStatsOnlineIpList:output_type -> xray.app.stats.command.GetStatsOnlineIpListResponse
|
6, // 12: xray.app.stats.command.StatsService.GetSysStats:output_type -> xray.app.stats.command.SysStatsResponse
|
||||||
8, // [8:13] is the sub-list for method output_type
|
7, // 13: xray.app.stats.command.StatsService.GetStatsOnlineIpList:output_type -> xray.app.stats.command.GetStatsOnlineIpListResponse
|
||||||
3, // [3:8] is the sub-list for method input_type
|
9, // 14: xray.app.stats.command.StatsService.GetAllOnlineUsers:output_type -> xray.app.stats.command.GetAllOnlineUsersResponse
|
||||||
3, // [3:3] is the sub-list for extension type_name
|
9, // [9:15] is the sub-list for method output_type
|
||||||
3, // [3:3] is the sub-list for extension extendee
|
3, // [3:9] is the sub-list for method input_type
|
||||||
0, // [0:3] is the sub-list for field type_name
|
3, // [3:3] is the sub-list for extension type_name
|
||||||
|
3, // [3:3] is the sub-list for extension extendee
|
||||||
|
0, // [0:3] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_stats_command_command_proto_init() }
|
func init() { file_command_proto_init() }
|
||||||
func file_app_stats_command_command_proto_init() {
|
func file_command_proto_init() {
|
||||||
if File_app_stats_command_command_proto != nil {
|
if File_command_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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: file_app_stats_command_command_proto_rawDesc,
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_command_proto_rawDesc), len(file_command_proto_rawDesc)),
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 10,
|
NumMessages: 12,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
GoTypes: file_app_stats_command_command_proto_goTypes,
|
GoTypes: file_command_proto_goTypes,
|
||||||
DependencyIndexes: file_app_stats_command_command_proto_depIdxs,
|
DependencyIndexes: file_command_proto_depIdxs,
|
||||||
MessageInfos: file_app_stats_command_command_proto_msgTypes,
|
MessageInfos: file_command_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_app_stats_command_command_proto = out.File
|
File_command_proto = out.File
|
||||||
file_app_stats_command_command_proto_rawDesc = nil
|
file_command_proto_goTypes = nil
|
||||||
file_app_stats_command_command_proto_goTypes = nil
|
file_command_proto_depIdxs = nil
|
||||||
file_app_stats_command_command_proto_depIdxs = nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,12 +51,19 @@ message GetStatsOnlineIpListResponse {
|
|||||||
map<string, int64> ips = 2;
|
map<string, int64> ips = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message GetAllOnlineUsersRequest {}
|
||||||
|
|
||||||
|
message GetAllOnlineUsersResponse {
|
||||||
|
repeated string users = 1;
|
||||||
|
}
|
||||||
|
|
||||||
service StatsService {
|
service StatsService {
|
||||||
rpc GetStats(GetStatsRequest) returns (GetStatsResponse) {}
|
rpc GetStats(GetStatsRequest) returns (GetStatsResponse) {}
|
||||||
rpc GetStatsOnline(GetStatsRequest) returns (GetStatsResponse) {}
|
rpc GetStatsOnline(GetStatsRequest) returns (GetStatsResponse) {}
|
||||||
rpc QueryStats(QueryStatsRequest) returns (QueryStatsResponse) {}
|
rpc QueryStats(QueryStatsRequest) returns (QueryStatsResponse) {}
|
||||||
rpc GetSysStats(SysStatsRequest) returns (SysStatsResponse) {}
|
rpc GetSysStats(SysStatsRequest) returns (SysStatsResponse) {}
|
||||||
rpc GetStatsOnlineIpList(GetStatsRequest) returns (GetStatsOnlineIpListResponse) {}
|
rpc GetStatsOnlineIpList(GetStatsRequest) returns (GetStatsOnlineIpListResponse) {}
|
||||||
|
rpc GetAllOnlineUsers(GetAllOnlineUsersRequest) returns (GetAllOnlineUsersResponse) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
message Config {}
|
message Config {}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// 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.5.1
|
// - protoc-gen-go-grpc v1.5.1
|
||||||
// - protoc v5.28.2
|
// - protoc v6.32.0
|
||||||
// source: app/stats/command/command.proto
|
// source: command.proto
|
||||||
|
|
||||||
package command
|
package command
|
||||||
|
|
||||||
@@ -24,6 +24,7 @@ const (
|
|||||||
StatsService_QueryStats_FullMethodName = "/xray.app.stats.command.StatsService/QueryStats"
|
StatsService_QueryStats_FullMethodName = "/xray.app.stats.command.StatsService/QueryStats"
|
||||||
StatsService_GetSysStats_FullMethodName = "/xray.app.stats.command.StatsService/GetSysStats"
|
StatsService_GetSysStats_FullMethodName = "/xray.app.stats.command.StatsService/GetSysStats"
|
||||||
StatsService_GetStatsOnlineIpList_FullMethodName = "/xray.app.stats.command.StatsService/GetStatsOnlineIpList"
|
StatsService_GetStatsOnlineIpList_FullMethodName = "/xray.app.stats.command.StatsService/GetStatsOnlineIpList"
|
||||||
|
StatsService_GetAllOnlineUsers_FullMethodName = "/xray.app.stats.command.StatsService/GetAllOnlineUsers"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StatsServiceClient is the client API for StatsService service.
|
// StatsServiceClient is the client API for StatsService service.
|
||||||
@@ -35,6 +36,7 @@ type StatsServiceClient interface {
|
|||||||
QueryStats(ctx context.Context, in *QueryStatsRequest, opts ...grpc.CallOption) (*QueryStatsResponse, error)
|
QueryStats(ctx context.Context, in *QueryStatsRequest, opts ...grpc.CallOption) (*QueryStatsResponse, error)
|
||||||
GetSysStats(ctx context.Context, in *SysStatsRequest, opts ...grpc.CallOption) (*SysStatsResponse, error)
|
GetSysStats(ctx context.Context, in *SysStatsRequest, opts ...grpc.CallOption) (*SysStatsResponse, error)
|
||||||
GetStatsOnlineIpList(ctx context.Context, in *GetStatsRequest, opts ...grpc.CallOption) (*GetStatsOnlineIpListResponse, error)
|
GetStatsOnlineIpList(ctx context.Context, in *GetStatsRequest, opts ...grpc.CallOption) (*GetStatsOnlineIpListResponse, error)
|
||||||
|
GetAllOnlineUsers(ctx context.Context, in *GetAllOnlineUsersRequest, opts ...grpc.CallOption) (*GetAllOnlineUsersResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type statsServiceClient struct {
|
type statsServiceClient struct {
|
||||||
@@ -95,6 +97,16 @@ func (c *statsServiceClient) GetStatsOnlineIpList(ctx context.Context, in *GetSt
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *statsServiceClient) GetAllOnlineUsers(ctx context.Context, in *GetAllOnlineUsersRequest, opts ...grpc.CallOption) (*GetAllOnlineUsersResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(GetAllOnlineUsersResponse)
|
||||||
|
err := c.cc.Invoke(ctx, StatsService_GetAllOnlineUsers_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
// StatsServiceServer is the server API for StatsService service.
|
// StatsServiceServer is the server API for StatsService service.
|
||||||
// All implementations must embed UnimplementedStatsServiceServer
|
// All implementations must embed UnimplementedStatsServiceServer
|
||||||
// for forward compatibility.
|
// for forward compatibility.
|
||||||
@@ -104,6 +116,7 @@ type StatsServiceServer interface {
|
|||||||
QueryStats(context.Context, *QueryStatsRequest) (*QueryStatsResponse, error)
|
QueryStats(context.Context, *QueryStatsRequest) (*QueryStatsResponse, error)
|
||||||
GetSysStats(context.Context, *SysStatsRequest) (*SysStatsResponse, error)
|
GetSysStats(context.Context, *SysStatsRequest) (*SysStatsResponse, error)
|
||||||
GetStatsOnlineIpList(context.Context, *GetStatsRequest) (*GetStatsOnlineIpListResponse, error)
|
GetStatsOnlineIpList(context.Context, *GetStatsRequest) (*GetStatsOnlineIpListResponse, error)
|
||||||
|
GetAllOnlineUsers(context.Context, *GetAllOnlineUsersRequest) (*GetAllOnlineUsersResponse, error)
|
||||||
mustEmbedUnimplementedStatsServiceServer()
|
mustEmbedUnimplementedStatsServiceServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +142,9 @@ func (UnimplementedStatsServiceServer) GetSysStats(context.Context, *SysStatsReq
|
|||||||
func (UnimplementedStatsServiceServer) GetStatsOnlineIpList(context.Context, *GetStatsRequest) (*GetStatsOnlineIpListResponse, error) {
|
func (UnimplementedStatsServiceServer) GetStatsOnlineIpList(context.Context, *GetStatsRequest) (*GetStatsOnlineIpListResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetStatsOnlineIpList not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetStatsOnlineIpList not implemented")
|
||||||
}
|
}
|
||||||
|
func (UnimplementedStatsServiceServer) GetAllOnlineUsers(context.Context, *GetAllOnlineUsersRequest) (*GetAllOnlineUsersResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method GetAllOnlineUsers not implemented")
|
||||||
|
}
|
||||||
func (UnimplementedStatsServiceServer) mustEmbedUnimplementedStatsServiceServer() {}
|
func (UnimplementedStatsServiceServer) mustEmbedUnimplementedStatsServiceServer() {}
|
||||||
func (UnimplementedStatsServiceServer) testEmbeddedByValue() {}
|
func (UnimplementedStatsServiceServer) testEmbeddedByValue() {}
|
||||||
|
|
||||||
@@ -240,6 +256,24 @@ func _StatsService_GetStatsOnlineIpList_Handler(srv interface{}, ctx context.Con
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _StatsService_GetAllOnlineUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(GetAllOnlineUsersRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(StatsServiceServer).GetAllOnlineUsers(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: StatsService_GetAllOnlineUsers_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(StatsServiceServer).GetAllOnlineUsers(ctx, req.(*GetAllOnlineUsersRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
// StatsService_ServiceDesc is the grpc.ServiceDesc for StatsService service.
|
// StatsService_ServiceDesc is the grpc.ServiceDesc for StatsService 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)
|
||||||
@@ -267,7 +301,11 @@ var StatsService_ServiceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "GetStatsOnlineIpList",
|
MethodName: "GetStatsOnlineIpList",
|
||||||
Handler: _StatsService_GetStatsOnlineIpList_Handler,
|
Handler: _StatsService_GetStatsOnlineIpList_Handler,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
MethodName: "GetAllOnlineUsers",
|
||||||
|
Handler: _StatsService_GetAllOnlineUsers_Handler,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{},
|
Streams: []grpc.StreamDesc{},
|
||||||
Metadata: "app/stats/command/command.proto",
|
Metadata: "command.proto",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,6 +161,21 @@ func (m *Manager) GetChannel(name string) stats.Channel {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAllOnlineUsers implements stats.Manager.
|
||||||
|
func (m *Manager) GetAllOnlineUsers() []string {
|
||||||
|
m.access.Lock()
|
||||||
|
defer m.access.Unlock()
|
||||||
|
|
||||||
|
usersOnline := make([]string, 0, len(m.onlineMap))
|
||||||
|
for user, onlineMap := range m.onlineMap {
|
||||||
|
if len(onlineMap.IpTimeMap()) > 0 {
|
||||||
|
usersOnline = append(usersOnline, user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return usersOnline
|
||||||
|
}
|
||||||
|
|
||||||
// Start implements common.Runnable.
|
// Start implements common.Runnable.
|
||||||
func (m *Manager) Start() error {
|
func (m *Manager) Start() error {
|
||||||
m.access.Lock()
|
m.access.Lock()
|
||||||
|
|||||||
@@ -4,22 +4,19 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PrintMigrateFeatureInfo prints a notice of the upcoming feature migration.
|
// PrintNonRemovalDeprecatedFeatureWarning prints a warning of the deprecated feature that won't be removed in the near future.
|
||||||
// Place it after the source feature related config file pharser code.
|
|
||||||
// Important note: Only use this when the target migrating feature is under construction.
|
|
||||||
// Important note: Even when the target migrating feature has finished its construction, this notice can still be used yet before announcing deprecation of the old feature.
|
|
||||||
// Do not remove this function even there is no reference to it.
|
// Do not remove this function even there is no reference to it.
|
||||||
func PrintMigrateFeatureInfo(sourceFeature string, targetFeature string) {
|
func PrintNonRemovalDeprecatedFeatureWarning(sourceFeature string, targetFeature string) {
|
||||||
LogInfo(context.Background(), "The feature "+sourceFeature+" will be migrated to "+targetFeature+" in the future.")
|
LogWarning(context.Background(), "The feature "+sourceFeature+" is deprecated, not recommended for using and might be removed. Please migrate to "+targetFeature+" as soon as possible.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintDeprecatedFeatureWarning prints a warning for deprecated and going to be removed feature.
|
// PrintDeprecatedFeatureWarning prints a warning for deprecated and going to be removed feature.
|
||||||
// Do not remove this function even there is no reference to it.
|
// Do not remove this function even there is no reference to it.
|
||||||
func PrintDeprecatedFeatureWarning(feature string, migrateFeature string) {
|
func PrintDeprecatedFeatureWarning(feature string, migrateFeature string) {
|
||||||
if len(migrateFeature) > 0 {
|
if len(migrateFeature) > 0 {
|
||||||
LogWarning(context.Background(), "This feature "+feature+" is deprecated and being migrated to "+migrateFeature+". Please update your config(s) according to release note and documentation before removal.")
|
LogWarning(context.Background(), "This feature "+feature+" is deprecated, will be removed soon and being migrated to "+migrateFeature+". Please update your config(s) according to release note and documentation before removal.")
|
||||||
} else {
|
} else {
|
||||||
LogWarning(context.Background(), "This feature "+feature+" is deprecated. Please update your config(s) according to release note and documentation before removal.")
|
LogWarning(context.Background(), "This feature "+feature+" is deprecated and will be removed soon. Please update your config(s) according to release note and documentation before removal.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -43,8 +43,9 @@ func (l *DNSLog) String() string {
|
|||||||
type dnsStatus string
|
type dnsStatus string
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DNSQueried = dnsStatus("got answer:")
|
DNSQueried = dnsStatus("got answer:")
|
||||||
DNSCacheHit = dnsStatus("cache HIT:")
|
DNSCacheHit = dnsStatus("cache HIT:")
|
||||||
|
DNSCacheOptimiste = dnsStatus("cache OPTIMISTE:")
|
||||||
)
|
)
|
||||||
|
|
||||||
func joinNetIP(ips []net.IP) string {
|
func joinNetIP(ips []net.IP) string {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/dispatcher"
|
|
||||||
"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"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
@@ -64,7 +63,6 @@ func (s *Server) DispatchLink(ctx context.Context, dest net.Destination, link *t
|
|||||||
if dest.Address != muxCoolAddress {
|
if dest.Address != muxCoolAddress {
|
||||||
return s.dispatcher.DispatchLink(ctx, dest, link)
|
return s.dispatcher.DispatchLink(ctx, dest, link)
|
||||||
}
|
}
|
||||||
link = s.dispatcher.(*dispatcher.DefaultDispatcher).WrapLink(ctx, link)
|
|
||||||
worker, err := NewServerWorker(ctx, s.dispatcher, link)
|
worker, err := NewServerWorker(ctx, s.dispatcher, link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FindProcess(dest Destination) (PID int, Name string, AbsolutePath string, err error) {
|
||||||
|
isLocal, err := IsLocal(dest.Address.IP())
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", "", errors.New("failed to determine if address is local: ", err)
|
||||||
|
}
|
||||||
|
if !isLocal {
|
||||||
|
return 0, "", "", ErrNotLocal
|
||||||
|
}
|
||||||
|
if dest.Network != Network_TCP && dest.Network != Network_UDP {
|
||||||
|
panic("Unsupported network type for process lookup.")
|
||||||
|
}
|
||||||
|
// the core should never has a domain as source(?
|
||||||
|
if dest.Address.Family() == AddressFamilyDomain {
|
||||||
|
panic("Domain addresses are not supported for process lookup.")
|
||||||
|
}
|
||||||
|
var procFile string
|
||||||
|
|
||||||
|
switch dest.Network {
|
||||||
|
case Network_TCP:
|
||||||
|
if dest.Address.Family() == AddressFamilyIPv4 {
|
||||||
|
procFile = "/proc/net/tcp"
|
||||||
|
}
|
||||||
|
if dest.Address.Family() == AddressFamilyIPv6 {
|
||||||
|
procFile = "/proc/net/tcp6"
|
||||||
|
}
|
||||||
|
case Network_UDP:
|
||||||
|
if dest.Address.Family() == AddressFamilyIPv4 {
|
||||||
|
procFile = "/proc/net/udp"
|
||||||
|
}
|
||||||
|
if dest.Address.Family() == AddressFamilyIPv6 {
|
||||||
|
procFile = "/proc/net/udp6"
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("Unsupported network type for process lookup.")
|
||||||
|
}
|
||||||
|
|
||||||
|
targetHexAddr, err := formatLittleEndianString(dest.Address, dest.Port)
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", "", errors.New("failed to format address: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
inode, err := findInodeInFile(procFile, targetHexAddr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", "", errors.New("could not search in ", procFile).Base(err)
|
||||||
|
}
|
||||||
|
if inode == "" {
|
||||||
|
return 0, "", "", errors.New("connection for ", dest.Address, ":", dest.Port, " not found in ", procFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
pidStr, err := findPidByInode(inode)
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", "", errors.New("could not find PID for inode ", inode, ": ", err)
|
||||||
|
}
|
||||||
|
if pidStr == "" {
|
||||||
|
return 0, "", "", errors.New("no process found for inode ", inode)
|
||||||
|
}
|
||||||
|
|
||||||
|
absPath, err := getAbsPath(pidStr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", "", errors.New("could not get process name for PID ", pidStr, ":", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
nameSplit := strings.Split(absPath, "/")
|
||||||
|
procName := nameSplit[len(nameSplit)-1]
|
||||||
|
|
||||||
|
pid, err := strconv.Atoi(pidStr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", "", errors.New("failed to parse PID: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pid, procName, absPath, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatLittleEndianString(addr Address, port Port) (string, error) {
|
||||||
|
ip := addr.IP()
|
||||||
|
var ipBytes []byte
|
||||||
|
if addr.Family() == AddressFamilyIPv4 {
|
||||||
|
ipBytes = ip.To4()
|
||||||
|
} else {
|
||||||
|
ipBytes = ip.To16()
|
||||||
|
}
|
||||||
|
if ipBytes == nil {
|
||||||
|
return "", errors.New("invalid IP format for ", addr.Family(), ": ", ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, j := 0, len(ipBytes)-1; i < j; i, j = i+1, j-1 {
|
||||||
|
ipBytes[i], ipBytes[j] = ipBytes[j], ipBytes[i]
|
||||||
|
}
|
||||||
|
portHex := fmt.Sprintf("%04X", uint16(port))
|
||||||
|
ipHex := strings.ToUpper(hex.EncodeToString(ipBytes))
|
||||||
|
return fmt.Sprintf("%s:%s", ipHex, portHex), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findInodeInFile(filePath, targetHexAddr string) (string, error) {
|
||||||
|
file, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
|
||||||
|
if len(fields) < 10 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
localAddress := fields[1]
|
||||||
|
if localAddress == targetHexAddr {
|
||||||
|
inode := fields[9]
|
||||||
|
return inode, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", scanner.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func findPidByInode(inode string) (string, error) {
|
||||||
|
procDir, err := os.ReadDir("/proc")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
targetLink := "socket:[" + inode + "]"
|
||||||
|
|
||||||
|
for _, entry := range procDir {
|
||||||
|
if !entry.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pid := entry.Name()
|
||||||
|
if _, err := strconv.Atoi(pid); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fdPath := fmt.Sprintf("/proc/%s/fd", pid)
|
||||||
|
fdDir, err := os.ReadDir(fdPath)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fdEntry := range fdDir {
|
||||||
|
linkPath := fmt.Sprintf("%s/%s", fdPath, fdEntry.Name())
|
||||||
|
linkTarget, err := os.Readlink(linkPath)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if linkTarget == targetLink {
|
||||||
|
return pid, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAbsPath(pid string) (string, error) {
|
||||||
|
path := fmt.Sprintf("/proc/%s/exe", pid)
|
||||||
|
return os.Readlink(path)
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
//go:build !windows && !linux
|
||||||
|
|
||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FindProcess(dest Destination) (int, string, string, error) {
|
||||||
|
return 0, "", "", errors.New("process lookup is not supported on this platform")
|
||||||
|
}
|
||||||
@@ -0,0 +1,243 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/netip"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
tcpTableFunc = "GetExtendedTcpTable"
|
||||||
|
tcpTablePidConn = 4
|
||||||
|
udpTableFunc = "GetExtendedUdpTable"
|
||||||
|
udpTablePid = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
getExTCPTable uintptr
|
||||||
|
getExUDPTable uintptr
|
||||||
|
|
||||||
|
once sync.Once
|
||||||
|
initErr error
|
||||||
|
)
|
||||||
|
|
||||||
|
func initWin32API() error {
|
||||||
|
h, err := windows.LoadLibrary("iphlpapi.dll")
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("LoadLibrary iphlpapi.dll failed").Base(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
getExTCPTable, err = windows.GetProcAddress(h, tcpTableFunc)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("GetProcAddress of ", tcpTableFunc, " failed").Base(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
getExUDPTable, err = windows.GetProcAddress(h, udpTableFunc)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("GetProcAddress of ", udpTableFunc, " failed").Base(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindProcess(dest Destination) (PID int, Name string, AbsolutePath string, err error) {
|
||||||
|
once.Do(func() {
|
||||||
|
initErr = initWin32API()
|
||||||
|
})
|
||||||
|
if initErr != nil {
|
||||||
|
return 0, "", "", initErr
|
||||||
|
}
|
||||||
|
isLocal, err := IsLocal(dest.Address.IP())
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", "", errors.New("failed to determine if address is local: ", err)
|
||||||
|
}
|
||||||
|
if !isLocal {
|
||||||
|
return 0, "", "", ErrNotLocal
|
||||||
|
}
|
||||||
|
if dest.Network != Network_TCP && dest.Network != Network_UDP {
|
||||||
|
panic("Unsupported network type for process lookup.")
|
||||||
|
}
|
||||||
|
// the core should never has a domain as source(?
|
||||||
|
if dest.Address.Family() == AddressFamilyDomain {
|
||||||
|
panic("Domain addresses are not supported for process lookup.")
|
||||||
|
}
|
||||||
|
var class int
|
||||||
|
var fn uintptr
|
||||||
|
switch dest.Network {
|
||||||
|
case Network_TCP:
|
||||||
|
fn = getExTCPTable
|
||||||
|
class = tcpTablePidConn
|
||||||
|
case Network_UDP:
|
||||||
|
fn = getExUDPTable
|
||||||
|
class = udpTablePid
|
||||||
|
default:
|
||||||
|
panic("Unsupported network type for process lookup.")
|
||||||
|
}
|
||||||
|
ip := dest.Address.IP()
|
||||||
|
port := int(dest.Port)
|
||||||
|
|
||||||
|
addr, ok := netip.AddrFromSlice(ip)
|
||||||
|
if !ok {
|
||||||
|
return 0, "", "", errors.New("invalid IP address")
|
||||||
|
}
|
||||||
|
addr = addr.Unmap()
|
||||||
|
|
||||||
|
family := windows.AF_INET
|
||||||
|
if addr.Is6() {
|
||||||
|
family = windows.AF_INET6
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := getTransportTable(fn, family, class)
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
s := newSearcher(dest.Network, dest.Address.Family())
|
||||||
|
|
||||||
|
pid, err := s.Search(buf, addr, uint16(port))
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", "", err
|
||||||
|
}
|
||||||
|
NameWithPath, err := getExecPathFromPID(pid)
|
||||||
|
NameWithPath = filepath.ToSlash(NameWithPath)
|
||||||
|
|
||||||
|
// drop .exe and path
|
||||||
|
nameSplit := strings.Split(NameWithPath, "/")
|
||||||
|
procName := nameSplit[len(nameSplit)-1]
|
||||||
|
procName = strings.TrimSuffix(procName, ".exe")
|
||||||
|
return int(pid), procName, NameWithPath, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type searcher struct {
|
||||||
|
itemSize int
|
||||||
|
port int
|
||||||
|
ip int
|
||||||
|
ipSize int
|
||||||
|
pid int
|
||||||
|
tcpState int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *searcher) Search(b []byte, ip netip.Addr, port uint16) (uint32, error) {
|
||||||
|
n := int(readNativeUint32(b[:4]))
|
||||||
|
itemSize := s.itemSize
|
||||||
|
for i := range n {
|
||||||
|
row := b[4+itemSize*i : 4+itemSize*(i+1)]
|
||||||
|
|
||||||
|
if s.tcpState >= 0 {
|
||||||
|
tcpState := readNativeUint32(row[s.tcpState : s.tcpState+4])
|
||||||
|
// MIB_TCP_STATE_ESTAB, only check established connections for TCP
|
||||||
|
if tcpState != 5 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// according to MSDN, only the lower 16 bits of dwLocalPort are used and the port number is in network endian.
|
||||||
|
// this field can be illustrated as follows depends on different machine endianess:
|
||||||
|
// little endian: [ MSB LSB 0 0 ] interpret as native uint32 is ((LSB<<8)|MSB)
|
||||||
|
// big endian: [ 0 0 MSB LSB ] interpret as native uint32 is ((MSB<<8)|LSB)
|
||||||
|
// so we need an syscall.Ntohs on the lower 16 bits after read the port as native uint32
|
||||||
|
srcPort := syscall.Ntohs(uint16(readNativeUint32(row[s.port : s.port+4])))
|
||||||
|
if srcPort != port {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
srcIP, _ := netip.AddrFromSlice(row[s.ip : s.ip+s.ipSize])
|
||||||
|
srcIP = srcIP.Unmap()
|
||||||
|
// windows binds an unbound udp socket to 0.0.0.0/[::] while first sendto
|
||||||
|
if ip != srcIP && (!srcIP.IsUnspecified() || s.tcpState != -1) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pid := readNativeUint32(row[s.pid : s.pid+4])
|
||||||
|
return pid, nil
|
||||||
|
}
|
||||||
|
return 0, errors.New("not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSearcher(network Network, family AddressFamily) *searcher {
|
||||||
|
var itemSize, port, ip, ipSize, pid int
|
||||||
|
tcpState := -1
|
||||||
|
switch network {
|
||||||
|
case Network_TCP:
|
||||||
|
if family == AddressFamilyIPv4 {
|
||||||
|
// struct MIB_TCPROW_OWNER_PID
|
||||||
|
itemSize, port, ip, ipSize, pid, tcpState = 24, 8, 4, 4, 20, 0
|
||||||
|
}
|
||||||
|
if family == AddressFamilyIPv6 {
|
||||||
|
// struct MIB_TCP6ROW_OWNER_PID
|
||||||
|
itemSize, port, ip, ipSize, pid, tcpState = 56, 20, 0, 16, 52, 48
|
||||||
|
}
|
||||||
|
case Network_UDP:
|
||||||
|
if family == AddressFamilyIPv4 {
|
||||||
|
// struct MIB_UDPROW_OWNER_PID
|
||||||
|
itemSize, port, ip, ipSize, pid = 12, 4, 0, 4, 8
|
||||||
|
}
|
||||||
|
if family == AddressFamilyIPv6 {
|
||||||
|
// struct MIB_UDP6ROW_OWNER_PID
|
||||||
|
itemSize, port, ip, ipSize, pid = 28, 20, 0, 16, 24
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &searcher{
|
||||||
|
itemSize: itemSize,
|
||||||
|
port: port,
|
||||||
|
ip: ip,
|
||||||
|
ipSize: ipSize,
|
||||||
|
pid: pid,
|
||||||
|
tcpState: tcpState,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTransportTable(fn uintptr, family int, class int) ([]byte, error) {
|
||||||
|
for size, buf := uint32(8), make([]byte, 8); ; {
|
||||||
|
ptr := unsafe.Pointer(&buf[0])
|
||||||
|
err, _, _ := syscall.Syscall6(fn, 6, uintptr(ptr), uintptr(unsafe.Pointer(&size)), 0, uintptr(family), uintptr(class), 0)
|
||||||
|
|
||||||
|
switch err {
|
||||||
|
case 0:
|
||||||
|
return buf, nil
|
||||||
|
case uintptr(syscall.ERROR_INSUFFICIENT_BUFFER):
|
||||||
|
buf = make([]byte, size)
|
||||||
|
default:
|
||||||
|
return nil, errors.New("syscall error: ", int(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readNativeUint32(b []byte) uint32 {
|
||||||
|
return *(*uint32)(unsafe.Pointer(&b[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getExecPathFromPID(pid uint32) (string, error) {
|
||||||
|
// kernel process starts with a colon in order to distinguish with normal processes
|
||||||
|
switch pid {
|
||||||
|
case 0:
|
||||||
|
// reserved pid for system idle process
|
||||||
|
return ":System Idle Process", nil
|
||||||
|
case 4:
|
||||||
|
// reserved pid for windows kernel image
|
||||||
|
return ":System", nil
|
||||||
|
}
|
||||||
|
h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, pid)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer windows.CloseHandle(h)
|
||||||
|
|
||||||
|
buf := make([]uint16, syscall.MAX_LONG_PATH)
|
||||||
|
size := uint32(len(buf))
|
||||||
|
err = windows.QueryFullProcessImageName(h, 0, &buf[0], &size)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return syscall.UTF16ToString(buf[:size]), nil
|
||||||
|
}
|
||||||
+41
-1
@@ -1,7 +1,13 @@
|
|||||||
// Package net is a drop-in replacement to Golang's net package, with some more functionalities.
|
// Package net is a drop-in replacement to Golang's net package, with some more functionalities.
|
||||||
package net // import "github.com/xtls/xray-core/common/net"
|
package net // import "github.com/xtls/xray-core/common/net"
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"net"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
)
|
||||||
|
|
||||||
// defines the maximum time an idle TCP session can survive in the tunnel, so
|
// defines the maximum time an idle TCP session can survive in the tunnel, so
|
||||||
// it should be consistent across HTTP versions and with other transports.
|
// it should be consistent across HTTP versions and with other transports.
|
||||||
@@ -12,3 +18,37 @@ const QuicgoH3KeepAlivePeriod = 10 * time.Second
|
|||||||
|
|
||||||
// consistent with chrome
|
// consistent with chrome
|
||||||
const ChromeH2KeepAlivePeriod = 45 * time.Second
|
const ChromeH2KeepAlivePeriod = 45 * time.Second
|
||||||
|
|
||||||
|
var ErrNotLocal = errors.New("the source address is not from local machine.")
|
||||||
|
|
||||||
|
type localIPCacheEntry struct {
|
||||||
|
addrs []net.Addr
|
||||||
|
lastUpdate time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
var localIPCache = atomic.Pointer[localIPCacheEntry]{}
|
||||||
|
|
||||||
|
func IsLocal(ip net.IP) (bool, error) {
|
||||||
|
var addrs []net.Addr
|
||||||
|
if entry := localIPCache.Load(); entry == nil || time.Since(entry.lastUpdate) > time.Minute {
|
||||||
|
var err error
|
||||||
|
addrs, err = net.InterfaceAddrs()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
localIPCache.Store(&localIPCacheEntry{
|
||||||
|
addrs: addrs,
|
||||||
|
lastUpdate: time.Now(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
addrs = entry.addrs
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if ipnet, ok := addr.(*net.IPNet); ok {
|
||||||
|
if ipnet.IP.Equal(ip) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -87,6 +87,16 @@ func PortListFromProto(l *PortList) MemoryPortList {
|
|||||||
return mpl
|
return mpl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *PortList) Ports() []uint32 {
|
||||||
|
var ports []uint32
|
||||||
|
for _, r := range l.Range {
|
||||||
|
for i := uint32(r.From); i <= uint32(r.To); i++ {
|
||||||
|
ports = append(ports, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ports
|
||||||
|
}
|
||||||
|
|
||||||
func (mpl MemoryPortList) Contains(port Port) bool {
|
func (mpl MemoryPortList) Contains(port Port) bool {
|
||||||
for _, pr := range mpl {
|
for _, pr := range mpl {
|
||||||
if pr.Contains(port) {
|
if pr.Contains(port) {
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ var (
|
|||||||
|
|
||||||
type ListenConfig = net.ListenConfig
|
type ListenConfig = net.ListenConfig
|
||||||
|
|
||||||
|
type KeepAliveConfig = net.KeepAliveConfig
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Listen = net.Listen
|
Listen = net.Listen
|
||||||
ListenTCP = net.ListenTCP
|
ListenTCP = net.ListenTCP
|
||||||
@@ -26,6 +28,12 @@ var FileConn = net.FileConn
|
|||||||
// ParseIP is an alias of net.ParseIP
|
// ParseIP is an alias of net.ParseIP
|
||||||
var ParseIP = net.ParseIP
|
var ParseIP = net.ParseIP
|
||||||
|
|
||||||
|
var ParseCIDR = net.ParseCIDR
|
||||||
|
|
||||||
|
var ResolveIPAddr = net.ResolveIPAddr
|
||||||
|
|
||||||
|
var InterfaceByName = net.InterfaceByName
|
||||||
|
|
||||||
var SplitHostPort = net.SplitHostPort
|
var SplitHostPort = net.SplitHostPort
|
||||||
|
|
||||||
var CIDRMask = net.CIDRMask
|
var CIDRMask = net.CIDRMask
|
||||||
@@ -51,6 +59,8 @@ type (
|
|||||||
UnixConn = net.UnixConn
|
UnixConn = net.UnixConn
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type IPAddr = net.IPAddr
|
||||||
|
|
||||||
// IP is an alias for net.IP.
|
// IP is an alias for net.IP.
|
||||||
type (
|
type (
|
||||||
IP = net.IP
|
IP = net.IP
|
||||||
@@ -82,3 +92,11 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Resolver = net.Resolver
|
type Resolver = net.Resolver
|
||||||
|
|
||||||
|
var DefaultResolver = net.DefaultResolver
|
||||||
|
|
||||||
|
var JoinHostPort = net.JoinHostPort
|
||||||
|
|
||||||
|
var InterfaceAddrs = net.InterfaceAddrs
|
||||||
|
|
||||||
|
var Interfaces = net.Interfaces
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
//go:build !windows
|
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package ctlcmd
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
func getSysProcAttr() *syscall.SysProcAttr {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package ctlcmd
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
func getSysProcAttr() *syscall.SysProcAttr {
|
|
||||||
return &syscall.SysProcAttr{
|
|
||||||
HideWindow: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
package ctlcmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/buf"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/platform"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Run(args []string, input io.Reader) (buf.MultiBuffer, error) {
|
|
||||||
xctl := platform.GetToolLocation("xctl")
|
|
||||||
if _, err := os.Stat(xctl); err != nil {
|
|
||||||
return nil, errors.New("xctl doesn't exist").Base(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var errBuffer buf.MultiBufferContainer
|
|
||||||
var outBuffer buf.MultiBufferContainer
|
|
||||||
|
|
||||||
cmd := exec.Command(xctl, args...)
|
|
||||||
cmd.Stderr = &errBuffer
|
|
||||||
cmd.Stdout = &outBuffer
|
|
||||||
cmd.SysProcAttr = getSysProcAttr()
|
|
||||||
if input != nil {
|
|
||||||
cmd.Stdin = input
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return nil, errors.New("failed to start xctl").Base(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cmd.Wait(); err != nil {
|
|
||||||
msg := "failed to execute xctl"
|
|
||||||
if errBuffer.Len() > 0 {
|
|
||||||
msg += ": \n" + strings.TrimSpace(errBuffer.MultiBuffer.String())
|
|
||||||
}
|
|
||||||
return nil, errors.New(msg).Base(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// log stderr, info message
|
|
||||||
if !errBuffer.IsEmpty() {
|
|
||||||
errors.LogInfo(context.Background(), "<xctl message> \n", strings.TrimSpace(errBuffer.MultiBuffer.String()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return outBuffer.MultiBuffer, nil
|
|
||||||
}
|
|
||||||
@@ -8,19 +8,10 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExpandEnv(s string) string {
|
|
||||||
return os.ExpandEnv(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LineSeparator() string {
|
func LineSeparator() string {
|
||||||
return "\n"
|
return "\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetToolLocation(file string) string {
|
|
||||||
toolPath := NewEnvFlag(ToolLocation).GetValue(getExecutableDir)
|
|
||||||
return filepath.Join(toolPath, file)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAssetLocation searches for `file` in the env dir, the executable dir, and certain locations
|
// GetAssetLocation searches for `file` in the env dir, the executable dir, and certain locations
|
||||||
func GetAssetLocation(file string) string {
|
func GetAssetLocation(file string) string {
|
||||||
assetPath := NewEnvFlag(AssetLocation).GetValue(getExecutableDir)
|
assetPath := NewEnvFlag(AssetLocation).GetValue(getExecutableDir)
|
||||||
|
|||||||
@@ -8,10 +8,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PluginLocation = "xray.location.plugin"
|
|
||||||
ConfigLocation = "xray.location.config"
|
ConfigLocation = "xray.location.config"
|
||||||
ConfdirLocation = "xray.location.confdir"
|
ConfdirLocation = "xray.location.confdir"
|
||||||
ToolLocation = "xray.location.tool"
|
|
||||||
AssetLocation = "xray.location.asset"
|
AssetLocation = "xray.location.asset"
|
||||||
CertLocation = "xray.location.cert"
|
CertLocation = "xray.location.cert"
|
||||||
|
|
||||||
@@ -24,6 +22,8 @@ const (
|
|||||||
BrowserDialerAddress = "xray.browser.dialer"
|
BrowserDialerAddress = "xray.browser.dialer"
|
||||||
XUDPLog = "xray.xudp.show"
|
XUDPLog = "xray.xudp.show"
|
||||||
XUDPBaseKey = "xray.xudp.basekey"
|
XUDPBaseKey = "xray.xudp.basekey"
|
||||||
|
|
||||||
|
TunFdKey = "xray.tun.fd"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EnvFlag struct {
|
type EnvFlag struct {
|
||||||
@@ -79,17 +79,6 @@ func getExecutableDir() string {
|
|||||||
return filepath.Dir(exec)
|
return filepath.Dir(exec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExecutableSubDir(dir string) func() string {
|
|
||||||
return func() string {
|
|
||||||
return filepath.Join(getExecutableDir(), dir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetPluginDirectory() string {
|
|
||||||
pluginDir := NewEnvFlag(PluginLocation).GetValue(getExecutableSubDir("plugins"))
|
|
||||||
return pluginDir
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetConfigurationPath() string {
|
func GetConfigurationPath() string {
|
||||||
configPath := NewEnvFlag(ConfigLocation).GetValue(getExecutableDir)
|
configPath := NewEnvFlag(ConfigLocation).GetValue(getExecutableDir)
|
||||||
return filepath.Join(configPath, "config.json")
|
return filepath.Join(configPath, "config.json")
|
||||||
|
|||||||
@@ -5,20 +5,10 @@ package platform
|
|||||||
|
|
||||||
import "path/filepath"
|
import "path/filepath"
|
||||||
|
|
||||||
func ExpandEnv(s string) string {
|
|
||||||
// TODO
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func LineSeparator() string {
|
func LineSeparator() string {
|
||||||
return "\r\n"
|
return "\r\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetToolLocation(file string) string {
|
|
||||||
toolPath := NewEnvFlag(ToolLocation).GetValue(getExecutableDir)
|
|
||||||
return filepath.Join(toolPath, file+".exe")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAssetLocation searches for `file` in the env dir and the executable dir
|
// GetAssetLocation searches for `file` in the env dir and the executable dir
|
||||||
func GetAssetLocation(file string) string {
|
func GetAssetLocation(file string) string {
|
||||||
assetPath := NewEnvFlag(AssetLocation).GetValue(getExecutableDir)
|
assetPath := NewEnvFlag(AssetLocation).GetValue(getExecutableDir)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/quic-go/quic-go/quicvarint"
|
"github.com/apernet/quic-go/quicvarint"
|
||||||
"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"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ package singbridge
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
B "github.com/sagernet/sing/common/buf"
|
B "github.com/sagernet/sing/common/buf"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/transport"
|
"github.com/xtls/xray-core/transport"
|
||||||
@@ -29,6 +31,8 @@ type PacketConnWrapper struct {
|
|||||||
cached buf.MultiBuffer
|
cached buf.MultiBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This ReadPacket implemented a timeout to avoid goroutine leak like PipeConnWrapper.Read()
|
||||||
|
// as a temporarily solution
|
||||||
func (w *PacketConnWrapper) ReadPacket(buffer *B.Buffer) (M.Socksaddr, error) {
|
func (w *PacketConnWrapper) ReadPacket(buffer *B.Buffer) (M.Socksaddr, error) {
|
||||||
if w.cached != nil {
|
if w.cached != nil {
|
||||||
mb, bb := buf.SplitFirst(w.cached)
|
mb, bb := buf.SplitFirst(w.cached)
|
||||||
@@ -47,10 +51,30 @@ func (w *PacketConnWrapper) ReadPacket(buffer *B.Buffer) (M.Socksaddr, error) {
|
|||||||
return ToSocksaddr(destination), nil
|
return ToSocksaddr(destination), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mb, err := w.ReadMultiBuffer()
|
|
||||||
if err != nil {
|
// timeout
|
||||||
return M.Socksaddr{}, err
|
type readResult struct {
|
||||||
|
mb buf.MultiBuffer
|
||||||
|
err error
|
||||||
}
|
}
|
||||||
|
c := make(chan readResult, 1)
|
||||||
|
go func() {
|
||||||
|
mb, err := w.ReadMultiBuffer()
|
||||||
|
c <- readResult{mb: mb, err: err}
|
||||||
|
}()
|
||||||
|
var mb buf.MultiBuffer
|
||||||
|
select {
|
||||||
|
case <-time.After(60 * time.Second):
|
||||||
|
common.Close(w.Reader)
|
||||||
|
common.Interrupt(w.Reader)
|
||||||
|
return M.Socksaddr{}, buf.ErrReadTimeout
|
||||||
|
case result := <-c:
|
||||||
|
if result.err != nil {
|
||||||
|
return M.Socksaddr{}, result.err
|
||||||
|
}
|
||||||
|
mb = result.mb
|
||||||
|
}
|
||||||
|
|
||||||
nb, bb := buf.SplitFirst(mb)
|
nb, bb := buf.SplitFirst(mb)
|
||||||
if bb == nil {
|
if bb == nil {
|
||||||
return M.Socksaddr{}, nil
|
return M.Socksaddr{}, nil
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package strmatcher
|
package strmatcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"regexp"
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ func (t Type) New(pattern string) (Matcher, error) {
|
|||||||
pattern: r,
|
pattern: r,
|
||||||
}, nil
|
}, nil
|
||||||
default:
|
default:
|
||||||
panic("Unknown type")
|
return nil, errors.New("unk type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -85,10 +85,14 @@ func ParseString(str string) (UUID, error) {
|
|||||||
b := uuid.Bytes()
|
b := uuid.Bytes()
|
||||||
|
|
||||||
for _, byteGroup := range byteGroups {
|
for _, byteGroup := range byteGroups {
|
||||||
if text[0] == '-' {
|
if len(text) > 0 && text[0] == '-' {
|
||||||
text = text[1:]
|
text = text[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(text) < byteGroup {
|
||||||
|
return uuid, errors.New("invalid UUID: ", str)
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := hex.Decode(b[:byteGroup/2], text[:byteGroup]); err != nil {
|
if _, err := hex.Decode(b[:byteGroup/2], text[:byteGroup]); err != nil {
|
||||||
return uuid, err
|
return uuid, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ func TestParseString(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Expect error but nil")
|
t.Fatal("Expect error but nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = ParseString("2418d087-648d-4990-86e8-19dca1d0")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Expect error but nil")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewUUID(t *testing.T) {
|
func TestNewUUID(t *testing.T) {
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ func GetGlobalID(ctx context.Context) (globalID [8]byte) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.Network == net.Network_UDP &&
|
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.Network == net.Network_UDP &&
|
||||||
(inbound.Name == "dokodemo-door" || inbound.Name == "socks" || inbound.Name == "shadowsocks") {
|
(inbound.Name == "dokodemo-door" || inbound.Name == "socks" || inbound.Name == "shadowsocks" || inbound.Name == "tun") {
|
||||||
h := blake3.New(8, BaseKey)
|
h := blake3.New(8, BaseKey)
|
||||||
h.Write([]byte(inbound.Source.String()))
|
h.Write([]byte(inbound.Source.String()))
|
||||||
copy(globalID[:], h.Sum(nil))
|
copy(globalID[:], h.Sum(nil))
|
||||||
|
|||||||
+7
-3
@@ -64,7 +64,11 @@ func GetMergedConfig(args cmdarg.Arg) (string, error) {
|
|||||||
var files []*ConfigSource
|
var files []*ConfigSource
|
||||||
supported := []string{"json", "yaml", "toml"}
|
supported := []string{"json", "yaml", "toml"}
|
||||||
for _, file := range args {
|
for _, file := range args {
|
||||||
format := getFormat(file)
|
format := "json"
|
||||||
|
if file != "stdin:" {
|
||||||
|
format = GetFormat(file)
|
||||||
|
}
|
||||||
|
|
||||||
if slices.Contains(supported, format) {
|
if slices.Contains(supported, format) {
|
||||||
files = append(files, &ConfigSource{
|
files = append(files, &ConfigSource{
|
||||||
Name: file,
|
Name: file,
|
||||||
@@ -98,7 +102,7 @@ func getExtension(filename string) string {
|
|||||||
return filename[idx+1:]
|
return filename[idx+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFormat(filename string) string {
|
func GetFormat(filename string) string {
|
||||||
return GetFormatByExtension(getExtension(filename))
|
return GetFormatByExtension(getExtension(filename))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +116,7 @@ func LoadConfig(formatName string, input interface{}) (*Config, error) {
|
|||||||
|
|
||||||
if formatName == "auto" {
|
if formatName == "auto" {
|
||||||
if file != "stdin:" {
|
if file != "stdin:" {
|
||||||
f = getFormat(file)
|
f = GetFormat(file)
|
||||||
} else {
|
} else {
|
||||||
f = "json"
|
f = "json"
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -17,9 +17,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Version_x byte = 25
|
Version_x byte = 26
|
||||||
Version_y byte = 10
|
Version_y byte = 1
|
||||||
Version_z byte = 15
|
Version_z byte = 23
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ type Router interface {
|
|||||||
PickRoute(ctx Context) (Route, error)
|
PickRoute(ctx Context) (Route, error)
|
||||||
AddRule(config *serial.TypedMessage, shouldAppend bool) error
|
AddRule(config *serial.TypedMessage, shouldAppend bool) error
|
||||||
RemoveRule(tag string) error
|
RemoveRule(tag string) error
|
||||||
|
ListRule() []Route
|
||||||
}
|
}
|
||||||
|
|
||||||
// Route is the routing result of Router feature.
|
// Route is the routing result of Router feature.
|
||||||
@@ -65,6 +66,11 @@ func (DefaultRouter) RemoveRule(tag string) error {
|
|||||||
return common.ErrNoClue
|
return common.ErrNoClue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListRule implements Router.
|
||||||
|
func (DefaultRouter) ListRule() []Route {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Start implements common.Runnable.
|
// Start implements common.Runnable.
|
||||||
func (DefaultRouter) Start() error {
|
func (DefaultRouter) Start() error {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -98,6 +98,9 @@ type Manager interface {
|
|||||||
UnregisterChannel(string) error
|
UnregisterChannel(string) error
|
||||||
// GetChannel returns a channel by its identifier.
|
// GetChannel returns a channel by its identifier.
|
||||||
GetChannel(string) Channel
|
GetChannel(string) Channel
|
||||||
|
|
||||||
|
// GetAllOnlineUsers returns all online users from all OnlineMaps.
|
||||||
|
GetAllOnlineUsers() []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrRegisterCounter tries to get the StatCounter first. If not exist, it then tries to create a new counter.
|
// GetOrRegisterCounter tries to get the StatCounter first. If not exist, it then tries to create a new counter.
|
||||||
@@ -190,6 +193,11 @@ func (NoopManager) GetChannel(string) Channel {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAllOnlineUsers implements Manager.
|
||||||
|
func (NoopManager) GetAllOnlineUsers() []string {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Start implements common.Runnable.
|
// Start implements common.Runnable.
|
||||||
func (NoopManager) Start() error { return nil }
|
func (NoopManager) Start() error { return nil }
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
module github.com/xtls/xray-core
|
module github.com/xtls/xray-core
|
||||||
|
|
||||||
go 1.25
|
go 1.25.6
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cloudflare/circl v1.6.1
|
github.com/apernet/quic-go v0.57.2-0.20260111184307-eec823306178
|
||||||
|
github.com/cloudflare/circl v1.6.3
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
||||||
github.com/golang/mock v1.7.0-rc.1
|
github.com/golang/mock v1.7.0-rc.1
|
||||||
github.com/google/go-cmp v0.7.0
|
github.com/google/go-cmp v0.7.0
|
||||||
github.com/gorilla/websocket v1.5.3
|
github.com/gorilla/websocket v1.5.3
|
||||||
github.com/miekg/dns v1.1.68
|
github.com/miekg/dns v1.1.72
|
||||||
github.com/pelletier/go-toml v1.9.5
|
github.com/pelletier/go-toml v1.9.5
|
||||||
github.com/pires/go-proxyproto v0.8.1
|
github.com/pires/go-proxyproto v0.9.0
|
||||||
github.com/quic-go/quic-go v0.55.0
|
github.com/refraction-networking/utls v1.8.2
|
||||||
github.com/refraction-networking/utls v1.8.1
|
|
||||||
github.com/sagernet/sing v0.5.1
|
github.com/sagernet/sing v0.5.1
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771
|
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771
|
||||||
@@ -21,14 +21,16 @@ require (
|
|||||||
github.com/vishvananda/netlink v1.3.1
|
github.com/vishvananda/netlink v1.3.1
|
||||||
github.com/xtls/reality v0.0.0-20251014195629-e4eec4520535
|
github.com/xtls/reality v0.0.0-20251014195629-e4eec4520535
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||||
golang.org/x/crypto v0.43.0
|
golang.org/x/crypto v0.47.0
|
||||||
golang.org/x/net v0.46.0
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
||||||
golang.org/x/sync v0.17.0
|
golang.org/x/net v0.49.0
|
||||||
golang.org/x/sys v0.37.0
|
golang.org/x/sync v0.19.0
|
||||||
|
golang.org/x/sys v0.40.0
|
||||||
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||||
google.golang.org/grpc v1.76.0
|
google.golang.org/grpc v1.78.0
|
||||||
google.golang.org/protobuf v1.36.10
|
google.golang.org/protobuf v1.36.11
|
||||||
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5
|
gvisor.dev/gvisor v0.0.0-20260109181451-4be7c433dae2
|
||||||
h12.io/socks v1.0.3
|
h12.io/socks v1.0.3
|
||||||
lukechampine.com/blake3 v1.4.1
|
lukechampine.com/blake3 v1.4.1
|
||||||
)
|
)
|
||||||
@@ -41,17 +43,16 @@ require (
|
|||||||
github.com/juju/ratelimit v1.0.2 // indirect
|
github.com/juju/ratelimit v1.0.2 // indirect
|
||||||
github.com/klauspost/compress v1.17.4 // indirect
|
github.com/klauspost/compress v1.17.4 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
|
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
|
||||||
github.com/kr/pretty v0.3.1 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/quic-go/qpack v0.5.1 // indirect
|
github.com/quic-go/qpack v0.6.0 // indirect
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||||
github.com/vishvananda/netns v0.0.5 // indirect
|
github.com/vishvananda/netns v0.0.5 // indirect
|
||||||
golang.org/x/mod v0.28.0 // indirect
|
golang.org/x/mod v0.31.0 // indirect
|
||||||
golang.org/x/text v0.30.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
golang.org/x/time v0.7.0 // indirect
|
golang.org/x/time v0.12.0 // indirect
|
||||||
golang.org/x/tools v0.37.0 // indirect
|
golang.org/x/tools v0.40.0 // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
github.com/apernet/quic-go v0.57.2-0.20260111184307-eec823306178 h1:bSq8n+gX4oO/qnM3MKf4kroW75n+phO9Qp6nigJKZ1E=
|
||||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
github.com/apernet/quic-go v0.57.2-0.20260111184307-eec823306178/go.mod h1:N1WIjPphkqs4efXWuyDNQ6OjjIK04vM3h+bEgwV+eVU=
|
||||||
|
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
||||||
|
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
@@ -38,27 +40,24 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
|||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
|
github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
|
||||||
github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
|
github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
|
||||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
|
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
|
||||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||||
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
github.com/pires/go-proxyproto v0.9.0 h1:3Qg3CLxWx4wJOw5uxhTvc0VrgsJeerDbGTvexu4UK1E=
|
||||||
github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
github.com/pires/go-proxyproto v0.9.0/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||||
github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
|
github.com/refraction-networking/utls v1.8.2 h1:j4Q1gJj0xngdeH+Ox/qND11aEfhpgoEvV+S9iJ2IdQo=
|
||||||
github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
|
github.com/refraction-networking/utls v1.8.2/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
||||||
github.com/refraction-networking/utls v1.8.1 h1:yNY1kapmQU8JeM1sSw2H2asfTIwWxIkrMJI0pRUOCAo=
|
|
||||||
github.com/refraction-networking/utls v1.8.1/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||||
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
||||||
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||||
@@ -78,38 +77,40 @@ github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZla
|
|||||||
github.com/xtls/reality v0.0.0-20251014195629-e4eec4520535 h1:nwobseOLLRtdbP6z7Z2aVI97u8ZptTgD1ofovhAKmeU=
|
github.com/xtls/reality v0.0.0-20251014195629-e4eec4520535 h1:nwobseOLLRtdbP6z7Z2aVI97u8ZptTgD1ofovhAKmeU=
|
||||||
github.com/xtls/reality v0.0.0-20251014195629-e4eec4520535/go.mod h1:vbHCV/3VWUvy1oKvTxxWJRPEWSeR1sYgQHIh6u/JiZQ=
|
github.com/xtls/reality v0.0.0-20251014195629-e4eec4520535/go.mod h1:vbHCV/3VWUvy1oKvTxxWJRPEWSeR1sYgQHIh6u/JiZQ=
|
||||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
|
||||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
|
||||||
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
||||||
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||||
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
|
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
|
||||||
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
|
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -117,21 +118,21 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
|
||||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
|
||||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||||
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
|
||||||
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -141,12 +142,12 @@ golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uI
|
|||||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda h1:i/Q+bfisr7gq6feoJnS/DlpdwEL4ihp41fvRiM3Ork0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||||
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
@@ -157,8 +158,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5 h1:sfK5nHuG7lRFZ2FdTT3RimOqWBg8IrVm+/Vko1FVOsk=
|
gvisor.dev/gvisor v0.0.0-20260109181451-4be7c433dae2 h1:fr6L00yGG2RP5NMea6njWpdC+bm+cMdFClrSpaicp1c=
|
||||||
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5/go.mod h1:3r5CMtNQMKIvBlrmM9xWUNamjKBYPOWyXOjmg5Kts3g=
|
gvisor.dev/gvisor v0.0.0-20260109181451-4be7c433dae2/go.mod h1:QkHjoMIBaYtpVufgwv3keYAbln78mBoCuShZrPrer1Q=
|
||||||
h12.io/socks v1.0.3 h1:Ka3qaQewws4j4/eDQnOdpr4wXsC//dXtWvftlIcCQUo=
|
h12.io/socks v1.0.3 h1:Ka3qaQewws4j4/eDQnOdpr4wXsC//dXtWvftlIcCQUo=
|
||||||
h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
|
h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
|
||||||
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
|
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
|
||||||
|
|||||||
+107
-26
@@ -16,19 +16,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type NameServerConfig struct {
|
type NameServerConfig struct {
|
||||||
Address *Address `json:"address"`
|
Address *Address `json:"address"`
|
||||||
ClientIP *Address `json:"clientIp"`
|
ClientIP *Address `json:"clientIp"`
|
||||||
Port uint16 `json:"port"`
|
Port uint16 `json:"port"`
|
||||||
SkipFallback bool `json:"skipFallback"`
|
SkipFallback bool `json:"skipFallback"`
|
||||||
Domains []string `json:"domains"`
|
Domains []string `json:"domains"`
|
||||||
ExpectedIPs StringList `json:"expectedIPs"`
|
ExpectedIPs StringList `json:"expectedIPs"`
|
||||||
ExpectIPs StringList `json:"expectIPs"`
|
ExpectIPs StringList `json:"expectIPs"`
|
||||||
QueryStrategy string `json:"queryStrategy"`
|
QueryStrategy string `json:"queryStrategy"`
|
||||||
Tag string `json:"tag"`
|
Tag string `json:"tag"`
|
||||||
TimeoutMs uint64 `json:"timeoutMs"`
|
TimeoutMs uint64 `json:"timeoutMs"`
|
||||||
DisableCache bool `json:"disableCache"`
|
DisableCache *bool `json:"disableCache"`
|
||||||
FinalQuery bool `json:"finalQuery"`
|
ServeStale *bool `json:"serveStale"`
|
||||||
UnexpectedIPs StringList `json:"unexpectedIPs"`
|
ServeExpiredTTL *uint32 `json:"serveExpiredTTL"`
|
||||||
|
FinalQuery bool `json:"finalQuery"`
|
||||||
|
UnexpectedIPs StringList `json:"unexpectedIPs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||||
@@ -40,19 +42,21 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var advanced struct {
|
var advanced struct {
|
||||||
Address *Address `json:"address"`
|
Address *Address `json:"address"`
|
||||||
ClientIP *Address `json:"clientIp"`
|
ClientIP *Address `json:"clientIp"`
|
||||||
Port uint16 `json:"port"`
|
Port uint16 `json:"port"`
|
||||||
SkipFallback bool `json:"skipFallback"`
|
SkipFallback bool `json:"skipFallback"`
|
||||||
Domains []string `json:"domains"`
|
Domains []string `json:"domains"`
|
||||||
ExpectedIPs StringList `json:"expectedIPs"`
|
ExpectedIPs StringList `json:"expectedIPs"`
|
||||||
ExpectIPs StringList `json:"expectIPs"`
|
ExpectIPs StringList `json:"expectIPs"`
|
||||||
QueryStrategy string `json:"queryStrategy"`
|
QueryStrategy string `json:"queryStrategy"`
|
||||||
Tag string `json:"tag"`
|
Tag string `json:"tag"`
|
||||||
TimeoutMs uint64 `json:"timeoutMs"`
|
TimeoutMs uint64 `json:"timeoutMs"`
|
||||||
DisableCache bool `json:"disableCache"`
|
DisableCache *bool `json:"disableCache"`
|
||||||
FinalQuery bool `json:"finalQuery"`
|
ServeStale *bool `json:"serveStale"`
|
||||||
UnexpectedIPs StringList `json:"unexpectedIPs"`
|
ServeExpiredTTL *uint32 `json:"serveExpiredTTL"`
|
||||||
|
FinalQuery bool `json:"finalQuery"`
|
||||||
|
UnexpectedIPs StringList `json:"unexpectedIPs"`
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(data, &advanced); err == nil {
|
if err := json.Unmarshal(data, &advanced); err == nil {
|
||||||
c.Address = advanced.Address
|
c.Address = advanced.Address
|
||||||
@@ -66,6 +70,8 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
|
|||||||
c.Tag = advanced.Tag
|
c.Tag = advanced.Tag
|
||||||
c.TimeoutMs = advanced.TimeoutMs
|
c.TimeoutMs = advanced.TimeoutMs
|
||||||
c.DisableCache = advanced.DisableCache
|
c.DisableCache = advanced.DisableCache
|
||||||
|
c.ServeStale = advanced.ServeStale
|
||||||
|
c.ServeExpiredTTL = advanced.ServeExpiredTTL
|
||||||
c.FinalQuery = advanced.FinalQuery
|
c.FinalQuery = advanced.FinalQuery
|
||||||
c.UnexpectedIPs = advanced.UnexpectedIPs
|
c.UnexpectedIPs = advanced.UnexpectedIPs
|
||||||
return nil
|
return nil
|
||||||
@@ -173,6 +179,8 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
|
|||||||
Tag: c.Tag,
|
Tag: c.Tag,
|
||||||
TimeoutMs: c.TimeoutMs,
|
TimeoutMs: c.TimeoutMs,
|
||||||
DisableCache: c.DisableCache,
|
DisableCache: c.DisableCache,
|
||||||
|
ServeStale: c.ServeStale,
|
||||||
|
ServeExpiredTTL: c.ServeExpiredTTL,
|
||||||
FinalQuery: c.FinalQuery,
|
FinalQuery: c.FinalQuery,
|
||||||
UnexpectedGeoip: unexpectedGeoipList,
|
UnexpectedGeoip: unexpectedGeoipList,
|
||||||
ActUnprior: actUnprior,
|
ActUnprior: actUnprior,
|
||||||
@@ -194,8 +202,11 @@ type DNSConfig struct {
|
|||||||
Tag string `json:"tag"`
|
Tag string `json:"tag"`
|
||||||
QueryStrategy string `json:"queryStrategy"`
|
QueryStrategy string `json:"queryStrategy"`
|
||||||
DisableCache bool `json:"disableCache"`
|
DisableCache bool `json:"disableCache"`
|
||||||
|
ServeStale bool `json:"serveStale"`
|
||||||
|
ServeExpiredTTL uint32 `json:"serveExpiredTTL"`
|
||||||
DisableFallback bool `json:"disableFallback"`
|
DisableFallback bool `json:"disableFallback"`
|
||||||
DisableFallbackIfMatch bool `json:"disableFallbackIfMatch"`
|
DisableFallbackIfMatch bool `json:"disableFallbackIfMatch"`
|
||||||
|
EnableParallelQuery bool `json:"enableParallelQuery"`
|
||||||
UseSystemHosts bool `json:"useSystemHosts"`
|
UseSystemHosts bool `json:"useSystemHosts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,8 +402,11 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
|
|||||||
config := &dns.Config{
|
config := &dns.Config{
|
||||||
Tag: c.Tag,
|
Tag: c.Tag,
|
||||||
DisableCache: c.DisableCache,
|
DisableCache: c.DisableCache,
|
||||||
|
ServeStale: c.ServeStale,
|
||||||
|
ServeExpiredTTL: c.ServeExpiredTTL,
|
||||||
DisableFallback: c.DisableFallback,
|
DisableFallback: c.DisableFallback,
|
||||||
DisableFallbackIfMatch: c.DisableFallbackIfMatch,
|
DisableFallbackIfMatch: c.DisableFallbackIfMatch,
|
||||||
|
EnableParallelQuery: c.EnableParallelQuery,
|
||||||
QueryStrategy: resolveQueryStrategy(c.QueryStrategy),
|
QueryStrategy: resolveQueryStrategy(c.QueryStrategy),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,11 +417,78 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
|
|||||||
config.ClientIp = []byte(c.ClientIP.IP())
|
config.ClientIp = []byte(c.ClientIP.IP())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build PolicyID
|
||||||
|
policyMap := map[string]uint32{}
|
||||||
|
nextPolicyID := uint32(1)
|
||||||
|
buildPolicyID := func(nsc *NameServerConfig) uint32 {
|
||||||
|
var sb strings.Builder
|
||||||
|
|
||||||
|
// ClientIP
|
||||||
|
if nsc.ClientIP != nil {
|
||||||
|
sb.WriteString("client=")
|
||||||
|
sb.WriteString(nsc.ClientIP.String())
|
||||||
|
sb.WriteByte('|')
|
||||||
|
} else {
|
||||||
|
sb.WriteString("client=none|")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SkipFallback
|
||||||
|
if nsc.SkipFallback {
|
||||||
|
sb.WriteString("skip=1|")
|
||||||
|
} else {
|
||||||
|
sb.WriteString("skip=0|")
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryStrategy
|
||||||
|
sb.WriteString("qs=")
|
||||||
|
sb.WriteString(strings.ToLower(strings.TrimSpace(nsc.QueryStrategy)))
|
||||||
|
sb.WriteByte('|')
|
||||||
|
|
||||||
|
// Tag
|
||||||
|
sb.WriteString("tag=")
|
||||||
|
sb.WriteString(strings.ToLower(strings.TrimSpace(nsc.Tag)))
|
||||||
|
sb.WriteByte('|')
|
||||||
|
|
||||||
|
// []string helper
|
||||||
|
writeList := func(tag string, lst []string) {
|
||||||
|
if len(lst) == 0 {
|
||||||
|
sb.WriteString(tag)
|
||||||
|
sb.WriteString("=[]|")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cp := make([]string, len(lst))
|
||||||
|
for i, s := range lst {
|
||||||
|
cp[i] = strings.TrimSpace(strings.ToLower(s))
|
||||||
|
}
|
||||||
|
sort.Strings(cp)
|
||||||
|
sb.WriteString(tag)
|
||||||
|
sb.WriteByte('=')
|
||||||
|
sb.WriteString(strings.Join(cp, ","))
|
||||||
|
sb.WriteByte('|')
|
||||||
|
}
|
||||||
|
|
||||||
|
writeList("domains", nsc.Domains)
|
||||||
|
writeList("expected", nsc.ExpectedIPs)
|
||||||
|
writeList("expect", nsc.ExpectIPs)
|
||||||
|
writeList("unexpected", nsc.UnexpectedIPs)
|
||||||
|
|
||||||
|
key := sb.String()
|
||||||
|
|
||||||
|
if id, ok := policyMap[key]; ok {
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
id := nextPolicyID
|
||||||
|
nextPolicyID++
|
||||||
|
policyMap[key] = id
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
for _, server := range c.Servers {
|
for _, server := range c.Servers {
|
||||||
ns, err := server.Build()
|
ns, err := server.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to build nameserver").Base(err)
|
return nil, errors.New("failed to build nameserver").Base(err)
|
||||||
}
|
}
|
||||||
|
ns.PolicyID = buildPolicyID(server)
|
||||||
config.NameServer = append(config.NameServer, ns)
|
config.NameServer = append(config.NameServer, ns)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-2
@@ -20,7 +20,8 @@ func TestDNSConfigParsing(t *testing.T) {
|
|||||||
return config.Build()
|
return config.Build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
expectedServeStale := true
|
||||||
|
expectedServeExpiredTTL := uint32(172800)
|
||||||
runMultiTestCase(t, []TestCase{
|
runMultiTestCase(t, []TestCase{
|
||||||
{
|
{
|
||||||
Input: `{
|
Input: `{
|
||||||
@@ -28,7 +29,9 @@ func TestDNSConfigParsing(t *testing.T) {
|
|||||||
"address": "8.8.8.8",
|
"address": "8.8.8.8",
|
||||||
"port": 5353,
|
"port": 5353,
|
||||||
"skipFallback": true,
|
"skipFallback": true,
|
||||||
"domains": ["domain:example.com"]
|
"domains": ["domain:example.com"],
|
||||||
|
"serveStale": true,
|
||||||
|
"serveExpiredTTL": 172800
|
||||||
}],
|
}],
|
||||||
"hosts": {
|
"hosts": {
|
||||||
"domain:example.com": "google.com",
|
"domain:example.com": "google.com",
|
||||||
@@ -40,6 +43,8 @@ func TestDNSConfigParsing(t *testing.T) {
|
|||||||
"clientIp": "10.0.0.1",
|
"clientIp": "10.0.0.1",
|
||||||
"queryStrategy": "UseIPv4",
|
"queryStrategy": "UseIPv4",
|
||||||
"disableCache": true,
|
"disableCache": true,
|
||||||
|
"serveStale": false,
|
||||||
|
"serveExpiredTTL": 86400,
|
||||||
"disableFallback": true
|
"disableFallback": true
|
||||||
}`,
|
}`,
|
||||||
Parser: parserCreator(),
|
Parser: parserCreator(),
|
||||||
@@ -68,6 +73,9 @@ func TestDNSConfigParsing(t *testing.T) {
|
|||||||
Size: 1,
|
Size: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ServeStale: &expectedServeStale,
|
||||||
|
ServeExpiredTTL: &expectedServeExpiredTTL,
|
||||||
|
PolicyID: 1, // Servers with certain identical fields share this ID, incrementing starting from 1. See: Build PolicyID
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
StaticHosts: []*dns.Config_HostMapping{
|
StaticHosts: []*dns.Config_HostMapping{
|
||||||
@@ -100,6 +108,8 @@ func TestDNSConfigParsing(t *testing.T) {
|
|||||||
ClientIp: []byte{10, 0, 0, 1},
|
ClientIp: []byte{10, 0, 0, 1},
|
||||||
QueryStrategy: dns.QueryStrategy_USE_IP4,
|
QueryStrategy: dns.QueryStrategy_USE_IP4,
|
||||||
DisableCache: true,
|
DisableCache: true,
|
||||||
|
ServeStale: false,
|
||||||
|
ServeExpiredTTL: 86400,
|
||||||
DisableFallback: true,
|
DisableFallback: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package conf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
|
"github.com/xtls/xray-core/proxy/hysteria"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HysteriaClientConfig struct {
|
||||||
|
Version int32 `json:"version"`
|
||||||
|
Address *Address `json:"address"`
|
||||||
|
Port uint16 `json:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *HysteriaClientConfig) Build() (proto.Message, error) {
|
||||||
|
if c.Version != 2 {
|
||||||
|
return nil, errors.New("version != 2")
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &hysteria.ClientConfig{}
|
||||||
|
config.Version = c.Version
|
||||||
|
config.Server = &protocol.ServerEndpoint{
|
||||||
|
Address: c.Address.Build(),
|
||||||
|
Port: uint32(c.Port),
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
@@ -83,8 +83,6 @@ func (c *RouterConfig) getDomainStrategy() router.Config_DomainStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch strings.ToLower(ds) {
|
switch strings.ToLower(ds) {
|
||||||
case "alwaysip":
|
|
||||||
return router.Config_UseIp
|
|
||||||
case "ipifnonmatch":
|
case "ipifnonmatch":
|
||||||
return router.Config_IpIfNonMatch
|
return router.Config_IpIfNonMatch
|
||||||
case "ipondemand":
|
case "ipondemand":
|
||||||
@@ -537,6 +535,7 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
|
|||||||
Attributes map[string]string `json:"attrs"`
|
Attributes map[string]string `json:"attrs"`
|
||||||
LocalIP *StringList `json:"localIP"`
|
LocalIP *StringList `json:"localIP"`
|
||||||
LocalPort *PortList `json:"localPort"`
|
LocalPort *PortList `json:"localPort"`
|
||||||
|
Process *StringList `json:"process"`
|
||||||
}
|
}
|
||||||
rawFieldRule := new(RawFieldRule)
|
rawFieldRule := new(RawFieldRule)
|
||||||
err := json.Unmarshal(msg, rawFieldRule)
|
err := json.Unmarshal(msg, rawFieldRule)
|
||||||
@@ -649,6 +648,10 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
|
|||||||
rule.Attributes = rawFieldRule.Attributes
|
rule.Attributes = rawFieldRule.Attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if rawFieldRule.Process != nil && len(*rawFieldRule.Process) > 0 {
|
||||||
|
rule.Process = *rawFieldRule.Process
|
||||||
|
}
|
||||||
|
|
||||||
return rule, nil
|
return rule, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ type ShadowsocksServerConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
|
func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
|
||||||
|
errors.PrintNonRemovalDeprecatedFeatureWarning("Shadowsocks (with no Forward Secrecy, etc.)", "VLESS Encryption")
|
||||||
|
|
||||||
if C.Contains(shadowaead_2022.List, v.Cipher) {
|
if C.Contains(shadowaead_2022.List, v.Cipher) {
|
||||||
return buildShadowsocks2022(v)
|
return buildShadowsocks2022(v)
|
||||||
}
|
}
|
||||||
@@ -185,6 +187,8 @@ type ShadowsocksClientConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
|
func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
|
||||||
|
errors.PrintNonRemovalDeprecatedFeatureWarning("Shadowsocks (with no Forward Secrecy, etc.)", "VLESS Encryption")
|
||||||
|
|
||||||
if v.Address != nil {
|
if v.Address != nil {
|
||||||
v.Servers = []*ShadowsocksServerTarget{
|
v.Servers = []*ShadowsocksServerTarget{
|
||||||
{
|
{
|
||||||
@@ -255,7 +259,7 @@ func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
|
|||||||
ss := &protocol.ServerEndpoint{
|
ss := &protocol.ServerEndpoint{
|
||||||
Address: server.Address.Build(),
|
Address: server.Address.Build(),
|
||||||
Port: uint32(server.Port),
|
Port: uint32(server.Port),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Level: uint32(server.Level),
|
Level: uint32(server.Level),
|
||||||
Email: server.Email,
|
Email: server.Email,
|
||||||
Account: serial.ToTypedMessage(account),
|
Account: serial.ToTypedMessage(account),
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
|
"github.com/xtls/xray-core/transport/internet/finalmask/salamander"
|
||||||
"github.com/xtls/xray-core/transport/internet/httpupgrade"
|
"github.com/xtls/xray-core/transport/internet/httpupgrade"
|
||||||
|
"github.com/xtls/xray-core/transport/internet/hysteria"
|
||||||
"github.com/xtls/xray-core/transport/internet/kcp"
|
"github.com/xtls/xray-core/transport/internet/kcp"
|
||||||
"github.com/xtls/xray-core/transport/internet/reality"
|
"github.com/xtls/xray-core/transport/internet/reality"
|
||||||
"github.com/xtls/xray-core/transport/internet/splithttp"
|
"github.com/xtls/xray-core/transport/internet/splithttp"
|
||||||
@@ -332,6 +334,170 @@ func (c *SplitHTTPConfig) Build() (proto.Message, error) {
|
|||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
Byte = 1
|
||||||
|
Kilobyte = 1024 * Byte
|
||||||
|
Megabyte = 1024 * Kilobyte
|
||||||
|
Gigabyte = 1024 * Megabyte
|
||||||
|
Terabyte = 1024 * Gigabyte
|
||||||
|
)
|
||||||
|
|
||||||
|
type Bandwidth string
|
||||||
|
|
||||||
|
func (b Bandwidth) Bps() (uint64, error) {
|
||||||
|
s := strings.TrimSpace(strings.ToLower(string(b)))
|
||||||
|
if s == "" {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
idx := len(s)
|
||||||
|
for i, c := range s {
|
||||||
|
if (c < '0' || c > '9') && c != '.' {
|
||||||
|
idx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numStr := s[:idx]
|
||||||
|
unit := strings.TrimSpace(s[idx:])
|
||||||
|
|
||||||
|
val, err := strconv.ParseFloat(numStr, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mul := uint64(1)
|
||||||
|
switch unit {
|
||||||
|
case "", "b", "bps":
|
||||||
|
mul = Byte
|
||||||
|
case "k", "kb", "kbps":
|
||||||
|
mul = Kilobyte
|
||||||
|
case "m", "mb", "mbps":
|
||||||
|
mul = Megabyte
|
||||||
|
case "g", "gb", "gbps":
|
||||||
|
mul = Gigabyte
|
||||||
|
case "t", "tb", "tbps":
|
||||||
|
mul = Terabyte
|
||||||
|
default:
|
||||||
|
return 0, errors.New("unsupported unit: " + unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint64(val*float64(mul)) / 8, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type UdpHop struct {
|
||||||
|
PortList json.RawMessage `json:"port"`
|
||||||
|
Interval int64 `json:"interval"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HysteriaConfig struct {
|
||||||
|
Version int32 `json:"version"`
|
||||||
|
Auth string `json:"auth"`
|
||||||
|
Congestion string `json:"congestion"`
|
||||||
|
Up Bandwidth `json:"up"`
|
||||||
|
Down Bandwidth `json:"down"`
|
||||||
|
UdpHop UdpHop `json:"udphop"`
|
||||||
|
|
||||||
|
InitStreamReceiveWindow uint64 `json:"initStreamReceiveWindow"`
|
||||||
|
MaxStreamReceiveWindow uint64 `json:"maxStreamReceiveWindow"`
|
||||||
|
InitConnectionReceiveWindow uint64 `json:"initConnectionReceiveWindow"`
|
||||||
|
MaxConnectionReceiveWindow uint64 `json:"maxConnectionReceiveWindow"`
|
||||||
|
MaxIdleTimeout int64 `json:"maxIdleTimeout"`
|
||||||
|
KeepAlivePeriod int64 `json:"keepAlivePeriod"`
|
||||||
|
DisablePathMTUDiscovery bool `json:"disablePathMTUDiscovery"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *HysteriaConfig) Build() (proto.Message, error) {
|
||||||
|
if c.Version != 2 {
|
||||||
|
return nil, errors.New("version != 2")
|
||||||
|
}
|
||||||
|
|
||||||
|
up, err := c.Up.Bps()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
down, err := c.Down.Bps()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Congestion = strings.ToLower(c.Congestion)
|
||||||
|
if c.Congestion == "force-brutal" && up == 0 {
|
||||||
|
return nil, errors.New("force-brutal require up")
|
||||||
|
}
|
||||||
|
|
||||||
|
var hop *PortList
|
||||||
|
if err := json.Unmarshal(c.UdpHop.PortList, &hop); err != nil {
|
||||||
|
hop = &PortList{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if up > 0 && up < 65536 {
|
||||||
|
return nil, errors.New("Up must be at least 65536 Bps")
|
||||||
|
}
|
||||||
|
if down > 0 && down < 65536 {
|
||||||
|
return nil, errors.New("Down must be at least 65536 Bps")
|
||||||
|
}
|
||||||
|
if c.UdpHop.Interval != 0 && c.UdpHop.Interval < 5 {
|
||||||
|
return nil, errors.New("Interval must be at least 5")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.InitStreamReceiveWindow > 0 && c.InitStreamReceiveWindow < 16384 {
|
||||||
|
return nil, errors.New("InitStreamReceiveWindow must be at least 16384")
|
||||||
|
}
|
||||||
|
if c.MaxStreamReceiveWindow > 0 && c.MaxStreamReceiveWindow < 16384 {
|
||||||
|
return nil, errors.New("MaxStreamReceiveWindow must be at least 16384")
|
||||||
|
}
|
||||||
|
if c.InitConnectionReceiveWindow > 0 && c.InitConnectionReceiveWindow < 16384 {
|
||||||
|
return nil, errors.New("InitConnectionReceiveWindow must be at least 16384")
|
||||||
|
}
|
||||||
|
if c.MaxConnectionReceiveWindow > 0 && c.MaxConnectionReceiveWindow < 16384 {
|
||||||
|
return nil, errors.New("MaxConnectionReceiveWindow must be at least 16384")
|
||||||
|
}
|
||||||
|
if c.MaxIdleTimeout != 0 && (c.MaxIdleTimeout < 4 || c.MaxIdleTimeout > 120) {
|
||||||
|
return nil, errors.New("MaxIdleTimeout must be between 4 and 120")
|
||||||
|
}
|
||||||
|
if c.KeepAlivePeriod != 0 && (c.KeepAlivePeriod < 2 || c.KeepAlivePeriod > 60) {
|
||||||
|
return nil, errors.New("KeepAlivePeriod must be between 2 and 60")
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &hysteria.Config{}
|
||||||
|
config.Version = c.Version
|
||||||
|
config.Auth = c.Auth
|
||||||
|
config.Congestion = c.Congestion
|
||||||
|
config.Up = up
|
||||||
|
config.Down = down
|
||||||
|
config.Ports = hop.Build().Ports()
|
||||||
|
config.Interval = c.UdpHop.Interval
|
||||||
|
config.InitStreamReceiveWindow = c.InitStreamReceiveWindow
|
||||||
|
config.MaxStreamReceiveWindow = c.MaxStreamReceiveWindow
|
||||||
|
config.InitConnReceiveWindow = c.InitConnectionReceiveWindow
|
||||||
|
config.MaxConnReceiveWindow = c.MaxConnectionReceiveWindow
|
||||||
|
config.MaxIdleTimeout = c.MaxIdleTimeout
|
||||||
|
config.KeepAlivePeriod = c.KeepAlivePeriod
|
||||||
|
config.DisablePathMtuDiscovery = c.DisablePathMTUDiscovery
|
||||||
|
|
||||||
|
if config.InitStreamReceiveWindow == 0 {
|
||||||
|
config.InitStreamReceiveWindow = 8388608
|
||||||
|
}
|
||||||
|
if config.MaxStreamReceiveWindow == 0 {
|
||||||
|
config.MaxStreamReceiveWindow = 8388608
|
||||||
|
}
|
||||||
|
if config.InitConnReceiveWindow == 0 {
|
||||||
|
config.InitConnReceiveWindow = 8388608 * 5 / 2
|
||||||
|
}
|
||||||
|
if config.MaxConnReceiveWindow == 0 {
|
||||||
|
config.MaxConnReceiveWindow = 8388608 * 5 / 2
|
||||||
|
}
|
||||||
|
if config.MaxIdleTimeout == 0 {
|
||||||
|
config.MaxIdleTimeout = 30
|
||||||
|
}
|
||||||
|
// if config.KeepAlivePeriod == 0 {
|
||||||
|
// config.KeepAlivePeriod = 10
|
||||||
|
// }
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
func readFileOrString(f string, s []string) ([]byte, error) {
|
func readFileOrString(f string, s []string) ([]byte, error) {
|
||||||
if len(f) > 0 {
|
if len(f) > 0 {
|
||||||
return filesystem.ReadCert(f)
|
return filesystem.ReadCert(f)
|
||||||
@@ -395,27 +561,26 @@ func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TLSConfig struct {
|
type TLSConfig struct {
|
||||||
Insecure bool `json:"allowInsecure"`
|
Insecure bool `json:"allowInsecure"`
|
||||||
Certs []*TLSCertConfig `json:"certificates"`
|
Certs []*TLSCertConfig `json:"certificates"`
|
||||||
ServerName string `json:"serverName"`
|
ServerName string `json:"serverName"`
|
||||||
ALPN *StringList `json:"alpn"`
|
ALPN *StringList `json:"alpn"`
|
||||||
EnableSessionResumption bool `json:"enableSessionResumption"`
|
EnableSessionResumption bool `json:"enableSessionResumption"`
|
||||||
DisableSystemRoot bool `json:"disableSystemRoot"`
|
DisableSystemRoot bool `json:"disableSystemRoot"`
|
||||||
MinVersion string `json:"minVersion"`
|
MinVersion string `json:"minVersion"`
|
||||||
MaxVersion string `json:"maxVersion"`
|
MaxVersion string `json:"maxVersion"`
|
||||||
CipherSuites string `json:"cipherSuites"`
|
CipherSuites string `json:"cipherSuites"`
|
||||||
Fingerprint string `json:"fingerprint"`
|
Fingerprint string `json:"fingerprint"`
|
||||||
RejectUnknownSNI bool `json:"rejectUnknownSni"`
|
RejectUnknownSNI bool `json:"rejectUnknownSni"`
|
||||||
PinnedPeerCertificateChainSha256 *[]string `json:"pinnedPeerCertificateChainSha256"`
|
PinnedPeerCertSha256 string `json:"pinnedPeerCertSha256"`
|
||||||
PinnedPeerCertificatePublicKeySha256 *[]string `json:"pinnedPeerCertificatePublicKeySha256"`
|
CurvePreferences *StringList `json:"curvePreferences"`
|
||||||
CurvePreferences *StringList `json:"curvePreferences"`
|
MasterKeyLog string `json:"masterKeyLog"`
|
||||||
MasterKeyLog string `json:"masterKeyLog"`
|
ServerNameToVerify string `json:"serverNameToVerify"`
|
||||||
ServerNameToVerify string `json:"serverNameToVerify"`
|
VerifyPeerCertInNames []string `json:"verifyPeerCertInNames"`
|
||||||
VerifyPeerCertInNames []string `json:"verifyPeerCertInNames"`
|
ECHServerKeys string `json:"echServerKeys"`
|
||||||
ECHServerKeys string `json:"echServerKeys"`
|
ECHConfigList string `json:"echConfigList"`
|
||||||
ECHConfigList string `json:"echConfigList"`
|
ECHForceQuery string `json:"echForceQuery"`
|
||||||
ECHForceQuery string `json:"echForceQuery"`
|
ECHSocketSettings *SocketConfig `json:"echSockopt"`
|
||||||
ECHSocketSettings *SocketConfig `json:"echSockopt"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build implements Buildable.
|
// Build implements Buildable.
|
||||||
@@ -431,6 +596,9 @@ func (c *TLSConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
serverName := c.ServerName
|
serverName := c.ServerName
|
||||||
config.AllowInsecure = c.Insecure
|
config.AllowInsecure = c.Insecure
|
||||||
|
if config.AllowInsecure {
|
||||||
|
errors.PrintDeprecatedFeatureWarning("allowInsecure", "pinnedPeerCertSha256")
|
||||||
|
}
|
||||||
if len(c.ServerName) > 0 {
|
if len(c.ServerName) > 0 {
|
||||||
config.ServerName = serverName
|
config.ServerName = serverName
|
||||||
}
|
}
|
||||||
@@ -458,25 +626,20 @@ func (c *TLSConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
config.RejectUnknownSni = c.RejectUnknownSNI
|
config.RejectUnknownSni = c.RejectUnknownSNI
|
||||||
|
|
||||||
if c.PinnedPeerCertificateChainSha256 != nil {
|
if c.PinnedPeerCertSha256 != "" {
|
||||||
config.PinnedPeerCertificateChainSha256 = [][]byte{}
|
config.PinnedPeerCertSha256 = [][]byte{}
|
||||||
for _, v := range *c.PinnedPeerCertificateChainSha256 {
|
// Split by tilde separator
|
||||||
hashValue, err := base64.StdEncoding.DecodeString(v)
|
hashes := strings.Split(c.PinnedPeerCertSha256, "~")
|
||||||
|
for _, v := range hashes {
|
||||||
|
v = strings.TrimSpace(v)
|
||||||
|
if v == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
hashValue, err := hex.DecodeString(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
config.PinnedPeerCertificateChainSha256 = append(config.PinnedPeerCertificateChainSha256, hashValue)
|
config.PinnedPeerCertSha256 = append(config.PinnedPeerCertSha256, hashValue)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.PinnedPeerCertificatePublicKeySha256 != nil {
|
|
||||||
config.PinnedPeerCertificatePublicKeySha256 = [][]byte{}
|
|
||||||
for _, v := range *c.PinnedPeerCertificatePublicKeySha256 {
|
|
||||||
hashValue, err := base64.StdEncoding.DecodeString(v)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
config.PinnedPeerCertificatePublicKeySha256 = append(config.PinnedPeerCertificatePublicKeySha256, hashValue)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,6 +791,9 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
config.ShortIds = make([][]byte, len(c.ShortIds))
|
config.ShortIds = make([][]byte, len(c.ShortIds))
|
||||||
for i, s := range c.ShortIds {
|
for i, s := range c.ShortIds {
|
||||||
|
if len(s) > 16 {
|
||||||
|
return nil, errors.New(`too long "shortIds[`, i, `]": `, s)
|
||||||
|
}
|
||||||
config.ShortIds[i] = make([]byte, 8)
|
config.ShortIds[i] = make([]byte, 8)
|
||||||
if _, err = hex.Decode(config.ShortIds[i], []byte(s)); err != nil {
|
if _, err = hex.Decode(config.ShortIds[i], []byte(s)); err != nil {
|
||||||
return nil, errors.New(`invalid "shortIds[`, i, `]": `, s)
|
return nil, errors.New(`invalid "shortIds[`, i, `]": `, s)
|
||||||
@@ -679,6 +845,9 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
|
|||||||
if len(c.ShortIds) != 0 {
|
if len(c.ShortIds) != 0 {
|
||||||
return nil, errors.New(`non-empty "shortIds", please use "shortId" instead`)
|
return nil, errors.New(`non-empty "shortIds", please use "shortId" instead`)
|
||||||
}
|
}
|
||||||
|
if len(c.ShortIds) > 16 {
|
||||||
|
return nil, errors.New(`too long "shortId": `, c.ShortId)
|
||||||
|
}
|
||||||
config.ShortId = make([]byte, 8)
|
config.ShortId = make([]byte, 8)
|
||||||
if _, err = hex.Decode(config.ShortId, []byte(c.ShortId)); err != nil {
|
if _, err = hex.Decode(config.ShortId, []byte(c.ShortId)); err != nil {
|
||||||
return nil, errors.New(`invalid "shortId": `, c.ShortId)
|
return nil, errors.New(`invalid "shortId": `, c.ShortId)
|
||||||
@@ -734,18 +903,20 @@ func (p TransportProtocol) Build() (string, error) {
|
|||||||
case "kcp", "mkcp":
|
case "kcp", "mkcp":
|
||||||
return "mkcp", nil
|
return "mkcp", nil
|
||||||
case "grpc":
|
case "grpc":
|
||||||
errors.PrintDeprecatedFeatureWarning("gRPC transport (with unnecessary costs, etc.)", "XHTTP stream-up H2")
|
errors.PrintNonRemovalDeprecatedFeatureWarning("gRPC transport (with unnecessary costs, etc.)", "XHTTP stream-up H2")
|
||||||
return "grpc", nil
|
return "grpc", nil
|
||||||
case "ws", "websocket":
|
case "ws", "websocket":
|
||||||
errors.PrintDeprecatedFeatureWarning("WebSocket transport (with ALPN http/1.1, etc.)", "XHTTP H2 & H3")
|
errors.PrintNonRemovalDeprecatedFeatureWarning("WebSocket transport (with ALPN http/1.1, etc.)", "XHTTP H2 & H3")
|
||||||
return "websocket", nil
|
return "websocket", nil
|
||||||
case "httpupgrade":
|
case "httpupgrade":
|
||||||
errors.PrintDeprecatedFeatureWarning("HTTPUpgrade transport (with ALPN http/1.1, etc.)", "XHTTP H2 & H3")
|
errors.PrintNonRemovalDeprecatedFeatureWarning("HTTPUpgrade transport (with ALPN http/1.1, etc.)", "XHTTP H2 & H3")
|
||||||
return "httpupgrade", nil
|
return "httpupgrade", nil
|
||||||
case "h2", "h3", "http":
|
case "h2", "h3", "http":
|
||||||
return "", errors.PrintRemovedFeatureError("HTTP transport (without header padding, etc.)", "XHTTP stream-one H2 & H3")
|
return "", errors.PrintRemovedFeatureError("HTTP transport (without header padding, etc.)", "XHTTP stream-one H2 & H3")
|
||||||
case "quic":
|
case "quic":
|
||||||
return "", errors.PrintRemovedFeatureError("QUIC transport (without web service, etc.)", "XHTTP stream-one H3")
|
return "", errors.PrintRemovedFeatureError("QUIC transport (without web service, etc.)", "XHTTP stream-one H3")
|
||||||
|
case "hysteria":
|
||||||
|
return "hysteria", nil
|
||||||
default:
|
default:
|
||||||
return "", errors.New("Config: unknown transport protocol: ", p)
|
return "", errors.New("Config: unknown transport protocol: ", p)
|
||||||
}
|
}
|
||||||
@@ -804,6 +975,7 @@ type SocketConfig struct {
|
|||||||
CustomSockopt []*CustomSockoptConfig `json:"customSockopt"`
|
CustomSockopt []*CustomSockoptConfig `json:"customSockopt"`
|
||||||
AddressPortStrategy string `json:"addressPortStrategy"`
|
AddressPortStrategy string `json:"addressPortStrategy"`
|
||||||
HappyEyeballsSettings *HappyEyeballsConfig `json:"happyEyeballs"`
|
HappyEyeballsSettings *HappyEyeballsConfig `json:"happyEyeballs"`
|
||||||
|
TrustedXForwardedFor []string `json:"trustedXForwardedFor"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build implements Buildable.
|
// Build implements Buildable.
|
||||||
@@ -923,14 +1095,58 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
|
|||||||
CustomSockopt: customSockopts,
|
CustomSockopt: customSockopts,
|
||||||
AddressPortStrategy: addressPortStrategy,
|
AddressPortStrategy: addressPortStrategy,
|
||||||
HappyEyeballs: happyEyeballs,
|
HappyEyeballs: happyEyeballs,
|
||||||
|
TrustedXForwardedFor: c.TrustedXForwardedFor,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
udpmaskLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
||||||
|
"salamander": func() interface{} { return new(Salamander) },
|
||||||
|
}, "type", "settings")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Salamander struct {
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Salamander) Build() (proto.Message, error) {
|
||||||
|
config := &salamander.Config{}
|
||||||
|
config.Password = c.Password
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type FinalMask struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Settings *json.RawMessage `json:"settings"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FinalMask) Build(tcpmaskLoader bool) (proto.Message, error) {
|
||||||
|
loader := udpmaskLoader
|
||||||
|
if tcpmaskLoader {
|
||||||
|
return nil, errors.New("")
|
||||||
|
}
|
||||||
|
|
||||||
|
settings := []byte("{}")
|
||||||
|
if c.Settings != nil {
|
||||||
|
settings = ([]byte)(*c.Settings)
|
||||||
|
}
|
||||||
|
rawConfig, err := loader.LoadWithID(settings, c.Type)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ts, err := rawConfig.(Buildable).Build()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ts, nil
|
||||||
|
}
|
||||||
|
|
||||||
type StreamConfig struct {
|
type StreamConfig struct {
|
||||||
Address *Address `json:"address"`
|
Address *Address `json:"address"`
|
||||||
Port uint16 `json:"port"`
|
Port uint16 `json:"port"`
|
||||||
Network *TransportProtocol `json:"network"`
|
Network *TransportProtocol `json:"network"`
|
||||||
Security string `json:"security"`
|
Security string `json:"security"`
|
||||||
|
Udpmasks []*FinalMask `json:"udpmasks"`
|
||||||
TLSSettings *TLSConfig `json:"tlsSettings"`
|
TLSSettings *TLSConfig `json:"tlsSettings"`
|
||||||
REALITYSettings *REALITYConfig `json:"realitySettings"`
|
REALITYSettings *REALITYConfig `json:"realitySettings"`
|
||||||
RAWSettings *TCPConfig `json:"rawSettings"`
|
RAWSettings *TCPConfig `json:"rawSettings"`
|
||||||
@@ -941,6 +1157,7 @@ type StreamConfig struct {
|
|||||||
GRPCSettings *GRPCConfig `json:"grpcSettings"`
|
GRPCSettings *GRPCConfig `json:"grpcSettings"`
|
||||||
WSSettings *WebSocketConfig `json:"wsSettings"`
|
WSSettings *WebSocketConfig `json:"wsSettings"`
|
||||||
HTTPUPGRADESettings *HttpUpgradeConfig `json:"httpupgradeSettings"`
|
HTTPUPGRADESettings *HttpUpgradeConfig `json:"httpupgradeSettings"`
|
||||||
|
HysteriaSettings *HysteriaConfig `json:"hysteriaSettings"`
|
||||||
SocketSettings *SocketConfig `json:"sockopt"`
|
SocketSettings *SocketConfig `json:"sockopt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -960,6 +1177,7 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
|||||||
}
|
}
|
||||||
config.ProtocolName = protocol
|
config.ProtocolName = protocol
|
||||||
}
|
}
|
||||||
|
|
||||||
switch strings.ToLower(c.Security) {
|
switch strings.ToLower(c.Security) {
|
||||||
case "", "none":
|
case "", "none":
|
||||||
case "tls":
|
case "tls":
|
||||||
@@ -993,6 +1211,7 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
|||||||
default:
|
default:
|
||||||
return nil, errors.New(`Unknown security "` + c.Security + `".`)
|
return nil, errors.New(`Unknown security "` + c.Security + `".`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.RAWSettings != nil {
|
if c.RAWSettings != nil {
|
||||||
c.TCPSettings = c.RAWSettings
|
c.TCPSettings = c.RAWSettings
|
||||||
}
|
}
|
||||||
@@ -1059,6 +1278,16 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
|||||||
Settings: serial.ToTypedMessage(hs),
|
Settings: serial.ToTypedMessage(hs),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if c.HysteriaSettings != nil {
|
||||||
|
hs, err := c.HysteriaSettings.Build()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("Failed to build Hysteria config.").Base(err)
|
||||||
|
}
|
||||||
|
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
|
||||||
|
ProtocolName: "hysteria",
|
||||||
|
Settings: serial.ToTypedMessage(hs),
|
||||||
|
})
|
||||||
|
}
|
||||||
if c.SocketSettings != nil {
|
if c.SocketSettings != nil {
|
||||||
ss, err := c.SocketSettings.Build()
|
ss, err := c.SocketSettings.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1066,6 +1295,15 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
|||||||
}
|
}
|
||||||
config.SocketSettings = ss
|
config.SocketSettings = ss
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, mask := range c.Udpmasks {
|
||||||
|
u, err := mask.Build(false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to build mask with type ", mask.Type).Base(err)
|
||||||
|
}
|
||||||
|
config.Udpmasks = append(config.Udpmasks, serial.ToTypedMessage(u))
|
||||||
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ type TrojanClientConfig struct {
|
|||||||
|
|
||||||
// Build implements Buildable
|
// Build implements Buildable
|
||||||
func (c *TrojanClientConfig) Build() (proto.Message, error) {
|
func (c *TrojanClientConfig) Build() (proto.Message, error) {
|
||||||
|
errors.PrintNonRemovalDeprecatedFeatureWarning("Trojan (with no Flow, etc.)", "VLESS with Flow & Seed")
|
||||||
|
|
||||||
if c.Address != nil {
|
if c.Address != nil {
|
||||||
c.Servers = []*TrojanServerTarget{
|
c.Servers = []*TrojanServerTarget{
|
||||||
{
|
{
|
||||||
@@ -74,7 +76,7 @@ func (c *TrojanClientConfig) Build() (proto.Message, error) {
|
|||||||
config.Server = &protocol.ServerEndpoint{
|
config.Server = &protocol.ServerEndpoint{
|
||||||
Address: rec.Address.Build(),
|
Address: rec.Address.Build(),
|
||||||
Port: uint32(rec.Port),
|
Port: uint32(rec.Port),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Level: uint32(rec.Level),
|
Level: uint32(rec.Level),
|
||||||
Email: rec.Email,
|
Email: rec.Email,
|
||||||
Account: serial.ToTypedMessage(&trojan.Account{
|
Account: serial.ToTypedMessage(&trojan.Account{
|
||||||
@@ -115,6 +117,8 @@ type TrojanServerConfig struct {
|
|||||||
|
|
||||||
// Build implements Buildable
|
// Build implements Buildable
|
||||||
func (c *TrojanServerConfig) Build() (proto.Message, error) {
|
func (c *TrojanServerConfig) Build() (proto.Message, error) {
|
||||||
|
errors.PrintNonRemovalDeprecatedFeatureWarning("Trojan (with no Flow, etc.)", "VLESS with Flow & Seed")
|
||||||
|
|
||||||
config := &trojan.ServerConfig{
|
config := &trojan.ServerConfig{
|
||||||
Users: make([]*protocol.User, len(c.Clients)),
|
Users: make([]*protocol.User, len(c.Clients)),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package conf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/xtls/xray-core/proxy/tun"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TunConfig struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
MTU uint32 `json:"MTU"`
|
||||||
|
UserLevel uint32 `json:"userLevel"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *TunConfig) Build() (proto.Message, error) {
|
||||||
|
config := &tun.Config{
|
||||||
|
Name: v.Name,
|
||||||
|
MTU: v.MTU,
|
||||||
|
UserLevel: v.UserLevel,
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Name == "" {
|
||||||
|
config.Name = "xray0"
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.MTU == 0 {
|
||||||
|
config.MTU = 1500
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
+15
-5
@@ -34,6 +34,7 @@ type VLessInboundConfig struct {
|
|||||||
Decryption string `json:"decryption"`
|
Decryption string `json:"decryption"`
|
||||||
Fallbacks []*VLessInboundFallback `json:"fallbacks"`
|
Fallbacks []*VLessInboundFallback `json:"fallbacks"`
|
||||||
Flow string `json:"flow"`
|
Flow string `json:"flow"`
|
||||||
|
Testseed []uint32 `json:"testseed"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build implements Buildable
|
// Build implements Buildable
|
||||||
@@ -41,8 +42,6 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
|||||||
config := new(inbound.Config)
|
config := new(inbound.Config)
|
||||||
config.Clients = make([]*protocol.User, len(c.Clients))
|
config.Clients = make([]*protocol.User, len(c.Clients))
|
||||||
switch c.Flow {
|
switch c.Flow {
|
||||||
case vless.None:
|
|
||||||
c.Flow = ""
|
|
||||||
case "", vless.XRV:
|
case "", vless.XRV:
|
||||||
default:
|
default:
|
||||||
return nil, errors.New(`VLESS "settings.flow" doesn't support "` + c.Flow + `" in this version`)
|
return nil, errors.New(`VLESS "settings.flow" doesn't support "` + c.Flow + `" in this version`)
|
||||||
@@ -66,12 +65,17 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
|||||||
switch account.Flow {
|
switch account.Flow {
|
||||||
case "":
|
case "":
|
||||||
account.Flow = c.Flow
|
account.Flow = c.Flow
|
||||||
case vless.None:
|
|
||||||
account.Flow = ""
|
|
||||||
case vless.XRV:
|
case vless.XRV:
|
||||||
default:
|
default:
|
||||||
return nil, errors.New(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`)
|
return nil, errors.New(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`)
|
||||||
}
|
}
|
||||||
|
if account.Flow == "" {
|
||||||
|
errors.PrintNonRemovalDeprecatedFeatureWarning("VLESS (with no Flow, etc.)", "VLESS with Flow & Seed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(account.Testseed) < 4 {
|
||||||
|
account.Testseed = c.Testseed
|
||||||
|
}
|
||||||
|
|
||||||
if account.Encryption != "" {
|
if account.Encryption != "" {
|
||||||
return nil, errors.New(`VLESS clients: "encryption" should not be in inbound settings`)
|
return nil, errors.New(`VLESS clients: "encryption" should not be in inbound settings`)
|
||||||
@@ -212,6 +216,8 @@ type VLessOutboundConfig struct {
|
|||||||
Seed string `json:"seed"`
|
Seed string `json:"seed"`
|
||||||
Encryption string `json:"encryption"`
|
Encryption string `json:"encryption"`
|
||||||
Reverse *vless.Reverse `json:"reverse"`
|
Reverse *vless.Reverse `json:"reverse"`
|
||||||
|
Testpre uint32 `json:"testpre"`
|
||||||
|
Testseed []uint32 `json:"testseed"`
|
||||||
Vnext []*VLessOutboundVnext `json:"vnext"`
|
Vnext []*VLessOutboundVnext `json:"vnext"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,6 +264,8 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
|
|||||||
//account.Seed = c.Seed
|
//account.Seed = c.Seed
|
||||||
account.Encryption = c.Encryption
|
account.Encryption = c.Encryption
|
||||||
account.Reverse = c.Reverse
|
account.Reverse = c.Reverse
|
||||||
|
account.Testpre = c.Testpre
|
||||||
|
account.Testseed = c.Testseed
|
||||||
} else {
|
} else {
|
||||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||||
return nil, errors.New(`VLESS users: invalid user`).Base(err)
|
return nil, errors.New(`VLESS users: invalid user`).Base(err)
|
||||||
@@ -271,7 +279,9 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
|
|||||||
account.Id = u.String()
|
account.Id = u.String()
|
||||||
|
|
||||||
switch account.Flow {
|
switch account.Flow {
|
||||||
case "", vless.XRV, vless.XRV + "-udp443":
|
case "":
|
||||||
|
errors.PrintNonRemovalDeprecatedFeatureWarning("VLESS (with no Flow, etc.)", "VLESS with Flow & Seed")
|
||||||
|
case vless.XRV, vless.XRV + "-udp443":
|
||||||
default:
|
default:
|
||||||
return nil, errors.New(`VLESS users: "flow" doesn't support "` + account.Flow + `" in this version`)
|
return nil, errors.New(`VLESS users: "flow" doesn't support "` + account.Flow + `" in this version`)
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -58,12 +58,14 @@ func (c *VMessDefaultConfig) Build() *inbound.DefaultConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type VMessInboundConfig struct {
|
type VMessInboundConfig struct {
|
||||||
Users []json.RawMessage `json:"clients"`
|
Users []json.RawMessage `json:"clients"`
|
||||||
Defaults *VMessDefaultConfig `json:"default"`
|
Defaults *VMessDefaultConfig `json:"default"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build implements Buildable
|
// Build implements Buildable
|
||||||
func (c *VMessInboundConfig) Build() (proto.Message, error) {
|
func (c *VMessInboundConfig) Build() (proto.Message, error) {
|
||||||
|
errors.PrintNonRemovalDeprecatedFeatureWarning("VMess (with no Forward Secrecy, etc.)", "VLESS Encryption")
|
||||||
|
|
||||||
config := &inbound.Config{}
|
config := &inbound.Config{}
|
||||||
|
|
||||||
if c.Defaults != nil {
|
if c.Defaults != nil {
|
||||||
@@ -113,6 +115,8 @@ type VMessOutboundConfig struct {
|
|||||||
|
|
||||||
// Build implements Buildable
|
// Build implements Buildable
|
||||||
func (c *VMessOutboundConfig) Build() (proto.Message, error) {
|
func (c *VMessOutboundConfig) Build() (proto.Message, error) {
|
||||||
|
errors.PrintNonRemovalDeprecatedFeatureWarning("VMess (with no Forward Secrecy, etc.)", "VLESS Encryption")
|
||||||
|
|
||||||
config := new(outbound.Config)
|
config := new(outbound.Config)
|
||||||
if c.Address != nil {
|
if c.Address != nil {
|
||||||
c.Receivers = []*VMessOutboundTarget{
|
c.Receivers = []*VMessOutboundTarget{
|
||||||
|
|||||||
+13
-12
@@ -3,8 +3,6 @@ package conf
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -30,6 +28,7 @@ var (
|
|||||||
"vmess": func() interface{} { return new(VMessInboundConfig) },
|
"vmess": func() interface{} { return new(VMessInboundConfig) },
|
||||||
"trojan": func() interface{} { return new(TrojanServerConfig) },
|
"trojan": func() interface{} { return new(TrojanServerConfig) },
|
||||||
"wireguard": func() interface{} { return &WireGuardConfig{IsClient: false} },
|
"wireguard": func() interface{} { return &WireGuardConfig{IsClient: false} },
|
||||||
|
"tun": func() interface{} { return new(TunConfig) },
|
||||||
}, "protocol", "settings")
|
}, "protocol", "settings")
|
||||||
|
|
||||||
outboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
outboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
||||||
@@ -44,11 +43,10 @@ var (
|
|||||||
"vless": func() interface{} { return new(VLessOutboundConfig) },
|
"vless": func() interface{} { return new(VLessOutboundConfig) },
|
||||||
"vmess": func() interface{} { return new(VMessOutboundConfig) },
|
"vmess": func() interface{} { return new(VMessOutboundConfig) },
|
||||||
"trojan": func() interface{} { return new(TrojanClientConfig) },
|
"trojan": func() interface{} { return new(TrojanClientConfig) },
|
||||||
|
"hysteria": func() interface{} { return new(HysteriaClientConfig) },
|
||||||
"dns": func() interface{} { return new(DNSOutboundConfig) },
|
"dns": func() interface{} { return new(DNSOutboundConfig) },
|
||||||
"wireguard": func() interface{} { return &WireGuardConfig{IsClient: true} },
|
"wireguard": func() interface{} { return &WireGuardConfig{IsClient: true} },
|
||||||
}, "protocol", "settings")
|
}, "protocol", "settings")
|
||||||
|
|
||||||
ctllog = log.New(os.Stderr, "xctl> ", 0)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type SniffingConfig struct {
|
type SniffingConfig struct {
|
||||||
@@ -120,20 +118,23 @@ func (m *MuxConfig) Build() (*proxyman.MultiplexingConfig, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type InboundDetourConfig struct {
|
type InboundDetourConfig struct {
|
||||||
Protocol string `json:"protocol"`
|
Protocol string `json:"protocol"`
|
||||||
PortList *PortList `json:"port"`
|
PortList *PortList `json:"port"`
|
||||||
ListenOn *Address `json:"listen"`
|
ListenOn *Address `json:"listen"`
|
||||||
Settings *json.RawMessage `json:"settings"`
|
Settings *json.RawMessage `json:"settings"`
|
||||||
Tag string `json:"tag"`
|
Tag string `json:"tag"`
|
||||||
StreamSetting *StreamConfig `json:"streamSettings"`
|
StreamSetting *StreamConfig `json:"streamSettings"`
|
||||||
SniffingConfig *SniffingConfig `json:"sniffing"`
|
SniffingConfig *SniffingConfig `json:"sniffing"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build implements Buildable.
|
// Build implements Buildable.
|
||||||
func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
|
func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
|
||||||
receiverSettings := &proxyman.ReceiverConfig{}
|
receiverSettings := &proxyman.ReceiverConfig{}
|
||||||
|
|
||||||
if c.ListenOn == nil {
|
// TUN inbound doesn't need port configuration as it uses network interface instead
|
||||||
|
if strings.ToLower(c.Protocol) == "tun" {
|
||||||
|
// Skip port validation for TUN
|
||||||
|
} else if c.ListenOn == nil {
|
||||||
// Listen on anyip, must set PortList
|
// Listen on anyip, must set PortList
|
||||||
if c.PortList == nil {
|
if c.PortList == nil {
|
||||||
return nil, errors.New("Listen on AnyIP but no Port(s) set in InboundDetour.")
|
return nil, errors.New("Listen on AnyIP but no Port(s) set in InboundDetour.")
|
||||||
|
|||||||
@@ -29,8 +29,10 @@ var CmdAPI = &base.Command{
|
|||||||
cmdInboundUserCount,
|
cmdInboundUserCount,
|
||||||
cmdAddRules,
|
cmdAddRules,
|
||||||
cmdRemoveRules,
|
cmdRemoveRules,
|
||||||
|
cmdListRules,
|
||||||
cmdSourceIpBlock,
|
cmdSourceIpBlock,
|
||||||
cmdOnlineStats,
|
cmdOnlineStats,
|
||||||
cmdOnlineStatsIpList,
|
cmdOnlineStatsIpList,
|
||||||
|
cmdGetAllOnlineUsers,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
routerService "github.com/xtls/xray-core/app/router/command"
|
||||||
|
"github.com/xtls/xray-core/main/commands/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cmdListRules = &base.Command{
|
||||||
|
CustomFlags: true,
|
||||||
|
UsageLine: "{{.Exec}} api lsrules [--server=127.0.0.1:8080]",
|
||||||
|
Short: "List routing rules",
|
||||||
|
Long: `
|
||||||
|
List routing rules in Xray.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
-s, -server <server:port>
|
||||||
|
The API server address. Default 127.0.0.1:8080
|
||||||
|
|
||||||
|
-t, -timeout <seconds>
|
||||||
|
Timeout in seconds for calling API. Default 3
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080
|
||||||
|
`,
|
||||||
|
Run: executeListRules,
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeListRules(cmd *base.Command, args []string) {
|
||||||
|
setSharedFlags(cmd)
|
||||||
|
cmd.Flag.Parse(args)
|
||||||
|
|
||||||
|
conn, ctx, close := dialAPIServer()
|
||||||
|
defer close()
|
||||||
|
|
||||||
|
client := routerService.NewRoutingServiceClient(conn)
|
||||||
|
resp, err := client.ListRule(ctx, &routerService.ListRuleRequest{})
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("failed to list rules: %s", err)
|
||||||
|
}
|
||||||
|
showJSONResponse(resp)
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
statsService "github.com/xtls/xray-core/app/stats/command"
|
||||||
|
"github.com/xtls/xray-core/main/commands/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cmdGetAllOnlineUsers = &base.Command{
|
||||||
|
CustomFlags: true,
|
||||||
|
UsageLine: "{{.Exec}} api statsgetallonlineusers [--server=127.0.0.1:8080]",
|
||||||
|
Short: "Retrieve array of all online users",
|
||||||
|
Long: `
|
||||||
|
Retrieve array of all online users.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
-s, -server <server:port>
|
||||||
|
The API server address. Default 127.0.0.1:8080
|
||||||
|
|
||||||
|
-t, -timeout <seconds>
|
||||||
|
Timeout in seconds for calling API. Default 3
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080"
|
||||||
|
`,
|
||||||
|
Run: executeGetAllOnlineUsers,
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeGetAllOnlineUsers(cmd *base.Command, args []string) {
|
||||||
|
setSharedFlags(cmd)
|
||||||
|
cmd.Flag.Parse(args)
|
||||||
|
conn, ctx, close := dialAPIServer()
|
||||||
|
defer close()
|
||||||
|
|
||||||
|
client := statsService.NewStatsServiceClient(conn)
|
||||||
|
r := &statsService.GetAllOnlineUsersRequest{}
|
||||||
|
resp, err := client.GetAllOnlineUsers(ctx, r)
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("failed to get stats: %s", err)
|
||||||
|
}
|
||||||
|
showJSONResponse(resp)
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@ package convert
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/cmdarg"
|
"github.com/xtls/xray-core/common/cmdarg"
|
||||||
creflect "github.com/xtls/xray-core/common/reflect"
|
creflect "github.com/xtls/xray-core/common/reflect"
|
||||||
@@ -61,7 +60,7 @@ func executeConvertConfigsToProtobuf(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(optFile) > 0 {
|
if len(optFile) > 0 {
|
||||||
switch core.GetFormatByExtension(getFileExtension(optFile)){
|
switch core.GetFormat(optFile){
|
||||||
case "protobuf", "":
|
case "protobuf", "":
|
||||||
fmt.Println("Output ProtoBuf file is ", optFile)
|
fmt.Println("Output ProtoBuf file is ", optFile)
|
||||||
default:
|
default:
|
||||||
@@ -106,11 +105,3 @@ func executeConvertConfigsToProtobuf(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFileExtension(filename string) string {
|
|
||||||
idx := strings.LastIndexByte(filename, '.')
|
|
||||||
if idx == -1 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return filename[idx+1:]
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
package tls
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/main/commands/base"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/tls"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cmdCertChainHash = &base.Command{
|
|
||||||
UsageLine: "{{.Exec}} certChainHash",
|
|
||||||
Short: "Calculate TLS certificates hash.",
|
|
||||||
Long: `
|
|
||||||
xray tls certChainHash --cert <cert.pem>
|
|
||||||
Calculate TLS certificate chain hash.
|
|
||||||
`,
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
cmdCertChainHash.Run = executeCertChainHash // break init loop
|
|
||||||
}
|
|
||||||
|
|
||||||
var input = cmdCertChainHash.Flag.String("cert", "fullchain.pem", "The file path of the certificates chain")
|
|
||||||
|
|
||||||
func executeCertChainHash(cmd *base.Command, args []string) {
|
|
||||||
fs := flag.NewFlagSet("certChainHash", flag.ContinueOnError)
|
|
||||||
if err := fs.Parse(args); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
certContent, err := os.ReadFile(*input)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
certChainHashB64 := tls.CalculatePEMCertChainSHA256Hash(certContent)
|
|
||||||
fmt.Println(certChainHashB64)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/main/commands/base"
|
||||||
|
"github.com/xtls/xray-core/transport/internet/tls"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cmdLeafCertHash = &base.Command{
|
||||||
|
UsageLine: "{{.Exec}} tls leafCertHash",
|
||||||
|
Short: "Calculate TLS leaf certificate hash.",
|
||||||
|
Long: `
|
||||||
|
xray tls leafCertHash --cert <cert.pem>
|
||||||
|
Calculate TLS leaf certificate hash.
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cmdLeafCertHash.Run = executeLeafCertHash // break init loop
|
||||||
|
}
|
||||||
|
|
||||||
|
var input = cmdLeafCertHash.Flag.String("cert", "fullchain.pem", "The file path of the leaf certificate")
|
||||||
|
|
||||||
|
func executeLeafCertHash(cmd *base.Command, args []string) {
|
||||||
|
fs := flag.NewFlagSet("leafCertHash", flag.ContinueOnError)
|
||||||
|
if err := fs.Parse(args); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
certContent, err := os.ReadFile(*input)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
certChainHashB64, err := tls.CalculatePEMLeafCertSHA256Hash(certContent)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("failed to decode cert", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(certChainHashB64)
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ package tls
|
|||||||
import (
|
import (
|
||||||
gotls "crypto/tls"
|
gotls "crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -156,8 +156,14 @@ func printTLSConnDetail(tlsConn *gotls.Conn) {
|
|||||||
|
|
||||||
func showCert() func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
func showCert() func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||||
return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||||
hash := GenerateCertChainHash(rawCerts)
|
var hash []byte
|
||||||
fmt.Println("Certificate Chain Hash: ", base64.StdEncoding.EncodeToString(hash))
|
for _, asn1Data := range rawCerts {
|
||||||
|
cert, _ := x509.ParseCertificate(asn1Data)
|
||||||
|
if cert.IsCA {
|
||||||
|
hash = GenerateCertHash(cert)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("Certificate Leaf Hash: ", hex.EncodeToString(hash))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ var CmdTLS = &base.Command{
|
|||||||
Commands: []*base.Command{
|
Commands: []*base.Command{
|
||||||
cmdCert,
|
cmdCert,
|
||||||
cmdPing,
|
cmdPing,
|
||||||
cmdCertChainHash,
|
cmdLeafCertHash,
|
||||||
cmdECH,
|
cmdECH,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,10 @@ import (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
configFileLoader func(string) (io.Reader, error)
|
configFileLoader func(string) (io.Reader, error)
|
||||||
extconfigLoader func([]string, io.Reader) (io.Reader, error)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
EffectiveConfigFileLoader configFileLoader
|
EffectiveConfigFileLoader configFileLoader
|
||||||
EffectiveExtConfigLoader extconfigLoader
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// LoadConfig reads from a path/url/stdin
|
// LoadConfig reads from a path/url/stdin
|
||||||
@@ -27,13 +25,3 @@ func LoadConfig(file string) (io.Reader, error) {
|
|||||||
}
|
}
|
||||||
return EffectiveConfigFileLoader(file)
|
return EffectiveConfigFileLoader(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadExtConfig calls xctl to handle multiple config
|
|
||||||
// the actual work also in external module
|
|
||||||
func LoadExtConfig(files []string, reader io.Reader) (io.Reader, error) {
|
|
||||||
if EffectiveExtConfigLoader == nil {
|
|
||||||
return nil, errors.New("external config module not loaded").AtError()
|
|
||||||
}
|
|
||||||
|
|
||||||
return EffectiveExtConfigLoader(files, reader)
|
|
||||||
}
|
|
||||||
|
|||||||
Vendored
-11
@@ -13,7 +13,6 @@ import (
|
|||||||
|
|
||||||
"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/platform/ctlcmd"
|
|
||||||
"github.com/xtls/xray-core/main/confloader"
|
"github.com/xtls/xray-core/main/confloader"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -129,16 +128,6 @@ func FetchUnixSocketHTTPContent(target string) ([]byte, error) {
|
|||||||
return content, nil
|
return content, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExtConfigLoader(files []string, reader io.Reader) (io.Reader, error) {
|
|
||||||
buf, err := ctlcmd.Run(append([]string{"convert"}, files...), reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.NewReader(buf.String()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
confloader.EffectiveConfigFileLoader = ConfigLoader
|
confloader.EffectiveConfigFileLoader = ConfigLoader
|
||||||
confloader.EffectiveExtConfigLoader = ExtConfigLoader
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user