mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-08-22 17:46:48 +08:00
Compare commits
1 Commits
7f23a1cb65
...
dev-sniff-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
95c2113250 |
72
.github/docker/Dockerfile
vendored
72
.github/docker/Dockerfile
vendored
@@ -1,62 +1,28 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM --platform=$BUILDPLATFORM golang:latest AS build
|
||||
|
||||
# Build xray-core
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM --platform=$BUILDPLATFORM golang:alpine AS build
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
|
||||
ADD https://github.com/v2fly/geoip/releases/latest/download/geoip.dat /v2fly/geoip.dat
|
||||
ADD https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat /v2fly/geosite.dat
|
||||
ADD https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat /loyalsoldier/geoip.dat
|
||||
ADD https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat /loyalsoldier/geosite.dat
|
||||
|
||||
# Download geodat into a staging directory
|
||||
ADD https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geoip.dat /tmp/geodat/geoip.dat
|
||||
ADD https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat /tmp/geodat/geosite.dat
|
||||
# chainguard/static contains only tzdata and ca-certificates, can be built with multiarch static binaries.
|
||||
FROM --platform=linux/amd64 chainguard/static:latest
|
||||
WORKDIR /var/log/xray
|
||||
COPY .github/docker/files/config.json /etc/xray/config.json
|
||||
COPY --from=build --chmod=755 /src/xray /usr/bin/xray
|
||||
|
||||
RUN mkdir -p /tmp/empty
|
||||
|
||||
# Create config files with empty JSON content
|
||||
RUN mkdir -p /tmp/usr/local/etc/xray
|
||||
RUN cat <<EOF >/tmp/usr/local/etc/xray/00_log.json
|
||||
{
|
||||
"log": {
|
||||
"error": "/var/log/xray/error.log",
|
||||
"loglevel": "warning",
|
||||
"access": "none",
|
||||
"dnsLog": false
|
||||
}
|
||||
}
|
||||
EOF
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/01_api.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/02_dns.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/03_routing.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/04_policy.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/05_inbounds.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/06_outbounds.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/07_transport.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/08_stats.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/09_reverse.json
|
||||
|
||||
# Create log files
|
||||
RUN mkdir -p /tmp/var/log/xray && touch \
|
||||
/tmp/var/log/xray/access.log \
|
||||
/tmp/var/log/xray/error.log
|
||||
|
||||
# Build finally image
|
||||
FROM gcr.io/distroless/static:nonroot
|
||||
|
||||
COPY --from=build --chown=0:0 --chmod=755 /src/xray /usr/local/bin/xray
|
||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /usr/local/share/xray
|
||||
COPY --from=build --chown=0:0 --chmod=644 /tmp/geodat/*.dat /usr/local/share/xray/
|
||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /usr/local/etc/xray
|
||||
COPY --from=build --chown=0:0 --chmod=644 /tmp/usr/local/etc/xray/*.json /usr/local/etc/xray/
|
||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /var/log/xray
|
||||
COPY --from=build --chown=65532:65532 --chmod=600 /tmp/var/log/xray/*.log /var/log/xray/
|
||||
|
||||
VOLUME /usr/local/etc/xray
|
||||
VOLUME /var/log/xray
|
||||
|
||||
ARG TZ=Etc/UTC
|
||||
USER root
|
||||
WORKDIR /root
|
||||
VOLUME /etc/xray
|
||||
ARG TZ=Asia/Shanghai
|
||||
ENV TZ=$TZ
|
||||
ENTRYPOINT [ "/usr/bin/xray" ]
|
||||
CMD [ "-confdir", "/etc/xray/" ]
|
||||
|
||||
ENTRYPOINT [ "/usr/local/bin/xray" ]
|
||||
CMD [ "-confdir", "/usr/local/etc/xray/" ]
|
||||
ARG flavor=v2fly
|
||||
COPY --from=build --chmod=644 /$flavor /usr/share/xray
|
||||
|
71
.github/docker/Dockerfile.usa
vendored
71
.github/docker/Dockerfile.usa
vendored
@@ -1,71 +0,0 @@
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM --platform=$BUILDPLATFORM golang:latest AS build
|
||||
|
||||
# Build xray-core
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
|
||||
|
||||
# Download geodat into a staging directory
|
||||
ADD https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geoip.dat /tmp/geodat/geoip.dat
|
||||
ADD https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat /tmp/geodat/geosite.dat
|
||||
|
||||
RUN mkdir -p /tmp/empty
|
||||
|
||||
# Create config files with empty JSON content
|
||||
RUN mkdir -p /tmp/usr/local/etc/xray
|
||||
RUN cat <<EOF >/tmp/usr/local/etc/xray/00_log.json
|
||||
{
|
||||
"log": {
|
||||
"error": "/var/log/xray/error.log",
|
||||
"loglevel": "warning",
|
||||
"access": "none",
|
||||
"dnsLog": false
|
||||
}
|
||||
}
|
||||
EOF
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/01_api.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/02_dns.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/03_routing.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/04_policy.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/05_inbounds.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/06_outbounds.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/07_transport.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/08_stats.json
|
||||
RUN echo '{}' >/tmp/usr/local/etc/xray/09_reverse.json
|
||||
|
||||
# Create log files
|
||||
RUN mkdir -p /tmp/var/log/xray && touch \
|
||||
/tmp/var/log/xray/access.log \
|
||||
/tmp/var/log/xray/error.log
|
||||
|
||||
# Build finally image
|
||||
# Note on Distroless Base Image and Architecture Support:
|
||||
# - The official 'gcr.io/distroless/static' image provided by Google only supports a limited set of architectures for Linux:
|
||||
# - linux/amd64
|
||||
# - linux/arm/v7
|
||||
# - linux/arm64/v8
|
||||
# - linux/ppc64le
|
||||
# - linux/s390x
|
||||
# - Upon inspection, the blob contents of the Distroless images across these architectures are nearly identical, with only minor differences in metadata (e.g., 'Architecture' field in the manifest).
|
||||
# - Due to this similarity in content, it is feasible to forcibly specify a single platform (e.g., '--platform=linux/amd64') for unsupported architectures, as the core image content remains compatible with statically compiled binaries like Go applications.
|
||||
FROM --platform=linux/amd64 gcr.io/distroless/static:nonroot
|
||||
|
||||
COPY --from=build --chown=0:0 --chmod=755 /src/xray /usr/local/bin/xray
|
||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /usr/local/share/xray
|
||||
COPY --from=build --chown=0:0 --chmod=644 /tmp/geodat/*.dat /usr/local/share/xray/
|
||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /usr/local/etc/xray
|
||||
COPY --from=build --chown=0:0 --chmod=644 /tmp/usr/local/etc/xray/*.json /usr/local/etc/xray/
|
||||
COPY --from=build --chown=0:0 --chmod=755 /tmp/empty /var/log/xray
|
||||
COPY --from=build --chown=65532:65532 --chmod=600 /tmp/var/log/xray/*.log /var/log/xray/
|
||||
|
||||
VOLUME /usr/local/etc/xray
|
||||
VOLUME /var/log/xray
|
||||
|
||||
ARG TZ=Etc/UTC
|
||||
ENV TZ=$TZ
|
||||
|
||||
ENTRYPOINT [ "/usr/local/bin/xray" ]
|
||||
CMD [ "-confdir", "/usr/local/etc/xray/" ]
|
18
.github/docker/files/config.json
vendored
Normal file
18
.github/docker/files/config.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"inbounds": [{
|
||||
"port": 9000,
|
||||
"protocol": "vmess",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"id": "1eb6e917-774b-4a84-aff6-b058577c60a5",
|
||||
"level": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}],
|
||||
"outbounds": [{
|
||||
"protocol": "freedom",
|
||||
"settings": {}
|
||||
}]
|
||||
}
|
152
.github/workflows/docker.yml
vendored
152
.github/workflows/docker.yml
vendored
@@ -1,130 +1,76 @@
|
||||
name: Build and Push Docker Image
|
||||
name: Build docker image
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
- released
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Docker image tag:"
|
||||
required: true
|
||||
latest:
|
||||
description: "Set to latest"
|
||||
type: boolean
|
||||
default: false
|
||||
types: [published]
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
if: (github.event.action != 'published') || (github.event.action == 'published' && github.event.release.prerelease == true)
|
||||
build-image:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Set repository and image name to lowercase
|
||||
env:
|
||||
IMAGE_NAME: "${{ github.repository }}"
|
||||
run: |
|
||||
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
|
||||
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
|
||||
|
||||
- name: Validate and extract tag
|
||||
run: |
|
||||
SOURCE_TAG="${{ github.event.inputs.tag }}"
|
||||
if [[ -z "$SOURCE_TAG" ]]; then
|
||||
SOURCE_TAG="${{ github.ref_name }}"
|
||||
fi
|
||||
|
||||
if [[ -z "$SOURCE_TAG" ]]; then
|
||||
echo "Error: Could not determine a valid tag source. Input tag and context tag (github.ref_name) are both empty."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$SOURCE_TAG" =~ ^v[0-9]+\.[0-9] ]]; then
|
||||
IMAGE_TAG="${SOURCE_TAG#v}"
|
||||
else
|
||||
IMAGE_TAG="$SOURCE_TAG"
|
||||
fi
|
||||
|
||||
echo "Docker image tag: '$IMAGE_TAG'."
|
||||
echo "IMAGE_TAG=$IMAGE_TAG" >>${GITHUB_ENV}
|
||||
|
||||
LATEST=false
|
||||
if [[ "${{ github.event_name }}" == "release" && "${{ github.event.release.prerelease }}" == "false" ]] || [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ github.event.inputs.latest }}" == "true" ]]; then
|
||||
LATEST=true
|
||||
fi
|
||||
|
||||
echo "Latest: '$LATEST'."
|
||||
echo "LATEST=$LATEST" >>${GITHUB_ENV}
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- name: Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/xray-core
|
||||
flavor: latest=auto
|
||||
tags: |
|
||||
type=sha
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
- name: Docker metadata Loyalsoldier flavor
|
||||
id: loyalsoldier
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/xray-core
|
||||
flavor: |
|
||||
latest=auto
|
||||
suffix=-ls,onlatest=true
|
||||
tags: |
|
||||
type=sha
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build Docker image (main architectures)
|
||||
id: build_main_arches
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: .github/docker/Dockerfile
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm/v7
|
||||
linux/arm64/v8
|
||||
linux/ppc64le
|
||||
linux/s390x
|
||||
linux/arm64
|
||||
linux/loong64
|
||||
linux/riscv64
|
||||
provenance: false
|
||||
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
- name: Build Docker image (additional architectures)
|
||||
id: build_additional_arches
|
||||
file: .github/docker/Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
- name: Build and push Loyalsoldier flavor
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: .github/docker/Dockerfile.usa
|
||||
platforms: |
|
||||
linux/386
|
||||
linux/arm/v6
|
||||
linux/riscv64
|
||||
linux/amd64
|
||||
linux/arm64
|
||||
linux/loong64
|
||||
linux/riscv64
|
||||
provenance: false
|
||||
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
- name: Create manifest list and push
|
||||
run: |
|
||||
echo "Creating multi-arch manifest with tag: '${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}'."
|
||||
docker buildx imagetools create \
|
||||
--tag ${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }} \
|
||||
${{ env.FULL_IMAGE_NAME }}@${{ steps.build_main_arches.outputs.digest }} \
|
||||
${{ env.FULL_IMAGE_NAME }}@${{ steps.build_additional_arches.outputs.digest }}
|
||||
|
||||
if [[ "${{ env.LATEST }}" == "true" ]]; then
|
||||
echo "Adding 'latest' tag to manifest: '${{ env.FULL_IMAGE_NAME }}:latest'."
|
||||
docker buildx imagetools create \
|
||||
--tag ${{ env.FULL_IMAGE_NAME }}:latest \
|
||||
${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
||||
fi
|
||||
|
||||
- name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
||||
|
||||
if [[ "${{ env.LATEST }}" == "true" ]]; then
|
||||
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:latest
|
||||
fi
|
||||
file: .github/docker/Dockerfile
|
||||
build-args: flavor=loyalsoldier
|
||||
push: true
|
||||
tags: |
|
||||
${{ steps.loyalsoldier.outputs.tags }}
|
||||
|
33
.github/workflows/release-win7.yml
vendored
33
.github/workflows/release-win7.yml
vendored
@@ -9,38 +9,7 @@ on:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
check-assets:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Restore Geodat Cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: resources
|
||||
key: xray-geodat-
|
||||
|
||||
- name: Check Assets Existence
|
||||
id: check-assets
|
||||
run: |
|
||||
[ -d 'resources' ] || mkdir resources
|
||||
LIST=('geoip.dat' 'geosite.dat')
|
||||
for FILE_NAME in "${LIST[@]}"
|
||||
do
|
||||
echo -e "Checking ${FILE_NAME}..."
|
||||
if [ -s "./resources/${FILE_NAME}" ]; then
|
||||
echo -e "${FILE_NAME} exists."
|
||||
else
|
||||
echo -e "${FILE_NAME} does not exist."
|
||||
echo "missing=true" >> $GITHUB_OUTPUT
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Sleep for 90 seconds if Assets Missing
|
||||
if: steps.check-assets.outputs.missing == 'true'
|
||||
run: sleep 90
|
||||
|
||||
build:
|
||||
needs: check-assets
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
@@ -82,7 +51,7 @@ jobs:
|
||||
GOSDK=$(go env GOROOT)
|
||||
rm -r $GOSDK/*
|
||||
cd $GOSDK
|
||||
curl -O -L -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://github.com/XTLS/go-win7/releases/latest/download/go-for-win7-linux-amd64.zip
|
||||
curl -O -L https://github.com/XTLS/go-win7/releases/latest/download/go-for-win7-linux-amd64.zip
|
||||
unzip ./go-for-win7-linux-amd64.zip -d $GOSDK
|
||||
rm ./go-for-win7-linux-amd64.zip
|
||||
|
||||
|
66
.github/workflows/release.yml
vendored
66
.github/workflows/release.yml
vendored
@@ -9,53 +9,7 @@ on:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
check-assets:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Restore Geodat Cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: resources
|
||||
key: xray-geodat-
|
||||
|
||||
- name: Check Assets Existence
|
||||
id: check-assets
|
||||
run: |
|
||||
[ -d 'resources' ] || mkdir resources
|
||||
LIST=('geoip.dat' 'geosite.dat')
|
||||
for FILE_NAME in "${LIST[@]}"
|
||||
do
|
||||
echo -e "Checking ${FILE_NAME}..."
|
||||
if [ -s "./resources/${FILE_NAME}" ]; then
|
||||
echo -e "${FILE_NAME} exists."
|
||||
else
|
||||
echo -e "${FILE_NAME} does not exist."
|
||||
echo "missing=true" >> $GITHUB_OUTPUT
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Trigger Asset Update Workflow if Assets Missing
|
||||
if: steps.check-assets.outputs.missing == 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const { owner, repo } = context.repo;
|
||||
await github.rest.actions.createWorkflowDispatch({
|
||||
owner,
|
||||
repo,
|
||||
workflow_id: 'scheduled-assets-update.yml',
|
||||
ref: context.ref
|
||||
});
|
||||
console.log('Triggered scheduled-assets-update.yml due to missing assets on branch:', context.ref);
|
||||
|
||||
- name: Sleep for 90 seconds if Assets Missing
|
||||
if: steps.check-assets.outputs.missing == 'true'
|
||||
run: sleep 90
|
||||
|
||||
build:
|
||||
needs: check-assets
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
@@ -88,11 +42,6 @@ jobs:
|
||||
- goos: android
|
||||
goarch: arm64
|
||||
# END Android ARM 8
|
||||
# BEGIN Android AMD64
|
||||
- goos: android
|
||||
goarch: amd64
|
||||
patch-assetname: android-amd64
|
||||
# END Android AMD64
|
||||
# Windows ARM
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
@@ -155,19 +104,6 @@ jobs:
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up NDK
|
||||
if: matrix.goos == 'android'
|
||||
run: |
|
||||
wget -qO android-ndk.zip https://dl.google.com/android/repository/android-ndk-r28b-linux.zip
|
||||
unzip android-ndk.zip
|
||||
rm android-ndk.zip
|
||||
declare -A arches=(
|
||||
["amd64"]="x86_64-linux-android24-clang"
|
||||
["arm64"]="aarch64-linux-android24-clang"
|
||||
)
|
||||
echo CC="$(realpath android-ndk-*/toolchains/llvm/prebuilt/linux-x86_64/bin)/${arches[${{ matrix.goarch }}]}" >> $GITHUB_ENV
|
||||
echo CGO_ENABLED=1 >> $GITHUB_ENV
|
||||
|
||||
- name: Show workflow information
|
||||
run: |
|
||||
_NAME=${{ matrix.patch-assetname }}
|
||||
@@ -183,7 +119,7 @@ jobs:
|
||||
|
||||
- name: Get project dependencies
|
||||
run: go mod download
|
||||
|
||||
|
||||
- name: Build Xray
|
||||
run: |
|
||||
mkdir -p build_assets
|
||||
|
@@ -1,6 +1,6 @@
|
||||
name: Scheduled assets update
|
||||
|
||||
# NOTE: This Github Actions is required by other actions, for preparing other packaging assets in a
|
||||
# NOTE: This Github Actions is required by other actions, for preparing other packaging assets in a
|
||||
# routine manner, for example: GeoIP/GeoSite.
|
||||
# Currently updating:
|
||||
# - Geodat (GeoIP/Geosite)
|
||||
@@ -9,7 +9,7 @@ on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# Update GeoData on every day (22:30 UTC)
|
||||
- cron: "30 22 * * *"
|
||||
- cron: '30 22 * * *'
|
||||
push:
|
||||
# Prevent triggering update request storm
|
||||
paths:
|
||||
@@ -45,12 +45,12 @@ jobs:
|
||||
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3,$4}'))
|
||||
FILE_NAME="${INFO[3]}.dat"
|
||||
echo -e "Verifying HASH key..."
|
||||
HASH="$(curl -sL -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
|
||||
HASH="$(curl -sL "https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
|
||||
if [ -s "./resources/${FILE_NAME}" ] && [ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ]; then
|
||||
continue
|
||||
else
|
||||
echo -e "Downloading https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat..."
|
||||
curl -L -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat" -o ./resources/${FILE_NAME}
|
||||
curl -L "https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat" -o ./resources/${FILE_NAME}
|
||||
echo -e "Verifying HASH key..."
|
||||
[ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ] || { echo -e "The HASH key of ${FILE_NAME} does not match cloud one."; exit 1; }
|
||||
echo "unhit=true" >> $GITHUB_OUTPUT
|
||||
|
29
.github/workflows/test.yml
vendored
29
.github/workflows/test.yml
vendored
@@ -6,36 +6,7 @@ on:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
check-assets:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Restore Geodat Cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: resources
|
||||
key: xray-geodat-
|
||||
- name: Check Assets Existence
|
||||
id: check-assets
|
||||
run: |
|
||||
[ -d 'resources' ] || mkdir resources
|
||||
LIST=('geoip.dat' 'geosite.dat')
|
||||
for FILE_NAME in "${LIST[@]}"
|
||||
do
|
||||
echo -e "Checking ${FILE_NAME}..."
|
||||
if [ -s "./resources/${FILE_NAME}" ]; then
|
||||
echo -e "${FILE_NAME} exists."
|
||||
else
|
||||
echo -e "${FILE_NAME} does not exist."
|
||||
echo "missing=true" >> $GITHUB_OUTPUT
|
||||
break
|
||||
fi
|
||||
done
|
||||
- name: Sleep for 90 seconds if Assets Missing
|
||||
if: steps.check-assets.outputs.missing == 'true'
|
||||
run: sleep 90
|
||||
|
||||
test:
|
||||
needs: check-assets
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
17
.gitignore
vendored
17
.gitignore
vendored
@@ -14,18 +14,10 @@
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# macOS specific files
|
||||
*.DS_Store
|
||||
|
||||
# IDE specific files
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
# Archive files
|
||||
.idea
|
||||
*.zip
|
||||
*.tar.gz
|
||||
|
||||
# Binaries
|
||||
xray
|
||||
xray_softfloat
|
||||
mockgen
|
||||
@@ -34,13 +26,8 @@ vprotogen
|
||||
errorgen
|
||||
!common/errors/errorgen/
|
||||
*.dat
|
||||
|
||||
# Build assets
|
||||
.vscode
|
||||
/build_assets
|
||||
|
||||
# Output from dlv test
|
||||
**/debug.*
|
||||
|
||||
# Certificates
|
||||
*.crt
|
||||
*.key
|
||||
|
26
README.md
26
README.md
@@ -38,13 +38,12 @@
|
||||
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
|
||||
- [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:**
|
||||
- [Remnawave](https://github.com/remnawave/panel)
|
||||
- [Marzban](https://github.com/Gozargah/Marzban)
|
||||
- [Xray-UI](https://github.com/qist/xray-ui)
|
||||
- [Hiddify](https://github.com/hiddify/Hiddify-Manager)
|
||||
- One Click
|
||||
- [Xray-REALITY](https://github.com/zxcvos/Xray-script), [xray-reality](https://github.com/sajjaddg/xray-reality), [reality-ezpz](https://github.com/aleskxyz/reality-ezpz)
|
||||
- [Xray_bash_onekey](https://github.com/hello-yunshu/Xray_bash_onekey), [XTool](https://github.com/LordPenguin666/XTool), [VPainLess](https://github.com/vpainless/vpainless)
|
||||
- [Xray_bash_onekey](https://github.com/hello-yunshu/Xray_bash_onekey), [XTool](https://github.com/LordPenguin666/XTool)
|
||||
- [v2ray-agent](https://github.com/mack-a/v2ray-agent), [Xray_onekey](https://github.com/wulabing/Xray_onekey), [ProxySU](https://github.com/proxysu/ProxySU)
|
||||
- Magisk
|
||||
- [Xray4Magisk](https://github.com/Asterisk4Magisk/Xray4Magisk)
|
||||
@@ -81,40 +80,31 @@
|
||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
- Android
|
||||
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
||||
- [X-flutter](https://github.com/XTLS/X-flutter)
|
||||
- [SaeedDev94/Xray](https://github.com/SaeedDev94/Xray)
|
||||
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
- iOS & macOS arm64
|
||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215)
|
||||
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
|
||||
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)
|
||||
- [OneXray](https://github.com/OneXray/OneXray)
|
||||
- macOS arm64 & x64
|
||||
- [V2rayU](https://github.com/yanue/V2rayU)
|
||||
- [V2RayXS](https://github.com/tzmax/V2RayXS)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
- [OneXray](https://github.com/OneXray/OneXray)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
|
||||
- Linux
|
||||
- [v2rayA](https://github.com/v2rayA/v2rayA)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
- [GorzRay](https://github.com/ketetefid/GorzRay)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
|
||||
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
||||
|
||||
- iOS & macOS arm64
|
||||
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
||||
- [Loon](https://apps.apple.com/us/app/loon/id1373567447)
|
||||
- Xray Tools
|
||||
- [xray-knife](https://github.com/lilendian0x00/xray-knife)
|
||||
- [xray-checker](https://github.com/kutovoys/xray-checker)
|
||||
- Xray Wrapper
|
||||
- [XTLS/libXray](https://github.com/XTLS/libXray)
|
||||
- [xtls-sdk](https://github.com/remnawave/xtls-sdk)
|
||||
- [xtlsapi](https://github.com/hiddify/xtlsapi)
|
||||
- [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite)
|
||||
- [Xray-core-python](https://github.com/LorenEteval/Xray-core-python)
|
||||
@@ -122,17 +112,15 @@
|
||||
- [XrayR](https://github.com/XrayR-project/XrayR)
|
||||
- [XrayR-release](https://github.com/XrayR-project/XrayR-release)
|
||||
- [XrayR-V2Board](https://github.com/missuo/XrayR-V2Board)
|
||||
- Cores
|
||||
- [Amnezia VPN](https://github.com/amnezia-vpn)
|
||||
- [mihomo](https://github.com/MetaCubeX/mihomo)
|
||||
- [sing-box](https://github.com/SagerNet/sing-box)
|
||||
- [Clash.Meta](https://github.com/MetaCubeX/Clash.Meta)
|
||||
- [clashN](https://github.com/2dust/clashN)
|
||||
- [Clash Meta for Android](https://github.com/MetaCubeX/ClashMetaForAndroid)
|
||||
- [sing-box](https://github.com/SagerNet/sing-box)
|
||||
|
||||
## Contributing
|
||||
|
||||
[Code of Conduct](https://github.com/XTLS/Xray-core/blob/main/CODE_OF_CONDUCT.md)
|
||||
|
||||
[](https://deepwiki.com/XTLS/Xray-core)
|
||||
|
||||
## Credits
|
||||
|
||||
- [Xray-core v1.0.0](https://github.com/XTLS/Xray-core/releases/tag/v1.0.0) was forked from [v2fly-core 9a03cc5](https://github.com/v2fly/v2ray-core/commit/9a03cc5c98d04cc28320fcee26dbc236b3291256), and we have made & accumulated a huge number of enhancements over time, check [the release notes for each version](https://github.com/XTLS/Xray-core/releases).
|
||||
|
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/net/cnc"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/signal/done"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
)
|
||||
@@ -109,13 +108,3 @@ func (co *Outbound) Close() error {
|
||||
co.closed = true
|
||||
return co.listener.Close()
|
||||
}
|
||||
|
||||
// SenderSettings implements outbound.Handler.
|
||||
func (co *Outbound) SenderSettings() *serial.TypedMessage {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProxySettings implements outbound.Handler.
|
||||
func (co *Outbound) ProxySettings() *serial.TypedMessage {
|
||||
return nil
|
||||
}
|
||||
|
@@ -31,23 +31,33 @@ type cachedReader struct {
|
||||
sync.Mutex
|
||||
reader *pipe.Reader
|
||||
cache buf.MultiBuffer
|
||||
|
||||
ReadBufferTimeout time.Duration
|
||||
}
|
||||
|
||||
func (r *cachedReader) Cache(b *buf.Buffer, deadline time.Duration) error {
|
||||
mb, err := r.reader.ReadMultiBufferTimeout(deadline)
|
||||
if err != nil {
|
||||
return err
|
||||
func (r *cachedReader) Cache(b *buf.Buffer) {
|
||||
var timeout time.Duration
|
||||
if r.ReadBufferTimeout == 0 {
|
||||
timeout = time.Millisecond * 100
|
||||
} else {
|
||||
timeout = r.ReadBufferTimeout
|
||||
}
|
||||
mb, _ := r.reader.ReadMultiBufferTimeout(timeout)
|
||||
r.Lock()
|
||||
if !mb.IsEmpty() {
|
||||
r.cache, _ = buf.MergeMulti(r.cache, mb)
|
||||
}
|
||||
b.Clear()
|
||||
rawBytes := b.Extend(min(r.cache.Len(), b.Cap()))
|
||||
cacheLen := r.cache.Len()
|
||||
if cacheLen <= b.Cap() {
|
||||
b.Clear()
|
||||
} else {
|
||||
b.Release()
|
||||
*b = *buf.NewWithSize(cacheLen)
|
||||
}
|
||||
rawBytes := b.Extend(cacheLen)
|
||||
n := r.cache.Copy(rawBytes)
|
||||
b.Resize(0, int32(n))
|
||||
r.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *cachedReader) readInternal() buf.MultiBuffer {
|
||||
@@ -96,6 +106,7 @@ type DefaultDispatcher struct {
|
||||
router routing.Router
|
||||
policy policy.Manager
|
||||
stats stats.Manager
|
||||
dns dns.Client
|
||||
fdns dns.FakeDNSEngine
|
||||
}
|
||||
|
||||
@@ -106,7 +117,7 @@ func init() {
|
||||
core.OptionalFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||
d.fdns = fdns
|
||||
})
|
||||
return d.Init(config.(*Config), om, router, pm, sm)
|
||||
return d.Init(config.(*Config), om, router, pm, sm, dc)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -115,11 +126,12 @@ func init() {
|
||||
}
|
||||
|
||||
// Init initializes DefaultDispatcher.
|
||||
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager) error {
|
||||
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dns dns.Client) error {
|
||||
d.ohm = om
|
||||
d.router = router
|
||||
d.policy = pm
|
||||
d.stats = sm
|
||||
d.dns = dns
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -351,11 +363,13 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
||||
}
|
||||
|
||||
func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, network net.Network) (SniffResult, error) {
|
||||
payload := buf.NewWithSize(32767)
|
||||
payload := buf.New()
|
||||
defer payload.Release()
|
||||
|
||||
sniffer := NewSniffer(ctx)
|
||||
|
||||
cReader.ReadBufferTimeout = sniffer.Timeout
|
||||
|
||||
metaresult, metadataErr := sniffer.SniffMetadata(ctx)
|
||||
|
||||
if metadataOnly {
|
||||
@@ -363,36 +377,26 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
|
||||
}
|
||||
|
||||
contentResult, contentErr := func() (SniffResult, error) {
|
||||
cacheDeadline := 200 * time.Millisecond
|
||||
totalAttempt := 0
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
cachingStartingTimeStamp := time.Now()
|
||||
err := cReader.Cache(payload, cacheDeadline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
totalAttempt++
|
||||
if totalAttempt > 2 {
|
||||
return nil, errSniffingTimeout
|
||||
}
|
||||
cachingTimeElapsed := time.Since(cachingStartingTimeStamp)
|
||||
cacheDeadline -= cachingTimeElapsed
|
||||
|
||||
cReader.Cache(payload)
|
||||
if !payload.IsEmpty() {
|
||||
result, err := sniffer.Sniff(ctx, payload.Bytes(), network)
|
||||
switch err {
|
||||
case common.ErrNoClue: // No Clue: protocol not matches, and sniffer cannot determine whether there will be a match or not
|
||||
totalAttempt++
|
||||
case protocol.ErrProtoNeedMoreData: // Protocol Need More Data: protocol matches, but need more data to complete sniffing
|
||||
// in this case, do not add totalAttempt(allow to read until timeout)
|
||||
default:
|
||||
if err != common.ErrNoClue {
|
||||
return result, err
|
||||
}
|
||||
} else {
|
||||
totalAttempt++
|
||||
}
|
||||
if totalAttempt >= 2 || cacheDeadline <= 0 {
|
||||
return nil, errSniffingTimeout
|
||||
if payload.IsFull() {
|
||||
return nil, errUnknownContent
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -408,6 +412,18 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
|
||||
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
if hosts, ok := d.dns.(dns.HostsLookup); ok && destination.Address.Family().IsDomain() {
|
||||
proxied := hosts.LookupHosts(ob.Target.String())
|
||||
if proxied != nil {
|
||||
ro := ob.RouteTarget == destination
|
||||
destination.Address = *proxied
|
||||
if ro {
|
||||
ob.RouteTarget = destination
|
||||
} else {
|
||||
ob.Target = destination
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var handler outbound.Handler
|
||||
|
||||
|
@@ -2,15 +2,16 @@ package dispatcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/protocol/bittorrent"
|
||||
"github.com/xtls/xray-core/common/protocol/http"
|
||||
"github.com/xtls/xray-core/common/protocol/quic"
|
||||
"github.com/xtls/xray-core/common/protocol/tls"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
)
|
||||
|
||||
type SniffResult interface {
|
||||
@@ -31,9 +32,11 @@ type protocolSnifferWithMetadata struct {
|
||||
|
||||
type Sniffer struct {
|
||||
sniffer []protocolSnifferWithMetadata
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
func NewSniffer(ctx context.Context) *Sniffer {
|
||||
content := session.ContentFromContext(ctx)
|
||||
ret := &Sniffer{
|
||||
sniffer: []protocolSnifferWithMetadata{
|
||||
{func(c context.Context, b []byte) (SniffResult, error) { return http.SniffHTTP(b, c) }, false, net.Network_TCP},
|
||||
@@ -42,6 +45,7 @@ func NewSniffer(ctx context.Context) *Sniffer {
|
||||
{func(c context.Context, b []byte) (SniffResult, error) { return quic.SniffQUIC(b) }, false, net.Network_UDP},
|
||||
{func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffUTP(b) }, false, net.Network_UDP},
|
||||
},
|
||||
Timeout: content.SniffingRequest.Timeout,
|
||||
}
|
||||
if sniffer, err := newFakeDNSSniffer(ctx); err == nil {
|
||||
others := ret.sniffer
|
||||
@@ -59,17 +63,14 @@ var errUnknownContent = errors.New("unknown content")
|
||||
func (s *Sniffer) Sniff(c context.Context, payload []byte, network net.Network) (SniffResult, error) {
|
||||
var pendingSniffer []protocolSnifferWithMetadata
|
||||
for _, si := range s.sniffer {
|
||||
protocolSniffer := si.protocolSniffer
|
||||
s := si.protocolSniffer
|
||||
if si.metadataSniffer || si.network != network {
|
||||
continue
|
||||
}
|
||||
result, err := protocolSniffer(c, payload)
|
||||
result, err := s(c, payload)
|
||||
if err == common.ErrNoClue {
|
||||
pendingSniffer = append(pendingSniffer, si)
|
||||
continue
|
||||
} else if err == protocol.ErrProtoNeedMoreData { // Sniffer protocol matched, but need more data to complete sniffing
|
||||
s.sniffer = []protocolSnifferWithMetadata{si}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err == nil && result != nil {
|
||||
|
@@ -1,188 +0,0 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
go_errors "errors"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CacheController struct {
|
||||
sync.RWMutex
|
||||
ips map[string]*record
|
||||
pub *pubsub.Service
|
||||
cacheCleanup *task.Periodic
|
||||
name string
|
||||
disableCache bool
|
||||
}
|
||||
|
||||
func NewCacheController(name string, disableCache bool) *CacheController {
|
||||
c := &CacheController{
|
||||
name: name,
|
||||
disableCache: disableCache,
|
||||
ips: make(map[string]*record),
|
||||
pub: pubsub.NewService(),
|
||||
}
|
||||
|
||||
c.cacheCleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
Execute: c.CacheCleanup,
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// CacheCleanup clears expired items from cache
|
||||
func (c *CacheController) CacheCleanup() error {
|
||||
now := time.Now()
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
if len(c.ips) == 0 {
|
||||
return errors.New("nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for domain, record := range c.ips {
|
||||
if record.A != nil && record.A.Expire.Before(now) {
|
||||
record.A = nil
|
||||
}
|
||||
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
||||
record.AAAA = nil
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
errors.LogDebug(context.Background(), c.name, "cache cleanup ", domain)
|
||||
delete(c.ips, domain)
|
||||
} else {
|
||||
c.ips[domain] = record
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.ips) == 0 {
|
||||
c.ips = make(map[string]*record)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CacheController) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
elapsed := time.Since(req.start)
|
||||
|
||||
c.Lock()
|
||||
rec, found := c.ips[req.domain]
|
||||
if !found {
|
||||
rec = &record{}
|
||||
}
|
||||
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
rec.A = ipRec
|
||||
case dnsmessage.TypeAAAA:
|
||||
rec.AAAA = ipRec
|
||||
}
|
||||
|
||||
errors.LogInfo(context.Background(), c.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||
c.ips[req.domain] = rec
|
||||
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
c.pub.Publish(req.domain+"4", nil)
|
||||
if !c.disableCache {
|
||||
_, _, err := rec.AAAA.getIPs()
|
||||
if !go_errors.Is(err, errRecordNotFound) {
|
||||
c.pub.Publish(req.domain+"6", nil)
|
||||
}
|
||||
}
|
||||
case dnsmessage.TypeAAAA:
|
||||
c.pub.Publish(req.domain+"6", nil)
|
||||
if !c.disableCache {
|
||||
_, _, err := rec.A.getIPs()
|
||||
if !go_errors.Is(err, errRecordNotFound) {
|
||||
c.pub.Publish(req.domain+"4", nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.Unlock()
|
||||
common.Must(c.cacheCleanup.Start())
|
||||
}
|
||||
|
||||
func (c *CacheController) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||
c.RLock()
|
||||
record, found := c.ips[domain]
|
||||
c.RUnlock()
|
||||
|
||||
if !found {
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
|
||||
var errs []error
|
||||
var allIPs []net.IP
|
||||
var rTTL uint32 = dns_feature.DefaultTTL
|
||||
|
||||
mergeReq := option.IPv4Enable && option.IPv6Enable
|
||||
|
||||
if option.IPv4Enable {
|
||||
ips, ttl, err := record.A.getIPs()
|
||||
if !mergeReq || go_errors.Is(err, errRecordNotFound) {
|
||||
return ips, ttl, err
|
||||
}
|
||||
if ttl < rTTL {
|
||||
rTTL = ttl
|
||||
}
|
||||
if len(ips) > 0 {
|
||||
allIPs = append(allIPs, ips...)
|
||||
} else {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if option.IPv6Enable {
|
||||
ips, ttl, err := record.AAAA.getIPs()
|
||||
if !mergeReq || go_errors.Is(err, errRecordNotFound) {
|
||||
return ips, ttl, err
|
||||
}
|
||||
if ttl < rTTL {
|
||||
rTTL = ttl
|
||||
}
|
||||
if len(ips) > 0 {
|
||||
allIPs = append(allIPs, ips...)
|
||||
} else {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(allIPs) > 0 {
|
||||
return allIPs, rTTL, nil
|
||||
}
|
||||
if go_errors.Is(errs[0], errs[1]) {
|
||||
return nil, rTTL, errs[0]
|
||||
}
|
||||
return nil, rTTL, errors.Combine(errs...)
|
||||
}
|
||||
|
||||
func (c *CacheController) registerSubscribers(domain string, option dns_feature.IPOption) (sub4 *pubsub.Subscriber, sub6 *pubsub.Subscriber) {
|
||||
// ipv4 and ipv6 belong to different subscription groups
|
||||
if option.IPv4Enable {
|
||||
sub4 = c.pub.Subscribe(domain + "4")
|
||||
}
|
||||
if option.IPv6Enable {
|
||||
sub6 = c.pub.Subscribe(domain + "6")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func closeSubscribers(sub4 *pubsub.Subscriber, sub6 *pubsub.Subscriber) {
|
||||
if sub4 != nil {
|
||||
sub4.Close()
|
||||
}
|
||||
if sub6 != nil {
|
||||
sub6.Close()
|
||||
}
|
||||
}
|
@@ -80,7 +80,6 @@ const (
|
||||
QueryStrategy_USE_IP QueryStrategy = 0
|
||||
QueryStrategy_USE_IP4 QueryStrategy = 1
|
||||
QueryStrategy_USE_IP6 QueryStrategy = 2
|
||||
QueryStrategy_USE_SYS QueryStrategy = 3
|
||||
)
|
||||
|
||||
// Enum value maps for QueryStrategy.
|
||||
@@ -89,13 +88,11 @@ var (
|
||||
0: "USE_IP",
|
||||
1: "USE_IP4",
|
||||
2: "USE_IP6",
|
||||
3: "USE_SYS",
|
||||
}
|
||||
QueryStrategy_value = map[string]int32{
|
||||
"USE_IP": 0,
|
||||
"USE_IP4": 1,
|
||||
"USE_IP6": 2,
|
||||
"USE_SYS": 3,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -135,16 +132,9 @@ type NameServer struct {
|
||||
ClientIp []byte `protobuf:"bytes,5,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
|
||||
SkipFallback bool `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"`
|
||||
PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
|
||||
ExpectedGeoip []*router.GeoIP `protobuf:"bytes,3,rep,name=expected_geoip,json=expectedGeoip,proto3" json:"expected_geoip,omitempty"`
|
||||
Geoip []*router.GeoIP `protobuf:"bytes,3,rep,name=geoip,proto3" json:"geoip,omitempty"`
|
||||
OriginalRules []*NameServer_OriginalRule `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
|
||||
QueryStrategy QueryStrategy `protobuf:"varint,7,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
||||
ActPrior bool `protobuf:"varint,8,opt,name=actPrior,proto3" json:"actPrior,omitempty"`
|
||||
Tag string `protobuf:"bytes,9,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
TimeoutMs uint64 `protobuf:"varint,10,opt,name=timeoutMs,proto3" json:"timeoutMs,omitempty"`
|
||||
DisableCache bool `protobuf:"varint,11,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
|
||||
FinalQuery bool `protobuf:"varint,12,opt,name=finalQuery,proto3" json:"finalQuery,omitempty"`
|
||||
UnexpectedGeoip []*router.GeoIP `protobuf:"bytes,13,rep,name=unexpected_geoip,json=unexpectedGeoip,proto3" json:"unexpected_geoip,omitempty"`
|
||||
ActUnprior bool `protobuf:"varint,14,opt,name=actUnprior,proto3" json:"actUnprior,omitempty"`
|
||||
}
|
||||
|
||||
func (x *NameServer) Reset() {
|
||||
@@ -205,9 +195,9 @@ func (x *NameServer) GetPrioritizedDomain() []*NameServer_PriorityDomain {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *NameServer) GetExpectedGeoip() []*router.GeoIP {
|
||||
func (x *NameServer) GetGeoip() []*router.GeoIP {
|
||||
if x != nil {
|
||||
return x.ExpectedGeoip
|
||||
return x.Geoip
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -226,55 +216,6 @@ func (x *NameServer) GetQueryStrategy() QueryStrategy {
|
||||
return QueryStrategy_USE_IP
|
||||
}
|
||||
|
||||
func (x *NameServer) GetActPrior() bool {
|
||||
if x != nil {
|
||||
return x.ActPrior
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *NameServer) GetTag() string {
|
||||
if x != nil {
|
||||
return x.Tag
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NameServer) GetTimeoutMs() uint64 {
|
||||
if x != nil {
|
||||
return x.TimeoutMs
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *NameServer) GetDisableCache() bool {
|
||||
if x != nil {
|
||||
return x.DisableCache
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *NameServer) GetFinalQuery() bool {
|
||||
if x != nil {
|
||||
return x.FinalQuery
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *NameServer) GetUnexpectedGeoip() []*router.GeoIP {
|
||||
if x != nil {
|
||||
return x.UnexpectedGeoip
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *NameServer) GetActUnprior() bool {
|
||||
if x != nil {
|
||||
return x.ActUnprior
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -567,7 +508,7 @@ var file_app_dns_config_proto_rawDesc = []byte{
|
||||
0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74,
|
||||
0x2f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x1a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb6, 0x06, 0x0a, 0x0a,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb2, 0x04, 0x0a, 0x0a,
|
||||
0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64,
|
||||
0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e,
|
||||
@@ -581,92 +522,75 @@ var file_app_dns_config_proto_rawDesc = []byte{
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65,
|
||||
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44,
|
||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x11, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a,
|
||||
0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3d, 0x0a, 0x0e, 0x65, 0x78, 0x70, 0x65,
|
||||
0x63, 0x74, 0x65, 0x64, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0d, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74,
|
||||
0x65, 0x64, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69,
|
||||
0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e,
|
||||
0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e,
|
||||
0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
|
||||
0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65,
|
||||
0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72,
|
||||
0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x74,
|
||||
0x50, 0x72, 0x69, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x63, 0x74,
|
||||
0x50, 0x72, 0x69, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x09, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x6f,
|
||||
0x75, 0x74, 0x4d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
|
||||
0x6f, 0x75, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
|
||||
0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6e,
|
||||
0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66,
|
||||
0x69, 0x6e, 0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x41, 0x0a, 0x10, 0x75, 0x6e, 0x65,
|
||||
0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0d, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0f, 0x75, 0x6e, 0x65,
|
||||
0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a,
|
||||
0x61, 0x63, 0x74, 0x55, 0x6e, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x0a, 0x61, 0x63, 0x74, 0x55, 0x6e, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x1a, 0x5e, 0x0a, 0x0e,
|
||||
0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34,
|
||||
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61,
|
||||
0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04,
|
||||
0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c,
|
||||
0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04,
|
||||
0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65,
|
||||
0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04,
|
||||
0x73, 0x69, 0x7a, 0x65, 0x22, 0x9c, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
||||
0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c,
|
||||
0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63,
|
||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69,
|
||||
0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52,
|
||||
0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03,
|
||||
0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x22,
|
||||
0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63,
|
||||
0x68, 0x65, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61,
|
||||
0x74, 0x65, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74,
|
||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
|
||||
0x12, 0x36, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62,
|
||||
0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
|
||||
0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x1a, 0x92, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73,
|
||||
0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63,
|
||||
0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16,
|
||||
0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03,
|
||||
0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65,
|
||||
0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
|
||||
0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x04, 0x08,
|
||||
0x07, 0x10, 0x08, 0x2a, 0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74,
|
||||
0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c,
|
||||
0x6c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x10, 0x02, 0x12,
|
||||
0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x2a, 0x42, 0x0a, 0x0d, 0x51, 0x75,
|
||||
0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55,
|
||||
0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49,
|
||||
0x50, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10,
|
||||
0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x53, 0x59, 0x53, 0x10, 0x03, 0x42, 0x46,
|
||||
0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64,
|
||||
0x6e, 0x73, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f,
|
||||
0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41,
|
||||
0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69,
|
||||
0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52,
|
||||
0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e,
|
||||
0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25,
|
||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61,
|
||||
0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61,
|
||||
0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52,
|
||||
0x75, 0x6c, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74,
|
||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72,
|
||||
0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79,
|
||||
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x1a, 0x5e, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f,
|
||||
0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79,
|
||||
0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61,
|
||||
0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
|
||||
0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67,
|
||||
0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04,
|
||||
0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65,
|
||||
0x22, 0x9c, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0b, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e,
|
||||
0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
|
||||
0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||
0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x68, 0x6f,
|
||||
0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
|
||||
0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73, 0x74, 0x61,
|
||||
0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18,
|
||||
0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69,
|
||||
0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x42,
|
||||
0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||
0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74,
|
||||
0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||
0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c,
|
||||
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x69, 0x73,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x36, 0x0a, 0x16,
|
||||
0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49,
|
||||
0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x64, 0x69,
|
||||
0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d,
|
||||
0x61, 0x74, 0x63, 0x68, 0x1a, 0x92, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70,
|
||||
0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e,
|
||||
0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67,
|
||||
0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f,
|
||||
0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61,
|
||||
0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x02,
|
||||
0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f,
|
||||
0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78,
|
||||
0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x2a,
|
||||
0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e,
|
||||
0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12,
|
||||
0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b,
|
||||
0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52,
|
||||
0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x2a, 0x35, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49,
|
||||
0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x01,
|
||||
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x02, 0x42, 0x46, 0x0a,
|
||||
0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e,
|
||||
0x73, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61,
|
||||
0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70,
|
||||
0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -697,20 +621,19 @@ var file_app_dns_config_proto_goTypes = []any{
|
||||
var file_app_dns_config_proto_depIdxs = []int32{
|
||||
7, // 0: xray.app.dns.NameServer.address:type_name -> xray.common.net.Endpoint
|
||||
4, // 1: xray.app.dns.NameServer.prioritized_domain:type_name -> xray.app.dns.NameServer.PriorityDomain
|
||||
8, // 2: xray.app.dns.NameServer.expected_geoip:type_name -> xray.app.router.GeoIP
|
||||
8, // 2: xray.app.dns.NameServer.geoip:type_name -> xray.app.router.GeoIP
|
||||
5, // 3: xray.app.dns.NameServer.original_rules:type_name -> xray.app.dns.NameServer.OriginalRule
|
||||
1, // 4: xray.app.dns.NameServer.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
||||
8, // 5: xray.app.dns.NameServer.unexpected_geoip:type_name -> xray.app.router.GeoIP
|
||||
2, // 6: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer
|
||||
6, // 7: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
||||
1, // 8: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
||||
0, // 9: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
|
||||
0, // 10: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType
|
||||
11, // [11:11] is the sub-list for method output_type
|
||||
11, // [11:11] is the sub-list for method input_type
|
||||
11, // [11:11] is the sub-list for extension type_name
|
||||
11, // [11:11] is the sub-list for extension extendee
|
||||
0, // [0:11] is the sub-list for field type_name
|
||||
2, // 5: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer
|
||||
6, // 6: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
||||
1, // 7: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
||||
0, // 8: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
|
||||
0, // 9: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType
|
||||
10, // [10:10] is the sub-list for method output_type
|
||||
10, // [10:10] is the sub-list for method input_type
|
||||
10, // [10:10] is the sub-list for extension type_name
|
||||
10, // [10:10] is the sub-list for extension extendee
|
||||
0, // [0:10] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_app_dns_config_proto_init() }
|
||||
|
@@ -25,16 +25,9 @@ message NameServer {
|
||||
}
|
||||
|
||||
repeated PriorityDomain prioritized_domain = 2;
|
||||
repeated xray.app.router.GeoIP expected_geoip = 3;
|
||||
repeated xray.app.router.GeoIP geoip = 3;
|
||||
repeated OriginalRule original_rules = 4;
|
||||
QueryStrategy query_strategy = 7;
|
||||
bool actPrior = 8;
|
||||
string tag = 9;
|
||||
uint64 timeoutMs = 10;
|
||||
bool disableCache = 11;
|
||||
bool finalQuery = 12;
|
||||
repeated xray.app.router.GeoIP unexpected_geoip = 13;
|
||||
bool actUnprior = 14;
|
||||
}
|
||||
|
||||
enum DomainMatchingType {
|
||||
@@ -48,7 +41,6 @@ enum QueryStrategy {
|
||||
USE_IP = 0;
|
||||
USE_IP4 = 1;
|
||||
USE_IP6 = 2;
|
||||
USE_SYS = 3;
|
||||
}
|
||||
|
||||
message Config {
|
||||
|
194
app/dns/dns.go
194
app/dns/dns.go
@@ -3,12 +3,11 @@ package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
go_errors "errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
@@ -20,6 +19,8 @@ import (
|
||||
// DNS is a DNS rely server.
|
||||
type DNS struct {
|
||||
sync.Mutex
|
||||
tag string
|
||||
disableCache bool
|
||||
disableFallback bool
|
||||
disableFallbackIfMatch bool
|
||||
ipOption *dns.IPOption
|
||||
@@ -28,7 +29,6 @@ type DNS struct {
|
||||
ctx context.Context
|
||||
domainMatcher strmatcher.IndexMatcher
|
||||
matcherInfos []*DomainMatcherInfo
|
||||
checkSystem bool
|
||||
}
|
||||
|
||||
// DomainMatcherInfo contains information attached to index returned by Server.domainMatcher
|
||||
@@ -39,6 +39,13 @@ type DomainMatcherInfo struct {
|
||||
|
||||
// New creates a new DNS server with given configuration.
|
||||
func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
var tag string
|
||||
if len(config.Tag) > 0 {
|
||||
tag = config.Tag
|
||||
} else {
|
||||
tag = generateRandomTag()
|
||||
}
|
||||
|
||||
var clientIP net.IP
|
||||
switch len(config.ClientIp) {
|
||||
case 0, net.IPv4len, net.IPv6len:
|
||||
@@ -47,36 +54,26 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
return nil, errors.New("unexpected client IP length ", len(config.ClientIp))
|
||||
}
|
||||
|
||||
var ipOption dns.IPOption
|
||||
checkSystem := false
|
||||
var ipOption *dns.IPOption
|
||||
switch config.QueryStrategy {
|
||||
case QueryStrategy_USE_IP:
|
||||
ipOption = dns.IPOption{
|
||||
ipOption = &dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
}
|
||||
case QueryStrategy_USE_SYS:
|
||||
ipOption = dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
}
|
||||
checkSystem = true
|
||||
case QueryStrategy_USE_IP4:
|
||||
ipOption = dns.IPOption{
|
||||
ipOption = &dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: false,
|
||||
FakeEnable: false,
|
||||
}
|
||||
case QueryStrategy_USE_IP6:
|
||||
ipOption = dns.IPOption{
|
||||
ipOption = &dns.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("unexpected query strategy ", config.QueryStrategy)
|
||||
}
|
||||
|
||||
hosts, err := NewStaticHosts(config.StaticHosts)
|
||||
@@ -84,14 +81,8 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
return nil, errors.New("failed to create hosts").Base(err)
|
||||
}
|
||||
|
||||
var clients []*Client
|
||||
clients := []*Client{}
|
||||
domainRuleCount := 0
|
||||
|
||||
var defaultTag = config.Tag
|
||||
if len(config.Tag) == 0 {
|
||||
defaultTag = generateRandomTag()
|
||||
}
|
||||
|
||||
for _, ns := range config.NameServer {
|
||||
domainRuleCount += len(ns.PrioritizedDomain)
|
||||
}
|
||||
@@ -99,6 +90,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
// MatcherInfos is ensured to cover the maximum index domainMatcher could return, where matcher's index starts from 1
|
||||
matcherInfos := make([]*DomainMatcherInfo, domainRuleCount+1)
|
||||
domainMatcher := &strmatcher.MatcherGroup{}
|
||||
geoipContainer := router.GeoIPMatcherContainer{}
|
||||
|
||||
for _, ns := range config.NameServer {
|
||||
clientIdx := len(clients)
|
||||
@@ -116,19 +108,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
case net.IPv4len, net.IPv6len:
|
||||
myClientIP = net.IP(ns.ClientIp)
|
||||
}
|
||||
|
||||
disableCache := config.DisableCache || ns.DisableCache
|
||||
|
||||
var tag = defaultTag
|
||||
if len(ns.Tag) > 0 {
|
||||
tag = ns.Tag
|
||||
}
|
||||
clientIPOption := ResolveIpOptionOverride(ns.QueryStrategy, ipOption)
|
||||
if !clientIPOption.IPv4Enable && !clientIPOption.IPv6Enable {
|
||||
return nil, errors.New("no QueryStrategy available for ", ns.Address)
|
||||
}
|
||||
|
||||
client, err := NewClient(ctx, ns, myClientIP, disableCache, tag, clientIPOption, &matcherInfos, updateDomain)
|
||||
client, err := NewClient(ctx, ns, myClientIP, geoipContainer, &matcherInfos, updateDomain)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to create client").Base(err)
|
||||
}
|
||||
@@ -137,19 +117,20 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
|
||||
// If there is no DNS client in config, add a `localhost` DNS client
|
||||
if len(clients) == 0 {
|
||||
clients = append(clients, NewLocalDNSClient(ipOption))
|
||||
clients = append(clients, NewLocalDNSClient())
|
||||
}
|
||||
|
||||
return &DNS{
|
||||
tag: tag,
|
||||
hosts: hosts,
|
||||
ipOption: &ipOption,
|
||||
ipOption: ipOption,
|
||||
clients: clients,
|
||||
ctx: ctx,
|
||||
domainMatcher: domainMatcher,
|
||||
matcherInfos: matcherInfos,
|
||||
disableCache: config.DisableCache,
|
||||
disableFallback: config.DisableFallback,
|
||||
disableFallbackIfMatch: config.DisableFallbackIfMatch,
|
||||
checkSystem: checkSystem,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -171,96 +152,94 @@ func (s *DNS) Close() error {
|
||||
// IsOwnLink implements proxy.dns.ownLinkVerifier
|
||||
func (s *DNS) IsOwnLink(ctx context.Context) bool {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound == nil {
|
||||
return false
|
||||
}
|
||||
for _, client := range s.clients {
|
||||
if client.tag == inbound.Tag {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return inbound != nil && inbound.Tag == s.tag
|
||||
}
|
||||
|
||||
// LookupIP implements dns.Client.
|
||||
func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
||||
// Normalize the FQDN form query
|
||||
domain = strings.TrimSuffix(domain, ".")
|
||||
func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
|
||||
if domain == "" {
|
||||
return nil, 0, errors.New("empty domain name")
|
||||
return nil, errors.New("empty domain name")
|
||||
}
|
||||
|
||||
if s.checkSystem {
|
||||
supportIPv4, supportIPv6 := checkSystemNetwork()
|
||||
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
||||
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
||||
} else {
|
||||
option.IPv4Enable = option.IPv4Enable && s.ipOption.IPv4Enable
|
||||
option.IPv6Enable = option.IPv6Enable && s.ipOption.IPv6Enable
|
||||
}
|
||||
option.IPv4Enable = option.IPv4Enable && s.ipOption.IPv4Enable
|
||||
option.IPv6Enable = option.IPv6Enable && s.ipOption.IPv6Enable
|
||||
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
return nil, dns.ErrEmptyResponse
|
||||
}
|
||||
|
||||
// Normalize the FQDN form query
|
||||
domain = strings.TrimSuffix(domain, ".")
|
||||
|
||||
// Static host lookup
|
||||
switch addrs := s.hosts.Lookup(domain, option); {
|
||||
case addrs == nil: // Domain not recorded in static host
|
||||
break
|
||||
case len(addrs) == 0: // Domain recorded, but no valid IP returned (e.g. IPv4 address with only IPv6 enabled)
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
return nil, dns.ErrEmptyResponse
|
||||
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Domain replacement
|
||||
errors.LogInfo(s.ctx, "domain replaced: ", domain, " -> ", addrs[0].Domain())
|
||||
domain = addrs[0].Domain()
|
||||
default: // Successfully found ip records in static host
|
||||
errors.LogInfo(s.ctx, "returning ", len(addrs), " IP(s) for domain ", domain, " -> ", addrs)
|
||||
ips, err := toNetIP(addrs)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return ips, 10, nil // Hosts ttl is 10
|
||||
return toNetIP(addrs)
|
||||
}
|
||||
|
||||
// Name servers lookup
|
||||
var errs []error
|
||||
errs := []error{}
|
||||
ctx := session.ContextWithInbound(s.ctx, &session.Inbound{Tag: s.tag})
|
||||
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)
|
||||
|
||||
ips, err := client.QueryIP(ctx, domain, option, s.disableCache)
|
||||
if len(ips) > 0 {
|
||||
if ttl == 0 {
|
||||
ttl = 1
|
||||
}
|
||||
return ips, ttl, nil
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
errors.LogInfoInner(s.ctx, err, "failed to lookup ip for domain ", domain, " at server ", client.Name())
|
||||
if err == nil {
|
||||
err = dns.ErrEmptyResponse
|
||||
if err != nil {
|
||||
errors.LogInfoInner(s.ctx, err, "failed to lookup ip for domain ", domain, " at server ", client.Name())
|
||||
errs = append(errs, err)
|
||||
}
|
||||
errs = append(errs, err)
|
||||
|
||||
if client.IsFinalQuery() {
|
||||
break
|
||||
// 5 for RcodeRefused in miekg/dns, hardcode to reduce binary size
|
||||
if err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch && err != dns.ErrEmptyResponse && dns.RCodeFromError(err) != 5 {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
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, errors.New("returning nil for domain ", domain).Base(errors.Combine(errs...))
|
||||
}
|
||||
|
||||
// LookupHosts implements dns.HostsLookup.
|
||||
func (s *DNS) LookupHosts(domain string) *net.Address {
|
||||
domain = strings.TrimSuffix(domain, ".")
|
||||
if domain == "" {
|
||||
return nil
|
||||
}
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
// Normalize the FQDN form query
|
||||
addrs := s.hosts.Lookup(domain, *s.ipOption)
|
||||
if len(addrs) > 0 {
|
||||
errors.LogInfo(s.ctx, "domain replaced: ", domain, " -> ", addrs[0].String())
|
||||
return &addrs[0]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetIPOption implements ClientWithIPOption.
|
||||
func (s *DNS) GetIPOption() *dns.IPOption {
|
||||
return s.ipOption
|
||||
}
|
||||
|
||||
// SetQueryOption implements ClientWithIPOption.
|
||||
func (s *DNS) SetQueryOption(isIPv4Enable, isIPv6Enable bool) {
|
||||
s.ipOption.IPv4Enable = isIPv4Enable
|
||||
s.ipOption.IPv6Enable = isIPv6Enable
|
||||
}
|
||||
|
||||
// SetFakeDNSOption implements ClientWithIPOption.
|
||||
func (s *DNS) SetFakeDNSOption(isFakeEnable bool) {
|
||||
s.ipOption.FakeEnable = isFakeEnable
|
||||
}
|
||||
|
||||
func (s *DNS) sortClients(domain string) []*Client {
|
||||
@@ -271,11 +250,7 @@ func (s *DNS) sortClients(domain string) []*Client {
|
||||
|
||||
// Priority domain matching
|
||||
hasMatch := false
|
||||
MatchSlice := s.domainMatcher.Match(domain)
|
||||
sort.Slice(MatchSlice, func(i, j int) bool {
|
||||
return MatchSlice[i] < MatchSlice[j]
|
||||
})
|
||||
for _, match := range MatchSlice {
|
||||
for _, match := range s.domainMatcher.Match(domain) {
|
||||
info := s.matcherInfos[match]
|
||||
client := s.clients[info.clientIdx]
|
||||
domainRule := client.domains[info.domainRuleIdx]
|
||||
@@ -322,22 +297,3 @@ func init() {
|
||||
return New(ctx, config.(*Config))
|
||||
}))
|
||||
}
|
||||
|
||||
func checkSystemNetwork() (supportIPv4 bool, supportIPv6 bool) {
|
||||
conn4, err4 := net.Dial("udp4", "8.8.8.8:53")
|
||||
if err4 != nil {
|
||||
supportIPv4 = false
|
||||
} else {
|
||||
supportIPv4 = true
|
||||
conn4.Close()
|
||||
}
|
||||
|
||||
conn6, err6 := net.Dial("udp6", "[2001:4860:4860::8888]:53")
|
||||
if err6 != nil {
|
||||
supportIPv6 = false
|
||||
} else {
|
||||
supportIPv6 = true
|
||||
conn6.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@@ -76,9 +76,6 @@ func (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
||||
case q.Name == "notexist.google.com." && q.Qtype == dns.TypeAAAA:
|
||||
ans.MsgHdr.Rcode = dns.RcodeNameError
|
||||
|
||||
case q.Name == "notexist.google.com." && q.Qtype == dns.TypeA:
|
||||
ans.MsgHdr.Rcode = dns.RcodeNameError
|
||||
|
||||
case q.Name == "hostname." && q.Qtype == dns.TypeA:
|
||||
rr, _ := dns.NewRR("hostname. IN A 127.0.0.1")
|
||||
ans.Answer = append(ans.Answer, rr)
|
||||
@@ -120,6 +117,7 @@ func TestUDPServerSubnet(t *testing.T) {
|
||||
Handler: &staticHandler{},
|
||||
UDPSize: 1200,
|
||||
}
|
||||
|
||||
go dnsServer.ListenAndServe()
|
||||
time.Sleep(time.Second)
|
||||
|
||||
@@ -157,7 +155,7 @@ func TestUDPServerSubnet(t *testing.T) {
|
||||
|
||||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||
|
||||
ips, _, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -218,7 +216,7 @@ func TestUDPServer(t *testing.T) {
|
||||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||
|
||||
{
|
||||
ips, _, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -233,7 +231,7 @@ func TestUDPServer(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
ips, _, err := client.LookupIP("facebook.com", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("facebook.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -248,7 +246,7 @@ func TestUDPServer(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
_, _, err := client.LookupIP("notexist.google.com", feature_dns.IPOption{
|
||||
_, err := client.LookupIP("notexist.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -262,7 +260,7 @@ func TestUDPServer(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
ips, _, err := client.LookupIP("ipv4only.google.com", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("ipv4only.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -278,7 +276,7 @@ func TestUDPServer(t *testing.T) {
|
||||
dnsServer.Shutdown()
|
||||
|
||||
{
|
||||
ips, _, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -359,7 +357,7 @@ func TestPrioritizedDomain(t *testing.T) {
|
||||
startTime := time.Now()
|
||||
|
||||
{
|
||||
ips, _, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -425,7 +423,7 @@ func TestUDPServerIPv6(t *testing.T) {
|
||||
|
||||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||
{
|
||||
ips, _, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -494,7 +492,7 @@ func TestStaticHostDomain(t *testing.T) {
|
||||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||
|
||||
{
|
||||
ips, _, err := client.LookupIP("example.com", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("example.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -539,7 +537,7 @@ func TestIPMatch(t *testing.T) {
|
||||
},
|
||||
Port: uint32(port),
|
||||
},
|
||||
ExpectedGeoip: []*router.GeoIP{
|
||||
Geoip: []*router.GeoIP{
|
||||
{
|
||||
CountryCode: "local",
|
||||
Cidr: []*router.CIDR{
|
||||
@@ -563,7 +561,7 @@ func TestIPMatch(t *testing.T) {
|
||||
},
|
||||
Port: uint32(port),
|
||||
},
|
||||
ExpectedGeoip: []*router.GeoIP{
|
||||
Geoip: []*router.GeoIP{
|
||||
{
|
||||
CountryCode: "test",
|
||||
Cidr: []*router.CIDR{
|
||||
@@ -605,7 +603,7 @@ func TestIPMatch(t *testing.T) {
|
||||
startTime := time.Now()
|
||||
|
||||
{
|
||||
ips, _, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -667,7 +665,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
// Equivalent of dotless:localhost
|
||||
{Type: DomainMatchingType_Regex, Domain: "^[^.]*localhost[^.]*$"},
|
||||
},
|
||||
ExpectedGeoip: []*router.GeoIP{
|
||||
Geoip: []*router.GeoIP{
|
||||
{ // Will match localhost, localhost-a and localhost-b,
|
||||
CountryCode: "local",
|
||||
Cidr: []*router.CIDR{
|
||||
@@ -728,7 +726,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
startTime := time.Now()
|
||||
|
||||
{ // Will match dotless:
|
||||
ips, _, err := client.LookupIP("hostname", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("hostname", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -743,7 +741,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match domain:local
|
||||
ips, _, err := client.LookupIP("hostname.local", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("hostname.local", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -758,7 +756,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match static ip
|
||||
ips, _, err := client.LookupIP("hostnamestatic", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("hostnamestatic", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -773,7 +771,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match domain replacing
|
||||
ips, _, err := client.LookupIP("hostnamealias", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("hostnamealias", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -787,8 +785,8 @@ func TestLocalDomain(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
{ // Will match dotless:localhost, but not expectedIPs: 127.0.0.2, 127.0.0.3, then matches at dotless:
|
||||
ips, _, err := client.LookupIP("localhost", feature_dns.IPOption{
|
||||
{ // Will match dotless:localhost, but not expectIPs: 127.0.0.2, 127.0.0.3, then matches at dotless:
|
||||
ips, err := client.LookupIP("localhost", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -802,8 +800,8 @@ func TestLocalDomain(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
{ // Will match dotless:localhost, and expectedIPs: 127.0.0.2, 127.0.0.3
|
||||
ips, _, err := client.LookupIP("localhost-a", feature_dns.IPOption{
|
||||
{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3
|
||||
ips, err := client.LookupIP("localhost-a", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -817,8 +815,8 @@ func TestLocalDomain(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
{ // Will match dotless:localhost, and expectedIPs: 127.0.0.2, 127.0.0.3
|
||||
ips, _, err := client.LookupIP("localhost-b", feature_dns.IPOption{
|
||||
{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3
|
||||
ips, err := client.LookupIP("localhost-b", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -833,7 +831,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match dotless:
|
||||
ips, _, err := client.LookupIP("Mijia Cloud", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("Mijia Cloud", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -897,7 +895,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
Domain: "google.com",
|
||||
},
|
||||
},
|
||||
ExpectedGeoip: []*router.GeoIP{
|
||||
Geoip: []*router.GeoIP{
|
||||
{ // Will only match 8.8.8.8 and 8.8.4.4
|
||||
Cidr: []*router.CIDR{
|
||||
{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
|
||||
@@ -922,7 +920,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
Domain: "google.com",
|
||||
},
|
||||
},
|
||||
ExpectedGeoip: []*router.GeoIP{
|
||||
Geoip: []*router.GeoIP{
|
||||
{ // Will match 8.8.8.8 and 8.8.8.7, etc
|
||||
Cidr: []*router.CIDR{
|
||||
{Ip: []byte{8, 8, 8, 7}, Prefix: 24},
|
||||
@@ -946,7 +944,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
Domain: "api.google.com",
|
||||
},
|
||||
},
|
||||
ExpectedGeoip: []*router.GeoIP{
|
||||
Geoip: []*router.GeoIP{
|
||||
{ // Will only match 8.8.7.7 (api.google.com)
|
||||
Cidr: []*router.CIDR{
|
||||
{Ip: []byte{8, 8, 7, 7}, Prefix: 32},
|
||||
@@ -970,7 +968,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
Domain: "v2.api.google.com",
|
||||
},
|
||||
},
|
||||
ExpectedGeoip: []*router.GeoIP{
|
||||
Geoip: []*router.GeoIP{
|
||||
{ // Will only match 8.8.7.8 (v2.api.google.com)
|
||||
Cidr: []*router.CIDR{
|
||||
{Ip: []byte{8, 8, 7, 8}, Prefix: 32},
|
||||
@@ -999,7 +997,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
startTime := time.Now()
|
||||
|
||||
{ // Will match server 1,2 and server 1 returns expected ip
|
||||
ips, _, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -1014,7 +1012,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match server 1,2 and server 1 returns unexpected ip, then server 2 returns expected one
|
||||
ips, _, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: false,
|
||||
FakeEnable: false,
|
||||
@@ -1029,7 +1027,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match server 3,1,2 and server 3 returns expected one
|
||||
ips, _, err := client.LookupIP("api.google.com", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("api.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
@@ -1044,7 +1042,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match server 4,3,1,2 and server 4 returns expected one
|
||||
ips, _, err := client.LookupIP("v2.api.google.com", feature_dns.IPOption{
|
||||
ips, err := client.LookupIP("v2.api.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
|
@@ -31,31 +31,30 @@ type record struct {
|
||||
|
||||
// IPRecord is a cacheable item for a resolved domain
|
||||
type IPRecord struct {
|
||||
ReqID uint16
|
||||
IP []net.IP
|
||||
Expire time.Time
|
||||
RCode dnsmessage.RCode
|
||||
RawHeader *dnsmessage.Header
|
||||
ReqID uint16
|
||||
IP []net.Address
|
||||
Expire time.Time
|
||||
RCode dnsmessage.RCode
|
||||
}
|
||||
|
||||
func (r *IPRecord) getIPs() ([]net.IP, uint32, error) {
|
||||
if r == nil {
|
||||
return nil, 0, errRecordNotFound
|
||||
func (r *IPRecord) getIPs() ([]net.Address, error) {
|
||||
if r == nil || r.Expire.Before(time.Now()) {
|
||||
return nil, errRecordNotFound
|
||||
}
|
||||
untilExpire := time.Until(r.Expire)
|
||||
if untilExpire <= 0 {
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
|
||||
ttl := uint32(untilExpire/time.Second) + uint32(1)
|
||||
if r.RCode != dnsmessage.RCodeSuccess {
|
||||
return nil, ttl, dns_feature.RCodeError(r.RCode)
|
||||
}
|
||||
if len(r.IP) == 0 {
|
||||
return nil, ttl, dns_feature.ErrEmptyResponse
|
||||
return nil, dns_feature.RCodeError(r.RCode)
|
||||
}
|
||||
return r.IP, nil
|
||||
}
|
||||
|
||||
return r.IP, ttl, nil
|
||||
func isNewer(baseRec *IPRecord, newRec *IPRecord) bool {
|
||||
if newRec == nil {
|
||||
return false
|
||||
}
|
||||
if baseRec == nil {
|
||||
return true
|
||||
}
|
||||
return baseRec.Expire.Before(newRec.Expire)
|
||||
}
|
||||
|
||||
var errRecordNotFound = errors.New("record not found")
|
||||
@@ -68,59 +67,49 @@ type dnsRequest struct {
|
||||
msg *dnsmessage.Message
|
||||
}
|
||||
|
||||
func genEDNS0Options(clientIP net.IP, padding int) *dnsmessage.Resource {
|
||||
if len(clientIP) == 0 && padding == 0 {
|
||||
func genEDNS0Options(clientIP net.IP) *dnsmessage.Resource {
|
||||
if len(clientIP) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
const EDNS0SUBNET = 0x8
|
||||
const EDNS0PADDING = 0xc
|
||||
var netmask int
|
||||
var family uint16
|
||||
|
||||
if len(clientIP) == 4 {
|
||||
family = 1
|
||||
netmask = 24 // 24 for IPV4, 96 for IPv6
|
||||
} else {
|
||||
family = 2
|
||||
netmask = 96
|
||||
}
|
||||
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint16(b[0:], family)
|
||||
b[2] = byte(netmask)
|
||||
b[3] = 0
|
||||
switch family {
|
||||
case 1:
|
||||
ip := clientIP.To4().Mask(net.CIDRMask(netmask, net.IPv4len*8))
|
||||
needLength := (netmask + 8 - 1) / 8 // division rounding up
|
||||
b = append(b, ip[:needLength]...)
|
||||
case 2:
|
||||
ip := clientIP.Mask(net.CIDRMask(netmask, net.IPv6len*8))
|
||||
needLength := (netmask + 8 - 1) / 8 // division rounding up
|
||||
b = append(b, ip[:needLength]...)
|
||||
}
|
||||
|
||||
const EDNS0SUBNET = 0x08
|
||||
|
||||
opt := new(dnsmessage.Resource)
|
||||
common.Must(opt.Header.SetEDNS0(1350, 0xfe00, true))
|
||||
body := dnsmessage.OPTResource{}
|
||||
opt.Body = &body
|
||||
|
||||
if len(clientIP) != 0 {
|
||||
var netmask int
|
||||
var family uint16
|
||||
|
||||
if len(clientIP) == 4 {
|
||||
family = 1
|
||||
netmask = 24 // 24 for IPV4, 96 for IPv6
|
||||
} else {
|
||||
family = 2
|
||||
netmask = 96
|
||||
}
|
||||
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint16(b[0:], family)
|
||||
b[2] = byte(netmask)
|
||||
b[3] = 0
|
||||
switch family {
|
||||
case 1:
|
||||
ip := clientIP.To4().Mask(net.CIDRMask(netmask, net.IPv4len*8))
|
||||
needLength := (netmask + 8 - 1) / 8 // division rounding up
|
||||
b = append(b, ip[:needLength]...)
|
||||
case 2:
|
||||
ip := clientIP.Mask(net.CIDRMask(netmask, net.IPv6len*8))
|
||||
needLength := (netmask + 8 - 1) / 8 // division rounding up
|
||||
b = append(b, ip[:needLength]...)
|
||||
}
|
||||
|
||||
body.Options = append(body.Options,
|
||||
dnsmessage.Option{
|
||||
opt.Body = &dnsmessage.OPTResource{
|
||||
Options: []dnsmessage.Option{
|
||||
{
|
||||
Code: EDNS0SUBNET,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
if padding != 0 {
|
||||
body.Options = append(body.Options,
|
||||
dnsmessage.Option{
|
||||
Code: EDNS0PADDING,
|
||||
Data: make([]byte, padding),
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return opt
|
||||
@@ -190,10 +179,9 @@ func parseResponse(payload []byte) (*IPRecord, error) {
|
||||
|
||||
now := time.Now()
|
||||
ipRecord := &IPRecord{
|
||||
ReqID: h.ID,
|
||||
RCode: h.RCode,
|
||||
Expire: now.Add(time.Second * dns_feature.DefaultTTL),
|
||||
RawHeader: &h,
|
||||
ReqID: h.ID,
|
||||
RCode: h.RCode,
|
||||
Expire: now.Add(time.Second * 600),
|
||||
}
|
||||
|
||||
L:
|
||||
@@ -208,7 +196,7 @@ L:
|
||||
|
||||
ttl := ah.TTL
|
||||
if ttl == 0 {
|
||||
ttl = 1
|
||||
ttl = 600
|
||||
}
|
||||
expire := now.Add(time.Duration(ttl) * time.Second)
|
||||
if ipRecord.Expire.After(expire) {
|
||||
@@ -222,17 +210,14 @@ L:
|
||||
errors.LogInfoInner(context.Background(), err, "failed to parse A record for domain: ", ah.Name)
|
||||
break L
|
||||
}
|
||||
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.A[:]).IP())
|
||||
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.A[:]))
|
||||
case dnsmessage.TypeAAAA:
|
||||
ans, err := parser.AAAAResource()
|
||||
if err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "failed to parse AAAA record for domain: ", ah.Name)
|
||||
break L
|
||||
}
|
||||
newIP := net.IPAddress(ans.AAAA[:]).IP()
|
||||
if len(newIP) == net.IPv6len {
|
||||
ipRecord.IP = append(ipRecord.IP, newIP)
|
||||
}
|
||||
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.AAAA[:]))
|
||||
default:
|
||||
if err := parser.SkipAnswer(); err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "failed to skip answer")
|
||||
|
@@ -51,7 +51,7 @@ func Test_parseResponse(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
"empty",
|
||||
&IPRecord{0, []net.IP(nil), time.Time{}, dnsmessage.RCodeSuccess, nil},
|
||||
&IPRecord{0, []net.Address(nil), time.Time{}, dnsmessage.RCodeSuccess},
|
||||
false,
|
||||
},
|
||||
{
|
||||
@@ -63,16 +63,15 @@ func Test_parseResponse(t *testing.T) {
|
||||
"a record",
|
||||
&IPRecord{
|
||||
1,
|
||||
[]net.IP{net.ParseIP("8.8.8.8"), net.ParseIP("8.8.4.4")},
|
||||
[]net.Address{net.ParseAddress("8.8.8.8"), net.ParseAddress("8.8.4.4")},
|
||||
time.Time{},
|
||||
dnsmessage.RCodeSuccess,
|
||||
nil,
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"aaaa record",
|
||||
&IPRecord{2, []net.IP{net.ParseIP("2001::123:8888"), net.ParseIP("2001::123:8844")}, time.Time{}, dnsmessage.RCodeSuccess, nil},
|
||||
&IPRecord{2, []net.Address{net.ParseAddress("2001::123:8888"), net.ParseAddress("2001::123:8844")}, time.Time{}, dnsmessage.RCodeSuccess},
|
||||
false,
|
||||
},
|
||||
}
|
||||
@@ -85,9 +84,8 @@ func Test_parseResponse(t *testing.T) {
|
||||
}
|
||||
|
||||
if got != nil {
|
||||
// reset the time and RawHeader
|
||||
// reset the time
|
||||
got.Expire = time.Time{}
|
||||
got.RawHeader = nil
|
||||
}
|
||||
if cmp.Diff(got, tt.want) != "" {
|
||||
t.Error(cmp.Diff(got, tt.want))
|
||||
@@ -156,7 +154,7 @@ func Test_genEDNS0Options(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := genEDNS0Options(tt.args.clientIP, 0); got == nil {
|
||||
if got := genEDNS0Options(tt.args.clientIP); got == nil {
|
||||
t.Errorf("genEDNS0Options() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
@@ -2,6 +2,7 @@ package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/strmatcher"
|
||||
@@ -40,6 +41,8 @@ func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
|
||||
}
|
||||
ips = append(ips, addr)
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("neither IP address nor proxied domain specified for domain: ", mapping.Domain).AtWarning()
|
||||
}
|
||||
|
||||
sh.ips[id] = ips
|
||||
@@ -59,14 +62,9 @@ func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
|
||||
}
|
||||
|
||||
func (h *StaticHosts) lookupInternal(domain string) []net.Address {
|
||||
ips := make([]net.Address, 0)
|
||||
found := false
|
||||
var ips []net.Address
|
||||
for _, id := range h.matchers.Match(domain) {
|
||||
ips = append(ips, h.ips[id]...)
|
||||
found = true
|
||||
}
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
return ips
|
||||
}
|
||||
@@ -74,7 +72,7 @@ func (h *StaticHosts) lookupInternal(domain string) []net.Address {
|
||||
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) []net.Address {
|
||||
switch addrs := h.lookupInternal(domain); {
|
||||
case len(addrs) == 0: // Not recorded in static hosts, return nil
|
||||
return addrs
|
||||
return nil
|
||||
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Try to unwrap domain
|
||||
errors.LogDebug(context.Background(), "found replaced domain: ", domain, " -> ", addrs[0].Domain(), ". Try to unwrap it")
|
||||
if maxDepth > 0 {
|
||||
|
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/strmatcher"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
@@ -21,27 +20,22 @@ type Server interface {
|
||||
// Name of the Client.
|
||||
Name() string
|
||||
// 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, clientIP net.IP, option dns.IPOption, disableCache bool) ([]net.IP, error)
|
||||
}
|
||||
|
||||
// Client is the interface for DNS client.
|
||||
type Client struct {
|
||||
server Server
|
||||
skipFallback bool
|
||||
domains []string
|
||||
expectedIPs []*router.GeoIPMatcher
|
||||
unexpectedIPs []*router.GeoIPMatcher
|
||||
actPrior bool
|
||||
actUnprior bool
|
||||
tag string
|
||||
timeoutMs time.Duration
|
||||
finalQuery bool
|
||||
ipOption *dns.IPOption
|
||||
checkSystem bool
|
||||
server Server
|
||||
clientIP net.IP
|
||||
skipFallback bool
|
||||
domains []string
|
||||
expectIPs []*router.GeoIPMatcher
|
||||
}
|
||||
|
||||
var errExpectedIPNonMatch = errors.New("expectIPs not match")
|
||||
|
||||
// NewServer creates a name server object according to the network destination url.
|
||||
func NewServer(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, queryStrategy QueryStrategy) (Server, error) {
|
||||
if address := dest.Address; address.Family().IsDomain() {
|
||||
u, err := url.Parse(address.Domain())
|
||||
if err != nil {
|
||||
@@ -49,29 +43,24 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis
|
||||
}
|
||||
switch {
|
||||
case strings.EqualFold(u.String(), "localhost"):
|
||||
return NewLocalNameServer(), nil
|
||||
return NewLocalNameServer(queryStrategy), nil
|
||||
case strings.EqualFold(u.Scheme, "https"): // DNS-over-HTTPS Remote mode
|
||||
return NewDoHNameServer(u, dispatcher, false, disableCache, clientIP), nil
|
||||
return NewDoHNameServer(u, dispatcher, queryStrategy, false)
|
||||
case strings.EqualFold(u.Scheme, "h2c"): // DNS-over-HTTPS h2c Remote mode
|
||||
return NewDoHNameServer(u, dispatcher, true, disableCache, clientIP), nil
|
||||
return NewDoHNameServer(u, dispatcher, queryStrategy, true)
|
||||
case strings.EqualFold(u.Scheme, "https+local"): // DNS-over-HTTPS Local mode
|
||||
return NewDoHNameServer(u, nil, false, disableCache, clientIP), nil
|
||||
case strings.EqualFold(u.Scheme, "h2c+local"): // DNS-over-HTTPS h2c Local mode
|
||||
return NewDoHNameServer(u, nil, true, disableCache, clientIP), nil
|
||||
return NewDoHLocalNameServer(u, queryStrategy), nil
|
||||
case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode
|
||||
return NewQUICNameServer(u, disableCache, clientIP)
|
||||
return NewQUICNameServer(u, queryStrategy)
|
||||
case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode
|
||||
return NewTCPNameServer(u, dispatcher, disableCache, clientIP)
|
||||
return NewTCPNameServer(u, dispatcher, queryStrategy)
|
||||
case strings.EqualFold(u.Scheme, "tcp+local"): // DNS-over-TCP Local mode
|
||||
return NewTCPLocalNameServer(u, disableCache, clientIP)
|
||||
return NewTCPLocalNameServer(u, queryStrategy)
|
||||
case strings.EqualFold(u.String(), "fakedns"):
|
||||
var fd dns.FakeDNSEngine
|
||||
err = core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||
core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||
fd = fdns
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewFakeDNSServer(fd), nil
|
||||
}
|
||||
}
|
||||
@@ -79,7 +68,7 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis
|
||||
dest.Network = net.Network_UDP
|
||||
}
|
||||
if dest.Network == net.Network_UDP { // UDP classic DNS mode
|
||||
return NewClassicNameServer(dest, dispatcher, disableCache, clientIP), nil
|
||||
return NewClassicNameServer(dest, dispatcher, queryStrategy), nil
|
||||
}
|
||||
return nil, errors.New("No available name server could be created from ", dest).AtWarning()
|
||||
}
|
||||
@@ -89,9 +78,7 @@ func NewClient(
|
||||
ctx context.Context,
|
||||
ns *NameServer,
|
||||
clientIP net.IP,
|
||||
disableCache bool,
|
||||
tag string,
|
||||
ipOption dns.IPOption,
|
||||
container router.GeoIPMatcherContainer,
|
||||
matcherInfos *[]*DomainMatcherInfo,
|
||||
updateDomainRule func(strmatcher.Matcher, int, []*DomainMatcherInfo) error,
|
||||
) (*Client, error) {
|
||||
@@ -99,7 +86,7 @@ func NewClient(
|
||||
|
||||
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
|
||||
// Create a new server for each client for now
|
||||
server, err := NewServer(ctx, ns.Address.AsDestination(), dispatcher, disableCache, clientIP)
|
||||
server, err := NewServer(ctx, ns.Address.AsDestination(), dispatcher, ns.GetQueryStrategy())
|
||||
if err != nil {
|
||||
return errors.New("failed to create nameserver").Base(err).AtWarning()
|
||||
}
|
||||
@@ -154,23 +141,13 @@ func NewClient(
|
||||
}
|
||||
|
||||
// Establish expected IPs
|
||||
var expectedMatchers []*router.GeoIPMatcher
|
||||
for _, geoip := range ns.ExpectedGeoip {
|
||||
matcher, err := router.GlobalGeoIPContainer.Add(geoip)
|
||||
var matchers []*router.GeoIPMatcher
|
||||
for _, geoip := range ns.Geoip {
|
||||
matcher, err := container.Add(geoip)
|
||||
if err != nil {
|
||||
return errors.New("failed to create expected ip matcher").Base(err).AtWarning()
|
||||
return errors.New("failed to create ip matcher").Base(err).AtWarning()
|
||||
}
|
||||
expectedMatchers = append(expectedMatchers, matcher)
|
||||
}
|
||||
|
||||
// Establish unexpected IPs
|
||||
var unexpectedMatchers []*router.GeoIPMatcher
|
||||
for _, geoip := range ns.UnexpectedGeoip {
|
||||
matcher, err := router.GlobalGeoIPContainer.Add(geoip)
|
||||
if err != nil {
|
||||
return errors.New("failed to create unexpected ip matcher").Base(err).AtWarning()
|
||||
}
|
||||
unexpectedMatchers = append(unexpectedMatchers, matcher)
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
|
||||
if len(clientIP) > 0 {
|
||||
@@ -178,29 +155,15 @@ func NewClient(
|
||||
case *net.IPOrDomain_Domain:
|
||||
errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetDomain(), " uses clientIP ", clientIP.String())
|
||||
case *net.IPOrDomain_Ip:
|
||||
errors.LogInfo(ctx, "DNS: client ", net.IP(ns.Address.Address.GetIp()), " uses clientIP ", clientIP.String())
|
||||
errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetIp(), " uses clientIP ", clientIP.String())
|
||||
}
|
||||
}
|
||||
|
||||
var timeoutMs = 4000 * time.Millisecond
|
||||
if ns.TimeoutMs > 0 {
|
||||
timeoutMs = time.Duration(ns.TimeoutMs) * time.Millisecond
|
||||
}
|
||||
|
||||
checkSystem := ns.QueryStrategy == QueryStrategy_USE_SYS
|
||||
|
||||
client.server = server
|
||||
client.clientIP = clientIP
|
||||
client.skipFallback = ns.SkipFallback
|
||||
client.domains = rules
|
||||
client.expectedIPs = expectedMatchers
|
||||
client.unexpectedIPs = unexpectedMatchers
|
||||
client.actPrior = ns.ActPrior
|
||||
client.actUnprior = ns.ActUnprior
|
||||
client.tag = tag
|
||||
client.timeoutMs = timeoutMs
|
||||
client.finalQuery = ns.FinalQuery
|
||||
client.ipOption = &ipOption
|
||||
client.checkSystem = checkSystem
|
||||
client.expectIPs = matchers
|
||||
return nil
|
||||
})
|
||||
return client, err
|
||||
@@ -211,79 +174,43 @@ func (c *Client) Name() string {
|
||||
return c.server.Name()
|
||||
}
|
||||
|
||||
func (c *Client) IsFinalQuery() bool {
|
||||
return c.finalQuery
|
||||
}
|
||||
|
||||
// QueryIP sends DNS query to the name server with the client's IP.
|
||||
func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
||||
if c.checkSystem {
|
||||
supportIPv4, supportIPv6 := checkSystemNetwork()
|
||||
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
||||
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
||||
} else {
|
||||
option.IPv4Enable = option.IPv4Enable && c.ipOption.IPv4Enable
|
||||
option.IPv6Enable = option.IPv6Enable && c.ipOption.IPv6Enable
|
||||
}
|
||||
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, c.timeoutMs)
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{Tag: c.tag})
|
||||
ips, ttl, err := c.server.QueryIP(ctx, domain, option)
|
||||
func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption, disableCache bool) ([]net.IP, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 4*time.Second)
|
||||
ips, err := c.server.QueryIP(ctx, domain, c.clientIP, option, disableCache)
|
||||
cancel()
|
||||
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
return ips, err
|
||||
}
|
||||
return c.MatchExpectedIPs(domain, ips)
|
||||
}
|
||||
|
||||
if len(ips) == 0 {
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
// MatchExpectedIPs matches queried domain IPs with expected IPs and returns matched ones.
|
||||
func (c *Client) MatchExpectedIPs(domain string, ips []net.IP) ([]net.IP, error) {
|
||||
if len(c.expectIPs) == 0 {
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
if len(c.expectedIPs) > 0 && !c.actPrior {
|
||||
ips = router.MatchIPs(c.expectedIPs, ips, false)
|
||||
errors.LogDebug(context.Background(), "domain ", domain, " expectedIPs ", ips, " matched at server ", c.Name())
|
||||
if len(ips) == 0 {
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
newIps := []net.IP{}
|
||||
for _, ip := range ips {
|
||||
for _, matcher := range c.expectIPs {
|
||||
if matcher.Match(ip) {
|
||||
newIps = append(newIps, ip)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.unexpectedIPs) > 0 && !c.actUnprior {
|
||||
ips = router.MatchIPs(c.unexpectedIPs, ips, true)
|
||||
errors.LogDebug(context.Background(), "domain ", domain, " unexpectedIPs ", ips, " matched at server ", c.Name())
|
||||
if len(ips) == 0 {
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
}
|
||||
if len(newIps) == 0 {
|
||||
return nil, errExpectedIPNonMatch
|
||||
}
|
||||
|
||||
if len(c.expectedIPs) > 0 && c.actPrior {
|
||||
ipsNew := router.MatchIPs(c.expectedIPs, ips, false)
|
||||
if len(ipsNew) > 0 {
|
||||
ips = ipsNew
|
||||
errors.LogDebug(context.Background(), "domain ", domain, " priorIPs ", ips, " matched at server ", c.Name())
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.unexpectedIPs) > 0 && c.actUnprior {
|
||||
ipsNew := router.MatchIPs(c.unexpectedIPs, ips, true)
|
||||
if len(ipsNew) > 0 {
|
||||
ips = ipsNew
|
||||
errors.LogDebug(context.Background(), "domain ", domain, " unpriorIPs ", ips, " matched at server ", c.Name())
|
||||
}
|
||||
}
|
||||
|
||||
return ips, ttl, nil
|
||||
errors.LogDebug(context.Background(), "domain ", domain, " expectIPs ", newIps, " matched at server ", c.Name())
|
||||
return newIps, nil
|
||||
}
|
||||
|
||||
func ResolveIpOptionOverride(queryStrategy QueryStrategy, ipOption dns.IPOption) dns.IPOption {
|
||||
switch queryStrategy {
|
||||
case QueryStrategy_USE_IP:
|
||||
return ipOption
|
||||
case QueryStrategy_USE_SYS:
|
||||
return ipOption
|
||||
case QueryStrategy_USE_IP4:
|
||||
return dns.IPOption{
|
||||
IPv4Enable: ipOption.IPv4Enable,
|
||||
|
@@ -4,26 +4,26 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
go_errors "errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
utls "github.com/refraction-networking/utls"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/crypto"
|
||||
"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/cnc"
|
||||
"github.com/xtls/xray-core/common/protocol/dns"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
@@ -31,108 +31,224 @@ import (
|
||||
// which is compatible with traditional dns over udp(RFC1035),
|
||||
// thus most of the DOH implementation is copied from udpns.go
|
||||
type DoHNameServer struct {
|
||||
cacheController *CacheController
|
||||
httpClient *http.Client
|
||||
dohURL string
|
||||
clientIP net.IP
|
||||
dispatcher routing.Dispatcher
|
||||
sync.RWMutex
|
||||
ips map[string]*record
|
||||
pub *pubsub.Service
|
||||
cleanup *task.Periodic
|
||||
httpClient *http.Client
|
||||
dohURL string
|
||||
name string
|
||||
queryStrategy QueryStrategy
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// NewDoHNameServer creates DOH server object for remote resolving.
|
||||
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy, h2c bool) (*DoHNameServer, error) {
|
||||
url.Scheme = "https"
|
||||
mode := "DOH"
|
||||
if dispatcher == nil {
|
||||
mode = "DOHL"
|
||||
errors.LogInfo(context.Background(), "DNS: created Remote DNS-over-HTTPS client for ", url.String(), ", with h2c ", h2c)
|
||||
s := baseDOHNameServer(url, "DOH", queryStrategy)
|
||||
|
||||
s.dispatcher = dispatcher
|
||||
dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
dest, err := net.ParseDestination(network + ":" + addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dnsCtx := toDnsContext(ctx, s.dohURL)
|
||||
if h2c {
|
||||
dnsCtx = session.ContextWithMitmAlpn11(dnsCtx, false) // for insurance
|
||||
dnsCtx = session.ContextWithMitmServerName(dnsCtx, url.Hostname())
|
||||
}
|
||||
link, err := s.dispatcher.Dispatch(dnsCtx, dest)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cc := common.ChainedClosable{}
|
||||
if cw, ok := link.Writer.(common.Closable); ok {
|
||||
cc = append(cc, cw)
|
||||
}
|
||||
if cr, ok := link.Reader.(common.Closable); ok {
|
||||
cc = append(cc, cr)
|
||||
}
|
||||
return cnc.NewConnection(
|
||||
cnc.ConnectionInputMulti(link.Writer),
|
||||
cnc.ConnectionOutputMulti(link.Reader),
|
||||
cnc.ConnectionOnClose(cc),
|
||||
), nil
|
||||
}
|
||||
errors.LogInfo(context.Background(), "DNS: created ", mode, " client for ", url.String(), ", with h2c ", h2c)
|
||||
s := &DoHNameServer{
|
||||
cacheController: NewCacheController(mode+"//"+url.Host, disableCache),
|
||||
dohURL: url.String(),
|
||||
clientIP: clientIP,
|
||||
|
||||
s.httpClient = &http.Client{
|
||||
Timeout: time.Second * 180,
|
||||
Transport: &http.Transport{
|
||||
MaxIdleConns: 30,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 30 * time.Second,
|
||||
ForceAttemptHTTP2: true,
|
||||
DialContext: dialContext,
|
||||
},
|
||||
}
|
||||
if h2c {
|
||||
s.httpClient.Transport = &http2.Transport{
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||
return dialContext(ctx, network, addr)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// NewDoHLocalNameServer creates DOH client object for local resolving
|
||||
func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameServer {
|
||||
url.Scheme = "https"
|
||||
s := baseDOHNameServer(url, "DOHL", queryStrategy)
|
||||
tr := &http.Transport{
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
ForceAttemptHTTP2: true,
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
dest, err := net.ParseDestination(network + ":" + addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := internet.DialSystem(ctx, dest, nil)
|
||||
log.Record(&log.AccessMessage{
|
||||
From: "DNS",
|
||||
To: s.dohURL,
|
||||
Status: log.AccessAccepted,
|
||||
Detour: "local",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
},
|
||||
}
|
||||
s.httpClient = &http.Client{
|
||||
Transport: &http2.Transport{
|
||||
IdleConnTimeout: net.ConnIdleTimeout,
|
||||
ReadIdleTimeout: net.ChromeH2KeepAlivePeriod,
|
||||
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||
dest, err := net.ParseDestination(network + ":" + addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var conn net.Conn
|
||||
if dispatcher != nil {
|
||||
dnsCtx := toDnsContext(ctx, s.dohURL)
|
||||
if h2c {
|
||||
dnsCtx = session.ContextWithMitmAlpn11(dnsCtx, false) // for insurance
|
||||
dnsCtx = session.ContextWithMitmServerName(dnsCtx, url.Hostname())
|
||||
}
|
||||
link, err := dispatcher.Dispatch(dnsCtx, dest)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cc := common.ChainedClosable{}
|
||||
if cw, ok := link.Writer.(common.Closable); ok {
|
||||
cc = append(cc, cw)
|
||||
}
|
||||
if cr, ok := link.Reader.(common.Closable); ok {
|
||||
cc = append(cc, cr)
|
||||
}
|
||||
conn = cnc.NewConnection(
|
||||
cnc.ConnectionInputMulti(link.Writer),
|
||||
cnc.ConnectionOutputMulti(link.Reader),
|
||||
cnc.ConnectionOnClose(cc),
|
||||
)
|
||||
} else {
|
||||
log.Record(&log.AccessMessage{
|
||||
From: "DNS",
|
||||
To: s.dohURL,
|
||||
Status: log.AccessAccepted,
|
||||
Detour: "local",
|
||||
})
|
||||
conn, err = internet.DialSystem(ctx, dest, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if !h2c {
|
||||
conn = utls.UClient(conn, &utls.Config{ServerName: url.Hostname()}, utls.HelloChrome_Auto)
|
||||
if err := conn.(*utls.UConn).HandshakeContext(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return conn, nil
|
||||
},
|
||||
},
|
||||
Timeout: time.Second * 180,
|
||||
Transport: tr,
|
||||
}
|
||||
errors.LogInfo(context.Background(), "DNS: created Local DNS-over-HTTPS client for ", url.String())
|
||||
return s
|
||||
}
|
||||
|
||||
func baseDOHNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) *DoHNameServer {
|
||||
s := &DoHNameServer{
|
||||
ips: make(map[string]*record),
|
||||
pub: pubsub.NewService(),
|
||||
name: prefix + "//" + url.Host,
|
||||
dohURL: url.String(),
|
||||
queryStrategy: queryStrategy,
|
||||
}
|
||||
s.cleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
Execute: s.Cleanup,
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Name implements Server.
|
||||
func (s *DoHNameServer) Name() string {
|
||||
return s.cacheController.name
|
||||
return s.name
|
||||
}
|
||||
|
||||
// Cleanup clears expired items from cache
|
||||
func (s *DoHNameServer) Cleanup() error {
|
||||
now := time.Now()
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
return errors.New("nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for domain, record := range s.ips {
|
||||
if record.A != nil && record.A.Expire.Before(now) {
|
||||
record.A = nil
|
||||
}
|
||||
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
||||
record.AAAA = nil
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||
delete(s.ips, domain)
|
||||
} else {
|
||||
s.ips[domain] = record
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
s.ips = make(map[string]*record)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *DoHNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
elapsed := time.Since(req.start)
|
||||
|
||||
s.Lock()
|
||||
rec, found := s.ips[req.domain]
|
||||
if !found {
|
||||
rec = &record{}
|
||||
}
|
||||
updated := false
|
||||
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
if isNewer(rec.A, ipRec) {
|
||||
rec.A = ipRec
|
||||
updated = true
|
||||
}
|
||||
case dnsmessage.TypeAAAA:
|
||||
addr := make([]net.Address, 0, len(ipRec.IP))
|
||||
for _, ip := range ipRec.IP {
|
||||
if len(ip.IP()) == net.IPv6len {
|
||||
addr = append(addr, ip)
|
||||
}
|
||||
}
|
||||
ipRec.IP = addr
|
||||
if isNewer(rec.AAAA, ipRec) {
|
||||
rec.AAAA = ipRec
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||
|
||||
if updated {
|
||||
s.ips[req.domain] = rec
|
||||
}
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
s.pub.Publish(req.domain+"4", nil)
|
||||
case dnsmessage.TypeAAAA:
|
||||
s.pub.Publish(req.domain+"6", nil)
|
||||
}
|
||||
s.Unlock()
|
||||
common.Must(s.cleanup.Start())
|
||||
}
|
||||
|
||||
func (s *DoHNameServer) newReqID() uint16 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *DoHNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
||||
errors.LogInfo(ctx, s.Name(), " querying: ", domain)
|
||||
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||
errors.LogInfo(ctx, s.name, " querying: ", domain)
|
||||
|
||||
if s.Name()+"." == "DOH//"+domain {
|
||||
errors.LogError(ctx, s.Name(), " tries to resolve itself! Use IP or set \"hosts\" instead.")
|
||||
noResponseErrCh <- errors.New("tries to resolve itself!", s.Name())
|
||||
if s.name+"." == "DOH//"+domain {
|
||||
errors.LogError(ctx, s.name, " tries to resolve itself! Use IP or set \"hosts\" instead.")
|
||||
return
|
||||
}
|
||||
|
||||
// As we don't want our traffic pattern looks like DoH, we use Random-Length Padding instead of Block-Length Padding recommended in RFC 8467
|
||||
// Although DoH server like 1.1.1.1 will pad the response to Block-Length 468, at least it is better than no padding for response at all
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, int(crypto.RandBetween(100, 300))))
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||
|
||||
var deadline time.Time
|
||||
if d, ok := ctx.Deadline(); ok {
|
||||
@@ -167,22 +283,19 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- er
|
||||
b, err := dns.PackMessage(r.msg)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to pack dns query for ", domain)
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
resp, err := s.dohHTTPSContext(dnsCtx, b.Bytes())
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to retrieve response for ", domain)
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
rec, err := parseResponse(resp)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to handle DOH response for ", domain)
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
s.cacheController.updateIP(r, rec)
|
||||
s.updateIP(r, rec)
|
||||
}(req)
|
||||
}
|
||||
}
|
||||
@@ -197,8 +310,6 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
|
||||
req.Header.Add("Accept", "application/dns-message")
|
||||
req.Header.Add("Content-Type", "application/dns-message")
|
||||
|
||||
req.Header.Set("X-Padding", strings.Repeat("X", int(crypto.RandBetween(100, 1000))))
|
||||
|
||||
hc := s.httpClient
|
||||
|
||||
resp, err := hc.Do(req.WithContext(ctx))
|
||||
@@ -215,50 +326,107 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
// QueryIP implements Server.
|
||||
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) { // nolint: dupl
|
||||
fqdn := Fqdn(domain)
|
||||
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
||||
defer closeSubscribers(sub4, sub6)
|
||||
func (s *DoHNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||
s.RLock()
|
||||
record, found := s.ips[domain]
|
||||
s.RUnlock()
|
||||
|
||||
if s.cacheController.disableCache {
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
||||
if !found {
|
||||
return nil, errRecordNotFound
|
||||
}
|
||||
|
||||
var err4 error
|
||||
var err6 error
|
||||
var ips []net.Address
|
||||
var ip6 []net.Address
|
||||
|
||||
if option.IPv4Enable {
|
||||
ips, err4 = record.A.getIPs()
|
||||
}
|
||||
|
||||
if option.IPv6Enable {
|
||||
ip6, err6 = record.AAAA.getIPs()
|
||||
ips = append(ips, ip6...)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
return toNetIP(ips)
|
||||
}
|
||||
|
||||
if err4 != nil {
|
||||
return nil, err4
|
||||
}
|
||||
|
||||
if err6 != nil {
|
||||
return nil, err6
|
||||
}
|
||||
|
||||
if (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {
|
||||
return nil, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
return nil, errRecordNotFound
|
||||
}
|
||||
|
||||
// QueryIP implements Server.
|
||||
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) { // nolint: dupl
|
||||
fqdn := Fqdn(domain)
|
||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
if 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
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err == nil || err == dns_feature.ErrEmptyResponse {
|
||||
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, err
|
||||
}
|
||||
}
|
||||
|
||||
noResponseErrCh := make(chan error, 2)
|
||||
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
||||
// ipv4 and ipv6 belong to different subscription groups
|
||||
var sub4, sub6 *pubsub.Subscriber
|
||||
if option.IPv4Enable {
|
||||
sub4 = s.pub.Subscribe(fqdn + "4")
|
||||
defer sub4.Close()
|
||||
}
|
||||
if option.IPv6Enable {
|
||||
sub6 = s.pub.Subscribe(fqdn + "6")
|
||||
defer sub6.Close()
|
||||
}
|
||||
done := make(chan interface{})
|
||||
go func() {
|
||||
if sub4 != nil {
|
||||
select {
|
||||
case <-sub4.Wait():
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
if sub6 != nil {
|
||||
select {
|
||||
case <-sub6.Wait():
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
close(done)
|
||||
}()
|
||||
s.sendQuery(ctx, fqdn, clientIP, option)
|
||||
start := time.Now()
|
||||
|
||||
if sub4 != nil {
|
||||
for {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, err
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, 0, ctx.Err()
|
||||
case err := <-noResponseErrCh:
|
||||
return nil, 0, err
|
||||
case <-sub4.Wait():
|
||||
sub4.Close()
|
||||
return nil, ctx.Err()
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
if sub6 != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, 0, ctx.Err()
|
||||
case err := <-noResponseErrCh:
|
||||
return nil, 0, err
|
||||
case <-sub6.Wait():
|
||||
sub6.Close()
|
||||
}
|
||||
}
|
||||
|
||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, ttl, err
|
||||
|
||||
}
|
||||
|
@@ -17,12 +17,12 @@ func TestDOHNameServer(t *testing.T) {
|
||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHNameServer(url, nil, false, false, net.IP(nil))
|
||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP)
|
||||
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", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
@@ -34,12 +34,12 @@ func TestDOHNameServerWithCache(t *testing.T) {
|
||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHNameServer(url, nil, false, false, net.IP(nil))
|
||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP)
|
||||
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", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
@@ -47,10 +47,10 @@ func TestDOHNameServerWithCache(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips2, _, err := s.QueryIP(ctx2, "google.com", dns_feature.IPOption{
|
||||
ips2, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
}, true)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if r := cmp.Diff(ips2, ips); r != "" {
|
||||
@@ -62,12 +62,12 @@ func TestDOHNameServerWithIPv4Override(t *testing.T) {
|
||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHNameServer(url, nil, false, false, net.IP(nil))
|
||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP4)
|
||||
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", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: false,
|
||||
})
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
@@ -85,12 +85,12 @@ func TestDOHNameServerWithIPv6Override(t *testing.T) {
|
||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHNameServer(url, nil, false, false, net.IP(nil))
|
||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP6)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||
IPv4Enable: false,
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
|
@@ -20,9 +20,9 @@ func (FakeDNSServer) Name() string {
|
||||
return "FakeDNS"
|
||||
}
|
||||
|
||||
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, _ net.IP, opt dns.IPOption, _ bool) ([]net.IP, error) {
|
||||
if f.fakeDNSEngine == nil {
|
||||
return nil, 0, errors.New("Unable to locate a fake DNS Engine").AtError()
|
||||
return nil, errors.New("Unable to locate a fake DNS Engine").AtError()
|
||||
}
|
||||
|
||||
var ips []net.Address
|
||||
@@ -34,13 +34,13 @@ func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, opt dns.IPOp
|
||||
|
||||
netIP, err := toNetIP(ips)
|
||||
if err != nil {
|
||||
return nil, 0, errors.New("Unable to convert IP to net ip").Base(err).AtError()
|
||||
return nil, errors.New("Unable to convert IP to net ip").Base(err).AtError()
|
||||
}
|
||||
|
||||
errors.LogInfo(ctx, f.Name(), " got answer: ", domain, " -> ", ips)
|
||||
|
||||
if len(netIP) > 0 {
|
||||
return netIP, 1, nil // fakeIP ttl is 1
|
||||
return netIP, nil
|
||||
}
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
return nil, dns.ErrEmptyResponse
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
@@ -13,14 +14,25 @@ import (
|
||||
|
||||
// LocalNameServer is an wrapper over local DNS feature.
|
||||
type LocalNameServer struct {
|
||||
client *localdns.Client
|
||||
client *localdns.Client
|
||||
queryStrategy QueryStrategy
|
||||
}
|
||||
|
||||
const errEmptyResponse = "No address associated with hostname"
|
||||
|
||||
// QueryIP implements Server.
|
||||
func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, option dns.IPOption) (ips []net.IP, ttl uint32, err error) {
|
||||
func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, _ net.IP, option dns.IPOption, _ bool) (ips []net.IP, err error) {
|
||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, dns.ErrEmptyResponse
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
ips, ttl, err = s.client.LookupIP(domain, option)
|
||||
ips, err = s.client.LookupIP(domain, option)
|
||||
|
||||
if err != nil && strings.HasSuffix(err.Error(), errEmptyResponse) {
|
||||
err = dns.ErrEmptyResponse
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
errors.LogInfo(ctx, "Localhost got answer: ", domain, " -> ", ips)
|
||||
@@ -36,14 +48,15 @@ func (s *LocalNameServer) Name() string {
|
||||
}
|
||||
|
||||
// NewLocalNameServer creates localdns server object for directly lookup in system DNS.
|
||||
func NewLocalNameServer() *LocalNameServer {
|
||||
func NewLocalNameServer(queryStrategy QueryStrategy) *LocalNameServer {
|
||||
errors.LogInfo(context.Background(), "DNS: created localhost client")
|
||||
return &LocalNameServer{
|
||||
client: localdns.New(),
|
||||
queryStrategy: queryStrategy,
|
||||
client: localdns.New(),
|
||||
}
|
||||
}
|
||||
|
||||
// NewLocalDNSClient creates localdns client object for directly lookup in system DNS.
|
||||
func NewLocalDNSClient(ipOption dns.IPOption) *Client {
|
||||
return &Client{server: NewLocalNameServer(), ipOption: &ipOption}
|
||||
func NewLocalDNSClient() *Client {
|
||||
return &Client{server: NewLocalNameServer(QueryStrategy_USE_IP)}
|
||||
}
|
||||
|
@@ -7,17 +7,18 @@ import (
|
||||
|
||||
. "github.com/xtls/xray-core/app/dns"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
)
|
||||
|
||||
func TestLocalNameServer(t *testing.T) {
|
||||
s := NewLocalNameServer()
|
||||
s := NewLocalNameServer(QueryStrategy_USE_IP)
|
||||
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", net.IP{}, dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
|
@@ -4,20 +4,23 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
go_errors "errors"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/log"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol/dns"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
@@ -30,14 +33,17 @@ const handshakeTimeout = time.Second * 8
|
||||
// QUICNameServer implemented DNS over QUIC
|
||||
type QUICNameServer struct {
|
||||
sync.RWMutex
|
||||
cacheController *CacheController
|
||||
destination *net.Destination
|
||||
connection *quic.Conn
|
||||
clientIP net.IP
|
||||
ips map[string]*record
|
||||
pub *pubsub.Service
|
||||
cleanup *task.Periodic
|
||||
name string
|
||||
destination *net.Destination
|
||||
connection quic.Connection
|
||||
queryStrategy QueryStrategy
|
||||
}
|
||||
|
||||
// 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, queryStrategy QueryStrategy) (*QUICNameServer, error) {
|
||||
errors.LogInfo(context.Background(), "DNS: created Local DNS-over-QUIC client for ", url.String())
|
||||
|
||||
var err error
|
||||
@@ -51,9 +57,15 @@ func NewQUICNameServer(url *url.URL, disableCache bool, clientIP net.IP) (*QUICN
|
||||
dest := net.UDPDestination(net.ParseAddress(url.Hostname()), port)
|
||||
|
||||
s := &QUICNameServer{
|
||||
cacheController: NewCacheController(url.String(), disableCache),
|
||||
destination: &dest,
|
||||
clientIP: clientIP,
|
||||
ips: make(map[string]*record),
|
||||
pub: pubsub.NewService(),
|
||||
name: url.String(),
|
||||
destination: &dest,
|
||||
queryStrategy: queryStrategy,
|
||||
}
|
||||
s.cleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
Execute: s.Cleanup,
|
||||
}
|
||||
|
||||
return s, nil
|
||||
@@ -61,17 +73,94 @@ func NewQUICNameServer(url *url.URL, disableCache bool, clientIP net.IP) (*QUICN
|
||||
|
||||
// Name returns client name
|
||||
func (s *QUICNameServer) Name() string {
|
||||
return s.cacheController.name
|
||||
return s.name
|
||||
}
|
||||
|
||||
// Cleanup clears expired items from cache
|
||||
func (s *QUICNameServer) Cleanup() error {
|
||||
now := time.Now()
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
return errors.New("nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for domain, record := range s.ips {
|
||||
if record.A != nil && record.A.Expire.Before(now) {
|
||||
record.A = nil
|
||||
}
|
||||
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
||||
record.AAAA = nil
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||
delete(s.ips, domain)
|
||||
} else {
|
||||
s.ips[domain] = record
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
s.ips = make(map[string]*record)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
elapsed := time.Since(req.start)
|
||||
|
||||
s.Lock()
|
||||
rec, found := s.ips[req.domain]
|
||||
if !found {
|
||||
rec = &record{}
|
||||
}
|
||||
updated := false
|
||||
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
if isNewer(rec.A, ipRec) {
|
||||
rec.A = ipRec
|
||||
updated = true
|
||||
}
|
||||
case dnsmessage.TypeAAAA:
|
||||
addr := make([]net.Address, 0)
|
||||
for _, ip := range ipRec.IP {
|
||||
if len(ip.IP()) == net.IPv6len {
|
||||
addr = append(addr, ip)
|
||||
}
|
||||
}
|
||||
ipRec.IP = addr
|
||||
if isNewer(rec.AAAA, ipRec) {
|
||||
rec.AAAA = ipRec
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||
|
||||
if updated {
|
||||
s.ips[req.domain] = rec
|
||||
}
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
s.pub.Publish(req.domain+"4", nil)
|
||||
case dnsmessage.TypeAAAA:
|
||||
s.pub.Publish(req.domain+"6", nil)
|
||||
}
|
||||
s.Unlock()
|
||||
common.Must(s.cleanup.Start())
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) newReqID() uint16 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
||||
errors.LogInfo(ctx, s.Name(), " querying: ", domain)
|
||||
func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||
errors.LogInfo(ctx, s.name, " querying: ", domain)
|
||||
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||
|
||||
var deadline time.Time
|
||||
if d, ok := ctx.Deadline(); ok {
|
||||
@@ -103,36 +192,23 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- e
|
||||
b, err := dns.PackMessage(r.msg)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
dnsReqBuf := buf.New()
|
||||
err = binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "binary write failed")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
_, err = dnsReqBuf.Write(b.Bytes())
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "buffer write failed")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
||||
dnsReqBuf.Write(b.Bytes())
|
||||
b.Release()
|
||||
|
||||
conn, err := s.openStream(dnsCtx)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to open quic connection")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
_, err = conn.Write(dnsReqBuf.Bytes())
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to send query")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
@@ -143,84 +219,137 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- e
|
||||
n, err := respBuf.ReadFullFrom(conn, 2)
|
||||
if err != nil && n == 0 {
|
||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
var length int16
|
||||
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
respBuf.Clear()
|
||||
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
||||
if err != nil && n == 0 {
|
||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
rec, err := parseResponse(respBuf.Bytes())
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to handle response")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
s.cacheController.updateIP(r, rec)
|
||||
s.updateIP(r, rec)
|
||||
}(req)
|
||||
}
|
||||
}
|
||||
|
||||
// QueryIP is called from dns.Server->queryIPTimeout
|
||||
func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||
fqdn := Fqdn(domain)
|
||||
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
||||
defer closeSubscribers(sub4, sub6)
|
||||
func (s *QUICNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||
s.RLock()
|
||||
record, found := s.ips[domain]
|
||||
s.RUnlock()
|
||||
|
||||
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
|
||||
}
|
||||
if !found {
|
||||
return nil, errRecordNotFound
|
||||
}
|
||||
|
||||
noResponseErrCh := make(chan error, 2)
|
||||
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
||||
start := time.Now()
|
||||
var err4 error
|
||||
var err6 error
|
||||
var ips []net.Address
|
||||
var ip6 []net.Address
|
||||
|
||||
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()
|
||||
}
|
||||
if option.IPv4Enable {
|
||||
ips, err4 = record.A.getIPs()
|
||||
}
|
||||
|
||||
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
|
||||
if option.IPv6Enable {
|
||||
ip6, err6 = record.AAAA.getIPs()
|
||||
ips = append(ips, ip6...)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
return toNetIP(ips)
|
||||
}
|
||||
|
||||
if err4 != nil {
|
||||
return nil, err4
|
||||
}
|
||||
|
||||
if err6 != nil {
|
||||
return nil, err6
|
||||
}
|
||||
|
||||
if (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {
|
||||
return nil, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
return nil, errRecordNotFound
|
||||
}
|
||||
|
||||
func isActive(s *quic.Conn) bool {
|
||||
// QueryIP is called from dns.Server->queryIPTimeout
|
||||
func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
|
||||
fqdn := Fqdn(domain)
|
||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
if disableCache {
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
|
||||
} else {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err == nil || err == dns_feature.ErrEmptyResponse {
|
||||
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, err
|
||||
}
|
||||
}
|
||||
|
||||
// ipv4 and ipv6 belong to different subscription groups
|
||||
var sub4, sub6 *pubsub.Subscriber
|
||||
if option.IPv4Enable {
|
||||
sub4 = s.pub.Subscribe(fqdn + "4")
|
||||
defer sub4.Close()
|
||||
}
|
||||
if option.IPv6Enable {
|
||||
sub6 = s.pub.Subscribe(fqdn + "6")
|
||||
defer sub6.Close()
|
||||
}
|
||||
done := make(chan interface{})
|
||||
go func() {
|
||||
if sub4 != nil {
|
||||
select {
|
||||
case <-sub4.Wait():
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
if sub6 != nil {
|
||||
select {
|
||||
case <-sub6.Wait():
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
close(done)
|
||||
}()
|
||||
s.sendQuery(ctx, fqdn, clientIP, option)
|
||||
start := time.Now()
|
||||
|
||||
for {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, err
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isActive(s quic.Connection) bool {
|
||||
select {
|
||||
case <-s.Context().Done():
|
||||
return false
|
||||
@@ -229,8 +358,8 @@ func isActive(s *quic.Conn) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) getConnection() (*quic.Conn, error) {
|
||||
var conn *quic.Conn
|
||||
func (s *QUICNameServer) getConnection() (quic.Connection, error) {
|
||||
var conn quic.Connection
|
||||
s.RLock()
|
||||
conn = s.connection
|
||||
if conn != nil && isActive(conn) {
|
||||
@@ -263,7 +392,7 @@ func (s *QUICNameServer) getConnection() (*quic.Conn, error) {
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) openConnection() (*quic.Conn, error) {
|
||||
func (s *QUICNameServer) openConnection() (quic.Connection, error) {
|
||||
tlsConfig := tls.Config{}
|
||||
quicConfig := &quic.Config{
|
||||
HandshakeIdleTimeout: handshakeTimeout,
|
||||
@@ -283,7 +412,7 @@ func (s *QUICNameServer) openConnection() (*quic.Conn, error) {
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) openStream(ctx context.Context) (*quic.Stream, error) {
|
||||
func (s *QUICNameServer) openStream(ctx context.Context) (quic.Stream, error) {
|
||||
conn, err := s.getConnection()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -16,23 +16,24 @@ import (
|
||||
func TestQUICNameServer(t *testing.T) {
|
||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
||||
common.Must(err)
|
||||
s, err := NewQUICNameServer(url, false, net.IP(nil))
|
||||
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP)
|
||||
common.Must(err)
|
||||
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", net.IP(nil), dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
t.Error("expect some ips, but got 0")
|
||||
}
|
||||
|
||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips2, _, err := s.QueryIP(ctx2, "google.com", dns.IPOption{
|
||||
ips2, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
}, true)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if r := cmp.Diff(ips2, ips); r != "" {
|
||||
@@ -43,13 +44,13 @@ func TestQUICNameServer(t *testing.T) {
|
||||
func TestQUICNameServerWithIPv4Override(t *testing.T) {
|
||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
||||
common.Must(err)
|
||||
s, err := NewQUICNameServer(url, false, net.IP(nil))
|
||||
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP4)
|
||||
common.Must(err)
|
||||
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", net.IP(nil), dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: false,
|
||||
})
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
@@ -66,13 +67,13 @@ func TestQUICNameServerWithIPv4Override(t *testing.T) {
|
||||
func TestQUICNameServerWithIPv6Override(t *testing.T) {
|
||||
url, err := url.Parse("quic://dns.adguard-dns.com")
|
||||
common.Must(err)
|
||||
s, err := NewQUICNameServer(url, false, net.IP(nil))
|
||||
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP6)
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns.IPOption{
|
||||
IPv4Enable: false,
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
|
@@ -4,11 +4,12 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
go_errors "errors"
|
||||
"net/url"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/log"
|
||||
@@ -16,28 +17,34 @@ import (
|
||||
"github.com/xtls/xray-core/common/net/cnc"
|
||||
"github.com/xtls/xray-core/common/protocol/dns"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
)
|
||||
|
||||
// TCPNameServer implemented DNS over TCP (RFC7766).
|
||||
type TCPNameServer struct {
|
||||
cacheController *CacheController
|
||||
destination *net.Destination
|
||||
reqID uint32
|
||||
dial func(context.Context) (net.Conn, error)
|
||||
clientIP net.IP
|
||||
sync.RWMutex
|
||||
name string
|
||||
destination *net.Destination
|
||||
ips map[string]*record
|
||||
pub *pubsub.Service
|
||||
cleanup *task.Periodic
|
||||
reqID uint32
|
||||
dial func(context.Context) (net.Conn, error)
|
||||
queryStrategy QueryStrategy
|
||||
}
|
||||
|
||||
// NewTCPNameServer creates DNS over TCP server object for remote resolving.
|
||||
func NewTCPNameServer(
|
||||
url *url.URL,
|
||||
dispatcher routing.Dispatcher,
|
||||
disableCache bool,
|
||||
clientIP net.IP,
|
||||
queryStrategy QueryStrategy,
|
||||
) (*TCPNameServer, error) {
|
||||
s, err := baseTCPNameServer(url, "TCP", disableCache, clientIP)
|
||||
s, err := baseTCPNameServer(url, "TCP", queryStrategy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -58,8 +65,8 @@ func NewTCPNameServer(
|
||||
}
|
||||
|
||||
// NewTCPLocalNameServer creates DNS over TCP client object for local resolving
|
||||
func NewTCPLocalNameServer(url *url.URL, disableCache bool, clientIP net.IP) (*TCPNameServer, error) {
|
||||
s, err := baseTCPNameServer(url, "TCPL", disableCache, clientIP)
|
||||
func NewTCPLocalNameServer(url *url.URL, queryStrategy QueryStrategy) (*TCPNameServer, error) {
|
||||
s, err := baseTCPNameServer(url, "TCPL", queryStrategy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -71,7 +78,7 @@ func NewTCPLocalNameServer(url *url.URL, disableCache bool, clientIP net.IP) (*T
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func baseTCPNameServer(url *url.URL, prefix string, disableCache bool, clientIP net.IP) (*TCPNameServer, error) {
|
||||
func baseTCPNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) (*TCPNameServer, error) {
|
||||
port := net.Port(53)
|
||||
if url.Port() != "" {
|
||||
var err error
|
||||
@@ -82,9 +89,15 @@ func baseTCPNameServer(url *url.URL, prefix string, disableCache bool, clientIP
|
||||
dest := net.TCPDestination(net.ParseAddress(url.Hostname()), port)
|
||||
|
||||
s := &TCPNameServer{
|
||||
cacheController: NewCacheController(prefix+"//"+dest.NetAddr(), disableCache),
|
||||
destination: &dest,
|
||||
clientIP: clientIP,
|
||||
destination: &dest,
|
||||
ips: make(map[string]*record),
|
||||
pub: pubsub.NewService(),
|
||||
name: prefix + "//" + dest.NetAddr(),
|
||||
queryStrategy: queryStrategy,
|
||||
}
|
||||
s.cleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
Execute: s.Cleanup,
|
||||
}
|
||||
|
||||
return s, nil
|
||||
@@ -92,17 +105,94 @@ func baseTCPNameServer(url *url.URL, prefix string, disableCache bool, clientIP
|
||||
|
||||
// Name implements Server.
|
||||
func (s *TCPNameServer) Name() string {
|
||||
return s.cacheController.name
|
||||
return s.name
|
||||
}
|
||||
|
||||
// Cleanup clears expired items from cache
|
||||
func (s *TCPNameServer) Cleanup() error {
|
||||
now := time.Now()
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
return errors.New("nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for domain, record := range s.ips {
|
||||
if record.A != nil && record.A.Expire.Before(now) {
|
||||
record.A = nil
|
||||
}
|
||||
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
||||
record.AAAA = nil
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||
delete(s.ips, domain)
|
||||
} else {
|
||||
s.ips[domain] = record
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
s.ips = make(map[string]*record)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TCPNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
elapsed := time.Since(req.start)
|
||||
|
||||
s.Lock()
|
||||
rec, found := s.ips[req.domain]
|
||||
if !found {
|
||||
rec = &record{}
|
||||
}
|
||||
updated := false
|
||||
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
if isNewer(rec.A, ipRec) {
|
||||
rec.A = ipRec
|
||||
updated = true
|
||||
}
|
||||
case dnsmessage.TypeAAAA:
|
||||
addr := make([]net.Address, 0)
|
||||
for _, ip := range ipRec.IP {
|
||||
if len(ip.IP()) == net.IPv6len {
|
||||
addr = append(addr, ip)
|
||||
}
|
||||
}
|
||||
ipRec.IP = addr
|
||||
if isNewer(rec.AAAA, ipRec) {
|
||||
rec.AAAA = ipRec
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||
|
||||
if updated {
|
||||
s.ips[req.domain] = rec
|
||||
}
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
s.pub.Publish(req.domain+"4", nil)
|
||||
case dnsmessage.TypeAAAA:
|
||||
s.pub.Publish(req.domain+"6", nil)
|
||||
}
|
||||
s.Unlock()
|
||||
common.Must(s.cleanup.Start())
|
||||
}
|
||||
|
||||
func (s *TCPNameServer) newReqID() uint16 {
|
||||
return uint16(atomic.AddUint32(&s.reqID, 1))
|
||||
}
|
||||
|
||||
func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, domain string, option dns_feature.IPOption) {
|
||||
errors.LogDebug(ctx, s.Name(), " querying DNS for: ", domain)
|
||||
func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||
errors.LogDebug(ctx, s.name, " querying DNS for: ", domain)
|
||||
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||
|
||||
var deadline time.Time
|
||||
if d, ok := ctx.Deadline(); ok {
|
||||
@@ -131,36 +221,23 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- er
|
||||
b, err := dns.PackMessage(r.msg)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to pack dns query")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := s.dial(dnsCtx)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to dial namesever")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
dnsReqBuf := buf.New()
|
||||
err = binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "binary write failed")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
_, err = dnsReqBuf.Write(b.Bytes())
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "buffer write failed")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
||||
dnsReqBuf.Write(b.Bytes())
|
||||
b.Release()
|
||||
|
||||
_, err = conn.Write(dnsReqBuf.Bytes())
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to send query")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
dnsReqBuf.Release()
|
||||
@@ -170,80 +247,129 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- er
|
||||
n, err := respBuf.ReadFullFrom(conn, 2)
|
||||
if err != nil && n == 0 {
|
||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
var length int16
|
||||
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to parse response length")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
respBuf.Clear()
|
||||
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
||||
if err != nil && n == 0 {
|
||||
errors.LogErrorInner(ctx, err, "failed to read response length")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
rec, err := parseResponse(respBuf.Bytes())
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to parse DNS over TCP response")
|
||||
noResponseErrCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
s.cacheController.updateIP(r, rec)
|
||||
s.updateIP(r, rec)
|
||||
}(req)
|
||||
}
|
||||
}
|
||||
|
||||
// QueryIP implements Server.
|
||||
func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||
fqdn := Fqdn(domain)
|
||||
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
||||
defer closeSubscribers(sub4, sub6)
|
||||
func (s *TCPNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||
s.RLock()
|
||||
record, found := s.ips[domain]
|
||||
s.RUnlock()
|
||||
|
||||
if s.cacheController.disableCache {
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
||||
if !found {
|
||||
return nil, errRecordNotFound
|
||||
}
|
||||
|
||||
var err4 error
|
||||
var err6 error
|
||||
var ips []net.Address
|
||||
var ip6 []net.Address
|
||||
|
||||
if option.IPv4Enable {
|
||||
ips, err4 = record.A.getIPs()
|
||||
}
|
||||
|
||||
if option.IPv6Enable {
|
||||
ip6, err6 = record.AAAA.getIPs()
|
||||
ips = append(ips, ip6...)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
return toNetIP(ips)
|
||||
}
|
||||
|
||||
if err4 != nil {
|
||||
return nil, err4
|
||||
}
|
||||
|
||||
if err6 != nil {
|
||||
return nil, err6
|
||||
}
|
||||
|
||||
return nil, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
// QueryIP implements Server.
|
||||
func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
|
||||
fqdn := Fqdn(domain)
|
||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
if 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
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err == nil || err == dns_feature.ErrEmptyResponse {
|
||||
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, err
|
||||
}
|
||||
}
|
||||
|
||||
noResponseErrCh := make(chan error, 2)
|
||||
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
||||
// ipv4 and ipv6 belong to different subscription groups
|
||||
var sub4, sub6 *pubsub.Subscriber
|
||||
if option.IPv4Enable {
|
||||
sub4 = s.pub.Subscribe(fqdn + "4")
|
||||
defer sub4.Close()
|
||||
}
|
||||
if option.IPv6Enable {
|
||||
sub6 = s.pub.Subscribe(fqdn + "6")
|
||||
defer sub6.Close()
|
||||
}
|
||||
done := make(chan interface{})
|
||||
go func() {
|
||||
if sub4 != nil {
|
||||
select {
|
||||
case <-sub4.Wait():
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
if sub6 != nil {
|
||||
select {
|
||||
case <-sub6.Wait():
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
close(done)
|
||||
}()
|
||||
s.sendQuery(ctx, fqdn, clientIP, option)
|
||||
start := time.Now()
|
||||
|
||||
if sub4 != nil {
|
||||
for {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, err
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, 0, ctx.Err()
|
||||
case err := <-noResponseErrCh:
|
||||
return nil, 0, err
|
||||
case <-sub4.Wait():
|
||||
sub4.Close()
|
||||
return nil, ctx.Err()
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
if sub6 != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, 0, ctx.Err()
|
||||
case err := <-noResponseErrCh:
|
||||
return nil, 0, err
|
||||
case <-sub6.Wait():
|
||||
sub6.Close()
|
||||
}
|
||||
}
|
||||
|
||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, ttl, err
|
||||
|
||||
}
|
||||
|
@@ -16,13 +16,13 @@ import (
|
||||
func TestTCPLocalNameServer(t *testing.T) {
|
||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||
common.Must(err)
|
||||
s, err := NewTCPLocalNameServer(url, false, net.IP(nil))
|
||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP)
|
||||
common.Must(err)
|
||||
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", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
@@ -33,13 +33,13 @@ func TestTCPLocalNameServer(t *testing.T) {
|
||||
func TestTCPLocalNameServerWithCache(t *testing.T) {
|
||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||
common.Must(err)
|
||||
s, err := NewTCPLocalNameServer(url, false, net.IP(nil))
|
||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP)
|
||||
common.Must(err)
|
||||
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", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
@@ -47,10 +47,10 @@ func TestTCPLocalNameServerWithCache(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips2, _, err := s.QueryIP(ctx2, "google.com", dns_feature.IPOption{
|
||||
ips2, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
}, true)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if r := cmp.Diff(ips2, ips); r != "" {
|
||||
@@ -61,13 +61,13 @@ func TestTCPLocalNameServerWithCache(t *testing.T) {
|
||||
func TestTCPLocalNameServerWithIPv4Override(t *testing.T) {
|
||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||
common.Must(err)
|
||||
s, err := NewTCPLocalNameServer(url, false, net.IP(nil))
|
||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP4)
|
||||
common.Must(err)
|
||||
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", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: false,
|
||||
})
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
|
||||
@@ -85,13 +85,13 @@ func TestTCPLocalNameServerWithIPv4Override(t *testing.T) {
|
||||
func TestTCPLocalNameServerWithIPv6Override(t *testing.T) {
|
||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||
common.Must(err)
|
||||
s, err := NewTCPLocalNameServer(url, false, net.IP(nil))
|
||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP6)
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, _, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||
IPv4Enable: false,
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
|
||||
|
@@ -2,7 +2,6 @@ package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
go_errors "errors"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -14,6 +13,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol/dns"
|
||||
udp_proto "github.com/xtls/xray-core/common/protocol/udp"
|
||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
@@ -24,36 +24,35 @@ import (
|
||||
// ClassicNameServer implemented traditional UDP DNS.
|
||||
type ClassicNameServer struct {
|
||||
sync.RWMutex
|
||||
cacheController *CacheController
|
||||
address *net.Destination
|
||||
requests map[uint16]*udpDnsRequest
|
||||
udpServer *udp.Dispatcher
|
||||
requestsCleanup *task.Periodic
|
||||
reqID uint32
|
||||
clientIP net.IP
|
||||
}
|
||||
|
||||
type udpDnsRequest struct {
|
||||
dnsRequest
|
||||
ctx context.Context
|
||||
name string
|
||||
address *net.Destination
|
||||
ips map[string]*record
|
||||
requests map[uint16]*dnsRequest
|
||||
pub *pubsub.Service
|
||||
udpServer *udp.Dispatcher
|
||||
cleanup *task.Periodic
|
||||
reqID uint32
|
||||
queryStrategy QueryStrategy
|
||||
}
|
||||
|
||||
// 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, queryStrategy QueryStrategy) *ClassicNameServer {
|
||||
// default to 53 if unspecific
|
||||
if address.Port == 0 {
|
||||
address.Port = net.Port(53)
|
||||
}
|
||||
|
||||
s := &ClassicNameServer{
|
||||
cacheController: NewCacheController(strings.ToUpper(address.String()), disableCache),
|
||||
address: &address,
|
||||
requests: make(map[uint16]*udpDnsRequest),
|
||||
clientIP: clientIP,
|
||||
address: &address,
|
||||
ips: make(map[string]*record),
|
||||
requests: make(map[uint16]*dnsRequest),
|
||||
pub: pubsub.NewService(),
|
||||
name: strings.ToUpper(address.String()),
|
||||
queryStrategy: queryStrategy,
|
||||
}
|
||||
s.requestsCleanup = &task.Periodic{
|
||||
s.cleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
Execute: s.RequestsCleanup,
|
||||
Execute: s.Cleanup,
|
||||
}
|
||||
s.udpServer = udp.NewDispatcher(dispatcher, s.HandleResponse)
|
||||
errors.LogInfo(context.Background(), "DNS: created UDP client initialized for ", address.NetAddr())
|
||||
@@ -62,17 +61,37 @@ func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher
|
||||
|
||||
// Name implements Server.
|
||||
func (s *ClassicNameServer) Name() string {
|
||||
return s.cacheController.name
|
||||
return s.name
|
||||
}
|
||||
|
||||
// RequestsCleanup clears expired items from cache
|
||||
func (s *ClassicNameServer) RequestsCleanup() error {
|
||||
// Cleanup clears expired items from cache
|
||||
func (s *ClassicNameServer) Cleanup() error {
|
||||
now := time.Now()
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if len(s.requests) == 0 {
|
||||
return errors.New(s.Name(), " nothing to do. stopping...")
|
||||
if len(s.ips) == 0 && len(s.requests) == 0 {
|
||||
return errors.New(s.name, " nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for domain, record := range s.ips {
|
||||
if record.A != nil && record.A.Expire.Before(now) {
|
||||
record.A = nil
|
||||
}
|
||||
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
||||
record.AAAA = nil
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
|
||||
delete(s.ips, domain)
|
||||
} else {
|
||||
s.ips[domain] = record
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
s.ips = make(map[string]*record)
|
||||
}
|
||||
|
||||
for id, req := range s.requests {
|
||||
@@ -82,7 +101,7 @@ func (s *ClassicNameServer) RequestsCleanup() error {
|
||||
}
|
||||
|
||||
if len(s.requests) == 0 {
|
||||
s.requests = make(map[uint16]*udpDnsRequest)
|
||||
s.requests = make(map[uint16]*dnsRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -92,7 +111,7 @@ func (s *ClassicNameServer) RequestsCleanup() error {
|
||||
func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_proto.Packet) {
|
||||
ipRec, err := parseResponse(packet.Payload.Bytes())
|
||||
if err != nil {
|
||||
errors.LogError(ctx, s.Name(), " fail to parse responded DNS udp")
|
||||
errors.LogError(ctx, s.name, " fail to parse responded DNS udp")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -105,107 +124,179 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
||||
}
|
||||
s.Unlock()
|
||||
if !ok {
|
||||
errors.LogError(ctx, s.Name(), " cannot find the pending request")
|
||||
errors.LogError(ctx, s.name, " cannot find the pending request")
|
||||
return
|
||||
}
|
||||
|
||||
// if truncated, retry with EDNS0 option(udp payload size: 1350)
|
||||
if ipRec.RawHeader.Truncated {
|
||||
// if already has EDNS0 option, no need to retry
|
||||
if len(req.msg.Additionals) == 0 {
|
||||
// copy necessary meta data from original request
|
||||
// and add EDNS0 option
|
||||
opt := new(dnsmessage.Resource)
|
||||
common.Must(opt.Header.SetEDNS0(1350, 0xfe00, true))
|
||||
opt.Body = &dnsmessage.OPTResource{}
|
||||
newMsg := *req.msg
|
||||
newReq := *req
|
||||
newMsg.Additionals = append(newMsg.Additionals, *opt)
|
||||
newMsg.ID = s.newReqID()
|
||||
newReq.msg = &newMsg
|
||||
s.addPendingRequest(&newReq)
|
||||
b, _ := dns.PackMessage(newReq.msg)
|
||||
s.udpServer.Dispatch(toDnsContext(newReq.ctx, s.address.String()), *s.address, b)
|
||||
return
|
||||
}
|
||||
var rec record
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
rec.A = ipRec
|
||||
case dnsmessage.TypeAAAA:
|
||||
rec.AAAA = ipRec
|
||||
}
|
||||
|
||||
s.cacheController.updateIP(&req.dnsRequest, ipRec)
|
||||
elapsed := time.Since(req.start)
|
||||
errors.LogInfo(ctx, s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
|
||||
if len(req.domain) > 0 && (rec.A != nil || rec.AAAA != nil) {
|
||||
s.updateIP(req.domain, &rec)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ClassicNameServer) updateIP(domain string, newRec *record) {
|
||||
s.Lock()
|
||||
|
||||
rec, found := s.ips[domain]
|
||||
if !found {
|
||||
rec = &record{}
|
||||
}
|
||||
|
||||
updated := false
|
||||
if isNewer(rec.A, newRec.A) {
|
||||
rec.A = newRec.A
|
||||
updated = true
|
||||
}
|
||||
if isNewer(rec.AAAA, newRec.AAAA) {
|
||||
rec.AAAA = newRec.AAAA
|
||||
updated = true
|
||||
}
|
||||
|
||||
if updated {
|
||||
errors.LogDebug(context.Background(), s.name, " updating IP records for domain:", domain)
|
||||
s.ips[domain] = rec
|
||||
}
|
||||
if newRec.A != nil {
|
||||
s.pub.Publish(domain+"4", nil)
|
||||
}
|
||||
if newRec.AAAA != nil {
|
||||
s.pub.Publish(domain+"6", nil)
|
||||
}
|
||||
s.Unlock()
|
||||
common.Must(s.cleanup.Start())
|
||||
}
|
||||
|
||||
func (s *ClassicNameServer) newReqID() uint16 {
|
||||
return uint16(atomic.AddUint32(&s.reqID, 1))
|
||||
}
|
||||
|
||||
func (s *ClassicNameServer) addPendingRequest(req *udpDnsRequest) {
|
||||
func (s *ClassicNameServer) addPendingRequest(req *dnsRequest) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
id := req.msg.ID
|
||||
req.expire = time.Now().Add(time.Second * 8)
|
||||
s.requests[id] = req
|
||||
s.Unlock()
|
||||
common.Must(s.requestsCleanup.Start())
|
||||
}
|
||||
|
||||
func (s *ClassicNameServer) sendQuery(ctx context.Context, _ chan<- error, domain string, option dns_feature.IPOption) {
|
||||
errors.LogDebug(ctx, s.Name(), " querying DNS for: ", domain)
|
||||
func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||
errors.LogDebug(ctx, s.name, " querying DNS for: ", domain)
|
||||
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||
|
||||
for _, req := range reqs {
|
||||
udpReq := &udpDnsRequest{
|
||||
dnsRequest: *req,
|
||||
ctx: ctx,
|
||||
}
|
||||
s.addPendingRequest(udpReq)
|
||||
s.addPendingRequest(req)
|
||||
b, _ := dns.PackMessage(req.msg)
|
||||
s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b)
|
||||
}
|
||||
}
|
||||
|
||||
// QueryIP implements Server.
|
||||
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, uint32, error) {
|
||||
fqdn := Fqdn(domain)
|
||||
sub4, sub6 := s.cacheController.registerSubscribers(fqdn, option)
|
||||
defer closeSubscribers(sub4, sub6)
|
||||
func (s *ClassicNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||
s.RLock()
|
||||
record, found := s.ips[domain]
|
||||
s.RUnlock()
|
||||
|
||||
if s.cacheController.disableCache {
|
||||
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.Name())
|
||||
if !found {
|
||||
return nil, errRecordNotFound
|
||||
}
|
||||
|
||||
var err4 error
|
||||
var err6 error
|
||||
var ips []net.Address
|
||||
var ip6 []net.Address
|
||||
|
||||
if option.IPv4Enable {
|
||||
ips, err4 = record.A.getIPs()
|
||||
}
|
||||
|
||||
if option.IPv6Enable {
|
||||
ip6, err6 = record.AAAA.getIPs()
|
||||
ips = append(ips, ip6...)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
return toNetIP(ips)
|
||||
}
|
||||
|
||||
if err4 != nil {
|
||||
return nil, err4
|
||||
}
|
||||
|
||||
if err6 != nil {
|
||||
return nil, err6
|
||||
}
|
||||
|
||||
return nil, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
// QueryIP implements Server.
|
||||
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
|
||||
fqdn := Fqdn(domain)
|
||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
if 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
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err == nil || err == dns_feature.ErrEmptyResponse {
|
||||
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, err
|
||||
}
|
||||
}
|
||||
|
||||
noResponseErrCh := make(chan error, 2)
|
||||
s.sendQuery(ctx, noResponseErrCh, fqdn, option)
|
||||
// ipv4 and ipv6 belong to different subscription groups
|
||||
var sub4, sub6 *pubsub.Subscriber
|
||||
if option.IPv4Enable {
|
||||
sub4 = s.pub.Subscribe(fqdn + "4")
|
||||
defer sub4.Close()
|
||||
}
|
||||
if option.IPv6Enable {
|
||||
sub6 = s.pub.Subscribe(fqdn + "6")
|
||||
defer sub6.Close()
|
||||
}
|
||||
done := make(chan interface{})
|
||||
go func() {
|
||||
if sub4 != nil {
|
||||
select {
|
||||
case <-sub4.Wait():
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
if sub6 != nil {
|
||||
select {
|
||||
case <-sub6.Wait():
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
close(done)
|
||||
}()
|
||||
s.sendQuery(ctx, fqdn, clientIP, option)
|
||||
start := time.Now()
|
||||
|
||||
if sub4 != nil {
|
||||
for {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, err
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, 0, ctx.Err()
|
||||
case err := <-noResponseErrCh:
|
||||
return nil, 0, err
|
||||
case <-sub4.Wait():
|
||||
sub4.Close()
|
||||
return nil, ctx.Err()
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
if sub6 != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, 0, ctx.Err()
|
||||
case err := <-noResponseErrCh:
|
||||
return nil, 0, err
|
||||
case <-sub6.Wait():
|
||||
sub6.Close()
|
||||
}
|
||||
}
|
||||
|
||||
ips, ttl, err := s.cacheController.findIPsForDomain(fqdn, option)
|
||||
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
return ips, ttl, err
|
||||
|
||||
}
|
||||
|
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/net/cnc"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/signal/done"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
)
|
||||
@@ -109,13 +108,3 @@ func (co *Outbound) Close() error {
|
||||
co.closed = true
|
||||
return co.listener.Close()
|
||||
}
|
||||
|
||||
// SenderSettings implements outbound.Handler.
|
||||
func (co *Outbound) SenderSettings() *serial.TypedMessage {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProxySettings implements outbound.Handler.
|
||||
func (co *Outbound) ProxySettings() *serial.TypedMessage {
|
||||
return nil
|
||||
}
|
||||
|
@@ -90,8 +90,6 @@ type HealthPingConfig struct {
|
||||
SamplingCount int32 `protobuf:"varint,4,opt,name=samplingCount,proto3" json:"samplingCount,omitempty"`
|
||||
// ping timeout, int64 values of time.Duration
|
||||
Timeout int64 `protobuf:"varint,5,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
||||
// http method to make request
|
||||
HttpMethod string `protobuf:"bytes,6,opt,name=httpMethod,proto3" json:"httpMethod,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HealthPingConfig) Reset() {
|
||||
@@ -159,13 +157,6 @@ func (x *HealthPingConfig) GetTimeout() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HealthPingConfig) GetHttpMethod() string {
|
||||
if x != nil {
|
||||
return x.HttpMethod
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_app_observatory_burst_config_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
||||
@@ -182,7 +173,7 @@ var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
||||
0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x62, 0x75, 0x72,
|
||||
0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22,
|
||||
0xd4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
||||
0xb4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69,
|
||||
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
@@ -193,9 +184,7 @@ var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
||||
0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73,
|
||||
0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07,
|
||||
0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x4d, 0x65,
|
||||
0x74, 0x68, 0x6f, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x68, 0x74, 0x74, 0x70,
|
||||
0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
|
||||
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
|
||||
0x72, 0x79, 0x2e, 0x62, 0x75, 0x72, 0x73, 0x74, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68,
|
||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
||||
|
@@ -26,7 +26,4 @@ message HealthPingConfig {
|
||||
int32 samplingCount = 4;
|
||||
// ping timeout, int64 values of time.Duration
|
||||
int64 timeout = 5;
|
||||
// http method to make request
|
||||
string httpMethod = 6;
|
||||
|
||||
}
|
||||
|
@@ -19,7 +19,6 @@ type HealthPingSettings struct {
|
||||
Interval time.Duration `json:"interval"`
|
||||
SamplingCount int `json:"sampling"`
|
||||
Timeout time.Duration `json:"timeout"`
|
||||
HttpMethod string `json:"httpMethod"`
|
||||
}
|
||||
|
||||
// HealthPing is the health checker for balancers
|
||||
@@ -38,21 +37,12 @@ type HealthPing struct {
|
||||
func NewHealthPing(ctx context.Context, dispatcher routing.Dispatcher, config *HealthPingConfig) *HealthPing {
|
||||
settings := &HealthPingSettings{}
|
||||
if config != nil {
|
||||
|
||||
var httpMethod string
|
||||
if config.HttpMethod == "" {
|
||||
httpMethod = "HEAD"
|
||||
} else {
|
||||
httpMethod = strings.TrimSpace(config.HttpMethod)
|
||||
}
|
||||
|
||||
settings = &HealthPingSettings{
|
||||
Connectivity: strings.TrimSpace(config.Connectivity),
|
||||
Destination: strings.TrimSpace(config.Destination),
|
||||
Interval: time.Duration(config.Interval),
|
||||
SamplingCount: int(config.SamplingCount),
|
||||
Timeout: time.Duration(config.Timeout),
|
||||
HttpMethod: httpMethod,
|
||||
}
|
||||
}
|
||||
if settings.Destination == "" {
|
||||
@@ -174,7 +164,7 @@ func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int)
|
||||
}
|
||||
time.AfterFunc(delay, func() {
|
||||
errors.LogDebug(h.ctx, "checking ", handler)
|
||||
delay, err := client.MeasureDelay(h.Settings.HttpMethod)
|
||||
delay, err := client.MeasureDelay()
|
||||
if err == nil {
|
||||
ch <- &rtt{
|
||||
handler: handler,
|
||||
@@ -261,7 +251,7 @@ func (h *HealthPing) checkConnectivity() bool {
|
||||
h.Settings.Connectivity,
|
||||
h.Settings.Timeout,
|
||||
)
|
||||
if _, err := tester.MeasureDelay(h.Settings.HttpMethod); err != nil {
|
||||
if _, err := tester.MeasureDelay(); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
@@ -2,7 +2,6 @@ package burst
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@@ -52,28 +51,20 @@ func newHTTPClient(ctxv context.Context, dispatcher routing.Dispatcher, handler
|
||||
}
|
||||
|
||||
// MeasureDelay returns the delay time of the request to dest
|
||||
func (s *pingClient) MeasureDelay(httpMethod string) (time.Duration, error) {
|
||||
func (s *pingClient) MeasureDelay() (time.Duration, error) {
|
||||
if s.httpClient == nil {
|
||||
panic("pingClient not initialized")
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(httpMethod, s.destination, nil)
|
||||
req, err := http.NewRequest(http.MethodHead, s.destination, nil)
|
||||
if err != nil {
|
||||
return rttFailed, err
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
resp, err := s.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return rttFailed, err
|
||||
}
|
||||
if httpMethod == http.MethodGet {
|
||||
_, err = io.Copy(io.Discard, resp.Body)
|
||||
if err != nil {
|
||||
return rttFailed, err
|
||||
}
|
||||
}
|
||||
// don't wait for body
|
||||
resp.Body.Close()
|
||||
|
||||
return time.Since(start), nil
|
||||
}
|
||||
|
@@ -3,7 +3,6 @@ package command
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/app/commander"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
@@ -100,28 +99,6 @@ func (s *handlerServer) AlterInbound(ctx context.Context, request *AlterInboundR
|
||||
return &AlterInboundResponse{}, operation.ApplyInbound(ctx, handler)
|
||||
}
|
||||
|
||||
func (s *handlerServer) ListInbounds(ctx context.Context, request *ListInboundsRequest) (*ListInboundsResponse, error) {
|
||||
handlers := s.ihm.ListHandlers(ctx)
|
||||
response := &ListInboundsResponse{}
|
||||
if request.GetIsOnlyTags() {
|
||||
for _, handler := range handlers {
|
||||
response.Inbounds = append(response.Inbounds, &core.InboundHandlerConfig{
|
||||
Tag: handler.Tag(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
for _, handler := range handlers {
|
||||
response.Inbounds = append(response.Inbounds, &core.InboundHandlerConfig{
|
||||
Tag: handler.Tag(),
|
||||
ReceiverSettings: handler.ReceiverSettings(),
|
||||
ProxySettings: handler.ProxySettings(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *handlerServer) GetInboundUsers(ctx context.Context, request *GetInboundUserRequest) (*GetInboundUserResponse, error) {
|
||||
handler, err := s.ihm.GetHandler(ctx, request.Tag)
|
||||
if err != nil {
|
||||
@@ -187,23 +164,6 @@ func (s *handlerServer) AlterOutbound(ctx context.Context, request *AlterOutboun
|
||||
return &AlterOutboundResponse{}, operation.ApplyOutbound(ctx, handler)
|
||||
}
|
||||
|
||||
func (s *handlerServer) ListOutbounds(ctx context.Context, request *ListOutboundsRequest) (*ListOutboundsResponse, error) {
|
||||
handlers := s.ohm.ListHandlers(ctx)
|
||||
response := &ListOutboundsResponse{}
|
||||
for _, handler := range handlers {
|
||||
// Ignore gRPC outbound
|
||||
if _, ok := handler.(*commander.Outbound); ok {
|
||||
continue
|
||||
}
|
||||
response.Outbounds = append(response.Outbounds, &core.OutboundHandlerConfig{
|
||||
Tag: handler.Tag(),
|
||||
SenderSettings: handler.SenderSettings(),
|
||||
ProxySettings: handler.ProxySettings(),
|
||||
})
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *handlerServer) mustEmbedUnimplementedHandlerServiceServer() {}
|
||||
|
||||
type service struct {
|
||||
|
@@ -364,96 +364,6 @@ func (*AlterInboundResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
type ListInboundsRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
IsOnlyTags bool `protobuf:"varint,1,opt,name=isOnlyTags,proto3" json:"isOnlyTags,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ListInboundsRequest) Reset() {
|
||||
*x = ListInboundsRequest{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListInboundsRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListInboundsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ListInboundsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListInboundsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ListInboundsRequest) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *ListInboundsRequest) GetIsOnlyTags() bool {
|
||||
if x != nil {
|
||||
return x.IsOnlyTags
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ListInboundsResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Inbounds []*core.InboundHandlerConfig `protobuf:"bytes,1,rep,name=inbounds,proto3" json:"inbounds,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ListInboundsResponse) Reset() {
|
||||
*x = ListInboundsResponse{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListInboundsResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListInboundsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ListInboundsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListInboundsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ListInboundsResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *ListInboundsResponse) GetInbounds() []*core.InboundHandlerConfig {
|
||||
if x != nil {
|
||||
return x.Inbounds
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type GetInboundUserRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -465,7 +375,7 @@ type GetInboundUserRequest struct {
|
||||
|
||||
func (x *GetInboundUserRequest) Reset() {
|
||||
*x = GetInboundUserRequest{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -477,7 +387,7 @@ func (x *GetInboundUserRequest) String() string {
|
||||
func (*GetInboundUserRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetInboundUserRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[8]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -490,7 +400,7 @@ func (x *GetInboundUserRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetInboundUserRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetInboundUserRequest) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{10}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *GetInboundUserRequest) GetTag() string {
|
||||
@@ -517,7 +427,7 @@ type GetInboundUserResponse struct {
|
||||
|
||||
func (x *GetInboundUserResponse) Reset() {
|
||||
*x = GetInboundUserResponse{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -529,7 +439,7 @@ func (x *GetInboundUserResponse) String() string {
|
||||
func (*GetInboundUserResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetInboundUserResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[9]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -542,7 +452,7 @@ func (x *GetInboundUserResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetInboundUserResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetInboundUserResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{11}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *GetInboundUserResponse) GetUsers() []*protocol.User {
|
||||
@@ -562,7 +472,7 @@ type GetInboundUsersCountResponse struct {
|
||||
|
||||
func (x *GetInboundUsersCountResponse) Reset() {
|
||||
*x = GetInboundUsersCountResponse{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -574,7 +484,7 @@ func (x *GetInboundUsersCountResponse) String() string {
|
||||
func (*GetInboundUsersCountResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetInboundUsersCountResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[10]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -587,7 +497,7 @@ func (x *GetInboundUsersCountResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetInboundUsersCountResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetInboundUsersCountResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{12}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{10}
|
||||
}
|
||||
|
||||
func (x *GetInboundUsersCountResponse) GetCount() int64 {
|
||||
@@ -607,7 +517,7 @@ type AddOutboundRequest struct {
|
||||
|
||||
func (x *AddOutboundRequest) Reset() {
|
||||
*x = AddOutboundRequest{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -619,7 +529,7 @@ func (x *AddOutboundRequest) String() string {
|
||||
func (*AddOutboundRequest) ProtoMessage() {}
|
||||
|
||||
func (x *AddOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[11]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -632,7 +542,7 @@ func (x *AddOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use AddOutboundRequest.ProtoReflect.Descriptor instead.
|
||||
func (*AddOutboundRequest) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{13}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{11}
|
||||
}
|
||||
|
||||
func (x *AddOutboundRequest) GetOutbound() *core.OutboundHandlerConfig {
|
||||
@@ -650,7 +560,7 @@ type AddOutboundResponse struct {
|
||||
|
||||
func (x *AddOutboundResponse) Reset() {
|
||||
*x = AddOutboundResponse{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -662,7 +572,7 @@ func (x *AddOutboundResponse) String() string {
|
||||
func (*AddOutboundResponse) ProtoMessage() {}
|
||||
|
||||
func (x *AddOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[12]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -675,7 +585,7 @@ func (x *AddOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use AddOutboundResponse.ProtoReflect.Descriptor instead.
|
||||
func (*AddOutboundResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{14}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{12}
|
||||
}
|
||||
|
||||
type RemoveOutboundRequest struct {
|
||||
@@ -688,7 +598,7 @@ type RemoveOutboundRequest struct {
|
||||
|
||||
func (x *RemoveOutboundRequest) Reset() {
|
||||
*x = RemoveOutboundRequest{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[15]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -700,7 +610,7 @@ func (x *RemoveOutboundRequest) String() string {
|
||||
func (*RemoveOutboundRequest) ProtoMessage() {}
|
||||
|
||||
func (x *RemoveOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[15]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[13]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -713,7 +623,7 @@ func (x *RemoveOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use RemoveOutboundRequest.ProtoReflect.Descriptor instead.
|
||||
func (*RemoveOutboundRequest) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{15}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{13}
|
||||
}
|
||||
|
||||
func (x *RemoveOutboundRequest) GetTag() string {
|
||||
@@ -731,7 +641,7 @@ type RemoveOutboundResponse struct {
|
||||
|
||||
func (x *RemoveOutboundResponse) Reset() {
|
||||
*x = RemoveOutboundResponse{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[16]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -743,7 +653,7 @@ func (x *RemoveOutboundResponse) String() string {
|
||||
func (*RemoveOutboundResponse) ProtoMessage() {}
|
||||
|
||||
func (x *RemoveOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[16]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[14]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -756,7 +666,7 @@ func (x *RemoveOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use RemoveOutboundResponse.ProtoReflect.Descriptor instead.
|
||||
func (*RemoveOutboundResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{16}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{14}
|
||||
}
|
||||
|
||||
type AlterOutboundRequest struct {
|
||||
@@ -770,7 +680,7 @@ type AlterOutboundRequest struct {
|
||||
|
||||
func (x *AlterOutboundRequest) Reset() {
|
||||
*x = AlterOutboundRequest{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[17]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[15]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -782,7 +692,7 @@ func (x *AlterOutboundRequest) String() string {
|
||||
func (*AlterOutboundRequest) ProtoMessage() {}
|
||||
|
||||
func (x *AlterOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[17]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[15]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -795,7 +705,7 @@ func (x *AlterOutboundRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use AlterOutboundRequest.ProtoReflect.Descriptor instead.
|
||||
func (*AlterOutboundRequest) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{17}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{15}
|
||||
}
|
||||
|
||||
func (x *AlterOutboundRequest) GetTag() string {
|
||||
@@ -820,7 +730,7 @@ type AlterOutboundResponse struct {
|
||||
|
||||
func (x *AlterOutboundResponse) Reset() {
|
||||
*x = AlterOutboundResponse{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[18]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[16]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -832,7 +742,7 @@ func (x *AlterOutboundResponse) String() string {
|
||||
func (*AlterOutboundResponse) ProtoMessage() {}
|
||||
|
||||
func (x *AlterOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[18]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[16]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -845,88 +755,7 @@ func (x *AlterOutboundResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use AlterOutboundResponse.ProtoReflect.Descriptor instead.
|
||||
func (*AlterOutboundResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{18}
|
||||
}
|
||||
|
||||
type ListOutboundsRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *ListOutboundsRequest) Reset() {
|
||||
*x = ListOutboundsRequest{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[19]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListOutboundsRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListOutboundsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ListOutboundsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[19]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListOutboundsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ListOutboundsRequest) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{19}
|
||||
}
|
||||
|
||||
type ListOutboundsResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Outbounds []*core.OutboundHandlerConfig `protobuf:"bytes,1,rep,name=outbounds,proto3" json:"outbounds,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ListOutboundsResponse) Reset() {
|
||||
*x = ListOutboundsResponse{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[20]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListOutboundsResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListOutboundsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ListOutboundsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[20]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListOutboundsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ListOutboundsResponse) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{20}
|
||||
}
|
||||
|
||||
func (x *ListOutboundsResponse) GetOutbounds() []*core.OutboundHandlerConfig {
|
||||
if x != nil {
|
||||
return x.Outbounds
|
||||
}
|
||||
return nil
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{16}
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
@@ -937,7 +766,7 @@ type Config struct {
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[21]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[17]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -949,7 +778,7 @@ func (x *Config) String() string {
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[21]
|
||||
mi := &file_app_proxyman_command_command_proto_msgTypes[17]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -962,7 +791,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{21}
|
||||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{17}
|
||||
}
|
||||
|
||||
var File_app_proxyman_command_command_proto protoreflect.FileDescriptor
|
||||
@@ -1002,84 +831,61 @@ var file_app_proxyman_command_command_proto_rawDesc = []byte{
|
||||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70,
|
||||
0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x22, 0x16, 0x0a, 0x14, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62,
|
||||
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x35, 0x0a, 0x13,
|
||||
0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x54, 0x61, 0x67,
|
||||
0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x54,
|
||||
0x61, 0x67, 0x73, 0x22, 0x53, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75,
|
||||
0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x69,
|
||||
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
|
||||
0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08,
|
||||
0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x22, 0x3f, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x49,
|
||||
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
|
||||
0x74, 0x61, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x4a, 0x0a, 0x16, 0x47, 0x65, 0x74,
|
||||
0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05,
|
||||
0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x34, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f,
|
||||
0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x52, 0x0a, 0x12, 0x41,
|
||||
0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x12, 0x3c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
||||
0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x22,
|
||||
0x15, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
||||
0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||
0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61,
|
||||
0x67, 0x22, 0x18, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4f, 0x75, 0x74, 0x62, 0x6f,
|
||||
0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x68, 0x0a, 0x14, 0x41,
|
||||
0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,
|
||||
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3f, 0x0a, 0x15,
|
||||
0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x4a, 0x0a,
|
||||
0x16, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73,
|
||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73,
|
||||
0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x34, 0x0a, 0x1c, 0x47, 0x65, 0x74,
|
||||
0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x43, 0x6f, 0x75, 0x6e,
|
||||
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75,
|
||||
0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22,
|
||||
0x52, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
||||
0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64,
|
||||
0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f,
|
||||
0x75, 0x6e, 0x64, 0x22, 0x15, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75,
|
||||
0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x0a, 0x15, 0x52, 0x65,
|
||||
0x6d, 0x6f, 0x76, 0x65, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x3e, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79,
|
||||
0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x17, 0x0a, 0x15, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75,
|
||||
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16,
|
||||
0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x57, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75,
|
||||
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x3e, 0x0a, 0x09, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x4f,
|
||||
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x22,
|
||||
0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0xae, 0x09, 0x0a, 0x0e, 0x48, 0x61,
|
||||
0x6e, 0x64, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6b, 0x0a, 0x0a,
|
||||
0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2c, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
|
||||
0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x74, 0x0a, 0x0d, 0x52, 0x65, 0x6d,
|
||||
0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2f, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62,
|
||||
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x78, 0x72,
|
||||
0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x18, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4f,
|
||||
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x68, 0x0a, 0x14, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x3e, 0x0a, 0x09, 0x6f, 0x70, 0x65,
|
||||
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61,
|
||||
0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09,
|
||||
0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x17, 0x0a, 0x15, 0x41, 0x6c, 0x74,
|
||||
0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0xc5, 0x07, 0x0a,
|
||||
0x0e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||
0x6b, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2c, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
|
||||
0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62,
|
||||
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e,
|
||||
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
|
||||
0x71, 0x0a, 0x0c, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12,
|
||||
0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||
0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x6c, 0x74, 0x65,
|
||||
0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||
0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x6c, 0x74, 0x65,
|
||||
0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x00, 0x12, 0x71, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
|
||||
0x64, 0x73, 0x12, 0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75,
|
||||
0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x74, 0x0a, 0x0d,
|
||||
0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2f, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
|
||||
0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
||||
0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30,
|
||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d,
|
||||
0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76,
|
||||
0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x00, 0x12, 0x71, 0x0a, 0x0c, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75,
|
||||
0x6e, 0x64, 0x12, 0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41,
|
||||
0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41,
|
||||
0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x78, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f,
|
||||
0x75, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
@@ -1118,22 +924,14 @@ var file_app_proxyman_command_command_proto_rawDesc = []byte{
|
||||
0x1a, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x6c, 0x74,
|
||||
0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x00, 0x12, 0x74, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x62,
|
||||
0x6f, 0x75, 0x6e, 0x64, 0x73, 0x12, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
||||
0x64, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
||||
0x6e, 0x64, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f,
|
||||
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||
0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2e, 0x67,
|
||||
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f,
|
||||
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x19,
|
||||
0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
|
||||
0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
0x73, 0x65, 0x22, 0x00, 0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f,
|
||||
0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x19, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41,
|
||||
0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -1148,7 +946,7 @@ func file_app_proxyman_command_command_proto_rawDescGZIP() []byte {
|
||||
return file_app_proxyman_command_command_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_app_proxyman_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 22)
|
||||
var file_app_proxyman_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 18)
|
||||
var file_app_proxyman_command_command_proto_goTypes = []any{
|
||||
(*AddUserOperation)(nil), // 0: xray.app.proxyman.command.AddUserOperation
|
||||
(*RemoveUserOperation)(nil), // 1: xray.app.proxyman.command.RemoveUserOperation
|
||||
@@ -1158,59 +956,49 @@ var file_app_proxyman_command_command_proto_goTypes = []any{
|
||||
(*RemoveInboundResponse)(nil), // 5: xray.app.proxyman.command.RemoveInboundResponse
|
||||
(*AlterInboundRequest)(nil), // 6: xray.app.proxyman.command.AlterInboundRequest
|
||||
(*AlterInboundResponse)(nil), // 7: xray.app.proxyman.command.AlterInboundResponse
|
||||
(*ListInboundsRequest)(nil), // 8: xray.app.proxyman.command.ListInboundsRequest
|
||||
(*ListInboundsResponse)(nil), // 9: xray.app.proxyman.command.ListInboundsResponse
|
||||
(*GetInboundUserRequest)(nil), // 10: xray.app.proxyman.command.GetInboundUserRequest
|
||||
(*GetInboundUserResponse)(nil), // 11: xray.app.proxyman.command.GetInboundUserResponse
|
||||
(*GetInboundUsersCountResponse)(nil), // 12: xray.app.proxyman.command.GetInboundUsersCountResponse
|
||||
(*AddOutboundRequest)(nil), // 13: xray.app.proxyman.command.AddOutboundRequest
|
||||
(*AddOutboundResponse)(nil), // 14: xray.app.proxyman.command.AddOutboundResponse
|
||||
(*RemoveOutboundRequest)(nil), // 15: xray.app.proxyman.command.RemoveOutboundRequest
|
||||
(*RemoveOutboundResponse)(nil), // 16: xray.app.proxyman.command.RemoveOutboundResponse
|
||||
(*AlterOutboundRequest)(nil), // 17: xray.app.proxyman.command.AlterOutboundRequest
|
||||
(*AlterOutboundResponse)(nil), // 18: xray.app.proxyman.command.AlterOutboundResponse
|
||||
(*ListOutboundsRequest)(nil), // 19: xray.app.proxyman.command.ListOutboundsRequest
|
||||
(*ListOutboundsResponse)(nil), // 20: xray.app.proxyman.command.ListOutboundsResponse
|
||||
(*Config)(nil), // 21: xray.app.proxyman.command.Config
|
||||
(*protocol.User)(nil), // 22: xray.common.protocol.User
|
||||
(*core.InboundHandlerConfig)(nil), // 23: xray.core.InboundHandlerConfig
|
||||
(*serial.TypedMessage)(nil), // 24: xray.common.serial.TypedMessage
|
||||
(*core.OutboundHandlerConfig)(nil), // 25: xray.core.OutboundHandlerConfig
|
||||
(*GetInboundUserRequest)(nil), // 8: xray.app.proxyman.command.GetInboundUserRequest
|
||||
(*GetInboundUserResponse)(nil), // 9: xray.app.proxyman.command.GetInboundUserResponse
|
||||
(*GetInboundUsersCountResponse)(nil), // 10: xray.app.proxyman.command.GetInboundUsersCountResponse
|
||||
(*AddOutboundRequest)(nil), // 11: xray.app.proxyman.command.AddOutboundRequest
|
||||
(*AddOutboundResponse)(nil), // 12: xray.app.proxyman.command.AddOutboundResponse
|
||||
(*RemoveOutboundRequest)(nil), // 13: xray.app.proxyman.command.RemoveOutboundRequest
|
||||
(*RemoveOutboundResponse)(nil), // 14: xray.app.proxyman.command.RemoveOutboundResponse
|
||||
(*AlterOutboundRequest)(nil), // 15: xray.app.proxyman.command.AlterOutboundRequest
|
||||
(*AlterOutboundResponse)(nil), // 16: xray.app.proxyman.command.AlterOutboundResponse
|
||||
(*Config)(nil), // 17: xray.app.proxyman.command.Config
|
||||
(*protocol.User)(nil), // 18: xray.common.protocol.User
|
||||
(*core.InboundHandlerConfig)(nil), // 19: xray.core.InboundHandlerConfig
|
||||
(*serial.TypedMessage)(nil), // 20: xray.common.serial.TypedMessage
|
||||
(*core.OutboundHandlerConfig)(nil), // 21: xray.core.OutboundHandlerConfig
|
||||
}
|
||||
var file_app_proxyman_command_command_proto_depIdxs = []int32{
|
||||
22, // 0: xray.app.proxyman.command.AddUserOperation.user:type_name -> xray.common.protocol.User
|
||||
23, // 1: xray.app.proxyman.command.AddInboundRequest.inbound:type_name -> xray.core.InboundHandlerConfig
|
||||
24, // 2: xray.app.proxyman.command.AlterInboundRequest.operation:type_name -> xray.common.serial.TypedMessage
|
||||
23, // 3: xray.app.proxyman.command.ListInboundsResponse.inbounds:type_name -> xray.core.InboundHandlerConfig
|
||||
22, // 4: xray.app.proxyman.command.GetInboundUserResponse.users:type_name -> xray.common.protocol.User
|
||||
25, // 5: xray.app.proxyman.command.AddOutboundRequest.outbound:type_name -> xray.core.OutboundHandlerConfig
|
||||
24, // 6: xray.app.proxyman.command.AlterOutboundRequest.operation:type_name -> xray.common.serial.TypedMessage
|
||||
25, // 7: xray.app.proxyman.command.ListOutboundsResponse.outbounds:type_name -> xray.core.OutboundHandlerConfig
|
||||
2, // 8: xray.app.proxyman.command.HandlerService.AddInbound:input_type -> xray.app.proxyman.command.AddInboundRequest
|
||||
4, // 9: xray.app.proxyman.command.HandlerService.RemoveInbound:input_type -> xray.app.proxyman.command.RemoveInboundRequest
|
||||
6, // 10: xray.app.proxyman.command.HandlerService.AlterInbound:input_type -> xray.app.proxyman.command.AlterInboundRequest
|
||||
8, // 11: xray.app.proxyman.command.HandlerService.ListInbounds:input_type -> xray.app.proxyman.command.ListInboundsRequest
|
||||
10, // 12: xray.app.proxyman.command.HandlerService.GetInboundUsers:input_type -> xray.app.proxyman.command.GetInboundUserRequest
|
||||
10, // 13: xray.app.proxyman.command.HandlerService.GetInboundUsersCount:input_type -> xray.app.proxyman.command.GetInboundUserRequest
|
||||
13, // 14: xray.app.proxyman.command.HandlerService.AddOutbound:input_type -> xray.app.proxyman.command.AddOutboundRequest
|
||||
15, // 15: xray.app.proxyman.command.HandlerService.RemoveOutbound:input_type -> xray.app.proxyman.command.RemoveOutboundRequest
|
||||
17, // 16: xray.app.proxyman.command.HandlerService.AlterOutbound:input_type -> xray.app.proxyman.command.AlterOutboundRequest
|
||||
19, // 17: xray.app.proxyman.command.HandlerService.ListOutbounds:input_type -> xray.app.proxyman.command.ListOutboundsRequest
|
||||
3, // 18: xray.app.proxyman.command.HandlerService.AddInbound:output_type -> xray.app.proxyman.command.AddInboundResponse
|
||||
5, // 19: xray.app.proxyman.command.HandlerService.RemoveInbound:output_type -> xray.app.proxyman.command.RemoveInboundResponse
|
||||
7, // 20: xray.app.proxyman.command.HandlerService.AlterInbound:output_type -> xray.app.proxyman.command.AlterInboundResponse
|
||||
9, // 21: xray.app.proxyman.command.HandlerService.ListInbounds:output_type -> xray.app.proxyman.command.ListInboundsResponse
|
||||
11, // 22: xray.app.proxyman.command.HandlerService.GetInboundUsers:output_type -> xray.app.proxyman.command.GetInboundUserResponse
|
||||
12, // 23: xray.app.proxyman.command.HandlerService.GetInboundUsersCount:output_type -> xray.app.proxyman.command.GetInboundUsersCountResponse
|
||||
14, // 24: xray.app.proxyman.command.HandlerService.AddOutbound:output_type -> xray.app.proxyman.command.AddOutboundResponse
|
||||
16, // 25: xray.app.proxyman.command.HandlerService.RemoveOutbound:output_type -> xray.app.proxyman.command.RemoveOutboundResponse
|
||||
18, // 26: xray.app.proxyman.command.HandlerService.AlterOutbound:output_type -> xray.app.proxyman.command.AlterOutboundResponse
|
||||
20, // 27: xray.app.proxyman.command.HandlerService.ListOutbounds:output_type -> xray.app.proxyman.command.ListOutboundsResponse
|
||||
18, // [18:28] is the sub-list for method output_type
|
||||
8, // [8:18] is the sub-list for method input_type
|
||||
8, // [8:8] is the sub-list for extension type_name
|
||||
8, // [8:8] is the sub-list for extension extendee
|
||||
0, // [0:8] is the sub-list for field type_name
|
||||
18, // 0: xray.app.proxyman.command.AddUserOperation.user:type_name -> xray.common.protocol.User
|
||||
19, // 1: xray.app.proxyman.command.AddInboundRequest.inbound:type_name -> xray.core.InboundHandlerConfig
|
||||
20, // 2: xray.app.proxyman.command.AlterInboundRequest.operation:type_name -> xray.common.serial.TypedMessage
|
||||
18, // 3: xray.app.proxyman.command.GetInboundUserResponse.users:type_name -> xray.common.protocol.User
|
||||
21, // 4: xray.app.proxyman.command.AddOutboundRequest.outbound:type_name -> xray.core.OutboundHandlerConfig
|
||||
20, // 5: xray.app.proxyman.command.AlterOutboundRequest.operation:type_name -> xray.common.serial.TypedMessage
|
||||
2, // 6: xray.app.proxyman.command.HandlerService.AddInbound:input_type -> xray.app.proxyman.command.AddInboundRequest
|
||||
4, // 7: xray.app.proxyman.command.HandlerService.RemoveInbound:input_type -> xray.app.proxyman.command.RemoveInboundRequest
|
||||
6, // 8: xray.app.proxyman.command.HandlerService.AlterInbound:input_type -> xray.app.proxyman.command.AlterInboundRequest
|
||||
8, // 9: xray.app.proxyman.command.HandlerService.GetInboundUsers:input_type -> xray.app.proxyman.command.GetInboundUserRequest
|
||||
8, // 10: xray.app.proxyman.command.HandlerService.GetInboundUsersCount:input_type -> xray.app.proxyman.command.GetInboundUserRequest
|
||||
11, // 11: xray.app.proxyman.command.HandlerService.AddOutbound:input_type -> xray.app.proxyman.command.AddOutboundRequest
|
||||
13, // 12: xray.app.proxyman.command.HandlerService.RemoveOutbound:input_type -> xray.app.proxyman.command.RemoveOutboundRequest
|
||||
15, // 13: xray.app.proxyman.command.HandlerService.AlterOutbound:input_type -> xray.app.proxyman.command.AlterOutboundRequest
|
||||
3, // 14: xray.app.proxyman.command.HandlerService.AddInbound:output_type -> xray.app.proxyman.command.AddInboundResponse
|
||||
5, // 15: xray.app.proxyman.command.HandlerService.RemoveInbound:output_type -> xray.app.proxyman.command.RemoveInboundResponse
|
||||
7, // 16: xray.app.proxyman.command.HandlerService.AlterInbound:output_type -> xray.app.proxyman.command.AlterInboundResponse
|
||||
9, // 17: xray.app.proxyman.command.HandlerService.GetInboundUsers:output_type -> xray.app.proxyman.command.GetInboundUserResponse
|
||||
10, // 18: xray.app.proxyman.command.HandlerService.GetInboundUsersCount:output_type -> xray.app.proxyman.command.GetInboundUsersCountResponse
|
||||
12, // 19: xray.app.proxyman.command.HandlerService.AddOutbound:output_type -> xray.app.proxyman.command.AddOutboundResponse
|
||||
14, // 20: xray.app.proxyman.command.HandlerService.RemoveOutbound:output_type -> xray.app.proxyman.command.RemoveOutboundResponse
|
||||
16, // 21: xray.app.proxyman.command.HandlerService.AlterOutbound:output_type -> xray.app.proxyman.command.AlterOutboundResponse
|
||||
14, // [14:22] is the sub-list for method output_type
|
||||
6, // [6:14] is the sub-list for method input_type
|
||||
6, // [6:6] is the sub-list for extension type_name
|
||||
6, // [6:6] is the sub-list for extension extendee
|
||||
0, // [0:6] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_app_proxyman_command_command_proto_init() }
|
||||
@@ -1224,7 +1012,7 @@ func file_app_proxyman_command_command_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_app_proxyman_command_command_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 22,
|
||||
NumMessages: 18,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
@@ -37,14 +37,6 @@ message AlterInboundRequest {
|
||||
|
||||
message AlterInboundResponse {}
|
||||
|
||||
message ListInboundsRequest {
|
||||
bool isOnlyTags = 1;
|
||||
}
|
||||
|
||||
message ListInboundsResponse {
|
||||
repeated core.InboundHandlerConfig inbounds = 1;
|
||||
}
|
||||
|
||||
message GetInboundUserRequest {
|
||||
string tag = 1;
|
||||
string email = 2;
|
||||
@@ -77,12 +69,6 @@ message AlterOutboundRequest {
|
||||
|
||||
message AlterOutboundResponse {}
|
||||
|
||||
message ListOutboundsRequest {}
|
||||
|
||||
message ListOutboundsResponse {
|
||||
repeated core.OutboundHandlerConfig outbounds = 1;
|
||||
}
|
||||
|
||||
service HandlerService {
|
||||
rpc AddInbound(AddInboundRequest) returns (AddInboundResponse) {}
|
||||
|
||||
@@ -90,8 +76,6 @@ service HandlerService {
|
||||
|
||||
rpc AlterInbound(AlterInboundRequest) returns (AlterInboundResponse) {}
|
||||
|
||||
rpc ListInbounds(ListInboundsRequest) returns (ListInboundsResponse) {}
|
||||
|
||||
rpc GetInboundUsers(GetInboundUserRequest) returns (GetInboundUserResponse) {}
|
||||
|
||||
rpc GetInboundUsersCount(GetInboundUserRequest) returns (GetInboundUsersCountResponse) {}
|
||||
@@ -101,8 +85,6 @@ service HandlerService {
|
||||
rpc RemoveOutbound(RemoveOutboundRequest) returns (RemoveOutboundResponse) {}
|
||||
|
||||
rpc AlterOutbound(AlterOutboundRequest) returns (AlterOutboundResponse) {}
|
||||
|
||||
rpc ListOutbounds(ListOutboundsRequest) returns (ListOutboundsResponse) {}
|
||||
}
|
||||
|
||||
message Config {}
|
||||
|
@@ -22,13 +22,11 @@ const (
|
||||
HandlerService_AddInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AddInbound"
|
||||
HandlerService_RemoveInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/RemoveInbound"
|
||||
HandlerService_AlterInbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AlterInbound"
|
||||
HandlerService_ListInbounds_FullMethodName = "/xray.app.proxyman.command.HandlerService/ListInbounds"
|
||||
HandlerService_GetInboundUsers_FullMethodName = "/xray.app.proxyman.command.HandlerService/GetInboundUsers"
|
||||
HandlerService_GetInboundUsersCount_FullMethodName = "/xray.app.proxyman.command.HandlerService/GetInboundUsersCount"
|
||||
HandlerService_AddOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AddOutbound"
|
||||
HandlerService_RemoveOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/RemoveOutbound"
|
||||
HandlerService_AlterOutbound_FullMethodName = "/xray.app.proxyman.command.HandlerService/AlterOutbound"
|
||||
HandlerService_ListOutbounds_FullMethodName = "/xray.app.proxyman.command.HandlerService/ListOutbounds"
|
||||
)
|
||||
|
||||
// HandlerServiceClient is the client API for HandlerService service.
|
||||
@@ -38,13 +36,11 @@ type HandlerServiceClient interface {
|
||||
AddInbound(ctx context.Context, in *AddInboundRequest, opts ...grpc.CallOption) (*AddInboundResponse, error)
|
||||
RemoveInbound(ctx context.Context, in *RemoveInboundRequest, opts ...grpc.CallOption) (*RemoveInboundResponse, error)
|
||||
AlterInbound(ctx context.Context, in *AlterInboundRequest, opts ...grpc.CallOption) (*AlterInboundResponse, error)
|
||||
ListInbounds(ctx context.Context, in *ListInboundsRequest, opts ...grpc.CallOption) (*ListInboundsResponse, error)
|
||||
GetInboundUsers(ctx context.Context, in *GetInboundUserRequest, opts ...grpc.CallOption) (*GetInboundUserResponse, error)
|
||||
GetInboundUsersCount(ctx context.Context, in *GetInboundUserRequest, opts ...grpc.CallOption) (*GetInboundUsersCountResponse, error)
|
||||
AddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error)
|
||||
RemoveOutbound(ctx context.Context, in *RemoveOutboundRequest, opts ...grpc.CallOption) (*RemoveOutboundResponse, error)
|
||||
AlterOutbound(ctx context.Context, in *AlterOutboundRequest, opts ...grpc.CallOption) (*AlterOutboundResponse, error)
|
||||
ListOutbounds(ctx context.Context, in *ListOutboundsRequest, opts ...grpc.CallOption) (*ListOutboundsResponse, error)
|
||||
}
|
||||
|
||||
type handlerServiceClient struct {
|
||||
@@ -85,16 +81,6 @@ func (c *handlerServiceClient) AlterInbound(ctx context.Context, in *AlterInboun
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *handlerServiceClient) ListInbounds(ctx context.Context, in *ListInboundsRequest, opts ...grpc.CallOption) (*ListInboundsResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListInboundsResponse)
|
||||
err := c.cc.Invoke(ctx, HandlerService_ListInbounds_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *handlerServiceClient) GetInboundUsers(ctx context.Context, in *GetInboundUserRequest, opts ...grpc.CallOption) (*GetInboundUserResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetInboundUserResponse)
|
||||
@@ -145,16 +131,6 @@ func (c *handlerServiceClient) AlterOutbound(ctx context.Context, in *AlterOutbo
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *handlerServiceClient) ListOutbounds(ctx context.Context, in *ListOutboundsRequest, opts ...grpc.CallOption) (*ListOutboundsResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListOutboundsResponse)
|
||||
err := c.cc.Invoke(ctx, HandlerService_ListOutbounds_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// HandlerServiceServer is the server API for HandlerService service.
|
||||
// All implementations must embed UnimplementedHandlerServiceServer
|
||||
// for forward compatibility.
|
||||
@@ -162,13 +138,11 @@ type HandlerServiceServer interface {
|
||||
AddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error)
|
||||
RemoveInbound(context.Context, *RemoveInboundRequest) (*RemoveInboundResponse, error)
|
||||
AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error)
|
||||
ListInbounds(context.Context, *ListInboundsRequest) (*ListInboundsResponse, error)
|
||||
GetInboundUsers(context.Context, *GetInboundUserRequest) (*GetInboundUserResponse, error)
|
||||
GetInboundUsersCount(context.Context, *GetInboundUserRequest) (*GetInboundUsersCountResponse, error)
|
||||
AddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error)
|
||||
RemoveOutbound(context.Context, *RemoveOutboundRequest) (*RemoveOutboundResponse, error)
|
||||
AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error)
|
||||
ListOutbounds(context.Context, *ListOutboundsRequest) (*ListOutboundsResponse, error)
|
||||
mustEmbedUnimplementedHandlerServiceServer()
|
||||
}
|
||||
|
||||
@@ -188,9 +162,6 @@ func (UnimplementedHandlerServiceServer) RemoveInbound(context.Context, *RemoveI
|
||||
func (UnimplementedHandlerServiceServer) AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AlterInbound not implemented")
|
||||
}
|
||||
func (UnimplementedHandlerServiceServer) ListInbounds(context.Context, *ListInboundsRequest) (*ListInboundsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListInbounds not implemented")
|
||||
}
|
||||
func (UnimplementedHandlerServiceServer) GetInboundUsers(context.Context, *GetInboundUserRequest) (*GetInboundUserResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetInboundUsers not implemented")
|
||||
}
|
||||
@@ -206,9 +177,6 @@ func (UnimplementedHandlerServiceServer) RemoveOutbound(context.Context, *Remove
|
||||
func (UnimplementedHandlerServiceServer) AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AlterOutbound not implemented")
|
||||
}
|
||||
func (UnimplementedHandlerServiceServer) ListOutbounds(context.Context, *ListOutboundsRequest) (*ListOutboundsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListOutbounds not implemented")
|
||||
}
|
||||
func (UnimplementedHandlerServiceServer) mustEmbedUnimplementedHandlerServiceServer() {}
|
||||
func (UnimplementedHandlerServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
@@ -284,24 +252,6 @@ func _HandlerService_AlterInbound_Handler(srv interface{}, ctx context.Context,
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _HandlerService_ListInbounds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListInboundsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(HandlerServiceServer).ListInbounds(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: HandlerService_ListInbounds_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(HandlerServiceServer).ListInbounds(ctx, req.(*ListInboundsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _HandlerService_GetInboundUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetInboundUserRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@@ -392,24 +342,6 @@ func _HandlerService_AlterOutbound_Handler(srv interface{}, ctx context.Context,
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _HandlerService_ListOutbounds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListOutboundsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(HandlerServiceServer).ListOutbounds(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: HandlerService_ListOutbounds_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(HandlerServiceServer).ListOutbounds(ctx, req.(*ListOutboundsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// HandlerService_ServiceDesc is the grpc.ServiceDesc for HandlerService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@@ -429,10 +361,6 @@ var HandlerService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "AlterInbound",
|
||||
Handler: _HandlerService_AlterInbound_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListInbounds",
|
||||
Handler: _HandlerService_ListInbounds_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetInboundUsers",
|
||||
Handler: _HandlerService_GetInboundUsers_Handler,
|
||||
@@ -453,10 +381,6 @@ var HandlerService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "AlterOutbound",
|
||||
Handler: _HandlerService_AlterOutbound_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListOutbounds",
|
||||
Handler: _HandlerService_ListOutbounds_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "app/proxyman/command/command.proto",
|
||||
|
@@ -190,8 +190,9 @@ type SniffingConfig struct {
|
||||
// Whether should only try to sniff metadata without waiting for client input.
|
||||
// Can be used to support SMTP like protocol where server send the first
|
||||
// message.
|
||||
MetadataOnly bool `protobuf:"varint,4,opt,name=metadata_only,json=metadataOnly,proto3" json:"metadata_only,omitempty"`
|
||||
RouteOnly bool `protobuf:"varint,5,opt,name=route_only,json=routeOnly,proto3" json:"route_only,omitempty"`
|
||||
MetadataOnly bool `protobuf:"varint,4,opt,name=metadata_only,json=metadataOnly,proto3" json:"metadata_only,omitempty"`
|
||||
RouteOnly bool `protobuf:"varint,5,opt,name=route_only,json=routeOnly,proto3" json:"route_only,omitempty"`
|
||||
Timeout int64 `protobuf:"varint,6,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SniffingConfig) Reset() {
|
||||
@@ -259,6 +260,13 @@ func (x *SniffingConfig) GetRouteOnly() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *SniffingConfig) GetTimeout() int64 {
|
||||
if x != nil {
|
||||
return x.Timeout
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type ReceiverConfig struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -725,7 +733,7 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
|
||||
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12,
|
||||
0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52,
|
||||
0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72,
|
||||
0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0xcc, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69,
|
||||
0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0xe6, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69,
|
||||
0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62,
|
||||
0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
|
||||
@@ -738,85 +746,87 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
|
||||
0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
|
||||
0x61, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f,
|
||||
0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x4f, 0x6e, 0x6c, 0x79, 0x22, 0xbd, 0x03, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
|
||||
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f,
|
||||
0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72,
|
||||
0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12,
|
||||
0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
|
||||
0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69,
|
||||
0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4e, 0x0a, 0x0f,
|
||||
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
|
||||
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
|
||||
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
|
||||
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74,
|
||||
0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x1c,
|
||||
0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
|
||||
0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01,
|
||||
0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69,
|
||||
0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e,
|
||||
0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e,
|
||||
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e,
|
||||
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04,
|
||||
0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
|
||||
0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a,
|
||||
0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12,
|
||||
0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74,
|
||||
0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e,
|
||||
0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x10, 0x72, 0x65,
|
||||
0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47,
|
||||
0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65,
|
||||
0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53,
|
||||
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f,
|
||||
0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xcb, 0x02, 0x0a, 0x0c, 0x53, 0x65,
|
||||
0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x03, 0x76, 0x69,
|
||||
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f,
|
||||
0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72,
|
||||
0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
|
||||
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72,
|
||||
0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61,
|
||||
0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e, 0x70, 0x72, 0x6f,
|
||||
0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
|
||||
0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65,
|
||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70,
|
||||
0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78,
|
||||
0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69,
|
||||
0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08,
|
||||
0x76, 0x69, 0x61, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||
0x76, 0x69, 0x61, 0x43, 0x69, 0x64, 0x72, 0x22, 0xa4, 0x01, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74,
|
||||
0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63,
|
||||
0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x63,
|
||||
0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75,
|
||||
0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x05, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72,
|
||||
0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x78,
|
||||
0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x42, 0x55,
|
||||
0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d,
|
||||
0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
|
||||
0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f,
|
||||
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18,
|
||||
0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0xbd,
|
||||
0x03, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52,
|
||||
0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73,
|
||||
0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72,
|
||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x56,
|
||||
0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72,
|
||||
0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e,
|
||||
0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||
0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74,
|
||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d,
|
||||
0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,
|
||||
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65,
|
||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76,
|
||||
0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69,
|
||||
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65,
|
||||
0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73,
|
||||
0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66,
|
||||
0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x07, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67,
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67,
|
||||
0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0xc0,
|
||||
0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65,
|
||||
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63,
|
||||
0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72,
|
||||
0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73,
|
||||
0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
|
||||
0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x22, 0xcb, 0x02, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
|
||||
0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03,
|
||||
0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65,
|
||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
|
||||
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74,
|
||||
0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
||||
0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65,
|
||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e,
|
||||
0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65,
|
||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x69, 0x61, 0x5f, 0x63, 0x69,
|
||||
0x64, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x69, 0x61, 0x43, 0x69, 0x64,
|
||||
0x72, 0x22, 0xa4, 0x01, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69,
|
||||
0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62,
|
||||
0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63,
|
||||
0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72,
|
||||
0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63,
|
||||
0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x78,
|
||||
0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28,
|
||||
0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34,
|
||||
0x33, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f,
|
||||
0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
|
||||
0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61,
|
||||
0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@@ -55,6 +55,8 @@ message SniffingConfig {
|
||||
bool metadata_only = 4;
|
||||
|
||||
bool route_only = 5;
|
||||
|
||||
int64 timeout = 6;
|
||||
}
|
||||
|
||||
message ReceiverConfig {
|
||||
|
@@ -9,13 +9,11 @@ import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/policy"
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {
|
||||
@@ -44,12 +42,10 @@ func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter)
|
||||
}
|
||||
|
||||
type AlwaysOnInboundHandler struct {
|
||||
proxyConfig interface{}
|
||||
receiverConfig *proxyman.ReceiverConfig
|
||||
proxy proxy.Inbound
|
||||
workers []worker
|
||||
mux *mux.Server
|
||||
tag string
|
||||
proxy proxy.Inbound
|
||||
workers []worker
|
||||
mux *mux.Server
|
||||
tag string
|
||||
}
|
||||
|
||||
func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*AlwaysOnInboundHandler, error) {
|
||||
@@ -63,11 +59,9 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
||||
}
|
||||
|
||||
h := &AlwaysOnInboundHandler{
|
||||
receiverConfig: receiverConfig,
|
||||
proxyConfig: proxyConfig,
|
||||
proxy: p,
|
||||
mux: mux.NewServer(ctx),
|
||||
tag: tag,
|
||||
proxy: p,
|
||||
mux: mux.NewServer(ctx),
|
||||
tag: tag,
|
||||
}
|
||||
|
||||
uplinkCounter, downlinkCounter := getStatCounter(core.MustFromContext(ctx), tag)
|
||||
@@ -193,16 +187,3 @@ func (h *AlwaysOnInboundHandler) Tag() string {
|
||||
func (h *AlwaysOnInboundHandler) GetInbound() proxy.Inbound {
|
||||
return h.proxy
|
||||
}
|
||||
|
||||
// ReceiverSettings implements inbound.Handler.
|
||||
func (h *AlwaysOnInboundHandler) ReceiverSettings() *serial.TypedMessage {
|
||||
return serial.ToTypedMessage(h.receiverConfig)
|
||||
}
|
||||
|
||||
// ProxySettings implements inbound.Handler.
|
||||
func (h *AlwaysOnInboundHandler) ProxySettings() *serial.TypedMessage {
|
||||
if v, ok := h.proxyConfig.(proto.Message); ok {
|
||||
return serial.ToTypedMessage(v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -10,12 +10,10 @@ import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type DynamicInboundHandler struct {
|
||||
@@ -207,16 +205,3 @@ func (h *DynamicInboundHandler) GetRandomInboundProxy() (interface{}, net.Port,
|
||||
func (h *DynamicInboundHandler) Tag() string {
|
||||
return h.tag
|
||||
}
|
||||
|
||||
// ReceiverSettings implements inbound.Handler.
|
||||
func (h *DynamicInboundHandler) ReceiverSettings() *serial.TypedMessage {
|
||||
return serial.ToTypedMessage(h.receiverConfig)
|
||||
}
|
||||
|
||||
// ProxySettings implements inbound.Handler.
|
||||
func (h *DynamicInboundHandler) ProxySettings() *serial.TypedMessage {
|
||||
if v, ok := h.proxyConfig.(proto.Message); ok {
|
||||
return serial.ToTypedMessage(v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -89,21 +89,6 @@ func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
|
||||
return common.ErrNoClue
|
||||
}
|
||||
|
||||
// ListHandlers implements inbound.Manager.
|
||||
func (m *Manager) ListHandlers(ctx context.Context) []inbound.Handler {
|
||||
m.access.RLock()
|
||||
defer m.access.RUnlock()
|
||||
|
||||
var response []inbound.Handler
|
||||
copy(m.untaggedHandler, response)
|
||||
|
||||
for _, v := range m.taggedHandlers {
|
||||
response = append(response, v)
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
// Start implements common.Runnable.
|
||||
func (m *Manager) Start() error {
|
||||
m.access.Lock()
|
||||
|
@@ -103,6 +103,7 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
||||
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
||||
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
||||
content.SniffingRequest.Timeout = time.Duration(w.sniffingConfig.Timeout) * time.Millisecond
|
||||
}
|
||||
ctx = session.ContextWithContent(ctx, content)
|
||||
|
||||
@@ -324,9 +325,9 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
||||
if w.sniffingConfig != nil {
|
||||
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
|
||||
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
||||
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
||||
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
||||
content.SniffingRequest.Timeout = time.Duration(w.sniffingConfig.Timeout) * time.Millisecond
|
||||
}
|
||||
ctx = session.ContextWithContent(ctx, content)
|
||||
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
|
||||
@@ -478,6 +479,7 @@ func (w *dsWorker) callback(conn stat.Connection) {
|
||||
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
||||
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
||||
content.SniffingRequest.Timeout = time.Duration(w.sniffingConfig.Timeout) * time.Millisecond
|
||||
}
|
||||
ctx = session.ContextWithContent(ctx, content)
|
||||
|
||||
|
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/net/cnc"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
@@ -28,7 +27,6 @@ import (
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
"github.com/xtls/xray-core/transport/pipe"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {
|
||||
@@ -61,7 +59,6 @@ type Handler struct {
|
||||
tag string
|
||||
senderSettings *proxyman.SenderConfig
|
||||
streamSettings *internet.MemoryStreamConfig
|
||||
proxyConfig proto.Message
|
||||
proxy proxy.Outbound
|
||||
outboundManager outbound.Manager
|
||||
mux *mux.ClientManager
|
||||
@@ -104,7 +101,6 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.proxyConfig = proxyConfig
|
||||
|
||||
rawProxyHandler, err := common.CreateObject(ctx, proxyConfig)
|
||||
if err != nil {
|
||||
@@ -245,9 +241,7 @@ func (h *Handler) DestIpAddress() net.IP {
|
||||
// Dial implements internet.Dialer.
|
||||
func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connection, error) {
|
||||
if h.senderSettings != nil {
|
||||
|
||||
if h.senderSettings.ProxySettings.HasTag() {
|
||||
|
||||
tag := h.senderSettings.ProxySettings.Tag
|
||||
handler := h.outboundManager.GetHandler(tag)
|
||||
if handler != nil {
|
||||
@@ -276,44 +270,22 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
||||
}
|
||||
|
||||
if h.senderSettings.Via != nil {
|
||||
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
var domain string
|
||||
addr := h.senderSettings.Via.AsAddress()
|
||||
domain = h.senderSettings.Via.GetDomain()
|
||||
switch {
|
||||
case h.senderSettings.ViaCidr != "":
|
||||
ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr)
|
||||
|
||||
case domain == "origin":
|
||||
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if inbound.Conn != nil {
|
||||
if h.senderSettings.ViaCidr == "" {
|
||||
if h.senderSettings.Via.AsAddress().Family().IsDomain() && h.senderSettings.Via.AsAddress().Domain() == "origin" {
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
origin, _, err := net.SplitHostPort(inbound.Conn.LocalAddr().String())
|
||||
if err == nil {
|
||||
ob.Gateway = net.ParseAddress(origin)
|
||||
errors.LogDebug(ctx, "use receive package ip as snedthrough: ", origin)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ob.Gateway = h.senderSettings.Via.AsAddress()
|
||||
}
|
||||
case domain == "srcip":
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if inbound.Conn != nil {
|
||||
clientaddr, _, err := net.SplitHostPort(inbound.Conn.RemoteAddr().String())
|
||||
if err == nil {
|
||||
ob.Gateway = net.ParseAddress(clientaddr)
|
||||
errors.LogDebug(ctx, "use client src ip as snedthrough: ", clientaddr)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//case addr.Family().IsDomain():
|
||||
default:
|
||||
ob.Gateway = addr
|
||||
|
||||
} else { //Get a random address.
|
||||
ob.Gateway = ParseRandomIPv6(h.senderSettings.Via.AsAddress(), h.senderSettings.ViaCidr)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,35 +325,23 @@ func (h *Handler) Start() error {
|
||||
// Close implements common.Closable.
|
||||
func (h *Handler) Close() error {
|
||||
common.Close(h.mux)
|
||||
common.Close(h.proxy)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SenderSettings implements outbound.Handler.
|
||||
func (h *Handler) SenderSettings() *serial.TypedMessage {
|
||||
return serial.ToTypedMessage(h.senderSettings)
|
||||
}
|
||||
|
||||
// ProxySettings implements outbound.Handler.
|
||||
func (h *Handler) ProxySettings() *serial.TypedMessage {
|
||||
return serial.ToTypedMessage(h.proxyConfig)
|
||||
}
|
||||
|
||||
func ParseRandomIP(addr net.Address, prefix string) net.Address {
|
||||
|
||||
_, ipnet, _ := gonet.ParseCIDR(addr.IP().String() + "/" + prefix)
|
||||
|
||||
ones, bits := ipnet.Mask.Size()
|
||||
subnetSize := new(big.Int).Lsh(big.NewInt(1), uint(bits-ones))
|
||||
|
||||
rnd, _ := rand.Int(rand.Reader, subnetSize)
|
||||
|
||||
startInt := new(big.Int).SetBytes(ipnet.IP)
|
||||
rndInt := new(big.Int).Add(startInt, rnd)
|
||||
|
||||
rndBytes := rndInt.Bytes()
|
||||
padded := make([]byte, len(ipnet.IP))
|
||||
copy(padded[len(padded)-len(rndBytes):], rndBytes)
|
||||
|
||||
return net.ParseAddress(gonet.IP(padded).String())
|
||||
func ParseRandomIPv6(address net.Address, prefix string) net.Address {
|
||||
_, network, _ := gonet.ParseCIDR(address.IP().String() + "/" + prefix)
|
||||
|
||||
maskSize, totalBits := network.Mask.Size()
|
||||
subnetSize := big.NewInt(1).Lsh(big.NewInt(1), uint(totalBits-maskSize))
|
||||
|
||||
// random
|
||||
randomBigInt, _ := rand.Int(rand.Reader, subnetSize)
|
||||
|
||||
startIPBigInt := big.NewInt(0).SetBytes(network.IP.To16())
|
||||
randomIPBigInt := big.NewInt(0).Add(startIPBigInt, randomBigInt)
|
||||
|
||||
randomIPBytes := randomIPBigInt.Bytes()
|
||||
randomIPBytes = append(make([]byte, 16-len(randomIPBytes)), randomIPBytes...)
|
||||
|
||||
return net.ParseAddress(gonet.IP(randomIPBytes).String())
|
||||
}
|
||||
|
@@ -145,21 +145,6 @@ func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListHandlers implements outbound.Manager.
|
||||
func (m *Manager) ListHandlers(ctx context.Context) []outbound.Handler {
|
||||
m.access.RLock()
|
||||
defer m.access.RUnlock()
|
||||
|
||||
var response []outbound.Handler
|
||||
copy(m.untaggedHandlers, response)
|
||||
|
||||
for _, v := range m.taggedHandler {
|
||||
response = append(response, v)
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
// Select implements outbound.HandlerSelector.
|
||||
func (m *Manager) Select(selectors []string) []string {
|
||||
|
||||
|
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
@@ -112,16 +111,6 @@ func (o *Outbound) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SenderSettings implements outbound.Handler.
|
||||
func (o *Outbound) SenderSettings() *serial.TypedMessage {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProxySettings implements outbound.Handler.
|
||||
func (o *Outbound) ProxySettings() *serial.TypedMessage {
|
||||
return nil
|
||||
}
|
||||
|
||||
type StaticMuxPicker struct {
|
||||
access sync.Mutex
|
||||
workers []*PortalWorker
|
||||
|
@@ -119,7 +119,7 @@ type MultiGeoIPMatcher struct {
|
||||
func NewMultiGeoIPMatcher(geoips []*GeoIP, onSource bool) (*MultiGeoIPMatcher, error) {
|
||||
var matchers []*GeoIPMatcher
|
||||
for _, geoip := range geoips {
|
||||
matcher, err := GlobalGeoIPContainer.Add(geoip)
|
||||
matcher, err := globalGeoIPContainer.Add(geoip)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -115,30 +115,4 @@ func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
var GlobalGeoIPContainer GeoIPMatcherContainer
|
||||
|
||||
func MatchIPs(matchers []*GeoIPMatcher, ips []net.IP, reverse bool) []net.IP {
|
||||
if len(matchers) == 0 {
|
||||
panic("GeoIP matchers should not be empty to avoid ambiguity")
|
||||
}
|
||||
newIPs := make([]net.IP, 0, len(ips))
|
||||
var isFound bool
|
||||
for _, ip := range ips {
|
||||
isFound = false
|
||||
for _, matcher := range matchers {
|
||||
if matcher.Match(ip) {
|
||||
isFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if isFound && !reverse {
|
||||
newIPs = append(newIPs, ip)
|
||||
continue
|
||||
}
|
||||
if !isFound && reverse {
|
||||
newIPs = append(newIPs, ip)
|
||||
continue
|
||||
}
|
||||
}
|
||||
return newIPs
|
||||
}
|
||||
var globalGeoIPContainer GeoIPMatcherContainer
|
||||
|
@@ -177,7 +177,7 @@ func TestIPOnDemand(t *testing.T) {
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
}).Return([]net.IP{{192, 168, 0, 1}}, uint32(600), nil).AnyTimes()
|
||||
}).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
|
||||
|
||||
r := new(Router)
|
||||
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
|
||||
@@ -222,7 +222,7 @@ func TestIPIfNonMatchDomain(t *testing.T) {
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
}).Return([]net.IP{{192, 168, 0, 1}}, uint32(600), nil).AnyTimes()
|
||||
}).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
|
||||
|
||||
r := new(Router)
|
||||
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
|
||||
|
@@ -12,8 +12,6 @@ import (
|
||||
"github.com/xtls/xray-core/core"
|
||||
feature_stats "github.com/xtls/xray-core/features/stats"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// statsServer is an implementation of StatsService.
|
||||
@@ -32,7 +30,7 @@ func NewStatsServer(manager feature_stats.Manager) StatsServiceServer {
|
||||
func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {
|
||||
c := s.stats.GetCounter(request.Name)
|
||||
if c == nil {
|
||||
return nil, status.Error(codes.NotFound, request.Name+" not found.")
|
||||
return nil, errors.New(request.Name, " not found.")
|
||||
}
|
||||
var value int64
|
||||
if request.Reset_ {
|
||||
@@ -51,7 +49,7 @@ func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*
|
||||
func (s *statsServer) GetStatsOnline(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {
|
||||
c := s.stats.GetOnlineMap(request.Name)
|
||||
if c == nil {
|
||||
return nil, status.Error(codes.NotFound, request.Name+" not found.")
|
||||
return nil, errors.New(request.Name, " not found.")
|
||||
}
|
||||
value := int64(c.Count())
|
||||
return &GetStatsResponse{
|
||||
@@ -66,7 +64,7 @@ func (s *statsServer) GetStatsOnlineIpList(ctx context.Context, request *GetStat
|
||||
c := s.stats.GetOnlineMap(request.Name)
|
||||
|
||||
if c == nil {
|
||||
return nil, status.Error(codes.NotFound, request.Name+" not found.")
|
||||
return nil, errors.New(request.Name, " not found.")
|
||||
}
|
||||
|
||||
ips := make(map[string]int64)
|
||||
|
@@ -40,11 +40,11 @@ func (c *OnlineMap) AddIP(ip string) {
|
||||
if ip == "127.0.0.1" {
|
||||
return
|
||||
}
|
||||
c.access.Lock()
|
||||
if _, ok := list[ip]; !ok {
|
||||
c.access.Lock()
|
||||
list[ip] = time.Now()
|
||||
c.access.Unlock()
|
||||
}
|
||||
c.access.Unlock()
|
||||
if time.Since(c.lastCleanup) > c.cleanupPeriod {
|
||||
list = c.RemoveExpiredIPs(list)
|
||||
c.lastCleanup = time.Now()
|
||||
|
@@ -13,19 +13,8 @@ const (
|
||||
Size = 8192
|
||||
)
|
||||
|
||||
var zero = [Size * 10]byte{0}
|
||||
|
||||
var pool = bytespool.GetPool(Size)
|
||||
|
||||
// ownership represents the data owner of the buffer.
|
||||
type ownership uint8
|
||||
|
||||
const (
|
||||
managed ownership = iota
|
||||
unmanaged
|
||||
bytespools
|
||||
)
|
||||
|
||||
// Buffer is a recyclable allocation of a byte array. Buffer.Release() recycles
|
||||
// the buffer into an internal buffer pool, in order to recreate a buffer more
|
||||
// quickly.
|
||||
@@ -33,11 +22,11 @@ type Buffer struct {
|
||||
v []byte
|
||||
start int32
|
||||
end int32
|
||||
ownership ownership
|
||||
unmanaged bool
|
||||
UDP *net.Destination
|
||||
}
|
||||
|
||||
// New creates a Buffer with 0 length and 8K capacity, managed.
|
||||
// New creates a Buffer with 0 length and 8K capacity.
|
||||
func New() *Buffer {
|
||||
buf := pool.Get().([]byte)
|
||||
if cap(buf) >= Size {
|
||||
@@ -51,7 +40,7 @@ func New() *Buffer {
|
||||
}
|
||||
}
|
||||
|
||||
// NewExisted creates a standard size Buffer with an existed bytearray, managed.
|
||||
// NewExisted creates a managed, standard size Buffer with an existed bytearray
|
||||
func NewExisted(b []byte) *Buffer {
|
||||
if cap(b) < Size {
|
||||
panic("Invalid buffer")
|
||||
@@ -68,16 +57,16 @@ func NewExisted(b []byte) *Buffer {
|
||||
}
|
||||
}
|
||||
|
||||
// FromBytes creates a Buffer with an existed bytearray, unmanaged.
|
||||
// FromBytes creates a Buffer with an existed bytearray
|
||||
func FromBytes(b []byte) *Buffer {
|
||||
return &Buffer{
|
||||
v: b,
|
||||
end: int32(len(b)),
|
||||
ownership: unmanaged,
|
||||
unmanaged: true,
|
||||
}
|
||||
}
|
||||
|
||||
// StackNew creates a new Buffer object on stack, managed.
|
||||
// StackNew creates a new Buffer object on stack.
|
||||
// This method is for buffers that is released in the same function.
|
||||
func StackNew() Buffer {
|
||||
buf := pool.Get().([]byte)
|
||||
@@ -92,17 +81,9 @@ func StackNew() Buffer {
|
||||
}
|
||||
}
|
||||
|
||||
// NewWithSize creates a Buffer with 0 length and capacity with at least the given size, bytespool's.
|
||||
func NewWithSize(size int32) *Buffer {
|
||||
return &Buffer{
|
||||
v: bytespool.Alloc(size),
|
||||
ownership: bytespools,
|
||||
}
|
||||
}
|
||||
|
||||
// Release recycles the buffer into an internal buffer pool.
|
||||
func (b *Buffer) Release() {
|
||||
if b == nil || b.v == nil || b.ownership == unmanaged {
|
||||
if b == nil || b.v == nil || b.unmanaged {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -110,13 +91,8 @@ func (b *Buffer) Release() {
|
||||
b.v = nil
|
||||
b.Clear()
|
||||
|
||||
switch b.ownership {
|
||||
case managed:
|
||||
if cap(p) == Size {
|
||||
pool.Put(p)
|
||||
}
|
||||
case bytespools:
|
||||
bytespool.Free(p)
|
||||
if cap(p) == Size {
|
||||
pool.Put(p)
|
||||
}
|
||||
b.UDP = nil
|
||||
}
|
||||
@@ -152,7 +128,6 @@ func (b *Buffer) Extend(n int32) []byte {
|
||||
}
|
||||
ext := b.v[b.end:end]
|
||||
b.end = end
|
||||
copy(ext, zero[:])
|
||||
return ext
|
||||
}
|
||||
|
||||
@@ -201,7 +176,6 @@ func (b *Buffer) Check() {
|
||||
|
||||
// Resize cuts the buffer at the given position.
|
||||
func (b *Buffer) Resize(from, to int32) {
|
||||
oldEnd := b.end
|
||||
if from < 0 {
|
||||
from += b.Len()
|
||||
}
|
||||
@@ -214,9 +188,6 @@ func (b *Buffer) Resize(from, to int32) {
|
||||
b.end = b.start + to
|
||||
b.start += from
|
||||
b.Check()
|
||||
if b.end > oldEnd {
|
||||
copy(b.v[oldEnd:b.end], zero[:])
|
||||
}
|
||||
}
|
||||
|
||||
// Advance cuts the buffer at the given position.
|
||||
@@ -244,6 +215,13 @@ func (b *Buffer) Cap() int32 {
|
||||
return int32(len(b.v))
|
||||
}
|
||||
|
||||
// NewWithSize creates a Buffer with 0 length and capacity with at least the given size.
|
||||
func NewWithSize(size int32) *Buffer {
|
||||
return &Buffer{
|
||||
v: bytespool.Alloc(size),
|
||||
}
|
||||
}
|
||||
|
||||
// IsEmpty returns true if the buffer is empty.
|
||||
func (b *Buffer) IsEmpty() bool {
|
||||
return b.Len() == 0
|
||||
|
@@ -1,15 +1,2 @@
|
||||
// Package crypto provides common crypto libraries for Xray.
|
||||
package crypto // import "github.com/xtls/xray-core/common/crypto"
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func RandBetween(from int64, to int64) int64 {
|
||||
if from == to {
|
||||
return from
|
||||
}
|
||||
bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from))
|
||||
return from + bigInt.Int64()
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -37,12 +36,12 @@ func AllEqual(expected error, actual error) bool {
|
||||
return false
|
||||
}
|
||||
for _, err := range errs {
|
||||
if !errors.Is(err, expected) {
|
||||
if err != expected {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
return errors.Is(errs, expected)
|
||||
return errs == expected
|
||||
}
|
||||
}
|
||||
|
@@ -120,7 +120,7 @@ func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.Bu
|
||||
func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||
// deep-clone outbounds because it is going to be mutated concurrently
|
||||
// (Target and OriginalTarget)
|
||||
ctx = session.ContextCloneOutboundsAndContent(ctx)
|
||||
ctx = session.ContextCloneOutbounds(ctx)
|
||||
errors.LogInfo(ctx, "received request for ", meta.Target)
|
||||
{
|
||||
msg := &log.AccessMessage{
|
||||
|
@@ -1,14 +1,2 @@
|
||||
// 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"
|
||||
|
||||
import "time"
|
||||
|
||||
// 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.
|
||||
const ConnIdleTimeout = 300 * time.Second
|
||||
|
||||
// consistent with quic-go
|
||||
const QuicgoH3KeepAlivePeriod = 10 * time.Second
|
||||
|
||||
// consistent with chrome
|
||||
const ChromeH2KeepAlivePeriod = 45 * time.Second
|
||||
|
@@ -3,7 +3,6 @@ package filesystem
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/platform"
|
||||
@@ -29,13 +28,6 @@ func ReadAsset(file string) ([]byte, error) {
|
||||
return ReadFile(platform.GetAssetLocation(file))
|
||||
}
|
||||
|
||||
func ReadCert(file string) ([]byte, error) {
|
||||
if filepath.IsAbs(file) {
|
||||
return ReadFile(file)
|
||||
}
|
||||
return ReadFile(platform.GetCertLocation(file))
|
||||
}
|
||||
|
||||
func CopyFile(dst string, src string) error {
|
||||
bytes, err := ReadFile(src)
|
||||
if err != nil {
|
||||
|
@@ -21,7 +21,7 @@ func GetToolLocation(file string) string {
|
||||
return filepath.Join(toolPath, file)
|
||||
}
|
||||
|
||||
// GetAssetLocation searches for `file` in the env dir, the executable dir, and certain locations
|
||||
// GetAssetLocation searches for `file` in certain locations
|
||||
func GetAssetLocation(file string) string {
|
||||
assetPath := NewEnvFlag(AssetLocation).GetValue(getExecutableDir)
|
||||
defPath := filepath.Join(assetPath, file)
|
||||
@@ -42,9 +42,3 @@ func GetAssetLocation(file string) string {
|
||||
// asset not found, let the caller throw out the error
|
||||
return defPath
|
||||
}
|
||||
|
||||
// GetCertLocation searches for `file` in the env dir and the executable dir
|
||||
func GetCertLocation(file string) string {
|
||||
certPath := NewEnvFlag(CertLocation).GetValue(getExecutableDir)
|
||||
return filepath.Join(certPath, file)
|
||||
}
|
||||
|
@@ -13,7 +13,6 @@ const (
|
||||
ConfdirLocation = "xray.location.confdir"
|
||||
ToolLocation = "xray.location.tool"
|
||||
AssetLocation = "xray.location.asset"
|
||||
CertLocation = "xray.location.cert"
|
||||
|
||||
UseReadV = "xray.buf.readv"
|
||||
UseFreedomSplice = "xray.buf.splice"
|
||||
|
@@ -19,14 +19,8 @@ func GetToolLocation(file string) string {
|
||||
return filepath.Join(toolPath, file+".exe")
|
||||
}
|
||||
|
||||
// GetAssetLocation searches for `file` in the env dir and the executable dir
|
||||
// GetAssetLocation searches for `file` in the executable dir
|
||||
func GetAssetLocation(file string) string {
|
||||
assetPath := NewEnvFlag(AssetLocation).GetValue(getExecutableDir)
|
||||
return filepath.Join(assetPath, file)
|
||||
}
|
||||
|
||||
// GetCertLocation searches for `file` in the env dir and the executable dir
|
||||
func GetCertLocation(file string) string {
|
||||
certPath := NewEnvFlag(CertLocation).GetValue(getExecutableDir)
|
||||
return filepath.Join(certPath, file)
|
||||
}
|
||||
|
@@ -63,7 +63,7 @@ func SniffHTTP(b []byte, c context.Context) (*SniffHeader, error) {
|
||||
ShouldSniffAttr := true
|
||||
// If content.Attributes have information, that means it comes from HTTP inbound PlainHTTP mode.
|
||||
// It will set attributes, so skip it.
|
||||
if content == nil || len(content.Attributes) != 0 {
|
||||
if content == nil || content.AttributeLen() != 0 {
|
||||
ShouldSniffAttr = false
|
||||
}
|
||||
if err := beginWithHTTPMethod(b); err != nil {
|
||||
|
@@ -1,7 +1 @@
|
||||
package protocol // import "github.com/xtls/xray-core/common/protocol"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var ErrProtoNeedMoreData = errors.New("protocol matches, but need more data to complete sniffing")
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/tls"
|
||||
@@ -10,8 +11,8 @@ import (
|
||||
"github.com/quic-go/quic-go/quicvarint"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/bytespool"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
ptls "github.com/xtls/xray-core/common/protocol/tls"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
@@ -46,17 +47,22 @@ var (
|
||||
errNotQuicInitial = errors.New("not initial packet")
|
||||
)
|
||||
|
||||
func SniffQUIC(b []byte) (*SniffHeader, error) {
|
||||
if len(b) == 0 {
|
||||
return nil, common.ErrNoClue
|
||||
}
|
||||
func SniffQUIC(b []byte) (resultReturn *SniffHeader, errorReturn error) {
|
||||
// In extremely rare cases, this sniffer may cause slice error
|
||||
// and we set recover() here to prevent crash.
|
||||
// TODO: Thoroughly fix this panic
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
errors.LogError(context.Background(), "Failed to sniff QUIC: ", r)
|
||||
resultReturn = nil
|
||||
errorReturn = common.ErrNoClue
|
||||
}
|
||||
}()
|
||||
|
||||
// Crypto data separated across packets
|
||||
cryptoLen := int32(0)
|
||||
cryptoDataBuf := buf.NewWithSize(32767)
|
||||
defer cryptoDataBuf.Release()
|
||||
cache := buf.New()
|
||||
defer cache.Release()
|
||||
cryptoLen := 0
|
||||
cryptoData := bytespool.Alloc(int32(len(b)))
|
||||
defer bytespool.Free(cryptoData)
|
||||
|
||||
// Parse QUIC packets
|
||||
for len(b) > 0 {
|
||||
@@ -99,25 +105,19 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
|
||||
return nil, errNotQuic
|
||||
}
|
||||
|
||||
if isQuicInitial { // Only initial packets have token, see https://datatracker.ietf.org/doc/html/rfc9000#section-17.2.2
|
||||
tokenLen, err := quicvarint.Read(buffer)
|
||||
if err != nil || tokenLen > uint64(len(b)) {
|
||||
return nil, errNotQuic
|
||||
}
|
||||
tokenLen, err := quicvarint.Read(buffer)
|
||||
if err != nil || tokenLen > uint64(len(b)) {
|
||||
return nil, errNotQuic
|
||||
}
|
||||
|
||||
if _, err = buffer.ReadBytes(int32(tokenLen)); err != nil {
|
||||
return nil, errNotQuic
|
||||
}
|
||||
if _, err = buffer.ReadBytes(int32(tokenLen)); err != nil {
|
||||
return nil, errNotQuic
|
||||
}
|
||||
|
||||
packetLen, err := quicvarint.Read(buffer)
|
||||
if err != nil {
|
||||
return nil, errNotQuic
|
||||
}
|
||||
// packetLen is impossible to be shorter than this
|
||||
if packetLen < 4 {
|
||||
return nil, errNotQuic
|
||||
}
|
||||
|
||||
hdrLen := len(b) - int(buffer.Len())
|
||||
if len(b) < hdrLen+int(packetLen) {
|
||||
@@ -130,6 +130,9 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
origPNBytes := make([]byte, 4)
|
||||
copy(origPNBytes, b[hdrLen:hdrLen+4])
|
||||
|
||||
var salt []byte
|
||||
if versionNumber == version1 {
|
||||
salt = quicSalt
|
||||
@@ -144,34 +147,44 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cache.Clear()
|
||||
cache := buf.New()
|
||||
defer cache.Release()
|
||||
|
||||
mask := cache.Extend(int32(block.BlockSize()))
|
||||
block.Encrypt(mask, b[hdrLen+4:hdrLen+4+len(mask)])
|
||||
block.Encrypt(mask, b[hdrLen+4:hdrLen+4+16])
|
||||
b[0] ^= mask[0] & 0xf
|
||||
packetNumberLength := int(b[0]&0x3 + 1)
|
||||
for i := range packetNumberLength {
|
||||
for i := range b[hdrLen : hdrLen+4] {
|
||||
b[hdrLen+i] ^= mask[i+1]
|
||||
}
|
||||
packetNumberLength := b[0]&0x3 + 1
|
||||
if packetNumberLength != 1 {
|
||||
return nil, errNotQuicInitial
|
||||
}
|
||||
var packetNumber uint32
|
||||
{
|
||||
n, err := buffer.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
packetNumber = uint32(n)
|
||||
}
|
||||
|
||||
extHdrLen := hdrLen + int(packetNumberLength)
|
||||
copy(b[extHdrLen:hdrLen+4], origPNBytes[packetNumberLength:])
|
||||
data := b[extHdrLen : int(packetLen)+hdrLen]
|
||||
|
||||
key := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic key", 16)
|
||||
iv := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic iv", 12)
|
||||
cipher := AEADAESGCMTLS13(key, iv)
|
||||
|
||||
nonce := cache.Extend(int32(cipher.NonceSize()))
|
||||
_, err = buffer.Read(nonce[len(nonce)-packetNumberLength:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
extHdrLen := hdrLen + packetNumberLength
|
||||
data := b[extHdrLen : int(packetLen)+hdrLen]
|
||||
binary.BigEndian.PutUint64(nonce[len(nonce)-8:], uint64(packetNumber))
|
||||
decrypted, err := cipher.Open(b[extHdrLen:extHdrLen], nonce, data, b[:extHdrLen])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buffer = buf.FromBytes(decrypted)
|
||||
for !buffer.IsEmpty() {
|
||||
frameType, _ := buffer.ReadByte()
|
||||
for i := 0; !buffer.IsEmpty(); i++ {
|
||||
frameType := byte(0x0) // Default to PADDING frame
|
||||
for frameType == 0x0 && !buffer.IsEmpty() {
|
||||
frameType, _ = buffer.ReadByte()
|
||||
}
|
||||
@@ -220,15 +233,16 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
|
||||
if err != nil || length > uint64(buffer.Len()) {
|
||||
return nil, io.ErrUnexpectedEOF
|
||||
}
|
||||
currentCryptoLen := int32(offset + length)
|
||||
if cryptoLen < currentCryptoLen {
|
||||
if cryptoDataBuf.Cap() < currentCryptoLen {
|
||||
return nil, io.ErrShortBuffer
|
||||
if cryptoLen < int(offset+length) {
|
||||
cryptoLen = int(offset + length)
|
||||
if len(cryptoData) < cryptoLen {
|
||||
newCryptoData := bytespool.Alloc(int32(cryptoLen))
|
||||
copy(newCryptoData, cryptoData)
|
||||
bytespool.Free(cryptoData)
|
||||
cryptoData = newCryptoData
|
||||
}
|
||||
cryptoDataBuf.Extend(currentCryptoLen - cryptoLen)
|
||||
cryptoLen = currentCryptoLen
|
||||
}
|
||||
if _, err := buffer.Read(cryptoDataBuf.BytesRange(int32(offset), currentCryptoLen)); err != nil { // Field: Crypto Data
|
||||
if _, err := buffer.Read(cryptoData[offset : offset+length]); err != nil { // Field: Crypto Data
|
||||
return nil, io.ErrUnexpectedEOF
|
||||
}
|
||||
case 0x1c: // CONNECTION_CLOSE frame, only 0x1c is permitted in initial packet
|
||||
@@ -253,7 +267,7 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
|
||||
}
|
||||
|
||||
tlsHdr := &ptls.SniffHeader{}
|
||||
err = ptls.ReadClientHello(cryptoDataBuf.BytesRange(0, cryptoLen), tlsHdr)
|
||||
err = ptls.ReadClientHello(cryptoData[:cryptoLen], tlsHdr)
|
||||
if err != nil {
|
||||
// The crypto data may have not been fully recovered in current packets,
|
||||
// So we continue to sniff rest packets.
|
||||
@@ -262,8 +276,7 @@ func SniffQUIC(b []byte) (*SniffHeader, error) {
|
||||
}
|
||||
return &SniffHeader{domain: tlsHdr.Domain()}, nil
|
||||
}
|
||||
// All payload is parsed as valid QUIC packets, but we need more packets for crypto data to read client hello.
|
||||
return nil, protocol.ErrProtoNeedMoreData
|
||||
return nil, common.ErrNoClue
|
||||
}
|
||||
|
||||
func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, length int) []byte {
|
||||
|
File diff suppressed because one or more lines are too long
2
common/protocol/tls/cert/.gitignore
vendored
Normal file
2
common/protocol/tls/cert/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.crt
|
||||
*.key
|
@@ -3,9 +3,9 @@ package tls
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
)
|
||||
|
||||
type SniffHeader struct {
|
||||
@@ -59,6 +59,9 @@ func ReadClientHello(data []byte, h *SniffHeader) error {
|
||||
}
|
||||
data = data[1+compressionMethodsLen:]
|
||||
|
||||
if len(data) == 0 {
|
||||
return errNotClientHello
|
||||
}
|
||||
if len(data) < 2 {
|
||||
return errNotClientHello
|
||||
}
|
||||
@@ -101,21 +104,13 @@ func ReadClientHello(data []byte, h *SniffHeader) error {
|
||||
return errNotClientHello
|
||||
}
|
||||
if nameType == 0 {
|
||||
// QUIC separated across packets
|
||||
// May cause the serverName to be incomplete
|
||||
b := byte(0)
|
||||
for _, b = range d[:nameLen] {
|
||||
if b <= ' ' {
|
||||
return protocol.ErrProtoNeedMoreData
|
||||
}
|
||||
}
|
||||
serverName := string(d[:nameLen])
|
||||
// An SNI value may not include a
|
||||
// trailing dot. See
|
||||
// https://tools.ietf.org/html/rfc6066#section-3.
|
||||
if b == '.' {
|
||||
if strings.HasSuffix(serverName, ".") {
|
||||
return errNotClientHello
|
||||
}
|
||||
serverName := string(d[:nameLen])
|
||||
h.domain = serverName
|
||||
return nil
|
||||
}
|
||||
|
@@ -42,7 +42,7 @@ func ContextWithOutbounds(ctx context.Context, outbounds []*Outbound) context.Co
|
||||
return context.WithValue(ctx, outboundSessionKey, outbounds)
|
||||
}
|
||||
|
||||
func ContextCloneOutboundsAndContent(ctx context.Context) context.Context {
|
||||
func ContextCloneOutbounds(ctx context.Context) context.Context {
|
||||
outbounds := OutboundsFromContext(ctx)
|
||||
newOutbounds := make([]*Outbound, len(outbounds))
|
||||
for i, ob := range outbounds {
|
||||
@@ -55,15 +55,7 @@ func ContextCloneOutboundsAndContent(ctx context.Context) context.Context {
|
||||
newOutbounds[i] = &v
|
||||
}
|
||||
|
||||
content := ContentFromContext(ctx)
|
||||
newContent := Content{}
|
||||
if content != nil {
|
||||
newContent = *content
|
||||
if content.Attributes != nil {
|
||||
panic("content.Attributes != nil")
|
||||
}
|
||||
}
|
||||
return ContextWithContent(ContextWithOutbounds(ctx, newOutbounds), &newContent)
|
||||
return ContextWithOutbounds(ctx, newOutbounds)
|
||||
}
|
||||
|
||||
func OutboundsFromContext(ctx context.Context) []*Outbound {
|
||||
|
@@ -4,6 +4,8 @@ package session // import "github.com/xtls/xray-core/common/session"
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
c "github.com/xtls/xray-core/common/ctx"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
@@ -74,11 +76,12 @@ type Outbound struct {
|
||||
|
||||
// SniffingRequest controls the behavior of content sniffing.
|
||||
type SniffingRequest struct {
|
||||
ExcludeForDomain []string // read-only once set
|
||||
OverrideDestinationForProtocol []string // read-only once set
|
||||
ExcludeForDomain []string
|
||||
OverrideDestinationForProtocol []string
|
||||
Enabled bool
|
||||
MetadataOnly bool
|
||||
RouteOnly bool
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
// Content is the metadata of the connection content.
|
||||
@@ -91,6 +94,10 @@ type Content struct {
|
||||
Attributes map[string]string
|
||||
|
||||
SkipDNSResolve bool
|
||||
|
||||
mu sync.Mutex
|
||||
|
||||
isLocked bool
|
||||
}
|
||||
|
||||
// Sockopt is the settings for socket connection.
|
||||
@@ -99,8 +106,22 @@ type Sockopt struct {
|
||||
Mark int32
|
||||
}
|
||||
|
||||
// Some how when using mux, there will be a same ctx between different requests
|
||||
// This will cause problem as it's designed for single request, like concurrent map writes
|
||||
// Add a Mutex as a temp solution
|
||||
|
||||
// SetAttribute attaches additional string attributes to content.
|
||||
func (c *Content) SetAttribute(name string, value string) {
|
||||
if c.isLocked {
|
||||
errors.LogError(context.Background(), "Multiple goroutines are tring to access one routing content, tring to write ", name, ":", value)
|
||||
}
|
||||
c.mu.Lock()
|
||||
c.isLocked = true
|
||||
defer func() {
|
||||
c.isLocked = false
|
||||
c.mu.Unlock()
|
||||
}()
|
||||
|
||||
if c.Attributes == nil {
|
||||
c.Attributes = make(map[string]string)
|
||||
}
|
||||
@@ -109,8 +130,24 @@ func (c *Content) SetAttribute(name string, value string) {
|
||||
|
||||
// Attribute retrieves additional string attributes from content.
|
||||
func (c *Content) Attribute(name string) string {
|
||||
c.mu.Lock()
|
||||
c.isLocked = true
|
||||
defer func() {
|
||||
c.isLocked = false
|
||||
c.mu.Unlock()
|
||||
}()
|
||||
if c.Attributes == nil {
|
||||
return ""
|
||||
}
|
||||
return c.Attributes[name]
|
||||
}
|
||||
|
||||
func (c *Content) AttributeLen() int {
|
||||
c.mu.Lock()
|
||||
c.isLocked = true
|
||||
defer func() {
|
||||
c.isLocked = false
|
||||
c.mu.Unlock()
|
||||
}()
|
||||
return len(c.Attributes)
|
||||
}
|
||||
|
@@ -67,9 +67,9 @@ func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
|
||||
t.checkTask.Close()
|
||||
}
|
||||
t.checkTask = checkTask
|
||||
t.Unlock()
|
||||
t.Update()
|
||||
common.Must(checkTask.Start())
|
||||
t.Unlock()
|
||||
}
|
||||
|
||||
func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
|
||||
|
@@ -18,8 +18,8 @@ import (
|
||||
|
||||
var (
|
||||
Version_x byte = 25
|
||||
Version_y byte = 6
|
||||
Version_z byte = 8
|
||||
Version_y byte = 2
|
||||
Version_z byte = 21
|
||||
)
|
||||
|
||||
var (
|
||||
|
@@ -90,11 +90,6 @@ type Instance struct {
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// Instance state
|
||||
func (server *Instance) IsRunning() bool {
|
||||
return server.running
|
||||
}
|
||||
|
||||
func AddInboundHandler(server *Instance, config *InboundHandlerConfig) error {
|
||||
inboundManager := server.GetFeature(inbound.ManagerType()).(inbound.Manager)
|
||||
rawHandler, err := CreateObject(server, config)
|
||||
|
@@ -21,7 +21,11 @@ type Client interface {
|
||||
features.Feature
|
||||
|
||||
// LookupIP returns IP address for the given domain. IPs may contain IPv4 and/or IPv6 addresses.
|
||||
LookupIP(domain string, option IPOption) ([]net.IP, uint32, error)
|
||||
LookupIP(domain string, option IPOption) ([]net.IP, error)
|
||||
}
|
||||
|
||||
type HostsLookup interface {
|
||||
LookupHosts(domain string) *net.Address
|
||||
}
|
||||
|
||||
// ClientType returns the type of Client interface. Can be used for implementing common.HasType.
|
||||
@@ -34,8 +38,6 @@ func ClientType() interface{} {
|
||||
// ErrEmptyResponse indicates that DNS query succeeded but no answer was returned.
|
||||
var ErrEmptyResponse = errors.New("empty response")
|
||||
|
||||
const DefaultTTL = 300
|
||||
|
||||
type RCodeError uint16
|
||||
|
||||
func (e RCodeError) Error() string {
|
||||
|
@@ -20,44 +20,41 @@ func (*Client) Start() error { return nil }
|
||||
func (*Client) Close() error { return nil }
|
||||
|
||||
// LookupIP implements Client.
|
||||
func (*Client) LookupIP(host string, option dns.IPOption) ([]net.IP, uint32, error) {
|
||||
func (*Client) LookupIP(host string, option dns.IPOption) ([]net.IP, error) {
|
||||
ips, err := net.LookupIP(host)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
return nil, err
|
||||
}
|
||||
parsedIPs := make([]net.IP, 0, len(ips))
|
||||
ipv4 := make([]net.IP, 0, len(ips))
|
||||
ipv6 := make([]net.IP, 0, len(ips))
|
||||
for _, ip := range ips {
|
||||
parsed := net.IPAddress(ip)
|
||||
if parsed == nil {
|
||||
continue
|
||||
if parsed != nil {
|
||||
parsedIPs = append(parsedIPs, parsed.IP())
|
||||
}
|
||||
parsedIP := parsed.IP()
|
||||
parsedIPs = append(parsedIPs, parsedIP)
|
||||
|
||||
if len(parsedIP) == net.IPv4len {
|
||||
ipv4 = append(ipv4, parsedIP)
|
||||
} else {
|
||||
ipv6 = append(ipv6, parsedIP)
|
||||
if len(ip) == net.IPv4len {
|
||||
ipv4 = append(ipv4, ip)
|
||||
}
|
||||
if len(ip) == net.IPv6len {
|
||||
ipv6 = append(ipv6, ip)
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case option.IPv4Enable && option.IPv6Enable:
|
||||
if len(parsedIPs) > 0 {
|
||||
return parsedIPs, dns.DefaultTTL, nil
|
||||
return parsedIPs, nil
|
||||
}
|
||||
case option.IPv4Enable:
|
||||
if len(ipv4) > 0 {
|
||||
return ipv4, dns.DefaultTTL, nil
|
||||
return ipv4, nil
|
||||
}
|
||||
case option.IPv6Enable:
|
||||
if len(ipv6) > 0 {
|
||||
return ipv6, dns.DefaultTTL, nil
|
||||
return ipv6, nil
|
||||
}
|
||||
}
|
||||
return nil, 0, dns.ErrEmptyResponse
|
||||
return nil, dns.ErrEmptyResponse
|
||||
}
|
||||
|
||||
// New create a new dns.Client that queries localhost for DNS.
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/features"
|
||||
)
|
||||
|
||||
@@ -16,10 +15,6 @@ type Handler interface {
|
||||
common.Runnable
|
||||
// The tag of this handler.
|
||||
Tag() string
|
||||
// Returns the active receiver settings.
|
||||
ReceiverSettings() *serial.TypedMessage
|
||||
// Returns the active proxy settings.
|
||||
ProxySettings() *serial.TypedMessage
|
||||
|
||||
// Deprecated: Do not use in new code.
|
||||
GetRandomInboundProxy() (interface{}, net.Port, int)
|
||||
@@ -37,9 +32,6 @@ type Manager interface {
|
||||
|
||||
// RemoveHandler removes a handler from Manager.
|
||||
RemoveHandler(ctx context.Context, tag string) error
|
||||
|
||||
// ListHandlers returns a list of inbound.Handler.
|
||||
ListHandlers(ctx context.Context) []Handler
|
||||
}
|
||||
|
||||
// ManagerType returns the type of Manager interface. Can be used for implementing common.HasType.
|
||||
|
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/features"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
)
|
||||
@@ -16,8 +15,6 @@ type Handler interface {
|
||||
common.Runnable
|
||||
Tag() string
|
||||
Dispatch(ctx context.Context, link *transport.Link)
|
||||
SenderSettings() *serial.TypedMessage
|
||||
ProxySettings() *serial.TypedMessage
|
||||
}
|
||||
|
||||
type HandlerSelector interface {
|
||||
@@ -38,9 +35,6 @@ type Manager interface {
|
||||
|
||||
// RemoveHandler removes a handler from outbound.Manager.
|
||||
RemoveHandler(ctx context.Context, tag string) error
|
||||
|
||||
// ListHandlers returns a list of outbound.Handler.
|
||||
ListHandlers(ctx context.Context) []Handler
|
||||
}
|
||||
|
||||
// ManagerType returns the type of Manager interface. Can be used to implement common.HasType.
|
||||
|
@@ -23,7 +23,7 @@ func (ctx *ResolvableContext) GetTargetIPs() []net.IP {
|
||||
}
|
||||
|
||||
if domain := ctx.GetTargetDomain(); len(domain) != 0 {
|
||||
ips, _, err := ctx.dnsClient.LookupIP(domain, dns.IPOption{
|
||||
ips, err := ctx.dnsClient.LookupIP(domain, dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
|
58
go.mod
58
go.mod
@@ -1,59 +1,61 @@
|
||||
module github.com/xtls/xray-core
|
||||
|
||||
go 1.24
|
||||
go 1.23
|
||||
|
||||
require (
|
||||
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0
|
||||
github.com/cloudflare/circl v1.6.1
|
||||
github.com/cloudflare/circl v1.6.0
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
||||
github.com/golang/mock v1.7.0-rc.1
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/miekg/dns v1.1.67
|
||||
github.com/miekg/dns v1.1.63
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/pires/go-proxyproto v0.8.1
|
||||
github.com/quic-go/quic-go v0.54.0
|
||||
github.com/refraction-networking/utls v1.8.0
|
||||
github.com/pires/go-proxyproto v0.8.0
|
||||
github.com/quic-go/quic-go v0.50.0
|
||||
github.com/refraction-networking/utls v1.6.7
|
||||
github.com/sagernet/sing v0.5.1
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
github.com/xtls/reality v0.0.0-20250722045654-4eaf7927f393
|
||||
github.com/vishvananda/netlink v1.3.0
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||
golang.org/x/crypto v0.40.0
|
||||
golang.org/x/net v0.42.0
|
||||
golang.org/x/sync v0.16.0
|
||||
golang.org/x/sys v0.34.0
|
||||
golang.org/x/crypto v0.33.0
|
||||
golang.org/x/net v0.35.0
|
||||
golang.org/x/sync v0.11.0
|
||||
golang.org/x/sys v0.30.0
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||
google.golang.org/grpc v1.74.2
|
||||
google.golang.org/protobuf v1.36.6
|
||||
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5
|
||||
google.golang.org/grpc v1.70.0
|
||||
google.golang.org/protobuf v1.36.5
|
||||
gvisor.dev/gvisor v0.0.0-20240320123526-dc6abceb7ff0
|
||||
h12.io/socks v1.0.3
|
||||
lukechampine.com/blake3 v1.4.1
|
||||
lukechampine.com/blake3 v1.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 // indirect
|
||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/juju/ratelimit v1.0.2 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect
|
||||
github.com/klauspost/compress v1.17.8 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
golang.org/x/tools v0.34.0 // indirect
|
||||
golang.org/x/tools v0.26.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
149
go.sum
149
go.sum
@@ -1,66 +1,65 @@
|
||||
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 h1:Wo41lDOevRJSGpevP+8Pk5bANX7fJacO2w04aqLiC5I=
|
||||
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM=
|
||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
|
||||
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 h1:BS21ZUJ/B5X2UVUbczfmdWH7GapPWAhxcMsDnjJTU1E=
|
||||
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0=
|
||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=
|
||||
github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364 h1:5XxdakFhqd9dnXoAZy1Mb2R/DZ6D1e+0bGC/JhucGYI=
|
||||
github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364/go.mod h1:eDJQioIyy4Yn3MVivT7rv/39gAJTrA7lgmYr8EW950c=
|
||||
github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI=
|
||||
github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
|
||||
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
|
||||
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0=
|
||||
github.com/miekg/dns v1.1.67/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
|
||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
|
||||
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
|
||||
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
||||
github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pires/go-proxyproto v0.8.0 h1:5unRmEAPbHXHuLjDg01CxJWf91cw3lKHc/0xzKpXEe0=
|
||||
github.com/pires/go-proxyproto v0.8.0/go.mod h1:iknsfgnH8EkjrMeMyvfKByp9TiBZCKZM0jx2xmKqnVY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
|
||||
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
|
||||
github.com/refraction-networking/utls v1.8.0 h1:L38krhiTAyj9EeiQQa2sg+hYb4qwLCqdMcpZrRfbONE=
|
||||
github.com/refraction-networking/utls v1.8.0/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
||||
github.com/quic-go/quic-go v0.50.0 h1:3H/ld1pa3CYhkcc20TPIyG1bNsdhn9qZBGN3b9/UyUo=
|
||||
github.com/quic-go/quic-go v0.50.0/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E=
|
||||
github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
|
||||
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
||||
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||
@@ -73,67 +72,68 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
|
||||
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
|
||||
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
|
||||
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/xtls/reality v0.0.0-20250722045654-4eaf7927f393 h1:WcsH1BAZVgbKpyyiyjOnS8deJcQ7BmYa2iNEPqEy574=
|
||||
github.com/xtls/reality v0.0.0-20250722045654-4eaf7927f393/go.mod h1:XxvnCCgBee4WWE0bc4E+a7wbk8gkJ/rS0vNVNtC5qp0=
|
||||
github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
|
||||
github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
|
||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d h1:+B97uD9uHLgAAulhigmys4BVwZZypzK7gPN3WtpgRJg=
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
|
||||
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
|
||||
go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
|
||||
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
|
||||
go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
|
||||
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
|
||||
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
|
||||
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg=
|
||||
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
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.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -141,15 +141,14 @@ golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeu
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
|
||||
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
|
||||
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
@@ -157,9 +156,9 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5 h1:sfK5nHuG7lRFZ2FdTT3RimOqWBg8IrVm+/Vko1FVOsk=
|
||||
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5/go.mod h1:3r5CMtNQMKIvBlrmM9xWUNamjKBYPOWyXOjmg5Kts3g=
|
||||
gvisor.dev/gvisor v0.0.0-20240320123526-dc6abceb7ff0 h1:P+U/06iIKPQ3DLcg+zBfSCia1luZ2msPZrJ8jYDFPs0=
|
||||
gvisor.dev/gvisor v0.0.0-20240320123526-dc6abceb7ff0/go.mod h1:NQHVAzMwvZ+Qe3ElSiHmq9RUm1MdNHpUZ52fiEqvn+0=
|
||||
h12.io/socks v1.0.3 h1:Ka3qaQewws4j4/eDQnOdpr4wXsC//dXtWvftlIcCQUo=
|
||||
h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
|
||||
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
|
||||
lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=
|
||||
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
|
||||
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
||||
|
@@ -8,13 +8,11 @@ import (
|
||||
|
||||
type Duration int64
|
||||
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (d *Duration) MarshalJSON() ([]byte, error) {
|
||||
dr := time.Duration(*d)
|
||||
return json.Marshal(dr.String())
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (d *Duration) UnmarshalJSON(b []byte) error {
|
||||
var v interface{}
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
|
@@ -23,7 +23,6 @@ func (v StringList) Len() int {
|
||||
return len(v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (v *StringList) UnmarshalJSON(data []byte) error {
|
||||
var strarray []string
|
||||
if err := json.Unmarshal(data, &strarray); err == nil {
|
||||
@@ -44,12 +43,10 @@ type Address struct {
|
||||
net.Address
|
||||
}
|
||||
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (v *Address) MarshalJSON() ([]byte, error) {
|
||||
func (v Address) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.Address.String())
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (v *Address) UnmarshalJSON(data []byte) error {
|
||||
var rawStr string
|
||||
if err := json.Unmarshal(data, &rawStr); err != nil {
|
||||
@@ -84,7 +81,6 @@ func (v Network) Build() net.Network {
|
||||
|
||||
type NetworkList []Network
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (v *NetworkList) UnmarshalJSON(data []byte) error {
|
||||
var strarray []Network
|
||||
if err := json.Unmarshal(data, &strarray); err == nil {
|
||||
@@ -173,19 +169,6 @@ func (v *PortRange) Build() *net.PortRange {
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (v *PortRange) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.String())
|
||||
}
|
||||
|
||||
func (port *PortRange) String() string {
|
||||
if port.From == port.To {
|
||||
return strconv.Itoa(int(port.From))
|
||||
} else {
|
||||
return fmt.Sprintf("%d-%d", port.From, port.To)
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (v *PortRange) UnmarshalJSON(data []byte) error {
|
||||
port, err := parseIntPort(data)
|
||||
@@ -220,21 +203,20 @@ func (list *PortList) Build() *net.PortList {
|
||||
return portList
|
||||
}
|
||||
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (v *PortList) MarshalJSON() ([]byte, error) {
|
||||
portStr := v.String()
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err == nil {
|
||||
return json.Marshal(port)
|
||||
} else {
|
||||
return json.Marshal(portStr)
|
||||
}
|
||||
func (v PortList) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.String())
|
||||
}
|
||||
|
||||
func (v PortList) String() string {
|
||||
ports := []string{}
|
||||
for _, port := range v.Range {
|
||||
ports = append(ports, port.String())
|
||||
if port.From == port.To {
|
||||
p := strconv.Itoa(int(port.From))
|
||||
ports = append(ports, p)
|
||||
} else {
|
||||
p := fmt.Sprintf("%d-%d", port.From, port.To)
|
||||
ports = append(ports, p)
|
||||
}
|
||||
}
|
||||
return strings.Join(ports, ",")
|
||||
}
|
||||
@@ -295,8 +277,7 @@ type Int32Range struct {
|
||||
To int32
|
||||
}
|
||||
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (v *Int32Range) MarshalJSON() ([]byte, error) {
|
||||
func (v Int32Range) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.String())
|
||||
}
|
||||
|
||||
@@ -308,7 +289,6 @@ func (v Int32Range) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (v *Int32Range) UnmarshalJSON(data []byte) error {
|
||||
defer v.ensureOrder()
|
||||
var str string
|
||||
|
@@ -1,11 +1,7 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@@ -21,17 +17,10 @@ type NameServerConfig struct {
|
||||
Port uint16 `json:"port"`
|
||||
SkipFallback bool `json:"skipFallback"`
|
||||
Domains []string `json:"domains"`
|
||||
ExpectedIPs StringList `json:"expectedIPs"`
|
||||
ExpectIPs StringList `json:"expectIPs"`
|
||||
ExpectIPs StringList `json:"expectIps"`
|
||||
QueryStrategy string `json:"queryStrategy"`
|
||||
Tag string `json:"tag"`
|
||||
TimeoutMs uint64 `json:"timeoutMs"`
|
||||
DisableCache bool `json:"disableCache"`
|
||||
FinalQuery bool `json:"finalQuery"`
|
||||
UnexpectedIPs StringList `json:"unexpectedIPs"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
|
||||
var address Address
|
||||
if err := json.Unmarshal(data, &address); err == nil {
|
||||
@@ -45,14 +34,8 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
|
||||
Port uint16 `json:"port"`
|
||||
SkipFallback bool `json:"skipFallback"`
|
||||
Domains []string `json:"domains"`
|
||||
ExpectedIPs StringList `json:"expectedIPs"`
|
||||
ExpectIPs StringList `json:"expectIPs"`
|
||||
ExpectIPs StringList `json:"expectIps"`
|
||||
QueryStrategy string `json:"queryStrategy"`
|
||||
Tag string `json:"tag"`
|
||||
TimeoutMs uint64 `json:"timeoutMs"`
|
||||
DisableCache bool `json:"disableCache"`
|
||||
FinalQuery bool `json:"finalQuery"`
|
||||
UnexpectedIPs StringList `json:"unexpectedIPs"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &advanced); err == nil {
|
||||
c.Address = advanced.Address
|
||||
@@ -60,14 +43,8 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
|
||||
c.Port = advanced.Port
|
||||
c.SkipFallback = advanced.SkipFallback
|
||||
c.Domains = advanced.Domains
|
||||
c.ExpectedIPs = advanced.ExpectedIPs
|
||||
c.ExpectIPs = advanced.ExpectIPs
|
||||
c.QueryStrategy = advanced.QueryStrategy
|
||||
c.Tag = advanced.Tag
|
||||
c.TimeoutMs = advanced.TimeoutMs
|
||||
c.DisableCache = advanced.DisableCache
|
||||
c.FinalQuery = advanced.FinalQuery
|
||||
c.UnexpectedIPs = advanced.UnexpectedIPs
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -115,38 +92,9 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
|
||||
})
|
||||
}
|
||||
|
||||
if len(c.ExpectedIPs) == 0 {
|
||||
c.ExpectedIPs = c.ExpectIPs
|
||||
}
|
||||
|
||||
actPrior := false
|
||||
var newExpectedIPs StringList
|
||||
for _, s := range c.ExpectedIPs {
|
||||
if s == "*" {
|
||||
actPrior = true
|
||||
} else {
|
||||
newExpectedIPs = append(newExpectedIPs, s)
|
||||
}
|
||||
}
|
||||
|
||||
actUnprior := false
|
||||
var newUnexpectedIPs StringList
|
||||
for _, s := range c.UnexpectedIPs {
|
||||
if s == "*" {
|
||||
actUnprior = true
|
||||
} else {
|
||||
newUnexpectedIPs = append(newUnexpectedIPs, s)
|
||||
}
|
||||
}
|
||||
|
||||
expectedGeoipList, err := ToCidrList(newExpectedIPs)
|
||||
geoipList, err := ToCidrList(c.ExpectIPs)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid expected IP rule: ", c.ExpectedIPs).Base(err)
|
||||
}
|
||||
|
||||
unexpectedGeoipList, err := ToCidrList(newUnexpectedIPs)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid unexpected IP rule: ", c.UnexpectedIPs).Base(err)
|
||||
return nil, errors.New("invalid IP rule: ", c.ExpectIPs).Base(err)
|
||||
}
|
||||
|
||||
var myClientIP []byte
|
||||
@@ -166,16 +114,9 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
|
||||
ClientIp: myClientIP,
|
||||
SkipFallback: c.SkipFallback,
|
||||
PrioritizedDomain: domains,
|
||||
ExpectedGeoip: expectedGeoipList,
|
||||
Geoip: geoipList,
|
||||
OriginalRules: originalRules,
|
||||
QueryStrategy: resolveQueryStrategy(c.QueryStrategy),
|
||||
ActPrior: actPrior,
|
||||
Tag: c.Tag,
|
||||
TimeoutMs: c.TimeoutMs,
|
||||
DisableCache: c.DisableCache,
|
||||
FinalQuery: c.FinalQuery,
|
||||
UnexpectedGeoip: unexpectedGeoipList,
|
||||
ActUnprior: actUnprior,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -196,7 +137,6 @@ type DNSConfig struct {
|
||||
DisableCache bool `json:"disableCache"`
|
||||
DisableFallback bool `json:"disableFallback"`
|
||||
DisableFallbackIfMatch bool `json:"disableFallbackIfMatch"`
|
||||
UseSystemHosts bool `json:"useSystemHosts"`
|
||||
}
|
||||
|
||||
type HostAddress struct {
|
||||
@@ -204,18 +144,6 @@ type HostAddress struct {
|
||||
addrs []*Address
|
||||
}
|
||||
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (h *HostAddress) MarshalJSON() ([]byte, error) {
|
||||
if (h.addr != nil) != (h.addrs != nil) {
|
||||
if h.addr != nil {
|
||||
return json.Marshal(h.addr)
|
||||
} else if h.addrs != nil {
|
||||
return json.Marshal(h.addrs)
|
||||
}
|
||||
}
|
||||
return nil, errors.New("unexpected config state")
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (h *HostAddress) UnmarshalJSON(data []byte) error {
|
||||
addr := new(Address)
|
||||
@@ -261,11 +189,6 @@ func getHostMapping(ha *HostAddress) *dns.Config_HostMapping {
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (m *HostsWrapper) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(m.Hosts)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (m *HostsWrapper) UnmarshalJSON(data []byte) error {
|
||||
hosts := make(map[string]*HostAddress)
|
||||
@@ -418,15 +341,6 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
|
||||
}
|
||||
config.StaticHosts = append(config.StaticHosts, staticHosts...)
|
||||
}
|
||||
if c.UseSystemHosts {
|
||||
systemHosts, err := readSystemHosts()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to read system hosts").Base(err)
|
||||
}
|
||||
for domain, ips := range systemHosts {
|
||||
config.StaticHosts = append(config.StaticHosts, &dns.Config_HostMapping{Ip: ips, Domain: domain, Type: dns.DomainMatchingType_Full})
|
||||
}
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
@@ -439,57 +353,7 @@ func resolveQueryStrategy(queryStrategy string) dns.QueryStrategy {
|
||||
return dns.QueryStrategy_USE_IP4
|
||||
case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6":
|
||||
return dns.QueryStrategy_USE_IP6
|
||||
case "usesys", "usesystem", "use_sys", "use_system", "use-sys", "use-system":
|
||||
return dns.QueryStrategy_USE_SYS
|
||||
default:
|
||||
return dns.QueryStrategy_USE_IP
|
||||
}
|
||||
}
|
||||
|
||||
func readSystemHosts() (map[string][][]byte, error) {
|
||||
var hostsPath string
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
hostsPath = filepath.Join(os.Getenv("SystemRoot"), "System32", "drivers", "etc", "hosts")
|
||||
default:
|
||||
hostsPath = "/etc/hosts"
|
||||
}
|
||||
|
||||
file, err := os.Open(hostsPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
hostsMap := make(map[string][][]byte)
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if i := strings.IndexByte(line, '#'); i >= 0 {
|
||||
// Discard comments.
|
||||
line = line[0:i]
|
||||
}
|
||||
f := strings.Fields(line)
|
||||
if len(f) < 2 {
|
||||
continue
|
||||
}
|
||||
addr := net.ParseAddress(f[0])
|
||||
if addr.Family().IsDomain() {
|
||||
continue
|
||||
}
|
||||
ip := addr.IP()
|
||||
for i := 1; i < len(f); i++ {
|
||||
domain := strings.TrimSuffix(f[i], ".")
|
||||
domain = strings.ToLower(domain)
|
||||
if v, ok := hostsMap[domain]; ok {
|
||||
hostsMap[domain] = append(v, ip)
|
||||
} else {
|
||||
hostsMap[domain] = [][]byte{ip}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return hostsMap, nil
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ func (c *DNSOutboundConfig) Build() (proto.Message, error) {
|
||||
switch c.NonIPQuery {
|
||||
case "":
|
||||
c.NonIPQuery = "drop"
|
||||
case "drop", "skip", "reject":
|
||||
case "drop", "skip":
|
||||
default:
|
||||
return nil, errors.New(`unknown "nonIPQuery": `, c.NonIPQuery)
|
||||
}
|
||||
|
@@ -20,18 +20,6 @@ type FakeDNSConfig struct {
|
||||
pools []*FakeDNSPoolElementConfig
|
||||
}
|
||||
|
||||
// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
|
||||
func (f *FakeDNSConfig) MarshalJSON() ([]byte, error) {
|
||||
if (f.pool != nil) != (f.pools != nil) {
|
||||
if f.pool != nil {
|
||||
return json.Marshal(f.pool)
|
||||
} else if f.pools != nil {
|
||||
return json.Marshal(f.pools)
|
||||
}
|
||||
}
|
||||
return nil, errors.New("unexpected config state")
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (f *FakeDNSConfig) UnmarshalJSON(data []byte) error {
|
||||
var pool FakeDNSPoolElementConfig
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/xtls/xray-core/app/observatory"
|
||||
"github.com/xtls/xray-core/app/observatory/burst"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/infra/conf/cfgcommon/duration"
|
||||
)
|
||||
|
||||
@@ -27,9 +26,6 @@ type BurstObservatoryConfig struct {
|
||||
}
|
||||
|
||||
func (b BurstObservatoryConfig) Build() (proto.Message, error) {
|
||||
if b.HealthCheck == nil {
|
||||
return nil, errors.New("BurstObservatory requires a valid pingConfig")
|
||||
}
|
||||
if result, err := b.HealthCheck.Build(); err == nil {
|
||||
return &burst.Config{SubjectSelector: b.SubjectSelector, PingConfig: result.(*burst.HealthPingConfig)}, nil
|
||||
} else {
|
||||
|
@@ -2,7 +2,6 @@ package conf
|
||||
|
||||
import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/app/observatory/burst"
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
@@ -52,23 +51,15 @@ type healthCheckSettings struct {
|
||||
Interval duration.Duration `json:"interval"`
|
||||
SamplingCount int `json:"sampling"`
|
||||
Timeout duration.Duration `json:"timeout"`
|
||||
HttpMethod string `json:"httpMethod"`
|
||||
}
|
||||
|
||||
func (h healthCheckSettings) Build() (proto.Message, error) {
|
||||
var httpMethod string
|
||||
if h.HttpMethod == "" {
|
||||
httpMethod = "HEAD"
|
||||
} else {
|
||||
httpMethod = strings.TrimSpace(h.HttpMethod)
|
||||
}
|
||||
return &burst.HealthPingConfig{
|
||||
Destination: h.Destination,
|
||||
Connectivity: h.Connectivity,
|
||||
Interval: int64(h.Interval),
|
||||
Timeout: int64(h.Timeout),
|
||||
SamplingCount: int32(h.SamplingCount),
|
||||
HttpMethod: httpMethod,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@@ -11,7 +11,6 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/cloudflare/circl/sign/mldsa/mldsa65"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
@@ -335,7 +334,7 @@ func (c *SplitHTTPConfig) Build() (proto.Message, error) {
|
||||
|
||||
func readFileOrString(f string, s []string) ([]byte, error) {
|
||||
if len(f) > 0 {
|
||||
return filesystem.ReadCert(f)
|
||||
return filesystem.ReadFile(f)
|
||||
}
|
||||
if len(s) > 0 {
|
||||
return []byte(strings.Join(s, "\n")), nil
|
||||
@@ -487,12 +486,6 @@ func (c *TLSConfig) Build() (proto.Message, error) {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
type LimitFallback struct {
|
||||
AfterBytes uint64
|
||||
BytesPerSec uint64
|
||||
BurstBytesPerSec uint64
|
||||
}
|
||||
|
||||
type REALITYConfig struct {
|
||||
MasterKeyLog string `json:"masterKeyLog"`
|
||||
Show bool `json:"show"`
|
||||
@@ -506,18 +499,12 @@ type REALITYConfig struct {
|
||||
MaxClientVer string `json:"maxClientVer"`
|
||||
MaxTimeDiff uint64 `json:"maxTimeDiff"`
|
||||
ShortIds []string `json:"shortIds"`
|
||||
Mldsa65Seed string `json:"mldsa65Seed"`
|
||||
|
||||
LimitFallbackUpload LimitFallback `json:"limitFallbackUpload"`
|
||||
LimitFallbackDownload LimitFallback `json:"limitFallbackDownload"`
|
||||
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
ServerName string `json:"serverName"`
|
||||
Password string `json:"password"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
ShortId string `json:"shortId"`
|
||||
Mldsa65Verify string `json:"mldsa65Verify"`
|
||||
SpiderX string `json:"spiderX"`
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
ServerName string `json:"serverName"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
ShortId string `json:"shortId"`
|
||||
SpiderX string `json:"spiderX"`
|
||||
}
|
||||
|
||||
func (c *REALITYConfig) Build() (proto.Message, error) {
|
||||
@@ -547,7 +534,7 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
|
||||
}
|
||||
default:
|
||||
if _, err = strconv.Atoi(s); err == nil {
|
||||
s = "localhost:" + s
|
||||
s = "127.0.0.1:" + s
|
||||
}
|
||||
if _, _, err = net.SplitHostPort(s); err == nil {
|
||||
c.Type = "tcp"
|
||||
@@ -612,22 +599,6 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
|
||||
config.Xver = c.Xver
|
||||
config.ServerNames = c.ServerNames
|
||||
config.MaxTimeDiff = c.MaxTimeDiff
|
||||
|
||||
if mldsa65Seed, err := base64.RawURLEncoding.DecodeString(c.Mldsa65Seed); err != nil || len(mldsa65Seed) != 32 {
|
||||
return nil, errors.New(`invalid "mldsa65Seed": `, c.Mldsa65Seed)
|
||||
} else {
|
||||
_, key := mldsa65.NewKeyFromSeed((*[32]byte)(mldsa65Seed))
|
||||
config.Mldsa65Key = key.Bytes()
|
||||
}
|
||||
|
||||
config.LimitFallbackUpload = new(reality.LimitFallback)
|
||||
config.LimitFallbackUpload.AfterBytes = c.LimitFallbackUpload.AfterBytes
|
||||
config.LimitFallbackUpload.BytesPerSec = c.LimitFallbackUpload.BytesPerSec
|
||||
config.LimitFallbackUpload.BurstBytesPerSec = c.LimitFallbackUpload.BurstBytesPerSec
|
||||
config.LimitFallbackDownload = new(reality.LimitFallback)
|
||||
config.LimitFallbackDownload.AfterBytes = c.LimitFallbackDownload.AfterBytes
|
||||
config.LimitFallbackDownload.BytesPerSec = c.LimitFallbackDownload.BytesPerSec
|
||||
config.LimitFallbackDownload.BurstBytesPerSec = c.LimitFallbackDownload.BurstBytesPerSec
|
||||
} else {
|
||||
config.Fingerprint = strings.ToLower(c.Fingerprint)
|
||||
if config.Fingerprint == "unsafe" || config.Fingerprint == "hellogolang" {
|
||||
@@ -639,14 +610,11 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
|
||||
if len(c.ServerNames) != 0 {
|
||||
return nil, errors.New(`non-empty "serverNames", please use "serverName" instead`)
|
||||
}
|
||||
if c.Password != "" {
|
||||
c.PublicKey = c.Password
|
||||
}
|
||||
if c.PublicKey == "" {
|
||||
return nil, errors.New(`empty "password"`)
|
||||
return nil, errors.New(`empty "publicKey"`)
|
||||
}
|
||||
if config.PublicKey, err = base64.RawURLEncoding.DecodeString(c.PublicKey); err != nil || len(config.PublicKey) != 32 {
|
||||
return nil, errors.New(`invalid "password": `, c.PublicKey)
|
||||
return nil, errors.New(`invalid "publicKey": `, c.PublicKey)
|
||||
}
|
||||
if len(c.ShortIds) != 0 {
|
||||
return nil, errors.New(`non-empty "shortIds", please use "shortId" instead`)
|
||||
@@ -655,9 +623,6 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
|
||||
if _, err = hex.Decode(config.ShortId, []byte(c.ShortId)); err != nil {
|
||||
return nil, errors.New(`invalid "shortId": `, c.ShortId)
|
||||
}
|
||||
if config.Mldsa65Verify, err = base64.RawURLEncoding.DecodeString(c.Mldsa65Verify); err != nil || len(config.Mldsa65Verify) != 1952 {
|
||||
return nil, errors.New(`invalid "mldsa65Verify": `, c.Mldsa65Verify)
|
||||
}
|
||||
if c.SpiderX == "" {
|
||||
c.SpiderX = "/"
|
||||
}
|
||||
@@ -722,58 +687,30 @@ func (p TransportProtocol) Build() (string, error) {
|
||||
}
|
||||
|
||||
type CustomSockoptConfig struct {
|
||||
Syetem string `json:"system"`
|
||||
Network string `json:"network"`
|
||||
Level string `json:"level"`
|
||||
Opt string `json:"opt"`
|
||||
Value string `json:"value"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type HappyEyeballsConfig struct {
|
||||
PrioritizeIPv6 bool `json:"prioritizeIPv6"`
|
||||
TryDelayMs uint64 `json:"tryDelayMs"`
|
||||
Interleave uint32 `json:"interleave"`
|
||||
MaxConcurrentTry uint32 `json:"maxConcurrentTry"`
|
||||
}
|
||||
|
||||
func (h *HappyEyeballsConfig) UnmarshalJSON(data []byte) error {
|
||||
var innerHappyEyeballsConfig = struct {
|
||||
PrioritizeIPv6 bool `json:"prioritizeIPv6"`
|
||||
TryDelayMs uint64 `json:"tryDelayMs"`
|
||||
Interleave uint32 `json:"interleave"`
|
||||
MaxConcurrentTry uint32 `json:"maxConcurrentTry"`
|
||||
}{PrioritizeIPv6: false, Interleave: 1, TryDelayMs: 0, MaxConcurrentTry: 4}
|
||||
if err := json.Unmarshal(data, &innerHappyEyeballsConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
h.PrioritizeIPv6 = innerHappyEyeballsConfig.PrioritizeIPv6
|
||||
h.TryDelayMs = innerHappyEyeballsConfig.TryDelayMs
|
||||
h.Interleave = innerHappyEyeballsConfig.Interleave
|
||||
h.MaxConcurrentTry = innerHappyEyeballsConfig.MaxConcurrentTry
|
||||
return nil
|
||||
Level string `json:"level"`
|
||||
Opt string `json:"opt"`
|
||||
Value string `json:"value"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type SocketConfig struct {
|
||||
Mark int32 `json:"mark"`
|
||||
TFO interface{} `json:"tcpFastOpen"`
|
||||
TProxy string `json:"tproxy"`
|
||||
AcceptProxyProtocol bool `json:"acceptProxyProtocol"`
|
||||
DomainStrategy string `json:"domainStrategy"`
|
||||
DialerProxy string `json:"dialerProxy"`
|
||||
TCPKeepAliveInterval int32 `json:"tcpKeepAliveInterval"`
|
||||
TCPKeepAliveIdle int32 `json:"tcpKeepAliveIdle"`
|
||||
TCPCongestion string `json:"tcpCongestion"`
|
||||
TCPWindowClamp int32 `json:"tcpWindowClamp"`
|
||||
TCPMaxSeg int32 `json:"tcpMaxSeg"`
|
||||
Penetrate bool `json:"penetrate"`
|
||||
TCPUserTimeout int32 `json:"tcpUserTimeout"`
|
||||
V6only bool `json:"v6only"`
|
||||
Interface string `json:"interface"`
|
||||
TcpMptcp bool `json:"tcpMptcp"`
|
||||
CustomSockopt []*CustomSockoptConfig `json:"customSockopt"`
|
||||
AddressPortStrategy string `json:"addressPortStrategy"`
|
||||
HappyEyeballsSettings *HappyEyeballsConfig `json:"happyEyeballs"`
|
||||
Mark int32 `json:"mark"`
|
||||
TFO interface{} `json:"tcpFastOpen"`
|
||||
TProxy string `json:"tproxy"`
|
||||
AcceptProxyProtocol bool `json:"acceptProxyProtocol"`
|
||||
DomainStrategy string `json:"domainStrategy"`
|
||||
DialerProxy string `json:"dialerProxy"`
|
||||
TCPKeepAliveInterval int32 `json:"tcpKeepAliveInterval"`
|
||||
TCPKeepAliveIdle int32 `json:"tcpKeepAliveIdle"`
|
||||
TCPCongestion string `json:"tcpCongestion"`
|
||||
TCPWindowClamp int32 `json:"tcpWindowClamp"`
|
||||
TCPMaxSeg int32 `json:"tcpMaxSeg"`
|
||||
Penetrate bool `json:"penetrate"`
|
||||
TCPUserTimeout int32 `json:"tcpUserTimeout"`
|
||||
V6only bool `json:"v6only"`
|
||||
Interface string `json:"interface"`
|
||||
TcpMptcp bool `json:"tcpMptcp"`
|
||||
CustomSockopt []*CustomSockoptConfig `json:"customSockopt"`
|
||||
}
|
||||
|
||||
// Build implements Buildable.
|
||||
@@ -835,44 +772,14 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
|
||||
|
||||
for _, copt := range c.CustomSockopt {
|
||||
customSockopt := &internet.CustomSockopt{
|
||||
System: copt.Syetem,
|
||||
Network: copt.Network,
|
||||
Level: copt.Level,
|
||||
Opt: copt.Opt,
|
||||
Value: copt.Value,
|
||||
Type: copt.Type,
|
||||
Level: copt.Level,
|
||||
Opt: copt.Opt,
|
||||
Value: copt.Value,
|
||||
Type: copt.Type,
|
||||
}
|
||||
customSockopts = append(customSockopts, customSockopt)
|
||||
}
|
||||
|
||||
addressPortStrategy := internet.AddressPortStrategy_None
|
||||
switch strings.ToLower(c.AddressPortStrategy) {
|
||||
case "none", "":
|
||||
addressPortStrategy = internet.AddressPortStrategy_None
|
||||
case "srvportonly":
|
||||
addressPortStrategy = internet.AddressPortStrategy_SrvPortOnly
|
||||
case "srvaddressonly":
|
||||
addressPortStrategy = internet.AddressPortStrategy_SrvAddressOnly
|
||||
case "srvportandaddress":
|
||||
addressPortStrategy = internet.AddressPortStrategy_SrvPortAndAddress
|
||||
case "txtportonly":
|
||||
addressPortStrategy = internet.AddressPortStrategy_TxtPortOnly
|
||||
case "txtaddressonly":
|
||||
addressPortStrategy = internet.AddressPortStrategy_TxtAddressOnly
|
||||
case "txtportandaddress":
|
||||
addressPortStrategy = internet.AddressPortStrategy_TxtPortAndAddress
|
||||
default:
|
||||
return nil, errors.New("unsupported address and port strategy: ", c.AddressPortStrategy)
|
||||
}
|
||||
|
||||
var happyEyeballs = &internet.HappyEyeballsConfig{Interleave: 1, PrioritizeIpv6: false, TryDelayMs: 0, MaxConcurrentTry: 4}
|
||||
if c.HappyEyeballsSettings != nil {
|
||||
happyEyeballs.PrioritizeIpv6 = c.HappyEyeballsSettings.PrioritizeIPv6
|
||||
happyEyeballs.Interleave = c.HappyEyeballsSettings.Interleave
|
||||
happyEyeballs.TryDelayMs = c.HappyEyeballsSettings.TryDelayMs
|
||||
happyEyeballs.MaxConcurrentTry = c.HappyEyeballsSettings.MaxConcurrentTry
|
||||
}
|
||||
|
||||
return &internet.SocketConfig{
|
||||
Mark: c.Mark,
|
||||
Tfo: tfo,
|
||||
@@ -891,8 +798,6 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
|
||||
Interface: c.Interface,
|
||||
TcpMptcp: c.TcpMptcp,
|
||||
CustomSockopt: customSockopts,
|
||||
AddressPortStrategy: addressPortStrategy,
|
||||
HappyEyeballs: happyEyeballs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@@ -26,7 +26,6 @@ func TestSocketConfig(t *testing.T) {
|
||||
Tfo: 256,
|
||||
DomainStrategy: internet.DomainStrategy_USE_IP,
|
||||
DialerProxy: "tag",
|
||||
HappyEyeballs: &internet.HappyEyeballsConfig{Interleave: 1, TryDelayMs: 0, PrioritizeIpv6: false, MaxConcurrentTry: 4},
|
||||
}
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
@@ -46,9 +45,8 @@ func TestSocketConfig(t *testing.T) {
|
||||
|
||||
// test "tcpFastOpen": false, disabled TFO is expected
|
||||
expectedOutput = &internet.SocketConfig{
|
||||
Mark: 0,
|
||||
Tfo: -1,
|
||||
HappyEyeballs: &internet.HappyEyeballsConfig{Interleave: 1, TryDelayMs: 0, PrioritizeIpv6: false, MaxConcurrentTry: 4},
|
||||
Mark: 0,
|
||||
Tfo: -1,
|
||||
}
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
@@ -65,9 +63,8 @@ func TestSocketConfig(t *testing.T) {
|
||||
|
||||
// test "tcpFastOpen": 65535, queue length 65535 is expected
|
||||
expectedOutput = &internet.SocketConfig{
|
||||
Mark: 0,
|
||||
Tfo: 65535,
|
||||
HappyEyeballs: &internet.HappyEyeballsConfig{Interleave: 1, TryDelayMs: 0, PrioritizeIpv6: false, MaxConcurrentTry: 4},
|
||||
Mark: 0,
|
||||
Tfo: 65535,
|
||||
}
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
@@ -84,9 +81,8 @@ func TestSocketConfig(t *testing.T) {
|
||||
|
||||
// test "tcpFastOpen": -65535, disable TFO is expected
|
||||
expectedOutput = &internet.SocketConfig{
|
||||
Mark: 0,
|
||||
Tfo: -65535,
|
||||
HappyEyeballs: &internet.HappyEyeballsConfig{Interleave: 1, TryDelayMs: 0, PrioritizeIpv6: false, MaxConcurrentTry: 4},
|
||||
Mark: 0,
|
||||
Tfo: -65535,
|
||||
}
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
@@ -103,9 +99,8 @@ func TestSocketConfig(t *testing.T) {
|
||||
|
||||
// test "tcpFastOpen": 0, no operation is expected
|
||||
expectedOutput = &internet.SocketConfig{
|
||||
Mark: 0,
|
||||
Tfo: 0,
|
||||
HappyEyeballs: &internet.HappyEyeballsConfig{Interleave: 1, TryDelayMs: 0, PrioritizeIpv6: false, MaxConcurrentTry: 4},
|
||||
Mark: 0,
|
||||
Tfo: 0,
|
||||
}
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
@@ -122,9 +117,8 @@ func TestSocketConfig(t *testing.T) {
|
||||
|
||||
// test omit "tcpFastOpen", no operation is expected
|
||||
expectedOutput = &internet.SocketConfig{
|
||||
Mark: 0,
|
||||
Tfo: 0,
|
||||
HappyEyeballs: &internet.HappyEyeballsConfig{Interleave: 1, TryDelayMs: 0, PrioritizeIpv6: false, MaxConcurrentTry: 4},
|
||||
Mark: 0,
|
||||
Tfo: 0,
|
||||
}
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
@@ -139,9 +133,8 @@ func TestSocketConfig(t *testing.T) {
|
||||
|
||||
// test "tcpFastOpen": null, no operation is expected
|
||||
expectedOutput = &internet.SocketConfig{
|
||||
Mark: 0,
|
||||
Tfo: 0,
|
||||
HappyEyeballs: &internet.HappyEyeballsConfig{Interleave: 1, TryDelayMs: 0, PrioritizeIpv6: false, MaxConcurrentTry: 4},
|
||||
Mark: 0,
|
||||
Tfo: 0,
|
||||
}
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
|
@@ -155,7 +155,7 @@ func (c *TrojanServerConfig) Build() (proto.Message, error) {
|
||||
}
|
||||
} else {
|
||||
if _, err := strconv.Atoi(fb.Dest); err == nil {
|
||||
fb.Dest = "localhost:" + fb.Dest
|
||||
fb.Dest = "127.0.0.1:" + fb.Dest
|
||||
}
|
||||
if _, _, err := net.SplitHostPort(fb.Dest); err == nil {
|
||||
fb.Type = "tcp"
|
||||
|
@@ -111,7 +111,7 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
||||
}
|
||||
} else {
|
||||
if _, err := strconv.Atoi(fb.Dest); err == nil {
|
||||
fb.Dest = "localhost:" + fb.Dest
|
||||
fb.Dest = "127.0.0.1:" + fb.Dest
|
||||
}
|
||||
if _, _, err := net.SplitHostPort(fb.Dest); err == nil {
|
||||
fb.Type = "tcp"
|
||||
|
@@ -110,7 +110,7 @@ func TestVLessInbound(t *testing.T) {
|
||||
Alpn: "",
|
||||
Path: "",
|
||||
Type: "tcp",
|
||||
Dest: "localhost:80",
|
||||
Dest: "127.0.0.1:80",
|
||||
Xver: 0,
|
||||
},
|
||||
{
|
||||
|
@@ -67,7 +67,7 @@ func (c *WireGuardConfig) Build() (proto.Message, error) {
|
||||
var err error
|
||||
config.SecretKey, err = ParseWireGuardKey(c.SecretKey)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid WireGuard secret key: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.Address == nil {
|
||||
@@ -126,10 +126,6 @@ func (c *WireGuardConfig) Build() (proto.Message, error) {
|
||||
func ParseWireGuardKey(str string) (string, error) {
|
||||
var err error
|
||||
|
||||
if str == "" {
|
||||
return "", errors.New("key must not be empty")
|
||||
}
|
||||
|
||||
if len(str)%2 == 0 {
|
||||
_, err = hex.DecodeString(str)
|
||||
if err == nil {
|
||||
|
@@ -55,6 +55,7 @@ type SniffingConfig struct {
|
||||
DomainsExcluded *StringList `json:"domainsExcluded"`
|
||||
MetadataOnly bool `json:"metadataOnly"`
|
||||
RouteOnly bool `json:"routeOnly"`
|
||||
Timeout int64 `json:"timeout"`
|
||||
}
|
||||
|
||||
// Build implements Buildable.
|
||||
@@ -69,8 +70,10 @@ func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {
|
||||
p = append(p, "tls")
|
||||
case "quic":
|
||||
p = append(p, "quic")
|
||||
case "fakedns", "fakedns+others":
|
||||
case "fakedns":
|
||||
p = append(p, "fakedns")
|
||||
case "fakedns+others":
|
||||
p = append(p, "fakedns+others")
|
||||
default:
|
||||
return nil, errors.New("unknown protocol: ", protocol)
|
||||
}
|
||||
@@ -90,6 +93,7 @@ func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {
|
||||
DomainsExcluded: d,
|
||||
MetadataOnly: c.MetadataOnly,
|
||||
RouteOnly: c.RouteOnly,
|
||||
Timeout: c.Timeout,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -239,14 +243,14 @@ func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
|
||||
}
|
||||
rawConfig, err := inboundConfigLoader.LoadWithID(settings, c.Protocol)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to load inbound detour config for protocol ", c.Protocol).Base(err)
|
||||
return nil, errors.New("failed to load inbound detour config.").Base(err)
|
||||
}
|
||||
if dokodemoConfig, ok := rawConfig.(*DokodemoConfig); ok {
|
||||
receiverSettings.ReceiveOriginalDestination = dokodemoConfig.Redirect
|
||||
}
|
||||
ts, err := rawConfig.(Buildable).Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build inbound handler for protocol ", c.Protocol).Base(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &core.InboundHandlerConfig{
|
||||
@@ -290,8 +294,7 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
||||
senderSettings.ViaCidr = strings.Split(*c.SendThrough, "/")[1]
|
||||
} else {
|
||||
if address.Family().IsDomain() {
|
||||
domain := address.Address.Domain()
|
||||
if domain != "origin" && domain != "srcip" {
|
||||
if address.Address.Domain() != "origin" {
|
||||
return nil, errors.New("unable to send through: " + address.String())
|
||||
}
|
||||
}
|
||||
@@ -302,7 +305,7 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
||||
if c.StreamSetting != nil {
|
||||
ss, err := c.StreamSetting.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build stream settings for outbound detour").Base(err)
|
||||
return nil, err
|
||||
}
|
||||
senderSettings.StreamSettings = ss
|
||||
}
|
||||
@@ -310,7 +313,7 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
||||
if c.ProxySettings != nil {
|
||||
ps, err := c.ProxySettings.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid outbound detour proxy settings").Base(err)
|
||||
return nil, errors.New("invalid outbound detour proxy settings.").Base(err)
|
||||
}
|
||||
if ps.TransportLayerProxy {
|
||||
if senderSettings.StreamSettings != nil {
|
||||
@@ -330,7 +333,7 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
||||
if c.MuxSettings != nil {
|
||||
ms, err := c.MuxSettings.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build Mux config").Base(err)
|
||||
return nil, errors.New("failed to build Mux config.").Base(err)
|
||||
}
|
||||
senderSettings.MultiplexSettings = ms
|
||||
}
|
||||
@@ -341,11 +344,11 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
||||
}
|
||||
rawConfig, err := outboundConfigLoader.LoadWithID(settings, c.Protocol)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to load outbound detour config for protocol ", c.Protocol).Base(err)
|
||||
return nil, errors.New("failed to parse to outbound detour config.").Base(err)
|
||||
}
|
||||
ts, err := rawConfig.(Buildable).Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build outbound handler for protocol ", c.Protocol).Base(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &core.OutboundHandlerConfig{
|
||||
@@ -489,7 +492,7 @@ func (c *Config) Override(o *Config, fn string) {
|
||||
// Build implements Buildable.
|
||||
func (c *Config) Build() (*core.Config, error) {
|
||||
if err := PostProcessConfigureFile(c); err != nil {
|
||||
return nil, errors.New("failed to post-process configuration file").Base(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config := &core.Config{
|
||||
@@ -503,21 +506,21 @@ func (c *Config) Build() (*core.Config, error) {
|
||||
if c.API != nil {
|
||||
apiConf, err := c.API.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build API configuration").Base(err)
|
||||
return nil, err
|
||||
}
|
||||
config.App = append(config.App, serial.ToTypedMessage(apiConf))
|
||||
}
|
||||
if c.Metrics != nil {
|
||||
metricsConf, err := c.Metrics.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build metrics configuration").Base(err)
|
||||
return nil, err
|
||||
}
|
||||
config.App = append(config.App, serial.ToTypedMessage(metricsConf))
|
||||
}
|
||||
if c.Stats != nil {
|
||||
statsConf, err := c.Stats.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build stats configuration").Base(err)
|
||||
return nil, err
|
||||
}
|
||||
config.App = append(config.App, serial.ToTypedMessage(statsConf))
|
||||
}
|
||||
@@ -535,7 +538,7 @@ func (c *Config) Build() (*core.Config, error) {
|
||||
if c.RouterConfig != nil {
|
||||
routerConfig, err := c.RouterConfig.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build routing configuration").Base(err)
|
||||
return nil, err
|
||||
}
|
||||
config.App = append(config.App, serial.ToTypedMessage(routerConfig))
|
||||
}
|
||||
@@ -543,7 +546,7 @@ func (c *Config) Build() (*core.Config, error) {
|
||||
if c.DNSConfig != nil {
|
||||
dnsApp, err := c.DNSConfig.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build DNS configuration").Base(err)
|
||||
return nil, errors.New("failed to parse DNS config").Base(err)
|
||||
}
|
||||
config.App = append(config.App, serial.ToTypedMessage(dnsApp))
|
||||
}
|
||||
@@ -551,7 +554,7 @@ func (c *Config) Build() (*core.Config, error) {
|
||||
if c.Policy != nil {
|
||||
pc, err := c.Policy.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build policy configuration").Base(err)
|
||||
return nil, err
|
||||
}
|
||||
config.App = append(config.App, serial.ToTypedMessage(pc))
|
||||
}
|
||||
@@ -559,7 +562,7 @@ func (c *Config) Build() (*core.Config, error) {
|
||||
if c.Reverse != nil {
|
||||
r, err := c.Reverse.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build reverse configuration").Base(err)
|
||||
return nil, err
|
||||
}
|
||||
config.App = append(config.App, serial.ToTypedMessage(r))
|
||||
}
|
||||
@@ -567,7 +570,7 @@ func (c *Config) Build() (*core.Config, error) {
|
||||
if c.FakeDNS != nil {
|
||||
r, err := c.FakeDNS.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build fake DNS configuration").Base(err)
|
||||
return nil, err
|
||||
}
|
||||
config.App = append([]*serial.TypedMessage{serial.ToTypedMessage(r)}, config.App...)
|
||||
}
|
||||
@@ -575,7 +578,7 @@ func (c *Config) Build() (*core.Config, error) {
|
||||
if c.Observatory != nil {
|
||||
r, err := c.Observatory.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build observatory configuration").Base(err)
|
||||
return nil, err
|
||||
}
|
||||
config.App = append(config.App, serial.ToTypedMessage(r))
|
||||
}
|
||||
@@ -583,7 +586,7 @@ func (c *Config) Build() (*core.Config, error) {
|
||||
if c.BurstObservatory != nil {
|
||||
r, err := c.BurstObservatory.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build burst observatory configuration").Base(err)
|
||||
return nil, err
|
||||
}
|
||||
config.App = append(config.App, serial.ToTypedMessage(r))
|
||||
}
|
||||
@@ -601,7 +604,7 @@ func (c *Config) Build() (*core.Config, error) {
|
||||
for _, rawInboundConfig := range inbounds {
|
||||
ic, err := rawInboundConfig.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build inbound config with tag ", rawInboundConfig.Tag).Base(err)
|
||||
return nil, err
|
||||
}
|
||||
config.Inbound = append(config.Inbound, ic)
|
||||
}
|
||||
@@ -615,7 +618,7 @@ func (c *Config) Build() (*core.Config, error) {
|
||||
for _, rawOutboundConfig := range outbounds {
|
||||
oc, err := rawOutboundConfig.Build()
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build outbound config with tag ", rawOutboundConfig.Tag).Base(err)
|
||||
return nil, err
|
||||
}
|
||||
config.Outbound = append(config.Outbound, oc)
|
||||
}
|
||||
|
@@ -89,11 +89,12 @@ func whichProtoc(suffix, targetedVersion string) (string, error) {
|
||||
|
||||
path, err := exec.LookPath(protoc)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(`
|
||||
errStr := fmt.Sprintf(`
|
||||
Command "%s" not found.
|
||||
Make sure that %s is in your system path or current path.
|
||||
Download %s v%s or later from https://github.com/protocolbuffers/protobuf/releases
|
||||
`, protoc, protoc, protoc, targetedVersion)
|
||||
return "", fmt.Errorf(errStr)
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
@@ -21,8 +21,6 @@ var CmdAPI = &base.Command{
|
||||
cmdAddOutbounds,
|
||||
cmdRemoveInbounds,
|
||||
cmdRemoveOutbounds,
|
||||
cmdListInbounds,
|
||||
cmdListOutbounds,
|
||||
cmdInboundUser,
|
||||
cmdInboundUserCount,
|
||||
cmdAddRules,
|
||||
|
@@ -1,47 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
handlerService "github.com/xtls/xray-core/app/proxyman/command"
|
||||
"github.com/xtls/xray-core/main/commands/base"
|
||||
)
|
||||
|
||||
var cmdListInbounds = &base.Command{
|
||||
CustomFlags: true,
|
||||
UsageLine: "{{.Exec}} api lsi [--server=127.0.0.1:8080] [--isOnlyTags=true]",
|
||||
Short: "List inbounds",
|
||||
Long: `
|
||||
List inbounds 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: executeListInbounds,
|
||||
}
|
||||
|
||||
func executeListInbounds(cmd *base.Command, args []string) {
|
||||
setSharedFlags(cmd)
|
||||
var isOnlyTagsStr string
|
||||
cmd.Flag.StringVar(&isOnlyTagsStr, "isOnlyTags", "", "")
|
||||
cmd.Flag.Parse(args)
|
||||
isOnlyTags := isOnlyTagsStr == "true"
|
||||
|
||||
conn, ctx, close := dialAPIServer()
|
||||
defer close()
|
||||
|
||||
client := handlerService.NewHandlerServiceClient(conn)
|
||||
|
||||
resp, err := client.ListInbounds(ctx, &handlerService.ListInboundsRequest{IsOnlyTags: isOnlyTags})
|
||||
if err != nil {
|
||||
base.Fatalf("failed to list inbounds: %s", err)
|
||||
}
|
||||
showJSONResponse(resp)
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
handlerService "github.com/xtls/xray-core/app/proxyman/command"
|
||||
"github.com/xtls/xray-core/main/commands/base"
|
||||
)
|
||||
|
||||
var cmdListOutbounds = &base.Command{
|
||||
CustomFlags: true,
|
||||
UsageLine: "{{.Exec}} api lso [--server=127.0.0.1:8080]",
|
||||
Short: "List outbounds",
|
||||
Long: `
|
||||
List outbounds 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: executeListOutbounds,
|
||||
}
|
||||
|
||||
func executeListOutbounds(cmd *base.Command, args []string) {
|
||||
setSharedFlags(cmd)
|
||||
cmd.Flag.Parse(args)
|
||||
|
||||
conn, ctx, close := dialAPIServer()
|
||||
defer close()
|
||||
|
||||
client := handlerService.NewHandlerServiceClient(conn)
|
||||
resp, err := client.ListOutbounds(ctx, &handlerService.ListOutboundsRequest{})
|
||||
if err != nil {
|
||||
base.Fatalf("failed to list outbounds: %s", err)
|
||||
}
|
||||
showJSONResponse(resp)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user