mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-07-23 10:24:15 +00:00
Merge branch 'main' into add-goxray-gui-client
This commit is contained in:
commit
3ecfabdbe5
27 changed files with 304 additions and 129 deletions
133
.github/workflows/docker.yml
vendored
133
.github/workflows/docker.yml
vendored
|
@ -1,36 +1,74 @@
|
|||
name: Build docker image
|
||||
name: Build and Push Docker Image
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
types:
|
||||
- published
|
||||
- released
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Docker image tag:"
|
||||
required: true
|
||||
latest:
|
||||
description: "Set to latest"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build-image:
|
||||
build-and-push:
|
||||
if: (github.event.action != 'published') || (github.event.action == 'published' && github.event.release.prerelease == true)
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set repository and image name to lowercase
|
||||
env:
|
||||
IMAGE_NAME: "${{ github.repository }}"
|
||||
run: |
|
||||
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
|
||||
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
|
||||
|
||||
- name: Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/xray-core
|
||||
flavor: latest=auto
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
- name: Validate and extract tag
|
||||
run: |
|
||||
SOURCE_TAG="${{ github.event.inputs.tag }}"
|
||||
if [[ -z "$SOURCE_TAG" ]]; then
|
||||
SOURCE_TAG="${{ github.ref_name }}"
|
||||
fi
|
||||
|
||||
- name: Docker metadata (unsupported architectures)
|
||||
id: metausa
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/xray-core
|
||||
flavor: |
|
||||
latest=auto
|
||||
suffix=-usa,onlatest=true
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
if [[ -z "$SOURCE_TAG" ]]; then
|
||||
echo "Error: Could not determine a valid tag source. Input tag and context tag (github.ref_name) are both empty."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$SOURCE_TAG" =~ ^v[0-9]+\.[0-9] ]]; then
|
||||
IMAGE_TAG="${SOURCE_TAG#v}"
|
||||
else
|
||||
IMAGE_TAG="$SOURCE_TAG"
|
||||
fi
|
||||
|
||||
echo "Docker image tag: '$IMAGE_TAG'."
|
||||
echo "IMAGE_TAG=$IMAGE_TAG" >>${GITHUB_ENV}
|
||||
|
||||
LATEST=false
|
||||
if [[ "${{ github.event_name }}" == "release" && "${{ github.event.release.prerelease }}" == "false" ]] || [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ github.event.inputs.latest }}" == "true" ]]; then
|
||||
LATEST=true
|
||||
fi
|
||||
|
||||
echo "Latest: '$LATEST'."
|
||||
echo "LATEST=$LATEST" >>${GITHUB_ENV}
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
|
@ -39,13 +77,12 @@ jobs:
|
|||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push
|
||||
- name: Build Docker image (main architectures)
|
||||
id: build_main_arches
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: .github/docker/Dockerfile
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm/v7
|
||||
|
@ -53,39 +90,41 @@ jobs:
|
|||
linux/ppc64le
|
||||
linux/s390x
|
||||
provenance: false
|
||||
file: .github/docker/Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
- name: Build and push (unsupported architectures)
|
||||
- name: Build Docker image (additional architectures)
|
||||
id: build_additional_arches
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: .github/docker/Dockerfile.usa
|
||||
platforms: |
|
||||
linux/386
|
||||
linux/arm/v6
|
||||
linux/riscv64
|
||||
linux/loong64
|
||||
provenance: false
|
||||
file: .github/docker/Dockerfile.usa
|
||||
push: true
|
||||
tags: ${{ steps.metausa.outputs.tags }}
|
||||
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
- name: Merge Multi-Arch Manifests
|
||||
- name: Create manifest list and push
|
||||
run: |
|
||||
echo "Starting to merge multi-architecture manifests..."
|
||||
echo "Creating multi-arch manifest with tag: '${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}'."
|
||||
docker buildx imagetools create \
|
||||
--tag ${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }} \
|
||||
${{ env.FULL_IMAGE_NAME }}@${{ steps.build_main_arches.outputs.digest }} \
|
||||
${{ env.FULL_IMAGE_NAME }}@${{ steps.build_additional_arches.outputs.digest }}
|
||||
|
||||
# Convert newlines to spaces and split into array
|
||||
TAGS=($(echo "${{ steps.meta.outputs.tags }}" | tr '\n' ' '))
|
||||
if [[ "${{ env.LATEST }}" == "true" ]]; then
|
||||
echo "Adding 'latest' tag to manifest: '${{ env.FULL_IMAGE_NAME }}:latest'."
|
||||
docker buildx imagetools create \
|
||||
--tag ${{ env.FULL_IMAGE_NAME }}:latest \
|
||||
${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
||||
fi
|
||||
|
||||
echo "Total tags to process: ${#TAGS[@]}"
|
||||
for tag in "${TAGS[@]}"; do
|
||||
echo "Merging tag: $tag with unsupported architectures ($tag-usa)"
|
||||
docker buildx imagetools create --append --tag "$tag" "$tag-usa"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to merge $tag-usa into $tag"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
- name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
||||
|
||||
echo "Multi-architecture manifest merge completed successfully."
|
||||
if [[ "${{ env.LATEST }}" == "true" ]]; then
|
||||
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:latest
|
||||
fi
|
||||
|
|
|
@ -81,11 +81,13 @@
|
|||
- [v2rayN](https://github.com/2dust/v2rayN)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
- Android
|
||||
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
||||
- [X-flutter](https://github.com/XTLS/X-flutter)
|
||||
- [SaeedDev94/Xray](https://github.com/SaeedDev94/Xray)
|
||||
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
- iOS & macOS arm64
|
||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215)
|
||||
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)
|
||||
|
@ -97,11 +99,13 @@
|
|||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
- [OneXray](https://github.com/OneXray/OneXray)
|
||||
- [GoXRay](https://github.com/goxray/desktop)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
- Linux
|
||||
- [v2rayA](https://github.com/v2rayA/v2rayA)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
- [GorzRay](https://github.com/ketetefid/GorzRay)
|
||||
- [GoXRay](https://github.com/goxray/desktop)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
|
||||
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ type QUICNameServer struct {
|
|||
sync.RWMutex
|
||||
cacheController *CacheController
|
||||
destination *net.Destination
|
||||
connection quic.Connection
|
||||
connection *quic.Conn
|
||||
clientIP net.IP
|
||||
}
|
||||
|
||||
|
@ -220,7 +220,7 @@ func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, option dns_
|
|||
|
||||
}
|
||||
|
||||
func isActive(s quic.Connection) bool {
|
||||
func isActive(s *quic.Conn) bool {
|
||||
select {
|
||||
case <-s.Context().Done():
|
||||
return false
|
||||
|
@ -229,8 +229,8 @@ func isActive(s quic.Connection) bool {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) getConnection() (quic.Connection, error) {
|
||||
var conn quic.Connection
|
||||
func (s *QUICNameServer) getConnection() (*quic.Conn, error) {
|
||||
var conn *quic.Conn
|
||||
s.RLock()
|
||||
conn = s.connection
|
||||
if conn != nil && isActive(conn) {
|
||||
|
@ -263,7 +263,7 @@ func (s *QUICNameServer) getConnection() (quic.Connection, error) {
|
|||
return conn, nil
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) openConnection() (quic.Connection, error) {
|
||||
func (s *QUICNameServer) openConnection() (*quic.Conn, error) {
|
||||
tlsConfig := tls.Config{}
|
||||
quicConfig := &quic.Config{
|
||||
HandshakeIdleTimeout: handshakeTimeout,
|
||||
|
@ -283,7 +283,7 @@ func (s *QUICNameServer) openConnection() (quic.Connection, error) {
|
|||
return conn, nil
|
||||
}
|
||||
|
||||
func (s *QUICNameServer) openStream(ctx context.Context) (quic.Stream, error) {
|
||||
func (s *QUICNameServer) openStream(ctx context.Context) (*quic.Stream, error) {
|
||||
conn, err := s.getConnection()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -90,6 +90,8 @@ type HealthPingConfig struct {
|
|||
SamplingCount int32 `protobuf:"varint,4,opt,name=samplingCount,proto3" json:"samplingCount,omitempty"`
|
||||
// ping timeout, int64 values of time.Duration
|
||||
Timeout int64 `protobuf:"varint,5,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
||||
// http method to make request
|
||||
HttpMethod string `protobuf:"bytes,6,opt,name=httpMethod,proto3" json:"httpMethod,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HealthPingConfig) Reset() {
|
||||
|
@ -157,6 +159,13 @@ func (x *HealthPingConfig) GetTimeout() int64 {
|
|||
return 0
|
||||
}
|
||||
|
||||
func (x *HealthPingConfig) GetHttpMethod() string {
|
||||
if x != nil {
|
||||
return x.HttpMethod
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_app_observatory_burst_config_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
||||
|
@ -173,7 +182,7 @@ var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
|||
0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x62, 0x75, 0x72,
|
||||
0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22,
|
||||
0xb4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
||||
0xd4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69,
|
||||
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
|
@ -184,7 +193,9 @@ var file_app_observatory_burst_config_proto_rawDesc = []byte{
|
|||
0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73,
|
||||
0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07,
|
||||
0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
|
||||
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x4d, 0x65,
|
||||
0x74, 0x68, 0x6f, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x68, 0x74, 0x74, 0x70,
|
||||
0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
|
||||
0x72, 0x79, 0x2e, 0x62, 0x75, 0x72, 0x73, 0x74, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68,
|
||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
||||
|
|
|
@ -26,4 +26,7 @@ message HealthPingConfig {
|
|||
int32 samplingCount = 4;
|
||||
// ping timeout, int64 values of time.Duration
|
||||
int64 timeout = 5;
|
||||
// http method to make request
|
||||
string httpMethod = 6;
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ type HealthPingSettings struct {
|
|||
Interval time.Duration `json:"interval"`
|
||||
SamplingCount int `json:"sampling"`
|
||||
Timeout time.Duration `json:"timeout"`
|
||||
HttpMethod string `json:"httpMethod"`
|
||||
}
|
||||
|
||||
// HealthPing is the health checker for balancers
|
||||
|
@ -37,12 +38,21 @@ type HealthPing struct {
|
|||
func NewHealthPing(ctx context.Context, dispatcher routing.Dispatcher, config *HealthPingConfig) *HealthPing {
|
||||
settings := &HealthPingSettings{}
|
||||
if config != nil {
|
||||
|
||||
var httpMethod string
|
||||
if config.HttpMethod == "" {
|
||||
httpMethod = "HEAD"
|
||||
} else {
|
||||
httpMethod = strings.TrimSpace(config.HttpMethod)
|
||||
}
|
||||
|
||||
settings = &HealthPingSettings{
|
||||
Connectivity: strings.TrimSpace(config.Connectivity),
|
||||
Destination: strings.TrimSpace(config.Destination),
|
||||
Interval: time.Duration(config.Interval),
|
||||
SamplingCount: int(config.SamplingCount),
|
||||
Timeout: time.Duration(config.Timeout),
|
||||
HttpMethod: httpMethod,
|
||||
}
|
||||
}
|
||||
if settings.Destination == "" {
|
||||
|
@ -164,7 +174,7 @@ func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int)
|
|||
}
|
||||
time.AfterFunc(delay, func() {
|
||||
errors.LogDebug(h.ctx, "checking ", handler)
|
||||
delay, err := client.MeasureDelay()
|
||||
delay, err := client.MeasureDelay(h.Settings.HttpMethod)
|
||||
if err == nil {
|
||||
ch <- &rtt{
|
||||
handler: handler,
|
||||
|
@ -251,7 +261,7 @@ func (h *HealthPing) checkConnectivity() bool {
|
|||
h.Settings.Connectivity,
|
||||
h.Settings.Timeout,
|
||||
)
|
||||
if _, err := tester.MeasureDelay(); err != nil {
|
||||
if _, err := tester.MeasureDelay(h.Settings.HttpMethod); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -2,6 +2,7 @@ package burst
|
|||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
|
@ -51,20 +52,28 @@ func newHTTPClient(ctxv context.Context, dispatcher routing.Dispatcher, handler
|
|||
}
|
||||
|
||||
// MeasureDelay returns the delay time of the request to dest
|
||||
func (s *pingClient) MeasureDelay() (time.Duration, error) {
|
||||
func (s *pingClient) MeasureDelay(httpMethod string) (time.Duration, error) {
|
||||
if s.httpClient == nil {
|
||||
panic("pingClient not initialized")
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodHead, s.destination, nil)
|
||||
|
||||
req, err := http.NewRequest(httpMethod, s.destination, nil)
|
||||
if err != nil {
|
||||
return rttFailed, err
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
resp, err := s.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return rttFailed, err
|
||||
}
|
||||
// don't wait for body
|
||||
if httpMethod == http.MethodGet {
|
||||
_, err = io.Copy(io.Discard, resp.Body)
|
||||
if err != nil {
|
||||
return rttFailed, err
|
||||
}
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return time.Since(start), nil
|
||||
}
|
||||
|
|
|
@ -103,13 +103,22 @@ func (s *handlerServer) AlterInbound(ctx context.Context, request *AlterInboundR
|
|||
func (s *handlerServer) ListInbounds(ctx context.Context, request *ListInboundsRequest) (*ListInboundsResponse, error) {
|
||||
handlers := s.ihm.ListHandlers(ctx)
|
||||
response := &ListInboundsResponse{}
|
||||
for _, handler := range handlers {
|
||||
response.Inbounds = append(response.Inbounds, &core.InboundHandlerConfig{
|
||||
Tag: handler.Tag(),
|
||||
ReceiverSettings: handler.ReceiverSettings(),
|
||||
ProxySettings: handler.ProxySettings(),
|
||||
})
|
||||
if request.GetIsOnlyTags() {
|
||||
for _, handler := range handlers {
|
||||
response.Inbounds = append(response.Inbounds, &core.InboundHandlerConfig{
|
||||
Tag: handler.Tag(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
for _, handler := range handlers {
|
||||
response.Inbounds = append(response.Inbounds, &core.InboundHandlerConfig{
|
||||
Tag: handler.Tag(),
|
||||
ReceiverSettings: handler.ReceiverSettings(),
|
||||
ProxySettings: handler.ProxySettings(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -368,6 +368,8 @@ type ListInboundsRequest struct {
|
|||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
IsOnlyTags bool `protobuf:"varint,1,opt,name=isOnlyTags,proto3" json:"isOnlyTags,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ListInboundsRequest) Reset() {
|
||||
|
@ -400,6 +402,13 @@ func (*ListInboundsRequest) Descriptor() ([]byte, []int) {
|
|||
return file_app_proxyman_command_command_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *ListInboundsRequest) GetIsOnlyTags() bool {
|
||||
if x != nil {
|
||||
return x.IsOnlyTags
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ListInboundsResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
@ -993,9 +1002,11 @@ var file_app_proxyman_command_command_proto_rawDesc = []byte{
|
|||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70,
|
||||
0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x22, 0x16, 0x0a, 0x14, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62,
|
||||
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, 0x0a, 0x13,
|
||||
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x35, 0x0a, 0x13,
|
||||
0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x22, 0x53, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x54, 0x61, 0x67,
|
||||
0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x54,
|
||||
0x61, 0x67, 0x73, 0x22, 0x53, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75,
|
||||
0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x69,
|
||||
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
|
||||
|
|
|
@ -37,7 +37,9 @@ message AlterInboundRequest {
|
|||
|
||||
message AlterInboundResponse {}
|
||||
|
||||
message ListInboundsRequest {}
|
||||
message ListInboundsRequest {
|
||||
bool isOnlyTags = 1;
|
||||
}
|
||||
|
||||
message ListInboundsResponse {
|
||||
repeated core.InboundHandlerConfig inbounds = 1;
|
||||
|
|
|
@ -12,6 +12,8 @@ import (
|
|||
"github.com/xtls/xray-core/core"
|
||||
feature_stats "github.com/xtls/xray-core/features/stats"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// statsServer is an implementation of StatsService.
|
||||
|
@ -30,7 +32,7 @@ func NewStatsServer(manager feature_stats.Manager) StatsServiceServer {
|
|||
func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {
|
||||
c := s.stats.GetCounter(request.Name)
|
||||
if c == nil {
|
||||
return nil, errors.New(request.Name, " not found.")
|
||||
return nil, status.Error(codes.NotFound, request.Name+" not found.")
|
||||
}
|
||||
var value int64
|
||||
if request.Reset_ {
|
||||
|
@ -49,7 +51,7 @@ func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*
|
|||
func (s *statsServer) GetStatsOnline(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {
|
||||
c := s.stats.GetOnlineMap(request.Name)
|
||||
if c == nil {
|
||||
return nil, errors.New(request.Name, " not found.")
|
||||
return nil, status.Error(codes.NotFound, request.Name+" not found.")
|
||||
}
|
||||
value := int64(c.Count())
|
||||
return &GetStatsResponse{
|
||||
|
@ -64,7 +66,7 @@ func (s *statsServer) GetStatsOnlineIpList(ctx context.Context, request *GetStat
|
|||
c := s.stats.GetOnlineMap(request.Name)
|
||||
|
||||
if c == nil {
|
||||
return nil, errors.New(request.Name, " not found.")
|
||||
return nil, status.Error(codes.NotFound, request.Name+" not found.")
|
||||
}
|
||||
|
||||
ips := make(map[string]int64)
|
||||
|
|
|
@ -67,9 +67,9 @@ func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
|
|||
t.checkTask.Close()
|
||||
}
|
||||
t.checkTask = checkTask
|
||||
t.Unlock()
|
||||
t.Update()
|
||||
common.Must(checkTask.Start())
|
||||
t.Unlock()
|
||||
}
|
||||
|
||||
func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
|
||||
|
|
21
go.mod
21
go.mod
|
@ -9,10 +9,10 @@ require (
|
|||
github.com/golang/mock v1.7.0-rc.1
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/miekg/dns v1.1.66
|
||||
github.com/miekg/dns v1.1.67
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/pires/go-proxyproto v0.8.1
|
||||
github.com/quic-go/quic-go v0.52.0
|
||||
github.com/quic-go/quic-go v0.54.0
|
||||
github.com/refraction-networking/utls v1.7.3
|
||||
github.com/sagernet/sing v0.5.1
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||
|
@ -20,12 +20,12 @@ require (
|
|||
github.com/stretchr/testify v1.10.0
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
github.com/xtls/reality v0.0.0-20250608132114-50752aec6bfb
|
||||
github.com/xtls/reality v0.0.0-20250715055725-05a351a64521
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||
golang.org/x/crypto v0.39.0
|
||||
golang.org/x/net v0.41.0
|
||||
golang.org/x/sync v0.15.0
|
||||
golang.org/x/sys v0.33.0
|
||||
golang.org/x/crypto v0.40.0
|
||||
golang.org/x/net v0.42.0
|
||||
golang.org/x/sync v0.16.0
|
||||
golang.org/x/sys v0.34.0
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||
google.golang.org/grpc v1.73.0
|
||||
google.golang.org/protobuf v1.36.6
|
||||
|
@ -38,22 +38,19 @@ require (
|
|||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect
|
||||
github.com/juju/ratelimit v1.0.2 // indirect
|
||||
github.com/klauspost/compress v1.17.8 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
golang.org/x/tools v0.34.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
|
44
go.sum
44
go.sum
|
@ -16,8 +16,6 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
|||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=
|
||||
github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
|
@ -26,8 +24,6 @@ github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
|||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
|
@ -40,12 +36,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/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
|
||||
github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
|
||||
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
|
||||
github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0=
|
||||
github.com/miekg/dns v1.1.67/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
|
||||
|
@ -56,8 +48,8 @@ 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/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA=
|
||||
github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
|
||||
github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
|
||||
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
|
||||
github.com/refraction-networking/utls v1.7.3 h1:L0WRhHY7Oq1T0zkdzVZMR6zWZv+sXbHB9zcuvsAEqCo=
|
||||
github.com/refraction-networking/utls v1.7.3/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||
|
@ -78,8 +70,8 @@ github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW
|
|||
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
|
||||
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/xtls/reality v0.0.0-20250608132114-50752aec6bfb h1:X6ziJCMsFF8Ac/0F3W7+UbFdHZTu+r5nZ/smksHVxNQ=
|
||||
github.com/xtls/reality v0.0.0-20250608132114-50752aec6bfb/go.mod h1:yD47RN65bDLZgyHWMfFDiqlzrq4usDMt/Xzsk6tMbhw=
|
||||
github.com/xtls/reality v0.0.0-20250715055725-05a351a64521 h1:hQQSzX6Y40nY1XT1TKAEpKwUHUUy3UvYKQIclLjYx9U=
|
||||
github.com/xtls/reality v0.0.0-20250715055725-05a351a64521/go.mod h1:yD47RN65bDLZgyHWMfFDiqlzrq4usDMt/Xzsk6tMbhw=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
|
@ -99,20 +91,20 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs
|
|||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
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.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -121,21 +113,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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
@ -30,7 +30,7 @@ func (c *DNSOutboundConfig) Build() (proto.Message, error) {
|
|||
switch c.NonIPQuery {
|
||||
case "":
|
||||
c.NonIPQuery = "drop"
|
||||
case "drop", "skip":
|
||||
case "drop", "skip", "reject":
|
||||
default:
|
||||
return nil, errors.New(`unknown "nonIPQuery": `, c.NonIPQuery)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package conf
|
|||
|
||||
import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/app/observatory/burst"
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
|
@ -51,15 +52,23 @@ type healthCheckSettings struct {
|
|||
Interval duration.Duration `json:"interval"`
|
||||
SamplingCount int `json:"sampling"`
|
||||
Timeout duration.Duration `json:"timeout"`
|
||||
HttpMethod string `json:"httpMethod"`
|
||||
}
|
||||
|
||||
func (h healthCheckSettings) Build() (proto.Message, error) {
|
||||
var httpMethod string
|
||||
if h.HttpMethod == "" {
|
||||
httpMethod = "HEAD"
|
||||
} else {
|
||||
httpMethod = strings.TrimSpace(h.HttpMethod)
|
||||
}
|
||||
return &burst.HealthPingConfig{
|
||||
Destination: h.Destination,
|
||||
Connectivity: h.Connectivity,
|
||||
Interval: int64(h.Interval),
|
||||
Timeout: int64(h.Timeout),
|
||||
SamplingCount: int32(h.SamplingCount),
|
||||
HttpMethod: httpMethod,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -544,7 +544,7 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
|
|||
}
|
||||
default:
|
||||
if _, err = strconv.Atoi(s); err == nil {
|
||||
s = "127.0.0.1:" + s
|
||||
s = "localhost:" + s
|
||||
}
|
||||
if _, _, err = net.SplitHostPort(s); err == nil {
|
||||
c.Type = "tcp"
|
||||
|
|
|
@ -155,7 +155,7 @@ func (c *TrojanServerConfig) Build() (proto.Message, error) {
|
|||
}
|
||||
} else {
|
||||
if _, err := strconv.Atoi(fb.Dest); err == nil {
|
||||
fb.Dest = "127.0.0.1:" + fb.Dest
|
||||
fb.Dest = "localhost:" + fb.Dest
|
||||
}
|
||||
if _, _, err := net.SplitHostPort(fb.Dest); err == nil {
|
||||
fb.Type = "tcp"
|
||||
|
|
|
@ -111,7 +111,7 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
|||
}
|
||||
} else {
|
||||
if _, err := strconv.Atoi(fb.Dest); err == nil {
|
||||
fb.Dest = "127.0.0.1:" + fb.Dest
|
||||
fb.Dest = "localhost:" + fb.Dest
|
||||
}
|
||||
if _, _, err := net.SplitHostPort(fb.Dest); err == nil {
|
||||
fb.Type = "tcp"
|
||||
|
|
|
@ -110,7 +110,7 @@ func TestVLessInbound(t *testing.T) {
|
|||
Alpn: "",
|
||||
Path: "",
|
||||
Type: "tcp",
|
||||
Dest: "127.0.0.1:80",
|
||||
Dest: "localhost:80",
|
||||
Xver: 0,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
var cmdListInbounds = &base.Command{
|
||||
CustomFlags: true,
|
||||
UsageLine: "{{.Exec}} api lsi [--server=127.0.0.1:8080]",
|
||||
UsageLine: "{{.Exec}} api lsi [--server=127.0.0.1:8080] [--isOnlyTags=true]",
|
||||
Short: "List inbounds",
|
||||
Long: `
|
||||
List inbounds in Xray.
|
||||
|
@ -29,14 +29,17 @@ Example:
|
|||
|
||||
func executeListInbounds(cmd *base.Command, args []string) {
|
||||
setSharedFlags(cmd)
|
||||
var isOnlyTagsStr string
|
||||
cmd.Flag.StringVar(&isOnlyTagsStr, "isOnlyTags", "", "")
|
||||
cmd.Flag.Parse(args)
|
||||
isOnlyTags := isOnlyTagsStr == "true"
|
||||
|
||||
conn, ctx, close := dialAPIServer()
|
||||
defer close()
|
||||
|
||||
client := handlerService.NewHandlerServiceClient(conn)
|
||||
|
||||
resp, err := client.ListInbounds(ctx, &handlerService.ListInboundsRequest{})
|
||||
resp, err := client.ListInbounds(ctx, &handlerService.ListInboundsRequest{IsOnlyTags: isOnlyTags})
|
||||
if err != nil {
|
||||
base.Fatalf("failed to list inbounds: %s", err)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@ import (
|
|||
"encoding/base64"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
|
||||
"github.com/xtls/xray-core/main/commands/base"
|
||||
. "github.com/xtls/xray-core/transport/internet/tls"
|
||||
|
@ -36,8 +39,13 @@ func executePing(cmd *base.Command, args []string) {
|
|||
base.Fatalf("domain not specified")
|
||||
}
|
||||
|
||||
domain := cmdPing.Flag.Arg(0)
|
||||
fmt.Println("Tls ping: ", domain)
|
||||
domainWithPort := cmdPing.Flag.Arg(0)
|
||||
fmt.Println("Tls ping: ", domainWithPort)
|
||||
TargetPort := 443
|
||||
domain, port, err := net.SplitHostPort(domainWithPort)
|
||||
if err == nil {
|
||||
TargetPort, _ = strconv.Atoi(port)
|
||||
}
|
||||
|
||||
var ip net.IP
|
||||
if len(*pingIPStr) > 0 {
|
||||
|
@ -58,14 +66,14 @@ func executePing(cmd *base.Command, args []string) {
|
|||
fmt.Println("-------------------")
|
||||
fmt.Println("Pinging without SNI")
|
||||
{
|
||||
tcpConn, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: ip, Port: 443})
|
||||
tcpConn, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: ip, Port: TargetPort})
|
||||
if err != nil {
|
||||
base.Fatalf("Failed to dial tcp: %s", err)
|
||||
}
|
||||
tlsConn := gotls.Client(tcpConn, &gotls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
NextProtos: []string{"http/1.1"},
|
||||
MaxVersion: gotls.VersionTLS12,
|
||||
MaxVersion: gotls.VersionTLS13,
|
||||
MinVersion: gotls.VersionTLS12,
|
||||
// Do not release tool before v5's refactor
|
||||
// VerifyPeerCertificate: showCert(),
|
||||
|
@ -75,6 +83,7 @@ func executePing(cmd *base.Command, args []string) {
|
|||
fmt.Println("Handshake failure: ", err)
|
||||
} else {
|
||||
fmt.Println("Handshake succeeded")
|
||||
printTLSConnDetail(tlsConn)
|
||||
printCertificates(tlsConn.ConnectionState().PeerCertificates)
|
||||
}
|
||||
tlsConn.Close()
|
||||
|
@ -90,7 +99,7 @@ func executePing(cmd *base.Command, args []string) {
|
|||
tlsConn := gotls.Client(tcpConn, &gotls.Config{
|
||||
ServerName: domain,
|
||||
NextProtos: []string{"http/1.1"},
|
||||
MaxVersion: gotls.VersionTLS12,
|
||||
MaxVersion: gotls.VersionTLS13,
|
||||
MinVersion: gotls.VersionTLS12,
|
||||
// Do not release tool before v5's refactor
|
||||
// VerifyPeerCertificate: showCert(),
|
||||
|
@ -100,6 +109,7 @@ func executePing(cmd *base.Command, args []string) {
|
|||
fmt.Println("handshake failure: ", err)
|
||||
} else {
|
||||
fmt.Println("handshake succeeded")
|
||||
printTLSConnDetail(tlsConn)
|
||||
printCertificates(tlsConn.ConnectionState().PeerCertificates)
|
||||
}
|
||||
tlsConn.Close()
|
||||
|
@ -117,6 +127,23 @@ func printCertificates(certs []*x509.Certificate) {
|
|||
}
|
||||
}
|
||||
|
||||
func printTLSConnDetail(tlsConn *gotls.Conn) {
|
||||
var tlsVersion string
|
||||
if tlsConn.ConnectionState().Version == gotls.VersionTLS13 {
|
||||
tlsVersion = "TLS 1.3"
|
||||
} else if tlsConn.ConnectionState().Version == gotls.VersionTLS12 {
|
||||
tlsVersion = "TLS 1.2"
|
||||
}
|
||||
fmt.Println("TLS Version:", tlsVersion)
|
||||
curveID := *(*gotls.CurveID)(unsafe.Pointer(reflect.ValueOf(tlsConn).Elem().FieldByName("curveID").UnsafeAddr()))
|
||||
if curveID != 0 {
|
||||
PostQuantum := (curveID == gotls.X25519MLKEM768)
|
||||
fmt.Println("Post-Quantum key exchange:", PostQuantum, "("+curveID.String()+")")
|
||||
} else {
|
||||
fmt.Println("Post-Quantum key exchange: false (RSA Exchange)")
|
||||
}
|
||||
}
|
||||
|
||||
func showCert() func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
hash := GenerateCertChainHash(rawCerts)
|
||||
|
|
|
@ -187,6 +187,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.
|
|||
if len(h.blockTypes) > 0 {
|
||||
for _, blocktype := range h.blockTypes {
|
||||
if blocktype == int32(qType) {
|
||||
if h.nonIPQuery == "reject" {
|
||||
go h.rejectNonIPQuery(id, qType, domain, writer)
|
||||
}
|
||||
errors.LogInfo(ctx, "blocked type ", qType, " query for domain ", domain)
|
||||
return nil
|
||||
}
|
||||
|
@ -199,6 +202,11 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.
|
|||
b.Release()
|
||||
continue
|
||||
}
|
||||
if h.nonIPQuery == "reject" {
|
||||
go h.rejectNonIPQuery(id, qType, domain, writer)
|
||||
b.Release()
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err := connWriter.WriteMessage(b); err != nil {
|
||||
|
@ -317,6 +325,43 @@ func (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string,
|
|||
}
|
||||
}
|
||||
|
||||
func (h *Handler) rejectNonIPQuery(id uint16, qType dnsmessage.Type, domain string, writer dns_proto.MessageWriter) {
|
||||
b := buf.New()
|
||||
rawBytes := b.Extend(buf.Size)
|
||||
builder := dnsmessage.NewBuilder(rawBytes[:0], dnsmessage.Header{
|
||||
ID: id,
|
||||
RCode: dnsmessage.RCodeRefused,
|
||||
RecursionAvailable: true,
|
||||
RecursionDesired: true,
|
||||
Response: true,
|
||||
Authoritative: true,
|
||||
})
|
||||
builder.EnableCompression()
|
||||
common.Must(builder.StartQuestions())
|
||||
err := builder.Question(dnsmessage.Question{
|
||||
Name: dnsmessage.MustNewName(domain),
|
||||
Class: dnsmessage.ClassINET,
|
||||
Type: qType,
|
||||
})
|
||||
if err != nil {
|
||||
errors.LogInfo(context.Background(), "unexpected domain ", domain, " when building reject message: ", err)
|
||||
b.Release()
|
||||
return
|
||||
}
|
||||
|
||||
msgBytes, err := builder.Finish()
|
||||
if err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "pack reject message")
|
||||
b.Release()
|
||||
return
|
||||
}
|
||||
b.Resize(0, int32(len(msgBytes)))
|
||||
|
||||
if err := writer.WriteMessage(b); err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "write reject answer")
|
||||
}
|
||||
}
|
||||
|
||||
type outboundConn struct {
|
||||
access sync.Mutex
|
||||
dialer func() (stat.Connection, error)
|
||||
|
|
|
@ -53,6 +53,7 @@ func (v *Validator) Get(hash string) *protocol.MemoryUser {
|
|||
|
||||
// Get a trojan user with hashed key, nil if user doesn't exist.
|
||||
func (v *Validator) GetByEmail(email string) *protocol.MemoryUser {
|
||||
email = strings.ToLower(email)
|
||||
u, _ := v.email.Load(email)
|
||||
if u != nil {
|
||||
return u.(*protocol.MemoryUser)
|
||||
|
|
|
@ -63,6 +63,7 @@ func (v *MemoryValidator) Get(id uuid.UUID) *protocol.MemoryUser {
|
|||
|
||||
// Get a VLESS user with email, nil if user doesn't exist.
|
||||
func (v *MemoryValidator) GetByEmail(email string) *protocol.MemoryUser {
|
||||
email = strings.ToLower(email)
|
||||
u, _ := v.email.Load(email)
|
||||
if u != nil {
|
||||
return u.(*protocol.MemoryUser)
|
||||
|
|
|
@ -161,7 +161,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
|
|||
transport = &http3.Transport{
|
||||
QUICConfig: quicConfig,
|
||||
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.Conn, error) {
|
||||
conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -486,11 +486,11 @@ func ConfigFromStreamSettings(settings *internet.MemoryStreamConfig) *Config {
|
|||
|
||||
func ParseCurveName(curveNames []string) []tls.CurveID {
|
||||
curveMap := map[string]tls.CurveID{
|
||||
"curvep256": tls.CurveP256,
|
||||
"curvep384": tls.CurveP384,
|
||||
"curvep521": tls.CurveP521,
|
||||
"x25519": tls.X25519,
|
||||
"x25519kyber768draft00": 0x6399,
|
||||
"curvep256": tls.CurveP256,
|
||||
"curvep384": tls.CurveP384,
|
||||
"curvep521": tls.CurveP521,
|
||||
"x25519": tls.X25519,
|
||||
"x25519mlkem768": tls.X25519MLKEM768,
|
||||
}
|
||||
|
||||
var curveIDs []tls.CurveID
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue