Compare commits

..

1 Commits

Author SHA1 Message Date
yuhan6665
3ed502abbb Try fix OnlineMap SIGSEGV and simplify code 2024-12-30 16:42:33 -05:00
109 changed files with 1265 additions and 2287 deletions

View File

@@ -1,5 +1,11 @@
name: Build and Release for Windows 7 name: Build and Release for Windows 7
# NOTE: This Github Actions file depends on the Makefile.
# Building the correct package requires the correct binaries generated by the Makefile. To
# ensure the correct output, the Makefile must accept the appropriate input and compile the
# correct file with the correct name. If you need to modify this file, please ensure it won't
# disrupt the Makefile.
on: on:
workflow_dispatch: workflow_dispatch:
release: release:
@@ -9,7 +15,51 @@ on:
types: [opened, synchronize, reopened] types: [opened, synchronize, reopened]
jobs: jobs:
prepare:
runs-on: ubuntu-latest
steps:
- name: Restore Cache
uses: actions/cache/restore@v4
with:
path: resources
key: xray-geodat-
- name: Update Geodat
id: update
uses: nick-fields/retry@v3
with:
timeout_minutes: 60
retry_wait_seconds: 60
max_attempts: 60
command: |
[ -d 'resources' ] || mkdir resources
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite')
for i in "${LIST[@]}"
do
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3}'))
FILE_NAME="${INFO[2]}.dat"
echo -e "Verifying HASH key..."
HASH="$(curl -sL "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.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/v2fly/${INFO[0]}/release/${INFO[1]}.dat..."
curl -L "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.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
fi
done
- name: Save Cache
uses: actions/cache/save@v4
if: ${{ steps.update.outputs.unhit }}
with:
path: resources
key: xray-geodat-${{ github.sha }}-${{ github.run_number }}
build: build:
needs: prepare
permissions: permissions:
contents: write contents: write
strategy: strategy:
@@ -31,9 +81,6 @@ jobs:
GOARCH: ${{ matrix.goarch }} GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: 0 CGO_ENABLED: 0
steps: steps:
- name: Checkout codebase
uses: actions/checkout@v4
- name: Show workflow information - name: Show workflow information
run: | run: |
_NAME=${{ matrix.assetname }} _NAME=${{ matrix.assetname }}
@@ -43,17 +90,18 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version: stable
check-latest: true check-latest: true
- name: Setup patched builder - name: Setup patched builder
run: | run: |
GOSDK=$(go env GOROOT) GOSDK=$(go env GOROOT)
rm -r $GOSDK/*
cd $GOSDK
curl -O -L https://github.com/XTLS/go-win7/releases/latest/download/go-for-win7-linux-amd64.zip curl -O -L https://github.com/XTLS/go-win7/releases/latest/download/go-for-win7-linux-amd64.zip
rm -r $GOSDK/*
unzip ./go-for-win7-linux-amd64.zip -d $GOSDK unzip ./go-for-win7-linux-amd64.zip -d $GOSDK
rm ./go-for-win7-linux-amd64.zip
- name: Checkout codebase
uses: actions/checkout@v4
- name: Get project dependencies - name: Get project dependencies
run: go mod download run: go mod download
@@ -61,15 +109,10 @@ jobs:
- name: Build Xray - name: Build Xray
run: | run: |
mkdir -p build_assets mkdir -p build_assets
COMMID=$(git describe --always --dirty) make
echo 'Building Xray for Windows 7...' find . -maxdepth 1 -type f -regex './\(wxray\|xray\).exe' -exec mv {} ./build_assets/ \;
go build -o build_assets/xray.exe -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
echo 'CreateObject("Wscript.Shell").Run "xray.exe -config config.json",0' > build_assets/xray_no_window.vbs
echo 'Start-Process -FilePath ".\xray.exe" -ArgumentList "-config .\config.json" -WindowStyle Hidden' > build_assets/xray_no_window.ps1
# The line below is for without running conhost.exe version. Commented for not being used. Provided for reference.
# go build -o build_assets/wxray.exe -trimpath -buildvcs=false -ldflags="-H windowsgui -X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
- name: Restore Geodat Cache - name: Restore Cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
with: with:
path: resources path: resources

View File

@@ -1,5 +1,11 @@
name: Build and Release name: Build and Release
# NOTE: This Github Actions file depends on the Makefile.
# Building the correct package requires the correct binaries generated by the Makefile. To
# ensure the correct output, the Makefile must accept the appropriate input and compile the
# correct file with the correct name. If you need to modify this file, please ensure it won't
# disrupt the Makefile.
on: on:
workflow_dispatch: workflow_dispatch:
release: release:
@@ -9,7 +15,51 @@ on:
types: [opened, synchronize, reopened] types: [opened, synchronize, reopened]
jobs: jobs:
prepare:
runs-on: ubuntu-latest
steps:
- name: Restore Cache
uses: actions/cache/restore@v4
with:
path: resources
key: xray-geodat-
- name: Update Geodat
id: update
uses: nick-fields/retry@v3
with:
timeout_minutes: 60
retry_wait_seconds: 60
max_attempts: 60
command: |
[ -d 'resources' ] || mkdir resources
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite')
for i in "${LIST[@]}"
do
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3}'))
FILE_NAME="${INFO[2]}.dat"
echo -e "Verifying HASH key..."
HASH="$(curl -sL "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.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/v2fly/${INFO[0]}/release/${INFO[1]}.dat..."
curl -L "https://raw.githubusercontent.com/v2fly/${INFO[0]}/release/${INFO[1]}.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
fi
done
- name: Save Cache
uses: actions/cache/save@v4
if: ${{ steps.update.outputs.unhit }}
with:
path: resources
key: xray-geodat-${{ github.sha }}-${{ github.run_number }}
build: build:
needs: prepare
permissions: permissions:
contents: write contents: write
strategy: strategy:
@@ -123,24 +173,10 @@ jobs:
- name: Build Xray - name: Build Xray
run: | run: |
mkdir -p build_assets mkdir -p build_assets
COMMID=$(git describe --always --dirty) make
if [[ ${GOOS} == 'windows' ]]; then find . -maxdepth 1 -type f -regex './\(wxray\|xray\|xray_softfloat\)\(\|.exe\)' -exec mv {} ./build_assets/ \;
echo 'Building Xray for Windows...'
go build -o build_assets/xray.exe -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
echo 'CreateObject("Wscript.Shell").Run "xray.exe -config config.json",0' > build_assets/xray_no_window.vbs
echo 'Start-Process -FilePath ".\xray.exe" -ArgumentList "-config .\config.json" -WindowStyle Hidden' > build_assets/xray_no_window.ps1
# The line below is for without running conhost.exe version. Commented for not being used. Provided for reference.
# go build -o build_assets/wxray.exe -trimpath -buildvcs=false -ldflags="-H windowsgui -X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
else
echo 'Building Xray...'
go build -o build_assets/xray -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
if [[ ${GOARCH} == 'mips' || ${GOARCH} == 'mipsle' ]]; then
echo 'Building soft-float Xray for MIPS/MIPSLE 32-bit...'
GOMIPS=softfloat go build -o build_assets/xray_softfloat -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=${COMMID} -s -w -buildid=" -v ./main
fi
fi
- name: Restore Geodat Cache - name: Restore Cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
with: with:
path: resources path: resources

View File

@@ -1,65 +0,0 @@
name: Scheduled assets update
# 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)
on:
workflow_dispatch:
schedule:
# Update GeoData on every day (22:30 UTC)
- cron: '30 22 * * *'
push:
# Prevent triggering update request storm
paths:
- ".github/workflows/scheduled-assets-update.yml"
pull_request:
# Prevent triggering update request storm
paths:
- ".github/workflows/scheduled-assets-update.yml"
jobs:
geodat:
if: github.event.schedule == '30 22 * * *' || github.event_name == 'push'|| github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- name: Restore Geodat Cache
uses: actions/cache/restore@v4
with:
path: resources
key: xray-geodat-
- name: Update Geodat
id: update
uses: nick-fields/retry@v3
with:
timeout_minutes: 60
retry_wait_seconds: 60
max_attempts: 60
command: |
[ -d 'resources' ] || mkdir resources
LIST=('Loyalsoldier v2ray-rules-dat geoip geoip' 'Loyalsoldier v2ray-rules-dat geosite geosite')
for i in "${LIST[@]}"
do
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3,$4}'))
FILE_NAME="${INFO[3]}.dat"
echo -e "Verifying HASH key..."
HASH="$(curl -sL "https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
if [ -s "./resources/${FILE_NAME}" ] && [ "$(sha256sum "./resources/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ]; then
continue
else
echo -e "Downloading https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat..."
curl -L "https://raw.githubusercontent.com/${INFO[0]}/${INFO[1]}/release/${INFO[2]}.dat" -o ./resources/${FILE_NAME}
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
fi
done
- name: Save Geodat Cache
uses: actions/cache/save@v4
if: ${{ steps.update.outputs.unhit }}
with:
path: resources
key: xray-geodat-${{ github.sha }}-${{ github.run_number }}

View File

@@ -22,7 +22,7 @@ jobs:
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- name: Restore Geodat Cache - name: Restore Cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
with: with:
path: resources path: resources

37
Makefile Normal file
View File

@@ -0,0 +1,37 @@
NAME = xray
VERSION=$(shell git describe --always --dirty)
# NOTE: This MAKEFILE can be used to build Xray-core locally and in Automatic workflows. It is \
provided for convenience in automatic building and functions as a part of it.
# NOTE: If you need to modify this file, please be aware that:\
- This file is not the main Makefile; it only accepts environment variables and builds the \
binary.\
- Automatic building expects the correct binaries to be built by this Makefile. If you \
intend to propose a change to this Makefile, carefully review the file below and ensure \
that the change will not accidentally break the automatic building:\
.github/workflows/release.yml \
Otherwise it is recommended to contact the project maintainers.
LDFLAGS = -X github.com/xtls/xray-core/core.build=$(VERSION) -s -w -buildid=
PARAMS = -trimpath -ldflags "$(LDFLAGS)" -v
MAIN = ./main
PREFIX ?= $(shell go env GOPATH)
ifeq ($(GOOS),windows)
OUTPUT = $(NAME).exe
ADDITION = go build -o w$(NAME).exe -trimpath -ldflags "-H windowsgui $(LDFLAGS)" -v $(MAIN)
else
OUTPUT = $(NAME)
endif
ifeq ($(shell echo "$(GOARCH)" | grep -Eq "(mips|mipsle)" && echo true),true) #
ADDITION = GOMIPS=softfloat go build -o $(NAME)_softfloat -trimpath -ldflags "$(LDFLAGS)" -v $(MAIN)
endif
.PHONY: clean build
build:
go build -o $(OUTPUT) $(PARAMS) $(MAIN)
$(ADDITION)
clean:
go clean -v -i $(PWD)
rm -f xray xray.exe wxray.exe xray_softfloat

View File

@@ -24,9 +24,7 @@
[Project X Channel](https://t.me/projectXtls) [Project X Channel](https://t.me/projectXtls)
[Project VLESS](https://t.me/projectVless) (Русский) [Project VLESS](https://t.me/projectVless) (non-Chinese)
[Project XHTTP](https://t.me/projectXhttp) (Persian)
## Installation ## Installation
@@ -74,8 +72,6 @@
- [PassWall](https://github.com/xiaorouji/openwrt-passwall), [PassWall 2](https://github.com/xiaorouji/openwrt-passwall2) - [PassWall](https://github.com/xiaorouji/openwrt-passwall), [PassWall 2](https://github.com/xiaorouji/openwrt-passwall2)
- [ShadowSocksR Plus+](https://github.com/fw876/helloworld) - [ShadowSocksR Plus+](https://github.com/fw876/helloworld)
- [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray)) - [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray))
- Asuswrt-Merlin
- [XRAYUI](https://github.com/DanielLavrushin/asuswrt-merlin-xrayui)
- Windows - Windows
- [v2rayN](https://github.com/2dust/v2rayN) - [v2rayN](https://github.com/2dust/v2rayN)
- [Furious](https://github.com/LorenEteval/Furious) - [Furious](https://github.com/LorenEteval/Furious)
@@ -102,7 +98,6 @@
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118) - [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
- Xray Tools - Xray Tools
- [xray-knife](https://github.com/lilendian0x00/xray-knife) - [xray-knife](https://github.com/lilendian0x00/xray-knife)
- [xray-checker](https://github.com/kutovoys/xray-checker)
- Xray Wrapper - Xray Wrapper
- [XTLS/libXray](https://github.com/XTLS/libXray) - [XTLS/libXray](https://github.com/XTLS/libXray)
- [xtlsapi](https://github.com/hiddify/xtlsapi) - [xtlsapi](https://github.com/hiddify/xtlsapi)
@@ -126,27 +121,25 @@
- [Xray-core v1.0.0](https://github.com/XTLS/Xray-core/releases/tag/v1.0.0) was forked from [v2fly-core 9a03cc5](https://github.com/v2fly/v2ray-core/commit/9a03cc5c98d04cc28320fcee26dbc236b3291256), and we have made & accumulated a huge number of enhancements over time, check [the release notes for each version](https://github.com/XTLS/Xray-core/releases). - [Xray-core v1.0.0](https://github.com/XTLS/Xray-core/releases/tag/v1.0.0) was forked from [v2fly-core 9a03cc5](https://github.com/v2fly/v2ray-core/commit/9a03cc5c98d04cc28320fcee26dbc236b3291256), and we have made & accumulated a huge number of enhancements over time, check [the release notes for each version](https://github.com/XTLS/Xray-core/releases).
- For third-party projects used in [Xray-core](https://github.com/XTLS/Xray-core), check your local or [the latest go.mod](https://github.com/XTLS/Xray-core/blob/main/go.mod). - For third-party projects used in [Xray-core](https://github.com/XTLS/Xray-core), check your local or [the latest go.mod](https://github.com/XTLS/Xray-core/blob/main/go.mod).
## One-line Compilation ## Compilation
### Windows (PowerShell) ### Windows (PowerShell)
```powershell ```powershell
$env:CGO_ENABLED=0 $env:CGO_ENABLED=0
go build -o xray.exe -trimpath -buildvcs=false -ldflags="-s -w -buildid=" -v ./main go build -o xray.exe -trimpath -ldflags "-s -w -buildid=" ./main
``` ```
### Linux / macOS ### Linux / macOS
```bash ```bash
CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -ldflags="-s -w -buildid=" -v ./main CGO_ENABLED=0 go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
``` ```
### Reproducible Releases ### Reproducible Releases
Make sure that you are using the same Go version, and remember to set the git commit id (7 bytes):
```bash ```bash
CGO_ENABLED=0 go build -o xray -trimpath -buildvcs=false -ldflags="-X github.com/xtls/xray-core/core.build=REPLACE -s -w -buildid=" -v ./main make
``` ```
## Stargazers over time ## Stargazers over time

View File

@@ -43,15 +43,11 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis
} }
switch { switch {
case strings.EqualFold(u.String(), "localhost"): case strings.EqualFold(u.String(), "localhost"):
return NewLocalNameServer(queryStrategy), nil return NewLocalNameServer(), nil
case strings.EqualFold(u.Scheme, "https"): // DNS-over-HTTPS Remote mode case strings.EqualFold(u.Scheme, "https"): // DOH Remote mode
return NewDoHNameServer(u, queryStrategy, dispatcher, false), nil return NewDoHNameServer(u, dispatcher, queryStrategy)
case strings.EqualFold(u.Scheme, "h2c"): // DNS-over-HTTPS h2c Remote mode case strings.EqualFold(u.Scheme, "https+local"): // DOH Local mode
return NewDoHNameServer(u, queryStrategy, dispatcher, true), nil return NewDoHLocalNameServer(u, queryStrategy), nil
case strings.EqualFold(u.Scheme, "https+local"): // DNS-over-HTTPS Local mode
return NewDoHNameServer(u, queryStrategy, nil, false), nil
case strings.EqualFold(u.Scheme, "h2c+local"): // DNS-over-HTTPS h2c Local mode
return NewDoHNameServer(u, queryStrategy, nil, true), nil
case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode
return NewQUICNameServer(u, queryStrategy) return NewQUICNameServer(u, queryStrategy)
case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode

View File

@@ -3,18 +3,14 @@ package dns
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/tls"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"strings"
"sync" "sync"
"time" "time"
utls "github.com/refraction-networking/utls"
"github.com/xtls/xray-core/common" "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/errors"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
@@ -27,13 +23,13 @@ import (
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"golang.org/x/net/dns/dnsmessage" "golang.org/x/net/dns/dnsmessage"
"golang.org/x/net/http2"
) )
// DoHNameServer implemented DNS over HTTPS (RFC8484) Wire Format, // DoHNameServer implemented DNS over HTTPS (RFC8484) Wire Format,
// which is compatible with traditional dns over udp(RFC1035), // which is compatible with traditional dns over udp(RFC1035),
// thus most of the DOH implementation is copied from udpns.go // thus most of the DOH implementation is copied from udpns.go
type DoHNameServer struct { type DoHNameServer struct {
dispatcher routing.Dispatcher
sync.RWMutex sync.RWMutex
ips map[string]*record ips map[string]*record
pub *pubsub.Service pub *pubsub.Service
@@ -44,18 +40,93 @@ type DoHNameServer struct {
queryStrategy QueryStrategy queryStrategy QueryStrategy
} }
// NewDoHNameServer creates DOH/DOHL client object for remote/local resolving. // NewDoHNameServer creates DOH server object for remote resolving.
func NewDoHNameServer(url *url.URL, queryStrategy QueryStrategy, dispatcher routing.Dispatcher, h2c bool) *DoHNameServer { func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (*DoHNameServer, error) {
url.Scheme = "https" errors.LogInfo(context.Background(), "DNS: created Remote DOH client for ", url.String())
mode := "DOH" s := baseDOHNameServer(url, "DOH", queryStrategy)
if dispatcher == nil {
mode = "DOHL" s.dispatcher = dispatcher
tr := &http.Transport{
MaxIdleConns: 30,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 30 * time.Second,
ForceAttemptHTTP2: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dest, err := net.ParseDestination(network + ":" + addr)
if err != nil {
return nil, err
}
link, err := s.dispatcher.Dispatch(toDnsContext(ctx, s.dohURL), 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.httpClient = &http.Client{
Timeout: time.Second * 180,
Transport: tr,
}
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{
Timeout: time.Second * 180,
Transport: tr,
}
errors.LogInfo(context.Background(), "DNS: created Local DOH client for ", url.String())
return s
}
func baseDOHNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) *DoHNameServer {
s := &DoHNameServer{ s := &DoHNameServer{
ips: make(map[string]*record), ips: make(map[string]*record),
pub: pubsub.NewService(), pub: pubsub.NewService(),
name: mode + "//" + url.Host, name: prefix + "//" + url.Host,
dohURL: url.String(), dohURL: url.String(),
queryStrategy: queryStrategy, queryStrategy: queryStrategy,
} }
@@ -63,65 +134,6 @@ func NewDoHNameServer(url *url.URL, queryStrategy QueryStrategy, dispatcher rout
Interval: time.Minute, Interval: time.Minute,
Execute: s.Cleanup, Execute: s.Cleanup,
} }
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
},
},
}
return s return s
} }
@@ -281,8 +293,6 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
req.Header.Add("Accept", "application/dns-message") req.Header.Add("Accept", "application/dns-message")
req.Header.Add("Content-Type", "application/dns-message") req.Header.Add("Content-Type", "application/dns-message")
req.Header.Set("X-Padding", strings.Repeat("X", int(crypto.RandBetween(100, 1000))))
hc := s.httpClient hc := s.httpClient
resp, err := hc.Do(req.WithContext(ctx)) resp, err := hc.Do(req.WithContext(ctx))

View File

@@ -17,7 +17,7 @@ func TestDOHNameServer(t *testing.T) {
url, err := url.Parse("https+local://1.1.1.1/dns-query") url, err := url.Parse("https+local://1.1.1.1/dns-query")
common.Must(err) common.Must(err)
s := NewDoHNameServer(url, QueryStrategy_USE_IP, nil, false) s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
IPv4Enable: true, IPv4Enable: true,
@@ -34,7 +34,7 @@ func TestDOHNameServerWithCache(t *testing.T) {
url, err := url.Parse("https+local://1.1.1.1/dns-query") url, err := url.Parse("https+local://1.1.1.1/dns-query")
common.Must(err) common.Must(err)
s := NewDoHNameServer(url, QueryStrategy_USE_IP, nil, false) s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
IPv4Enable: true, IPv4Enable: true,
@@ -62,7 +62,7 @@ func TestDOHNameServerWithIPv4Override(t *testing.T) {
url, err := url.Parse("https+local://1.1.1.1/dns-query") url, err := url.Parse("https+local://1.1.1.1/dns-query")
common.Must(err) common.Must(err)
s := NewDoHNameServer(url, QueryStrategy_USE_IP4, nil, false) s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP4)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
IPv4Enable: true, IPv4Enable: true,
@@ -85,7 +85,7 @@ func TestDOHNameServerWithIPv6Override(t *testing.T) {
url, err := url.Parse("https+local://1.1.1.1/dns-query") url, err := url.Parse("https+local://1.1.1.1/dns-query")
common.Must(err) common.Must(err)
s := NewDoHNameServer(url, QueryStrategy_USE_IP6, nil, false) s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP6)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
IPv4Enable: true, IPv4Enable: true,

View File

@@ -14,19 +14,13 @@ import (
// LocalNameServer is an wrapper over local DNS feature. // LocalNameServer is an wrapper over local DNS feature.
type LocalNameServer struct { type LocalNameServer struct {
client *localdns.Client client *localdns.Client
queryStrategy QueryStrategy
} }
const errEmptyResponse = "No address associated with hostname" const errEmptyResponse = "No address associated with hostname"
// QueryIP implements Server. // QueryIP implements Server.
func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, _ net.IP, option dns.IPOption, _ bool) (ips []net.IP, 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() start := time.Now()
ips, err = s.client.LookupIP(domain, option) ips, err = s.client.LookupIP(domain, option)
@@ -48,15 +42,14 @@ func (s *LocalNameServer) Name() string {
} }
// NewLocalNameServer creates localdns server object for directly lookup in system DNS. // NewLocalNameServer creates localdns server object for directly lookup in system DNS.
func NewLocalNameServer(queryStrategy QueryStrategy) *LocalNameServer { func NewLocalNameServer() *LocalNameServer {
errors.LogInfo(context.Background(), "DNS: created localhost client") errors.LogInfo(context.Background(), "DNS: created localhost client")
return &LocalNameServer{ return &LocalNameServer{
queryStrategy: queryStrategy, client: localdns.New(),
client: localdns.New(),
} }
} }
// NewLocalDNSClient creates localdns client object for directly lookup in system DNS. // NewLocalDNSClient creates localdns client object for directly lookup in system DNS.
func NewLocalDNSClient() *Client { func NewLocalDNSClient() *Client {
return &Client{server: NewLocalNameServer(QueryStrategy_USE_IP)} return &Client{server: NewLocalNameServer()}
} }

View File

@@ -12,7 +12,7 @@ import (
) )
func TestLocalNameServer(t *testing.T) { func TestLocalNameServer(t *testing.T) {
s := NewLocalNameServer(QueryStrategy_USE_IP) s := NewLocalNameServer()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
ips, err := s.QueryIP(ctx, "google.com", net.IP{}, dns.IPOption{ ips, err := s.QueryIP(ctx, "google.com", net.IP{}, dns.IPOption{
IPv4Enable: true, IPv4Enable: true,

View File

@@ -8,7 +8,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/quic-go/quic-go" "github.com/xtls/quic-go"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"

View File

@@ -27,8 +27,7 @@ type Config struct {
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// Tag of the outbound handler that handles metrics http connections. // Tag of the outbound handler that handles metrics http connections.
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"` Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
Listen string `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"`
} }
func (x *Config) Reset() { func (x *Config) Reset() {
@@ -68,28 +67,20 @@ func (x *Config) GetTag() string {
return "" return ""
} }
func (x *Config) GetListen() string {
if x != nil {
return x.Listen
}
return ""
}
var File_app_metrics_config_proto protoreflect.FileDescriptor var File_app_metrics_config_proto protoreflect.FileDescriptor
var file_app_metrics_config_proto_rawDesc = []byte{ var file_app_metrics_config_proto_rawDesc = []byte{
0x0a, 0x18, 0x61, 0x70, 0x70, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x63, 0x6f, 0x0a, 0x18, 0x61, 0x70, 0x70, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x63, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61, 0x79, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x32, 0x0a, 0x06, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x1a, 0x0a, 0x06,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x42, 0x52, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e,
0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
0x42, 0x52, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x70, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0xaa, 0x02, 0x10, 0x58, 0x72, 0x61, 0x79,
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72,
0x73, 0xaa, 0x02, 0x10, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4d, 0x65, 0x74, 0x6f, 0x74, 0x6f, 0x33,
0x72, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -10,5 +10,4 @@ option java_multiple_files = true;
message Config { message Config {
// Tag of the outbound handler that handles metrics http connections. // Tag of the outbound handler that handles metrics http connections.
string tag = 1; string tag = 1;
string listen = 2;
} }

View File

@@ -24,15 +24,12 @@ type MetricsHandler struct {
statsManager feature_stats.Manager statsManager feature_stats.Manager
observatory extension.Observatory observatory extension.Observatory
tag string tag string
listen string
tcpListener net.Listener
} }
// NewMetricsHandler creates a new MetricsHandler based on the given config. // NewMetricsHandler creates a new MetricsHandler based on the given config.
func NewMetricsHandler(ctx context.Context, config *Config) (*MetricsHandler, error) { func NewMetricsHandler(ctx context.Context, config *Config) (*MetricsHandler, error) {
c := &MetricsHandler{ c := &MetricsHandler{
tag: config.Tag, tag: config.Tag,
listen: config.Listen,
} }
common.Must(core.RequireFeatures(ctx, func(om outbound.Manager, sm feature_stats.Manager) { common.Must(core.RequireFeatures(ctx, func(om outbound.Manager, sm feature_stats.Manager) {
c.statsManager = sm c.statsManager = sm
@@ -90,23 +87,6 @@ func (p *MetricsHandler) Type() interface{} {
} }
func (p *MetricsHandler) Start() error { func (p *MetricsHandler) Start() error {
// direct listen a port if listen is set
if p.listen != "" {
TCPlistener, err := net.Listen("tcp", p.listen)
if err != nil {
return err
}
p.tcpListener = TCPlistener
errors.LogInfo(context.Background(), "Metrics server listening on ", p.listen)
go func() {
if err := http.Serve(TCPlistener, http.DefaultServeMux); err != nil {
errors.LogErrorInner(context.Background(), err, "failed to start metrics server")
}
}()
}
listener := &OutboundListener{ listener := &OutboundListener{
buffer: make(chan net.Conn, 4), buffer: make(chan net.Conn, 4),
done: done.New(), done: done.New(),

View File

@@ -66,10 +66,10 @@ func NewHealthPing(ctx context.Context, dispatcher routing.Dispatcher, config *H
settings.Timeout = time.Duration(5) * time.Second settings.Timeout = time.Duration(5) * time.Second
} }
return &HealthPing{ return &HealthPing{
ctx: ctx, ctx: ctx,
dispatcher: dispatcher, dispatcher: dispatcher,
Settings: settings, Settings: settings,
Results: nil, Results: nil,
} }
} }

View File

@@ -32,7 +32,7 @@ type Observer struct {
finished *done.Instance finished *done.Instance
ohm outbound.Manager ohm outbound.Manager
dispatcher routing.Dispatcher dispatcher routing.Dispatcher
} }
@@ -226,9 +226,9 @@ func New(ctx context.Context, config *Config) (*Observer, error) {
return nil, errors.New("Cannot get depended features").Base(err) return nil, errors.New("Cannot get depended features").Base(err)
} }
return &Observer{ return &Observer{
config: config, config: config,
ctx: ctx, ctx: ctx,
ohm: outboundManager, ohm: outboundManager,
dispatcher: dispatcher, dispatcher: dispatcher,
}, nil }, nil
} }

View File

@@ -23,7 +23,7 @@ type DynamicInboundHandler struct {
receiverConfig *proxyman.ReceiverConfig receiverConfig *proxyman.ReceiverConfig
streamSettings *internet.MemoryStreamConfig streamSettings *internet.MemoryStreamConfig
portMutex sync.Mutex portMutex sync.Mutex
portsInUse map[net.Port]struct{} portsInUse map[net.Port]bool
workerMutex sync.RWMutex workerMutex sync.RWMutex
worker []worker worker []worker
lastRefresh time.Time lastRefresh time.Time
@@ -39,7 +39,7 @@ func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *p
tag: tag, tag: tag,
proxyConfig: proxyConfig, proxyConfig: proxyConfig,
receiverConfig: receiverConfig, receiverConfig: receiverConfig,
portsInUse: make(map[net.Port]struct{}), portsInUse: make(map[net.Port]bool),
mux: mux.NewServer(ctx), mux: mux.NewServer(ctx),
v: v, v: v,
ctx: ctx, ctx: ctx,
@@ -84,7 +84,7 @@ func (h *DynamicInboundHandler) allocatePort() net.Port {
port := net.Port(allPorts[r]) port := net.Port(allPorts[r])
_, used := h.portsInUse[port] _, used := h.portsInUse[port]
if !used { if !used {
h.portsInUse[port] = struct{}{} h.portsInUse[port] = true
return port return port
} }
} }

View File

@@ -464,7 +464,8 @@ func (w *dsWorker) callback(conn stat.Connection) {
} }
} }
ctx = session.ContextWithInbound(ctx, &session.Inbound{ ctx = session.ContextWithInbound(ctx, &session.Inbound{
Source: net.DestinationFromAddr(conn.RemoteAddr()), // Unix have no source addr, so we use gateway as source for log.
Source: net.UnixDestination(w.address),
Gateway: net.UnixDestination(w.address), Gateway: net.UnixDestination(w.address),
Tag: w.tag, Tag: w.tag,
Conn: conn, Conn: conn,

View File

@@ -273,16 +273,7 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
outbounds := session.OutboundsFromContext(ctx) outbounds := session.OutboundsFromContext(ctx)
ob := outbounds[len(outbounds)-1] ob := outbounds[len(outbounds)-1]
if h.senderSettings.ViaCidr == "" { if h.senderSettings.ViaCidr == "" {
if h.senderSettings.Via.AsAddress().Family().IsDomain() && h.senderSettings.Via.AsAddress().Domain() == "origin" { ob.Gateway = h.senderSettings.Via.AsAddress()
if inbound := session.InboundFromContext(ctx); inbound != nil {
origin, _, err := net.SplitHostPort(inbound.Conn.LocalAddr().String())
if err == nil {
ob.Gateway = net.ParseAddress(origin)
}
}
} else {
ob.Gateway = h.senderSettings.Via.AsAddress()
}
} else { //Get a random address. } else { //Get a random address.
ob.Gateway = ParseRandomIPv6(h.senderSettings.Via.AsAddress(), h.senderSettings.ViaCidr) ob.Gateway = ParseRandomIPv6(h.senderSettings.Via.AsAddress(), h.senderSettings.ViaCidr)
} }

View File

@@ -60,24 +60,6 @@ func (s *statsServer) GetStatsOnline(ctx context.Context, request *GetStatsReque
}, nil }, nil
} }
func (s *statsServer) GetStatsOnlineIpList(ctx context.Context, request *GetStatsRequest) (*GetStatsOnlineIpListResponse, error) {
c := s.stats.GetOnlineMap(request.Name)
if c == nil {
return nil, errors.New(request.Name, " not found.")
}
ips := make(map[string]int64)
for ip, t := range c.IpTimeMap() {
ips[ip] = t.Unix()
}
return &GetStatsOnlineIpListResponse{
Name: request.Name,
Ips: ips,
}, nil
}
func (s *statsServer) QueryStats(ctx context.Context, request *QueryStatsRequest) (*QueryStatsResponse, error) { func (s *statsServer) QueryStats(ctx context.Context, request *QueryStatsRequest) (*QueryStatsResponse, error) {
matcher, err := strmatcher.Substr.New(request.Pattern) matcher, err := strmatcher.Substr.New(request.Pattern)
if err != nil { if err != nil {

View File

@@ -424,59 +424,6 @@ func (x *SysStatsResponse) GetUptime() uint32 {
return 0 return 0
} }
type GetStatsOnlineIpListResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Ips map[string]int64 `protobuf:"bytes,2,rep,name=ips,proto3" json:"ips,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
}
func (x *GetStatsOnlineIpListResponse) Reset() {
*x = GetStatsOnlineIpListResponse{}
mi := &file_app_stats_command_command_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetStatsOnlineIpListResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetStatsOnlineIpListResponse) ProtoMessage() {}
func (x *GetStatsOnlineIpListResponse) ProtoReflect() protoreflect.Message {
mi := &file_app_stats_command_command_proto_msgTypes[7]
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 GetStatsOnlineIpListResponse.ProtoReflect.Descriptor instead.
func (*GetStatsOnlineIpListResponse) Descriptor() ([]byte, []int) {
return file_app_stats_command_command_proto_rawDescGZIP(), []int{7}
}
func (x *GetStatsOnlineIpListResponse) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *GetStatsOnlineIpListResponse) GetIps() map[string]int64 {
if x != nil {
return x.Ips
}
return nil
}
type Config struct { type Config struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -485,7 +432,7 @@ type Config struct {
func (x *Config) Reset() { func (x *Config) Reset() {
*x = Config{} *x = Config{}
mi := &file_app_stats_command_command_proto_msgTypes[8] mi := &file_app_stats_command_command_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -497,7 +444,7 @@ func (x *Config) String() string {
func (*Config) ProtoMessage() {} func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message { func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_stats_command_command_proto_msgTypes[8] mi := &file_app_stats_command_command_proto_msgTypes[7]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -510,7 +457,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
// Deprecated: Use Config.ProtoReflect.Descriptor instead. // Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) { func (*Config) Descriptor() ([]byte, []int) {
return file_app_stats_command_command_proto_rawDescGZIP(), []int{8} return file_app_stats_command_command_proto_rawDescGZIP(), []int{7}
} }
var File_app_stats_command_command_proto protoreflect.FileDescriptor var File_app_stats_command_command_proto protoreflect.FileDescriptor
@@ -559,60 +506,40 @@ var file_app_stats_command_command_proto_rawDesc = []byte{
0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4e, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x50, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4e, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x50,
0x61, 0x75, 0x73, 0x65, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4e, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x55, 0x61, 0x75, 0x73, 0x65, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4e, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x55,
0x70, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x55, 0x70, 0x74, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x55, 0x70, 0x74,
0x69, 0x6d, 0x65, 0x22, 0xbb, 0x01, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x69, 0x6d, 0x65, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0xa1, 0x03,
0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x49, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5f,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x27, 0x2e, 0x78, 0x72, 0x61,
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4f, 0x0a, 0x03, 0x69, 0x70, 0x73, 0x18,
0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47,
0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x49, 0x70, 0x4c,
0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x49, 0x70, 0x73, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x52, 0x03, 0x69, 0x70, 0x73, 0x1a, 0x36, 0x0a, 0x08, 0x49, 0x70, 0x73,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0x9a, 0x04, 0x0a, 0x0c,
0x53, 0x74, 0x61, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5f, 0x0a, 0x08,
0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61,
0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74,
0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x65, 0x0a,
0x0e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x12,
0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x00, 0x12, 0x65, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61,
0x74, 0x73, 0x12, 0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74,
0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x51, 0x75, 0x65, 0x72,
0x79, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63,
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x62, 0x0a, 0x0b, 0x47,
0x65, 0x74, 0x53, 0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x27, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x61, 0x6e, 0x64, 0x2e, 0x53, 0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73,
0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74,
0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
0x77, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x69, 0x6e,
0x65, 0x49, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x65, 0x12, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61,
0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74,
0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x78, 0x72, 0x61,
0x1a, 0x34, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70,
0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x49, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x65, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x64, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x61, 0x74, 0x73, 0x12, 0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x51, 0x75,
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73,
0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x16, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x62, 0x0a,
0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x0b, 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x27, 0x2e, 0x78,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53, 0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53,
0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x00, 0x42, 0x64, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50,
0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74,
0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70,
0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02,
0x16, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x2e,
0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@@ -627,38 +554,33 @@ func file_app_stats_command_command_proto_rawDescGZIP() []byte {
return file_app_stats_command_command_proto_rawDescData return file_app_stats_command_command_proto_rawDescData
} }
var file_app_stats_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 10) var file_app_stats_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_app_stats_command_command_proto_goTypes = []any{ var file_app_stats_command_command_proto_goTypes = []any{
(*GetStatsRequest)(nil), // 0: xray.app.stats.command.GetStatsRequest (*GetStatsRequest)(nil), // 0: xray.app.stats.command.GetStatsRequest
(*Stat)(nil), // 1: xray.app.stats.command.Stat (*Stat)(nil), // 1: xray.app.stats.command.Stat
(*GetStatsResponse)(nil), // 2: xray.app.stats.command.GetStatsResponse (*GetStatsResponse)(nil), // 2: xray.app.stats.command.GetStatsResponse
(*QueryStatsRequest)(nil), // 3: xray.app.stats.command.QueryStatsRequest (*QueryStatsRequest)(nil), // 3: xray.app.stats.command.QueryStatsRequest
(*QueryStatsResponse)(nil), // 4: xray.app.stats.command.QueryStatsResponse (*QueryStatsResponse)(nil), // 4: xray.app.stats.command.QueryStatsResponse
(*SysStatsRequest)(nil), // 5: xray.app.stats.command.SysStatsRequest (*SysStatsRequest)(nil), // 5: xray.app.stats.command.SysStatsRequest
(*SysStatsResponse)(nil), // 6: xray.app.stats.command.SysStatsResponse (*SysStatsResponse)(nil), // 6: xray.app.stats.command.SysStatsResponse
(*GetStatsOnlineIpListResponse)(nil), // 7: xray.app.stats.command.GetStatsOnlineIpListResponse (*Config)(nil), // 7: xray.app.stats.command.Config
(*Config)(nil), // 8: xray.app.stats.command.Config
nil, // 9: xray.app.stats.command.GetStatsOnlineIpListResponse.IpsEntry
} }
var file_app_stats_command_command_proto_depIdxs = []int32{ var file_app_stats_command_command_proto_depIdxs = []int32{
1, // 0: xray.app.stats.command.GetStatsResponse.stat:type_name -> xray.app.stats.command.Stat 1, // 0: xray.app.stats.command.GetStatsResponse.stat:type_name -> xray.app.stats.command.Stat
1, // 1: xray.app.stats.command.QueryStatsResponse.stat:type_name -> xray.app.stats.command.Stat 1, // 1: xray.app.stats.command.QueryStatsResponse.stat:type_name -> xray.app.stats.command.Stat
9, // 2: xray.app.stats.command.GetStatsOnlineIpListResponse.ips:type_name -> xray.app.stats.command.GetStatsOnlineIpListResponse.IpsEntry 0, // 2: xray.app.stats.command.StatsService.GetStats:input_type -> xray.app.stats.command.GetStatsRequest
0, // 3: xray.app.stats.command.StatsService.GetStats:input_type -> xray.app.stats.command.GetStatsRequest 0, // 3: xray.app.stats.command.StatsService.GetStatsOnline:input_type -> xray.app.stats.command.GetStatsRequest
0, // 4: xray.app.stats.command.StatsService.GetStatsOnline:input_type -> xray.app.stats.command.GetStatsRequest 3, // 4: xray.app.stats.command.StatsService.QueryStats:input_type -> xray.app.stats.command.QueryStatsRequest
3, // 5: xray.app.stats.command.StatsService.QueryStats:input_type -> xray.app.stats.command.QueryStatsRequest 5, // 5: xray.app.stats.command.StatsService.GetSysStats:input_type -> xray.app.stats.command.SysStatsRequest
5, // 6: xray.app.stats.command.StatsService.GetSysStats:input_type -> xray.app.stats.command.SysStatsRequest 2, // 6: xray.app.stats.command.StatsService.GetStats:output_type -> xray.app.stats.command.GetStatsResponse
0, // 7: xray.app.stats.command.StatsService.GetStatsOnlineIpList:input_type -> xray.app.stats.command.GetStatsRequest 2, // 7: xray.app.stats.command.StatsService.GetStatsOnline:output_type -> xray.app.stats.command.GetStatsResponse
2, // 8: xray.app.stats.command.StatsService.GetStats:output_type -> xray.app.stats.command.GetStatsResponse 4, // 8: xray.app.stats.command.StatsService.QueryStats:output_type -> xray.app.stats.command.QueryStatsResponse
2, // 9: xray.app.stats.command.StatsService.GetStatsOnline:output_type -> xray.app.stats.command.GetStatsResponse 6, // 9: xray.app.stats.command.StatsService.GetSysStats:output_type -> xray.app.stats.command.SysStatsResponse
4, // 10: xray.app.stats.command.StatsService.QueryStats:output_type -> xray.app.stats.command.QueryStatsResponse 6, // [6:10] is the sub-list for method output_type
6, // 11: xray.app.stats.command.StatsService.GetSysStats:output_type -> xray.app.stats.command.SysStatsResponse 2, // [2:6] is the sub-list for method input_type
7, // 12: xray.app.stats.command.StatsService.GetStatsOnlineIpList:output_type -> xray.app.stats.command.GetStatsOnlineIpListResponse 2, // [2:2] is the sub-list for extension type_name
8, // [8:13] is the sub-list for method output_type 2, // [2:2] is the sub-list for extension extendee
3, // [3:8] is the sub-list for method input_type 0, // [0:2] is the sub-list for field type_name
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
} }
func init() { file_app_stats_command_command_proto_init() } func init() { file_app_stats_command_command_proto_init() }
@@ -672,7 +594,7 @@ func file_app_stats_command_command_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_stats_command_command_proto_rawDesc, RawDescriptor: file_app_stats_command_command_proto_rawDesc,
NumEnums: 0, NumEnums: 0,
NumMessages: 10, NumMessages: 8,
NumExtensions: 0, NumExtensions: 0,
NumServices: 1, NumServices: 1,
}, },

View File

@@ -46,17 +46,11 @@ message SysStatsResponse {
uint32 Uptime = 10; uint32 Uptime = 10;
} }
message GetStatsOnlineIpListResponse {
string name = 1;
map<string, int64> ips = 2;
}
service StatsService { service StatsService {
rpc GetStats(GetStatsRequest) returns (GetStatsResponse) {} rpc GetStats(GetStatsRequest) returns (GetStatsResponse) {}
rpc GetStatsOnline(GetStatsRequest) returns (GetStatsResponse) {} rpc GetStatsOnline(GetStatsRequest) returns (GetStatsResponse) {}
rpc QueryStats(QueryStatsRequest) returns (QueryStatsResponse) {} rpc QueryStats(QueryStatsRequest) returns (QueryStatsResponse) {}
rpc GetSysStats(SysStatsRequest) returns (SysStatsResponse) {} rpc GetSysStats(SysStatsRequest) returns (SysStatsResponse) {}
rpc GetStatsOnlineIpList(GetStatsRequest) returns (GetStatsOnlineIpListResponse) {}
} }
message Config {} message Config {}

View File

@@ -19,11 +19,10 @@ import (
const _ = grpc.SupportPackageIsVersion9 const _ = grpc.SupportPackageIsVersion9
const ( const (
StatsService_GetStats_FullMethodName = "/xray.app.stats.command.StatsService/GetStats" StatsService_GetStats_FullMethodName = "/xray.app.stats.command.StatsService/GetStats"
StatsService_GetStatsOnline_FullMethodName = "/xray.app.stats.command.StatsService/GetStatsOnline" StatsService_GetStatsOnline_FullMethodName = "/xray.app.stats.command.StatsService/GetStatsOnline"
StatsService_QueryStats_FullMethodName = "/xray.app.stats.command.StatsService/QueryStats" StatsService_QueryStats_FullMethodName = "/xray.app.stats.command.StatsService/QueryStats"
StatsService_GetSysStats_FullMethodName = "/xray.app.stats.command.StatsService/GetSysStats" StatsService_GetSysStats_FullMethodName = "/xray.app.stats.command.StatsService/GetSysStats"
StatsService_GetStatsOnlineIpList_FullMethodName = "/xray.app.stats.command.StatsService/GetStatsOnlineIpList"
) )
// StatsServiceClient is the client API for StatsService service. // StatsServiceClient is the client API for StatsService service.
@@ -34,7 +33,6 @@ type StatsServiceClient interface {
GetStatsOnline(ctx context.Context, in *GetStatsRequest, opts ...grpc.CallOption) (*GetStatsResponse, error) GetStatsOnline(ctx context.Context, in *GetStatsRequest, opts ...grpc.CallOption) (*GetStatsResponse, error)
QueryStats(ctx context.Context, in *QueryStatsRequest, opts ...grpc.CallOption) (*QueryStatsResponse, error) QueryStats(ctx context.Context, in *QueryStatsRequest, opts ...grpc.CallOption) (*QueryStatsResponse, error)
GetSysStats(ctx context.Context, in *SysStatsRequest, opts ...grpc.CallOption) (*SysStatsResponse, error) GetSysStats(ctx context.Context, in *SysStatsRequest, opts ...grpc.CallOption) (*SysStatsResponse, error)
GetStatsOnlineIpList(ctx context.Context, in *GetStatsRequest, opts ...grpc.CallOption) (*GetStatsOnlineIpListResponse, error)
} }
type statsServiceClient struct { type statsServiceClient struct {
@@ -85,16 +83,6 @@ func (c *statsServiceClient) GetSysStats(ctx context.Context, in *SysStatsReques
return out, nil return out, nil
} }
func (c *statsServiceClient) GetStatsOnlineIpList(ctx context.Context, in *GetStatsRequest, opts ...grpc.CallOption) (*GetStatsOnlineIpListResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetStatsOnlineIpListResponse)
err := c.cc.Invoke(ctx, StatsService_GetStatsOnlineIpList_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// StatsServiceServer is the server API for StatsService service. // StatsServiceServer is the server API for StatsService service.
// All implementations must embed UnimplementedStatsServiceServer // All implementations must embed UnimplementedStatsServiceServer
// for forward compatibility. // for forward compatibility.
@@ -103,7 +91,6 @@ type StatsServiceServer interface {
GetStatsOnline(context.Context, *GetStatsRequest) (*GetStatsResponse, error) GetStatsOnline(context.Context, *GetStatsRequest) (*GetStatsResponse, error)
QueryStats(context.Context, *QueryStatsRequest) (*QueryStatsResponse, error) QueryStats(context.Context, *QueryStatsRequest) (*QueryStatsResponse, error)
GetSysStats(context.Context, *SysStatsRequest) (*SysStatsResponse, error) GetSysStats(context.Context, *SysStatsRequest) (*SysStatsResponse, error)
GetStatsOnlineIpList(context.Context, *GetStatsRequest) (*GetStatsOnlineIpListResponse, error)
mustEmbedUnimplementedStatsServiceServer() mustEmbedUnimplementedStatsServiceServer()
} }
@@ -126,9 +113,6 @@ func (UnimplementedStatsServiceServer) QueryStats(context.Context, *QueryStatsRe
func (UnimplementedStatsServiceServer) GetSysStats(context.Context, *SysStatsRequest) (*SysStatsResponse, error) { func (UnimplementedStatsServiceServer) GetSysStats(context.Context, *SysStatsRequest) (*SysStatsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetSysStats not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetSysStats not implemented")
} }
func (UnimplementedStatsServiceServer) GetStatsOnlineIpList(context.Context, *GetStatsRequest) (*GetStatsOnlineIpListResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetStatsOnlineIpList not implemented")
}
func (UnimplementedStatsServiceServer) mustEmbedUnimplementedStatsServiceServer() {} func (UnimplementedStatsServiceServer) mustEmbedUnimplementedStatsServiceServer() {}
func (UnimplementedStatsServiceServer) testEmbeddedByValue() {} func (UnimplementedStatsServiceServer) testEmbeddedByValue() {}
@@ -222,24 +206,6 @@ func _StatsService_GetSysStats_Handler(srv interface{}, ctx context.Context, dec
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _StatsService_GetStatsOnlineIpList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetStatsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StatsServiceServer).GetStatsOnlineIpList(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: StatsService_GetStatsOnlineIpList_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StatsServiceServer).GetStatsOnlineIpList(ctx, req.(*GetStatsRequest))
}
return interceptor(ctx, in, info, handler)
}
// StatsService_ServiceDesc is the grpc.ServiceDesc for StatsService service. // StatsService_ServiceDesc is the grpc.ServiceDesc for StatsService service.
// It's only intended for direct use with grpc.RegisterService, // It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy) // and not to be introspected or modified (even as a copy)
@@ -263,10 +229,6 @@ var StatsService_ServiceDesc = grpc.ServiceDesc{
MethodName: "GetSysStats", MethodName: "GetSysStats",
Handler: _StatsService_GetSysStats_Handler, Handler: _StatsService_GetSysStats_Handler,
}, },
{
MethodName: "GetStatsOnlineIpList",
Handler: _StatsService_GetStatsOnlineIpList_Handler,
},
}, },
Streams: []grpc.StreamDesc{}, Streams: []grpc.StreamDesc{},
Metadata: "app/stats/command/command.proto", Metadata: "app/stats/command/command.proto",

View File

@@ -35,28 +35,33 @@ func (c *OnlineMap) List() []string {
// AddIP implements stats.OnlineMap. // AddIP implements stats.OnlineMap.
func (c *OnlineMap) AddIP(ip string) { func (c *OnlineMap) AddIP(ip string) {
list := c.ipList
if ip == "127.0.0.1" { if ip == "127.0.0.1" {
return return
} }
if _, ok := list[ip]; !ok {
c.access.Lock() c.access.Lock()
list[ip] = time.Now() defer c.access.Unlock()
c.access.Unlock()
if _, ok := c.ipList[ip]; !ok {
c.ipList[ip] = time.Now()
} }
if time.Since(c.lastCleanup) > c.cleanupPeriod { if time.Since(c.lastCleanup) > c.cleanupPeriod {
list = c.RemoveExpiredIPs(list) now := time.Now()
for k, t := range c.ipList {
diff := now.Sub(t)
if diff.Seconds() > 20 {
delete(c.ipList, k) // safe to do delete in range
}
}
c.lastCleanup = time.Now() c.lastCleanup = time.Now()
} }
c.value = len(list) c.value = len(c.ipList)
c.ipList = list
} }
func (c *OnlineMap) GetKeys() []string { func (c *OnlineMap) GetKeys() []string {
c.access.RLock() c.access.Lock()
defer c.access.RUnlock() defer c.access.Unlock()
keys := []string{} keys := []string{}
for k := range c.ipList { for k := range c.ipList {
@@ -64,27 +69,3 @@ func (c *OnlineMap) GetKeys() []string {
} }
return keys return keys
} }
func (c *OnlineMap) RemoveExpiredIPs(list map[string]time.Time) map[string]time.Time {
c.access.Lock()
defer c.access.Unlock()
now := time.Now()
for k, t := range list {
diff := now.Sub(t)
if diff.Seconds() > 20 {
delete(list, k)
}
}
return list
}
func (c *OnlineMap) IpTimeMap() map[string]time.Time {
list := c.ipList
if time.Since(c.lastCleanup) > c.cleanupPeriod {
list = c.RemoveExpiredIPs(list)
c.lastCleanup = time.Now()
}
return c.ipList
}

View File

@@ -1,15 +1,2 @@
// Package crypto provides common crypto libraries for Xray. // Package crypto provides common crypto libraries for Xray.
package crypto // import "github.com/xtls/xray-core/common/crypto" 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()
}

View File

@@ -146,7 +146,7 @@ func (w *fileLogWriter) Close() error {
func CreateStdoutLogWriter() WriterCreator { func CreateStdoutLogWriter() WriterCreator {
return func() Writer { return func() Writer {
return &consoleLogWriter{ return &consoleLogWriter{
logger: log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lmicroseconds), logger: log.New(os.Stdout, "", log.Ldate|log.Ltime),
} }
} }
} }
@@ -155,7 +155,7 @@ func CreateStdoutLogWriter() WriterCreator {
func CreateStderrLogWriter() WriterCreator { func CreateStderrLogWriter() WriterCreator {
return func() Writer { return func() Writer {
return &consoleLogWriter{ return &consoleLogWriter{
logger: log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lmicroseconds), logger: log.New(os.Stderr, "", log.Ldate|log.Ltime),
} }
} }
} }
@@ -174,7 +174,7 @@ func CreateFileLogWriter(path string) (WriterCreator, error) {
} }
return &fileLogWriter{ return &fileLogWriter{
file: file, file: file,
logger: log.New(file, "", log.Ldate|log.Ltime|log.Lmicroseconds), logger: log.New(file, "", log.Ldate|log.Ltime),
} }
}, nil }, nil
} }

View File

@@ -89,10 +89,12 @@ func UnixDestination(address Address) Destination {
// NetAddr returns the network address in this Destination in string form. // NetAddr returns the network address in this Destination in string form.
func (d Destination) NetAddr() string { func (d Destination) NetAddr() string {
addr := "" addr := ""
if d.Network == Network_TCP || d.Network == Network_UDP { if d.Address != nil {
addr = d.Address.String() + ":" + d.Port.String() if d.Network == Network_TCP || d.Network == Network_UDP {
} else if d.Network == Network_UNIX { addr = d.Address.String() + ":" + d.Port.String()
addr = d.Address.String() } else if d.Network == Network_UNIX {
addr = d.Address.String()
}
} }
return addr return addr
} }

View File

@@ -1,14 +1,2 @@
// Package net is a drop-in replacement to Golang's net package, with some more functionalities. // Package net is a drop-in replacement to Golang's net package, with some more functionalities.
package net // import "github.com/xtls/xray-core/common/net" package net // import "github.com/xtls/xray-core/common/net"
import "time"
// 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

View File

@@ -76,9 +76,8 @@ type (
) )
var ( var (
ResolveTCPAddr = net.ResolveTCPAddr
ResolveUDPAddr = net.ResolveUDPAddr
ResolveUnixAddr = net.ResolveUnixAddr ResolveUnixAddr = net.ResolveUnixAddr
ResolveUDPAddr = net.ResolveUDPAddr
) )
type Resolver = net.Resolver type Resolver = net.Resolver

View File

@@ -8,7 +8,7 @@ import (
"encoding/binary" "encoding/binary"
"io" "io"
"github.com/quic-go/quic-go/quicvarint" "github.com/xtls/quic-go/quicvarint"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/bytespool" "github.com/xtls/xray-core/common/bytespool"

View File

@@ -1,2 +1 @@
*.crt *.pem
*.key

View File

@@ -78,9 +78,9 @@ func printJSON(certificate *Certificate) {
func printFile(certificate *Certificate, name string) error { func printFile(certificate *Certificate, name string) error {
certPEM, keyPEM := certificate.ToPEM() certPEM, keyPEM := certificate.ToPEM()
return task.Run(context.Background(), func() error { return task.Run(context.Background(), func() error {
return writeFile(certPEM, name+".crt") return writeFile(certPEM, name+"_cert.pem")
}, func() error { }, func() error {
return writeFile(keyPEM, name+".key") return writeFile(keyPEM, name+"_key.pem")
}) })
} }

View File

@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect" "reflect"
"slices"
"strings" "strings"
cnet "github.com/xtls/xray-core/common/net" cnet "github.com/xtls/xray-core/common/net"
@@ -31,9 +32,6 @@ func JSONMarshalWithoutEscape(t interface{}) ([]byte, error) {
} }
func marshalTypedMessage(v *cserial.TypedMessage, ignoreNullValue bool, insertTypeInfo bool) interface{} { func marshalTypedMessage(v *cserial.TypedMessage, ignoreNullValue bool, insertTypeInfo bool) interface{} {
if v == nil {
return nil
}
tmsg, err := v.GetInstance() tmsg, err := v.GetInstance()
if err != nil { if err != nil {
return nil return nil
@@ -58,9 +56,7 @@ func marshalSlice(v reflect.Value, ignoreNullValue bool, insertTypeInfo bool) in
} }
func isNullValue(f reflect.StructField, rv reflect.Value) bool { func isNullValue(f reflect.StructField, rv reflect.Value) bool {
if rv.Kind() == reflect.Struct { if rv.Kind() == reflect.String && rv.Len() == 0 {
return false
} else if rv.Kind() == reflect.String && rv.Len() == 0 {
return true return true
} else if !isValueKind(rv.Kind()) && rv.IsNil() { } else if !isValueKind(rv.Kind()) && rv.IsNil() {
return true return true
@@ -186,12 +182,6 @@ func marshalKnownType(v interface{}, ignoreNullValue bool, insertTypeInfo bool)
case *conf.PortList: case *conf.PortList:
cpl := v.(*conf.PortList) cpl := v.(*conf.PortList)
return serializePortList(cpl.Build()) return serializePortList(cpl.Build())
case conf.Int32Range:
i32rng := v.(conf.Int32Range)
if i32rng.Left == i32rng.Right {
return i32rng.Left, true
}
return i32rng.String(), true
case cnet.Address: case cnet.Address:
if addr := v.(cnet.Address); addr != nil { if addr := v.(cnet.Address); addr != nil {
return addr.String(), true return addr.String(), true
@@ -202,29 +192,28 @@ func marshalKnownType(v interface{}, ignoreNullValue bool, insertTypeInfo bool)
} }
} }
var valueKinds = []reflect.Kind{
reflect.Bool,
reflect.Int,
reflect.Int8,
reflect.Int16,
reflect.Int32,
reflect.Int64,
reflect.Uint,
reflect.Uint8,
reflect.Uint16,
reflect.Uint32,
reflect.Uint64,
reflect.Uintptr,
reflect.Float32,
reflect.Float64,
reflect.Complex64,
reflect.Complex128,
reflect.String,
}
func isValueKind(kind reflect.Kind) bool { func isValueKind(kind reflect.Kind) bool {
switch kind { return slices.Contains(valueKinds, kind)
case reflect.Bool,
reflect.Int,
reflect.Int8,
reflect.Int16,
reflect.Int32,
reflect.Int64,
reflect.Uint,
reflect.Uint8,
reflect.Uint16,
reflect.Uint32,
reflect.Uint64,
reflect.Uintptr,
reflect.Float32,
reflect.Float64,
reflect.Complex64,
reflect.Complex128,
reflect.String:
return true
default:
return false
}
} }
func marshalInterface(v interface{}, ignoreNullValue bool, insertTypeInfo bool) interface{} { func marshalInterface(v interface{}, ignoreNullValue bool, insertTypeInfo bool) interface{} {

View File

@@ -116,129 +116,98 @@ func TestMarshalConfigJson(t *testing.T) {
"system", "system",
"inboundDownlink", "inboundDownlink",
"outboundUplink", "outboundUplink",
"XHTTP_IN",
"\"host\": \"bing.com\"",
"scMaxEachPostBytes",
"\"from\": 100",
"\"to\": 1000",
"\"from\": 1000000",
"\"to\": 1000000",
} }
for _, kw := range keywords { for _, kw := range keywords {
if !strings.Contains(tc, kw) { if !strings.Contains(tc, kw) {
t.Log("config.json:", tc) t.Error("marshaled config error")
t.Error("keyword not found:", kw)
break
} }
} }
} }
func getConfig() string { func getConfig() string {
return `{ return `{
"log": { "log": {
"loglevel": "debug" "loglevel": "debug"
}, },
"stats": {}, "stats": {},
"policy": { "policy": {
"levels": { "levels": {
"0": { "0": {
"statsUserUplink": true, "statsUserUplink": true,
"statsUserDownlink": true "statsUserDownlink": true
} }
}, },
"system": { "system": {
"statsInboundUplink": true, "statsInboundUplink": true,
"statsInboundDownlink": true, "statsInboundDownlink": true,
"statsOutboundUplink": true, "statsOutboundUplink": true,
"statsOutboundDownlink": true "statsOutboundDownlink": true
} }
}, },
"inbounds": [ "inbounds": [
{ {
"tag": "agentin", "tag": "agentin",
"protocol": "http", "protocol": "http",
"port": 18080, "port": 8080,
"listen": "127.0.0.1", "listen": "127.0.0.1",
"settings": {} "settings": {}
}, },
{ {
"listen": "127.0.0.1", "listen": "127.0.0.1",
"port": 10085, "port": 10085,
"protocol": "dokodemo-door", "protocol": "dokodemo-door",
"settings": { "settings": {
"address": "127.0.0.1" "address": "127.0.0.1"
}, },
"tag": "api-in" "tag": "api-in"
} }
], ],
"api": { "api": {
"tag": "api", "tag": "api",
"services": [ "services": [
"HandlerService", "HandlerService",
"StatsService" "StatsService"
] ]
}, },
"routing": { "routing": {
"rules": [ "rules": [
{ {
"inboundTag": [ "inboundTag": [
"api-in" "api-in"
], ],
"outboundTag": "api", "outboundTag": "api",
"type": "field" "type": "field"
} }
], ],
"domainStrategy": "AsIs" "domainStrategy": "AsIs"
}, },
"outbounds": [ "outbounds": [
{ {
"protocol": "vless", "protocol": "vless",
"settings": { "settings": {
"vnext": [ "vnext": [
{ {
"address": "1.2.3.4", "address": "1.2.3.4",
"port": 1234, "port": 1234,
"users": [ "users": [
{ {
"id": "4784f9b8-a879-4fec-9718-ebddefa47750", "id": "4784f9b8-a879-4fec-9718-ebddefa47750",
"encryption": "none" "encryption": "none"
} }
] ]
} }
] ]
}, },
"tag": "XHTTP_IN", "tag": "agentout",
"streamSettings": { "streamSettings": {
"network": "xhttp", "network": "ws",
"xhttpSettings": { "security": "none",
"host": "bing.com", "wsSettings": {
"path": "/xhttp_client_upload", "path": "/?ed=2048",
"mode": "auto", "host": "bing.com"
"extra": { }
"noSSEHeader": false, }
"scMaxEachPostBytes": 1000000, }
"scMaxBufferedPosts": 30, ]
"xPaddingBytes": "100-1000" }`
}
},
"sockopt": {
"tcpFastOpen": true,
"acceptProxyProtocol": false,
"tcpcongestion": "bbr",
"tcpMptcp": true
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls",
"quic"
],
"metadataOnly": false,
"routeOnly": true
}
}
]
}`
} }

View File

@@ -23,8 +23,6 @@ const (
timeoutOnlyKey ctx.SessionKey = 8 timeoutOnlyKey ctx.SessionKey = 8
allowedNetworkKey ctx.SessionKey = 9 allowedNetworkKey ctx.SessionKey = 9
handlerSessionKey ctx.SessionKey = 10 handlerSessionKey ctx.SessionKey = 10
mitmAlpn11Key ctx.SessionKey = 11
mitmServerNameKey ctx.SessionKey = 12
) )
func ContextWithInbound(ctx context.Context, inbound *Inbound) context.Context { func ContextWithInbound(ctx context.Context, inbound *Inbound) context.Context {
@@ -164,25 +162,3 @@ func AllowedNetworkFromContext(ctx context.Context) net.Network {
} }
return net.Network_Unknown return net.Network_Unknown
} }
func ContextWithMitmAlpn11(ctx context.Context, alpn11 bool) context.Context {
return context.WithValue(ctx, mitmAlpn11Key, alpn11)
}
func MitmAlpn11FromContext(ctx context.Context) bool {
if val, ok := ctx.Value(mitmAlpn11Key).(bool); ok {
return val
}
return false
}
func ContextWithMitmServerName(ctx context.Context, serverName string) context.Context {
return context.WithValue(ctx, mitmServerNameKey, serverName)
}
func MitmServerNameFromContext(ctx context.Context) string {
if val, ok := ctx.Value(mitmServerNameKey).(string); ok {
return val
}
return ""
}

View File

@@ -18,8 +18,8 @@ import (
var ( var (
Version_x byte = 25 Version_x byte = 25
Version_y byte = 3 Version_y byte = 1
Version_z byte = 3 Version_z byte = 1
) )
var ( var (

View File

@@ -25,7 +25,7 @@ type Handler interface {
// xray:api:stable // xray:api:stable
type Manager interface { type Manager interface {
features.Feature features.Feature
// GetHandler returns an InboundHandler for the given tag. // GetHandlers returns an InboundHandler for the given tag.
GetHandler(ctx context.Context, tag string) (Handler, error) GetHandler(ctx context.Context, tag string) (Handler, error)
// AddHandler adds the given handler into this Manager. // AddHandler adds the given handler into this Manager.
AddHandler(ctx context.Context, handler Handler) error AddHandler(ctx context.Context, handler Handler) error

View File

@@ -11,7 +11,7 @@ type Context interface {
// GetInboundTag returns the tag of the inbound the connection was from. // GetInboundTag returns the tag of the inbound the connection was from.
GetInboundTag() string GetInboundTag() string
// GetSourceIPs returns the source IPs bound to the connection. // GetSourcesIPs returns the source IPs bound to the connection.
GetSourceIPs() []net.IP GetSourceIPs() []net.IP
// GetSourcePort returns the source port of the connection. // GetSourcePort returns the source port of the connection.

View File

@@ -2,7 +2,6 @@ package stats
import ( import (
"context" "context"
"time"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
@@ -31,8 +30,6 @@ type OnlineMap interface {
AddIP(string) AddIP(string)
// List is the current OnlineMap ip list. // List is the current OnlineMap ip list.
List() []string List() []string
// IpTimeMap return client ips and their last access time.
IpTimeMap() map[string]time.Time
} }
// Channel is the interface for stats channel. // Channel is the interface for stats channel.

38
go.mod
View File

@@ -1,18 +1,17 @@
module github.com/xtls/xray-core module github.com/xtls/xray-core
go 1.24 go 1.23
require ( require (
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0
github.com/cloudflare/circl v1.6.0 github.com/cloudflare/circl v1.5.0
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
github.com/golang/mock v1.7.0-rc.1 github.com/golang/mock v1.7.0-rc.1
github.com/google/go-cmp v0.7.0 github.com/google/go-cmp v0.6.0
github.com/gorilla/websocket v1.5.3 github.com/gorilla/websocket v1.5.3
github.com/miekg/dns v1.1.63 github.com/miekg/dns v1.1.62
github.com/pelletier/go-toml v1.9.5 github.com/pelletier/go-toml v1.9.5
github.com/pires/go-proxyproto v0.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/refraction-networking/utls v1.6.7
github.com/sagernet/sing v0.5.1 github.com/sagernet/sing v0.5.1
github.com/sagernet/sing-shadowsocks v0.2.7 github.com/sagernet/sing-shadowsocks v0.2.7
@@ -20,18 +19,19 @@ require (
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
github.com/vishvananda/netlink v1.3.0 github.com/vishvananda/netlink v1.3.0
github.com/xtls/quic-go v0.48.2
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
golang.org/x/crypto v0.35.0 golang.org/x/crypto v0.31.0
golang.org/x/net v0.35.0 golang.org/x/net v0.33.0
golang.org/x/sync v0.11.0 golang.org/x/sync v0.10.0
golang.org/x/sys v0.30.0 golang.org/x/sys v0.28.0
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
google.golang.org/grpc v1.70.0 google.golang.org/grpc v1.69.2
google.golang.org/protobuf v1.36.5 google.golang.org/protobuf v1.36.1
gvisor.dev/gvisor v0.0.0-20240320123526-dc6abceb7ff0 gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489
h12.io/socks v1.0.3 h12.io/socks v1.0.3
lukechampine.com/blake3 v1.4.0 lukechampine.com/blake3 v1.3.0
) )
require ( require (
@@ -48,14 +48,14 @@ require (
github.com/quic-go/qpack v0.5.1 // indirect github.com/quic-go/qpack v0.5.1 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/vishvananda/netns v0.0.4 // indirect github.com/vishvananda/netns v0.0.4 // indirect
go.uber.org/mock v0.5.0 // indirect go.uber.org/mock v0.4.0 // indirect
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect
golang.org/x/mod v0.21.0 // indirect golang.org/x/mod v0.18.0 // indirect
golang.org/x/text v0.22.0 // indirect golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.7.0 // indirect golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.26.0 // indirect golang.org/x/tools v0.22.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

92
go.sum
View File

@@ -2,8 +2,8 @@ github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 h1:Wo41lDOevRJS
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM= github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= 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.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cloudflare/circl v1.5.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.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -24,8 +24,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 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 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= 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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 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 h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g=
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= 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 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
@@ -38,8 +38,8 @@ github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0N
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= 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 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 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.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= 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/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 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
@@ -54,8 +54,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
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 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= 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 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
@@ -76,41 +74,43 @@ github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQ
github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs= 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 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/xtls/quic-go v0.48.2 h1:59Gs+E9qtc9s0uniXYDA649gNEZlMWcNpFLyp9jfkuE=
github.com/xtls/quic-go v0.48.2/go.mod h1:rcyY5J0JT+1d5pa5Y+FbCsXM7Zu79jE87ZSFOBfiH7Q=
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d h1:+B97uD9uHLgAAulhigmys4BVwZZypzK7gPN3WtpgRJg= 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/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= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg= 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/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.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -119,21 +119,21 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.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.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.5.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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -141,12 +141,12 @@ 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/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 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.1/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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -156,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.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gvisor.dev/gvisor v0.0.0-20240320123526-dc6abceb7ff0 h1:P+U/06iIKPQ3DLcg+zBfSCia1luZ2msPZrJ8jYDFPs0= gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 h1:ze1vwAdliUAr68RQ5NtufWaXaOg8WUO2OACzEV+TNdE=
gvisor.dev/gvisor v0.0.0-20240320123526-dc6abceb7ff0/go.mod h1:NQHVAzMwvZ+Qe3ElSiHmq9RUm1MdNHpUZ52fiEqvn+0= gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk=
h12.io/socks v1.0.3 h1:Ka3qaQewws4j4/eDQnOdpr4wXsC//dXtWvftlIcCQUo= h12.io/socks v1.0.3 h1:Ka3qaQewws4j4/eDQnOdpr4wXsC//dXtWvftlIcCQUo=
h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck= h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
lukechampine.com/blake3 v1.4.0 h1:xDbKOZCVbnZsfzM6mHSYcGRHZ3YrLDzqz8XnV4uaD5w= lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
lukechampine.com/blake3 v1.4.0/go.mod h1:MQJNQCTnR+kwOP/JEZSxj3MaQjp80FOFSNMMHXcSeX0= lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=

View File

@@ -203,24 +203,6 @@ func (list *PortList) Build() *net.PortList {
return portList return portList
} }
func (v PortList) MarshalJSON() ([]byte, error) {
return json.Marshal(v.String())
}
func (v PortList) String() string {
ports := []string{}
for _, port := range v.Range {
if port.From == port.To {
p := strconv.Itoa(int(port.From))
ports = append(ports, p)
} else {
p := fmt.Sprintf("%d-%d", port.From, port.To)
ports = append(ports, p)
}
}
return strings.Join(ports, ",")
}
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON // UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
func (list *PortList) UnmarshalJSON(data []byte) error { func (list *PortList) UnmarshalJSON(data []byte) error {
var listStr string var listStr string

View File

@@ -12,13 +12,13 @@ import (
) )
type NameServerConfig struct { type NameServerConfig struct {
Address *Address `json:"address"` Address *Address
ClientIP *Address `json:"clientIp"` ClientIP *Address
Port uint16 `json:"port"` Port uint16
SkipFallback bool `json:"skipFallback"` SkipFallback bool
Domains []string `json:"domains"` Domains []string
ExpectIPs StringList `json:"expectIps"` ExpectIPs StringList
QueryStrategy string `json:"queryStrategy"` QueryStrategy string
} }
func (c *NameServerConfig) UnmarshalJSON(data []byte) error { func (c *NameServerConfig) UnmarshalJSON(data []byte) error {

View File

@@ -2,7 +2,6 @@ package conf
import ( import (
"encoding/base64" "encoding/base64"
"encoding/hex"
"net" "net"
"strings" "strings"
@@ -153,9 +152,8 @@ func (c *FreedomConfig) Build() (proto.Message, error) {
func ParseNoise(noise *Noise) (*freedom.Noise, error) { func ParseNoise(noise *Noise) (*freedom.Noise, error) {
var err error var err error
NConfig := new(freedom.Noise) NConfig := new(freedom.Noise)
noise.Packet = strings.TrimSpace(noise.Packet)
switch noise.Type { switch strings.ToLower(noise.Type) {
case "rand": case "rand":
min, max, err := ParseRangeString(noise.Packet) min, max, err := ParseRangeString(noise.Packet)
if err != nil { if err != nil {
@@ -168,25 +166,18 @@ func ParseNoise(noise *Noise) (*freedom.Noise, error) {
} }
case "str": case "str":
// user input string //user input string
NConfig.Packet = []byte(noise.Packet) NConfig.StrNoise = []byte(strings.TrimSpace(noise.Packet))
case "hex":
// user input hex
NConfig.Packet, err = hex.DecodeString(noise.Packet)
if err != nil {
return nil, errors.New("Invalid hex string").Base(err)
}
case "base64": case "base64":
// user input base64 //user input base64
NConfig.Packet, err = base64.RawURLEncoding.DecodeString(strings.NewReplacer("+", "-", "/", "_", "=", "").Replace(noise.Packet)) NConfig.StrNoise, err = base64.StdEncoding.DecodeString(strings.TrimSpace(noise.Packet))
if err != nil { if err != nil {
return nil, errors.New("Invalid base64 string").Base(err) return nil, errors.New("Invalid base64 string")
} }
default: default:
return nil, errors.New("Invalid packet, only rand/str/hex/base64 are supported") return nil, errors.New("Invalid packet, only rand/str/base64 are supported")
} }
if noise.Delay != nil { if noise.Delay != nil {

View File

@@ -6,21 +6,15 @@ import (
) )
type MetricsConfig struct { type MetricsConfig struct {
Tag string `json:"tag"` Tag string `json:"tag"`
Listen string `json:"listen"`
} }
func (c *MetricsConfig) Build() (*metrics.Config, error) { func (c *MetricsConfig) Build() (*metrics.Config, error) {
if c.Listen == "" && c.Tag == "" {
return nil, errors.New("Metrics must have a tag or listen address.")
}
// If the tag is empty but have "listen" set a default "Metrics" for compatibility.
if c.Tag == "" { if c.Tag == "" {
c.Tag = "Metrics" return nil, errors.New("metrics tag can't be empty.")
} }
return &metrics.Config{ return &metrics.Config{
Tag: c.Tag, Tag: c.Tag,
Listen: c.Listen,
}, nil }, nil
} }

View File

@@ -231,7 +231,6 @@ type SplitHTTPConfig struct {
ScMaxEachPostBytes Int32Range `json:"scMaxEachPostBytes"` ScMaxEachPostBytes Int32Range `json:"scMaxEachPostBytes"`
ScMinPostsIntervalMs Int32Range `json:"scMinPostsIntervalMs"` ScMinPostsIntervalMs Int32Range `json:"scMinPostsIntervalMs"`
ScMaxBufferedPosts int64 `json:"scMaxBufferedPosts"` ScMaxBufferedPosts int64 `json:"scMaxBufferedPosts"`
ScStreamUpServerSecs Int32Range `json:"scStreamUpServerSecs"`
Xmux XmuxConfig `json:"xmux"` Xmux XmuxConfig `json:"xmux"`
DownloadSettings *StreamConfig `json:"downloadSettings"` DownloadSettings *StreamConfig `json:"downloadSettings"`
Extra json.RawMessage `json:"extra"` Extra json.RawMessage `json:"extra"`
@@ -281,10 +280,6 @@ func (c *SplitHTTPConfig) Build() (proto.Message, error) {
} }
} }
if c.XPaddingBytes != (Int32Range{}) && (c.XPaddingBytes.From <= 0 || c.XPaddingBytes.To <= 0) {
return nil, errors.New("xPaddingBytes cannot be disabled")
}
if c.Xmux.MaxConnections.To > 0 && c.Xmux.MaxConcurrency.To > 0 { if c.Xmux.MaxConnections.To > 0 && c.Xmux.MaxConcurrency.To > 0 {
return nil, errors.New("maxConnections cannot be specified together with maxConcurrency") return nil, errors.New("maxConnections cannot be specified together with maxConcurrency")
} }
@@ -308,7 +303,6 @@ func (c *SplitHTTPConfig) Build() (proto.Message, error) {
ScMaxEachPostBytes: newRangeConfig(c.ScMaxEachPostBytes), ScMaxEachPostBytes: newRangeConfig(c.ScMaxEachPostBytes),
ScMinPostsIntervalMs: newRangeConfig(c.ScMinPostsIntervalMs), ScMinPostsIntervalMs: newRangeConfig(c.ScMinPostsIntervalMs),
ScMaxBufferedPosts: c.ScMaxBufferedPosts, ScMaxBufferedPosts: c.ScMaxBufferedPosts,
ScStreamUpServerSecs: newRangeConfig(c.ScStreamUpServerSecs),
Xmux: &splithttp.XmuxConfig{ Xmux: &splithttp.XmuxConfig{
MaxConcurrency: newRangeConfig(c.Xmux.MaxConcurrency), MaxConcurrency: newRangeConfig(c.Xmux.MaxConcurrency),
MaxConnections: newRangeConfig(c.Xmux.MaxConnections), MaxConnections: newRangeConfig(c.Xmux.MaxConnections),
@@ -410,8 +404,6 @@ type TLSConfig struct {
PinnedPeerCertificatePublicKeySha256 *[]string `json:"pinnedPeerCertificatePublicKeySha256"` PinnedPeerCertificatePublicKeySha256 *[]string `json:"pinnedPeerCertificatePublicKeySha256"`
CurvePreferences *StringList `json:"curvePreferences"` CurvePreferences *StringList `json:"curvePreferences"`
MasterKeyLog string `json:"masterKeyLog"` MasterKeyLog string `json:"masterKeyLog"`
ServerNameToVerify string `json:"serverNameToVerify"`
VerifyPeerCertInNames []string `json:"verifyPeerCertInNames"`
} }
// Build implements Buildable. // Build implements Buildable.
@@ -433,13 +425,6 @@ func (c *TLSConfig) Build() (proto.Message, error) {
if c.ALPN != nil && len(*c.ALPN) > 0 { if c.ALPN != nil && len(*c.ALPN) > 0 {
config.NextProtocol = []string(*c.ALPN) config.NextProtocol = []string(*c.ALPN)
} }
if len(config.NextProtocol) > 1 {
for _, p := range config.NextProtocol {
if tcp.IsFromMitm(p) {
return nil, errors.New(`only one element is allowed in "alpn" when using "fromMitm" in it`)
}
}
}
if c.CurvePreferences != nil && len(*c.CurvePreferences) > 0 { if c.CurvePreferences != nil && len(*c.CurvePreferences) > 0 {
config.CurvePreferences = []string(*c.CurvePreferences) config.CurvePreferences = []string(*c.CurvePreferences)
} }
@@ -450,7 +435,7 @@ func (c *TLSConfig) Build() (proto.Message, error) {
config.CipherSuites = c.CipherSuites config.CipherSuites = c.CipherSuites
config.Fingerprint = strings.ToLower(c.Fingerprint) config.Fingerprint = strings.ToLower(c.Fingerprint)
if config.Fingerprint != "unsafe" && tls.GetFingerprint(config.Fingerprint) == nil { if config.Fingerprint != "unsafe" && tls.GetFingerprint(config.Fingerprint) == nil {
return nil, errors.New(`unknown "fingerprint": `, config.Fingerprint) return nil, errors.New(`unknown fingerprint: `, config.Fingerprint)
} }
config.RejectUnknownSni = c.RejectUnknownSNI config.RejectUnknownSni = c.RejectUnknownSNI
@@ -478,11 +463,6 @@ func (c *TLSConfig) Build() (proto.Message, error) {
config.MasterKeyLog = c.MasterKeyLog config.MasterKeyLog = c.MasterKeyLog
if c.ServerNameToVerify != "" {
return nil, errors.PrintRemovedFeatureError(`"serverNameToVerify"`, `"verifyPeerCertInNames"`)
}
config.VerifyPeerCertInNames = c.VerifyPeerCertInNames
return config, nil return config, nil
} }
@@ -711,7 +691,6 @@ type SocketConfig struct {
Interface string `json:"interface"` Interface string `json:"interface"`
TcpMptcp bool `json:"tcpMptcp"` TcpMptcp bool `json:"tcpMptcp"`
CustomSockopt []*CustomSockoptConfig `json:"customSockopt"` CustomSockopt []*CustomSockoptConfig `json:"customSockopt"`
AddressPortStrategy string `json:"addressPortStrategy"`
} }
// Build implements Buildable. // Build implements Buildable.
@@ -781,26 +760,6 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
customSockopts = append(customSockopts, customSockopt) 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)
}
return &internet.SocketConfig{ return &internet.SocketConfig{
Mark: c.Mark, Mark: c.Mark,
Tfo: tfo, Tfo: tfo,
@@ -819,7 +778,6 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
Interface: c.Interface, Interface: c.Interface,
TcpMptcp: c.TcpMptcp, TcpMptcp: c.TcpMptcp,
CustomSockopt: customSockopts, CustomSockopt: customSockopts,
AddressPortStrategy: addressPortStrategy,
}, nil }, nil
} }

View File

@@ -292,9 +292,7 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
senderSettings.ViaCidr = strings.Split(*c.SendThrough, "/")[1] senderSettings.ViaCidr = strings.Split(*c.SendThrough, "/")[1]
} else { } else {
if address.Family().IsDomain() { if address.Family().IsDomain() {
if address.Address.Domain() != "origin" { return nil, errors.New("unable to send through: " + address.String())
return nil, errors.New("unable to send through: " + address.String())
}
} }
} }
senderSettings.Via = address.Build() senderSettings.Via = address.Build()

View File

@@ -89,11 +89,12 @@ func whichProtoc(suffix, targetedVersion string) (string, error) {
path, err := exec.LookPath(protoc) path, err := exec.LookPath(protoc)
if err != nil { if err != nil {
return "", fmt.Errorf(` errStr := fmt.Sprintf(`
Command "%s" not found. Command "%s" not found.
Make sure that %s is in your system path or current path. 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 Download %s v%s or later from https://github.com/protocolbuffers/protobuf/releases
`, protoc, protoc, protoc, targetedVersion) `, protoc, protoc, protoc, targetedVersion)
return "", fmt.Errorf(errStr)
} }
return path, nil return path, nil
} }

View File

@@ -27,6 +27,5 @@ var CmdAPI = &base.Command{
cmdRemoveRules, cmdRemoveRules,
cmdSourceIpBlock, cmdSourceIpBlock,
cmdOnlineStats, cmdOnlineStats,
cmdOnlineStatsIpList,
}, },
} }

View File

@@ -13,20 +13,25 @@ import (
var cmdBalancerInfo = &base.Command{ var cmdBalancerInfo = &base.Command{
CustomFlags: true, CustomFlags: true,
UsageLine: "{{.Exec}} api bi [--server=127.0.0.1:8080] [balancer]...", UsageLine: "{{.Exec}} api bi [--server=127.0.0.1:8080] [balancer]...",
Short: "Retrieve balancer information", Short: "balancer information",
Long: ` Long: `
Retrieve information of specified balancers, including health, strategy and selecting. Get information of specified balancers, including health, strategy
If no balancer tag specified, information for all balancers is returned. and selecting. If no balancer tag specified, get information of
all balancers.
> Ensure that "RoutingService" is enabled under "config.api.services" in the server configuration. > Make sure you have "RoutingService" set in "config.api.services"
of server config.
Arguments: Arguments:
-json
Use json output.
-s, -server <server:port> -s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout <seconds> -t, -timeout <seconds>
Timeout in seconds for calling API. Default 3 Timeout seconds to call API. Default 3
Example: Example:

View File

@@ -7,27 +7,31 @@ import (
var cmdBalancerOverride = &base.Command{ var cmdBalancerOverride = &base.Command{
CustomFlags: true, CustomFlags: true,
UsageLine: "{{.Exec}} api bo [--server=127.0.0.1:8080] <-b balancer> outboundTag <-r>", UsageLine: "{{.Exec}} api bo [--server=127.0.0.1:8080] <-b balancer> outboundTag",
Short: "Override balancer", Short: "balancer override",
Long: ` Long: `
Override the selection target of a balancer. Override a balancer's selection.
> Ensure that the "RoutingService" is properly configured under "config.api.services" in the server configuration. > Make sure you have "RoutingService" set in "config.api.services"
of server config.
Once the balancer's selection is overridden: Once a balancer's selecting is overridden:
- The balancer's selection result will always be outboundTag - The balancer's selection result will always be outboundTag
Arguments: Arguments:
-s, -server <server:port> -r, -remove
The API server address. Default 127.0.0.1:8080 Remove the overridden
-t, -timeout <seconds>
Timeout in seconds for calling API. Default 3
-r, -remove -r, -remove
Remove the existing override. Remove the override
-s, -server
The API server address. Default 127.0.0.1:8080
-t, -timeout
Timeout seconds to call API. Default 3
Example: Example:

View File

@@ -8,28 +8,20 @@ import (
var cmdInboundUser = &base.Command{ var cmdInboundUser = &base.Command{
CustomFlags: true, CustomFlags: true,
UsageLine: "{{.Exec}} api inbounduser [--server=127.0.0.1:8080] -tag=tag [-email=email]", UsageLine: "{{.Exec}} api inbounduser [--server=127.0.0.1:8080] -tag=tag [-email=email]",
Short: "Retrieve inbound user(s)", Short: "Get Inbound User",
Long: ` Long: `
Get User info from an inbound. Get User info from an inbound.
Arguments: Arguments:
-s, -server
-s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout
-t, -timeout <seconds> Timeout seconds to call API. Default 3
Timeout in seconds for calling API. Default 3
-tag -tag
Inbound tag Inbound tag
-email
-email User email. If email is not given, will get all users
The user's email address. If not provided, all users will be retrieved.
Example: Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -tag="tag name" -email="xray@love.com"
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -tag="tag name"
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -tag="tag name" -email="xray@love.com"
`, `,
Run: executeInboundUser, Run: executeInboundUser,
} }

View File

@@ -8,24 +8,18 @@ import (
var cmdInboundUserCount = &base.Command{ var cmdInboundUserCount = &base.Command{
CustomFlags: true, CustomFlags: true,
UsageLine: "{{.Exec}} api inboundusercount [--server=127.0.0.1:8080] -tag=tag", UsageLine: "{{.Exec}} api inboundusercount [--server=127.0.0.1:8080] -tag=tag",
Short: "Retrieve inbound user count", Short: "Get Inbound User Count",
Long: ` Long: `
Retrieve the user count for a specified inbound tag. Get User count from an inbound.
Arguments: Arguments:
-s, -server
-s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout
-t, -timeout <seconds> Timeout seconds to call API. Default 3
Timeout in seconds for calling API. Default 3
-tag -tag
Inbound tag Inbound tag
Example: Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -tag="tag name"
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -tag="tag name"
`, `,
Run: executeInboundUserCount, Run: executeInboundUserCount,
} }

View File

@@ -15,18 +15,13 @@ var cmdAddInbounds = &base.Command{
Short: "Add inbounds", Short: "Add inbounds",
Long: ` Long: `
Add inbounds to Xray. Add inbounds to Xray.
Arguments: Arguments:
-s, -server
-s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout
-t, -timeout <seconds> Timeout seconds to call API. Default 3
Timeout in seconds for calling API. Default 3
Example: Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json c2.json
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json c2.json
`, `,
Run: executeAddInbounds, Run: executeAddInbounds,
} }

View File

@@ -14,18 +14,13 @@ var cmdRemoveInbounds = &base.Command{
Short: "Remove inbounds", Short: "Remove inbounds",
Long: ` Long: `
Remove inbounds from Xray. Remove inbounds from Xray.
Arguments: Arguments:
-s, -server
-s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout
-t, -timeout <seconds> Timeout seconds to call API. Default 3
Timeout in seconds for calling API. Default 3
Example: Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json "tag name"
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json "tag name"
`, `,
Run: executeRemoveInbounds, Run: executeRemoveInbounds,
} }

View File

@@ -11,18 +11,11 @@ var cmdRestartLogger = &base.Command{
Short: "Restart the logger", Short: "Restart the logger",
Long: ` Long: `
Restart the logger of Xray. Restart the logger of Xray.
Arguments: Arguments:
-s, -server
-s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout
-t, -timeout <seconds> Timeout seconds to call API. Default 3
Timeout in seconds for calling API. Default 3
Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080
`, `,
Run: executeRestartLogger, Run: executeRestartLogger,
} }

View File

@@ -15,18 +15,13 @@ var cmdAddOutbounds = &base.Command{
Short: "Add outbounds", Short: "Add outbounds",
Long: ` Long: `
Add outbounds to Xray. Add outbounds to Xray.
Arguments: Arguments:
-s, -server
-s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout
-t, -timeout <seconds> Timeout seconds to call API. Default 3
Timeout in seconds for calling API. Default 3
Example: Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json c2.json
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json c2.json
`, `,
Run: executeAddOutbounds, Run: executeAddOutbounds,
} }

View File

@@ -14,18 +14,13 @@ var cmdRemoveOutbounds = &base.Command{
Short: "Remove outbounds", Short: "Remove outbounds",
Long: ` Long: `
Remove outbounds from Xray. Remove outbounds from Xray.
Arguments: Arguments:
-s, -server
-s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout
-t, -timeout <seconds> Timeout seconds to call API. Default 3
Timeout in seconds for calling API. Default 3
Example: Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json "tag name"
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json "tag name"
`, `,
Run: executeRemoveOutbounds, Run: executeRemoveOutbounds,
} }

View File

@@ -16,21 +16,16 @@ var cmdAddRules = &base.Command{
Short: "Add routing rules", Short: "Add routing rules",
Long: ` Long: `
Add routing rules to Xray. Add routing rules to Xray.
Arguments: Arguments:
-s, -server
-s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout
-t, -timeout <seconds>
Timeout seconds to call API. Default 3 Timeout seconds to call API. Default 3
-append -append
Append to the existing configuration instead of replacing it. Default false append or replace config. Default false
Example: Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json c2.json
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json c2.json
`, `,
Run: executeAddRules, Run: executeAddRules,
} }

View File

@@ -9,22 +9,17 @@ import (
var cmdRemoveRules = &base.Command{ var cmdRemoveRules = &base.Command{
CustomFlags: true, CustomFlags: true,
UsageLine: "{{.Exec}} api rmrules [--server=127.0.0.1:8080] [ruleTag]...", UsageLine: "{{.Exec}} api rmrules [--server=127.0.0.1:8080] ruleTag1 ruleTag2...",
Short: "Remove routing rules by ruleTag", Short: "Remove routing rules by ruleTag",
Long: ` Long: `
Remove routing rules by ruleTag from Xray. Remove routing rules by ruleTag from Xray.
Arguments: Arguments:
-s, -server
-s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout
-t, -timeout <seconds> Timeout seconds to call API. Default 3
Timeout in seconds for calling API. Default 3
Example: Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 ruleTag1 ruleTag2
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 ruleTag1 ruleTag2
`, `,
Run: executeRemoveRules, Run: executeRemoveRules,
} }

View File

@@ -14,34 +14,25 @@ import (
var cmdSourceIpBlock = &base.Command{ var cmdSourceIpBlock = &base.Command{
CustomFlags: true, CustomFlags: true,
UsageLine: "{{.Exec}} api sib [--server=127.0.0.1:8080] -outbound=blocked -inbound=socks 1.2.3.4", UsageLine: "{{.Exec}} api sib [--server=127.0.0.1:8080] -outbound=blocked -inbound=socks 1.2.3.4",
Short: "Block connections by source IP", Short: "Drop connections by source ip",
Long: ` Long: `
Block connections by source IP address. Drop connections by source ip.
Arguments: Arguments:
-s, -server
-s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout
-t, -timeout <seconds> Timeout seconds to call API. Default 3
Timeout in seconds for calling API. Default 3
-outbound -outbound
Specifies the outbound tag. route traffic to specific outbound.
-inbound -inbound
Specifies the inbound tag. target traffig from specific inbound.
-ruletag -ruletag
The ruleTag. Default sourceIpBlock set ruleTag. Default sourceIpBlock
-reset -reset
remove ruletag and apply new source IPs. Default false remove ruletag and apply new source IPs. Default false
Example: Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json c2.json
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -outbound=blocked -inbound=socks 1.2.3.4
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -outbound=blocked -inbound=socks 1.2.3.4 -reset
`, `,
Run: executeSourceIpBlock, Run: executeSourceIpBlock,
} }

View File

@@ -8,26 +8,19 @@ import (
var cmdGetStats = &base.Command{ var cmdGetStats = &base.Command{
CustomFlags: true, CustomFlags: true,
UsageLine: "{{.Exec}} api stats [--server=127.0.0.1:8080] [-name '']", UsageLine: "{{.Exec}} api stats [--server=127.0.0.1:8080] [-name '']",
Short: "Retrieve statistics", Short: "Get statistics",
Long: ` Long: `
Retrieve the statistics from Xray. Get statistics from Xray.
Arguments: Arguments:
-s, -server
-s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout
-t, -timeout <seconds> Timeout seconds to call API. Default 3
Timeout in seconds for calling API. Default 3
-name -name
Name of the counter. Name of the stat counter.
-reset -reset
Reset the counter after fetching their values. Default false Reset the counter to fetching its value.
Example: Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -name "inbound>>>statin>>>traffic>>>downlink" {{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -name "inbound>>>statin>>>traffic>>>downlink"
`, `,
Run: executeGetStats, Run: executeGetStats,

View File

@@ -7,25 +7,21 @@ import (
var cmdOnlineStats = &base.Command{ var cmdOnlineStats = &base.Command{
CustomFlags: true, CustomFlags: true,
UsageLine: "{{.Exec}} api statsonline [--server=127.0.0.1:8080] [-email '']", UsageLine: "{{.Exec}} api statsonline [--server=127.0.0.1:8080] [-name '']",
Short: "Retrieve the online session count for a user", Short: "Get online user",
Long: ` Long: `
Retrieve the current number of active sessions for a user from Xray. Get statistics from Xray.
Arguments: Arguments:
-s, -server
-s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout
-t, -timeout <seconds> Timeout seconds to call API. Default 3
Timeout in seconds for calling API. Default 3
-email -email
The user's email address. email of the user.
-reset
Reset the counter to fetching its value.
Example: Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -email "user1@test.com"
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -email "xray@love.com"
`, `,
Run: executeOnlineStats, Run: executeOnlineStats,
} }

View File

@@ -1,51 +0,0 @@
package api
import (
statsService "github.com/xtls/xray-core/app/stats/command"
"github.com/xtls/xray-core/main/commands/base"
)
var cmdOnlineStatsIpList = &base.Command{
CustomFlags: true,
UsageLine: "{{.Exec}} api statsonlineiplist [--server=127.0.0.1:8080] [-email '']",
Short: "Retrieve a user's online IP addresses and access times",
Long: `
Retrieve the online IP addresses and corresponding access timestamps for a user from 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
-email
The user's email address.
Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -email "xray@love.com"
`,
Run: executeOnlineStatsIpList,
}
func executeOnlineStatsIpList(cmd *base.Command, args []string) {
setSharedFlags(cmd)
email := cmd.Flag.String("email", "", "")
cmd.Flag.Parse(args)
statName := "user>>>" + *email + ">>>online"
conn, ctx, close := dialAPIServer()
defer close()
client := statsService.NewStatsServiceClient(conn)
r := &statsService.GetStatsRequest{
Name: statName,
Reset_: false,
}
resp, err := client.GetStatsOnlineIpList(ctx, r)
if err != nil {
base.Fatalf("failed to get stats: %s", err)
}
showJSONResponse(resp)
}

View File

@@ -11,23 +11,16 @@ var cmdQueryStats = &base.Command{
Short: "Query statistics", Short: "Query statistics",
Long: ` Long: `
Query statistics from Xray. Query statistics from Xray.
Arguments: Arguments:
-s, -server
-s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout
-t, -timeout <seconds> Timeout seconds to call API. Default 3
Timeout in seconds for calling API. Default 3
-pattern -pattern
Filter pattern for the statistics query. Pattern of the query.
-reset -reset
Reset the counter after fetching their values. Default false Reset the counter to fetching its value.
Example: Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -pattern "counter_" {{.Exec}} {{.LongName}} --server=127.0.0.1:8080 -pattern "counter_"
`, `,
Run: executeQueryStats, Run: executeQueryStats,

View File

@@ -8,21 +8,14 @@ import (
var cmdSysStats = &base.Command{ var cmdSysStats = &base.Command{
CustomFlags: true, CustomFlags: true,
UsageLine: "{{.Exec}} api statssys [--server=127.0.0.1:8080]", UsageLine: "{{.Exec}} api statssys [--server=127.0.0.1:8080]",
Short: "Retrieve system statistics", Short: "Get system statistics",
Long: ` Long: `
Retrieve system statistics from Xray. Get system statistics from Xray.
Arguments: Arguments:
-s, -server
-s, -server <server:port>
The API server address. Default 127.0.0.1:8080 The API server address. Default 127.0.0.1:8080
-t, -timeout
-t, -timeout <seconds> Timeout seconds to call API. Default 3
Timeout in seconds for calling API. Default 3
Example:
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080
`, `,
Run: executeSysStats, Run: executeSysStats,
} }

View File

@@ -50,17 +50,17 @@ func executeTypedMessageToJson(cmd *base.Command, args []string) {
reader, err := confloader.LoadConfig(cmd.Flag.Arg(0)) reader, err := confloader.LoadConfig(cmd.Flag.Arg(0))
if err != nil { if err != nil {
base.Fatalf("failed to load config: %s", err) base.Fatalf(err.Error())
} }
b, err := io.ReadAll(reader) b, err := io.ReadAll(reader)
if err != nil { if err != nil {
base.Fatalf("failed to read config: %s", err) base.Fatalf(err.Error())
} }
tm := cserial.TypedMessage{} tm := cserial.TypedMessage{}
if err = json.Unmarshal(b, &tm); err != nil { if err = json.Unmarshal(b, &tm); err != nil {
base.Fatalf("failed to unmarshal config: %s", err) base.Fatalf(err.Error())
} }
if j, ok := creflect.MarshalToJson(&tm, injectTypeInfo); ok { if j, ok := creflect.MarshalToJson(&tm, injectTypeInfo); ok {

View File

@@ -53,12 +53,12 @@ func executeConvertConfigsToProtobuf(cmd *base.Command, args []string) {
} }
if len(unnamedArgs) < 1 { if len(unnamedArgs) < 1 {
base.Fatalf("invalid config list length: %d", len(unnamedArgs)) base.Fatalf("empty config list")
} }
pbConfig, err := core.LoadConfig("auto", unnamedArgs) pbConfig, err := core.LoadConfig("auto", unnamedArgs)
if err != nil { if err != nil {
base.Fatalf("failed to load config: %s", err) base.Fatalf(err.Error())
} }
if optDump { if optDump {

View File

@@ -42,8 +42,7 @@ func Curve25519Genkey(StdEncoding bool, input_base64 string) {
// Modify random bytes using algorithm described at: // Modify random bytes using algorithm described at:
// https://cr.yp.to/ecdh.html. // https://cr.yp.to/ecdh.html.
privateKey[0] &= 248 privateKey[0] &= 248
privateKey[31] &= 127 privateKey[31] &= 127 | 64
privateKey[31] |= 64
if publicKey, err = curve25519.X25519(privateKey, curve25519.Basepoint); err != nil { if publicKey, err = curve25519.X25519(privateKey, curve25519.Basepoint); err != nil {
output = err.Error() output = err.Error()

View File

@@ -120,9 +120,9 @@ func writeFile(content []byte, name string) error {
func printFile(certificate *cert.Certificate, name string) error { func printFile(certificate *cert.Certificate, name string) error {
certPEM, keyPEM := certificate.ToPEM() certPEM, keyPEM := certificate.ToPEM()
return task.Run(context.Background(), func() error { return task.Run(context.Background(), func() error {
return writeFile(certPEM, name+".crt") return writeFile(certPEM, name+"_cert.pem")
}, func() error { }, func() error {
return writeFile(keyPEM, name+".key") return writeFile(keyPEM, name+"_key.pem")
}) })
} }

View File

@@ -45,7 +45,6 @@ The -dump flag tells Xray to print the merged config.
func init() { func init() {
cmdRun.Run = executeRun // break init loop cmdRun.Run = executeRun // break init loop
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
} }
var ( var (

View File

@@ -18,7 +18,6 @@ import (
"github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls"
) )
func init() { func init() {
@@ -64,6 +63,10 @@ func (d *DokodemoDoor) policy() policy.Session {
return p return p
} }
type hasHandshakeAddressContext interface {
HandshakeAddressContext(ctx context.Context) net.Address
}
// Process implements proxy.Inbound. // Process implements proxy.Inbound.
func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error { func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error {
errors.LogDebug(ctx, "processing connection from: ", conn.RemoteAddr()) errors.LogDebug(ctx, "processing connection from: ", conn.RemoteAddr())
@@ -83,14 +86,11 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
destinationOverridden = true destinationOverridden = true
} }
} }
if tlsConn, ok := conn.(tls.Interface); ok && !destinationOverridden { if handshake, ok := conn.(hasHandshakeAddressContext); ok && !destinationOverridden {
if serverName := tlsConn.HandshakeContextServerName(ctx); serverName != "" { addr := handshake.HandshakeAddressContext(ctx)
dest.Address = net.DomainAddress(serverName) if addr != nil {
dest.Address = addr
destinationOverridden = true destinationOverridden = true
ctx = session.ContextWithMitmServerName(ctx, serverName)
}
if tlsConn.NegotiatedProtocol() != "h2" {
ctx = session.ContextWithMitmAlpn11(ctx, true)
} }
} }
} }

View File

@@ -233,7 +233,7 @@ type Noise struct {
LengthMax uint64 `protobuf:"varint,2,opt,name=length_max,json=lengthMax,proto3" json:"length_max,omitempty"` LengthMax uint64 `protobuf:"varint,2,opt,name=length_max,json=lengthMax,proto3" json:"length_max,omitempty"`
DelayMin uint64 `protobuf:"varint,3,opt,name=delay_min,json=delayMin,proto3" json:"delay_min,omitempty"` DelayMin uint64 `protobuf:"varint,3,opt,name=delay_min,json=delayMin,proto3" json:"delay_min,omitempty"`
DelayMax uint64 `protobuf:"varint,4,opt,name=delay_max,json=delayMax,proto3" json:"delay_max,omitempty"` DelayMax uint64 `protobuf:"varint,4,opt,name=delay_max,json=delayMax,proto3" json:"delay_max,omitempty"`
Packet []byte `protobuf:"bytes,5,opt,name=packet,proto3" json:"packet,omitempty"` StrNoise []byte `protobuf:"bytes,5,opt,name=str_noise,json=strNoise,proto3" json:"str_noise,omitempty"`
} }
func (x *Noise) Reset() { func (x *Noise) Reset() {
@@ -294,9 +294,9 @@ func (x *Noise) GetDelayMax() uint64 {
return 0 return 0
} }
func (x *Noise) GetPacket() []byte { func (x *Noise) GetStrNoise() []byte {
if x != nil { if x != nil {
return x.Packet return x.StrNoise
} }
return nil return nil
} }
@@ -412,7 +412,7 @@ var file_proxy_freedom_config_proto_rawDesc = []byte{
0x6c, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x6c, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x69, 0x6e, 0x74,
0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x61, 0x78, 0x22, 0x97, 0x01, 0x0a, 0x05, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x61, 0x78, 0x22, 0x9c, 0x01, 0x0a, 0x05,
0x4e, 0x6f, 0x69, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f,
0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74,
0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d,
@@ -420,49 +420,49 @@ var file_proxy_freedom_config_proto_rawDesc = []byte{
0x4d, 0x61, 0x78, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x69, 0x6e, 0x4d, 0x61, 0x78, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x69, 0x6e,
0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x69, 0x6e,
0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20,
0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x61, 0x78, 0x12, 0x16, 0x0a, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x61, 0x78, 0x12, 0x1b, 0x0a,
0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x09, 0x73, 0x74, 0x72, 0x5f, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c,
0x61, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x97, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x74, 0x72, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x22, 0x97, 0x04, 0x0a, 0x06, 0x43,
0x12, 0x52, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x52, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f,
0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x43, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x64, 0x6f, 0x6d, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69,
0x74, 0x65, 0x67, 0x79, 0x12, 0x5a, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x5a, 0x0a, 0x14, 0x64, 0x65, 0x73,
0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70,
0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x44, 0x65, 0x73,
0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x13, 0x64, 0x65, 0x73,
0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65,
0x38, 0x0a, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c,
0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74,
0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72,
0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x46, 0x72, 0x61, 0x67,
0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x25,
0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x12, 0x31, 0x0a, 0x06, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f,
0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x31, 0x0a, 0x06, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x18,
0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x52, 0x06, 0x6e, 0x6f, 0x69, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
0x73, 0x65, 0x73, 0x22, 0xa9, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x4e, 0x6f, 0x69, 0x73, 0x65,
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x49, 0x53, 0x10, 0x52, 0x06, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x22, 0xa9, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x6d,
0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41,
0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x53, 0x5f, 0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50,
0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12,
0x50, 0x34, 0x36, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08,
0x34, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53,
0x06, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x07, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x4f, 0x52, 0x43,
0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x08, 0x12, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x06, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f,
0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10, 0x09, 0x12, 0x49, 0x50, 0x34, 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49,
0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, 0x10, 0x0a, 0x42, 0x50, 0x36, 0x10, 0x08, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50,
0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x34, 0x36, 0x10, 0x09, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50,
0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x36, 0x34, 0x10, 0x0a, 0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x50, 0x01,
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x66, 0x72, 0x65, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c,
0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78,
0x79, 0x2e, 0x46, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x79, 0x2f, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79,
0x33, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x46, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -25,7 +25,7 @@ message Noise {
uint64 length_max = 2; uint64 length_max = 2;
uint64 delay_min = 3; uint64 delay_min = 3;
uint64 delay_max = 4; uint64 delay_max = 4;
bytes packet = 5; bytes str_noise = 5;
} }
message Config { message Config {

View File

@@ -4,12 +4,12 @@ import (
"context" "context"
"crypto/rand" "crypto/rand"
"io" "io"
"math/big"
"time" "time"
"github.com/pires/go-proxyproto" "github.com/pires/go-proxyproto"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
@@ -266,9 +266,6 @@ func isTLSConn(conn stat.Connection) bool {
if _, ok := conn.(*tls.Conn); ok { if _, ok := conn.(*tls.Conn); ok {
return true return true
} }
if _, ok := conn.(*tls.UConn); ok {
return true
}
} }
return false return false
} }
@@ -410,11 +407,11 @@ func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
var err error var err error
for _, n := range w.noises { for _, n := range w.noises {
//User input string or base64 encoded string //User input string or base64 encoded string
if n.Packet != nil { if n.StrNoise != nil {
noise = n.Packet noise = n.StrNoise
} else { } else {
//Random noise //Random noise
noise, err = GenerateRandomBytes(crypto.RandBetween(int64(n.LengthMin), noise, err = GenerateRandomBytes(randBetween(int64(n.LengthMin),
int64(n.LengthMax))) int64(n.LengthMax)))
} }
if err != nil { if err != nil {
@@ -423,7 +420,7 @@ func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)}) w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)})
if n.DelayMin != 0 || n.DelayMax != 0 { if n.DelayMin != 0 || n.DelayMax != 0 {
time.Sleep(time.Duration(crypto.RandBetween(int64(n.DelayMin), int64(n.DelayMax))) * time.Millisecond) time.Sleep(time.Duration(randBetween(int64(n.DelayMin), int64(n.DelayMax))) * time.Millisecond)
} }
} }
@@ -452,7 +449,7 @@ func (f *FragmentWriter) Write(b []byte) (int, error) {
buf := make([]byte, 1024) buf := make([]byte, 1024)
var hello []byte var hello []byte
for from := 0; ; { for from := 0; ; {
to := from + int(crypto.RandBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax))) to := from + int(randBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax)))
if to > len(data) { if to > len(data) {
to = len(data) to = len(data)
} }
@@ -466,7 +463,7 @@ func (f *FragmentWriter) Write(b []byte) (int, error) {
hello = append(hello, buf[:5+l]...) hello = append(hello, buf[:5+l]...)
} else { } else {
_, err := f.writer.Write(buf[:5+l]) _, err := f.writer.Write(buf[:5+l])
time.Sleep(time.Duration(crypto.RandBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond) time.Sleep(time.Duration(randBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@@ -493,13 +490,13 @@ func (f *FragmentWriter) Write(b []byte) (int, error) {
return f.writer.Write(b) return f.writer.Write(b)
} }
for from := 0; ; { for from := 0; ; {
to := from + int(crypto.RandBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax))) to := from + int(randBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax)))
if to > len(b) { if to > len(b) {
to = len(b) to = len(b)
} }
n, err := f.writer.Write(b[from:to]) n, err := f.writer.Write(b[from:to])
from += n from += n
time.Sleep(time.Duration(crypto.RandBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond) time.Sleep(time.Duration(randBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond)
if err != nil { if err != nil {
return from, err return from, err
} }
@@ -509,6 +506,14 @@ func (f *FragmentWriter) Write(b []byte) (int, error) {
} }
} }
// stolen from github.com/xtls/xray-core/transport/internet/reality
func randBetween(left int64, right int64) int64 {
if left == right {
return left
}
bigInt, _ := rand.Int(rand.Reader, big.NewInt(right-left))
return left + bigInt.Int64()
}
func GenerateRandomBytes(n int64) ([]byte, error) { func GenerateRandomBytes(n int64) ([]byte, error) {
b := make([]byte, n) b := make([]byte, n)
_, err := rand.Read(b) _, err := rand.Read(b)

View File

@@ -151,7 +151,6 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
return buf.Copy(link.Reader, buf.NewWriter(conn), buf.UpdateActivity(timer)) return buf.Copy(link.Reader, buf.NewWriter(conn), buf.UpdateActivity(timer))
} }
responseFunc := func() error { responseFunc := func() error {
ob.CanSpliceCopy = 1
defer timer.SetTimeout(p.Timeouts.UplinkOnly) defer timer.SetTimeout(p.Timeouts.UplinkOnly)
return buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer)) return buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer))
} }

View File

@@ -207,7 +207,6 @@ func (s *Server) handleConnect(ctx context.Context, _ *http.Request, reader *buf
} }
responseDone := func() error { responseDone := func() error {
inbound.CanSpliceCopy = 1
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly) defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
v2writer := buf.NewWriter(conn) v2writer := buf.NewWriter(conn)

View File

@@ -107,65 +107,37 @@ type TrafficState struct {
IsTLS bool IsTLS bool
Cipher uint16 Cipher uint16
RemainingServerHello int32 RemainingServerHello int32
Inbound InboundState
Outbound OutboundState
}
type InboundState struct {
// reader link state
WithinPaddingBuffers bool
UplinkReaderDirectCopy bool
RemainingCommand int32
RemainingContent int32
RemainingPadding int32
CurrentCommand int
// write link state
IsPadding bool
DownlinkWriterDirectCopy bool
}
type OutboundState struct {
// reader link state // reader link state
WithinPaddingBuffers bool WithinPaddingBuffers bool
DownlinkReaderDirectCopy bool ReaderSwitchToDirectCopy bool
RemainingCommand int32 RemainingCommand int32
RemainingContent int32 RemainingContent int32
RemainingPadding int32 RemainingPadding int32
CurrentCommand int CurrentCommand int
// write link state // write link state
IsPadding bool IsPadding bool
UplinkWriterDirectCopy bool WriterSwitchToDirectCopy bool
} }
func NewTrafficState(userUUID []byte) *TrafficState { func NewTrafficState(userUUID []byte) *TrafficState {
return &TrafficState{ return &TrafficState{
UserUUID: userUUID, UserUUID: userUUID,
NumberOfPacketToFilter: 8, NumberOfPacketToFilter: 8,
EnableXtls: false, EnableXtls: false,
IsTLS12orAbove: false, IsTLS12orAbove: false,
IsTLS: false, IsTLS: false,
Cipher: 0, Cipher: 0,
RemainingServerHello: -1, RemainingServerHello: -1,
Inbound: InboundState{ WithinPaddingBuffers: true,
WithinPaddingBuffers: true, ReaderSwitchToDirectCopy: false,
UplinkReaderDirectCopy: false, RemainingCommand: -1,
RemainingCommand: -1, RemainingContent: -1,
RemainingContent: -1, RemainingPadding: -1,
RemainingPadding: -1, CurrentCommand: 0,
CurrentCommand: 0, IsPadding: true,
IsPadding: true, WriterSwitchToDirectCopy: false,
DownlinkWriterDirectCopy: false,
},
Outbound: OutboundState{
WithinPaddingBuffers: true,
DownlinkReaderDirectCopy: false,
RemainingCommand: -1,
RemainingContent: -1,
RemainingPadding: -1,
CurrentCommand: 0,
IsPadding: true,
UplinkWriterDirectCopy: false,
},
} }
} }
@@ -175,58 +147,37 @@ type VisionReader struct {
buf.Reader buf.Reader
trafficState *TrafficState trafficState *TrafficState
ctx context.Context ctx context.Context
isUplink bool
} }
func NewVisionReader(reader buf.Reader, state *TrafficState, isUplink bool, context context.Context) *VisionReader { func NewVisionReader(reader buf.Reader, state *TrafficState, context context.Context) *VisionReader {
return &VisionReader{ return &VisionReader{
Reader: reader, Reader: reader,
trafficState: state, trafficState: state,
ctx: context, ctx: context,
isUplink: isUplink,
} }
} }
func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) { func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
buffer, err := w.Reader.ReadMultiBuffer() buffer, err := w.Reader.ReadMultiBuffer()
if !buffer.IsEmpty() { if !buffer.IsEmpty() {
var withinPaddingBuffers *bool if w.trafficState.WithinPaddingBuffers || w.trafficState.NumberOfPacketToFilter > 0 {
var remainingContent *int32
var remainingPadding *int32
var currentCommand *int
var switchToDirectCopy *bool
if w.isUplink {
withinPaddingBuffers = &w.trafficState.Inbound.WithinPaddingBuffers
remainingContent = &w.trafficState.Inbound.RemainingContent
remainingPadding = &w.trafficState.Inbound.RemainingPadding
currentCommand = &w.trafficState.Inbound.CurrentCommand
switchToDirectCopy = &w.trafficState.Inbound.UplinkReaderDirectCopy
} else {
withinPaddingBuffers = &w.trafficState.Outbound.WithinPaddingBuffers
remainingContent = &w.trafficState.Outbound.RemainingContent
remainingPadding = &w.trafficState.Outbound.RemainingPadding
currentCommand = &w.trafficState.Outbound.CurrentCommand
switchToDirectCopy = &w.trafficState.Outbound.DownlinkReaderDirectCopy
}
if *withinPaddingBuffers || w.trafficState.NumberOfPacketToFilter > 0 {
mb2 := make(buf.MultiBuffer, 0, len(buffer)) mb2 := make(buf.MultiBuffer, 0, len(buffer))
for _, b := range buffer { for _, b := range buffer {
newbuffer := XtlsUnpadding(b, w.trafficState, w.isUplink, w.ctx) newbuffer := XtlsUnpadding(b, w.trafficState, w.ctx)
if newbuffer.Len() > 0 { if newbuffer.Len() > 0 {
mb2 = append(mb2, newbuffer) mb2 = append(mb2, newbuffer)
} }
} }
buffer = mb2 buffer = mb2
if *remainingContent > 0 || *remainingPadding > 0 || *currentCommand == 0 { if w.trafficState.RemainingContent > 0 || w.trafficState.RemainingPadding > 0 || w.trafficState.CurrentCommand == 0 {
*withinPaddingBuffers = true w.trafficState.WithinPaddingBuffers = true
} else if *currentCommand == 1 { } else if w.trafficState.CurrentCommand == 1 {
*withinPaddingBuffers = false w.trafficState.WithinPaddingBuffers = false
} else if *currentCommand == 2 { } else if w.trafficState.CurrentCommand == 2 {
*withinPaddingBuffers = false w.trafficState.WithinPaddingBuffers = false
*switchToDirectCopy = true w.trafficState.ReaderSwitchToDirectCopy = true
} else { } else {
errors.LogInfo(w.ctx, "XtlsRead unknown command ", *currentCommand, buffer.Len()) errors.LogInfo(w.ctx, "XtlsRead unknown command ", w.trafficState.CurrentCommand, buffer.Len())
} }
} }
if w.trafficState.NumberOfPacketToFilter > 0 { if w.trafficState.NumberOfPacketToFilter > 0 {
@@ -243,10 +194,9 @@ type VisionWriter struct {
trafficState *TrafficState trafficState *TrafficState
ctx context.Context ctx context.Context
writeOnceUserUUID []byte writeOnceUserUUID []byte
isUplink bool
} }
func NewVisionWriter(writer buf.Writer, state *TrafficState, isUplink bool, context context.Context) *VisionWriter { func NewVisionWriter(writer buf.Writer, state *TrafficState, context context.Context) *VisionWriter {
w := make([]byte, len(state.UserUUID)) w := make([]byte, len(state.UserUUID))
copy(w, state.UserUUID) copy(w, state.UserUUID)
return &VisionWriter{ return &VisionWriter{
@@ -254,7 +204,6 @@ func NewVisionWriter(writer buf.Writer, state *TrafficState, isUplink bool, cont
trafficState: state, trafficState: state,
ctx: context, ctx: context,
writeOnceUserUUID: w, writeOnceUserUUID: w,
isUplink: isUplink,
} }
} }
@@ -262,16 +211,7 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
if w.trafficState.NumberOfPacketToFilter > 0 { if w.trafficState.NumberOfPacketToFilter > 0 {
XtlsFilterTls(mb, w.trafficState, w.ctx) XtlsFilterTls(mb, w.trafficState, w.ctx)
} }
var isPadding *bool if w.trafficState.IsPadding {
var switchToDirectCopy *bool
if w.isUplink {
isPadding = &w.trafficState.Outbound.IsPadding
switchToDirectCopy = &w.trafficState.Outbound.UplinkWriterDirectCopy
} else {
isPadding = &w.trafficState.Inbound.IsPadding
switchToDirectCopy = &w.trafficState.Inbound.DownlinkWriterDirectCopy
}
if *isPadding {
if len(mb) == 1 && mb[0] == nil { if len(mb) == 1 && mb[0] == nil {
mb[0] = XtlsPadding(nil, CommandPaddingContinue, &w.writeOnceUserUUID, true, w.ctx) // we do a long padding to hide vless header mb[0] = XtlsPadding(nil, CommandPaddingContinue, &w.writeOnceUserUUID, true, w.ctx) // we do a long padding to hide vless header
return w.Writer.WriteMultiBuffer(mb) return w.Writer.WriteMultiBuffer(mb)
@@ -281,7 +221,7 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
for i, b := range mb { for i, b := range mb {
if w.trafficState.IsTLS && b.Len() >= 6 && bytes.Equal(TlsApplicationDataStart, b.BytesTo(3)) { if w.trafficState.IsTLS && b.Len() >= 6 && bytes.Equal(TlsApplicationDataStart, b.BytesTo(3)) {
if w.trafficState.EnableXtls { if w.trafficState.EnableXtls {
*switchToDirectCopy = true w.trafficState.WriterSwitchToDirectCopy = true
} }
var command byte = CommandPaddingContinue var command byte = CommandPaddingContinue
if i == len(mb)-1 { if i == len(mb)-1 {
@@ -291,16 +231,16 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
} }
} }
mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, true, w.ctx) mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, true, w.ctx)
*isPadding = false // padding going to end w.trafficState.IsPadding = false // padding going to end
longPadding = false longPadding = false
continue continue
} else if !w.trafficState.IsTLS12orAbove && w.trafficState.NumberOfPacketToFilter <= 1 { // For compatibility with earlier vision receiver, we finish padding 1 packet early } else if !w.trafficState.IsTLS12orAbove && w.trafficState.NumberOfPacketToFilter <= 1 { // For compatibility with earlier vision receiver, we finish padding 1 packet early
*isPadding = false w.trafficState.IsPadding = false
mb[i] = XtlsPadding(b, CommandPaddingEnd, &w.writeOnceUserUUID, longPadding, w.ctx) mb[i] = XtlsPadding(b, CommandPaddingEnd, &w.writeOnceUserUUID, longPadding, w.ctx)
break break
} }
var command byte = CommandPaddingContinue var command byte = CommandPaddingContinue
if i == len(mb)-1 && !*isPadding { if i == len(mb)-1 && !w.trafficState.IsPadding {
command = CommandPaddingEnd command = CommandPaddingEnd
if w.trafficState.EnableXtls { if w.trafficState.EnableXtls {
command = CommandPaddingDirect command = CommandPaddingDirect
@@ -387,53 +327,38 @@ func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, longPadding bool
} }
// XtlsUnpadding remove padding and parse command // XtlsUnpadding remove padding and parse command
func XtlsUnpadding(b *buf.Buffer, s *TrafficState, isUplink bool, ctx context.Context) *buf.Buffer { func XtlsUnpadding(b *buf.Buffer, s *TrafficState, ctx context.Context) *buf.Buffer {
var remainingCommand *int32 if s.RemainingCommand == -1 && s.RemainingContent == -1 && s.RemainingPadding == -1 { // initial state
var remainingContent *int32
var remainingPadding *int32
var currentCommand *int
if isUplink {
remainingCommand = &s.Inbound.RemainingCommand
remainingContent = &s.Inbound.RemainingContent
remainingPadding = &s.Inbound.RemainingPadding
currentCommand = &s.Inbound.CurrentCommand
} else {
remainingCommand = &s.Outbound.RemainingCommand
remainingContent = &s.Outbound.RemainingContent
remainingPadding = &s.Outbound.RemainingPadding
currentCommand = &s.Outbound.CurrentCommand
}
if *remainingCommand == -1 && *remainingContent == -1 && *remainingPadding == -1 { // initial state
if b.Len() >= 21 && bytes.Equal(s.UserUUID, b.BytesTo(16)) { if b.Len() >= 21 && bytes.Equal(s.UserUUID, b.BytesTo(16)) {
b.Advance(16) b.Advance(16)
*remainingCommand = 5 s.RemainingCommand = 5
} else { } else {
return b return b
} }
} }
newbuffer := buf.New() newbuffer := buf.New()
for b.Len() > 0 { for b.Len() > 0 {
if *remainingCommand > 0 { if s.RemainingCommand > 0 {
data, err := b.ReadByte() data, err := b.ReadByte()
if err != nil { if err != nil {
return newbuffer return newbuffer
} }
switch *remainingCommand { switch s.RemainingCommand {
case 5: case 5:
*currentCommand = int(data) s.CurrentCommand = int(data)
case 4: case 4:
*remainingContent = int32(data) << 8 s.RemainingContent = int32(data) << 8
case 3: case 3:
*remainingContent = *remainingContent | int32(data) s.RemainingContent = s.RemainingContent | int32(data)
case 2: case 2:
*remainingPadding = int32(data) << 8 s.RemainingPadding = int32(data) << 8
case 1: case 1:
*remainingPadding = *remainingPadding | int32(data) s.RemainingPadding = s.RemainingPadding | int32(data)
errors.LogInfo(ctx, "Xtls Unpadding new block, content ", *remainingContent, " padding ", *remainingPadding, " command ", *currentCommand) errors.LogInfo(ctx, "Xtls Unpadding new block, content ", s.RemainingContent, " padding ", s.RemainingPadding, " command ", s.CurrentCommand)
} }
*remainingCommand-- s.RemainingCommand--
} else if *remainingContent > 0 { } else if s.RemainingContent > 0 {
len := *remainingContent len := s.RemainingContent
if b.Len() < len { if b.Len() < len {
len = b.Len() len = b.Len()
} }
@@ -442,22 +367,22 @@ func XtlsUnpadding(b *buf.Buffer, s *TrafficState, isUplink bool, ctx context.Co
return newbuffer return newbuffer
} }
newbuffer.Write(data) newbuffer.Write(data)
*remainingContent -= len s.RemainingContent -= len
} else { // remainingPadding > 0 } else { // remainingPadding > 0
len := *remainingPadding len := s.RemainingPadding
if b.Len() < len { if b.Len() < len {
len = b.Len() len = b.Len()
} }
b.Advance(len) b.Advance(len)
*remainingPadding -= len s.RemainingPadding -= len
} }
if *remainingCommand <= 0 && *remainingContent <= 0 && *remainingPadding <= 0 { // this block done if s.RemainingCommand <= 0 && s.RemainingContent <= 0 && s.RemainingPadding <= 0 { // this block done
if *currentCommand == 0 { if s.CurrentCommand == 0 {
*remainingCommand = 5 s.RemainingCommand = 5
} else { } else {
*remainingCommand = -1 // set to initial state s.RemainingCommand = -1 // set to initial state
*remainingContent = -1 s.RemainingContent = -1
*remainingPadding = -1 s.RemainingPadding = -1
if b.Len() > 0 { // shouldn't happen if b.Len() > 0 { // shouldn't happen
newbuffer.Write(b.Bytes()) newbuffer.Write(b.Bytes())
} }
@@ -524,7 +449,7 @@ func XtlsFilterTls(buffer buf.MultiBuffer, trafficState *TrafficState, ctx conte
} }
} }
// UnwrapRawConn support unwrap stats, tls, utls, reality, proxyproto, uds-wrapper conn and get raw tcp/uds conn from it // UnwrapRawConn support unwrap stats, tls, utls, reality and proxyproto conn and get raw tcp conn from it
func UnwrapRawConn(conn net.Conn) (net.Conn, stats.Counter, stats.Counter) { func UnwrapRawConn(conn net.Conn) (net.Conn, stats.Counter, stats.Counter) {
var readCounter, writerCounter stats.Counter var readCounter, writerCounter stats.Counter
if conn != nil { if conn != nil {
@@ -547,9 +472,6 @@ func UnwrapRawConn(conn net.Conn) (net.Conn, stats.Counter, stats.Counter) {
conn = pc.Raw() conn = pc.Raw()
// 8192 > 4096, there is no need to process pc's bufReader // 8192 > 4096, there is no need to process pc's bufReader
} }
if uc, ok := conn.(*internet.UnixConnWrapper); ok {
conn = uc.UnixConn
}
} }
return conn, readCounter, writerCounter return conn, readCounter, writerCounter
} }

View File

@@ -146,7 +146,6 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
return buf.Copy(link.Reader, buf.NewWriter(conn), buf.UpdateActivity(timer)) return buf.Copy(link.Reader, buf.NewWriter(conn), buf.UpdateActivity(timer))
} }
responseFunc = func() error { responseFunc = func() error {
ob.CanSpliceCopy = 1
defer timer.SetTimeout(p.Timeouts.UplinkOnly) defer timer.SetTimeout(p.Timeouts.UplinkOnly)
return buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer)) return buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer))
} }
@@ -162,7 +161,6 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
return buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)) return buf.Copy(link.Reader, writer, buf.UpdateActivity(timer))
} }
responseFunc = func() error { responseFunc = func() error {
ob.CanSpliceCopy = 1
defer timer.SetTimeout(p.Timeouts.UplinkOnly) defer timer.SetTimeout(p.Timeouts.UplinkOnly)
reader := &UDPReader{Reader: udpConn} reader := &UDPReader{Reader: udpConn}
return buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)) return buf.Copy(reader, link.Writer, buf.UpdateActivity(timer))

View File

@@ -2,7 +2,6 @@ package socks
import ( import (
"context" "context"
goerrors "errors"
"io" "io"
"time" "time"
@@ -79,13 +78,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
switch network { switch network {
case net.Network_TCP: case net.Network_TCP:
firstbyte := make([]byte, 1) firstbyte := make([]byte, 1)
if n, err := conn.Read(firstbyte); n == 0 { conn.Read(firstbyte)
if goerrors.Is(err, io.EOF) {
errors.LogInfo(ctx, "Connection closed immediately, likely health check connection")
return nil
}
return errors.New("failed to read from connection").Base(err)
}
if firstbyte[0] != 5 && firstbyte[0] != 4 { // Check if it is Socks5/4/4a if firstbyte[0] != 5 && firstbyte[0] != 4 { // Check if it is Socks5/4/4a
errors.LogDebug(ctx, "Not Socks request, try to parse as HTTP request") errors.LogDebug(ctx, "Not Socks request, try to parse as HTTP request")
return s.httpServer.ProcessWithFirstbyte(ctx, network, conn, dispatcher, firstbyte...) return s.httpServer.ProcessWithFirstbyte(ctx, network, conn, dispatcher, firstbyte...)
@@ -199,7 +192,6 @@ func (s *Server) transport(ctx context.Context, reader io.Reader, writer io.Writ
} }
responseDone := func() error { responseDone := func() error {
inbound.CanSpliceCopy = 1
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly) defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
v2writer := buf.NewWriter(writer) v2writer := buf.NewWriter(writer)
@@ -257,7 +249,6 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dis
if inbound != nil && inbound.Source.IsValid() { if inbound != nil && inbound.Source.IsValid() {
errors.LogInfo(ctx, "client UDP connection from ", inbound.Source) errors.LogInfo(ctx, "client UDP connection from ", inbound.Source)
} }
inbound.CanSpliceCopy = 1
var dest *net.Destination var dest *net.Destination

View File

@@ -61,13 +61,13 @@ func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {
} }
// EncodeBodyAddons returns a Writer that auto-encrypt content written by caller. // EncodeBodyAddons returns a Writer that auto-encrypt content written by caller.
func EncodeBodyAddons(writer io.Writer, request *protocol.RequestHeader, requestAddons *Addons, state *proxy.TrafficState, isUplink bool, context context.Context) buf.Writer { func EncodeBodyAddons(writer io.Writer, request *protocol.RequestHeader, requestAddons *Addons, state *proxy.TrafficState, context context.Context) buf.Writer {
if request.Command == protocol.RequestCommandUDP { if request.Command == protocol.RequestCommandUDP {
return NewMultiLengthPacketWriter(writer.(buf.Writer)) return NewMultiLengthPacketWriter(writer.(buf.Writer))
} }
w := buf.NewWriter(writer) w := buf.NewWriter(writer)
if requestAddons.Flow == vless.XRV { if requestAddons.Flow == vless.XRV {
w = proxy.NewVisionWriter(w, state, isUplink, context) w = proxy.NewVisionWriter(w, state, context)
} }
return w return w
} }

View File

@@ -172,19 +172,19 @@ func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*A
} }
// XtlsRead filter and read xtls protocol // XtlsRead filter and read xtls protocol
func XtlsRead(reader buf.Reader, writer buf.Writer, timer *signal.ActivityTimer, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, trafficState *proxy.TrafficState, ob *session.Outbound, isUplink bool, ctx context.Context) error { func XtlsRead(reader buf.Reader, writer buf.Writer, timer *signal.ActivityTimer, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, trafficState *proxy.TrafficState, ob *session.Outbound, ctx context.Context) error {
err := func() error { err := func() error {
for { for {
if isUplink && trafficState.Inbound.UplinkReaderDirectCopy || !isUplink && trafficState.Outbound.DownlinkReaderDirectCopy { if trafficState.ReaderSwitchToDirectCopy {
var writerConn net.Conn var writerConn net.Conn
var inTimer *signal.ActivityTimer var inTimer *signal.ActivityTimer
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil { if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil {
writerConn = inbound.Conn writerConn = inbound.Conn
inTimer = inbound.Timer inTimer = inbound.Timer
if isUplink && inbound.CanSpliceCopy == 2 { if inbound.CanSpliceCopy == 2 {
inbound.CanSpliceCopy = 1 inbound.CanSpliceCopy = 1
} }
if !isUplink && ob != nil && ob.CanSpliceCopy == 2 { // ob need to be passed in due to context can change if ob != nil && ob.CanSpliceCopy == 2 { // ob need to be passed in due to context can change
ob.CanSpliceCopy = 1 ob.CanSpliceCopy = 1
} }
} }
@@ -193,7 +193,7 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer *signal.ActivityTimer,
buffer, err := reader.ReadMultiBuffer() buffer, err := reader.ReadMultiBuffer()
if !buffer.IsEmpty() { if !buffer.IsEmpty() {
timer.Update() timer.Update()
if isUplink && trafficState.Inbound.UplinkReaderDirectCopy || !isUplink && trafficState.Outbound.DownlinkReaderDirectCopy { if trafficState.ReaderSwitchToDirectCopy {
// XTLS Vision processes struct TLS Conn's input and rawInput // XTLS Vision processes struct TLS Conn's input and rawInput
if inputBuffer, err := buf.ReadFrom(input); err == nil { if inputBuffer, err := buf.ReadFrom(input); err == nil {
if !inputBuffer.IsEmpty() { if !inputBuffer.IsEmpty() {
@@ -222,28 +222,24 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer *signal.ActivityTimer,
} }
// XtlsWrite filter and write xtls protocol // XtlsWrite filter and write xtls protocol
func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, trafficState *proxy.TrafficState, ob *session.Outbound, isUplink bool, ctx context.Context) error { func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, trafficState *proxy.TrafficState, ob *session.Outbound, ctx context.Context) error {
err := func() error { err := func() error {
var ct stats.Counter var ct stats.Counter
for { for {
buffer, err := reader.ReadMultiBuffer() buffer, err := reader.ReadMultiBuffer()
if isUplink && trafficState.Outbound.UplinkWriterDirectCopy || !isUplink && trafficState.Inbound.DownlinkWriterDirectCopy { if trafficState.WriterSwitchToDirectCopy {
if inbound := session.InboundFromContext(ctx); inbound != nil { if inbound := session.InboundFromContext(ctx); inbound != nil {
if !isUplink && inbound.CanSpliceCopy == 2 { if inbound.CanSpliceCopy == 2 {
inbound.CanSpliceCopy = 1 inbound.CanSpliceCopy = 1
} }
if isUplink && ob != nil && ob.CanSpliceCopy == 2 { if ob != nil && ob.CanSpliceCopy == 2 {
ob.CanSpliceCopy = 1 ob.CanSpliceCopy = 1
} }
} }
rawConn, _, writerCounter := proxy.UnwrapRawConn(conn) rawConn, _, writerCounter := proxy.UnwrapRawConn(conn)
writer = buf.NewWriter(rawConn) writer = buf.NewWriter(rawConn)
ct = writerCounter ct = writerCounter
if isUplink { trafficState.WriterSwitchToDirectCopy = false
trafficState.Outbound.UplinkWriterDirectCopy = false
} else {
trafficState.Inbound.DownlinkWriterDirectCopy = false
}
} }
if !buffer.IsEmpty() { if !buffer.IsEmpty() {
if ct != nil { if ct != nil {

View File

@@ -538,8 +538,8 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
if requestAddons.Flow == vless.XRV { if requestAddons.Flow == vless.XRV {
ctx1 := session.ContextWithInbound(ctx, nil) // TODO enable splice ctx1 := session.ContextWithInbound(ctx, nil) // TODO enable splice
clientReader = proxy.NewVisionReader(clientReader, trafficState, true, ctx1) clientReader = proxy.NewVisionReader(clientReader, trafficState, ctx1)
err = encoding.XtlsRead(clientReader, serverWriter, timer, connection, input, rawInput, trafficState, nil, true, ctx1) err = encoding.XtlsRead(clientReader, serverWriter, timer, connection, input, rawInput, trafficState, nil, ctx1)
} else { } else {
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBuffer // from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBuffer
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer)) err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
@@ -561,7 +561,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
} }
// default: clientWriter := bufferWriter // default: clientWriter := bufferWriter
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, false, ctx) clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, ctx)
multiBuffer, err1 := serverReader.ReadMultiBuffer() multiBuffer, err1 := serverReader.ReadMultiBuffer()
if err1 != nil { if err1 != nil {
return err1 // ... return err1 // ...
@@ -576,7 +576,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
var err error var err error
if requestAddons.Flow == vless.XRV { if requestAddons.Flow == vless.XRV {
err = encoding.XtlsWrite(serverReader, clientWriter, timer, connection, trafficState, nil, false, ctx) err = encoding.XtlsWrite(serverReader, clientWriter, timer, connection, trafficState, nil, ctx)
} else { } else {
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBuffer // from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBuffer
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer)) err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))

View File

@@ -194,7 +194,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
} }
// default: serverWriter := bufferWriter // default: serverWriter := bufferWriter
serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, true, ctx) serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, ctx)
if request.Command == protocol.RequestCommandMux && request.Port == 666 { if request.Command == protocol.RequestCommandMux && request.Port == 666 {
serverWriter = xudp.NewPacketWriter(serverWriter, target, xudp.GetGlobalID(ctx)) serverWriter = xudp.NewPacketWriter(serverWriter, target, xudp.GetGlobalID(ctx))
} }
@@ -234,7 +234,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
} }
} }
ctx1 := session.ContextWithInbound(ctx, nil) // TODO enable splice ctx1 := session.ContextWithInbound(ctx, nil) // TODO enable splice
err = encoding.XtlsWrite(clientReader, serverWriter, timer, conn, trafficState, ob, true, ctx1) err = encoding.XtlsWrite(clientReader, serverWriter, timer, conn, trafficState, ob, ctx1)
} else { } else {
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBuffer // from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBuffer
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer)) err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
@@ -261,7 +261,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
// default: serverReader := buf.NewReader(conn) // default: serverReader := buf.NewReader(conn)
serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons) serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons)
if requestAddons.Flow == vless.XRV { if requestAddons.Flow == vless.XRV {
serverReader = proxy.NewVisionReader(serverReader, trafficState, false, ctx) serverReader = proxy.NewVisionReader(serverReader, trafficState, ctx)
} }
if request.Command == protocol.RequestCommandMux && request.Port == 666 { if request.Command == protocol.RequestCommandMux && request.Port == 666 {
if requestAddons.Flow == vless.XRV { if requestAddons.Flow == vless.XRV {
@@ -272,7 +272,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
} }
if requestAddons.Flow == vless.XRV { if requestAddons.Flow == vless.XRV {
err = encoding.XtlsRead(serverReader, clientWriter, timer, conn, input, rawInput, trafficState, ob, false, ctx) err = encoding.XtlsRead(serverReader, clientWriter, timer, conn, input, rawInput, trafficState, ob, ctx)
} else { } else {
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBuffer // from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBuffer
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer)) err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))

View File

@@ -157,7 +157,7 @@ func (tun *netTun) Write(buf [][]byte, offset int) (int, error) {
// WriteNotify implements channel.Notification // WriteNotify implements channel.Notification
func (tun *netTun) WriteNotify() { func (tun *netTun) WriteNotify() {
pkt := tun.ep.Read() pkt := tun.ep.Read()
if pkt == nil { if pkt.IsNil() {
return return
} }

View File

@@ -194,7 +194,7 @@ func createGVisorTun(localAddresses []netip.Addr, mtu int, handler promiscuousMo
Timeout: 15 * time.Second, Timeout: 15 * time.Second,
}) })
handler(xnet.UDPDestination(xnet.IPAddress(id.LocalAddress.AsSlice()), xnet.Port(id.LocalPort)), gonet.NewUDPConn(&wq, ep)) handler(xnet.UDPDestination(xnet.IPAddress(id.LocalAddress.AsSlice()), xnet.Port(id.LocalPort)), gonet.NewUDPConn(stack, &wq, ep))
}(r) }(r)
}) })
stack.SetTransportProtocolHandler(udp.ProtocolNumber, udpForwarder.HandlePacket) stack.SetTransportProtocolHandler(udp.ProtocolNumber, udpForwarder.HandlePacket)

View File

@@ -5,7 +5,6 @@ import (
"context" "context"
_ "embed" _ "embed"
"encoding/base64" "encoding/base64"
"encoding/json"
"net/http" "net/http"
"time" "time"
@@ -18,12 +17,6 @@ import (
//go:embed dialer.html //go:embed dialer.html
var webpage []byte var webpage []byte
type task struct {
Method string `json:"method"`
URL string `json:"url"`
Extra any `json:"extra,omitempty"`
}
var conns chan *websocket.Conn var conns chan *websocket.Conn
var upgrader = &websocket.Upgrader{ var upgrader = &websocket.Upgrader{
@@ -62,69 +55,23 @@ func HasBrowserDialer() bool {
return conns != nil return conns != nil
} }
type webSocketExtra struct {
Protocol string `json:"protocol,omitempty"`
}
func DialWS(uri string, ed []byte) (*websocket.Conn, error) { func DialWS(uri string, ed []byte) (*websocket.Conn, error) {
task := task{ data := []byte("WS " + uri)
Method: "WS",
URL: uri,
}
if ed != nil { if ed != nil {
task.Extra = webSocketExtra{ data = append(data, " "+base64.RawURLEncoding.EncodeToString(ed)...)
Protocol: base64.RawURLEncoding.EncodeToString(ed),
}
} }
return dialTask(task) return dialRaw(data)
} }
type httpExtra struct { func DialGet(uri string) (*websocket.Conn, error) {
Referrer string `json:"referrer,omitempty"` data := []byte("GET " + uri)
Headers map[string]string `json:"headers,omitempty"` return dialRaw(data)
} }
func httpExtraFromHeaders(headers http.Header) *httpExtra { func DialPost(uri string, payload []byte) error {
if len(headers) == 0 { data := []byte("POST " + uri)
return nil conn, err := dialRaw(data)
}
extra := httpExtra{}
if referrer := headers.Get("Referer"); referrer != "" {
extra.Referrer = referrer
headers.Del("Referer")
}
if len(headers) > 0 {
extra.Headers = make(map[string]string)
for header := range headers {
extra.Headers[header] = headers.Get(header)
}
}
return &extra
}
func DialGet(uri string, headers http.Header) (*websocket.Conn, error) {
task := task{
Method: "GET",
URL: uri,
Extra: httpExtraFromHeaders(headers),
}
return dialTask(task)
}
func DialPost(uri string, headers http.Header, payload []byte) error {
task := task{
Method: "POST",
URL: uri,
Extra: httpExtraFromHeaders(headers),
}
conn, err := dialTask(task)
if err != nil { if err != nil {
return err return err
} }
@@ -143,12 +90,7 @@ func DialPost(uri string, headers http.Header, payload []byte) error {
return nil return nil
} }
func dialTask(task task) (*websocket.Conn, error) { func dialRaw(data []byte) (*websocket.Conn, error) {
data, err := json.Marshal(task)
if err != nil {
return nil, err
}
var conn *websocket.Conn var conn *websocket.Conn
for { for {
conn = <-conns conn = <-conns
@@ -158,7 +100,7 @@ func dialTask(task task) (*websocket.Conn, error) {
break break
} }
} }
err = CheckOK(conn) err := CheckOK(conn)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -14,28 +14,10 @@
let upstreamGetCount = 0; let upstreamGetCount = 0;
let upstreamWsCount = 0; let upstreamWsCount = 0;
let upstreamPostCount = 0; let upstreamPostCount = 0;
function prepareRequestInit(extra) {
const requestInit = {};
if (extra.referrer) {
// note: we have to strip the protocol and host part.
// Browsers disallow that, and will reset the value to current page if attempted.
const referrer = URL.parse(extra.referrer);
requestInit.referrer = referrer.pathname + referrer.search + referrer.hash;
requestInit.referrerPolicy = "unsafe-url";
}
if (extra.headers) {
requestInit.headers = extra.headers;
}
return requestInit;
}
let check = function () { let check = function () {
if (clientIdleCount > 0) { if (clientIdleCount > 0) {
return; return;
} };
clientIdleCount += 1; clientIdleCount += 1;
console.log("Prepare", url); console.log("Prepare", url);
let ws = new WebSocket(url); let ws = new WebSocket(url);
@@ -47,12 +29,12 @@
// double-checking that this continues to work // double-checking that this continues to work
ws.onmessage = function (event) { ws.onmessage = function (event) {
clientIdleCount -= 1; clientIdleCount -= 1;
let task = JSON.parse(event.data); let [method, url, protocol] = event.data.split(" ");
switch (task.method) { switch (method) {
case "WS": { case "WS": {
upstreamWsCount += 1; upstreamWsCount += 1;
console.log("Dial WS", task.url, task.extra.protocol); console.log("Dial WS", url, protocol);
const wss = new WebSocket(task.url, task.extra.protocol); const wss = new WebSocket(url, protocol);
wss.binaryType = "arraybuffer"; wss.binaryType = "arraybuffer";
let opened = false; let opened = false;
ws.onmessage = function (event) { ws.onmessage = function (event) {
@@ -78,12 +60,10 @@
wss.close() wss.close()
}; };
break; break;
} };
case "GET": { case "GET": {
(async () => { (async () => {
const requestInit = prepareRequestInit(task.extra); console.log("Dial GET", url);
console.log("Dial GET", task.url);
ws.send("ok"); ws.send("ok");
const controller = new AbortController(); const controller = new AbortController();
@@ -103,62 +83,58 @@
ws.onclose = (event) => { ws.onclose = (event) => {
try { try {
reader && reader.cancel(); reader && reader.cancel();
} catch(e) {} } catch(e) {};
try { try {
controller.abort(); controller.abort();
} catch(e) {} } catch(e) {};
}; };
try { try {
upstreamGetCount += 1; upstreamGetCount += 1;
const response = await fetch(url, {signal: controller.signal});
requestInit.signal = controller.signal;
const response = await fetch(task.url, requestInit);
const body = await response.body; const body = await response.body;
reader = body.getReader(); reader = body.getReader();
while (true) { while (true) {
const { done, value } = await reader.read(); const { done, value } = await reader.read();
if (value) ws.send(value); // don't send back "undefined" string when received nothing ws.send(value);
if (done) break; if (done) break;
} };
} finally { } finally {
upstreamGetCount -= 1; upstreamGetCount -= 1;
console.log("Dial GET DONE, remaining: ", upstreamGetCount); console.log("Dial GET DONE, remaining: ", upstreamGetCount);
ws.close(); ws.close();
} };
})(); })();
break; break;
} };
case "POST": { case "POST": {
upstreamPostCount += 1; upstreamPostCount += 1;
console.log("Dial POST", url);
const requestInit = prepareRequestInit(task.extra);
requestInit.method = "POST";
console.log("Dial POST", task.url);
ws.send("ok"); ws.send("ok");
ws.onmessage = async (event) => { ws.onmessage = async (event) => {
try { try {
requestInit.body = event.data; const response = await fetch(
const response = await fetch(task.url, requestInit); url,
{method: "POST", body: event.data}
);
if (response.ok) { if (response.ok) {
ws.send("ok"); ws.send("ok");
} else { } else {
console.error("bad status code"); console.error("bad status code");
ws.send("fail"); ws.send("fail");
} };
} finally { } finally {
upstreamPostCount -= 1; upstreamPostCount -= 1;
console.log("Dial POST DONE, remaining: ", upstreamPostCount); console.log("Dial POST DONE, remaining: ", upstreamPostCount);
ws.close(); ws.close();
} };
}; };
break; break;
} };
} };
check(); check();
}; };

View File

@@ -95,67 +95,6 @@ func (DomainStrategy) EnumDescriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{0} return file_transport_internet_config_proto_rawDescGZIP(), []int{0}
} }
type AddressPortStrategy int32
const (
AddressPortStrategy_None AddressPortStrategy = 0
AddressPortStrategy_SrvPortOnly AddressPortStrategy = 1
AddressPortStrategy_SrvAddressOnly AddressPortStrategy = 2
AddressPortStrategy_SrvPortAndAddress AddressPortStrategy = 3
AddressPortStrategy_TxtPortOnly AddressPortStrategy = 4
AddressPortStrategy_TxtAddressOnly AddressPortStrategy = 5
AddressPortStrategy_TxtPortAndAddress AddressPortStrategy = 6
)
// Enum value maps for AddressPortStrategy.
var (
AddressPortStrategy_name = map[int32]string{
0: "None",
1: "SrvPortOnly",
2: "SrvAddressOnly",
3: "SrvPortAndAddress",
4: "TxtPortOnly",
5: "TxtAddressOnly",
6: "TxtPortAndAddress",
}
AddressPortStrategy_value = map[string]int32{
"None": 0,
"SrvPortOnly": 1,
"SrvAddressOnly": 2,
"SrvPortAndAddress": 3,
"TxtPortOnly": 4,
"TxtAddressOnly": 5,
"TxtPortAndAddress": 6,
}
)
func (x AddressPortStrategy) Enum() *AddressPortStrategy {
p := new(AddressPortStrategy)
*p = x
return p
}
func (x AddressPortStrategy) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (AddressPortStrategy) Descriptor() protoreflect.EnumDescriptor {
return file_transport_internet_config_proto_enumTypes[1].Descriptor()
}
func (AddressPortStrategy) Type() protoreflect.EnumType {
return &file_transport_internet_config_proto_enumTypes[1]
}
func (x AddressPortStrategy) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use AddressPortStrategy.Descriptor instead.
func (AddressPortStrategy) EnumDescriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{1}
}
type SocketConfig_TProxyMode int32 type SocketConfig_TProxyMode int32
const ( const (
@@ -192,11 +131,11 @@ func (x SocketConfig_TProxyMode) String() string {
} }
func (SocketConfig_TProxyMode) Descriptor() protoreflect.EnumDescriptor { func (SocketConfig_TProxyMode) Descriptor() protoreflect.EnumDescriptor {
return file_transport_internet_config_proto_enumTypes[2].Descriptor() return file_transport_internet_config_proto_enumTypes[1].Descriptor()
} }
func (SocketConfig_TProxyMode) Type() protoreflect.EnumType { func (SocketConfig_TProxyMode) Type() protoreflect.EnumType {
return &file_transport_internet_config_proto_enumTypes[2] return &file_transport_internet_config_proto_enumTypes[1]
} }
func (x SocketConfig_TProxyMode) Number() protoreflect.EnumNumber { func (x SocketConfig_TProxyMode) Number() protoreflect.EnumNumber {
@@ -495,24 +434,23 @@ type SocketConfig struct {
Tproxy SocketConfig_TProxyMode `protobuf:"varint,3,opt,name=tproxy,proto3,enum=xray.transport.internet.SocketConfig_TProxyMode" json:"tproxy,omitempty"` Tproxy SocketConfig_TProxyMode `protobuf:"varint,3,opt,name=tproxy,proto3,enum=xray.transport.internet.SocketConfig_TProxyMode" json:"tproxy,omitempty"`
// ReceiveOriginalDestAddress is for enabling IP_RECVORIGDSTADDR socket // ReceiveOriginalDestAddress is for enabling IP_RECVORIGDSTADDR socket
// option. This option is for UDP only. // option. This option is for UDP only.
ReceiveOriginalDestAddress bool `protobuf:"varint,4,opt,name=receive_original_dest_address,json=receiveOriginalDestAddress,proto3" json:"receive_original_dest_address,omitempty"` ReceiveOriginalDestAddress bool `protobuf:"varint,4,opt,name=receive_original_dest_address,json=receiveOriginalDestAddress,proto3" json:"receive_original_dest_address,omitempty"`
BindAddress []byte `protobuf:"bytes,5,opt,name=bind_address,json=bindAddress,proto3" json:"bind_address,omitempty"` BindAddress []byte `protobuf:"bytes,5,opt,name=bind_address,json=bindAddress,proto3" json:"bind_address,omitempty"`
BindPort uint32 `protobuf:"varint,6,opt,name=bind_port,json=bindPort,proto3" json:"bind_port,omitempty"` BindPort uint32 `protobuf:"varint,6,opt,name=bind_port,json=bindPort,proto3" json:"bind_port,omitempty"`
AcceptProxyProtocol bool `protobuf:"varint,7,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3" json:"accept_proxy_protocol,omitempty"` AcceptProxyProtocol bool `protobuf:"varint,7,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3" json:"accept_proxy_protocol,omitempty"`
DomainStrategy DomainStrategy `protobuf:"varint,8,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"` DomainStrategy DomainStrategy `protobuf:"varint,8,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"`
DialerProxy string `protobuf:"bytes,9,opt,name=dialer_proxy,json=dialerProxy,proto3" json:"dialer_proxy,omitempty"` DialerProxy string `protobuf:"bytes,9,opt,name=dialer_proxy,json=dialerProxy,proto3" json:"dialer_proxy,omitempty"`
TcpKeepAliveInterval int32 `protobuf:"varint,10,opt,name=tcp_keep_alive_interval,json=tcpKeepAliveInterval,proto3" json:"tcp_keep_alive_interval,omitempty"` TcpKeepAliveInterval int32 `protobuf:"varint,10,opt,name=tcp_keep_alive_interval,json=tcpKeepAliveInterval,proto3" json:"tcp_keep_alive_interval,omitempty"`
TcpKeepAliveIdle int32 `protobuf:"varint,11,opt,name=tcp_keep_alive_idle,json=tcpKeepAliveIdle,proto3" json:"tcp_keep_alive_idle,omitempty"` TcpKeepAliveIdle int32 `protobuf:"varint,11,opt,name=tcp_keep_alive_idle,json=tcpKeepAliveIdle,proto3" json:"tcp_keep_alive_idle,omitempty"`
TcpCongestion string `protobuf:"bytes,12,opt,name=tcp_congestion,json=tcpCongestion,proto3" json:"tcp_congestion,omitempty"` TcpCongestion string `protobuf:"bytes,12,opt,name=tcp_congestion,json=tcpCongestion,proto3" json:"tcp_congestion,omitempty"`
Interface string `protobuf:"bytes,13,opt,name=interface,proto3" json:"interface,omitempty"` Interface string `protobuf:"bytes,13,opt,name=interface,proto3" json:"interface,omitempty"`
V6Only bool `protobuf:"varint,14,opt,name=v6only,proto3" json:"v6only,omitempty"` V6Only bool `protobuf:"varint,14,opt,name=v6only,proto3" json:"v6only,omitempty"`
TcpWindowClamp int32 `protobuf:"varint,15,opt,name=tcp_window_clamp,json=tcpWindowClamp,proto3" json:"tcp_window_clamp,omitempty"` TcpWindowClamp int32 `protobuf:"varint,15,opt,name=tcp_window_clamp,json=tcpWindowClamp,proto3" json:"tcp_window_clamp,omitempty"`
TcpUserTimeout int32 `protobuf:"varint,16,opt,name=tcp_user_timeout,json=tcpUserTimeout,proto3" json:"tcp_user_timeout,omitempty"` TcpUserTimeout int32 `protobuf:"varint,16,opt,name=tcp_user_timeout,json=tcpUserTimeout,proto3" json:"tcp_user_timeout,omitempty"`
TcpMaxSeg int32 `protobuf:"varint,17,opt,name=tcp_max_seg,json=tcpMaxSeg,proto3" json:"tcp_max_seg,omitempty"` TcpMaxSeg int32 `protobuf:"varint,17,opt,name=tcp_max_seg,json=tcpMaxSeg,proto3" json:"tcp_max_seg,omitempty"`
Penetrate bool `protobuf:"varint,18,opt,name=penetrate,proto3" json:"penetrate,omitempty"` Penetrate bool `protobuf:"varint,18,opt,name=penetrate,proto3" json:"penetrate,omitempty"`
TcpMptcp bool `protobuf:"varint,19,opt,name=tcp_mptcp,json=tcpMptcp,proto3" json:"tcp_mptcp,omitempty"` TcpMptcp bool `protobuf:"varint,19,opt,name=tcp_mptcp,json=tcpMptcp,proto3" json:"tcp_mptcp,omitempty"`
CustomSockopt []*CustomSockopt `protobuf:"bytes,20,rep,name=customSockopt,proto3" json:"customSockopt,omitempty"` CustomSockopt []*CustomSockopt `protobuf:"bytes,20,rep,name=customSockopt,proto3" json:"customSockopt,omitempty"`
AddressPortStrategy AddressPortStrategy `protobuf:"varint,21,opt,name=address_port_strategy,json=addressPortStrategy,proto3,enum=xray.transport.internet.AddressPortStrategy" json:"address_port_strategy,omitempty"`
} }
func (x *SocketConfig) Reset() { func (x *SocketConfig) Reset() {
@@ -685,13 +623,6 @@ func (x *SocketConfig) GetCustomSockopt() []*CustomSockopt {
return nil return nil
} }
func (x *SocketConfig) GetAddressPortStrategy() AddressPortStrategy {
if x != nil {
return x.AddressPortStrategy
}
return AddressPortStrategy_None
}
var File_transport_internet_config_proto protoreflect.FileDescriptor var File_transport_internet_config_proto protoreflect.FileDescriptor
var file_transport_internet_config_proto_rawDesc = []byte{ var file_transport_internet_config_proto_rawDesc = []byte{
@@ -747,7 +678,7 @@ var file_transport_internet_config_proto_rawDesc = []byte{
0x28, 0x09, 0x52, 0x03, 0x6f, 0x70, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x09, 0x52, 0x03, 0x6f, 0x70, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a,
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70,
0x65, 0x22, 0xfd, 0x07, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x65, 0x22, 0x9b, 0x07, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
0x52, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x52, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x66, 0x6f, 0x18, 0x02, 0x20,
0x01, 0x28, 0x05, 0x52, 0x03, 0x74, 0x66, 0x6f, 0x12, 0x48, 0x0a, 0x06, 0x74, 0x70, 0x72, 0x6f, 0x01, 0x28, 0x05, 0x52, 0x03, 0x74, 0x66, 0x6f, 0x12, 0x48, 0x0a, 0x06, 0x74, 0x70, 0x72, 0x6f,
@@ -801,44 +732,28 @@ var file_transport_internet_config_proto_rawDesc = []byte{
0x74, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x74, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74,
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
0x74, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x6f, 0x63, 0x6b, 0x6f, 0x70, 0x74, 0x52, 0x74, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x6f, 0x63, 0x6b, 0x6f, 0x70, 0x74, 0x52,
0x0d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x6f, 0x63, 0x6b, 0x6f, 0x70, 0x74, 0x12, 0x60, 0x0d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x6f, 0x63, 0x6b, 0x6f, 0x70, 0x74, 0x22, 0x2f,
0x0a, 0x15, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x0a, 0x0a, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x07, 0x0a, 0x03,
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x4f, 0x66, 0x66, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x10,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10, 0x02, 0x2a,
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0xa9, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
0x6f, 0x72, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x13, 0x61, 0x64, 0x64, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a,
0x72, 0x65, 0x73, 0x73, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45,
0x22, 0x2f, 0x0a, 0x0a, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x07, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50,
0x0a, 0x03, 0x4f, 0x66, 0x66, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x36, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10,
0x79, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, 0x10, 0x05, 0x12,
0x02, 0x2a, 0xa9, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x0c, 0x0a, 0x08, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x06, 0x12, 0x0d, 0x0a,
0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x49, 0x53, 0x10, 0x00, 0x12, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x09,
0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x08, 0x12, 0x0e, 0x0a, 0x0a, 0x46,
0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10, 0x09, 0x12, 0x0e, 0x0a, 0x0a, 0x46,
0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, 0x10, 0x0a, 0x42, 0x67, 0x0a, 0x1b, 0x63,
0x36, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, 0x10, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
0x05, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x06, 0x12, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69,
0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x07, 0x12, 0x0d, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72,
0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x08, 0x12, 0x0e, 0x0a, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10, 0x09, 0x12, 0x0e, 0x0a, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61,
0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, 0x10, 0x0a, 0x2a, 0x97, 0x01, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65,
0x0a, 0x13, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x72, 0x72, 0x6e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00, 0x12,
0x0f, 0x0a, 0x0b, 0x53, 0x72, 0x76, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x01,
0x12, 0x12, 0x0a, 0x0e, 0x53, 0x72, 0x76, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4f, 0x6e,
0x6c, 0x79, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x72, 0x76, 0x50, 0x6f, 0x72, 0x74, 0x41,
0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x54,
0x78, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e,
0x54, 0x78, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x05,
0x12, 0x15, 0x0a, 0x11, 0x54, 0x78, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x41, 0x6e, 0x64, 0x41, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x06, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63,
0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@@ -853,35 +768,33 @@ func file_transport_internet_config_proto_rawDescGZIP() []byte {
return file_transport_internet_config_proto_rawDescData return file_transport_internet_config_proto_rawDescData
} }
var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_transport_internet_config_proto_goTypes = []any{ var file_transport_internet_config_proto_goTypes = []any{
(DomainStrategy)(0), // 0: xray.transport.internet.DomainStrategy (DomainStrategy)(0), // 0: xray.transport.internet.DomainStrategy
(AddressPortStrategy)(0), // 1: xray.transport.internet.AddressPortStrategy (SocketConfig_TProxyMode)(0), // 1: xray.transport.internet.SocketConfig.TProxyMode
(SocketConfig_TProxyMode)(0), // 2: xray.transport.internet.SocketConfig.TProxyMode (*TransportConfig)(nil), // 2: xray.transport.internet.TransportConfig
(*TransportConfig)(nil), // 3: xray.transport.internet.TransportConfig (*StreamConfig)(nil), // 3: xray.transport.internet.StreamConfig
(*StreamConfig)(nil), // 4: xray.transport.internet.StreamConfig (*ProxyConfig)(nil), // 4: xray.transport.internet.ProxyConfig
(*ProxyConfig)(nil), // 5: xray.transport.internet.ProxyConfig (*CustomSockopt)(nil), // 5: xray.transport.internet.CustomSockopt
(*CustomSockopt)(nil), // 6: xray.transport.internet.CustomSockopt (*SocketConfig)(nil), // 6: xray.transport.internet.SocketConfig
(*SocketConfig)(nil), // 7: xray.transport.internet.SocketConfig (*serial.TypedMessage)(nil), // 7: xray.common.serial.TypedMessage
(*serial.TypedMessage)(nil), // 8: xray.common.serial.TypedMessage (*net.IPOrDomain)(nil), // 8: xray.common.net.IPOrDomain
(*net.IPOrDomain)(nil), // 9: xray.common.net.IPOrDomain
} }
var file_transport_internet_config_proto_depIdxs = []int32{ var file_transport_internet_config_proto_depIdxs = []int32{
8, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage 7, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage
9, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain 8, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain
3, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig 2, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig
8, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage 7, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage
7, // 4: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig 6, // 4: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig
2, // 5: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode 1, // 5: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode
0, // 6: xray.transport.internet.SocketConfig.domain_strategy:type_name -> xray.transport.internet.DomainStrategy 0, // 6: xray.transport.internet.SocketConfig.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
6, // 7: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt 5, // 7: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt
1, // 8: xray.transport.internet.SocketConfig.address_port_strategy:type_name -> xray.transport.internet.AddressPortStrategy 8, // [8:8] is the sub-list for method output_type
9, // [9:9] is the sub-list for method output_type 8, // [8:8] is the sub-list for method input_type
9, // [9:9] is the sub-list for method input_type 8, // [8:8] is the sub-list for extension type_name
9, // [9:9] is the sub-list for extension type_name 8, // [8:8] is the sub-list for extension extendee
9, // [9:9] is the sub-list for extension extendee 0, // [0:8] is the sub-list for field type_name
0, // [0:9] is the sub-list for field type_name
} }
func init() { file_transport_internet_config_proto_init() } func init() { file_transport_internet_config_proto_init() }
@@ -894,7 +807,7 @@ func file_transport_internet_config_proto_init() {
File: protoimpl.DescBuilder{ File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_transport_internet_config_proto_rawDesc, RawDescriptor: file_transport_internet_config_proto_rawDesc,
NumEnums: 3, NumEnums: 2,
NumMessages: 5, NumMessages: 5,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,

View File

@@ -23,16 +23,6 @@ enum DomainStrategy {
FORCE_IP64 = 10; FORCE_IP64 = 10;
} }
enum AddressPortStrategy {
None = 0;
SrvPortOnly = 1;
SrvAddressOnly = 2;
SrvPortAndAddress = 3;
TxtPortOnly = 4;
TxtAddressOnly = 5;
TxtPortAndAddress = 6;
}
message TransportConfig { message TransportConfig {
// Transport protocol name. // Transport protocol name.
string protocol_name = 3; string protocol_name = 3;
@@ -126,6 +116,4 @@ message SocketConfig {
bool tcp_mptcp = 19; bool tcp_mptcp = 19;
repeated CustomSockopt customSockopt = 20; repeated CustomSockopt customSockopt = 20;
AddressPortStrategy address_port_strategy = 21;
} }

View File

@@ -2,9 +2,6 @@ package internet
import ( import (
"context" "context"
"fmt"
gonet "net"
"strings"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/dice"
@@ -143,93 +140,6 @@ func redirect(ctx context.Context, dst net.Destination, obt string) net.Conn {
return nil return nil
} }
func checkAddressPortStrategy(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (*net.Destination, error) {
if sockopt.AddressPortStrategy == AddressPortStrategy_None {
return nil, nil
}
newDest := dest
var OverridePort, OverrideAddress bool
var OverrideBy string
switch sockopt.AddressPortStrategy {
case AddressPortStrategy_SrvPortOnly:
OverridePort = true
OverrideAddress = false
OverrideBy = "srv"
case AddressPortStrategy_SrvAddressOnly:
OverridePort = false
OverrideAddress = true
OverrideBy = "srv"
case AddressPortStrategy_SrvPortAndAddress:
OverridePort = true
OverrideAddress = true
OverrideBy = "srv"
case AddressPortStrategy_TxtPortOnly:
OverridePort = true
OverrideAddress = false
OverrideBy = "txt"
case AddressPortStrategy_TxtAddressOnly:
OverridePort = false
OverrideAddress = true
OverrideBy = "txt"
case AddressPortStrategy_TxtPortAndAddress:
OverridePort = true
OverrideAddress = true
OverrideBy = "txt"
default:
return nil, errors.New("unknown AddressPortStrategy")
}
if !dest.Address.Family().IsDomain() {
return nil, nil
}
if OverrideBy == "srv" {
errors.LogDebug(ctx, "query SRV record for "+dest.Address.String())
parts := strings.SplitN(dest.Address.String(), ".", 3)
if len(parts) != 3 {
return nil, errors.New("invalid address format", dest.Address.String())
}
_, srvRecords, err := gonet.DefaultResolver.LookupSRV(context.Background(), parts[0][1:], parts[1][1:], parts[2])
if err != nil {
return nil, errors.New("failed to lookup SRV record").Base(err)
}
errors.LogDebug(ctx, "SRV record: "+fmt.Sprintf("addr=%s, port=%d, priority=%d, weight=%d", srvRecords[0].Target, srvRecords[0].Port, srvRecords[0].Priority, srvRecords[0].Weight))
if OverridePort {
newDest.Port = net.Port(srvRecords[0].Port)
}
if OverrideAddress {
newDest.Address = net.ParseAddress(srvRecords[0].Target)
}
return &newDest, nil
}
if OverrideBy == "txt" {
errors.LogDebug(ctx, "query TXT record for "+dest.Address.String())
txtRecords, err := gonet.DefaultResolver.LookupTXT(ctx, dest.Address.String())
if err != nil {
errors.LogError(ctx, "failed to lookup SRV record: "+err.Error())
return nil, errors.New("failed to lookup SRV record").Base(err)
}
for _, txtRecord := range txtRecords {
errors.LogDebug(ctx, "TXT record: "+txtRecord)
addr_s, port_s, _ := net.SplitHostPort(string(txtRecord))
addr := net.ParseAddress(addr_s)
port, err := net.PortFromString(port_s)
if err != nil {
continue
}
if OverridePort {
newDest.Port = port
}
if OverrideAddress {
newDest.Address = addr
}
return &newDest, nil
}
}
return nil, nil
}
// DialSystem calls system dialer to create a network connection. // DialSystem calls system dialer to create a network connection.
func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) { func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) {
var src net.Address var src net.Address
@@ -242,11 +152,6 @@ func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig
return effectiveSystemDialer.Dial(ctx, src, dest, sockopt) return effectiveSystemDialer.Dial(ctx, src, dest, sockopt)
} }
if newDest, err := checkAddressPortStrategy(ctx, dest, sockopt); err == nil && newDest != nil {
errors.LogInfo(ctx, "replace destination with "+newDest.String())
dest = *newDest
}
if canLookupIP(ctx, dest, sockopt) { if canLookupIP(ctx, dest, sockopt) {
ips, err := lookupIP(dest.Address.String(), sockopt.DomainStrategy, src) ips, err := lookupIP(dest.Address.String(), sockopt.DomainStrategy, src)
if err == nil && len(ips) > 0 { if err == nil && len(ips) > 0 {

View File

@@ -8,6 +8,7 @@ import (
"crypto/ecdh" "crypto/ecdh"
"crypto/ed25519" "crypto/ed25519"
"crypto/hmac" "crypto/hmac"
"crypto/rand"
"crypto/sha256" "crypto/sha256"
"crypto/sha512" "crypto/sha512"
gotls "crypto/tls" gotls "crypto/tls"
@@ -15,6 +16,7 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"io" "io"
"math/big"
"net/http" "net/http"
"reflect" "reflect"
"regexp" "regexp"
@@ -25,7 +27,6 @@ import (
utls "github.com/refraction-networking/utls" utls "github.com/refraction-networking/utls"
"github.com/xtls/reality" "github.com/xtls/reality"
"github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
@@ -179,12 +180,12 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
prefix := []byte("https://" + uConn.ServerName) prefix := []byte("https://" + uConn.ServerName)
maps.Lock() maps.Lock()
if maps.maps == nil { if maps.maps == nil {
maps.maps = make(map[string]map[string]struct{}) maps.maps = make(map[string]map[string]bool)
} }
paths := maps.maps[uConn.ServerName] paths := maps.maps[uConn.ServerName]
if paths == nil { if paths == nil {
paths = make(map[string]struct{}) paths = make(map[string]bool)
paths[config.SpiderX] = struct{}{} paths[config.SpiderX] = true
maps.maps[uConn.ServerName] = paths maps.maps[uConn.ServerName] = paths
} }
firstURL := string(prefix) + getPathLocked(paths) firstURL := string(prefix) + getPathLocked(paths)
@@ -212,13 +213,13 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
} }
times := 1 times := 1
if !first { if !first {
times = int(crypto.RandBetween(config.SpiderY[4], config.SpiderY[5])) times = int(randBetween(config.SpiderY[4], config.SpiderY[5]))
} }
for j := 0; j < times; j++ { for j := 0; j < times; j++ {
if !first && j == 0 { if !first && j == 0 {
req.Header.Set("Referer", firstURL) req.Header.Set("Referer", firstURL)
} }
req.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", int(crypto.RandBetween(config.SpiderY[0], config.SpiderY[1])))}) req.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", int(randBetween(config.SpiderY[0], config.SpiderY[1])))})
if resp, err = client.Do(req); err != nil { if resp, err = client.Do(req); err != nil {
break break
} }
@@ -231,7 +232,7 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
for _, m := range href.FindAllSubmatch(body, -1) { for _, m := range href.FindAllSubmatch(body, -1) {
m[1] = bytes.TrimPrefix(m[1], prefix) m[1] = bytes.TrimPrefix(m[1], prefix)
if !bytes.Contains(m[1], dot) { if !bytes.Contains(m[1], dot) {
paths[string(m[1])] = struct{}{} paths[string(m[1])] = true
} }
} }
req.URL.Path = getPathLocked(paths) req.URL.Path = getPathLocked(paths)
@@ -242,18 +243,18 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
} }
maps.Unlock() maps.Unlock()
if !first { if !first {
time.Sleep(time.Duration(crypto.RandBetween(config.SpiderY[6], config.SpiderY[7])) * time.Millisecond) // interval time.Sleep(time.Duration(randBetween(config.SpiderY[6], config.SpiderY[7])) * time.Millisecond) // interval
} }
} }
} }
get(true) get(true)
concurrency := int(crypto.RandBetween(config.SpiderY[2], config.SpiderY[3])) concurrency := int(randBetween(config.SpiderY[2], config.SpiderY[3]))
for i := 0; i < concurrency; i++ { for i := 0; i < concurrency; i++ {
go get(false) go get(false)
} }
// Do not close the connection // Do not close the connection
}() }()
time.Sleep(time.Duration(crypto.RandBetween(config.SpiderY[8], config.SpiderY[9])) * time.Millisecond) // return time.Sleep(time.Duration(randBetween(config.SpiderY[8], config.SpiderY[9])) * time.Millisecond) // return
return nil, errors.New("REALITY: processed invalid connection").AtWarning() return nil, errors.New("REALITY: processed invalid connection").AtWarning()
} }
return uConn, nil return uConn, nil
@@ -266,11 +267,11 @@ var (
var maps struct { var maps struct {
sync.Mutex sync.Mutex
maps map[string]map[string]struct{} maps map[string]map[string]bool
} }
func getPathLocked(paths map[string]struct{}) string { func getPathLocked(paths map[string]bool) string {
stopAt := int(crypto.RandBetween(0, int64(len(paths)-1))) stopAt := int(randBetween(0, int64(len(paths)-1)))
i := 0 i := 0
for s := range paths { for s := range paths {
if i == stopAt { if i == stopAt {
@@ -280,3 +281,11 @@ func getPathLocked(paths map[string]struct{}) string {
} }
return "/" return "/"
} }
func randBetween(left int64, right int64) int64 {
if left == right {
return left
}
bigInt, _ := rand.Int(rand.Reader, big.NewInt(right-left))
return left + bigInt.Int64()
}

View File

@@ -5,15 +5,13 @@ import (
"io" "io"
gonet "net" gonet "net"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/transport/internet/browser_dialer" "github.com/xtls/xray-core/transport/internet/browser_dialer"
"github.com/xtls/xray-core/transport/internet/websocket" "github.com/xtls/xray-core/transport/internet/websocket"
) )
// BrowserDialerClient implements splithttp.DialerClient in terms of browser dialer // implements splithttp.DialerClient in terms of browser dialer
type BrowserDialerClient struct { // has no fields because everything is global state :O)
transportConfig *Config type BrowserDialerClient struct{}
}
func (c *BrowserDialerClient) IsClosed() bool { func (c *BrowserDialerClient) IsClosed() bool {
panic("not implemented yet") panic("not implemented yet")
@@ -21,10 +19,10 @@ func (c *BrowserDialerClient) IsClosed() bool {
func (c *BrowserDialerClient) OpenStream(ctx context.Context, url string, body io.Reader, uploadOnly bool) (io.ReadCloser, gonet.Addr, gonet.Addr, error) { func (c *BrowserDialerClient) OpenStream(ctx context.Context, url string, body io.Reader, uploadOnly bool) (io.ReadCloser, gonet.Addr, gonet.Addr, error) {
if body != nil { if body != nil {
return nil, nil, nil, errors.New("bidirectional streaming for browser dialer not implemented yet") panic("not implemented yet")
} }
conn, err := browser_dialer.DialGet(url, c.transportConfig.GetRequestHeader(url)) conn, err := browser_dialer.DialGet(url)
dummyAddr := &gonet.IPAddr{} dummyAddr := &gonet.IPAddr{}
if err != nil { if err != nil {
return nil, dummyAddr, dummyAddr, err return nil, dummyAddr, dummyAddr, err
@@ -39,7 +37,7 @@ func (c *BrowserDialerClient) PostPacket(ctx context.Context, url string, body i
return err return err
} }
err = browser_dialer.DialPost(url, c.transportConfig.GetRequestHeader(url), bytes) err = browser_dialer.DialPost(url, bytes)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -55,12 +55,12 @@ func (c *DefaultDialerClient) OpenStream(ctx context.Context, url string, body i
}, },
}) })
method := "GET" // stream-down method := "GET"
if body != nil { if body != nil {
method = "POST" // stream-up/one method = "POST"
} }
req, _ := http.NewRequestWithContext(context.WithoutCancel(ctx), method, url, body) req, _ := http.NewRequestWithContext(ctx, method, url, body)
req.Header = c.transportConfig.GetRequestHeader(url) req.Header = c.transportConfig.GetRequestHeader()
if method == "POST" && !c.transportConfig.NoGRPCHeader { if method == "POST" && !c.transportConfig.NoGRPCHeader {
req.Header.Set("Content-Type", "application/grpc") req.Header.Set("Content-Type", "application/grpc")
} }
@@ -69,20 +69,17 @@ func (c *DefaultDialerClient) OpenStream(ctx context.Context, url string, body i
go func() { go func() {
resp, err := c.client.Do(req) resp, err := c.client.Do(req)
if err != nil { if err != nil {
if !uploadOnly { // stream-down is enough errors.LogInfoInner(ctx, err, "failed to "+method+" "+url)
c.closed = true
errors.LogInfoInner(ctx, err, "failed to "+method+" "+url)
}
gotConn.Close() gotConn.Close()
wrc.Close() wrc.Close()
return return
} }
if resp.StatusCode != 200 && !uploadOnly { if resp.StatusCode != 200 && !uploadOnly {
// c.closed = true
errors.LogInfo(ctx, "unexpected status ", resp.StatusCode) errors.LogInfo(ctx, "unexpected status ", resp.StatusCode)
} }
if resp.StatusCode != 200 || uploadOnly { // stream-up if resp.StatusCode != 200 || uploadOnly {
io.Copy(io.Discard, resp.Body) resp.Body.Close()
resp.Body.Close() // if it is called immediately, the upload will be interrupted also
wrc.Close() wrc.Close()
return return
} }
@@ -94,24 +91,23 @@ func (c *DefaultDialerClient) OpenStream(ctx context.Context, url string, body i
} }
func (c *DefaultDialerClient) PostPacket(ctx context.Context, url string, body io.Reader, contentLength int64) error { func (c *DefaultDialerClient) PostPacket(ctx context.Context, url string, body io.Reader, contentLength int64) error {
req, err := http.NewRequestWithContext(context.WithoutCancel(ctx), "POST", url, body) req, err := http.NewRequestWithContext(ctx, "POST", url, body)
if err != nil { if err != nil {
return err return err
} }
req.ContentLength = contentLength req.ContentLength = contentLength
req.Header = c.transportConfig.GetRequestHeader(url) req.Header = c.transportConfig.GetRequestHeader()
if c.httpVersion != "1.1" { if c.httpVersion != "1.1" {
resp, err := c.client.Do(req) resp, err := c.client.Do(req)
if err != nil { if err != nil {
c.closed = true
return err return err
} }
io.Copy(io.Discard, resp.Body)
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
// c.closed = true
return errors.New("bad status code:", resp.Status) return errors.New("bad status code:", resp.Status)
} }
} else { } else {
@@ -143,12 +139,11 @@ func (c *DefaultDialerClient) PostPacket(ctx context.Context, url string, body i
if h1UploadConn.UnreadedResponsesCount > 0 { if h1UploadConn.UnreadedResponsesCount > 0 {
resp, err := http.ReadResponse(h1UploadConn.RespBufReader, req) resp, err := http.ReadResponse(h1UploadConn.RespBufReader, req)
if err != nil { if err != nil {
c.closed = true
return fmt.Errorf("error while reading response: %s", err.Error()) return fmt.Errorf("error while reading response: %s", err.Error())
} }
io.Copy(io.Discard, resp.Body)
defer resp.Body.Close()
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
// c.closed = true
// resp.Body.Close() // I'm not sure
return fmt.Errorf("got non-200 error response code: %d", resp.StatusCode) return fmt.Errorf("got non-200 error response code: %d", resp.StatusCode)
} }
} }

View File

@@ -1,12 +1,12 @@
package splithttp package splithttp
import ( import (
"crypto/rand"
"math/big"
"net/http" "net/http"
"net/url"
"strings" "strings"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
) )
@@ -33,31 +33,24 @@ func (c *Config) GetNormalizedQuery() string {
query = pathAndQuery[1] query = pathAndQuery[1]
} }
/* if query != "" {
if query != "" { query += "&"
query += "&" }
}
query += "x_version=" + core.Version() paddingLen := c.GetNormalizedXPaddingBytes().rand()
*/ if paddingLen > 0 {
query += "x_padding=" + strings.Repeat("0", int(paddingLen))
}
return query return query
} }
func (c *Config) GetRequestHeader(rawURL string) http.Header { func (c *Config) GetRequestHeader() http.Header {
header := http.Header{} header := http.Header{}
for k, v := range c.Headers { for k, v := range c.Headers {
header.Add(k, v) header.Add(k, v)
} }
u, _ := url.Parse(rawURL)
// https://www.rfc-editor.org/rfc/rfc7541.html#appendix-B
// h2's HPACK Header Compression feature employs a huffman encoding using a static table.
// 'X' is assigned an 8 bit code, so HPACK compression won't change actual padding length on the wire.
// https://www.rfc-editor.org/rfc/rfc9204.html#section-4.1.2-2
// h3's similar QPACK feature uses the same huffman table.
u.RawQuery = "x_padding=" + strings.Repeat("X", int(c.GetNormalizedXPaddingBytes().rand()))
header.Set("Referer", u.String())
return header return header
} }
@@ -65,8 +58,10 @@ func (c *Config) WriteResponseHeader(writer http.ResponseWriter) {
// CORS headers for the browser dialer // CORS headers for the browser dialer
writer.Header().Set("Access-Control-Allow-Origin", "*") writer.Header().Set("Access-Control-Allow-Origin", "*")
writer.Header().Set("Access-Control-Allow-Methods", "GET, POST") writer.Header().Set("Access-Control-Allow-Methods", "GET, POST")
// writer.Header().Set("X-Version", core.Version()) paddingLen := c.GetNormalizedXPaddingBytes().rand()
writer.Header().Set("X-Padding", strings.Repeat("X", int(c.GetNormalizedXPaddingBytes().rand()))) if paddingLen > 0 {
writer.Header().Set("X-Padding", strings.Repeat("0", int(paddingLen)))
}
} }
func (c *Config) GetNormalizedXPaddingBytes() RangeConfig { func (c *Config) GetNormalizedXPaddingBytes() RangeConfig {
@@ -110,17 +105,6 @@ func (c *Config) GetNormalizedScMaxBufferedPosts() int {
return int(c.ScMaxBufferedPosts) return int(c.ScMaxBufferedPosts)
} }
func (c *Config) GetNormalizedScStreamUpServerSecs() RangeConfig {
if c.ScStreamUpServerSecs == nil || c.ScStreamUpServerSecs.To == 0 {
return RangeConfig{
From: 20,
To: 80,
}
}
return *c.ScMinPostsIntervalMs
}
func (m *XmuxConfig) GetNormalizedMaxConcurrency() RangeConfig { func (m *XmuxConfig) GetNormalizedMaxConcurrency() RangeConfig {
if m.MaxConcurrency == nil { if m.MaxConcurrency == nil {
return RangeConfig{ return RangeConfig{
@@ -183,5 +167,9 @@ func init() {
} }
func (c RangeConfig) rand() int32 { func (c RangeConfig) rand() int32 {
return int32(crypto.RandBetween(int64(c.From), int64(c.To))) if c.From == c.To {
return c.From
}
bigInt, _ := rand.Int(rand.Reader, big.NewInt(int64(c.To-c.From)))
return c.From + int32(bigInt.Int64())
} }

View File

@@ -174,9 +174,8 @@ type Config struct {
ScMaxEachPostBytes *RangeConfig `protobuf:"bytes,8,opt,name=scMaxEachPostBytes,proto3" json:"scMaxEachPostBytes,omitempty"` ScMaxEachPostBytes *RangeConfig `protobuf:"bytes,8,opt,name=scMaxEachPostBytes,proto3" json:"scMaxEachPostBytes,omitempty"`
ScMinPostsIntervalMs *RangeConfig `protobuf:"bytes,9,opt,name=scMinPostsIntervalMs,proto3" json:"scMinPostsIntervalMs,omitempty"` ScMinPostsIntervalMs *RangeConfig `protobuf:"bytes,9,opt,name=scMinPostsIntervalMs,proto3" json:"scMinPostsIntervalMs,omitempty"`
ScMaxBufferedPosts int64 `protobuf:"varint,10,opt,name=scMaxBufferedPosts,proto3" json:"scMaxBufferedPosts,omitempty"` ScMaxBufferedPosts int64 `protobuf:"varint,10,opt,name=scMaxBufferedPosts,proto3" json:"scMaxBufferedPosts,omitempty"`
ScStreamUpServerSecs *RangeConfig `protobuf:"bytes,11,opt,name=scStreamUpServerSecs,proto3" json:"scStreamUpServerSecs,omitempty"` Xmux *XmuxConfig `protobuf:"bytes,11,opt,name=xmux,proto3" json:"xmux,omitempty"`
Xmux *XmuxConfig `protobuf:"bytes,12,opt,name=xmux,proto3" json:"xmux,omitempty"` DownloadSettings *internet.StreamConfig `protobuf:"bytes,12,opt,name=downloadSettings,proto3" json:"downloadSettings,omitempty"`
DownloadSettings *internet.StreamConfig `protobuf:"bytes,13,opt,name=downloadSettings,proto3" json:"downloadSettings,omitempty"`
} }
func (x *Config) Reset() { func (x *Config) Reset() {
@@ -279,13 +278,6 @@ func (x *Config) GetScMaxBufferedPosts() int64 {
return 0 return 0
} }
func (x *Config) GetScStreamUpServerSecs() *RangeConfig {
if x != nil {
return x.ScStreamUpServerSecs
}
return nil
}
func (x *Config) GetXmux() *XmuxConfig { func (x *Config) GetXmux() *XmuxConfig {
if x != nil { if x != nil {
return x.Xmux return x.Xmux
@@ -344,7 +336,7 @@ var file_transport_internet_splithttp_config_proto_rawDesc = []byte{
0x10, 0x68, 0x4d, 0x61, 0x78, 0x52, 0x65, 0x75, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x63, 0x10, 0x68, 0x4d, 0x61, 0x78, 0x52, 0x65, 0x75, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x63,
0x73, 0x12, 0x2a, 0x0a, 0x10, 0x68, 0x4b, 0x65, 0x65, 0x70, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x50, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x68, 0x4b, 0x65, 0x65, 0x70, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x50,
0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x68, 0x4b, 0x65, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x68, 0x4b, 0x65,
0x65, 0x70, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x22, 0xdc, 0x06, 0x65, 0x70, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x22, 0xf8, 0x05,
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,
0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68,
@@ -379,35 +371,29 @@ var file_transport_internet_splithttp_config_proto_rawDesc = []byte{
0x72, 0x76, 0x61, 0x6c, 0x4d, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x73, 0x63, 0x4d, 0x61, 0x78, 0x42, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x73, 0x63, 0x4d, 0x61, 0x78, 0x42,
0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01,
0x28, 0x03, 0x52, 0x12, 0x73, 0x63, 0x4d, 0x61, 0x78, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x28, 0x03, 0x52, 0x12, 0x73, 0x63, 0x4d, 0x61, 0x78, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65,
0x64, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x62, 0x0a, 0x14, 0x73, 0x63, 0x53, 0x74, 0x72, 0x65, 0x64, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x41, 0x0a, 0x04, 0x78, 0x6d, 0x75, 0x78, 0x18, 0x0b,
0x61, 0x6d, 0x55, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x63, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 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, 0x73, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73,
0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x58, 0x6d, 0x75, 0x78, 0x43, 0x6f, 0x6e,
0x6e, 0x66, 0x69, 0x67, 0x52, 0x14, 0x73, 0x63, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x55, 0x70, 0x66, 0x69, 0x67, 0x52, 0x04, 0x78, 0x6d, 0x75, 0x78, 0x12, 0x51, 0x0a, 0x10, 0x64, 0x6f, 0x77,
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x63, 0x73, 0x12, 0x41, 0x0a, 0x04, 0x78, 0x6d, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x0c, 0x20,
0x75, 0x78, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74,
0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x58, 0x6d, 0x75, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x64, 0x6f, 0x77, 0x6e,
0x78, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x04, 0x78, 0x6d, 0x75, 0x78, 0x12, 0x51, 0x0a, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x1a, 0x3a, 0x0a, 0x0c,
0x10, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76,
0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x85, 0x01, 0x0a, 0x25, 0x63, 0x6f, 0x6d,
0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x1a, 0x3a, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74,
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x74, 0x70, 0x50, 0x01, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f,
0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x85, 0x01, 0x0a, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x25, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x65, 0x74, 0x2f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0xaa, 0x02, 0x21, 0x58,
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e,
0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x50, 0x01, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x48, 0x74, 0x74, 0x70,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70,
0xaa, 0x02, 0x21, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x70, 0x6c, 0x69, 0x74,
0x48, 0x74, 0x74, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@@ -440,14 +426,13 @@ var file_transport_internet_splithttp_config_proto_depIdxs = []int32{
0, // 6: xray.transport.internet.splithttp.Config.xPaddingBytes:type_name -> xray.transport.internet.splithttp.RangeConfig 0, // 6: xray.transport.internet.splithttp.Config.xPaddingBytes:type_name -> xray.transport.internet.splithttp.RangeConfig
0, // 7: xray.transport.internet.splithttp.Config.scMaxEachPostBytes:type_name -> xray.transport.internet.splithttp.RangeConfig 0, // 7: xray.transport.internet.splithttp.Config.scMaxEachPostBytes:type_name -> xray.transport.internet.splithttp.RangeConfig
0, // 8: xray.transport.internet.splithttp.Config.scMinPostsIntervalMs:type_name -> xray.transport.internet.splithttp.RangeConfig 0, // 8: xray.transport.internet.splithttp.Config.scMinPostsIntervalMs:type_name -> xray.transport.internet.splithttp.RangeConfig
0, // 9: xray.transport.internet.splithttp.Config.scStreamUpServerSecs:type_name -> xray.transport.internet.splithttp.RangeConfig 1, // 9: xray.transport.internet.splithttp.Config.xmux:type_name -> xray.transport.internet.splithttp.XmuxConfig
1, // 10: xray.transport.internet.splithttp.Config.xmux:type_name -> xray.transport.internet.splithttp.XmuxConfig 4, // 10: xray.transport.internet.splithttp.Config.downloadSettings:type_name -> xray.transport.internet.StreamConfig
4, // 11: xray.transport.internet.splithttp.Config.downloadSettings:type_name -> xray.transport.internet.StreamConfig 11, // [11:11] is the sub-list for method output_type
12, // [12:12] is the sub-list for method output_type 11, // [11:11] is the sub-list for method input_type
12, // [12:12] is the sub-list for method input_type 11, // [11:11] is the sub-list for extension type_name
12, // [12:12] is the sub-list for extension type_name 11, // [11:11] is the sub-list for extension extendee
12, // [12:12] is the sub-list for extension extendee 0, // [0:11] is the sub-list for field type_name
0, // [0:12] is the sub-list for field type_name
} }
func init() { file_transport_internet_splithttp_config_proto_init() } func init() { file_transport_internet_splithttp_config_proto_init() }

View File

@@ -33,7 +33,6 @@ message Config {
RangeConfig scMaxEachPostBytes = 8; RangeConfig scMaxEachPostBytes = 8;
RangeConfig scMinPostsIntervalMs = 9; RangeConfig scMinPostsIntervalMs = 9;
int64 scMaxBufferedPosts = 10; int64 scMaxBufferedPosts = 10;
RangeConfig scStreamUpServerSecs = 11; XmuxConfig xmux = 11;
XmuxConfig xmux = 12; xray.transport.internet.StreamConfig downloadSettings = 12;
xray.transport.internet.StreamConfig downloadSettings = 13;
} }

View File

@@ -13,8 +13,8 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/quic-go/quic-go" "github.com/xtls/quic-go"
"github.com/quic-go/quic-go/http3" "github.com/xtls/quic-go/http3"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
@@ -30,6 +30,16 @@ import (
"golang.org/x/net/http2" "golang.org/x/net/http2"
) )
// 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
type dialerConf struct { type dialerConf struct {
net.Destination net.Destination
*internet.MemoryStreamConfig *internet.MemoryStreamConfig
@@ -43,8 +53,8 @@ var (
func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (DialerClient, *XmuxClient) { func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (DialerClient, *XmuxClient) {
realityConfig := reality.ConfigFromStreamSettings(streamSettings) realityConfig := reality.ConfigFromStreamSettings(streamSettings)
if browser_dialer.HasBrowserDialer() && realityConfig == nil { if browser_dialer.HasBrowserDialer() && realityConfig != nil {
return &BrowserDialerClient{transportConfig: streamSettings.ProtocolSettings.(*Config)}, nil return &BrowserDialerClient{}, nil
} }
globalDialerAccess.Lock() globalDialerAccess.Lock()
@@ -144,13 +154,13 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
if httpVersion == "3" { if httpVersion == "3" {
if keepAlivePeriod == 0 { if keepAlivePeriod == 0 {
keepAlivePeriod = net.QuicgoH3KeepAlivePeriod keepAlivePeriod = quicgoH3KeepAlivePeriod
} }
if keepAlivePeriod < 0 { if keepAlivePeriod < 0 {
keepAlivePeriod = 0 keepAlivePeriod = 0
} }
quicConfig := &quic.Config{ quicConfig := &quic.Config{
MaxIdleTimeout: net.ConnIdleTimeout, MaxIdleTimeout: connIdleTimeout,
// these two are defaults of quic-go/http3. the default of quic-go (no // these two are defaults of quic-go/http3. the default of quic-go (no
// http3) is different, so it is hardcoded here for clarity. // http3) is different, so it is hardcoded here for clarity.
@@ -158,7 +168,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
MaxIncomingStreams: -1, MaxIncomingStreams: -1,
KeepAlivePeriod: keepAlivePeriod, KeepAlivePeriod: keepAlivePeriod,
} }
transport = &http3.Transport{ transport = &http3.RoundTripper{
QUICConfig: quicConfig, QUICConfig: quicConfig,
TLSClientConfig: gotlsConfig, TLSClientConfig: gotlsConfig,
Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (quic.EarlyConnection, error) { Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
@@ -188,7 +198,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
return nil, err return nil, err
} }
default: default:
udpConn = &internet.FakePacketConn{Conn: c} udpConn = &internet.FakePacketConn{c}
udpAddr, err = net.ResolveUDPAddr("udp", c.RemoteAddr().String()) udpAddr, err = net.ResolveUDPAddr("udp", c.RemoteAddr().String())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -200,7 +210,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
} }
} else if httpVersion == "2" { } else if httpVersion == "2" {
if keepAlivePeriod == 0 { if keepAlivePeriod == 0 {
keepAlivePeriod = net.ChromeH2KeepAlivePeriod keepAlivePeriod = chromeH2KeepAlivePeriod
} }
if keepAlivePeriod < 0 { if keepAlivePeriod < 0 {
keepAlivePeriod = 0 keepAlivePeriod = 0
@@ -209,7 +219,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
DialTLSContext: func(ctxInner context.Context, network string, addr string, cfg *gotls.Config) (net.Conn, error) { DialTLSContext: func(ctxInner context.Context, network string, addr string, cfg *gotls.Config) (net.Conn, error) {
return dialContext(ctxInner) return dialContext(ctxInner)
}, },
IdleConnTimeout: net.ConnIdleTimeout, IdleConnTimeout: connIdleTimeout,
ReadIdleTimeout: keepAlivePeriod, ReadIdleTimeout: keepAlivePeriod,
} }
} else { } else {
@@ -220,7 +230,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
transport = &http.Transport{ transport = &http.Transport{
DialTLSContext: httpDialContext, DialTLSContext: httpDialContext,
DialContext: httpDialContext, DialContext: httpDialContext,
IdleConnTimeout: net.ConnIdleTimeout, IdleConnTimeout: connIdleTimeout,
// chunked transfer download with KeepAlives is buggy with // chunked transfer download with KeepAlives is buggy with
// http.Client and our custom dial context. // http.Client and our custom dial context.
DisableKeepAlives: true, DisableKeepAlives: true,
@@ -357,22 +367,19 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
}, },
} }
var err error
if mode == "stream-one" { if mode == "stream-one" {
requestURL.Path = transportConfiguration.GetNormalizedPath() requestURL.Path = transportConfiguration.GetNormalizedPath()
if xmuxClient != nil { if xmuxClient != nil {
xmuxClient.LeftRequests.Add(-1) xmuxClient.LeftRequests.Add(-1)
} }
conn.reader, conn.remoteAddr, conn.localAddr, err = httpClient.OpenStream(ctx, requestURL.String(), reader, false) conn.reader, conn.remoteAddr, conn.localAddr, _ = httpClient.OpenStream(context.WithoutCancel(ctx), requestURL.String(), reader, false)
if err != nil { // browser dialer only
return nil, err
}
return stat.Connection(&conn), nil return stat.Connection(&conn), nil
} else { // stream-down } else { // stream-down
var err error
if xmuxClient2 != nil { if xmuxClient2 != nil {
xmuxClient2.LeftRequests.Add(-1) xmuxClient2.LeftRequests.Add(-1)
} }
conn.reader, conn.remoteAddr, conn.localAddr, err = httpClient2.OpenStream(ctx, requestURL2.String(), nil, false) conn.reader, conn.remoteAddr, conn.localAddr, err = httpClient2.OpenStream(context.WithoutCancel(ctx), requestURL2.String(), nil, false)
if err != nil { // browser dialer only if err != nil { // browser dialer only
return nil, err return nil, err
} }
@@ -381,10 +388,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
if xmuxClient != nil { if xmuxClient != nil {
xmuxClient.LeftRequests.Add(-1) xmuxClient.LeftRequests.Add(-1)
} }
_, _, _, err = httpClient.OpenStream(ctx, requestURL.String(), reader, true) httpClient.OpenStream(ctx, requestURL.String(), reader, true)
if err != nil { // browser dialer only
return nil, err
}
return stat.Connection(&conn), nil return stat.Connection(&conn), nil
} }
@@ -424,6 +428,8 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
// can reassign Path (potentially concurrently) // can reassign Path (potentially concurrently)
url := requestURL url := requestURL
url.Path += "/" + strconv.FormatInt(seq, 10) url.Path += "/" + strconv.FormatInt(seq, 10)
// reassign query to get different padding
url.RawQuery = transportConfiguration.GetNormalizedQuery()
seq += 1 seq += 1
@@ -448,7 +454,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
go func() { go func() {
err := httpClient.PostPacket( err := httpClient.PostPacket(
ctx, context.WithoutCancel(ctx),
url.String(), url.String(),
&buf.MultiBufferContainer{MultiBuffer: chunk}, &buf.MultiBufferContainer{MultiBuffer: chunk},
int64(chunk.Len()), int64(chunk.Len()),

View File

@@ -1,19 +1,18 @@
package splithttp package splithttp
import ( import (
"bytes"
"context" "context"
gotls "crypto/tls" "crypto/tls"
"io" "io"
gonet "net"
"net/http" "net/http"
"net/url"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/quic-go/quic-go" "github.com/xtls/quic-go"
"github.com/quic-go/quic-go/http3" "github.com/xtls/quic-go/http3"
goreality "github.com/xtls/reality" goreality "github.com/xtls/reality"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
@@ -23,7 +22,9 @@ import (
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/reality" "github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" v2tls "github.com/xtls/xray-core/transport/internet/tls"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
) )
type requestHandler struct { type requestHandler struct {
@@ -33,7 +34,7 @@ type requestHandler struct {
ln *Listener ln *Listener
sessionMu *sync.Mutex sessionMu *sync.Mutex
sessions sync.Map sessions sync.Map
localAddr net.Addr localAddr gonet.TCPAddr
} }
type httpSession struct { type httpSession struct {
@@ -45,6 +46,21 @@ type httpSession struct {
isFullyConnected *done.Instance isFullyConnected *done.Instance
} }
func (h *requestHandler) maybeReapSession(isFullyConnected *done.Instance, sessionId string) {
shouldReap := done.New()
go func() {
time.Sleep(30 * time.Second)
shouldReap.Close()
}()
select {
case <-isFullyConnected.Wait():
return
case <-shouldReap.Wait():
h.sessions.Delete(sessionId)
}
}
func (h *requestHandler) upsertSession(sessionId string) *httpSession { func (h *requestHandler) upsertSession(sessionId string) *httpSession {
// fast path // fast path
currentSessionAny, ok := h.sessions.Load(sessionId) currentSessionAny, ok := h.sessions.Load(sessionId)
@@ -67,21 +83,7 @@ func (h *requestHandler) upsertSession(sessionId string) *httpSession {
} }
h.sessions.Store(sessionId, s) h.sessions.Store(sessionId, s)
go h.maybeReapSession(s.isFullyConnected, sessionId)
shouldReap := done.New()
go func() {
time.Sleep(30 * time.Second)
shouldReap.Close()
}()
go func() {
select {
case <-shouldReap.Wait():
h.sessions.Delete(sessionId)
s.uploadQueue.Close()
case <-s.isFullyConnected.Wait():
}
}()
return s return s
} }
@@ -100,29 +102,10 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
h.config.WriteResponseHeader(writer) h.config.WriteResponseHeader(writer)
/*
clientVer := []int{0, 0, 0}
x_version := strings.Split(request.URL.Query().Get("x_version"), ".")
for j := 0; j < 3 && len(x_version) > j; j++ {
clientVer[j], _ = strconv.Atoi(x_version[j])
}
*/
validRange := h.config.GetNormalizedXPaddingBytes() validRange := h.config.GetNormalizedXPaddingBytes()
paddingLength := 0 x_padding := int32(len(request.URL.Query().Get("x_padding")))
if validRange.To > 0 && (x_padding < validRange.From || x_padding > validRange.To) {
referrer := request.Header.Get("Referer") errors.LogInfo(context.Background(), "invalid x_padding length:", x_padding)
if referrer != "" {
if referrerURL, err := url.Parse(referrer); err == nil {
// Browser dialer cannot control the host part of referrer header, so only check the query
paddingLength = len(referrerURL.Query().Get("x_padding"))
}
} else {
paddingLength = len(request.URL.Query().Get("x_padding"))
}
if int32(paddingLength) < validRange.From || int32(paddingLength) > validRange.To {
errors.LogInfo(context.Background(), "invalid x_padding length:", int32(paddingLength))
writer.WriteHeader(http.StatusBadRequest) writer.WriteHeader(http.StatusBadRequest)
return return
} }
@@ -140,25 +123,14 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
} }
forwardedAddrs := http_proto.ParseXForwardedFor(request.Header) forwardedAddrs := http_proto.ParseXForwardedFor(request.Header)
var remoteAddr net.Addr remoteAddr, err := gonet.ResolveTCPAddr("tcp", request.RemoteAddr)
var err error
remoteAddr, err = net.ResolveTCPAddr("tcp", request.RemoteAddr)
if err != nil { if err != nil {
remoteAddr = &net.TCPAddr{ remoteAddr = &gonet.TCPAddr{}
IP: []byte{0, 0, 0, 0},
Port: 0,
}
}
if request.ProtoMajor == 3 {
remoteAddr = &net.UDPAddr{
IP: remoteAddr.(*net.TCPAddr).IP,
Port: remoteAddr.(*net.TCPAddr).Port,
}
} }
if len(forwardedAddrs) > 0 && forwardedAddrs[0].Family().IsIP() { if len(forwardedAddrs) > 0 && forwardedAddrs[0].Family().IsIP() {
remoteAddr = &net.TCPAddr{ remoteAddr = &net.TCPAddr{
IP: forwardedAddrs[0].IP(), IP: forwardedAddrs[0].IP(),
Port: 0, Port: int(0),
} }
} }
@@ -168,7 +140,7 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
} }
scMaxEachPostBytes := int(h.ln.config.GetNormalizedScMaxEachPostBytes().To) scMaxEachPostBytes := int(h.ln.config.GetNormalizedScMaxEachPostBytes().To)
if request.Method == "POST" && sessionId != "" { // stream-up, packet-up if request.Method == "POST" && sessionId != "" {
seq := "" seq := ""
if len(subpath) > 1 { if len(subpath) > 1 {
seq = subpath[1] seq = subpath[1]
@@ -180,39 +152,16 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
writer.WriteHeader(http.StatusBadRequest) writer.WriteHeader(http.StatusBadRequest)
return return
} }
httpSC := &httpServerConn{
Instance: done.New(),
Reader: request.Body,
ResponseWriter: writer,
}
err = currentSession.uploadQueue.Push(Packet{ err = currentSession.uploadQueue.Push(Packet{
Reader: httpSC, Reader: request.Body,
}) })
if err != nil { if err != nil {
errors.LogInfoInner(context.Background(), err, "failed to upload (PushReader)") errors.LogInfoInner(context.Background(), err, "failed to upload (PushReader)")
writer.WriteHeader(http.StatusConflict) writer.WriteHeader(http.StatusConflict)
} else { } else {
writer.Header().Set("X-Accel-Buffering", "no")
writer.Header().Set("Cache-Control", "no-store")
writer.WriteHeader(http.StatusOK) writer.WriteHeader(http.StatusOK)
scStreamUpServerSecs := h.config.GetNormalizedScStreamUpServerSecs() <-request.Context().Done()
if referrer != "" && scStreamUpServerSecs.To > 0 {
go func() {
for {
_, err := httpSC.Write(bytes.Repeat([]byte{'X'}, int(h.config.GetNormalizedXPaddingBytes().rand())))
if err != nil {
break
}
time.Sleep(time.Duration(scStreamUpServerSecs.rand()) * time.Second)
}
}()
}
select {
case <-request.Context().Done():
case <-httpSC.Wait():
}
} }
httpSC.Close()
return return
} }
@@ -222,10 +171,10 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
return return
} }
payload, err := io.ReadAll(io.LimitReader(request.Body, int64(scMaxEachPostBytes)+1)) payload, err := io.ReadAll(request.Body)
if len(payload) > scMaxEachPostBytes { if len(payload) > scMaxEachPostBytes {
errors.LogInfo(context.Background(), "Too large upload. scMaxEachPostBytes is set to ", scMaxEachPostBytes, "but request size exceed it. Adjust scMaxEachPostBytes on the server to be at least as large as client.") errors.LogInfo(context.Background(), "Too large upload. scMaxEachPostBytes is set to ", scMaxEachPostBytes, "but request had size ", len(payload), ". Adjust scMaxEachPostBytes on the server to be at least as large as client.")
writer.WriteHeader(http.StatusRequestEntityTooLarge) writer.WriteHeader(http.StatusRequestEntityTooLarge)
return return
} }
@@ -255,7 +204,12 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
} }
writer.WriteHeader(http.StatusOK) writer.WriteHeader(http.StatusOK)
} else if request.Method == "GET" || sessionId == "" { // stream-down, stream-one } else if request.Method == "GET" || sessionId == "" {
responseFlusher, ok := writer.(http.Flusher)
if !ok {
panic("expected http.ResponseWriter to be an http.Flusher")
}
if sessionId != "" { if sessionId != "" {
// after GET is done, the connection is finished. disable automatic // after GET is done, the connection is finished. disable automatic
// session reaping, and handle it in defer // session reaping, and handle it in defer
@@ -276,20 +230,21 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
} }
writer.WriteHeader(http.StatusOK) writer.WriteHeader(http.StatusOK)
writer.(http.Flusher).Flush()
httpSC := &httpServerConn{ responseFlusher.Flush()
Instance: done.New(),
Reader: request.Body, downloadDone := done.New()
ResponseWriter: writer,
}
conn := splitConn{ conn := splitConn{
writer: httpSC, writer: &httpResponseBodyWriter{
reader: httpSC, responseWriter: writer,
downloadDone: downloadDone,
responseFlusher: responseFlusher,
},
reader: request.Body,
remoteAddr: remoteAddr, remoteAddr: remoteAddr,
localAddr: h.localAddr,
} }
if sessionId != "" { // if not stream-one if sessionId != "" {
conn.reader = currentSession.uploadQueue conn.reader = currentSession.uploadQueue
} }
@@ -298,7 +253,7 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
// "A ResponseWriter may not be used after [Handler.ServeHTTP] has returned." // "A ResponseWriter may not be used after [Handler.ServeHTTP] has returned."
select { select {
case <-request.Context().Done(): case <-request.Context().Done():
case <-httpSC.Wait(): case <-downloadDone.Wait():
} }
conn.Close() conn.Close()
@@ -308,30 +263,31 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
} }
} }
type httpServerConn struct { type httpResponseBodyWriter struct {
sync.Mutex sync.Mutex
*done.Instance responseWriter http.ResponseWriter
io.Reader // no need to Close request.Body responseFlusher http.Flusher
http.ResponseWriter downloadDone *done.Instance
} }
func (c *httpServerConn) Write(b []byte) (int, error) { func (c *httpResponseBodyWriter) Write(b []byte) (int, error) {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
if c.Done() { if c.downloadDone.Done() {
return 0, io.ErrClosedPipe return 0, io.ErrClosedPipe
} }
n, err := c.ResponseWriter.Write(b) n, err := c.responseWriter.Write(b)
if err == nil { if err == nil {
c.ResponseWriter.(http.Flusher).Flush() c.responseFlusher.Flush()
} }
return n, err return n, err
} }
func (c *httpServerConn) Close() error { func (c *httpResponseBodyWriter) Close() error {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
return c.Instance.Close() c.downloadDone.Close()
return nil
} }
type Listener struct { type Listener struct {
@@ -345,30 +301,34 @@ type Listener struct {
isH3 bool isH3 bool
} }
func ListenXH(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (internet.Listener, error) { func ListenSH(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (internet.Listener, error) {
l := &Listener{ l := &Listener{
addConn: addConn, addConn: addConn,
} }
l.config = streamSettings.ProtocolSettings.(*Config) shSettings := streamSettings.ProtocolSettings.(*Config)
l.config = shSettings
if l.config != nil { if l.config != nil {
if streamSettings.SocketSettings == nil { if streamSettings.SocketSettings == nil {
streamSettings.SocketSettings = &internet.SocketConfig{} streamSettings.SocketSettings = &internet.SocketConfig{}
} }
} }
var listener net.Listener
var err error
var localAddr = gonet.TCPAddr{}
handler := &requestHandler{ handler := &requestHandler{
config: l.config, config: shSettings,
host: l.config.Host, host: shSettings.Host,
path: l.config.GetNormalizedPath(), path: shSettings.GetNormalizedPath(),
ln: l, ln: l,
sessionMu: &sync.Mutex{}, sessionMu: &sync.Mutex{},
sessions: sync.Map{}, sessions: sync.Map{},
localAddr: localAddr,
} }
tlsConfig := getTLSConfig(streamSettings) tlsConfig := getTLSConfig(streamSettings)
l.isH3 = len(tlsConfig.NextProtos) == 1 && tlsConfig.NextProtos[0] == "h3" l.isH3 = len(tlsConfig.NextProtos) == 1 && tlsConfig.NextProtos[0] == "h3"
var err error
if port == net.Port(0) { // unix if port == net.Port(0) { // unix
l.listener, err = internet.ListenSystem(ctx, &net.UnixAddr{ listener, err = internet.ListenSystem(ctx, &net.UnixAddr{
Name: address.Domain(), Name: address.Domain(),
Net: "unix", Net: "unix",
}, streamSettings.SocketSettings) }, streamSettings.SocketSettings)
@@ -384,24 +344,27 @@ func ListenXH(ctx context.Context, address net.Address, port net.Port, streamSet
if err != nil { if err != nil {
return nil, errors.New("failed to listen UDP for XHTTP/3 on ", address, ":", port).Base(err) return nil, errors.New("failed to listen UDP for XHTTP/3 on ", address, ":", port).Base(err)
} }
l.h3listener, err = quic.ListenEarly(Conn, tlsConfig, nil) h3listener, err := quic.ListenEarly(Conn, tlsConfig, nil)
if err != nil { if err != nil {
return nil, errors.New("failed to listen QUIC for XHTTP/3 on ", address, ":", port).Base(err) return nil, errors.New("failed to listen QUIC for XHTTP/3 on ", address, ":", port).Base(err)
} }
l.h3listener = h3listener
errors.LogInfo(ctx, "listening QUIC for XHTTP/3 on ", address, ":", port) errors.LogInfo(ctx, "listening QUIC for XHTTP/3 on ", address, ":", port)
handler.localAddr = l.h3listener.Addr()
l.h3server = &http3.Server{ l.h3server = &http3.Server{
Handler: handler, Handler: handler,
} }
go func() { go func() {
if err := l.h3server.ServeListener(l.h3listener); err != nil { if err := l.h3server.ServeListener(l.h3listener); err != nil {
errors.LogErrorInner(ctx, err, "failed to serve HTTP/3 for XHTTP/3") errors.LogWarningInner(ctx, err, "failed to serve HTTP/3 for XHTTP/3")
} }
}() }()
} else { // tcp } else { // tcp
l.listener, err = internet.ListenSystem(ctx, &net.TCPAddr{ localAddr = gonet.TCPAddr{
IP: address.IP(),
Port: int(port),
}
listener, err = internet.ListenSystem(ctx, &net.TCPAddr{
IP: address.IP(), IP: address.IP(),
Port: int(port), Port: int(port),
}, streamSettings.SocketSettings) }, streamSettings.SocketSettings)
@@ -412,31 +375,29 @@ func ListenXH(ctx context.Context, address net.Address, port net.Port, streamSet
} }
// tcp/unix (h1/h2) // tcp/unix (h1/h2)
if l.listener != nil { if listener != nil {
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil { if config := v2tls.ConfigFromStreamSettings(streamSettings); config != nil {
if tlsConfig := config.GetTLSConfig(); tlsConfig != nil { if tlsConfig := config.GetTLSConfig(); tlsConfig != nil {
l.listener = gotls.NewListener(l.listener, tlsConfig) listener = tls.NewListener(listener, tlsConfig)
} }
} }
if config := reality.ConfigFromStreamSettings(streamSettings); config != nil { if config := reality.ConfigFromStreamSettings(streamSettings); config != nil {
l.listener = goreality.NewListener(l.listener, config.GetREALITYConfig()) listener = goreality.NewListener(listener, config.GetREALITYConfig())
} }
handler.localAddr = l.listener.Addr() // h2cHandler can handle both plaintext HTTP/1.1 and h2c
h2cHandler := h2c.NewHandler(handler, &http2.Server{})
// server can handle both plaintext HTTP/1.1 and h2c l.listener = listener
protocols := new(http.Protocols)
protocols.SetHTTP1(true)
protocols.SetUnencryptedHTTP2(true)
l.server = http.Server{ l.server = http.Server{
Handler: handler, Handler: h2cHandler,
ReadHeaderTimeout: time.Second * 4, ReadHeaderTimeout: time.Second * 4,
MaxHeaderBytes: 8192, MaxHeaderBytes: 8192,
Protocols: protocols,
} }
go func() { go func() {
if err := l.server.Serve(l.listener); err != nil { if err := l.server.Serve(l.listener); err != nil {
errors.LogErrorInner(ctx, err, "failed to serve HTTP for XHTTP") errors.LogWarningInner(ctx, err, "failed to serve HTTP for XHTTP")
} }
}() }()
} }
@@ -466,13 +427,13 @@ func (ln *Listener) Close() error {
} }
return errors.New("listener does not have an HTTP/3 server or a net.listener") return errors.New("listener does not have an HTTP/3 server or a net.listener")
} }
func getTLSConfig(streamSettings *internet.MemoryStreamConfig) *gotls.Config { func getTLSConfig(streamSettings *internet.MemoryStreamConfig) *tls.Config {
config := tls.ConfigFromStreamSettings(streamSettings) config := v2tls.ConfigFromStreamSettings(streamSettings)
if config == nil { if config == nil {
return &gotls.Config{} return &tls.Config{}
} }
return config.GetTLSConfig() return config.GetTLSConfig()
} }
func init() { func init() {
common.Must(internet.RegisterTransportListener(protocolName, ListenXH)) common.Must(internet.RegisterTransportListener(protocolName, ListenSH))
} }

Some files were not shown because too many files have changed in this diff Show More