Compare commits

...
30 Commits
Author SHA1 Message Date
yuhan6665 7f48a2a3d0 Add back pipe for reverse proxy portal 2025-09-21 20:07:38 -04:00
yuhan6665 b285ccc180 Add back pipe for Mux
For Mux, we need to use pipe to guard against multiple sub-connections writing back responses at the same time
2025-09-21 10:52:05 -04:00
yuhan6665 97f977003d Add Vless Mux and Enc tests 2025-09-21 10:52:05 -04:00
yuhan6665 1b8eba1338 Inbound remove NoTerminationSignal 2025-09-20 18:31:11 -04:00
yuhan6665 b14d5407e5 Refactor code to use DispatchLink() in vmess inbound
- Always apply NoTerminationSignal
2025-09-20 18:31:11 -04:00
𐲓𐳛𐳪𐳂𐳐 𐲀𐳢𐳦𐳫𐳢 𐲥𐳔𐳛𐳪𐳌𐳑𐳖𐳇andGitHub fe57507fd9 Outbound: One endpoint and at most one user only (#5144)
https://github.com/XTLS/Xray-core/pull/5124#issuecomment-3281091009

Fixes https://github.com/XTLS/Xray-core/pull/5124#pullrequestreview-3218097421
2025-09-15 13:31:27 +00:00
𐲓𐳛𐳪𐳂𐳐 𐲀𐳢𐳦𐳫𐳢 𐲥𐳔𐳛𐳪𐳌𐳑𐳖𐳇andGitHub 83c5370eec Config: Outbound proxy config no need to be nested (#5124)
Like https://github.com/XTLS/Xray-core/commit/eda8be601f56c788b1ad176c7d68d8e2ce22c7ca
2025-09-11 13:48:20 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1a48453bea Bump google.golang.org/grpc from 1.75.0 to 1.75.1 (#5129)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.75.0 to 1.75.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.75.0...v1.75.1)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-version: 1.75.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-11 13:08:21 +00:00
patternihaandGitHub 3167e5cec0 app/dispatcher/default.go: Close link when routedDispatch() failed (#5131) 2025-09-11 12:36:22 +00:00
RPRX 5148c5786f app/dispatcher/default.go: Add comment on run-time rejecting non-existent outbound tag
https://github.com/XTLS/Xray-core/pull/5101#issuecomment-3270341615
2025-09-10 17:30:13 +00:00
RPRXandGitHub 3edfb0e335 v25.9.11
Announcement of NFTs by Project X: https://github.com/XTLS/Xray-core/discussions/3633
Project X NFT: https://opensea.io/assets/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1

VLESS Post-Quantum Encryption: https://github.com/XTLS/Xray-core/pull/5067
VLESS NFT: https://opensea.io/collection/vless

XHTTP: Beyond REALITY: https://github.com/XTLS/Xray-core/discussions/4113
REALITY NFT: https://opensea.io/assets/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/2
2025-09-10 11:47:07 +00:00
patternihaandGitHub d3248a4f8e app/reverse/bridge.go: Add timer nil check (#5119)
Fixes https://github.com/XTLS/Xray-core/issues/5120
2025-09-10 11:43:21 +00:00
风扇滑翔翼andGitHub 30e10be95d Fix https://github.com/XTLS/Xray-core/pull/5114#issuecomment-3273017153 (#5118) 2025-09-10 11:41:44 +00:00
RPRXandGitHub cced1477a0 v25.9.10
Announcement of NFTs by Project X: https://github.com/XTLS/Xray-core/discussions/3633
Project X NFT: https://opensea.io/assets/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/1

VLESS Post-Quantum Encryption: https://github.com/XTLS/Xray-core/pull/5067
VLESS NFT: https://opensea.io/collection/vless

XHTTP: Beyond REALITY: https://github.com/XTLS/Xray-core/discussions/4113
REALITY NFT: https://opensea.io/assets/ethereum/0x5ee362866001613093361eb8569d59c4141b76d1/2
2025-09-10 00:36:44 +00:00
patternihaandGitHub 9f5dcb1591 MUX: Prevent goroutine leak (#5110) 2025-09-10 00:33:19 +00:00
风扇滑翔翼andGitHub ce5c51d3ba TPROXY: Prevent TCP loopback (#5114)
Fixes https://t.me/projectXray/4434526
2025-09-10 00:25:52 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
11f670c8a6 Bump google.golang.org/protobuf from 1.36.8 to 1.36.9 (#5115)
Bumps google.golang.org/protobuf from 1.36.8 to 1.36.9.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-version: 1.36.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-10 00:20:10 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
a387ae9590 Bump golang.org/x/net from 0.43.0 to 0.44.0 (#5116)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.43.0 to 0.44.0.
- [Commits](https://github.com/golang/net/compare/v0.43.0...v0.44.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.44.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-10 00:19:52 +00:00
RPRXandGitHub 4ae497106d Update github.com/xtls/reality to 20250904214705
https://github.com/XTLS/REALITY/commit/431b6ff8c67cc18811d48b18df9ec28e1ecf57f7
2025-09-10 00:16:58 +00:00
心隨緣動andGitHub 1f4fc2e7bb README.md: Add X-Panel to Web Panels (#5094) 2025-09-09 14:25:36 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ae44b86b0d Bump actions/setup-go from 5 to 6 (#5087)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5 to 6.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-09 14:22:36 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8276a443bc Bump actions/github-script from 7 to 8 (#5086)
Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 8.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-09 14:22:25 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1e2f251bb3 Bump golang.org/x/crypto from 0.41.0 to 0.42.0 (#5113)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.41.0 to 0.42.0.
- [Commits](https://github.com/golang/crypto/compare/v0.41.0...v0.42.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.42.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-09 14:21:25 +00:00
RPRXandGitHub 845010b535 VLESS protocol: Add Reverse Proxy (4) Command and extremely simple config (#5101)
https://github.com/XTLS/Xray-core/issues/5088#issuecomment-3263093341
2025-09-09 14:19:12 +00:00
风扇滑翔翼andGitHub a0c63ba1cf VMess: Returns clearer error in AuthIDDecoderHolder (#5090) 2025-09-08 14:19:17 +00:00
风扇滑翔翼andGitHub 2b82366148 mKCP: Fix key derivation for obfuscation (#5106)
Fixes https://github.com/XTLS/Xray-core/issues/5096
2025-09-08 13:59:28 +00:00
AndyChiang888andGitHub ab1fa13ebe Commands: Fix "with SNI" printing fixed port 443 for tls ping (#5099) 2025-09-07 14:12:21 +00:00
patternihaandGitHub 4740ba2425 app/reverse/portal.go: Fix goroutine leak & Add EndpointOverride (#5100)
https://github.com/XTLS/Xray-core/issues/5088#issuecomment-3263558403
2025-09-07 10:38:21 +00:00
RPRXandGitHub 4b0ee28f1c app/reverse/portal.go: Fix HandleConnection() returns immediately (from DispatchLink() with configured domain)
Fixes https://github.com/XTLS/Xray-core/issues/5088
2025-09-07 02:15:52 +00:00
RPRXandGitHub 6ec0291d4e app/reverse/bridge.go: Fix DispatchLink() returns immediately
Fixes https://github.com/XTLS/Xray-core/issues/5088
2025-09-05 15:58:49 +00:00
88 changed files with 1917 additions and 2591 deletions
+1 -1
View File
@@ -72,7 +72,7 @@ jobs:
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v6
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
+2 -2
View File
@@ -37,7 +37,7 @@ jobs:
- name: Trigger Asset Update Workflow if Assets Missing - name: Trigger Asset Update Workflow if Assets Missing
if: steps.check-assets.outputs.missing == 'true' if: steps.check-assets.outputs.missing == 'true'
uses: actions/github-script@v7 uses: actions/github-script@v8
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
script: | script: |
@@ -176,7 +176,7 @@ jobs:
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v6
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
+1 -1
View File
@@ -47,7 +47,7 @@ jobs:
- name: Checkout codebase - name: Checkout codebase
uses: actions/checkout@v5 uses: actions/checkout@v5
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v6
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
+1
View File
@@ -44,6 +44,7 @@
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray) - [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
- [wulabing/xray_docker](https://github.com/wulabing/xray_docker) - [wulabing/xray_docker](https://github.com/wulabing/xray_docker)
- Web Panel - **WARNING: Please DO NOT USE plain HTTP panels like 3X-UI**, as they are believed to be bribed by Iran GFW for supporting plain HTTP by default and refused to change (https://github.com/XTLS/Xray-core/pull/3884#issuecomment-2439595331), which has already put many users' data security in danger in the past few years. **If you are already using 3X-UI, please switch to the following panels, which are verified to support HTTPS and SSH port forwarding only:** - Web Panel - **WARNING: Please DO NOT USE plain HTTP panels like 3X-UI**, as they are believed to be bribed by Iran GFW for supporting plain HTTP by default and refused to change (https://github.com/XTLS/Xray-core/pull/3884#issuecomment-2439595331), which has already put many users' data security in danger in the past few years. **If you are already using 3X-UI, please switch to the following panels, which are verified to support HTTPS and SSH port forwarding only:**
- [X-Panel](https://github.com/xeefei/X-Panel)
- [Remnawave](https://github.com/remnawave/panel) - [Remnawave](https://github.com/remnawave/panel)
- [Marzban](https://github.com/Gozargah/Marzban) - [Marzban](https://github.com/Gozargah/Marzban)
- [Xray-UI](https://github.com/qist/xray-ui) - [Xray-UI](https://github.com/qist/xray-ui)
+3
View File
@@ -483,6 +483,9 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
handler = h handler = h
} else { } else {
errors.LogWarning(ctx, "non existing outTag: ", outTag) errors.LogWarning(ctx, "non existing outTag: ", outTag)
common.Close(link.Writer)
common.Interrupt(link.Reader)
return // DO NOT CHANGE: the traffic shouldn't be processed by default outbound if the specified outbound tag doesn't exist (yet), e.g., VLESS Reverse Proxy
} }
} else { } else {
errors.LogInfo(ctx, "default route for ", destination) errors.LogInfo(ctx, "default route for ", destination)
-22
View File
@@ -1,23 +1 @@
package proxyman package proxyman
func (s *AllocationStrategy) GetConcurrencyValue() uint32 {
if s == nil || s.Concurrency == nil {
return 3
}
return s.Concurrency.Value
}
func (s *AllocationStrategy) GetRefreshValue() uint32 {
if s == nil || s.Refresh == nil {
return 5
}
return s.Refresh.Value
}
func (c *ReceiverConfig) GetEffectiveSniffingSettings() *SniffingConfig {
if c.SniffingSettings != nil {
return c.SniffingSettings
}
return nil
}
+143 -400
View File
@@ -23,58 +23,6 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
) )
type AllocationStrategy_Type int32
const (
// Always allocate all connection handlers.
AllocationStrategy_Always AllocationStrategy_Type = 0
// Randomly allocate specific range of handlers.
AllocationStrategy_Random AllocationStrategy_Type = 1
// External. Not supported yet.
AllocationStrategy_External AllocationStrategy_Type = 2
)
// Enum value maps for AllocationStrategy_Type.
var (
AllocationStrategy_Type_name = map[int32]string{
0: "Always",
1: "Random",
2: "External",
}
AllocationStrategy_Type_value = map[string]int32{
"Always": 0,
"Random": 1,
"External": 2,
}
)
func (x AllocationStrategy_Type) Enum() *AllocationStrategy_Type {
p := new(AllocationStrategy_Type)
*p = x
return p
}
func (x AllocationStrategy_Type) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (AllocationStrategy_Type) Descriptor() protoreflect.EnumDescriptor {
return file_app_proxyman_config_proto_enumTypes[0].Descriptor()
}
func (AllocationStrategy_Type) Type() protoreflect.EnumType {
return &file_app_proxyman_config_proto_enumTypes[0]
}
func (x AllocationStrategy_Type) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use AllocationStrategy_Type.Descriptor instead.
func (AllocationStrategy_Type) EnumDescriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 0}
}
type InboundConfig struct { type InboundConfig struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -111,71 +59,6 @@ func (*InboundConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{0} return file_app_proxyman_config_proto_rawDescGZIP(), []int{0}
} }
type AllocationStrategy struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type AllocationStrategy_Type `protobuf:"varint,1,opt,name=type,proto3,enum=xray.app.proxyman.AllocationStrategy_Type" json:"type,omitempty"`
// Number of handlers (ports) running in parallel.
// Default value is 3 if unset.
Concurrency *AllocationStrategy_AllocationStrategyConcurrency `protobuf:"bytes,2,opt,name=concurrency,proto3" json:"concurrency,omitempty"`
// Number of minutes before a handler is regenerated.
// Default value is 5 if unset.
Refresh *AllocationStrategy_AllocationStrategyRefresh `protobuf:"bytes,3,opt,name=refresh,proto3" json:"refresh,omitempty"`
}
func (x *AllocationStrategy) Reset() {
*x = AllocationStrategy{}
mi := &file_app_proxyman_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AllocationStrategy) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AllocationStrategy) ProtoMessage() {}
func (x *AllocationStrategy) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AllocationStrategy.ProtoReflect.Descriptor instead.
func (*AllocationStrategy) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1}
}
func (x *AllocationStrategy) GetType() AllocationStrategy_Type {
if x != nil {
return x.Type
}
return AllocationStrategy_Always
}
func (x *AllocationStrategy) GetConcurrency() *AllocationStrategy_AllocationStrategyConcurrency {
if x != nil {
return x.Concurrency
}
return nil
}
func (x *AllocationStrategy) GetRefresh() *AllocationStrategy_AllocationStrategyRefresh {
if x != nil {
return x.Refresh
}
return nil
}
type SniffingConfig struct { type SniffingConfig struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -196,7 +79,7 @@ type SniffingConfig struct {
func (x *SniffingConfig) Reset() { func (x *SniffingConfig) Reset() {
*x = SniffingConfig{} *x = SniffingConfig{}
mi := &file_app_proxyman_config_proto_msgTypes[2] mi := &file_app_proxyman_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -208,7 +91,7 @@ func (x *SniffingConfig) String() string {
func (*SniffingConfig) ProtoMessage() {} func (*SniffingConfig) ProtoMessage() {}
func (x *SniffingConfig) ProtoReflect() protoreflect.Message { func (x *SniffingConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[2] mi := &file_app_proxyman_config_proto_msgTypes[1]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -221,7 +104,7 @@ func (x *SniffingConfig) ProtoReflect() protoreflect.Message {
// Deprecated: Use SniffingConfig.ProtoReflect.Descriptor instead. // Deprecated: Use SniffingConfig.ProtoReflect.Descriptor instead.
func (*SniffingConfig) Descriptor() ([]byte, []int) { func (*SniffingConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{2} return file_app_proxyman_config_proto_rawDescGZIP(), []int{1}
} }
func (x *SniffingConfig) GetEnabled() bool { func (x *SniffingConfig) GetEnabled() bool {
@@ -268,15 +151,14 @@ type ReceiverConfig struct {
PortList *net.PortList `protobuf:"bytes,1,opt,name=port_list,json=portList,proto3" json:"port_list,omitempty"` PortList *net.PortList `protobuf:"bytes,1,opt,name=port_list,json=portList,proto3" json:"port_list,omitempty"`
// Listen specifies the IP address that the Receiver should listen on. // Listen specifies the IP address that the Receiver should listen on.
Listen *net.IPOrDomain `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"` Listen *net.IPOrDomain `protobuf:"bytes,2,opt,name=listen,proto3" json:"listen,omitempty"`
AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy,proto3" json:"allocation_strategy,omitempty"` StreamSettings *internet.StreamConfig `protobuf:"bytes,3,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
StreamSettings *internet.StreamConfig `protobuf:"bytes,4,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"` ReceiveOriginalDestination bool `protobuf:"varint,4,opt,name=receive_original_destination,json=receiveOriginalDestination,proto3" json:"receive_original_destination,omitempty"`
ReceiveOriginalDestination bool `protobuf:"varint,5,opt,name=receive_original_destination,json=receiveOriginalDestination,proto3" json:"receive_original_destination,omitempty"` SniffingSettings *SniffingConfig `protobuf:"bytes,6,opt,name=sniffing_settings,json=sniffingSettings,proto3" json:"sniffing_settings,omitempty"`
SniffingSettings *SniffingConfig `protobuf:"bytes,7,opt,name=sniffing_settings,json=sniffingSettings,proto3" json:"sniffing_settings,omitempty"`
} }
func (x *ReceiverConfig) Reset() { func (x *ReceiverConfig) Reset() {
*x = ReceiverConfig{} *x = ReceiverConfig{}
mi := &file_app_proxyman_config_proto_msgTypes[3] mi := &file_app_proxyman_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -288,7 +170,7 @@ func (x *ReceiverConfig) String() string {
func (*ReceiverConfig) ProtoMessage() {} func (*ReceiverConfig) ProtoMessage() {}
func (x *ReceiverConfig) ProtoReflect() protoreflect.Message { func (x *ReceiverConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[3] mi := &file_app_proxyman_config_proto_msgTypes[2]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -301,7 +183,7 @@ func (x *ReceiverConfig) ProtoReflect() protoreflect.Message {
// Deprecated: Use ReceiverConfig.ProtoReflect.Descriptor instead. // Deprecated: Use ReceiverConfig.ProtoReflect.Descriptor instead.
func (*ReceiverConfig) Descriptor() ([]byte, []int) { func (*ReceiverConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{3} return file_app_proxyman_config_proto_rawDescGZIP(), []int{2}
} }
func (x *ReceiverConfig) GetPortList() *net.PortList { func (x *ReceiverConfig) GetPortList() *net.PortList {
@@ -318,13 +200,6 @@ func (x *ReceiverConfig) GetListen() *net.IPOrDomain {
return nil return nil
} }
func (x *ReceiverConfig) GetAllocationStrategy() *AllocationStrategy {
if x != nil {
return x.AllocationStrategy
}
return nil
}
func (x *ReceiverConfig) GetStreamSettings() *internet.StreamConfig { func (x *ReceiverConfig) GetStreamSettings() *internet.StreamConfig {
if x != nil { if x != nil {
return x.StreamSettings return x.StreamSettings
@@ -358,7 +233,7 @@ type InboundHandlerConfig struct {
func (x *InboundHandlerConfig) Reset() { func (x *InboundHandlerConfig) Reset() {
*x = InboundHandlerConfig{} *x = InboundHandlerConfig{}
mi := &file_app_proxyman_config_proto_msgTypes[4] mi := &file_app_proxyman_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -370,7 +245,7 @@ func (x *InboundHandlerConfig) String() string {
func (*InboundHandlerConfig) ProtoMessage() {} func (*InboundHandlerConfig) ProtoMessage() {}
func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message { func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[4] mi := &file_app_proxyman_config_proto_msgTypes[3]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -383,7 +258,7 @@ func (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {
// Deprecated: Use InboundHandlerConfig.ProtoReflect.Descriptor instead. // Deprecated: Use InboundHandlerConfig.ProtoReflect.Descriptor instead.
func (*InboundHandlerConfig) Descriptor() ([]byte, []int) { func (*InboundHandlerConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{4} return file_app_proxyman_config_proto_rawDescGZIP(), []int{3}
} }
func (x *InboundHandlerConfig) GetTag() string { func (x *InboundHandlerConfig) GetTag() string {
@@ -415,7 +290,7 @@ type OutboundConfig struct {
func (x *OutboundConfig) Reset() { func (x *OutboundConfig) Reset() {
*x = OutboundConfig{} *x = OutboundConfig{}
mi := &file_app_proxyman_config_proto_msgTypes[5] mi := &file_app_proxyman_config_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -427,7 +302,7 @@ func (x *OutboundConfig) String() string {
func (*OutboundConfig) ProtoMessage() {} func (*OutboundConfig) ProtoMessage() {}
func (x *OutboundConfig) ProtoReflect() protoreflect.Message { func (x *OutboundConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[5] mi := &file_app_proxyman_config_proto_msgTypes[4]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -440,7 +315,7 @@ func (x *OutboundConfig) ProtoReflect() protoreflect.Message {
// Deprecated: Use OutboundConfig.ProtoReflect.Descriptor instead. // Deprecated: Use OutboundConfig.ProtoReflect.Descriptor instead.
func (*OutboundConfig) Descriptor() ([]byte, []int) { func (*OutboundConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{5} return file_app_proxyman_config_proto_rawDescGZIP(), []int{4}
} }
type SenderConfig struct { type SenderConfig struct {
@@ -459,7 +334,7 @@ type SenderConfig struct {
func (x *SenderConfig) Reset() { func (x *SenderConfig) Reset() {
*x = SenderConfig{} *x = SenderConfig{}
mi := &file_app_proxyman_config_proto_msgTypes[6] mi := &file_app_proxyman_config_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -471,7 +346,7 @@ func (x *SenderConfig) String() string {
func (*SenderConfig) ProtoMessage() {} func (*SenderConfig) ProtoMessage() {}
func (x *SenderConfig) ProtoReflect() protoreflect.Message { func (x *SenderConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[6] mi := &file_app_proxyman_config_proto_msgTypes[5]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -484,7 +359,7 @@ func (x *SenderConfig) ProtoReflect() protoreflect.Message {
// Deprecated: Use SenderConfig.ProtoReflect.Descriptor instead. // Deprecated: Use SenderConfig.ProtoReflect.Descriptor instead.
func (*SenderConfig) Descriptor() ([]byte, []int) { func (*SenderConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{6} return file_app_proxyman_config_proto_rawDescGZIP(), []int{5}
} }
func (x *SenderConfig) GetVia() *net.IPOrDomain { func (x *SenderConfig) GetVia() *net.IPOrDomain {
@@ -546,7 +421,7 @@ type MultiplexingConfig struct {
func (x *MultiplexingConfig) Reset() { func (x *MultiplexingConfig) Reset() {
*x = MultiplexingConfig{} *x = MultiplexingConfig{}
mi := &file_app_proxyman_config_proto_msgTypes[7] mi := &file_app_proxyman_config_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -558,7 +433,7 @@ func (x *MultiplexingConfig) String() string {
func (*MultiplexingConfig) ProtoMessage() {} func (*MultiplexingConfig) ProtoMessage() {}
func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message { func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[7] mi := &file_app_proxyman_config_proto_msgTypes[6]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -571,7 +446,7 @@ func (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {
// Deprecated: Use MultiplexingConfig.ProtoReflect.Descriptor instead. // Deprecated: Use MultiplexingConfig.ProtoReflect.Descriptor instead.
func (*MultiplexingConfig) Descriptor() ([]byte, []int) { func (*MultiplexingConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{7} return file_app_proxyman_config_proto_rawDescGZIP(), []int{6}
} }
func (x *MultiplexingConfig) GetEnabled() bool { func (x *MultiplexingConfig) GetEnabled() bool {
@@ -602,96 +477,6 @@ func (x *MultiplexingConfig) GetXudpProxyUDP443() string {
return "" return ""
} }
type AllocationStrategy_AllocationStrategyConcurrency struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *AllocationStrategy_AllocationStrategyConcurrency) Reset() {
*x = AllocationStrategy_AllocationStrategyConcurrency{}
mi := &file_app_proxyman_config_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AllocationStrategy_AllocationStrategyConcurrency) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AllocationStrategy_AllocationStrategyConcurrency) ProtoMessage() {}
func (x *AllocationStrategy_AllocationStrategyConcurrency) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AllocationStrategy_AllocationStrategyConcurrency.ProtoReflect.Descriptor instead.
func (*AllocationStrategy_AllocationStrategyConcurrency) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 0}
}
func (x *AllocationStrategy_AllocationStrategyConcurrency) GetValue() uint32 {
if x != nil {
return x.Value
}
return 0
}
type AllocationStrategy_AllocationStrategyRefresh struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *AllocationStrategy_AllocationStrategyRefresh) Reset() {
*x = AllocationStrategy_AllocationStrategyRefresh{}
mi := &file_app_proxyman_config_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AllocationStrategy_AllocationStrategyRefresh) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AllocationStrategy_AllocationStrategyRefresh) ProtoMessage() {}
func (x *AllocationStrategy_AllocationStrategyRefresh) ProtoReflect() protoreflect.Message {
mi := &file_app_proxyman_config_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AllocationStrategy_AllocationStrategyRefresh.ProtoReflect.Descriptor instead.
func (*AllocationStrategy_AllocationStrategyRefresh) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 1}
}
func (x *AllocationStrategy_AllocationStrategyRefresh) GetValue() uint32 {
if x != nil {
return x.Value
}
return 0
}
var File_app_proxyman_config_proto protoreflect.FileDescriptor var File_app_proxyman_config_proto protoreflect.FileDescriptor
var file_app_proxyman_config_proto_rawDesc = []byte{ var file_app_proxyman_config_proto_rawDesc = []byte{
@@ -706,130 +491,98 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,
0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0x0f, 0x0a, 0x0d, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6f, 0x74, 0x6f, 0x22, 0x0f, 0x0a, 0x0d, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x22, 0xae, 0x03, 0x0a, 0x12, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xcc, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e,
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x3e, 0x0a, 0x04, 0x74, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c,
0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x65, 0x0a, 0x0b, 0x63, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72,
0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x72, 0x69, 0x64, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x5f,
0x32, 0x43, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f,
0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x12,
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6f, 0x6e, 0x6c, 0x79,
0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f, 0x6e,
0x63, 0x79, 0x12, 0x59, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x18, 0x03, 0x20, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x4f,
0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6e, 0x6c, 0x79, 0x22, 0xe5, 0x02, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72,
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c,
0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x65, 0x66, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74,
0x72, 0x65, 0x73, 0x68, 0x52, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x1a, 0x35, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x33,
0x1d, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x14, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, 0x73,
0x61, 0x6c, 0x75, 0x65, 0x1a, 0x31, 0x0a, 0x19, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x74, 0x65, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65,
0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78,
0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e,
0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69,
0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f,
0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0xcc, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69,
0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e,
0x65, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e,
0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,
0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,
0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
0x5f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74,
0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x22, 0xc0, 0x01, 0x0a, 0x14,
0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6f, 0x6e, 0x6c, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f,
0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,
0x61, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76,
0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
0x4f, 0x6e, 0x6c, 0x79, 0x22, 0xbd, 0x03, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73,
0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x61, 0x67, 0x65, 0x52, 0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73,
0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e,
0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69,
0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10,
0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x22, 0x9d, 0x03, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x67, 0x12, 0x2d, 0x0a, 0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4e, 0x0a, 0x0f, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x12, 0x4b, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d,
0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a,
0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
0x6e, 0x67, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75,
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e,
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04,
0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a,
0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12,
0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74,
0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e,
0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x10, 0x72, 0x65,
0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47,
0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65,
0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x9d, 0x03, 0x0a, 0x0c, 0x53, 0x65,
0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x03, 0x76, 0x69,
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72,
0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72,
0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78,
0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65,
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70,
0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78,
0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69,
0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08,
0x76, 0x69, 0x61, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x76, 0x69, 0x61, 0x43, 0x69, 0x64, 0x72, 0x12, 0x50, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65,
0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e,
0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65,
0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, 0xa4, 0x01, 0x0a, 0x12, 0x4d, 0x75,
0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69,
0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x69, 0x61, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18,
0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x69, 0x61, 0x43, 0x69, 0x64, 0x72, 0x12, 0x50,
0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74,
0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x74, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
0x22, 0xa4, 0x01, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e,
0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c,
0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79,
0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65,
0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75,
0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x78, 0x75,
0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a,
0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33,
0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e,
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61,
0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@@ -844,48 +597,39 @@ func file_app_proxyman_config_proto_rawDescGZIP() []byte {
return file_app_proxyman_config_proto_rawDescData return file_app_proxyman_config_proto_rawDescData
} }
var file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_app_proxyman_config_proto_goTypes = []any{ var file_app_proxyman_config_proto_goTypes = []any{
(AllocationStrategy_Type)(0), // 0: xray.app.proxyman.AllocationStrategy.Type (*InboundConfig)(nil), // 0: xray.app.proxyman.InboundConfig
(*InboundConfig)(nil), // 1: xray.app.proxyman.InboundConfig (*SniffingConfig)(nil), // 1: xray.app.proxyman.SniffingConfig
(*AllocationStrategy)(nil), // 2: xray.app.proxyman.AllocationStrategy (*ReceiverConfig)(nil), // 2: xray.app.proxyman.ReceiverConfig
(*SniffingConfig)(nil), // 3: xray.app.proxyman.SniffingConfig (*InboundHandlerConfig)(nil), // 3: xray.app.proxyman.InboundHandlerConfig
(*ReceiverConfig)(nil), // 4: xray.app.proxyman.ReceiverConfig (*OutboundConfig)(nil), // 4: xray.app.proxyman.OutboundConfig
(*InboundHandlerConfig)(nil), // 5: xray.app.proxyman.InboundHandlerConfig (*SenderConfig)(nil), // 5: xray.app.proxyman.SenderConfig
(*OutboundConfig)(nil), // 6: xray.app.proxyman.OutboundConfig (*MultiplexingConfig)(nil), // 6: xray.app.proxyman.MultiplexingConfig
(*SenderConfig)(nil), // 7: xray.app.proxyman.SenderConfig (*net.PortList)(nil), // 7: xray.common.net.PortList
(*MultiplexingConfig)(nil), // 8: xray.app.proxyman.MultiplexingConfig (*net.IPOrDomain)(nil), // 8: xray.common.net.IPOrDomain
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 9: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency (*internet.StreamConfig)(nil), // 9: xray.transport.internet.StreamConfig
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh (*serial.TypedMessage)(nil), // 10: xray.common.serial.TypedMessage
(*net.PortList)(nil), // 11: xray.common.net.PortList (*internet.ProxyConfig)(nil), // 11: xray.transport.internet.ProxyConfig
(*net.IPOrDomain)(nil), // 12: xray.common.net.IPOrDomain (internet.DomainStrategy)(0), // 12: xray.transport.internet.DomainStrategy
(*internet.StreamConfig)(nil), // 13: xray.transport.internet.StreamConfig
(*serial.TypedMessage)(nil), // 14: xray.common.serial.TypedMessage
(*internet.ProxyConfig)(nil), // 15: xray.transport.internet.ProxyConfig
(internet.DomainStrategy)(0), // 16: xray.transport.internet.DomainStrategy
} }
var file_app_proxyman_config_proto_depIdxs = []int32{ var file_app_proxyman_config_proto_depIdxs = []int32{
0, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type 7, // 0: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList
9, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency 8, // 1: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
10, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh 9, // 2: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
11, // 3: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList 1, // 3: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
12, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain 10, // 4: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
2, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy 10, // 5: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
13, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig 8, // 6: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
3, // 7: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig 9, // 7: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
14, // 8: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage 11, // 8: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
14, // 9: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage 6, // 9: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
12, // 10: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain 12, // 10: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy
13, // 11: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig 11, // [11:11] is the sub-list for method output_type
15, // 12: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig 11, // [11:11] is the sub-list for method input_type
8, // 13: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig 11, // [11:11] is the sub-list for extension type_name
16, // 14: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy 11, // [11:11] is the sub-list for extension extendee
15, // [15:15] is the sub-list for method output_type 0, // [0:11] is the sub-list for field type_name
15, // [15:15] is the sub-list for method input_type
15, // [15:15] is the sub-list for extension type_name
15, // [15:15] is the sub-list for extension extendee
0, // [0:15] is the sub-list for field type_name
} }
func init() { file_app_proxyman_config_proto_init() } func init() { file_app_proxyman_config_proto_init() }
@@ -898,14 +642,13 @@ func file_app_proxyman_config_proto_init() {
File: protoimpl.DescBuilder{ File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_proxyman_config_proto_rawDesc, RawDescriptor: file_app_proxyman_config_proto_rawDesc,
NumEnums: 1, NumEnums: 0,
NumMessages: 10, NumMessages: 7,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },
GoTypes: file_app_proxyman_config_proto_goTypes, GoTypes: file_app_proxyman_config_proto_goTypes,
DependencyIndexes: file_app_proxyman_config_proto_depIdxs, DependencyIndexes: file_app_proxyman_config_proto_depIdxs,
EnumInfos: file_app_proxyman_config_proto_enumTypes,
MessageInfos: file_app_proxyman_config_proto_msgTypes, MessageInfos: file_app_proxyman_config_proto_msgTypes,
}.Build() }.Build()
File_app_proxyman_config_proto = out.File File_app_proxyman_config_proto = out.File
+4 -32
View File
@@ -13,33 +13,6 @@ import "common/serial/typed_message.proto";
message InboundConfig {} message InboundConfig {}
message AllocationStrategy {
enum Type {
// Always allocate all connection handlers.
Always = 0;
// Randomly allocate specific range of handlers.
Random = 1;
// External. Not supported yet.
External = 2;
}
Type type = 1;
message AllocationStrategyConcurrency { uint32 value = 1; }
// Number of handlers (ports) running in parallel.
// Default value is 3 if unset.
AllocationStrategyConcurrency concurrency = 2;
message AllocationStrategyRefresh { uint32 value = 1; }
// Number of minutes before a handler is regenerated.
// Default value is 5 if unset.
AllocationStrategyRefresh refresh = 3;
}
message SniffingConfig { message SniffingConfig {
// Whether or not to enable content sniffing on an inbound connection. // Whether or not to enable content sniffing on an inbound connection.
bool enabled = 1; bool enabled = 1;
@@ -62,11 +35,10 @@ message ReceiverConfig {
xray.common.net.PortList port_list = 1; xray.common.net.PortList port_list = 1;
// Listen specifies the IP address that the Receiver should listen on. // Listen specifies the IP address that the Receiver should listen on.
xray.common.net.IPOrDomain listen = 2; xray.common.net.IPOrDomain listen = 2;
AllocationStrategy allocation_strategy = 3; xray.transport.internet.StreamConfig stream_settings = 3;
xray.transport.internet.StreamConfig stream_settings = 4; bool receive_original_destination = 4;
bool receive_original_destination = 5; reserved 5;
reserved 6; SniffingConfig sniffing_settings = 6;
SniffingConfig sniffing_settings = 7;
} }
message InboundHandlerConfig { message InboundHandlerConfig {
+3 -12
View File
@@ -5,7 +5,6 @@ import (
"github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/mux" "github.com/xtls/xray-core/common/mux"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
@@ -103,7 +102,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
stream: mss, stream: mss,
tag: tag, tag: tag,
dispatcher: h.mux, dispatcher: h.mux,
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(), sniffingConfig: receiverConfig.SniffingSettings,
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
ctx: ctx, ctx: ctx,
@@ -125,7 +124,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
recvOrigDest: receiverConfig.ReceiveOriginalDestination, recvOrigDest: receiverConfig.ReceiveOriginalDestination,
tag: tag, tag: tag,
dispatcher: h.mux, dispatcher: h.mux,
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(), sniffingConfig: receiverConfig.SniffingSettings,
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
ctx: ctx, ctx: ctx,
@@ -140,7 +139,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
address: address, address: address,
port: net.Port(port), port: net.Port(port),
dispatcher: h.mux, dispatcher: h.mux,
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(), sniffingConfig: receiverConfig.SniffingSettings,
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
stream: mss, stream: mss,
@@ -178,14 +177,6 @@ func (h *AlwaysOnInboundHandler) Close() error {
return nil return nil
} }
func (h *AlwaysOnInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {
if len(h.workers) == 0 {
return nil, 0, 0
}
w := h.workers[dice.Roll(len(h.workers))]
return w.Proxy(), w.Port(), 9999
}
func (h *AlwaysOnInboundHandler) Tag() string { func (h *AlwaysOnInboundHandler) Tag() string {
return h.tag return h.tag
} }
-222
View File
@@ -1,222 +0,0 @@
package inbound
import (
"context"
"sync"
"time"
"github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/mux"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/proxy"
"github.com/xtls/xray-core/transport/internet"
"google.golang.org/protobuf/proto"
)
type DynamicInboundHandler struct {
tag string
v *core.Instance
proxyConfig interface{}
receiverConfig *proxyman.ReceiverConfig
streamSettings *internet.MemoryStreamConfig
portMutex sync.Mutex
portsInUse map[net.Port]struct{}
workerMutex sync.RWMutex
worker []worker
lastRefresh time.Time
mux *mux.Server
task *task.Periodic
ctx context.Context
}
func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*DynamicInboundHandler, error) {
v := core.MustFromContext(ctx)
h := &DynamicInboundHandler{
tag: tag,
proxyConfig: proxyConfig,
receiverConfig: receiverConfig,
portsInUse: make(map[net.Port]struct{}),
mux: mux.NewServer(ctx),
v: v,
ctx: ctx,
}
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
if err != nil {
return nil, errors.New("failed to parse stream settings").Base(err).AtWarning()
}
if receiverConfig.ReceiveOriginalDestination {
if mss.SocketSettings == nil {
mss.SocketSettings = &internet.SocketConfig{}
}
if mss.SocketSettings.Tproxy == internet.SocketConfig_Off {
mss.SocketSettings.Tproxy = internet.SocketConfig_Redirect
}
mss.SocketSettings.ReceiveOriginalDestAddress = true
}
h.streamSettings = mss
h.task = &task.Periodic{
Interval: time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()),
Execute: h.refresh,
}
return h, nil
}
func (h *DynamicInboundHandler) allocatePort() net.Port {
allPorts := []int32{}
for _, pr := range h.receiverConfig.PortList.Range {
for i := pr.From; i <= pr.To; i++ {
allPorts = append(allPorts, int32(i))
}
}
h.portMutex.Lock()
defer h.portMutex.Unlock()
for {
r := dice.Roll(len(allPorts))
port := net.Port(allPorts[r])
_, used := h.portsInUse[port]
if !used {
h.portsInUse[port] = struct{}{}
return port
}
}
}
func (h *DynamicInboundHandler) closeWorkers(workers []worker) {
ports2Del := make([]net.Port, len(workers))
for idx, worker := range workers {
ports2Del[idx] = worker.Port()
if err := worker.Close(); err != nil {
errors.LogInfoInner(h.ctx, err, "failed to close worker")
}
}
h.portMutex.Lock()
for _, port := range ports2Del {
delete(h.portsInUse, port)
}
h.portMutex.Unlock()
}
func (h *DynamicInboundHandler) refresh() error {
h.lastRefresh = time.Now()
timeout := time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()) * 2
concurrency := h.receiverConfig.AllocationStrategy.GetConcurrencyValue()
workers := make([]worker, 0, concurrency)
address := h.receiverConfig.Listen.AsAddress()
if address == nil {
address = net.AnyIP
}
uplinkCounter, downlinkCounter := getStatCounter(h.v, h.tag)
for i := uint32(0); i < concurrency; i++ {
port := h.allocatePort()
rawProxy, err := core.CreateObject(h.v, h.proxyConfig)
if err != nil {
errors.LogWarningInner(h.ctx, err, "failed to create proxy instance")
continue
}
p := rawProxy.(proxy.Inbound)
nl := p.Network()
if net.HasNetwork(nl, net.Network_TCP) {
worker := &tcpWorker{
tag: h.tag,
address: address,
port: port,
proxy: p,
stream: h.streamSettings,
recvOrigDest: h.receiverConfig.ReceiveOriginalDestination,
dispatcher: h.mux,
sniffingConfig: h.receiverConfig.GetEffectiveSniffingSettings(),
uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter,
ctx: h.ctx,
}
if err := worker.Start(); err != nil {
errors.LogWarningInner(h.ctx, err, "failed to create TCP worker")
continue
}
workers = append(workers, worker)
}
if net.HasNetwork(nl, net.Network_UDP) {
worker := &udpWorker{
tag: h.tag,
proxy: p,
address: address,
port: port,
dispatcher: h.mux,
sniffingConfig: h.receiverConfig.GetEffectiveSniffingSettings(),
uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter,
stream: h.streamSettings,
ctx: h.ctx,
}
if err := worker.Start(); err != nil {
errors.LogWarningInner(h.ctx, err, "failed to create UDP worker")
continue
}
workers = append(workers, worker)
}
}
h.workerMutex.Lock()
h.worker = workers
h.workerMutex.Unlock()
time.AfterFunc(timeout, func() {
h.closeWorkers(workers)
})
return nil
}
func (h *DynamicInboundHandler) Start() error {
return h.task.Start()
}
func (h *DynamicInboundHandler) Close() error {
return h.task.Close()
}
func (h *DynamicInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {
h.workerMutex.RLock()
defer h.workerMutex.RUnlock()
if len(h.worker) == 0 {
return nil, 0, 0
}
w := h.worker[dice.Roll(len(h.worker))]
expire := h.receiverConfig.AllocationStrategy.GetRefreshValue() - uint32(time.Since(h.lastRefresh)/time.Minute)
return w.Proxy(), w.Port(), int(expire)
}
func (h *DynamicInboundHandler) Tag() string {
return h.tag
}
// ReceiverSettings implements inbound.Handler.
func (h *DynamicInboundHandler) ReceiverSettings() *serial.TypedMessage {
return serial.ToTypedMessage(h.receiverConfig)
}
// ProxySettings implements inbound.Handler.
func (h *DynamicInboundHandler) ProxySettings() *serial.TypedMessage {
if v, ok := h.proxyConfig.(proto.Message); ok {
return serial.ToTypedMessage(v)
}
return nil
}
+1 -9
View File
@@ -178,15 +178,7 @@ func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound
ctx = session.ContextWithAllowedNetwork(ctx, net.Network_UDP) ctx = session.ContextWithAllowedNetwork(ctx, net.Network_UDP)
} }
allocStrategy := receiverSettings.AllocationStrategy return NewAlwaysOnInboundHandler(ctx, tag, receiverSettings, proxySettings)
if allocStrategy == nil || allocStrategy.Type == proxyman.AllocationStrategy_Always {
return NewAlwaysOnInboundHandler(ctx, tag, receiverSettings, proxySettings)
}
if allocStrategy.Type == proxyman.AllocationStrategy_Random {
return NewDynamicInboundHandler(ctx, tag, receiverSettings, proxySettings)
}
return nil, errors.New("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).AtError()
} }
func init() { func init() {
+34
View File
@@ -2,6 +2,7 @@ package inbound
import ( import (
"context" "context"
gonet "net"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@@ -76,7 +77,25 @@ func (w *tcpWorker) callback(conn stat.Connection) {
case internet.SocketConfig_TProxy: case internet.SocketConfig_TProxy:
dest = net.DestinationFromAddr(conn.LocalAddr()) dest = net.DestinationFromAddr(conn.LocalAddr())
} }
if dest.IsValid() { if dest.IsValid() {
// Check if try to connect to this inbound itself (can cause loopback)
var isLoopBack bool
if w.address == net.AnyIP || w.address == net.AnyIPv6 {
if dest.Port.Value() == w.port.Value() && IsLocal(dest.Address.IP()) {
isLoopBack = true
}
} else {
if w.hub.Addr().String() == dest.NetAddr() {
isLoopBack = true
}
}
if isLoopBack {
cancel()
conn.Close()
errors.LogError(ctx, errors.New("loopback connection detected"))
return
}
outbounds[0].Target = dest outbounds[0].Target = dest
} }
} }
@@ -544,3 +563,18 @@ func (w *dsWorker) Close() error {
return nil return nil
} }
func IsLocal(ip net.IP) bool {
addrs, err := gonet.InterfaceAddrs()
if err != nil {
return false
}
for _, addr := range addrs {
if ipnet, ok := addr.(*gonet.IPNet); ok {
if ipnet.IP.Equal(ip) {
return true
}
}
}
return false
}
+2
View File
@@ -108,6 +108,8 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
} }
h.proxyConfig = proxyConfig h.proxyConfig = proxyConfig
ctx = session.ContextWithHandler(ctx, h)
rawProxyHandler, err := common.CreateObject(ctx, proxyConfig) rawProxyHandler, err := common.CreateObject(ctx, proxyConfig)
if err != nil { if err != nil {
return nil, err return nil, err
+56 -30
View File
@@ -9,6 +9,7 @@ import (
"github.com/xtls/xray-core/common/mux" "github.com/xtls/xray-core/common/mux"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
@@ -53,6 +54,11 @@ func (b *Bridge) cleanup() {
if w.IsActive() { if w.IsActive() {
activeWorkers = append(activeWorkers, w) activeWorkers = append(activeWorkers, w)
} }
if w.Closed() {
if w.Timer != nil {
w.Timer.SetTimeout(0)
}
}
} }
if len(activeWorkers) != len(b.workers) { if len(activeWorkers) != len(b.workers) {
@@ -94,10 +100,11 @@ func (b *Bridge) Close() error {
} }
type BridgeWorker struct { type BridgeWorker struct {
tag string Tag string
worker *mux.ServerWorker Worker *mux.ServerWorker
dispatcher routing.Dispatcher Dispatcher routing.Dispatcher
state Control_State State Control_State
Timer *signal.ActivityTimer
} }
func NewBridgeWorker(domain string, tag string, d routing.Dispatcher) (*BridgeWorker, error) { func NewBridgeWorker(domain string, tag string, d routing.Dispatcher) (*BridgeWorker, error) {
@@ -115,16 +122,20 @@ func NewBridgeWorker(domain string, tag string, d routing.Dispatcher) (*BridgeWo
} }
w := &BridgeWorker{ w := &BridgeWorker{
dispatcher: d, Dispatcher: d,
tag: tag, Tag: tag,
} }
worker, err := mux.NewServerWorker(context.Background(), w, link) worker, err := mux.NewServerWorker(context.Background(), w, link)
if err != nil { if err != nil {
return nil, err return nil, err
} }
w.worker = worker w.Worker = worker
terminate := func() {
worker.Close()
}
w.Timer = signal.CancelAfterInactivity(ctx, terminate, 60*time.Second)
return w, nil return w, nil
} }
@@ -141,48 +152,63 @@ func (w *BridgeWorker) Close() error {
} }
func (w *BridgeWorker) IsActive() bool { func (w *BridgeWorker) IsActive() bool {
return w.state == Control_ACTIVE && !w.worker.Closed() return w.State == Control_ACTIVE && !w.Worker.Closed()
}
func (w *BridgeWorker) Closed() bool {
return w.Worker.Closed()
} }
func (w *BridgeWorker) Connections() uint32 { func (w *BridgeWorker) Connections() uint32 {
return w.worker.ActiveConnections() return w.Worker.ActiveConnections()
} }
func (w *BridgeWorker) handleInternalConn(link *transport.Link) { func (w *BridgeWorker) handleInternalConn(link *transport.Link) {
go func() { reader := link.Reader
reader := link.Reader for {
for { mb, err := reader.ReadMultiBuffer()
mb, err := reader.ReadMultiBuffer() if err != nil {
if err != nil { if w.Timer != nil {
break if w.Closed() {
w.Timer.SetTimeout(0)
} else {
w.Timer.SetTimeout(24 * time.Hour)
}
} }
for _, b := range mb { return
var ctl Control }
if err := proto.Unmarshal(b.Bytes(), &ctl); err != nil { if w.Timer != nil {
errors.LogInfoInner(context.Background(), err, "failed to parse proto message") w.Timer.Update()
break }
} for _, b := range mb {
if ctl.State != w.state { var ctl Control
w.state = ctl.State if err := proto.Unmarshal(b.Bytes(), &ctl); err != nil {
errors.LogInfoInner(context.Background(), err, "failed to parse proto message")
if w.Timer != nil {
w.Timer.SetTimeout(0)
} }
return
}
if ctl.State != w.State {
w.State = ctl.State
} }
} }
}() }
} }
func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) { func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {
if !isInternalDomain(dest) { if !isInternalDomain(dest) {
ctx = session.ContextWithInbound(ctx, &session.Inbound{ ctx = session.ContextWithInbound(ctx, &session.Inbound{
Tag: w.tag, Tag: w.Tag,
}) })
return w.dispatcher.Dispatch(ctx, dest) return w.Dispatcher.Dispatch(ctx, dest)
} }
opt := []pipe.Option{pipe.WithSizeLimit(16 * 1024)} opt := []pipe.Option{pipe.WithSizeLimit(16 * 1024)}
uplinkReader, uplinkWriter := pipe.New(opt...) uplinkReader, uplinkWriter := pipe.New(opt...)
downlinkReader, downlinkWriter := pipe.New(opt...) downlinkReader, downlinkWriter := pipe.New(opt...)
w.handleInternalConn(&transport.Link{ go w.handleInternalConn(&transport.Link{
Reader: downlinkReader, Reader: downlinkReader,
Writer: uplinkWriter, Writer: uplinkWriter,
}) })
@@ -196,12 +222,12 @@ func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*tra
func (w *BridgeWorker) DispatchLink(ctx context.Context, dest net.Destination, link *transport.Link) error { func (w *BridgeWorker) DispatchLink(ctx context.Context, dest net.Destination, link *transport.Link) error {
if !isInternalDomain(dest) { if !isInternalDomain(dest) {
ctx = session.ContextWithInbound(ctx, &session.Inbound{ ctx = session.ContextWithInbound(ctx, &session.Inbound{
Tag: w.tag, Tag: w.Tag,
}) })
return w.dispatcher.DispatchLink(ctx, dest, link) return w.Dispatcher.DispatchLink(ctx, dest, link)
} }
link = w.dispatcher.(*dispatcher.DefaultDispatcher).WrapLink(ctx, link) link = w.Dispatcher.(*dispatcher.DefaultDispatcher).WrapLink(ctx, link)
w.handleInternalConn(link) w.handleInternalConn(link)
return nil return nil
+43 -2
View File
@@ -12,6 +12,7 @@ import (
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
@@ -71,7 +72,14 @@ func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) err
} }
if isDomain(ob.Target, p.domain) { if isDomain(ob.Target, p.domain) {
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{}) opts := pipe.OptionsFromContext(ctx)
uplinkReader, uplinkWriter := pipe.New(opts...)
downlinkReader, downlinkWriter := pipe.New(opts...)
muxClient, err := mux.NewClientWorker(transport.Link{
Reader: uplinkReader,
Writer: downlinkWriter,
}, mux.ClientStrategy{})
if err != nil { if err != nil {
return errors.New("failed to create mux client worker").Base(err).AtWarning() return errors.New("failed to create mux client worker").Base(err).AtWarning()
} }
@@ -82,9 +90,34 @@ func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) err
} }
p.picker.AddWorker(worker) p.picker.AddWorker(worker)
inboundLink := &transport.Link{Reader: downlinkReader, Writer: uplinkWriter}
requestDone := func() error {
if err := buf.Copy(link.Reader, inboundLink.Writer); err != nil {
return errors.New("failed to transfer request").Base(err)
}
return nil
}
responseDone := func() error {
if err := buf.Copy(inboundLink.Reader, link.Writer); err != nil {
return err
}
return nil
}
requestDonePost := task.OnSuccess(requestDone, task.Close(inboundLink.Writer))
if err := task.Run(ctx, requestDonePost, responseDone); err != nil {
common.Interrupt(inboundLink.Reader)
common.Interrupt(inboundLink.Writer)
return errors.New("connection ends").Base(err)
}
return nil return nil
} }
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil && ob.OriginalTarget.Address != ob.Target.Address {
link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
}
return p.client.Dispatch(ctx, link) return p.client.Dispatch(ctx, link)
} }
@@ -101,6 +134,7 @@ func (o *Outbound) Dispatch(ctx context.Context, link *transport.Link) {
if err := o.portal.HandleConnection(ctx, link); err != nil { if err := o.portal.HandleConnection(ctx, link); err != nil {
errors.LogInfoInner(ctx, err, "failed to process reverse connection") errors.LogInfoInner(ctx, err, "failed to process reverse connection")
common.Interrupt(link.Writer) common.Interrupt(link.Writer)
common.Interrupt(link.Reader)
} }
} }
@@ -146,6 +180,8 @@ func (p *StaticMuxPicker) cleanup() error {
for _, w := range p.workers { for _, w := range p.workers {
if !w.Closed() { if !w.Closed() {
activeWorkers = append(activeWorkers, w) activeWorkers = append(activeWorkers, w)
} else {
w.timer.SetTimeout(0)
} }
} }
@@ -212,6 +248,7 @@ type PortalWorker struct {
reader buf.Reader reader buf.Reader
draining bool draining bool
counter uint32 counter uint32
timer *signal.ActivityTimer
} }
func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) { func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
@@ -231,10 +268,14 @@ func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
if !f { if !f {
return nil, errors.New("unable to dispatch control connection") return nil, errors.New("unable to dispatch control connection")
} }
terminate := func() {
client.Close()
}
w := &PortalWorker{ w := &PortalWorker{
client: client, client: client,
reader: downlinkReader, reader: downlinkReader,
writer: uplinkWriter, writer: uplinkWriter,
timer: signal.CancelAfterInactivity(ctx, terminate, 24*time.Hour), // // prevent leak
} }
w.control = &task.Periodic{ w.control = &task.Periodic{
Execute: w.heartbeat, Execute: w.heartbeat,
@@ -261,7 +302,6 @@ func (w *PortalWorker) heartbeat() error {
msg.State = Control_DRAIN msg.State = Control_DRAIN
defer func() { defer func() {
w.client.GetTimer().Reset(time.Second * 16)
common.Close(w.writer) common.Close(w.writer)
common.Interrupt(w.reader) common.Interrupt(w.reader)
w.writer = nil w.writer = nil
@@ -273,6 +313,7 @@ func (w *PortalWorker) heartbeat() error {
b, err := proto.Marshal(msg) b, err := proto.Marshal(msg)
common.Must(err) common.Must(err)
mb := buf.MergeBytes(nil, b) mb := buf.MergeBytes(nil, b)
w.timer.Update()
return w.writer.WriteMultiBuffer(mb) return w.writer.WriteMultiBuffer(mb)
} }
return nil return nil
+1 -1
View File
@@ -12,7 +12,7 @@ import (
) )
const ( const (
internalDomain = "reverse.internal.v2fly.org" // make reverse proxy compatible with v2fly internalDomain = "reverse"
) )
func isDomain(dest net.Destination, domain string) bool { func isDomain(dest net.Destination, domain string) bool {
+16 -10
View File
@@ -215,14 +215,20 @@ func (m *ClientWorker) Closed() bool {
return m.done.Done() return m.done.Done()
} }
func (m *ClientWorker) GetTimer() *time.Ticker { func (m *ClientWorker) WaitClosed() <-chan struct{} {
return m.timer return m.done.Wait()
}
func (m *ClientWorker) Close() error {
return m.done.Close()
} }
func (m *ClientWorker) monitor() { func (m *ClientWorker) monitor() {
defer m.timer.Stop() defer m.timer.Stop()
for { for {
checkSize := m.sessionManager.Size()
checkCount := m.sessionManager.Count()
select { select {
case <-m.done.Wait(): case <-m.done.Wait():
m.sessionManager.Close() m.sessionManager.Close()
@@ -230,8 +236,7 @@ func (m *ClientWorker) monitor() {
common.Interrupt(m.link.Reader) common.Interrupt(m.link.Reader)
return return
case <-m.timer.C: case <-m.timer.C:
size := m.sessionManager.Size() if m.sessionManager.CloseIfNoSessionAndIdle(checkSize, checkCount) {
if size == 0 && m.sessionManager.CloseIfNoSession() {
common.Must(m.done.Close()) common.Must(m.done.Close())
} }
} }
@@ -251,7 +256,7 @@ func writeFirstPayload(reader buf.Reader, writer *Writer) error {
return nil return nil
} }
func fetchInput(ctx context.Context, s *Session, output buf.Writer, timer *time.Ticker) { func fetchInput(ctx context.Context, s *Session, output buf.Writer) {
outbounds := session.OutboundsFromContext(ctx) outbounds := session.OutboundsFromContext(ctx)
ob := outbounds[len(outbounds)-1] ob := outbounds[len(outbounds)-1]
transferType := protocol.TransferTypeStream transferType := protocol.TransferTypeStream
@@ -262,7 +267,6 @@ func fetchInput(ctx context.Context, s *Session, output buf.Writer, timer *time.
writer := NewWriter(s.ID, ob.Target, output, transferType, xudp.GetGlobalID(ctx)) writer := NewWriter(s.ID, ob.Target, output, transferType, xudp.GetGlobalID(ctx))
defer s.Close(false) defer s.Close(false)
defer writer.Close() defer writer.Close()
defer timer.Reset(time.Second * 16)
errors.LogInfo(ctx, "dispatching request to ", ob.Target) errors.LogInfo(ctx, "dispatching request to ", ob.Target)
if err := writeFirstPayload(s.input, writer); err != nil { if err := writeFirstPayload(s.input, writer); err != nil {
@@ -312,10 +316,12 @@ func (m *ClientWorker) Dispatch(ctx context.Context, link *transport.Link) bool
} }
s.input = link.Reader s.input = link.Reader
s.output = link.Writer s.output = link.Writer
if _, ok := link.Reader.(*pipe.Reader); ok { go fetchInput(ctx, s, m.link.Writer)
go fetchInput(ctx, s, m.link.Writer, m.timer) if _, ok := link.Reader.(*pipe.Reader); !ok {
} else { select {
fetchInput(ctx, s, m.link.Writer, m.timer) case <-ctx.Done():
case <-s.done.Wait():
}
} }
return true return true
} }
+83 -14
View File
@@ -3,8 +3,8 @@ package mux
import ( import (
"context" "context"
"io" "io"
"time"
"github.com/xtls/xray-core/app/dispatcher"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
@@ -12,7 +12,11 @@ import (
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
//"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/signal/done"
"github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
//"github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/pipe" "github.com/xtls/xray-core/transport/pipe"
@@ -62,9 +66,45 @@ func (s *Server) DispatchLink(ctx context.Context, dest net.Destination, link *t
if dest.Address != muxCoolAddress { if dest.Address != muxCoolAddress {
return s.dispatcher.DispatchLink(ctx, dest, link) return s.dispatcher.DispatchLink(ctx, dest, link)
} }
link = s.dispatcher.(*dispatcher.DefaultDispatcher).WrapLink(ctx, link)
_, err := NewServerWorker(ctx, s.dispatcher, link) // For Mux, we need to use pipe to guard against multiple sub-connections writing back responses at the same time
return err // sessionPolicy = h.policyManager.ForLevel(request.User.Level)
// ctx, cancel := context.WithCancel(ctx)
// timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
// ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)
opts := pipe.OptionsFromContext(ctx)
uplinkReader, uplinkWriter := pipe.New(opts...)
downlinkReader, downlinkWriter := pipe.New(opts...)
_, err := NewServerWorker(ctx, s.dispatcher, &transport.Link{
Reader: uplinkReader,
Writer: downlinkWriter,
})
if err != nil {
return err
}
inboundLink := &transport.Link{Reader: downlinkReader, Writer: uplinkWriter}
requestDone := func() error {
//defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
if err := buf.Copy(link.Reader, inboundLink.Writer); err != nil {
return errors.New("failed to transfer request").Base(err)
}
return nil
}
responseDone := func() error {
//defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
if err := buf.Copy(inboundLink.Reader, link.Writer); err != nil {
return err
}
return nil
}
requestDonePost := task.OnSuccess(requestDone, task.Close(inboundLink.Writer))
if err := task.Run(ctx, requestDonePost, responseDone); err != nil {
common.Interrupt(inboundLink.Reader)
common.Interrupt(inboundLink.Writer)
return errors.New("connection ends").Base(err)
}
return nil
} }
// Start implements common.Runnable. // Start implements common.Runnable.
@@ -81,6 +121,8 @@ type ServerWorker struct {
dispatcher routing.Dispatcher dispatcher routing.Dispatcher
link *transport.Link link *transport.Link
sessionManager *SessionManager sessionManager *SessionManager
done *done.Instance
timer *time.Ticker
} }
func NewServerWorker(ctx context.Context, d routing.Dispatcher, link *transport.Link) (*ServerWorker, error) { func NewServerWorker(ctx context.Context, d routing.Dispatcher, link *transport.Link) (*ServerWorker, error) {
@@ -88,15 +130,14 @@ func NewServerWorker(ctx context.Context, d routing.Dispatcher, link *transport.
dispatcher: d, dispatcher: d,
link: link, link: link,
sessionManager: NewSessionManager(), sessionManager: NewSessionManager(),
done: done.New(),
timer: time.NewTicker(60 * time.Second),
} }
if inbound := session.InboundFromContext(ctx); inbound != nil { if inbound := session.InboundFromContext(ctx); inbound != nil {
inbound.CanSpliceCopy = 3 inbound.CanSpliceCopy = 3
} }
if _, ok := link.Reader.(*pipe.Reader); ok { go worker.run(ctx)
go worker.run(ctx) go worker.monitor()
} else {
worker.run(ctx)
}
return worker, nil return worker, nil
} }
@@ -111,12 +152,40 @@ func handle(ctx context.Context, s *Session, output buf.Writer) {
s.Close(false) s.Close(false)
} }
func (w *ServerWorker) monitor() {
defer w.timer.Stop()
for {
checkSize := w.sessionManager.Size()
checkCount := w.sessionManager.Count()
select {
case <-w.done.Wait():
w.sessionManager.Close()
common.Interrupt(w.link.Writer)
common.Interrupt(w.link.Reader)
return
case <-w.timer.C:
if w.sessionManager.CloseIfNoSessionAndIdle(checkSize, checkCount) {
common.Must(w.done.Close())
}
}
}
}
func (w *ServerWorker) ActiveConnections() uint32 { func (w *ServerWorker) ActiveConnections() uint32 {
return uint32(w.sessionManager.Size()) return uint32(w.sessionManager.Size())
} }
func (w *ServerWorker) Closed() bool { func (w *ServerWorker) Closed() bool {
return w.sessionManager.Closed() return w.done.Done()
}
func (w *ServerWorker) WaitClosed() <-chan struct{} {
return w.done.Wait()
}
func (w *ServerWorker) Close() error {
return w.done.Close()
} }
func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.BufferedReader) error { func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.BufferedReader) error {
@@ -317,11 +386,11 @@ func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedRead
} }
func (w *ServerWorker) run(ctx context.Context) { func (w *ServerWorker) run(ctx context.Context) {
reader := &buf.BufferedReader{Reader: w.link.Reader} defer func() {
common.Must(w.done.Close())
}()
defer w.sessionManager.Close() reader := &buf.BufferedReader{Reader: w.link.Reader}
defer common.Interrupt(w.link.Reader)
defer common.Interrupt(w.link.Writer)
for { for {
select { select {
+11 -3
View File
@@ -12,6 +12,7 @@ import (
"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/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/signal/done"
"github.com/xtls/xray-core/transport/pipe" "github.com/xtls/xray-core/transport/pipe"
) )
@@ -53,7 +54,7 @@ func (m *SessionManager) Count() int {
func (m *SessionManager) Allocate(Strategy *ClientStrategy) *Session { func (m *SessionManager) Allocate(Strategy *ClientStrategy) *Session {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
MaxConcurrency := int(Strategy.MaxConcurrency) MaxConcurrency := int(Strategy.MaxConcurrency)
MaxConnection := uint16(Strategy.MaxConnection) MaxConnection := uint16(Strategy.MaxConnection)
@@ -65,6 +66,7 @@ func (m *SessionManager) Allocate(Strategy *ClientStrategy) *Session {
s := &Session{ s := &Session{
ID: m.count, ID: m.count,
parent: m, parent: m,
done: done.New(),
} }
m.sessions[s.ID] = s m.sessions[s.ID] = s
return s return s
@@ -115,7 +117,7 @@ func (m *SessionManager) Get(id uint16) (*Session, bool) {
return s, found return s, found
} }
func (m *SessionManager) CloseIfNoSession() bool { func (m *SessionManager) CloseIfNoSessionAndIdle(checkSize int, checkCount int) bool {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
@@ -123,11 +125,13 @@ func (m *SessionManager) CloseIfNoSession() bool {
return true return true
} }
if len(m.sessions) != 0 { if len(m.sessions) != 0 || checkSize != 0 || checkCount != int(m.count) {
return false return false
} }
m.closed = true m.closed = true
m.sessions = nil
return true return true
} }
@@ -157,6 +161,7 @@ type Session struct {
ID uint16 ID uint16
transferType protocol.TransferType transferType protocol.TransferType
closed bool closed bool
done *done.Instance
XUDP *XUDP XUDP *XUDP
} }
@@ -171,6 +176,9 @@ func (s *Session) Close(locked bool) error {
return nil return nil
} }
s.closed = true s.closed = true
if s.done != nil {
s.done.Close()
}
if s.XUDP == nil { if s.XUDP == nil {
common.Interrupt(s.input) common.Interrupt(s.input)
common.Close(s.output) common.Close(s.output)
+2 -2
View File
@@ -41,11 +41,11 @@ func TestSessionManagerClose(t *testing.T) {
m := NewSessionManager() m := NewSessionManager()
s := m.Allocate(&ClientStrategy{}) s := m.Allocate(&ClientStrategy{})
if m.CloseIfNoSession() { if m.CloseIfNoSessionAndIdle(m.Size(), m.Count()) {
t.Error("able to close") t.Error("able to close")
} }
m.Remove(false, s.ID) m.Remove(false, s.ID)
if !m.CloseIfNoSession() { if !m.CloseIfNoSessionAndIdle(m.Size(), m.Count()) {
t.Error("not able to close") t.Error("not able to close")
} }
} }
+2 -10
View File
@@ -5,7 +5,6 @@ import (
"github.com/xtls/xray-core/common/bitmask" "github.com/xtls/xray-core/common/bitmask"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/uuid"
"golang.org/x/sys/cpu" "golang.org/x/sys/cpu"
) )
@@ -16,11 +15,12 @@ const (
RequestCommandTCP = RequestCommand(0x01) RequestCommandTCP = RequestCommand(0x01)
RequestCommandUDP = RequestCommand(0x02) RequestCommandUDP = RequestCommand(0x02)
RequestCommandMux = RequestCommand(0x03) RequestCommandMux = RequestCommand(0x03)
RequestCommandRvs = RequestCommand(0x04)
) )
func (c RequestCommand) TransferType() TransferType { func (c RequestCommand) TransferType() TransferType {
switch c { switch c {
case RequestCommandTCP, RequestCommandMux: case RequestCommandTCP, RequestCommandMux, RequestCommandRvs:
return TransferTypeStream return TransferTypeStream
case RequestCommandUDP: case RequestCommandUDP:
return TransferTypePacket return TransferTypePacket
@@ -70,14 +70,6 @@ type ResponseHeader struct {
Command ResponseCommand Command ResponseCommand
} }
type CommandSwitchAccount struct {
Host net.Address
Port net.Port
ID uuid.UUID
Level uint32
ValidMin byte
}
var ( var (
// Keep in sync with crypto/tls/cipher_suites.go. // Keep in sync with crypto/tls/cipher_suites.go.
hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ && cpu.X86.HasSSE41 && cpu.X86.HasSSSE3 hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ && cpu.X86.HasSSE41 && cpu.X86.HasSSSE3
-89
View File
@@ -1,89 +0,0 @@
package protocol
import (
"sync"
)
type ServerList struct {
sync.RWMutex
servers []*ServerSpec
}
func NewServerList() *ServerList {
return &ServerList{}
}
func (sl *ServerList) AddServer(server *ServerSpec) {
sl.Lock()
defer sl.Unlock()
sl.servers = append(sl.servers, server)
}
func (sl *ServerList) Size() uint32 {
sl.RLock()
defer sl.RUnlock()
return uint32(len(sl.servers))
}
func (sl *ServerList) GetServer(idx uint32) *ServerSpec {
sl.Lock()
defer sl.Unlock()
for {
if idx >= uint32(len(sl.servers)) {
return nil
}
server := sl.servers[idx]
if !server.IsValid() {
sl.removeServer(idx)
continue
}
return server
}
}
func (sl *ServerList) removeServer(idx uint32) {
n := len(sl.servers)
sl.servers[idx] = sl.servers[n-1]
sl.servers = sl.servers[:n-1]
}
type ServerPicker interface {
PickServer() *ServerSpec
}
type RoundRobinServerPicker struct {
sync.Mutex
serverlist *ServerList
nextIndex uint32
}
func NewRoundRobinServerPicker(serverlist *ServerList) *RoundRobinServerPicker {
return &RoundRobinServerPicker{
serverlist: serverlist,
nextIndex: 0,
}
}
func (p *RoundRobinServerPicker) PickServer() *ServerSpec {
p.Lock()
defer p.Unlock()
next := p.nextIndex
server := p.serverlist.GetServer(next)
if server == nil {
next = 0
server = p.serverlist.GetServer(0)
}
next++
if next >= p.serverlist.Size() {
next = 0
}
p.nextIndex = next
return server
}
-71
View File
@@ -1,71 +0,0 @@
package protocol_test
import (
"testing"
"time"
"github.com/xtls/xray-core/common/net"
. "github.com/xtls/xray-core/common/protocol"
)
func TestServerList(t *testing.T) {
list := NewServerList()
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(1)), AlwaysValid()))
if list.Size() != 1 {
t.Error("list size: ", list.Size())
}
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(2)), BeforeTime(time.Now().Add(time.Second))))
if list.Size() != 2 {
t.Error("list.size: ", list.Size())
}
server := list.GetServer(1)
if server.Destination().Port != 2 {
t.Error("server: ", server.Destination())
}
time.Sleep(2 * time.Second)
server = list.GetServer(1)
if server != nil {
t.Error("server: ", server)
}
server = list.GetServer(0)
if server.Destination().Port != 1 {
t.Error("server: ", server.Destination())
}
}
func TestServerPicker(t *testing.T) {
list := NewServerList()
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(1)), AlwaysValid()))
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(2)), BeforeTime(time.Now().Add(time.Second))))
list.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(3)), BeforeTime(time.Now().Add(time.Second))))
picker := NewRoundRobinServerPicker(list)
server := picker.PickServer()
if server.Destination().Port != 1 {
t.Error("server: ", server.Destination())
}
server = picker.PickServer()
if server.Destination().Port != 2 {
t.Error("server: ", server.Destination())
}
server = picker.PickServer()
if server.Destination().Port != 3 {
t.Error("server: ", server.Destination())
}
server = picker.PickServer()
if server.Destination().Port != 1 {
t.Error("server: ", server.Destination())
}
time.Sleep(2 * time.Second)
server = picker.PickServer()
if server.Destination().Port != 1 {
t.Error("server: ", server.Destination())
}
server = picker.PickServer()
if server.Destination().Port != 1 {
t.Error("server: ", server.Destination())
}
}
+10 -102
View File
@@ -1,122 +1,30 @@
package protocol package protocol
import ( import (
"sync"
"time"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
) )
type ValidationStrategy interface {
IsValid() bool
Invalidate()
}
type alwaysValidStrategy struct{}
func AlwaysValid() ValidationStrategy {
return alwaysValidStrategy{}
}
func (alwaysValidStrategy) IsValid() bool {
return true
}
func (alwaysValidStrategy) Invalidate() {}
type timeoutValidStrategy struct {
until time.Time
}
func BeforeTime(t time.Time) ValidationStrategy {
return &timeoutValidStrategy{
until: t,
}
}
func (s *timeoutValidStrategy) IsValid() bool {
return s.until.After(time.Now())
}
func (s *timeoutValidStrategy) Invalidate() {
s.until = time.Time{}
}
type ServerSpec struct { type ServerSpec struct {
sync.RWMutex Destination net.Destination
dest net.Destination User *MemoryUser
users []*MemoryUser
valid ValidationStrategy
} }
func NewServerSpec(dest net.Destination, valid ValidationStrategy, users ...*MemoryUser) *ServerSpec { func NewServerSpec(dest net.Destination, user *MemoryUser) *ServerSpec {
return &ServerSpec{ return &ServerSpec{
dest: dest, Destination: dest,
users: users, User: user,
valid: valid,
} }
} }
func NewServerSpecFromPB(spec *ServerEndpoint) (*ServerSpec, error) { func NewServerSpecFromPB(spec *ServerEndpoint) (*ServerSpec, error) {
dest := net.TCPDestination(spec.Address.AsAddress(), net.Port(spec.Port)) dest := net.TCPDestination(spec.Address.AsAddress(), net.Port(spec.Port))
mUsers := make([]*MemoryUser, len(spec.User)) var dUser *MemoryUser
for idx, u := range spec.User { if spec.User != nil {
mUser, err := u.ToMemoryUser() user, err := spec.User.ToMemoryUser()
if err != nil { if err != nil {
return nil, err return nil, err
} }
mUsers[idx] = mUser dUser = user
} }
return NewServerSpec(dest, AlwaysValid(), mUsers...), nil return NewServerSpec(dest, dUser), nil
}
func (s *ServerSpec) Destination() net.Destination {
return s.dest
}
func (s *ServerSpec) HasUser(user *MemoryUser) bool {
s.RLock()
defer s.RUnlock()
for _, u := range s.users {
if u.Account.Equals(user.Account) {
return true
}
}
return false
}
func (s *ServerSpec) AddUser(user *MemoryUser) {
if s.HasUser(user) {
return
}
s.Lock()
defer s.Unlock()
s.users = append(s.users, user)
}
func (s *ServerSpec) PickUser() *MemoryUser {
s.RLock()
defer s.RUnlock()
userCount := len(s.users)
switch userCount {
case 0:
return nil
case 1:
return s.users[0]
default:
return s.users[dice.Roll(userCount)]
}
}
func (s *ServerSpec) IsValid() bool {
return s.valid.IsValid()
}
func (s *ServerSpec) Invalidate() {
s.valid.Invalidate()
} }
+3 -3
View File
@@ -28,7 +28,7 @@ type ServerEndpoint struct {
Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
User []*User `protobuf:"bytes,3,rep,name=user,proto3" json:"user,omitempty"` User *User `protobuf:"bytes,3,opt,name=user,proto3" json:"user,omitempty"`
} }
func (x *ServerEndpoint) Reset() { func (x *ServerEndpoint) Reset() {
@@ -75,7 +75,7 @@ func (x *ServerEndpoint) GetPort() uint32 {
return 0 return 0
} }
func (x *ServerEndpoint) GetUser() []*User { func (x *ServerEndpoint) GetUser() *User {
if x != nil { if x != nil {
return x.User return x.User
} }
@@ -98,7 +98,7 @@ var file_common_protocol_server_spec_proto_rawDesc = []byte{
0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x2e, 0x0a, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x2e, 0x0a,
0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x42, 0x5e, 0x0a, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x42, 0x5e, 0x0a,
0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
+1 -1
View File
@@ -12,5 +12,5 @@ import "common/protocol/user.proto";
message ServerEndpoint { message ServerEndpoint {
xray.common.net.IPOrDomain address = 1; xray.common.net.IPOrDomain address = 1;
uint32 port = 2; uint32 port = 2;
repeated xray.common.protocol.User user = 3; xray.common.protocol.User user = 3;
} }
-79
View File
@@ -1,79 +0,0 @@
package protocol_test
import (
"strings"
"testing"
"time"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net"
. "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/proxy/vmess"
)
func TestAlwaysValidStrategy(t *testing.T) {
strategy := AlwaysValid()
if !strategy.IsValid() {
t.Error("strategy not valid")
}
strategy.Invalidate()
if !strategy.IsValid() {
t.Error("strategy not valid")
}
}
func TestTimeoutValidStrategy(t *testing.T) {
strategy := BeforeTime(time.Now().Add(2 * time.Second))
if !strategy.IsValid() {
t.Error("strategy not valid")
}
time.Sleep(3 * time.Second)
if strategy.IsValid() {
t.Error("strategy is valid")
}
strategy = BeforeTime(time.Now().Add(2 * time.Second))
strategy.Invalidate()
if strategy.IsValid() {
t.Error("strategy is valid")
}
}
func TestUserInServerSpec(t *testing.T) {
uuid1 := uuid.New()
uuid2 := uuid.New()
toAccount := func(a *vmess.Account) Account {
account, err := a.AsAccount()
common.Must(err)
return account
}
spec := NewServerSpec(net.Destination{}, AlwaysValid(), &MemoryUser{
Email: "test1@example.com",
Account: toAccount(&vmess.Account{Id: uuid1.String()}),
})
if spec.HasUser(&MemoryUser{
Email: "test1@example.com",
Account: toAccount(&vmess.Account{Id: uuid2.String()}),
}) {
t.Error("has user: ", uuid2)
}
spec.AddUser(&MemoryUser{Email: "test2@example.com"})
if !spec.HasUser(&MemoryUser{
Email: "test1@example.com",
Account: toAccount(&vmess.Account{Id: uuid1.String()}),
}) {
t.Error("not having user: ", uuid1)
}
}
func TestPickUser(t *testing.T) {
spec := NewServerSpec(net.Destination{}, AlwaysValid(), &MemoryUser{Email: "test1@example.com"}, &MemoryUser{Email: "test2@example.com"}, &MemoryUser{Email: "test3@example.com"})
user := spec.PickUser()
if !strings.HasSuffix(user.Email, "@example.com") {
t.Error("user: ", user.Email)
}
}
+19 -7
View File
@@ -6,6 +6,7 @@ import (
"github.com/xtls/xray-core/common/ctx" "github.com/xtls/xray-core/common/ctx"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
) )
@@ -16,13 +17,13 @@ const (
inboundSessionKey ctx.SessionKey = 1 inboundSessionKey ctx.SessionKey = 1
outboundSessionKey ctx.SessionKey = 2 outboundSessionKey ctx.SessionKey = 2
contentSessionKey ctx.SessionKey = 3 contentSessionKey ctx.SessionKey = 3
muxPreferredSessionKey ctx.SessionKey = 4 // unused muxPreferredSessionKey ctx.SessionKey = 4 // unused
sockoptSessionKey ctx.SessionKey = 5 // used by dokodemo to only receive sockopt.Mark sockoptSessionKey ctx.SessionKey = 5 // used by dokodemo to only receive sockopt.Mark
trackedConnectionErrorKey ctx.SessionKey = 6 // used by observer to get outbound error trackedConnectionErrorKey ctx.SessionKey = 6 // used by observer to get outbound error
dispatcherKey ctx.SessionKey = 7 // used by ss2022 inbounds to get dispatcher dispatcherKey ctx.SessionKey = 7 // used by ss2022 inbounds to get dispatcher
timeoutOnlyKey ctx.SessionKey = 8 // mux context's child contexts to only cancel when its own traffic times out timeoutOnlyKey ctx.SessionKey = 8 // mux context's child contexts to only cancel when its own traffic times out
allowedNetworkKey ctx.SessionKey = 9 // muxcool server control incoming request tcp/udp allowedNetworkKey ctx.SessionKey = 9 // muxcool server control incoming request tcp/udp
handlerSessionKey ctx.SessionKey = 10 // unused handlerSessionKey ctx.SessionKey = 10 // outbound gets full handler
mitmAlpn11Key ctx.SessionKey = 11 // used by TLS dialer mitmAlpn11Key ctx.SessionKey = 11 // used by TLS dialer
mitmServerNameKey ctx.SessionKey = 12 // used by TLS dialer mitmServerNameKey ctx.SessionKey = 12 // used by TLS dialer
) )
@@ -163,6 +164,17 @@ func AllowedNetworkFromContext(ctx context.Context) net.Network {
return net.Network_Unknown return net.Network_Unknown
} }
func ContextWithHandler(ctx context.Context, handler outbound.Handler) context.Context {
return context.WithValue(ctx, handlerSessionKey, handler)
}
func HandlerFromContext(ctx context.Context) outbound.Handler {
if val, ok := ctx.Value(handlerSessionKey).(outbound.Handler); ok {
return val
}
return nil
}
func ContextWithMitmAlpn11(ctx context.Context, alpn11 bool) context.Context { func ContextWithMitmAlpn11(ctx context.Context, alpn11 bool) context.Context {
return context.WithValue(ctx, mitmAlpn11Key, alpn11) return context.WithValue(ctx, mitmAlpn11Key, alpn11)
} }
+1 -1
View File
@@ -19,7 +19,7 @@ import (
var ( var (
Version_x byte = 25 Version_x byte = 25
Version_y byte = 9 Version_y byte = 9
Version_z byte = 5 Version_z byte = 11
) )
var ( var (
+7 -11
View File
@@ -63,17 +63,13 @@ func TestXrayClose(t *testing.T) {
Outbound: []*OutboundHandlerConfig{ Outbound: []*OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(0),
Port: uint32(0), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
-4
View File
@@ -4,7 +4,6 @@ import (
"context" "context"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/features" "github.com/xtls/xray-core/features"
) )
@@ -20,9 +19,6 @@ type Handler interface {
ReceiverSettings() *serial.TypedMessage ReceiverSettings() *serial.TypedMessage
// Returns the active proxy settings. // Returns the active proxy settings.
ProxySettings() *serial.TypedMessage ProxySettings() *serial.TypedMessage
// Deprecated: Do not use in new code.
GetRandomInboundProxy() (interface{}, net.Port, int)
} }
// Manager is a feature that manages InboundHandlers. // Manager is a feature that manages InboundHandlers.
+10 -10
View File
@@ -19,15 +19,15 @@ require (
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.11.1
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.1 github.com/vishvananda/netlink v1.3.1
github.com/xtls/reality v0.0.0-20250828044527-046fad5ab64f github.com/xtls/reality v0.0.0-20250904214705-431b6ff8c67c
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
golang.org/x/crypto v0.41.0 golang.org/x/crypto v0.42.0
golang.org/x/net v0.43.0 golang.org/x/net v0.44.0
golang.org/x/sync v0.16.0 golang.org/x/sync v0.17.0
golang.org/x/sys v0.35.0 golang.org/x/sys v0.36.0
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
google.golang.org/grpc v1.75.0 google.golang.org/grpc v1.75.1
google.golang.org/protobuf v1.36.8 google.golang.org/protobuf v1.36.9
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5 gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5
h12.io/socks v1.0.3 h12.io/socks v1.0.3
lukechampine.com/blake3 v1.4.1 lukechampine.com/blake3 v1.4.1
@@ -47,10 +47,10 @@ require (
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/vishvananda/netns v0.0.5 // indirect github.com/vishvananda/netns v0.0.5 // indirect
go.uber.org/mock v0.5.0 // indirect go.uber.org/mock v0.5.0 // indirect
golang.org/x/mod v0.26.0 // indirect golang.org/x/mod v0.27.0 // indirect
golang.org/x/text v0.28.0 // indirect golang.org/x/text v0.29.0 // indirect
golang.org/x/time v0.7.0 // indirect golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.35.0 // indirect golang.org/x/tools v0.36.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-20250707201910-8d1bb00bc6a7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
+20 -20
View File
@@ -75,8 +75,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/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 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/xtls/reality v0.0.0-20250828044527-046fad5ab64f h1:o1Kryl9qEYYzNep9RId9DM1kBn8tBrcK5UJnti/l0NI= github.com/xtls/reality v0.0.0-20250904214705-431b6ff8c67c h1:LHLhQY3mKXSpTcQAkjFR4/6ar3rXjQryNeM7khK3AHU=
github.com/xtls/reality v0.0.0-20250828044527-046fad5ab64f/go.mod h1:XxvnCCgBee4WWE0bc4E+a7wbk8gkJ/rS0vNVNtC5qp0= github.com/xtls/reality v0.0.0-20250904214705-431b6ff8c67c/go.mod h1:XxvnCCgBee4WWE0bc4E+a7wbk8gkJ/rS0vNVNtC5qp0=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
@@ -96,20 +96,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= 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.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
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.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
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.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
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.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -117,21 +117,21 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= 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/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-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.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
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=
@@ -143,10 +143,10 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4= google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+44 -10
View File
@@ -51,31 +51,65 @@ type HTTPRemoteConfig struct {
} }
type HTTPClientConfig struct { type HTTPClientConfig struct {
Servers []*HTTPRemoteConfig `json:"servers"` Address *Address `json:"address"`
Headers map[string]string `json:"headers"` Port uint16 `json:"port"`
Level uint32 `json:"level"`
Email string `json:"email"`
Username string `json:"user"`
Password string `json:"pass"`
Servers []*HTTPRemoteConfig `json:"servers"`
Headers map[string]string `json:"headers"`
} }
func (v *HTTPClientConfig) Build() (proto.Message, error) { func (v *HTTPClientConfig) Build() (proto.Message, error) {
config := new(http.ClientConfig) config := new(http.ClientConfig)
config.Server = make([]*protocol.ServerEndpoint, len(v.Servers)) if v.Address != nil {
for idx, serverConfig := range v.Servers { v.Servers = []*HTTPRemoteConfig{
{
Address: v.Address,
Port: v.Port,
},
}
if len(v.Username) > 0 {
v.Servers[0].Users = []json.RawMessage{{}}
}
}
if len(v.Servers) != 1 {
return nil, errors.New(`HTTP settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple HTTP outbounds and routing balancer instead`)
}
for _, serverConfig := range v.Servers {
if len(serverConfig.Users) > 1 {
return nil, errors.New(`HTTP servers: "users" should have one member at most. Multiple members in "users" should use multiple HTTP outbounds and routing balancer instead`)
}
server := &protocol.ServerEndpoint{ server := &protocol.ServerEndpoint{
Address: serverConfig.Address.Build(), Address: serverConfig.Address.Build(),
Port: uint32(serverConfig.Port), Port: uint32(serverConfig.Port),
} }
for _, rawUser := range serverConfig.Users { for _, rawUser := range serverConfig.Users {
user := new(protocol.User) user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil { if v.Address != nil {
return nil, errors.New("failed to parse HTTP user").Base(err).AtError() user.Level = v.Level
user.Email = v.Email
} else {
if err := json.Unmarshal(rawUser, user); err != nil {
return nil, errors.New("failed to parse HTTP user").Base(err).AtError()
}
} }
account := new(HTTPAccount) account := new(HTTPAccount)
if err := json.Unmarshal(rawUser, account); err != nil { if v.Address != nil {
return nil, errors.New("failed to parse HTTP account").Base(err).AtError() account.Username = v.Username
account.Password = v.Password
} else {
if err := json.Unmarshal(rawUser, account); err != nil {
return nil, errors.New("failed to parse HTTP account").Base(err).AtError()
}
} }
user.Account = serial.ToTypedMessage(account.Build()) user.Account = serial.ToTypedMessage(account.Build())
server.User = append(server.User, user) server.User = user
break
} }
config.Server[idx] = server config.Server = server
break
} }
config.Header = make([]*http.Header, 0, 32) config.Header = make([]*http.Header, 0, 32)
for key, value := range v.Headers { for key, value := range v.Headers {
+36 -16
View File
@@ -162,22 +162,46 @@ func buildShadowsocks2022(v *ShadowsocksServerConfig) (proto.Message, error) {
type ShadowsocksServerTarget struct { type ShadowsocksServerTarget struct {
Address *Address `json:"address"` Address *Address `json:"address"`
Port uint16 `json:"port"` Port uint16 `json:"port"`
Level byte `json:"level"`
Email string `json:"email"`
Cipher string `json:"method"` Cipher string `json:"method"`
Password string `json:"password"` Password string `json:"password"`
Email string `json:"email"`
Level byte `json:"level"`
IVCheck bool `json:"ivCheck"` IVCheck bool `json:"ivCheck"`
UoT bool `json:"uot"` UoT bool `json:"uot"`
UoTVersion int `json:"uotVersion"` UoTVersion int `json:"uotVersion"`
} }
type ShadowsocksClientConfig struct { type ShadowsocksClientConfig struct {
Servers []*ShadowsocksServerTarget `json:"servers"` Address *Address `json:"address"`
Port uint16 `json:"port"`
Level byte `json:"level"`
Email string `json:"email"`
Cipher string `json:"method"`
Password string `json:"password"`
IVCheck bool `json:"ivCheck"`
UoT bool `json:"uot"`
UoTVersion int `json:"uotVersion"`
Servers []*ShadowsocksServerTarget `json:"servers"`
} }
func (v *ShadowsocksClientConfig) Build() (proto.Message, error) { func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
if len(v.Servers) == 0 { if v.Address != nil {
return nil, errors.New("0 Shadowsocks server configured.") v.Servers = []*ShadowsocksServerTarget{
{
Address: v.Address,
Port: v.Port,
Level: v.Level,
Email: v.Email,
Cipher: v.Cipher,
Password: v.Password,
IVCheck: v.IVCheck,
UoT: v.UoT,
UoTVersion: v.UoTVersion,
},
}
}
if len(v.Servers) != 1 {
return nil, errors.New(`Shadowsocks settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple Shadowsocks outbounds and routing balancer instead`)
} }
if len(v.Servers) == 1 { if len(v.Servers) == 1 {
@@ -205,8 +229,7 @@ func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
} }
config := new(shadowsocks.ClientConfig) config := new(shadowsocks.ClientConfig)
serverSpecs := make([]*protocol.ServerEndpoint, len(v.Servers)) for _, server := range v.Servers {
for idx, server := range v.Servers {
if C.Contains(shadowaead_2022.List, server.Cipher) { if C.Contains(shadowaead_2022.List, server.Cipher) {
return nil, errors.New("Shadowsocks 2022 accept no multi servers") return nil, errors.New("Shadowsocks 2022 accept no multi servers")
} }
@@ -232,19 +255,16 @@ func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
ss := &protocol.ServerEndpoint{ ss := &protocol.ServerEndpoint{
Address: server.Address.Build(), Address: server.Address.Build(),
Port: uint32(server.Port), Port: uint32(server.Port),
User: []*protocol.User{ User: &protocol.User{
{ Level: uint32(server.Level),
Level: uint32(server.Level), Email: server.Email,
Email: server.Email, Account: serial.ToTypedMessage(account),
Account: serial.ToTypedMessage(account),
},
}, },
} }
serverSpecs[idx] = ss config.Server = ss
break
} }
config.Server = serverSpecs
return config, nil return config, nil
} }
+43 -9
View File
@@ -70,30 +70,64 @@ type SocksRemoteConfig struct {
} }
type SocksClientConfig struct { type SocksClientConfig struct {
Servers []*SocksRemoteConfig `json:"servers"` Address *Address `json:"address"`
Port uint16 `json:"port"`
Level uint32 `json:"level"`
Email string `json:"email"`
Username string `json:"user"`
Password string `json:"pass"`
Servers []*SocksRemoteConfig `json:"servers"`
} }
func (v *SocksClientConfig) Build() (proto.Message, error) { func (v *SocksClientConfig) Build() (proto.Message, error) {
config := new(socks.ClientConfig) config := new(socks.ClientConfig)
config.Server = make([]*protocol.ServerEndpoint, len(v.Servers)) if v.Address != nil {
for idx, serverConfig := range v.Servers { v.Servers = []*SocksRemoteConfig{
{
Address: v.Address,
Port: v.Port,
},
}
if len(v.Username) > 0 {
v.Servers[0].Users = []json.RawMessage{{}}
}
}
if len(v.Servers) != 1 {
return nil, errors.New(`SOCKS settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple SOCKS outbounds and routing balancer instead`)
}
for _, serverConfig := range v.Servers {
if len(serverConfig.Users) > 1 {
return nil, errors.New(`SOCKS servers: "users" should have one member at most. Multiple members in "users" should use multiple SOCKS outbounds and routing balancer instead`)
}
server := &protocol.ServerEndpoint{ server := &protocol.ServerEndpoint{
Address: serverConfig.Address.Build(), Address: serverConfig.Address.Build(),
Port: uint32(serverConfig.Port), Port: uint32(serverConfig.Port),
} }
for _, rawUser := range serverConfig.Users { for _, rawUser := range serverConfig.Users {
user := new(protocol.User) user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil { if v.Address != nil {
return nil, errors.New("failed to parse Socks user").Base(err).AtError() user.Level = v.Level
user.Email = v.Email
} else {
if err := json.Unmarshal(rawUser, user); err != nil {
return nil, errors.New("failed to parse Socks user").Base(err).AtError()
}
} }
account := new(SocksAccount) account := new(SocksAccount)
if err := json.Unmarshal(rawUser, account); err != nil { if v.Address != nil {
return nil, errors.New("failed to parse socks account").Base(err).AtError() account.Username = v.Username
account.Password = v.Password
} else {
if err := json.Unmarshal(rawUser, account); err != nil {
return nil, errors.New("failed to parse socks account").Base(err).AtError()
}
} }
user.Account = serial.ToTypedMessage(account.Build()) user.Account = serial.ToTypedMessage(account.Build())
server.User = append(server.User, user) server.User = user
break
} }
config.Server[idx] = server config.Server = server
break
} }
return config, nil return config, nil
} }
+38 -15
View File
@@ -65,24 +65,47 @@ func TestSocksOutboundConfig(t *testing.T) {
}`, }`,
Parser: loadJSON(creator), Parser: loadJSON(creator),
Output: &socks.ClientConfig{ Output: &socks.ClientConfig{
Server: []*protocol.ServerEndpoint{ Server: &protocol.ServerEndpoint{
{ Address: &net.IPOrDomain{
Address: &net.IPOrDomain{ Address: &net.IPOrDomain_Ip{
Address: &net.IPOrDomain_Ip{ Ip: []byte{127, 0, 0, 1},
Ip: []byte{127, 0, 0, 1},
},
}, },
Port: 1234, },
User: []*protocol.User{ Port: 1234,
{ User: &protocol.User{
Email: "test@email.com", Email: "test@email.com",
Account: serial.ToTypedMessage(&socks.Account{ Account: serial.ToTypedMessage(&socks.Account{
Username: "test user", Username: "test user",
Password: "test pass", Password: "test pass",
}), }),
}, },
},
},
},
{
Input: `{
"address": "127.0.0.1",
"port": 1234,
"user": "test user",
"pass": "test pass",
"email": "test@email.com"
}`,
Parser: loadJSON(creator),
Output: &socks.ClientConfig{
Server: &protocol.ServerEndpoint{
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
}, },
}, },
Port: 1234,
User: &protocol.User{
Email: "test@email.com",
Account: serial.ToTypedMessage(&socks.Account{
Username: "test user",
Password: "test pass",
}),
},
}, },
}, },
}, },
+34 -18
View File
@@ -20,28 +20,44 @@ import (
type TrojanServerTarget struct { type TrojanServerTarget struct {
Address *Address `json:"address"` Address *Address `json:"address"`
Port uint16 `json:"port"` Port uint16 `json:"port"`
Password string `json:"password"`
Email string `json:"email"`
Level byte `json:"level"` Level byte `json:"level"`
Email string `json:"email"`
Password string `json:"password"`
Flow string `json:"flow"` Flow string `json:"flow"`
} }
// TrojanClientConfig is configuration of trojan servers // TrojanClientConfig is configuration of trojan servers
type TrojanClientConfig struct { type TrojanClientConfig struct {
Servers []*TrojanServerTarget `json:"servers"` Address *Address `json:"address"`
Port uint16 `json:"port"`
Level byte `json:"level"`
Email string `json:"email"`
Password string `json:"password"`
Flow string `json:"flow"`
Servers []*TrojanServerTarget `json:"servers"`
} }
// Build implements Buildable // Build implements Buildable
func (c *TrojanClientConfig) Build() (proto.Message, error) { func (c *TrojanClientConfig) Build() (proto.Message, error) {
if len(c.Servers) == 0 { if c.Address != nil {
return nil, errors.New("0 Trojan server configured.") c.Servers = []*TrojanServerTarget{
{
Address: c.Address,
Port: c.Port,
Level: c.Level,
Email: c.Email,
Password: c.Password,
Flow: c.Flow,
},
}
}
if len(c.Servers) != 1 {
return nil, errors.New(`Trojan settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple Trojan outbounds and routing balancer instead`)
} }
config := &trojan.ClientConfig{ config := &trojan.ClientConfig{}
Server: make([]*protocol.ServerEndpoint, len(c.Servers)),
}
for idx, rec := range c.Servers { for _, rec := range c.Servers {
if rec.Address == nil { if rec.Address == nil {
return nil, errors.New("Trojan server address is not set.") return nil, errors.New("Trojan server address is not set.")
} }
@@ -55,19 +71,19 @@ func (c *TrojanClientConfig) Build() (proto.Message, error) {
return nil, errors.PrintRemovedFeatureError(`Flow for Trojan`, ``) return nil, errors.PrintRemovedFeatureError(`Flow for Trojan`, ``)
} }
config.Server[idx] = &protocol.ServerEndpoint{ config.Server = &protocol.ServerEndpoint{
Address: rec.Address.Build(), Address: rec.Address.Build(),
Port: uint32(rec.Port), Port: uint32(rec.Port),
User: []*protocol.User{ User: &protocol.User{
{ Level: uint32(rec.Level),
Level: uint32(rec.Level), Email: rec.Email,
Email: rec.Email, Account: serial.ToTypedMessage(&trojan.Account{
Account: serial.ToTypedMessage(&trojan.Account{ Password: rec.Password,
Password: rec.Password, }),
}),
},
}, },
} }
break
} }
return config, nil return config, nil
+53 -15
View File
@@ -77,6 +77,10 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
return nil, errors.New(`VLESS clients: "encryption" should not be in inbound settings`) return nil, errors.New(`VLESS clients: "encryption" should not be in inbound settings`)
} }
if account.Reverse != nil && account.Reverse.Tag == "" {
return nil, errors.New(`VLESS clients: "tag" can't be empty for "reverse"`)
}
user.Account = serial.ToTypedMessage(account) user.Account = serial.ToTypedMessage(account)
config.Clients[idx] = user config.Clients[idx] = user
} }
@@ -199,37 +203,65 @@ type VLessOutboundVnext struct {
} }
type VLessOutboundConfig struct { type VLessOutboundConfig struct {
Vnext []*VLessOutboundVnext `json:"vnext"` Address *Address `json:"address"`
Port uint16 `json:"port"`
Level uint32 `json:"level"`
Email string `json:"email"`
Id string `json:"id"`
Flow string `json:"flow"`
Seed string `json:"seed"`
Encryption string `json:"encryption"`
Reverse *vless.Reverse `json:"reverse"`
Vnext []*VLessOutboundVnext `json:"vnext"`
} }
// Build implements Buildable // Build implements Buildable
func (c *VLessOutboundConfig) Build() (proto.Message, error) { func (c *VLessOutboundConfig) Build() (proto.Message, error) {
config := new(outbound.Config) config := new(outbound.Config)
if c.Address != nil {
if len(c.Vnext) != 1 { c.Vnext = []*VLessOutboundVnext{
return nil, errors.New(`VLESS settings: "vnext" should have one and only one member`) {
Address: c.Address,
Port: c.Port,
Users: []json.RawMessage{{}},
},
}
} }
config.Vnext = make([]*protocol.ServerEndpoint, len(c.Vnext)) if len(c.Vnext) != 1 {
for idx, rec := range c.Vnext { return nil, errors.New(`VLESS settings: "vnext" should have one and only one member. Multiple endpoints in "vnext" should use multiple VLESS outbounds and routing balancer instead`)
}
for _, rec := range c.Vnext {
if rec.Address == nil { if rec.Address == nil {
return nil, errors.New(`VLESS vnext: "address" is not set`) return nil, errors.New(`VLESS vnext: "address" is not set`)
} }
if len(rec.Users) != 1 { if len(rec.Users) != 1 {
return nil, errors.New(`VLESS vnext: "users" should have one and only one member`) return nil, errors.New(`VLESS vnext: "users" should have one and only one member. Multiple members in "users" should use multiple VLESS outbounds and routing balancer instead`)
} }
spec := &protocol.ServerEndpoint{ spec := &protocol.ServerEndpoint{
Address: rec.Address.Build(), Address: rec.Address.Build(),
Port: uint32(rec.Port), Port: uint32(rec.Port),
User: make([]*protocol.User, len(rec.Users)),
} }
for idx, rawUser := range rec.Users { for _, rawUser := range rec.Users {
user := new(protocol.User) user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil { if c.Address != nil {
return nil, errors.New(`VLESS users: invalid user`).Base(err) user.Level = c.Level
user.Email = c.Email
} else {
if err := json.Unmarshal(rawUser, user); err != nil {
return nil, errors.New(`VLESS users: invalid user`).Base(err)
}
} }
account := new(vless.Account) account := new(vless.Account)
if err := json.Unmarshal(rawUser, account); err != nil { if c.Address != nil {
return nil, errors.New(`VLESS users: invalid user`).Base(err) account.Id = c.Id
account.Flow = c.Flow
//account.Seed = c.Seed
account.Encryption = c.Encryption
account.Reverse = c.Reverse
} else {
if err := json.Unmarshal(rawUser, account); err != nil {
return nil, errors.New(`VLESS users: invalid user`).Base(err)
}
} }
u, err := uuid.ParseString(account.Id) u, err := uuid.ParseString(account.Id)
@@ -288,10 +320,16 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
return nil, errors.New(`VLESS users: unsupported "encryption": ` + account.Encryption) return nil, errors.New(`VLESS users: unsupported "encryption": ` + account.Encryption)
} }
if account.Reverse != nil && account.Reverse.Tag == "" {
return nil, errors.New(`VLESS clients: "tag" can't be empty for "reverse"`)
}
user.Account = serial.ToTypedMessage(account) user.Account = serial.ToTypedMessage(account)
spec.User[idx] = user spec.User = user
break
} }
config.Vnext[idx] = spec config.Vnext = spec
break
} }
return config, nil return config, nil
+41 -16
View File
@@ -35,25 +35,50 @@ func TestVLessOutbound(t *testing.T) {
}`, }`,
Parser: loadJSON(creator), Parser: loadJSON(creator),
Output: &outbound.Config{ Output: &outbound.Config{
Vnext: []*protocol.ServerEndpoint{ Vnext: &protocol.ServerEndpoint{
{ Address: &net.IPOrDomain{
Address: &net.IPOrDomain{ Address: &net.IPOrDomain_Domain{
Address: &net.IPOrDomain_Domain{ Domain: "example.com",
Domain: "example.com",
},
}, },
Port: 443, },
User: []*protocol.User{ Port: 443,
{ User: &protocol.User{
Account: serial.ToTypedMessage(&vless.Account{ Account: serial.ToTypedMessage(&vless.Account{
Id: "27848739-7e62-4138-9fd3-098a63964b6b", Id: "27848739-7e62-4138-9fd3-098a63964b6b",
Flow: "xtls-rprx-vision-udp443", Flow: "xtls-rprx-vision-udp443",
Encryption: "none", Encryption: "none",
}), }),
Level: 0, Level: 0,
}, },
},
},
},
{
Input: `{
"address": "example.com",
"port": 443,
"id": "27848739-7e62-4138-9fd3-098a63964b6b",
"flow": "xtls-rprx-vision-udp443",
"encryption": "none",
"level": 0
}`,
Parser: loadJSON(creator),
Output: &outbound.Config{
Vnext: &protocol.ServerEndpoint{
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Domain{
Domain: "example.com",
}, },
}, },
Port: 443,
User: &protocol.User{
Account: serial.ToTypedMessage(&vless.Account{
Id: "27848739-7e62-4138-9fd3-098a63964b6b",
Flow: "xtls-rprx-vision-udp443",
Encryption: "none",
}),
Level: 0,
},
}, },
}, },
}, },
+42 -32
View File
@@ -46,17 +46,6 @@ func (a *VMessAccount) Build() *vmess.Account {
} }
} }
type VMessDetourConfig struct {
ToTag string `json:"to"`
}
// Build implements Buildable
func (c *VMessDetourConfig) Build() *inbound.DetourConfig {
return &inbound.DetourConfig{
To: c.ToTag,
}
}
type VMessDefaultConfig struct { type VMessDefaultConfig struct {
Level byte `json:"level"` Level byte `json:"level"`
} }
@@ -71,7 +60,6 @@ func (c *VMessDefaultConfig) Build() *inbound.DefaultConfig {
type VMessInboundConfig struct { type VMessInboundConfig struct {
Users []json.RawMessage `json:"clients"` Users []json.RawMessage `json:"clients"`
Defaults *VMessDefaultConfig `json:"default"` Defaults *VMessDefaultConfig `json:"default"`
DetourConfig *VMessDetourConfig `json:"detour"`
} }
// Build implements Buildable // Build implements Buildable
@@ -82,10 +70,6 @@ func (c *VMessInboundConfig) Build() (proto.Message, error) {
config.Default = c.Defaults.Build() config.Default = c.Defaults.Build()
} }
if c.DetourConfig != nil {
config.Detour = c.DetourConfig.Build()
}
config.User = make([]*protocol.User, len(c.Users)) config.User = make([]*protocol.User, len(c.Users))
for idx, rawData := range c.Users { for idx, rawData := range c.Users {
user := new(protocol.User) user := new(protocol.User)
@@ -117,23 +101,37 @@ type VMessOutboundTarget struct {
} }
type VMessOutboundConfig struct { type VMessOutboundConfig struct {
Receivers []*VMessOutboundTarget `json:"vnext"` Address *Address `json:"address"`
Port uint16 `json:"port"`
Level uint32 `json:"level"`
Email string `json:"email"`
ID string `json:"id"`
Security string `json:"security"`
Experiments string `json:"experiments"`
Receivers []*VMessOutboundTarget `json:"vnext"`
} }
// Build implements Buildable // Build implements Buildable
func (c *VMessOutboundConfig) Build() (proto.Message, error) { func (c *VMessOutboundConfig) Build() (proto.Message, error) {
config := new(outbound.Config) config := new(outbound.Config)
if c.Address != nil {
if len(c.Receivers) == 0 { c.Receivers = []*VMessOutboundTarget{
return nil, errors.New("0 VMess receiver configured") {
Address: c.Address,
Port: c.Port,
Users: []json.RawMessage{{}},
},
}
} }
serverSpecs := make([]*protocol.ServerEndpoint, len(c.Receivers)) if len(c.Receivers) != 1 {
for idx, rec := range c.Receivers { return nil, errors.New(`VMess settings: "vnext" should have one and only one member. Multiple endpoints in "vnext" should use multiple VMess outbounds and routing balancer instead`)
if len(rec.Users) == 0 { }
return nil, errors.New("0 user configured for VMess outbound") for _, rec := range c.Receivers {
if len(rec.Users) != 1 {
return nil, errors.New(`VMess vnext: "users" should have one and only one member. Multiple members in "users" should use multiple VMess outbounds and routing balancer instead`)
} }
if rec.Address == nil { if rec.Address == nil {
return nil, errors.New("address is not set in VMess outbound config") return nil, errors.New(`VMess vnext: "address" is not set`)
} }
spec := &protocol.ServerEndpoint{ spec := &protocol.ServerEndpoint{
Address: rec.Address.Build(), Address: rec.Address.Build(),
@@ -141,12 +139,23 @@ func (c *VMessOutboundConfig) Build() (proto.Message, error) {
} }
for _, rawUser := range rec.Users { for _, rawUser := range rec.Users {
user := new(protocol.User) user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil { if c.Address != nil {
return nil, errors.New("invalid VMess user").Base(err) user.Level = c.Level
user.Email = c.Email
} else {
if err := json.Unmarshal(rawUser, user); err != nil {
return nil, errors.New("invalid VMess user").Base(err)
}
} }
account := new(VMessAccount) account := new(VMessAccount)
if err := json.Unmarshal(rawUser, account); err != nil { if c.Address != nil {
return nil, errors.New("invalid VMess user").Base(err) account.ID = c.ID
account.Security = c.Security
account.Experiments = c.Experiments
} else {
if err := json.Unmarshal(rawUser, account); err != nil {
return nil, errors.New("invalid VMess user").Base(err)
}
} }
u, err := uuid.ParseString(account.ID) u, err := uuid.ParseString(account.ID)
@@ -156,10 +165,11 @@ func (c *VMessOutboundConfig) Build() (proto.Message, error) {
account.ID = u.String() account.ID = u.String()
user.Account = serial.ToTypedMessage(account.Build()) user.Account = serial.ToTypedMessage(account.Build())
spec.User = append(spec.User, user) spec.User = user
break
} }
serverSpecs[idx] = spec config.Receiver = spec
break
} }
config.Receiver = serverSpecs
return config, nil return config, nil
} }
+44 -25
View File
@@ -34,27 +34,53 @@ func TestVMessOutbound(t *testing.T) {
}`, }`,
Parser: loadJSON(creator), Parser: loadJSON(creator),
Output: &outbound.Config{ Output: &outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: &net.IPOrDomain{
Address: &net.IPOrDomain{ Address: &net.IPOrDomain_Ip{
Address: &net.IPOrDomain_Ip{ Ip: []byte{127, 0, 0, 1},
Ip: []byte{127, 0, 0, 1},
},
}, },
Port: 80, },
User: []*protocol.User{ Port: 80,
{ User: &protocol.User{
Email: "love@example.com", Email: "love@example.com",
Level: 255, Level: 255,
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
Id: "e641f5ad-9397-41e3-bf1a-e8740dfed019", Id: "e641f5ad-9397-41e3-bf1a-e8740dfed019",
SecuritySettings: &protocol.SecurityConfig{ SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AUTO, Type: protocol.SecurityType_AUTO,
},
}),
}, },
}),
},
},
},
},
{
Input: `{
"address": "127.0.0.1",
"port": 80,
"id": "e641f5ad-9397-41e3-bf1a-e8740dfed019",
"email": "love@example.com",
"level": 255
}`,
Parser: loadJSON(creator),
Output: &outbound.Config{
Receiver: &protocol.ServerEndpoint{
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
}, },
}, },
Port: 80,
User: &protocol.User{
Email: "love@example.com",
Level: 255,
Account: serial.ToTypedMessage(&vmess.Account{
Id: "e641f5ad-9397-41e3-bf1a-e8740dfed019",
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AUTO,
},
}),
},
}, },
}, },
}, },
@@ -79,11 +105,7 @@ func TestVMessInbound(t *testing.T) {
], ],
"default": { "default": {
"level": 0 "level": 0
}, }
"detour": {
"to": "tag_to_detour"
},
"disableInsecureEncryption": true
}`, }`,
Parser: loadJSON(creator), Parser: loadJSON(creator),
Output: &inbound.Config{ Output: &inbound.Config{
@@ -102,9 +124,6 @@ func TestVMessInbound(t *testing.T) {
Default: &inbound.DefaultConfig{ Default: &inbound.DefaultConfig{
Level: 0, Level: 0,
}, },
Detour: &inbound.DetourConfig{
To: "tag_to_detour",
},
}, },
}, },
}) })
-60
View File
@@ -3,7 +3,6 @@ package conf
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"fmt"
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
@@ -120,47 +119,12 @@ func (m *MuxConfig) Build() (*proxyman.MultiplexingConfig, error) {
}, nil }, nil
} }
type InboundDetourAllocationConfig struct {
Strategy string `json:"strategy"`
Concurrency *uint32 `json:"concurrency"`
RefreshMin *uint32 `json:"refresh"`
}
// Build implements Buildable.
func (c *InboundDetourAllocationConfig) Build() (*proxyman.AllocationStrategy, error) {
config := new(proxyman.AllocationStrategy)
switch strings.ToLower(c.Strategy) {
case "always":
config.Type = proxyman.AllocationStrategy_Always
case "random":
config.Type = proxyman.AllocationStrategy_Random
case "external":
config.Type = proxyman.AllocationStrategy_External
default:
return nil, errors.New("unknown allocation strategy: ", c.Strategy)
}
if c.Concurrency != nil {
config.Concurrency = &proxyman.AllocationStrategy_AllocationStrategyConcurrency{
Value: *c.Concurrency,
}
}
if c.RefreshMin != nil {
config.Refresh = &proxyman.AllocationStrategy_AllocationStrategyRefresh{
Value: *c.RefreshMin,
}
}
return config, nil
}
type InboundDetourConfig struct { type InboundDetourConfig struct {
Protocol string `json:"protocol"` Protocol string `json:"protocol"`
PortList *PortList `json:"port"` PortList *PortList `json:"port"`
ListenOn *Address `json:"listen"` ListenOn *Address `json:"listen"`
Settings *json.RawMessage `json:"settings"` Settings *json.RawMessage `json:"settings"`
Tag string `json:"tag"` Tag string `json:"tag"`
Allocation *InboundDetourAllocationConfig `json:"allocate"`
StreamSetting *StreamConfig `json:"streamSettings"` StreamSetting *StreamConfig `json:"streamSettings"`
SniffingConfig *SniffingConfig `json:"sniffing"` SniffingConfig *SniffingConfig `json:"sniffing"`
} }
@@ -197,30 +161,6 @@ func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
} }
} }
if c.Allocation != nil {
concurrency := -1
if c.Allocation.Concurrency != nil && c.Allocation.Strategy == "random" {
concurrency = int(*c.Allocation.Concurrency)
}
portRange := 0
for _, pr := range c.PortList.Range {
portRange += int(pr.To - pr.From + 1)
}
if concurrency >= 0 && concurrency >= portRange {
var ports strings.Builder
for _, pr := range c.PortList.Range {
fmt.Fprintf(&ports, "%d-%d ", pr.From, pr.To)
}
return nil, errors.New("not enough ports. concurrency = ", concurrency, " ports: ", ports.String())
}
as, err := c.Allocation.Build()
if err != nil {
return nil, err
}
receiverSettings.AllocationStrategy = as
}
if c.StreamSetting != nil { if c.StreamSetting != nil {
ss, err := c.StreamSetting.Build() ss, err := c.StreamSetting.Build()
if err != nil { if err != nil {
-10
View File
@@ -58,10 +58,6 @@ func TestXrayConfig(t *testing.T) {
}, },
"protocol": "vmess", "protocol": "vmess",
"port": "443-500", "port": "443-500",
"allocate": {
"strategy": "random",
"concurrency": 3
},
"settings": { "settings": {
"clients": [ "clients": [
{ {
@@ -123,12 +119,6 @@ func TestXrayConfig(t *testing.T) {
From: 443, From: 443,
To: 500, To: 500,
}}}, }}},
AllocationStrategy: &proxyman.AllocationStrategy{
Type: proxyman.AllocationStrategy_Random,
Concurrency: &proxyman.AllocationStrategy_AllocationStrategyConcurrency{
Value: 3,
},
},
StreamSettings: &internet.StreamConfig{ StreamSettings: &internet.StreamConfig{
ProtocolName: "websocket", ProtocolName: "websocket",
TransportSettings: []*internet.TransportConfig{ TransportSettings: []*internet.TransportConfig{
+1 -1
View File
@@ -92,7 +92,7 @@ func executePing(cmd *base.Command, args []string) {
fmt.Println("-------------------") fmt.Println("-------------------")
fmt.Println("Pinging with SNI") fmt.Println("Pinging with 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 { if err != nil {
base.Fatalf("Failed to dial tcp: %s", err) base.Fatalf("Failed to dial tcp: %s", err)
} }
+10 -16
View File
@@ -31,7 +31,7 @@ import (
) )
type Client struct { type Client struct {
serverPicker protocol.ServerPicker server *protocol.ServerSpec
policyManager policy.Manager policyManager policy.Manager
header []*Header header []*Header
} }
@@ -48,21 +48,17 @@ var (
// NewClient create a new http client based on the given config. // NewClient create a new http client based on the given config.
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) { func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
serverList := protocol.NewServerList() if config.Server == nil {
for _, rec := range config.Server { return nil, errors.New(`no target server found`)
s, err := protocol.NewServerSpecFromPB(rec)
if err != nil {
return nil, errors.New("failed to get server spec").Base(err)
}
serverList.AddServer(s)
} }
if serverList.Size() == 0 { server, err := protocol.NewServerSpecFromPB(config.Server)
return nil, errors.New("0 target server") if err != nil {
return nil, errors.New("failed to get server spec").Base(err)
} }
v := core.MustFromContext(ctx) v := core.MustFromContext(ctx)
return &Client{ return &Client{
serverPicker: protocol.NewRoundRobinServerPicker(serverList), server: server,
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
header: config.Header, header: config.Header,
}, nil }, nil
@@ -84,7 +80,9 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
return errors.New("UDP is not supported by HTTP outbound") return errors.New("UDP is not supported by HTTP outbound")
} }
var user *protocol.MemoryUser server := c.server
dest := server.Destination
user := server.User
var conn stat.Connection var conn stat.Connection
mbuf, _ := link.Reader.ReadMultiBuffer() mbuf, _ := link.Reader.ReadMultiBuffer()
@@ -102,10 +100,6 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
} }
if err := retry.ExponentialBackoff(5, 100).On(func() error { if err := retry.ExponentialBackoff(5, 100).On(func() error {
server := c.serverPicker.PickServer()
dest := server.Destination()
user = server.PickUser()
netConn, err := setUpHTTPTunnel(ctx, dest, targetAddr, user, dialer, header, firstPayload) netConn, err := setUpHTTPTunnel(ctx, dest, targetAddr, user, dialer, header, firstPayload)
if netConn != nil { if netConn != nil {
if _, ok := netConn.(*http2Conn); !ok { if _, ok := netConn.(*http2Conn); !ok {
+4 -4
View File
@@ -196,8 +196,8 @@ type ClientConfig struct {
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// Sever is a list of HTTP server addresses. // Sever is a list of HTTP server addresses.
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"` Server *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
Header []*Header `protobuf:"bytes,2,rep,name=header,proto3" json:"header,omitempty"` Header []*Header `protobuf:"bytes,2,rep,name=header,proto3" json:"header,omitempty"`
} }
func (x *ClientConfig) Reset() { func (x *ClientConfig) Reset() {
@@ -230,7 +230,7 @@ func (*ClientConfig) Descriptor() ([]byte, []int) {
return file_proxy_http_config_proto_rawDescGZIP(), []int{3} return file_proxy_http_config_proto_rawDescGZIP(), []int{3}
} }
func (x *ClientConfig) GetServer() []*protocol.ServerEndpoint { func (x *ClientConfig) GetServer() *protocol.ServerEndpoint {
if x != nil { if x != nil {
return x.Server return x.Server
} }
@@ -275,7 +275,7 @@ var file_proxy_http_config_proto_rawDesc = []byte{
0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x7d, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x7d, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18,
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72,
0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x76, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20,
+1 -1
View File
@@ -28,6 +28,6 @@ message Header {
// ClientConfig is the protobuf config for HTTP proxy client. // ClientConfig is the protobuf config for HTTP proxy client.
message ClientConfig { message ClientConfig {
// Sever is a list of HTTP server addresses. // Sever is a list of HTTP server addresses.
repeated xray.common.protocol.ServerEndpoint server = 1; xray.common.protocol.ServerEndpoint server = 1;
repeated Header header = 2; repeated Header header = 2;
} }
+3 -3
View File
@@ -678,10 +678,10 @@ func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net
errors.LogInfo(ctx, "CopyRawConn splice") errors.LogInfo(ctx, "CopyRawConn splice")
statWriter, _ := writer.(*dispatcher.SizeStatWriter) statWriter, _ := writer.(*dispatcher.SizeStatWriter)
//runtime.Gosched() // necessary //runtime.Gosched() // necessary
time.Sleep(time.Millisecond) // without this, there will be a rare ssl error for freedom splice time.Sleep(time.Millisecond) // without this, there will be a rare ssl error for freedom splice
timer.SetTimeout(8 * time.Hour) // prevent leak, just in case timer.SetTimeout(24 * time.Hour) // prevent leak, just in case
if inTimer != nil { if inTimer != nil {
inTimer.SetTimeout(8 * time.Hour) inTimer.SetTimeout(24 * time.Hour)
} }
w, err := tc.ReadFrom(readerConn) w, err := tc.ReadFrom(readerConn)
if readCounter != nil { if readCounter != nil {
+12 -17
View File
@@ -22,27 +22,23 @@ import (
// Client is a inbound handler for Shadowsocks protocol // Client is a inbound handler for Shadowsocks protocol
type Client struct { type Client struct {
serverPicker protocol.ServerPicker server *protocol.ServerSpec
policyManager policy.Manager policyManager policy.Manager
} }
// NewClient create a new Shadowsocks client. // NewClient create a new Shadowsocks client.
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) { func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
serverList := protocol.NewServerList() if config.Server == nil {
for _, rec := range config.Server { return nil, errors.New(`no target server found`)
s, err := protocol.NewServerSpecFromPB(rec)
if err != nil {
return nil, errors.New("failed to parse server spec").Base(err)
}
serverList.AddServer(s)
} }
if serverList.Size() == 0 { server, err := protocol.NewServerSpecFromPB(config.Server)
return nil, errors.New("0 server") if err != nil {
return nil, errors.New("failed to get server spec").Base(err)
} }
v := core.MustFromContext(ctx) v := core.MustFromContext(ctx)
client := &Client{ client := &Client{
serverPicker: protocol.NewRoundRobinServerPicker(serverList), server: server,
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
} }
return client, nil return client, nil
@@ -60,13 +56,12 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
destination := ob.Target destination := ob.Target
network := destination.Network network := destination.Network
var server *protocol.ServerSpec server := c.server
dest := server.Destination
dest.Network = network
var conn stat.Connection var conn stat.Connection
err := retry.ExponentialBackoff(5, 100).On(func() error { err := retry.ExponentialBackoff(5, 100).On(func() error {
server = c.serverPicker.PickServer()
dest := server.Destination()
dest.Network = network
rawConn, err := dialer.Dial(ctx, dest) rawConn, err := dialer.Dial(ctx, dest)
if err != nil { if err != nil {
return err return err
@@ -78,7 +73,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
if err != nil { if err != nil {
return errors.New("failed to find an available destination").AtWarning().Base(err) return errors.New("failed to find an available destination").AtWarning().Base(err)
} }
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", network, ":", server.Destination().NetAddr()) errors.LogInfo(ctx, "tunneling request to ", destination, " via ", network, ":", server.Destination.NetAddr())
defer conn.Close() defer conn.Close()
@@ -93,7 +88,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
request.Command = protocol.RequestCommandUDP request.Command = protocol.RequestCommandUDP
} }
user := server.PickUser() user := server.User
_, ok := user.Account.(*MemoryAccount) _, ok := user.Account.(*MemoryAccount)
if !ok { if !ok {
return errors.New("user account is not valid") return errors.New("user account is not valid")
+3 -3
View File
@@ -199,7 +199,7 @@ type ClientConfig struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"` Server *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
} }
func (x *ClientConfig) Reset() { func (x *ClientConfig) Reset() {
@@ -232,7 +232,7 @@ func (*ClientConfig) Descriptor() ([]byte, []int) {
return file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{2} return file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{2}
} }
func (x *ClientConfig) GetServer() []*protocol.ServerEndpoint { func (x *ClientConfig) GetServer() *protocol.ServerEndpoint {
if x != nil { if x != nil {
return x.Server return x.Server
} }
@@ -268,7 +268,7 @@ var file_proxy_shadowsocks_config_proto_rawDesc = []byte{
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e,
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22,
0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64,
0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2a, 0x74, 0x0a, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2a, 0x74, 0x0a,
+1 -1
View File
@@ -32,5 +32,5 @@ message ServerConfig {
} }
message ClientConfig { message ClientConfig {
repeated xray.common.protocol.ServerEndpoint server = 1; xray.common.protocol.ServerEndpoint server = 1;
} }
+10 -17
View File
@@ -22,27 +22,23 @@ import (
// Client is a Socks5 client. // Client is a Socks5 client.
type Client struct { type Client struct {
serverPicker protocol.ServerPicker server *protocol.ServerSpec
policyManager policy.Manager policyManager policy.Manager
} }
// NewClient create a new Socks5 client based on the given config. // NewClient create a new Socks5 client based on the given config.
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) { func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
serverList := protocol.NewServerList() if config.Server == nil {
for _, rec := range config.Server { return nil, errors.New(`no target server found`)
s, err := protocol.NewServerSpecFromPB(rec)
if err != nil {
return nil, errors.New("failed to get server spec").Base(err)
}
serverList.AddServer(s)
} }
if serverList.Size() == 0 { server, err := protocol.NewServerSpecFromPB(config.Server)
return nil, errors.New("0 target server") if err != nil {
return nil, errors.New("failed to get server spec").Base(err)
} }
v := core.MustFromContext(ctx) v := core.MustFromContext(ctx)
c := &Client{ c := &Client{
serverPicker: protocol.NewRoundRobinServerPicker(serverList), server: server,
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
} }
@@ -62,15 +58,12 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
destination := ob.Target destination := ob.Target
// Outbound server. // Outbound server.
var server *protocol.ServerSpec server := c.server
// Outbound server's destination. dest := server.Destination
var dest net.Destination
// Connection to the outbound server. // Connection to the outbound server.
var conn stat.Connection var conn stat.Connection
if err := retry.ExponentialBackoff(5, 100).On(func() error { if err := retry.ExponentialBackoff(5, 100).On(func() error {
server = c.serverPicker.PickServer()
dest = server.Destination()
rawConn, err := dialer.Dial(ctx, dest) rawConn, err := dialer.Dial(ctx, dest)
if err != nil { if err != nil {
return err return err
@@ -101,7 +94,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
request.Command = protocol.RequestCommandUDP request.Command = protocol.RequestCommandUDP
} }
user := server.PickUser() user := server.User
if user != nil { if user != nil {
request.User = user request.User = user
p = c.policyManager.ForLevel(user.Level) p = c.policyManager.ForLevel(user.Level)
+3 -3
View File
@@ -210,7 +210,7 @@ type ClientConfig struct {
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// Sever is a list of Socks server addresses. // Sever is a list of Socks server addresses.
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"` Server *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
} }
func (x *ClientConfig) Reset() { func (x *ClientConfig) Reset() {
@@ -243,7 +243,7 @@ func (*ClientConfig) Descriptor() ([]byte, []int) {
return file_proxy_socks_config_proto_rawDescGZIP(), []int{2} return file_proxy_socks_config_proto_rawDescGZIP(), []int{2}
} }
func (x *ClientConfig) GetServer() []*protocol.ServerEndpoint { func (x *ClientConfig) GetServer() *protocol.ServerEndpoint {
if x != nil { if x != nil {
return x.Server return x.Server
} }
@@ -286,7 +286,7 @@ var file_proxy_socks_config_proto_rawDesc = []byte{
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x3a, 0x02, 0x38, 0x01, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76,
0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2a, 0x25, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x65, 0x72, 0x2a, 0x25, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b,
+1 -1
View File
@@ -35,5 +35,5 @@ message ServerConfig {
// ClientConfig is the protobuf config for Socks client. // ClientConfig is the protobuf config for Socks client.
message ClientConfig { message ClientConfig {
// Sever is a list of Socks server addresses. // Sever is a list of Socks server addresses.
repeated xray.common.protocol.ServerEndpoint server = 1; xray.common.protocol.ServerEndpoint server = 1;
} }
+11 -16
View File
@@ -22,27 +22,23 @@ import (
// Client is a inbound handler for trojan protocol // Client is a inbound handler for trojan protocol
type Client struct { type Client struct {
serverPicker protocol.ServerPicker server *protocol.ServerSpec
policyManager policy.Manager policyManager policy.Manager
} }
// NewClient create a new trojan client. // NewClient create a new trojan client.
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) { func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
serverList := protocol.NewServerList() if config.Server == nil {
for _, rec := range config.Server { return nil, errors.New(`no target server found`)
s, err := protocol.NewServerSpecFromPB(rec)
if err != nil {
return nil, errors.New("failed to parse server spec").Base(err)
}
serverList.AddServer(s)
} }
if serverList.Size() == 0 { server, err := protocol.NewServerSpecFromPB(config.Server)
return nil, errors.New("0 server") if err != nil {
return nil, errors.New("failed to get server spec").Base(err)
} }
v := core.MustFromContext(ctx) v := core.MustFromContext(ctx)
client := &Client{ client := &Client{
serverPicker: protocol.NewRoundRobinServerPicker(serverList), server: server,
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
} }
return client, nil return client, nil
@@ -60,12 +56,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
destination := ob.Target destination := ob.Target
network := destination.Network network := destination.Network
var server *protocol.ServerSpec server := c.server
var conn stat.Connection var conn stat.Connection
err := retry.ExponentialBackoff(5, 100).On(func() error { err := retry.ExponentialBackoff(5, 100).On(func() error {
server = c.serverPicker.PickServer() rawConn, err := dialer.Dial(ctx, server.Destination)
rawConn, err := dialer.Dial(ctx, server.Destination())
if err != nil { if err != nil {
return err return err
} }
@@ -76,11 +71,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
if err != nil { if err != nil {
return errors.New("failed to find an available destination").AtWarning().Base(err) return errors.New("failed to find an available destination").AtWarning().Base(err)
} }
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", server.Destination().NetAddr()) errors.LogInfo(ctx, "tunneling request to ", destination, " via ", server.Destination.NetAddr())
defer conn.Close() defer conn.Close()
user := server.PickUser() user := server.User
account, ok := user.Account.(*MemoryAccount) account, ok := user.Account.(*MemoryAccount)
if !ok { if !ok {
return errors.New("user account is not valid") return errors.New("user account is not valid")
+3 -3
View File
@@ -156,7 +156,7 @@ type ClientConfig struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"` Server *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
} }
func (x *ClientConfig) Reset() { func (x *ClientConfig) Reset() {
@@ -189,7 +189,7 @@ func (*ClientConfig) Descriptor() ([]byte, []int) {
return file_proxy_trojan_config_proto_rawDescGZIP(), []int{2} return file_proxy_trojan_config_proto_rawDescGZIP(), []int{2}
} }
func (x *ClientConfig) GetServer() []*protocol.ServerEndpoint { func (x *ClientConfig) GetServer() *protocol.ServerEndpoint {
if x != nil { if x != nil {
return x.Server return x.Server
} }
@@ -271,7 +271,7 @@ var file_proxy_trojan_config_proto_rawDesc = []byte{
0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x06, 0x20, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x06, 0x20,
0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52,
0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x7b, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x7b, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65,
+1 -1
View File
@@ -23,7 +23,7 @@ message Fallback {
} }
message ClientConfig { message ClientConfig {
repeated xray.common.protocol.ServerEndpoint server = 1; xray.common.protocol.ServerEndpoint server = 1;
} }
message ServerConfig { message ServerConfig {
+4
View File
@@ -21,6 +21,7 @@ func (a *Account) AsAccount() (protocol.Account, error) {
XorMode: a.XorMode, XorMode: a.XorMode,
Seconds: a.Seconds, Seconds: a.Seconds,
Padding: a.Padding, Padding: a.Padding,
Reverse: a.Reverse,
}, nil }, nil
} }
@@ -35,6 +36,8 @@ type MemoryAccount struct {
XorMode uint32 XorMode uint32
Seconds uint32 Seconds uint32
Padding string Padding string
Reverse *Reverse
} }
// Equals implements protocol.Account.Equals(). // Equals implements protocol.Account.Equals().
@@ -54,5 +57,6 @@ func (a *MemoryAccount) ToProto() proto.Message {
XorMode: a.XorMode, XorMode: a.XorMode,
Seconds: a.Seconds, Seconds: a.Seconds,
Padding: a.Padding, Padding: a.Padding,
Reverse: a.Reverse,
} }
} }
+93 -33
View File
@@ -20,6 +20,51 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
) )
type Reverse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
}
func (x *Reverse) Reset() {
*x = Reverse{}
mi := &file_proxy_vless_account_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Reverse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Reverse) ProtoMessage() {}
func (x *Reverse) ProtoReflect() protoreflect.Message {
mi := &file_proxy_vless_account_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Reverse.ProtoReflect.Descriptor instead.
func (*Reverse) Descriptor() ([]byte, []int) {
return file_proxy_vless_account_proto_rawDescGZIP(), []int{0}
}
func (x *Reverse) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
type Account struct { type Account struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -28,16 +73,17 @@ type Account struct {
// ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57". // ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
// Flow settings. May be "xtls-rprx-vision". // Flow settings. May be "xtls-rprx-vision".
Flow string `protobuf:"bytes,2,opt,name=flow,proto3" json:"flow,omitempty"` Flow string `protobuf:"bytes,2,opt,name=flow,proto3" json:"flow,omitempty"`
Encryption string `protobuf:"bytes,3,opt,name=encryption,proto3" json:"encryption,omitempty"` Encryption string `protobuf:"bytes,3,opt,name=encryption,proto3" json:"encryption,omitempty"`
XorMode uint32 `protobuf:"varint,4,opt,name=xorMode,proto3" json:"xorMode,omitempty"` XorMode uint32 `protobuf:"varint,4,opt,name=xorMode,proto3" json:"xorMode,omitempty"`
Seconds uint32 `protobuf:"varint,5,opt,name=seconds,proto3" json:"seconds,omitempty"` Seconds uint32 `protobuf:"varint,5,opt,name=seconds,proto3" json:"seconds,omitempty"`
Padding string `protobuf:"bytes,6,opt,name=padding,proto3" json:"padding,omitempty"` Padding string `protobuf:"bytes,6,opt,name=padding,proto3" json:"padding,omitempty"`
Reverse *Reverse `protobuf:"bytes,7,opt,name=reverse,proto3" json:"reverse,omitempty"`
} }
func (x *Account) Reset() { func (x *Account) Reset() {
*x = Account{} *x = Account{}
mi := &file_proxy_vless_account_proto_msgTypes[0] mi := &file_proxy_vless_account_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -49,7 +95,7 @@ func (x *Account) String() string {
func (*Account) ProtoMessage() {} func (*Account) ProtoMessage() {}
func (x *Account) ProtoReflect() protoreflect.Message { func (x *Account) ProtoReflect() protoreflect.Message {
mi := &file_proxy_vless_account_proto_msgTypes[0] mi := &file_proxy_vless_account_proto_msgTypes[1]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -62,7 +108,7 @@ func (x *Account) ProtoReflect() protoreflect.Message {
// Deprecated: Use Account.ProtoReflect.Descriptor instead. // Deprecated: Use Account.ProtoReflect.Descriptor instead.
func (*Account) Descriptor() ([]byte, []int) { func (*Account) Descriptor() ([]byte, []int) {
return file_proxy_vless_account_proto_rawDescGZIP(), []int{0} return file_proxy_vless_account_proto_rawDescGZIP(), []int{1}
} }
func (x *Account) GetId() string { func (x *Account) GetId() string {
@@ -107,28 +153,40 @@ func (x *Account) GetPadding() string {
return "" return ""
} }
func (x *Account) GetReverse() *Reverse {
if x != nil {
return x.Reverse
}
return nil
}
var File_proxy_vless_account_proto protoreflect.FileDescriptor var File_proxy_vless_account_proto protoreflect.FileDescriptor
var file_proxy_vless_account_proto_rawDesc = []byte{ var file_proxy_vless_account_proto_rawDesc = []byte{
0x0a, 0x19, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x61, 0x63, 0x0a, 0x19, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x61, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x22, 0x9b, 0x01, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x22, 0x1b, 0x0a,
0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x07, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x6f, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0xd0, 0x01, 0x0a, 0x07, 0x41,
0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1e, 0x0a, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02,
0x09, 0x52, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x6e,
0x07, 0x78, 0x6f, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
0x78, 0x6f, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x78, 0x6f,
0x64, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x78, 0x6f, 0x72,
0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18,
0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x42, 0x52, 0x0a, 0x14, 0x63, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x18,
0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
0x65, 0x73, 0x73, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x33, 0x0a, 0x07, 0x72, 0x65, 0x76, 0x65,
0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x72, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0xaa, 0x02, 0x10, 0x58, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x52, 0x65, 0x76,
0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x62, 0x65, 0x72, 0x73, 0x65, 0x52, 0x07, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x42, 0x52, 0x0a,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
0x76, 0x6c, 0x65, 0x73, 0x73, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f,
0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0xaa, 0x02,
0x10, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73,
0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@@ -143,16 +201,18 @@ func file_proxy_vless_account_proto_rawDescGZIP() []byte {
return file_proxy_vless_account_proto_rawDescData return file_proxy_vless_account_proto_rawDescData
} }
var file_proxy_vless_account_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_proxy_vless_account_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_proxy_vless_account_proto_goTypes = []any{ var file_proxy_vless_account_proto_goTypes = []any{
(*Account)(nil), // 0: xray.proxy.vless.Account (*Reverse)(nil), // 0: xray.proxy.vless.Reverse
(*Account)(nil), // 1: xray.proxy.vless.Account
} }
var file_proxy_vless_account_proto_depIdxs = []int32{ var file_proxy_vless_account_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type 0, // 0: xray.proxy.vless.Account.reverse:type_name -> xray.proxy.vless.Reverse
0, // [0:0] is the sub-list for method input_type 1, // [1:1] is the sub-list for method output_type
0, // [0:0] is the sub-list for extension type_name 1, // [1:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension extendee 1, // [1:1] is the sub-list for extension type_name
0, // [0:0] is the sub-list for field type_name 1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
} }
func init() { file_proxy_vless_account_proto_init() } func init() { file_proxy_vless_account_proto_init() }
@@ -166,7 +226,7 @@ func file_proxy_vless_account_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_vless_account_proto_rawDesc, RawDescriptor: file_proxy_vless_account_proto_rawDesc,
NumEnums: 0, NumEnums: 0,
NumMessages: 1, NumMessages: 2,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },
+6
View File
@@ -6,6 +6,10 @@ option go_package = "github.com/xtls/xray-core/proxy/vless";
option java_package = "com.xray.proxy.vless"; option java_package = "com.xray.proxy.vless";
option java_multiple_files = true; option java_multiple_files = true;
message Reverse {
string tag = 1;
}
message Account { message Account {
// ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57". // ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
string id = 1; string id = 1;
@@ -16,4 +20,6 @@ message Account {
uint32 xorMode = 4; uint32 xorMode = 4;
uint32 seconds = 5; uint32 seconds = 5;
string padding = 6; string padding = 6;
Reverse reverse = 7;
} }
+3 -2
View File
@@ -46,7 +46,7 @@ func EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requ
return errors.New("failed to write request command").Base(err) return errors.New("failed to write request command").Base(err)
} }
if request.Command != protocol.RequestCommandMux { if request.Command != protocol.RequestCommandMux && request.Command != protocol.RequestCommandRvs {
if err := addrParser.WriteAddressPort(&buffer, request.Address, request.Port); err != nil { if err := addrParser.WriteAddressPort(&buffer, request.Address, request.Port); err != nil {
return errors.New("failed to write request address and port").Base(err) return errors.New("failed to write request address and port").Base(err)
} }
@@ -112,7 +112,8 @@ func DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validat
switch request.Command { switch request.Command {
case protocol.RequestCommandMux: case protocol.RequestCommandMux:
request.Address = net.DomainAddress("v1.mux.cool") request.Address = net.DomainAddress("v1.mux.cool")
request.Port = 0 case protocol.RequestCommandRvs:
request.Address = net.DomainAddress("v1.rvs.cool")
case protocol.RequestCommandTCP, protocol.RequestCommandUDP: case protocol.RequestCommandTCP, protocol.RequestCommandUDP:
if addr, port, err := addrParser.ReadAddressPort(&buffer, reader); err == nil { if addr, port, err := addrParser.ReadAddressPort(&buffer, reader); err == nil {
request.Address = addr request.Address = addr
+123 -11
View File
@@ -12,19 +12,24 @@ import (
"time" "time"
"unsafe" "unsafe"
"github.com/xtls/xray-core/app/dispatcher"
"github.com/xtls/xray-core/app/reverse"
"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"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/mux"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/retry" "github.com/xtls/xray-core/common/retry"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal" "github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
feature_inbound "github.com/xtls/xray-core/features/inbound" feature_inbound "github.com/xtls/xray-core/features/inbound"
"github.com/xtls/xray-core/features/outbound"
"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/proxy" "github.com/xtls/xray-core/proxy"
@@ -66,12 +71,14 @@ func init() {
// Handler is an inbound connection handler that handles messages in VLess protocol. // Handler is an inbound connection handler that handles messages in VLess protocol.
type Handler struct { type Handler struct {
inboundHandlerManager feature_inbound.Manager inboundHandlerManager feature_inbound.Manager
policyManager policy.Manager policyManager policy.Manager
validator vless.Validator validator vless.Validator
dns dns.Client decryption *encryption.ServerInstance
decryption *encryption.ServerInstance outboundHandlerManager outbound.Manager
fallbacks map[string]map[string]map[string]*Fallback // or nil defaultDispatcher *dispatcher.DefaultDispatcher
ctx context.Context
fallbacks map[string]map[string]map[string]*Fallback // or nil
// regexps map[string]*regexp.Regexp // or nil // regexps map[string]*regexp.Regexp // or nil
} }
@@ -79,10 +86,12 @@ type Handler struct {
func New(ctx context.Context, config *Config, dc dns.Client, validator vless.Validator) (*Handler, error) { func New(ctx context.Context, config *Config, dc dns.Client, validator vless.Validator) (*Handler, error) {
v := core.MustFromContext(ctx) v := core.MustFromContext(ctx)
handler := &Handler{ handler := &Handler{
inboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager), inboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
dns: dc, validator: validator,
validator: validator, outboundHandlerManager: v.GetFeature(outbound.ManagerType()).(outbound.Manager),
defaultDispatcher: v.GetFeature(routing.DispatcherType()).(*dispatcher.DefaultDispatcher),
ctx: ctx,
} }
if config.Decryption != "" && config.Decryption != "none" { if config.Decryption != "" && config.Decryption != "none" {
@@ -174,11 +183,49 @@ func isMuxAndNotXUDP(request *protocol.RequestHeader, first *buf.Buffer) bool {
firstBytes[6] == 2) // Network type: UDP firstBytes[6] == 2) // Network type: UDP
} }
func (h *Handler) GetReverse(a *vless.MemoryAccount) (*Reverse, error) {
u := h.validator.Get(a.ID.UUID())
if u == nil {
return nil, errors.New("reverse: user " + a.ID.String() + " doesn't exist anymore")
}
a = u.Account.(*vless.MemoryAccount)
if a.Reverse == nil || a.Reverse.Tag == "" {
return nil, errors.New("reverse: user " + a.ID.String() + " is not allowed to create reverse proxy")
}
r := h.outboundHandlerManager.GetHandler(a.Reverse.Tag)
if r == nil {
picker, _ := reverse.NewStaticMuxPicker()
r = &Reverse{tag: a.Reverse.Tag, picker: picker, client: &mux.ClientManager{Picker: picker}}
for len(h.outboundHandlerManager.ListHandlers(h.ctx)) == 0 {
time.Sleep(time.Second) // prevents this outbound from becoming the default outbound
}
if err := h.outboundHandlerManager.AddHandler(h.ctx, r); err != nil {
return nil, err
}
}
if r, ok := r.(*Reverse); ok {
return r, nil
}
return nil, errors.New("reverse: outbound " + a.Reverse.Tag + " is not type Reverse")
}
func (h *Handler) RemoveReverse(u *protocol.MemoryUser) {
if u != nil {
a := u.Account.(*vless.MemoryAccount)
if a.Reverse != nil && a.Reverse.Tag != "" {
h.outboundHandlerManager.RemoveHandler(h.ctx, a.Reverse.Tag)
}
}
}
// Close implements common.Closable.Close(). // Close implements common.Closable.Close().
func (h *Handler) Close() error { func (h *Handler) Close() error {
if h.decryption != nil { if h.decryption != nil {
h.decryption.Close() h.decryption.Close()
} }
for _, u := range h.validator.GetAll() {
h.RemoveReverse(u)
}
return errors.Combine(common.Close(h.validator)) return errors.Combine(common.Close(h.validator))
} }
@@ -189,6 +236,7 @@ func (h *Handler) AddUser(ctx context.Context, u *protocol.MemoryUser) error {
// RemoveUser implements proxy.UserManager.RemoveUser(). // RemoveUser implements proxy.UserManager.RemoveUser().
func (h *Handler) RemoveUser(ctx context.Context, e string) error { func (h *Handler) RemoveUser(ctx context.Context, e string) error {
h.RemoveReverse(h.validator.GetByEmail(e))
return h.validator.Del(e) return h.validator.Del(e)
} }
@@ -500,7 +548,8 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
switch request.Command { switch request.Command {
case protocol.RequestCommandUDP: case protocol.RequestCommandUDP:
return errors.New(requestAddons.Flow + " doesn't support UDP").AtWarning() return errors.New(requestAddons.Flow + " doesn't support UDP").AtWarning()
case protocol.RequestCommandMux: case protocol.RequestCommandMux, protocol.RequestCommandRvs:
inbound.CanSpliceCopy = 3
fallthrough // we will break Mux connections that contain TCP requests fallthrough // we will break Mux connections that contain TCP requests
case protocol.RequestCommandTCP: case protocol.RequestCommandTCP:
var t reflect.Type var t reflect.Type
@@ -565,6 +614,14 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, false, ctx, connection, nil) clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, false, ctx, connection, nil)
bufferWriter.SetFlushNext() bufferWriter.SetFlushNext()
if request.Command == protocol.RequestCommandRvs {
r, err := h.GetReverse(account)
if err != nil {
return err
}
return r.NewMux(ctx, h.defaultDispatcher.WrapLink(ctx, &transport.Link{Reader: clientReader, Writer: clientWriter}))
}
if err := dispatcher.DispatchLink(ctx, request.Destination(), &transport.Link{ if err := dispatcher.DispatchLink(ctx, request.Destination(), &transport.Link{
Reader: clientReader, Reader: clientReader,
Writer: clientWriter}, Writer: clientWriter},
@@ -573,3 +630,58 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
} }
return nil return nil
} }
type Reverse struct {
tag string
picker *reverse.StaticMuxPicker
client *mux.ClientManager
}
func (r *Reverse) Tag() string {
return r.tag
}
func (r *Reverse) NewMux(ctx context.Context, link *transport.Link) error {
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
if err != nil {
return errors.New("failed to create mux client worker").Base(err).AtWarning()
}
worker, err := reverse.NewPortalWorker(muxClient)
if err != nil {
return errors.New("failed to create portal worker").Base(err).AtWarning()
}
r.picker.AddWorker(worker)
select {
case <-ctx.Done():
case <-muxClient.WaitClosed():
}
return nil
}
func (r *Reverse) Dispatch(ctx context.Context, link *transport.Link) {
outbounds := session.OutboundsFromContext(ctx)
ob := outbounds[len(outbounds)-1]
if ob != nil {
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil && ob.OriginalTarget.Address != ob.Target.Address {
link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
}
r.client.Dispatch(ctx, link)
}
}
func (r *Reverse) Start() error {
return nil
}
func (r *Reverse) Close() error {
return nil
}
func (r *Reverse) SenderSettings() *serial.TypedMessage {
return nil
}
func (r *Reverse) ProxySettings() *serial.TypedMessage {
return nil
}
+3 -3
View File
@@ -26,7 +26,7 @@ type Config struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Vnext []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=vnext,proto3" json:"vnext,omitempty"` Vnext *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=vnext,proto3" json:"vnext,omitempty"`
} }
func (x *Config) Reset() { func (x *Config) Reset() {
@@ -59,7 +59,7 @@ func (*Config) Descriptor() ([]byte, []int) {
return file_proxy_vless_outbound_config_proto_rawDescGZIP(), []int{0} return file_proxy_vless_outbound_config_proto_rawDescGZIP(), []int{0}
} }
func (x *Config) GetVnext() []*protocol.ServerEndpoint { func (x *Config) GetVnext() *protocol.ServerEndpoint {
if x != nil { if x != nil {
return x.Vnext return x.Vnext
} }
@@ -76,7 +76,7 @@ var file_proxy_vless_outbound_config_proto_rawDesc = []byte{
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x22, 0x44, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x6f, 0x22, 0x44, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3a, 0x0a, 0x05, 0x76,
0x6e, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x6e, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
0x52, 0x05, 0x76, 0x6e, 0x65, 0x78, 0x74, 0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x52, 0x05, 0x76, 0x6e, 0x65, 0x78, 0x74, 0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
+1 -1
View File
@@ -9,5 +9,5 @@ option java_multiple_files = true;
import "common/protocol/server_spec.proto"; import "common/protocol/server_spec.proto";
message Config { message Config {
repeated xray.common.protocol.ServerEndpoint vnext = 1; xray.common.protocol.ServerEndpoint vnext = 1;
} }
+120 -20
View File
@@ -11,9 +11,12 @@ import (
"unsafe" "unsafe"
utls "github.com/refraction-networking/utls" utls "github.com/refraction-networking/utls"
proxyman "github.com/xtls/xray-core/app/proxyman/outbound"
"github.com/xtls/xray-core/app/reverse"
"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"
"github.com/xtls/xray-core/common/mux"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/retry" "github.com/xtls/xray-core/common/retry"
@@ -23,6 +26,7 @@ import (
"github.com/xtls/xray-core/common/xudp" "github.com/xtls/xray-core/common/xudp"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/proxy" "github.com/xtls/xray-core/proxy"
"github.com/xtls/xray-core/proxy/vless" "github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/proxy/vless/encoding" "github.com/xtls/xray-core/proxy/vless/encoding"
@@ -32,6 +36,7 @@ import (
"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" "github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/pipe"
) )
func init() { func init() {
@@ -42,33 +47,31 @@ func init() {
// Handler is an outbound connection handler for VLess protocol. // Handler is an outbound connection handler for VLess protocol.
type Handler struct { type Handler struct {
serverList *protocol.ServerList server *protocol.ServerSpec
serverPicker protocol.ServerPicker
policyManager policy.Manager policyManager policy.Manager
cone bool cone bool
encryption *encryption.ClientInstance encryption *encryption.ClientInstance
reverse *Reverse
} }
// New creates a new VLess outbound handler. // New creates a new VLess outbound handler.
func New(ctx context.Context, config *Config) (*Handler, error) { func New(ctx context.Context, config *Config) (*Handler, error) {
serverList := protocol.NewServerList() if config.Vnext == nil {
for _, rec := range config.Vnext { return nil, errors.New(`no vnext found`)
s, err := protocol.NewServerSpecFromPB(rec) }
if err != nil { server, err := protocol.NewServerSpecFromPB(config.Vnext)
return nil, errors.New("failed to parse server spec").Base(err).AtError() if err != nil {
} return nil, errors.New("failed to get server spec").Base(err).AtError()
serverList.AddServer(s)
} }
v := core.MustFromContext(ctx) v := core.MustFromContext(ctx)
handler := &Handler{ handler := &Handler{
serverList: serverList, server: server,
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
cone: ctx.Value("cone").(bool), cone: ctx.Value("cone").(bool),
} }
a := handler.serverPicker.PickServer().PickUser().Account.(*vless.MemoryAccount) a := handler.server.User.Account.(*vless.MemoryAccount)
if a.Encryption != "" && a.Encryption != "none" { if a.Encryption != "" && a.Encryption != "none" {
s := strings.Split(a.Encryption, ".") s := strings.Split(a.Encryption, ".")
var nfsPKeysBytes [][]byte var nfsPKeysBytes [][]byte
@@ -82,24 +85,49 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
} }
} }
if a.Reverse != nil {
handler.reverse = &Reverse{
tag: a.Reverse.Tag,
dispatcher: v.GetFeature(routing.DispatcherType()).(routing.Dispatcher),
ctx: ctx,
handler: handler,
}
handler.reverse.monitorTask = &task.Periodic{
Execute: handler.reverse.monitor,
Interval: time.Second * 2,
}
go func() {
time.Sleep(2 * time.Second)
handler.reverse.Start()
}()
}
return handler, nil return handler, nil
} }
// Close implements common.Closable.Close().
func (h *Handler) Close() error {
if h.reverse != nil {
return h.reverse.Close()
}
return nil
}
// Process implements proxy.Outbound.Process(). // Process implements proxy.Outbound.Process().
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error { func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
outbounds := session.OutboundsFromContext(ctx) outbounds := session.OutboundsFromContext(ctx)
ob := outbounds[len(outbounds)-1] ob := outbounds[len(outbounds)-1]
if !ob.Target.IsValid() { if !ob.Target.IsValid() && ob.Target.Address.String() != "v1.rvs.cool" {
return errors.New("target not specified").AtError() return errors.New("target not specified").AtError()
} }
ob.Name = "vless" ob.Name = "vless"
var rec *protocol.ServerSpec rec := h.server
var conn stat.Connection var conn stat.Connection
if err := retry.ExponentialBackoff(5, 200).On(func() error { if err := retry.ExponentialBackoff(5, 200).On(func() error {
rec = h.serverPicker.PickServer()
var err error var err error
conn, err = dialer.Dial(ctx, rec.Destination()) conn, err = dialer.Dial(ctx, rec.Destination)
if err != nil { if err != nil {
return err return err
} }
@@ -114,7 +142,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
iConn = statConn.Connection iConn = statConn.Connection
} }
target := ob.Target target := ob.Target
errors.LogInfo(ctx, "tunneling request to ", target, " via ", rec.Destination().NetAddr()) errors.LogInfo(ctx, "tunneling request to ", target, " via ", rec.Destination.NetAddr())
if h.encryption != nil { if h.encryption != nil {
var err error var err error
@@ -127,13 +155,21 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
if target.Network == net.Network_UDP { if target.Network == net.Network_UDP {
command = protocol.RequestCommandUDP command = protocol.RequestCommandUDP
} }
if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.cool" { if target.Address.Family().IsDomain() {
command = protocol.RequestCommandMux switch target.Address.Domain() {
case "v1.mux.cool":
command = protocol.RequestCommandMux
case "v1.rvs.cool":
if target.Network != net.Network_Unknown {
return errors.New("nice try baby").AtError()
}
command = protocol.RequestCommandRvs
}
} }
request := &protocol.RequestHeader{ request := &protocol.RequestHeader{
Version: encoding.Version, Version: encoding.Version,
User: rec.PickUser(), User: rec.User,
Command: command, Command: command,
Address: target.Address, Address: target.Address,
Port: target.Port, Port: target.Port,
@@ -321,3 +357,67 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return nil return nil
} }
type Reverse struct {
tag string
dispatcher routing.Dispatcher
ctx context.Context
handler *Handler
workers []*reverse.BridgeWorker
monitorTask *task.Periodic
}
func (r *Reverse) monitor() error {
var activeWorkers []*reverse.BridgeWorker
for _, w := range r.workers {
if w.IsActive() {
activeWorkers = append(activeWorkers, w)
}
}
if len(activeWorkers) != len(r.workers) {
r.workers = activeWorkers
}
var numConnections uint32
var numWorker uint32
for _, w := range r.workers {
if w.IsActive() {
numConnections += w.Connections()
numWorker++
}
}
if numWorker == 0 || numConnections/numWorker > 16 {
reader1, writer1 := pipe.New(pipe.WithSizeLimit(2 * buf.Size))
reader2, writer2 := pipe.New(pipe.WithSizeLimit(2 * buf.Size))
link1 := &transport.Link{Reader: reader1, Writer: writer2}
link2 := &transport.Link{Reader: reader2, Writer: writer1}
w := &reverse.BridgeWorker{
Tag: r.tag,
Dispatcher: r.dispatcher,
}
worker, err := mux.NewServerWorker(r.ctx, w, link1)
if err != nil {
errors.LogWarningInner(r.ctx, err, "failed to create mux server worker")
return nil
}
w.Worker = worker
r.workers = append(r.workers, w)
go func() {
ctx := session.ContextWithOutbounds(r.ctx, []*session.Outbound{{
Target: net.Destination{Address: net.DomainAddress("v1.rvs.cool")},
}})
r.handler.Process(ctx, link2, session.HandlerFromContext(ctx).(*proxyman.Handler))
common.Interrupt(reader1)
common.Interrupt(reader2)
}()
}
return nil
}
func (r *Reverse) Start() error {
return r.monitorTask.Start()
}
func (r *Reverse) Close() error {
return r.monitorTask.Close()
}
+6 -4
View File
@@ -17,8 +17,10 @@ import (
) )
var ( var (
ErrNotFound = errors.New("user do not exist") ErrNotFound = errors.New("user do not exist")
ErrReplay = errors.New("replayed request") ErrNeagtiveTime = errors.New("timestamp is negative")
ErrInvalidTime = errors.New("invalid timestamp, perhaps unsynchronized time")
ErrReplay = errors.New("replayed request")
) )
func CreateAuthID(cmdKey []byte, time int64) [16]byte { func CreateAuthID(cmdKey []byte, time int64) [16]byte {
@@ -102,11 +104,11 @@ func (a *AuthIDDecoderHolder) Match(authID [16]byte) (interface{}, error) {
} }
if t < 0 { if t < 0 {
continue return nil, ErrNeagtiveTime
} }
if math.Abs(math.Abs(float64(t))-float64(time.Now().Unix())) > 120 { if math.Abs(math.Abs(float64(t))-float64(time.Now().Unix())) > 120 {
continue return nil, ErrInvalidTime
} }
if !a.filter.Check(authID[:]) { if !a.filter.Check(authID[:]) {
-72
View File
@@ -7,10 +7,7 @@ import (
"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"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/uuid"
) )
var ( var (
@@ -29,9 +26,6 @@ func MarshalCommand(command interface{}, writer io.Writer) error {
var cmdID byte var cmdID byte
var factory CommandFactory var factory CommandFactory
switch command.(type) { switch command.(type) {
case *protocol.CommandSwitchAccount:
factory = new(CommandSwitchAccountFactory)
cmdID = 1
default: default:
return ErrUnknownCommand return ErrUnknownCommand
} }
@@ -67,8 +61,6 @@ func UnmarshalCommand(cmdID byte, data []byte) (protocol.ResponseCommand, error)
var factory CommandFactory var factory CommandFactory
switch cmdID { switch cmdID {
case 1:
factory = new(CommandSwitchAccountFactory)
default: default:
return nil, ErrUnknownCommand return nil, ErrUnknownCommand
} }
@@ -79,67 +71,3 @@ type CommandFactory interface {
Marshal(command interface{}, writer io.Writer) error Marshal(command interface{}, writer io.Writer) error
Unmarshal(data []byte) (interface{}, error) Unmarshal(data []byte) (interface{}, error)
} }
type CommandSwitchAccountFactory struct{}
func (f *CommandSwitchAccountFactory) Marshal(command interface{}, writer io.Writer) error {
cmd, ok := command.(*protocol.CommandSwitchAccount)
if !ok {
return ErrCommandTypeMismatch
}
hostStr := ""
if cmd.Host != nil {
hostStr = cmd.Host.String()
}
common.Must2(writer.Write([]byte{byte(len(hostStr))}))
if len(hostStr) > 0 {
common.Must2(writer.Write([]byte(hostStr)))
}
common.Must2(serial.WriteUint16(writer, cmd.Port.Value()))
idBytes := cmd.ID.Bytes()
common.Must2(writer.Write(idBytes))
common.Must2(serial.WriteUint16(writer, 0)) // compatible with legacy alterId
common.Must2(writer.Write([]byte{byte(cmd.Level)}))
common.Must2(writer.Write([]byte{cmd.ValidMin}))
return nil
}
func (f *CommandSwitchAccountFactory) Unmarshal(data []byte) (interface{}, error) {
cmd := new(protocol.CommandSwitchAccount)
if len(data) == 0 {
return nil, ErrInsufficientLength
}
lenHost := int(data[0])
if len(data) < lenHost+1 {
return nil, ErrInsufficientLength
}
if lenHost > 0 {
cmd.Host = net.ParseAddress(string(data[1 : 1+lenHost]))
}
portStart := 1 + lenHost
if len(data) < portStart+2 {
return nil, ErrInsufficientLength
}
cmd.Port = net.PortFromBytes(data[portStart : portStart+2])
idStart := portStart + 2
if len(data) < idStart+16 {
return nil, ErrInsufficientLength
}
cmd.ID, _ = uuid.ParseBytes(data[idStart : idStart+16])
levelStart := idStart + 16 + 2
if len(data) < levelStart+1 {
return nil, ErrInsufficientLength
}
cmd.Level = uint32(data[levelStart])
timeStart := levelStart + 1
if len(data) < timeStart+1 {
return nil, ErrInsufficientLength
}
cmd.ValidMin = data[timeStart]
return cmd, nil
}
-55
View File
@@ -1,55 +0,0 @@
package encoding_test
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/uuid"
. "github.com/xtls/xray-core/proxy/vmess/encoding"
)
func TestSwitchAccount(t *testing.T) {
sa := &protocol.CommandSwitchAccount{
Port: 1234,
ID: uuid.New(),
Level: 128,
ValidMin: 16,
}
buffer := buf.New()
common.Must(MarshalCommand(sa, buffer))
cmd, err := UnmarshalCommand(1, buffer.BytesFrom(2))
common.Must(err)
sa2, ok := cmd.(*protocol.CommandSwitchAccount)
if !ok {
t.Fatal("failed to convert command to CommandSwitchAccount")
}
if r := cmp.Diff(sa2, sa); r != "" {
t.Error(r)
}
}
func TestSwitchAccountBugOffByOne(t *testing.T) {
sa := &protocol.CommandSwitchAccount{
Port: 1234,
ID: uuid.New(),
Level: 128,
ValidMin: 16,
}
buffer := buf.New()
csaf := CommandSwitchAccountFactory{}
common.Must(csaf.Marshal(sa, buffer))
Payload := buffer.Bytes()
cmd, err := csaf.Unmarshal(Payload[:len(Payload)-1])
assert.Error(t, err)
assert.Nil(t, cmd)
}
+20 -34
View File
@@ -118,7 +118,6 @@ type Config struct {
User []*protocol.User `protobuf:"bytes,1,rep,name=user,proto3" json:"user,omitempty"` User []*protocol.User `protobuf:"bytes,1,rep,name=user,proto3" json:"user,omitempty"`
Default *DefaultConfig `protobuf:"bytes,2,opt,name=default,proto3" json:"default,omitempty"` Default *DefaultConfig `protobuf:"bytes,2,opt,name=default,proto3" json:"default,omitempty"`
Detour *DetourConfig `protobuf:"bytes,3,opt,name=detour,proto3" json:"detour,omitempty"` // 4 is for legacy setting
} }
func (x *Config) Reset() { func (x *Config) Reset() {
@@ -165,13 +164,6 @@ func (x *Config) GetDefault() *DefaultConfig {
return nil return nil
} }
func (x *Config) GetDetour() *DetourConfig {
if x != nil {
return x.Detour
}
return nil
}
var File_proxy_vmess_inbound_config_proto protoreflect.FileDescriptor var File_proxy_vmess_inbound_config_proto protoreflect.FileDescriptor
var file_proxy_vmess_inbound_config_proto_rawDesc = []byte{ var file_proxy_vmess_inbound_config_proto_rawDesc = []byte{
@@ -185,26 +177,21 @@ var file_proxy_vmess_inbound_config_proto_rawDesc = []byte{
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x22, 0x25, 0x0a, 0x0d, 0x44, 0x65, 0x66, 0x61, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x22, 0x25, 0x0a, 0x0d, 0x44, 0x65, 0x66, 0x61,
0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76,
0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22,
0xbb, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x04, 0x75, 0x73, 0x7b, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x04, 0x75, 0x73, 0x65,
0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55,
0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x07, 0x64, 0x65, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x07, 0x64, 0x65, 0x66,
0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61,
0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e,
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e,
0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x3e, 0x0a, 0x66, 0x69, 0x67, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x42, 0x6a, 0x0a, 0x1c,
0x06, 0x64, 0x65, 0x74, 0x6f, 0x75, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2d,
0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x74, 0x6f, 0x75, 0x72, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x64, 0x65, 0x74, 0x6f, 0x75, 0x72, 0x42, 0x6a, 0x0a, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f,
0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02, 0x18,
0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6d, 0x65, 0x73, 0x73,
0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79,
0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02,
0x18, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6d, 0x65, 0x73,
0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
} }
var ( var (
@@ -229,12 +216,11 @@ var file_proxy_vmess_inbound_config_proto_goTypes = []any{
var file_proxy_vmess_inbound_config_proto_depIdxs = []int32{ var file_proxy_vmess_inbound_config_proto_depIdxs = []int32{
3, // 0: xray.proxy.vmess.inbound.Config.user:type_name -> xray.common.protocol.User 3, // 0: xray.proxy.vmess.inbound.Config.user:type_name -> xray.common.protocol.User
1, // 1: xray.proxy.vmess.inbound.Config.default:type_name -> xray.proxy.vmess.inbound.DefaultConfig 1, // 1: xray.proxy.vmess.inbound.Config.default:type_name -> xray.proxy.vmess.inbound.DefaultConfig
0, // 2: xray.proxy.vmess.inbound.Config.detour:type_name -> xray.proxy.vmess.inbound.DetourConfig 2, // [2:2] is the sub-list for method output_type
3, // [3:3] is the sub-list for method output_type 2, // [2:2] is the sub-list for method input_type
3, // [3:3] is the sub-list for method input_type 2, // [2:2] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension type_name 2, // [2:2] is the sub-list for extension extendee
3, // [3:3] is the sub-list for extension extendee 0, // [0:2] is the sub-list for field type_name
0, // [0:3] is the sub-list for field type_name
} }
func init() { file_proxy_vmess_inbound_config_proto_init() } func init() { file_proxy_vmess_inbound_config_proto_init() }
-2
View File
@@ -19,6 +19,4 @@ message DefaultConfig {
message Config { message Config {
repeated xray.common.protocol.User user = 1; repeated xray.common.protocol.User user = 1;
DefaultConfig default = 2; DefaultConfig default = 2;
DetourConfig detour = 3;
// 4 is for legacy setting
} }
+17 -109
View File
@@ -14,8 +14,6 @@ import (
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/common/uuid" "github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
feature_inbound "github.com/xtls/xray-core/features/inbound" feature_inbound "github.com/xtls/xray-core/features/inbound"
@@ -23,6 +21,7 @@ import (
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/proxy/vmess" "github.com/xtls/xray-core/proxy/vmess"
"github.com/xtls/xray-core/proxy/vmess/encoding" "github.com/xtls/xray-core/proxy/vmess/encoding"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
) )
@@ -106,7 +105,6 @@ type Handler struct {
inboundHandlerManager feature_inbound.Manager inboundHandlerManager feature_inbound.Manager
clients *vmess.TimedUserValidator clients *vmess.TimedUserValidator
usersByEmail *userByEmail usersByEmail *userByEmail
detours *DetourConfig
sessionHistory *encoding.SessionHistory sessionHistory *encoding.SessionHistory
} }
@@ -117,7 +115,6 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
inboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager), inboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager),
clients: vmess.NewTimedUserValidator(), clients: vmess.NewTimedUserValidator(),
detours: config.Detour,
usersByEmail: newUserByEmail(config.GetDefaultValue()), usersByEmail: newUserByEmail(config.GetDefaultValue()),
sessionHistory: encoding.NewSessionHistory(), sessionHistory: encoding.NewSessionHistory(),
} }
@@ -186,44 +183,6 @@ func (h *Handler) RemoveUser(ctx context.Context, email string) error {
return nil return nil
} }
func transferResponse(timer signal.ActivityUpdater, session *encoding.ServerSession, request *protocol.RequestHeader, response *protocol.ResponseHeader, input buf.Reader, output *buf.BufferedWriter) error {
session.EncodeResponseHeader(response, output)
bodyWriter, err := session.EncodeResponseBody(request, output)
if err != nil {
return errors.New("failed to start decoding response").Base(err)
}
{
// Optimize for small response packet
data, err := input.ReadMultiBuffer()
if err != nil {
return err
}
if err := bodyWriter.WriteMultiBuffer(data); err != nil {
return err
}
}
if err := output.SetBuffered(false); err != nil {
return err
}
if err := buf.Copy(input, bodyWriter, buf.UpdateActivity(timer)); err != nil {
return err
}
account := request.User.Account.(*vmess.MemoryAccount)
if request.Option.Has(protocol.RequestOptionChunkStream) && !account.NoTerminationSignal {
if err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {
return err
}
}
return nil
}
// Process implements proxy.Inbound.Process(). // Process implements proxy.Inbound.Process().
func (h *Handler) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error { func (h *Handler) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
sessionPolicy := h.policyManager.ForLevel(0) sessionPolicy := h.policyManager.ForLevel(0)
@@ -277,84 +236,33 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
inbound.CanSpliceCopy = 3 inbound.CanSpliceCopy = 3
inbound.User = request.User inbound.User = request.User
sessionPolicy = h.policyManager.ForLevel(request.User.Level) bodyReader, err := svrSession.DecodeRequestBody(request, reader)
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)
link, err := dispatcher.Dispatch(ctx, request.Destination())
if err != nil { if err != nil {
return errors.New("failed to dispatch request to ", request.Destination()).Base(err) return errors.New("failed to start decoding").Base(err)
} }
requestDone := func() error { writer := buf.NewBufferedWriter(buf.NewWriter(connection))
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly) response := &protocol.ResponseHeader{
Command: h.generateCommand(ctx, request),
bodyReader, err := svrSession.DecodeRequestBody(request, reader)
if err != nil {
return errors.New("failed to start decoding").Base(err)
}
if err := buf.Copy(bodyReader, link.Writer, buf.UpdateActivity(timer)); err != nil {
return errors.New("failed to transfer request").Base(err)
}
return nil
} }
svrSession.EncodeResponseHeader(response, writer)
responseDone := func() error { bodyWriter, err := svrSession.EncodeResponseBody(request, writer)
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly) if err != nil {
return errors.New("failed to start decoding response").Base(err)
writer := buf.NewBufferedWriter(buf.NewWriter(connection))
defer writer.Flush()
response := &protocol.ResponseHeader{
Command: h.generateCommand(ctx, request),
}
return transferResponse(timer, svrSession, request, response, link.Reader, writer)
} }
writer.SetFlushNext()
requestDonePost := task.OnSuccess(requestDone, task.Close(link.Writer)) if err := dispatcher.DispatchLink(ctx, request.Destination(), &transport.Link{
if err := task.Run(ctx, requestDonePost, responseDone); err != nil { Reader: bodyReader,
common.Interrupt(link.Reader) Writer: bodyWriter},
common.Interrupt(link.Writer) ); err != nil {
return errors.New("connection ends").Base(err) return errors.New("failed to dispatch request").Base(err)
} }
return nil return nil
} }
// Stub command generator
func (h *Handler) generateCommand(ctx context.Context, request *protocol.RequestHeader) protocol.ResponseCommand { func (h *Handler) generateCommand(ctx context.Context, request *protocol.RequestHeader) protocol.ResponseCommand {
if h.detours != nil {
tag := h.detours.To
if h.inboundHandlerManager != nil {
handler, err := h.inboundHandlerManager.GetHandler(ctx, tag)
if err != nil {
errors.LogWarningInner(ctx, err, "failed to get detour handler: ", tag)
return nil
}
proxyHandler, port, availableMin := handler.GetRandomInboundProxy()
inboundHandler, ok := proxyHandler.(*Handler)
if ok && inboundHandler != nil {
if availableMin > 255 {
availableMin = 255
}
errors.LogDebug(ctx, "pick detour handler for port ", port, " for ", availableMin, " minutes.")
user := inboundHandler.GetOrGenerateUser(request.User.Email)
if user == nil {
return nil
}
account := user.Account.(*vmess.MemoryAccount)
return &protocol.CommandSwitchAccount{
Port: port,
ID: account.ID.UUID(),
Level: user.Level,
ValidMin: byte(availableMin),
}
}
}
}
return nil return nil
} }
+2 -29
View File
@@ -1,41 +1,14 @@
package outbound package outbound
import ( import (
"time"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/proxy/vmess"
) )
func (h *Handler) handleSwitchAccount(cmd *protocol.CommandSwitchAccount) { // As a stub command consumer.
rawAccount := &vmess.Account{
Id: cmd.ID.String(),
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AUTO,
},
}
account, err := rawAccount.AsAccount()
common.Must(err)
user := &protocol.MemoryUser{
Email: "",
Level: cmd.Level,
Account: account,
}
dest := net.TCPDestination(cmd.Host, cmd.Port)
until := time.Now().Add(time.Duration(cmd.ValidMin) * time.Minute)
h.serverList.AddServer(protocol.NewServerSpec(dest, protocol.BeforeTime(until), user))
}
func (h *Handler) handleCommand(dest net.Destination, cmd protocol.ResponseCommand) { func (h *Handler) handleCommand(dest net.Destination, cmd protocol.ResponseCommand) {
switch typedCommand := cmd.(type) { switch cmd.(type) {
case *protocol.CommandSwitchAccount:
if typedCommand.Host == nil {
typedCommand.Host = dest.Address
}
h.handleSwitchAccount(typedCommand)
default: default:
} }
} }
+3 -3
View File
@@ -26,7 +26,7 @@ type Config struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Receiver []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=Receiver,proto3" json:"Receiver,omitempty"` Receiver *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=Receiver,proto3" json:"Receiver,omitempty"`
} }
func (x *Config) Reset() { func (x *Config) Reset() {
@@ -59,7 +59,7 @@ func (*Config) Descriptor() ([]byte, []int) {
return file_proxy_vmess_outbound_config_proto_rawDescGZIP(), []int{0} return file_proxy_vmess_outbound_config_proto_rawDescGZIP(), []int{0}
} }
func (x *Config) GetReceiver() []*protocol.ServerEndpoint { func (x *Config) GetReceiver() *protocol.ServerEndpoint {
if x != nil { if x != nil {
return x.Receiver return x.Receiver
} }
@@ -76,7 +76,7 @@ var file_proxy_vmess_outbound_config_proto_rawDesc = []byte{
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x22, 0x4a, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x40, 0x0a, 0x08, 0x52, 0x6f, 0x22, 0x4a, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x40, 0x0a, 0x08, 0x52,
0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f,
0x69, 0x6e, 0x74, 0x52, 0x08, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x42, 0x6d, 0x0a, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x42, 0x6d, 0x0a,
+1 -1
View File
@@ -9,5 +9,5 @@ option java_multiple_files = true;
import "common/protocol/server_spec.proto"; import "common/protocol/server_spec.proto";
message Config { message Config {
repeated xray.common.protocol.ServerEndpoint Receiver = 1; xray.common.protocol.ServerEndpoint Receiver = 1;
} }
+14 -17
View File
@@ -29,27 +29,24 @@ import (
// Handler is an outbound connection handler for VMess protocol. // Handler is an outbound connection handler for VMess protocol.
type Handler struct { type Handler struct {
serverList *protocol.ServerList server *protocol.ServerSpec
serverPicker protocol.ServerPicker
policyManager policy.Manager policyManager policy.Manager
cone bool cone bool
} }
// New creates a new VMess outbound handler. // New creates a new VMess outbound handler.
func New(ctx context.Context, config *Config) (*Handler, error) { func New(ctx context.Context, config *Config) (*Handler, error) {
serverList := protocol.NewServerList() if config.Receiver == nil {
for _, rec := range config.Receiver { return nil, errors.New(`no vnext found`)
s, err := protocol.NewServerSpecFromPB(rec) }
if err != nil { server, err := protocol.NewServerSpecFromPB(config.Receiver)
return nil, errors.New("failed to parse server spec").Base(err) if err != nil {
} return nil, errors.New("failed to get server spec").Base(err)
serverList.AddServer(s)
} }
v := core.MustFromContext(ctx) v := core.MustFromContext(ctx)
handler := &Handler{ handler := &Handler{
serverList: serverList, server: server,
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
cone: ctx.Value("cone").(bool), cone: ctx.Value("cone").(bool),
} }
@@ -67,11 +64,11 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
ob.Name = "vmess" ob.Name = "vmess"
ob.CanSpliceCopy = 3 ob.CanSpliceCopy = 3
var rec *protocol.ServerSpec rec := h.server
var conn stat.Connection var conn stat.Connection
err := retry.ExponentialBackoff(5, 200).On(func() error { err := retry.ExponentialBackoff(5, 200).On(func() error {
rec = h.serverPicker.PickServer() rawConn, err := dialer.Dial(ctx, rec.Destination)
rawConn, err := dialer.Dial(ctx, rec.Destination())
if err != nil { if err != nil {
return err return err
} }
@@ -85,7 +82,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
defer conn.Close() defer conn.Close()
target := ob.Target target := ob.Target
errors.LogInfo(ctx, "tunneling request to ", target, " via ", rec.Destination().NetAddr()) errors.LogInfo(ctx, "tunneling request to ", target, " via ", rec.Destination.NetAddr())
command := protocol.RequestCommandTCP command := protocol.RequestCommandTCP
if target.Network == net.Network_UDP { if target.Network == net.Network_UDP {
@@ -95,7 +92,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
command = protocol.RequestCommandMux command = protocol.RequestCommandMux
} }
user := rec.PickUser() user := rec.User
request := &protocol.RequestHeader{ request := &protocol.RequestHeader{
Version: encoding.Version, Version: encoding.Version,
User: user, User: user,
@@ -202,7 +199,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
if err != nil { if err != nil {
return errors.New("failed to read header").Base(err) return errors.New("failed to read header").Base(err)
} }
h.handleCommand(rec.Destination(), header.Command) h.handleCommand(rec.Destination, header.Command)
bodyReader, err := session.DecodeResponseBody(request, reader) bodyReader, err := session.DecodeResponseBody(request, reader)
if err != nil { if err != nil {
+18 -26
View File
@@ -423,20 +423,16 @@ func TestCommanderAddRemoveUser(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: u2.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: u2.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
}, },
}, }),
}, },
}, },
}), }),
@@ -600,20 +596,16 @@ func TestCommanderStats(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
}, },
}, }),
}, },
}, },
}), }),
+14 -22
View File
@@ -94,17 +94,13 @@ func TestDokodemoTCP(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -190,17 +186,13 @@ func TestDokodemoUDP(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
+37 -57
View File
@@ -170,17 +170,13 @@ func TestProxy(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: serverUserID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: serverUserID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -193,17 +189,13 @@ func TestProxy(t *testing.T) {
{ {
Tag: "proxy", Tag: "proxy",
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(proxyPort),
Port: uint32(proxyPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: proxyUserID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: proxyUserID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -308,17 +300,13 @@ func TestProxyOverKCP(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: serverUserID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: serverUserID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -334,17 +322,13 @@ func TestProxyOverKCP(t *testing.T) {
{ {
Tag: "proxy", Tag: "proxy",
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(proxyPort),
Port: uint32(proxyPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: proxyUserID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: proxyUserID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -685,20 +669,16 @@ func TestDialXray(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
}, },
}, }),
}, },
}, },
}), }),
+18 -26
View File
@@ -119,20 +119,16 @@ func TestVMessClosing(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
}, },
}, }),
}, },
}, },
}), }),
@@ -223,20 +219,16 @@ func TestZeroBuffer(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
}, },
}, }),
}, },
}, },
}), }),
+18 -26
View File
@@ -155,20 +155,16 @@ func TestReverseProxy(t *testing.T) {
{ {
Tag: "reverse", Tag: "reverse",
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(reversePort),
Port: uint32(reversePort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
}, },
}, }),
}, },
}, },
}), }),
@@ -348,20 +344,16 @@ func TestReverseProxyLongRunning(t *testing.T) {
{ {
Tag: "reverse", Tag: "reverse",
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(reversePort),
Port: uint32(reversePort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
}, },
}, }),
}, },
}, },
}), }),
+25 -45
View File
@@ -75,15 +75,11 @@ func TestShadowsocksChaCha20Poly1305TCP(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{ ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
Server: []*protocol.ServerEndpoint{ Server: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: account,
{
Account: account,
},
},
}, },
}, },
}), }),
@@ -171,15 +167,11 @@ func TestShadowsocksAES256GCMTCP(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{ ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
Server: []*protocol.ServerEndpoint{ Server: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: account,
{
Account: account,
},
},
}, },
}, },
}), }),
@@ -268,15 +260,11 @@ func TestShadowsocksAES128GCMUDP(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{ ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
Server: []*protocol.ServerEndpoint{ Server: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: account,
{
Account: account,
},
},
}, },
}, },
}), }),
@@ -370,15 +358,11 @@ func TestShadowsocksAES128GCMUDPMux(t *testing.T) {
}, },
}), }),
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{ ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
Server: []*protocol.ServerEndpoint{ Server: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: account,
{
Account: account,
},
},
}, },
}, },
}), }),
@@ -455,15 +439,11 @@ func TestShadowsocksNone(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{ ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
Server: []*protocol.ServerEndpoint{ Server: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: account,
{
Account: account,
},
},
}, },
}, },
}), }),
+27 -41
View File
@@ -73,18 +73,14 @@ func TestSocksBridgeTCP(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&socks.ClientConfig{ ProxySettings: serial.ToTypedMessage(&socks.ClientConfig{
Server: []*protocol.ServerEndpoint{ Server: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&socks.Account{
{ Username: "Test Account",
Account: serial.ToTypedMessage(&socks.Account{ Password: "Test Password",
Username: "Test Account", }),
Password: "Test Password",
}),
},
},
}, },
}, },
}), }),
@@ -152,18 +148,14 @@ func TestSocksWithHttpRequest(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&http.ClientConfig{ ProxySettings: serial.ToTypedMessage(&http.ClientConfig{
Server: []*protocol.ServerEndpoint{ Server: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&http.Account{
{ Username: "Test Account",
Account: serial.ToTypedMessage(&http.Account{ Password: "Test Password",
Username: "Test Account", }),
Password: "Test Password",
}),
},
},
}, },
}, },
}), }),
@@ -256,18 +248,14 @@ func TestSocksBridageUDP(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&socks.ClientConfig{ ProxySettings: serial.ToTypedMessage(&socks.ClientConfig{
Server: []*protocol.ServerEndpoint{ Server: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&socks.Account{
{ Username: "Test Account",
Account: serial.ToTypedMessage(&socks.Account{ Password: "Test Password",
Username: "Test Account", }),
Password: "Test Password",
}),
},
},
}, },
}, },
}), }),
@@ -375,11 +363,9 @@ func TestSocksBridageUDPWithRouting(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&socks.ClientConfig{ ProxySettings: serial.ToTypedMessage(&socks.ClientConfig{
Server: []*protocol.ServerEndpoint{ Server: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort),
},
}, },
}), }),
}, },
+70 -110
View File
@@ -89,17 +89,13 @@ func TestSimpleTLSConnection(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -204,17 +200,13 @@ func TestAutoIssuingCertificate(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -309,17 +301,13 @@ func TestTLSOverKCP(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -409,17 +397,13 @@ func TestTLSOverWebSocket(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -525,17 +509,13 @@ func TestGRPC(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -641,17 +621,13 @@ func TestGRPCMultiMode(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -752,17 +728,13 @@ func TestSimpleTLSConnectionPinned(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -854,17 +826,13 @@ func TestSimpleTLSConnectionPinnedWrongCert(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -955,17 +923,13 @@ func TestUTLSConnectionPinned(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -1058,17 +1022,13 @@ func TestUTLSConnectionPinnedWrongCert(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
+7 -11
View File
@@ -85,17 +85,13 @@ func TestHTTPConnectionHeader(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
+236 -46
View File
@@ -94,17 +94,13 @@ func TestVless(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Vnext: []*protocol.ServerEndpoint{ Vnext: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vless.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vless.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -125,6 +121,212 @@ func TestVless(t *testing.T) {
} }
} }
func TestVlessMuxTcp(t *testing.T) {
tcpServer := tcp.Server{
MsgProcessor: xor,
}
dest, err := tcpServer.Start()
common.Must(err)
defer tcpServer.Close()
userID := protocol.NewID(uuid.New())
serverPort := tcp.PickPort()
serverConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
Clients: []*protocol.User{
{
Account: serial.ToTypedMessage(&vless.Account{
Id: userID.String(),
}),
},
},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
clientPort := tcp.PickPort()
clientConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
Networks: []net.Network{net.Network_TCP},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
MultiplexSettings: &proxyman.MultiplexingConfig{
Enabled: true,
Concurrency: 4,
},
}),
ProxySettings: serial.ToTypedMessage(&outbound.Config{
Vnext: &protocol.ServerEndpoint{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(serverPort),
User: &protocol.User{
Account: serial.ToTypedMessage(&vless.Account{
Id: userID.String(),
}),
},
},
}),
},
},
}
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
common.Must(err)
defer CloseAllServers(servers)
for range "abcd" {
var errg errgroup.Group
for range 3 {
errg.Go(testTCPConn(clientPort, 10240, time.Second*20))
}
if err := errg.Wait(); err != nil {
t.Fatal(err)
}
time.Sleep(time.Second)
}
}
func TestVlessEncMuxTcp(t *testing.T) {
tcpServer := tcp.Server{
MsgProcessor: xor,
}
dest, err := tcpServer.Start()
common.Must(err)
defer tcpServer.Close()
userID := protocol.NewID(uuid.New())
serverPort := tcp.PickPort()
serverConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
Clients: []*protocol.User{
{
Account: serial.ToTypedMessage(&vless.Account{
Id: userID.String(),
}),
},
},
SecondsFrom: 600, //mlkem768x25519plus.native.600s.
Decryption: "Gzh5Aa3Ibo3343XFC7V2a8ucOpFeGjOL6jMlBZAfjqyty2rdRms8xccBAm68imYw2q96gg2dcueeL2r7n_2YzQ",
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
clientPort := tcp.PickPort()
clientConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
Networks: []net.Network{net.Network_TCP},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
MultiplexSettings: &proxyman.MultiplexingConfig{
Enabled: true,
Concurrency: 4,
},
}),
ProxySettings: serial.ToTypedMessage(&outbound.Config{
Vnext: &protocol.ServerEndpoint{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(serverPort),
User: &protocol.User{
Account: serial.ToTypedMessage(&vless.Account{
Id: userID.String(),
Seconds: 1, //mlkem768x25519plus.native.0rtt.
Encryption: "ExaMB4tIHpFikMeZwAJ8_8hxpZNi3gY13Ft455yC04xiCWgWUwMvKUwDQVm8zLcE8EKnjVlhRDmkTzMzvTMZyYlswCuqx0YK9kVNNFcrQJWD8JpAmTN8fffApIoWitDEAUTEp9S_Ehxo-9a2evRyKqJcQ6WmPiiyGbZrnNAfLKhdRsA15rZt6eKMVQExtDpucfaFc2E4-GtKzKd7P0I6bXccC1q4gqyZcXiEfOmmWBTPMTkNPEUdnQVsPiSWgJxslQZ5pYlPE7GQE7qoxYBItDMhkHZ4l0YwsvgZ1EQ2yTEn9DOxbyMihLk4kSAtg1IrW7tCTNkhyVsUY3SeyReB2sfN2AU-TXmVGUJMTKJ1jfywu8JIb9lG14HB1Rku6nVNcIMTzyshvsi_8AQFCSOcDdQ7ZpBxKxW7N1tKXBI0shq7vWdufjpYCjAVh-k_QgonVOwadYt-wPMxDntbWzEf_yC9eFQ6cBGd5smWNeSQZwAvqXw_WVPD56EVlaQ5HpsOkqBdy1Enr1NnH7WdgNsfk6RSQhRgW1dF9XBUKylpqsvOXkq3I0fLuuJFfuEZu4MeNvdgI2mbM_UxK8AzlRwkm7Eb1WQfm-S05HJefdZzu8kHYamggwtNQum_NtODzRgw3uWbjYbEBIY0j9IMhyGynOYQHHmrR2kT-dh08GwVD7BfsJRvFYgy2ZI8a3xGgHyi6MKKE8g7krEd-ne_4ddSaysgctaiiLwI4NVRbYJIT8XEbmKTIwoZx4R7m7AffYJo2NlfEPREg8stBcY5dAGXeSwD0pxs-jCJOeifQYq7Elq216SrwCmayLg3XJcpxutOmkhai6hRO6eBP6uy9XlLXyMt3TW6isx_rRt1hXCezkl_8hPEcqI9tPE0ZYVQ-eMh2_e35gQyPUw02aequ4ojaHV03QaSMquqF8RXG7k1gDed9vqex3aFaSN6UUNkebLKrqAiPmq0fccQ3qdbAxLGZ0ZFF5mIwEiFoTM6V4yPgntkRYtxcCKK-5YkPfsIunrM3EsWDCovp_Ahdfs-aqQLqzk1wVKTLQaQI5ApBlmGB3EauNdHFJBoeGZOF9e7QbGujhGRGMpS1fFtI2SqlcXINZU7YvR2JMfBrvBYZ9whXawM_Rg31IJR1raMGAEm6hNpa7SBD0cprIZxG6HKUQFMGHVlVohjwpWE5AGIc5Rc8Va2x8e3zFTMTUIwCdMz1XlNaqBMldJx01JQLwgSsnfGGlEJ_jYujvYNo0EBk4yev1Ap6nO-zSU-WtimlhEP0-cb22Q6e4wCEnWfO-lABJsrhwhrbloM51k5QVIefNyIvDWBszpRsreidUZVU4TOH2EoltYslWdPkcckfCplFLyvGKBItoAPRTOKRCjOsqlmj9OvpbDCzedZUmjLNfoLSwsPC7Nk2FpIkVUG6WxCE2YiU9LFrZIgWRKwUluM_at9w7wowRkujXEAQiJKtuUWQCxGyVbJtufLmQI6_yafmwgLoSlyE0cL-_Rf4nBCBjJnmyBDRvAoA-W08vw53uMt3RnFVwKFqo3PonmYAETv5rrMjh3L3K16QS-2EgL_R7WAFd0",
}),
},
},
}),
},
},
}
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
common.Must(err)
defer CloseAllServers(servers)
for range "abcd" {
var errg errgroup.Group
for range 3 {
errg.Go(testTCPConn(clientPort, 10240, time.Second*20))
}
if err := errg.Wait(); err != nil {
t.Fatal(err)
}
time.Sleep(time.Second)
}
}
func TestVlessTls(t *testing.T) { func TestVlessTls(t *testing.T) {
tcpServer := tcp.Server{ tcpServer := tcp.Server{
MsgProcessor: xor, MsgProcessor: xor,
@@ -199,17 +401,13 @@ func TestVlessTls(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Vnext: []*protocol.ServerEndpoint{ Vnext: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vless.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vless.Account{ }),
Id: userID.String(),
}),
},
},
}, },
}, },
}), }),
@@ -322,18 +520,14 @@ func TestVlessXtlsVision(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Vnext: []*protocol.ServerEndpoint{ Vnext: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vless.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vless.Account{ Flow: vless.XRV,
Id: userID.String(), }),
Flow: vless.XRV,
}),
},
},
}, },
}, },
}), }),
@@ -456,18 +650,14 @@ func TestVlessXtlsVisionReality(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Vnext: []*protocol.ServerEndpoint{ Vnext: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vless.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vless.Account{ Flow: vless.XRV,
Id: userID.String(), }),
Flow: vless.XRV,
}),
},
},
}, },
}, },
}), }),
+111 -300
View File
@@ -26,147 +26,6 @@ import (
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
func TestVMessDynamicPort(t *testing.T) {
tcpServer := tcp.Server{
MsgProcessor: xor,
}
dest, err := tcpServer.Start()
common.Must(err)
defer tcpServer.Close()
userID := protocol.NewID(uuid.New())
retry := 1
serverPort := tcp.PickPort()
for {
serverConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(),
}),
},
},
Detour: &inbound.DetourConfig{
To: "detour",
},
}),
},
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort + 100)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
Networks: []net.Network{net.Network_TCP},
}),
},
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{
Range: []*net.PortRange{{From: uint32(serverPort + 1), To: uint32(serverPort + 99)}},
},
Listen: net.NewIPOrDomain(net.LocalHostIP),
AllocationStrategy: &proxyman.AllocationStrategy{
Type: proxyman.AllocationStrategy_Random,
Concurrency: &proxyman.AllocationStrategy_AllocationStrategyConcurrency{
Value: 2,
},
Refresh: &proxyman.AllocationStrategy_AllocationStrategyRefresh{
Value: 5,
},
},
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{}),
Tag: "detour",
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
server, _ := InitializeServerConfig(serverConfig)
if server != nil && WaitConnAvailableWithTest(t, testTCPConn(serverPort+100, 1024, time.Second*2)) {
defer CloseServer(server)
break
}
retry += 1
if retry > 5 {
t.Fatal("All attempts failed to start server")
}
serverPort = tcp.PickPort()
}
clientPort := tcp.PickPort()
clientConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
Networks: []net.Network{net.Network_TCP},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{
{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(serverPort),
User: []*protocol.User{
{
Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(),
}),
},
},
},
},
}),
},
},
}
server, err := InitializeServerConfig(clientConfig)
common.Must(err)
defer CloseServer(server)
if !WaitConnAvailableWithTest(t, testTCPConn(clientPort, 1024, time.Second*2)) {
t.Fail()
}
}
func TestVMessGCM(t *testing.T) { func TestVMessGCM(t *testing.T) {
tcpServer := tcp.Server{ tcpServer := tcp.Server{
MsgProcessor: xor, MsgProcessor: xor,
@@ -232,20 +91,16 @@ func TestVMessGCM(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
}, },
}, }),
}, },
}, },
}), }),
@@ -334,20 +189,16 @@ func TestVMessGCMReadv(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
}, },
}, }),
}, },
}, },
}), }),
@@ -439,20 +290,16 @@ func TestVMessGCMUDP(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
}, },
}, }),
}, },
}, },
}), }),
@@ -538,20 +385,16 @@ func TestVMessChacha20(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_CHACHA20_POLY1305,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_CHACHA20_POLY1305,
},
}),
}, },
}, }),
}, },
}, },
}), }),
@@ -638,20 +481,16 @@ func TestVMessNone(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_NONE,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_NONE,
},
}),
}, },
}, }),
}, },
}, },
}), }),
@@ -740,20 +579,16 @@ func TestVMessKCP(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
}, },
}, }),
}, },
}, },
}), }),
@@ -866,20 +701,16 @@ func TestVMessKCPLarge(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
}, },
}, }),
}, },
}, },
}), }),
@@ -999,20 +830,16 @@ func TestVMessGCMMux(t *testing.T) {
}, },
}), }),
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
}, },
}, }),
}, },
}, },
}), }),
@@ -1126,20 +953,16 @@ func TestVMessGCMMuxUDP(t *testing.T) {
}, },
}), }),
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
}),
}, },
}, }),
}, },
}, },
}), }),
@@ -1233,20 +1056,16 @@ func TestVMessZero(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_ZERO,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_ZERO,
},
}),
}, },
}, }),
}, },
}, },
}), }),
@@ -1332,21 +1151,17 @@ func TestVMessGCMLengthAuth(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
TestsEnabled: "AuthenticatedLength",
}),
}, },
}, TestsEnabled: "AuthenticatedLength",
}),
}, },
}, },
}), }),
@@ -1398,7 +1213,7 @@ func TestVMessGCMLengthAuthPlusNoTerminationSignal(t *testing.T) {
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(), Id: userID.String(),
TestsEnabled: "AuthenticatedLength|NoTerminationSignal", TestsEnabled: "AuthenticatedLength|",
}), }),
}, },
}, },
@@ -1436,21 +1251,17 @@ func TestVMessGCMLengthAuthPlusNoTerminationSignal(t *testing.T) {
Outbound: []*core.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: &protocol.ServerEndpoint{
{ Address: net.NewIPOrDomain(net.LocalHostIP),
Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort),
Port: uint32(serverPort), User: &protocol.User{
User: []*protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{
{ Id: userID.String(),
Account: serial.ToTypedMessage(&vmess.Account{ SecuritySettings: &protocol.SecurityConfig{
Id: userID.String(), Type: protocol.SecurityType_AES128_GCM,
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM,
},
TestsEnabled: "AuthenticatedLength|NoTerminationSignal",
}),
}, },
}, TestsEnabled: "AuthenticatedLength|NoTerminationSignal",
}),
}, },
}, },
}), }),
+1 -1
View File
@@ -9,5 +9,5 @@ import (
func NewAEADAESGCMBasedOnSeed(seed string) cipher.AEAD { func NewAEADAESGCMBasedOnSeed(seed string) cipher.AEAD {
hashedSeed := sha256.Sum256([]byte(seed)) hashedSeed := sha256.Sum256([]byte(seed))
return crypto.NewAesGcm(hashedSeed[:]) return crypto.NewAesGcm(hashedSeed[:16])
} }