Compare commits

...

24 Commits
ax ... v1.5.2

Author SHA1 Message Date
yuhan6665
980b35b3fe Update version 1.5.2 2021-12-24 09:19:17 -05:00
yuhan6665
9ea1bf7c1d Fix shadowsocks xchacha cipher nonce size 2021-12-19 21:18:35 -05:00
hmol233
63da3a5481 grpc: add initial_windows_size option 2021-12-19 21:14:14 -05:00
rf2892jfdsajf
3057a7c999 doc: add contributing section to readme and update build instruction style (#863)
* doc: add bash style

* doc: add code of conduct to readme

Co-authored-by: Your Name <you@example.com>
2021-12-19 19:10:00 -05:00
xqzr
c8e2a99e68 fix unsupported cipher method: xChaCha20-IETF-Poly1305 2021-12-16 18:57:06 -05:00
tritu
756bac7fa4 go 1.17.5 2021-12-15 21:12:00 -05:00
yuhan6665
b0a08d3ed3 Update version 1.5.1 2021-12-14 20:34:07 -05:00
yuhan6665
0d292e0dcd Update dependencies 2021-12-14 20:33:15 -05:00
yuhan6665
dd9da23a59 Add statistics in conn testing
Occasional error is observed when we execute long test
Print time and memory for better troubleshooting in the future

Co-authored-by: Jebbs <qjebbs@gmail.com>
2021-12-14 20:15:05 -05:00
yuhan6665
4e88a369c4 Fix vmess test with portList 2021-12-14 20:01:53 -05:00
yuhan6665
e93da4bd02 Fix some tests and format code (#830)
* Increase some tls test timeout

* Fix TestUserValidator

* Change all tests to VMessAEAD

Old VMess MD5 tests will be rejected and fail in 2022

* Chore: auto format code
2021-12-14 19:28:47 -05:00
yuhan6665
d5a7901601 Unified drain support for vmess and shadowsocks (#791)
* Added test for no terminate signal

* unified drain support for vmess and shadowsockets

* drain: add generated file

Co-authored-by: Shelikhoo <xiaokangwang@outlook.com>
2021-12-14 19:27:31 -05:00
Shelikhoo
6fb5c887b2 Fix DoS attack vulnerability in CommandSwitchAccountFactory 2021-12-11 20:14:57 -05:00
yaotthaha-vscode
4fc284a8e9 Try to fix UDP error 2021-12-01 12:02:27 -05:00
yuhan6665
7c240e8630 Fix null pointer exception for observatory
Core setup router object first, when InjectContext() is called, observatory object is still null,
so observatory need to be injected after InjectContext()
2021-11-20 00:48:02 -05:00
lucifer9
d6ae4e9ba2 Make it easier to configure multiple listening ports 2021-11-17 23:13:15 -05:00
dependabot[bot]
c3298c38a0 Bump google.golang.org/grpc from 1.41.0 to 1.42.0
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.41.0 to 1.42.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.41.0...v1.42.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-04 21:09:16 -04:00
dev_0x1
eb6ced79e7 Add .vscode to ignored directories 2021-11-04 21:08:26 -04:00
秋のかえで
63d0cb1bd6 Refactor: new Shadowsocks validator (#629)
* Refactor: new Shadowsocks validator

* Fix NoneCliper cannot work

* Feat: refine the size of drain

* fix: fix validator after merge 'main'

* fix: UDP user logic

* style: refine code style
2021-10-31 22:10:26 -04:00
roc
dd6769954c hotRelodaInterval --> hotReloadInterval 2021-10-26 21:45:31 -04:00
Zhu Sheng Li
28b17b529d Add concurrency option for outbound observation
Add `enableConcurrency` option, false by default.

If it's set as `true`, start probing outbounds concurrently in every
circle of observation. Wait `probeInterval` between observation circles.
2021-10-26 13:09:03 +08:00
yuhan6665
abb8ba8b0e Observatory related fixes (#788)
* fix:observatory not supported by multi-json

* Fix: observatory starts with empty config & fails to close (#957)

* Update strategy_leastping.go (#1019)

* add custom probe URL support for observatory

* add custom probe interval for observer

* apply coding style

* Fix: observatory log & JSON config(#1211)

Co-authored-by: ihotte <ihotte@yeah.net>

* Change default probe url from api.v2fly.org to www.google.com

* Cherry-pick missing code from branch 'dev-advloadblancer-2'

Co-authored-by: Shelikhoo <xiaokangwang@outlook.com>
Co-authored-by: Loyalsoldier <10487845+Loyalsoldier@users.noreply.github.com>
Co-authored-by: fanyiguan <52657276+fanyiguang@users.noreply.github.com>
Co-authored-by: ihotte <3087168217@qq.com>
Co-authored-by: ihotte <ihotte@yeah.net>
2021-10-26 13:00:31 +08:00
Shelikhoo
7038bded7b Added experiment to avoid sending the termination signal
(cherry picked from commit c5357e1f000054ba5836468922cae52a830c8019)
2021-10-22 18:34:57 +08:00
Shelikhoo
ff35118af5 VMess AEAD based packet length
(cherry picked from commit 08221600082a79376bdc262f2ffec1a3129ae98d)
2021-10-22 18:34:57 +08:00
134 changed files with 2098 additions and 923 deletions

View File

@@ -123,7 +123,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: ^1.17.2 go-version: ^1.17.5
- name: Get project dependencies - name: Get project dependencies
run: go mod download run: go mod download

View File

@@ -28,7 +28,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: ^1.17.2 go-version: ^1.17.5
- name: Checkout codebase - name: Checkout codebase
uses: actions/checkout@v2 uses: actions/checkout@v2

1
.gitignore vendored
View File

@@ -26,3 +26,4 @@ vprotogen
errorgen errorgen
!common/errors/errorgen/ !common/errors/errorgen/
*.dat *.dat
.vscode

View File

@@ -27,6 +27,9 @@
- [(Tap) Repository 0](https://github.com/N4FA/homebrew-xray) - [(Tap) Repository 0](https://github.com/N4FA/homebrew-xray)
- [(Tap) Repository 1](https://github.com/xiruizhao/homebrew-xray) - [(Tap) Repository 1](https://github.com/xiruizhao/homebrew-xray)
## Contributing
[Code Of Conduct](https://github.com/XTLS/Xray-core/blob/main/CODE_OF_CONDUCT.md)
## Usage ## Usage
[Xray-examples](https://github.com/XTLS/Xray-examples) / [VLESS-TCP-XTLS-WHATEVER](https://github.com/XTLS/Xray-examples/tree/main/VLESS-TCP-XTLS-WHATEVER) [Xray-examples](https://github.com/XTLS/Xray-examples) / [VLESS-TCP-XTLS-WHATEVER](https://github.com/XTLS/Xray-examples/tree/main/VLESS-TCP-XTLS-WHATEVER)
@@ -71,13 +74,13 @@ This repo relies on the following third-party projects:
### Windows ### Windows
``` ```bash
go build -o xray.exe -trimpath -ldflags "-s -w -buildid=" ./main go build -o xray.exe -trimpath -ldflags "-s -w -buildid=" ./main
``` ```
### Linux / macOS ### Linux / macOS
``` ```bash
go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main
``` ```

View File

@@ -4,7 +4,6 @@ package dispatcher
import ( import (
"context" "context"
"github.com/xtls/xray-core/features/dns"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -16,6 +15,7 @@ import (
"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/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/outbound" "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"

View File

@@ -6,6 +6,7 @@ import (
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/miekg/dns" "github.com/miekg/dns"
"github.com/xtls/xray-core/app/dispatcher" "github.com/xtls/xray-core/app/dispatcher"
. "github.com/xtls/xray-core/app/dns" . "github.com/xtls/xray-core/app/dns"
"github.com/xtls/xray-core/app/policy" "github.com/xtls/xray-core/app/policy"

View File

@@ -1,9 +1,8 @@
package fakedns package fakedns
import ( import (
"testing"
gonet "net" gonet "net"
"testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"

View File

@@ -4,6 +4,7 @@ import (
"testing" "testing"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
. "github.com/xtls/xray-core/app/dns" . "github.com/xtls/xray-core/app/dns"
"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/net"

View File

@@ -4,9 +4,8 @@ import (
"context" "context"
"strings" "strings"
"github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/dns/localdns" "github.com/xtls/xray-core/features/dns/localdns"
) )

View File

@@ -5,10 +5,9 @@ import (
"testing" "testing"
"time" "time"
"github.com/xtls/xray-core/common/net"
. "github.com/xtls/xray-core/app/dns" . "github.com/xtls/xray-core/app/dns"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
) )

View File

@@ -8,6 +8,9 @@ import (
"time" "time"
"github.com/lucas-clemente/quic-go" "github.com/lucas-clemente/quic-go"
"golang.org/x/net/dns/dnsmessage"
"golang.org/x/net/http2"
"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/net" "github.com/xtls/xray-core/common/net"
@@ -17,8 +20,6 @@ import (
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
dns_feature "github.com/xtls/xray-core/features/dns" dns_feature "github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
"golang.org/x/net/dns/dnsmessage"
"golang.org/x/net/http2"
) )
// NextProtoDQ - During connection establishment, DNS/QUIC support is indicated // NextProtoDQ - During connection establishment, DNS/QUIC support is indicated

View File

@@ -6,13 +6,12 @@ import (
"testing" "testing"
"time" "time"
"github.com/xtls/xray-core/features/dns"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
. "github.com/xtls/xray-core/app/dns" . "github.com/xtls/xray-core/app/dns"
"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/net"
"github.com/xtls/xray-core/features/dns"
) )
func TestQUICNameServer(t *testing.T) { func TestQUICNameServer(t *testing.T) {

View File

@@ -2,7 +2,7 @@ package log
import ( import (
"sync" "sync"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
) )

View File

@@ -0,0 +1,51 @@
//go:build !confonly
// +build !confonly
package command
import (
"context"
"google.golang.org/grpc"
"github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/common"
core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/extension"
)
type service struct {
UnimplementedObservatoryServiceServer
v *core.Instance
observatory extension.Observatory
}
func (s *service) GetOutboundStatus(ctx context.Context, request *GetOutboundStatusRequest) (*GetOutboundStatusResponse, error) {
resp, err := s.observatory.GetObservation(ctx)
if err != nil {
return nil, err
}
retdata := resp.(*observatory.ObservationResult)
return &GetOutboundStatusResponse{
Status: retdata,
}, nil
}
func (s *service) Register(server *grpc.Server) {
RegisterObservatoryServiceServer(server, s)
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
s := core.MustFromContext(ctx)
sv := &service{v: s}
err := s.RequireFeatures(func(Observatory extension.Observatory) {
sv.observatory = Observatory
})
if err != nil {
return nil, err
}
return sv, nil
}))
}

View File

@@ -0,0 +1,278 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.18.0
// source: app/observatory/command/command.proto
package command
import (
observatory "github.com/xtls/xray-core/app/observatory"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type GetOutboundStatusRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *GetOutboundStatusRequest) Reset() {
*x = GetOutboundStatusRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_command_command_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetOutboundStatusRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetOutboundStatusRequest) ProtoMessage() {}
func (x *GetOutboundStatusRequest) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_command_command_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetOutboundStatusRequest.ProtoReflect.Descriptor instead.
func (*GetOutboundStatusRequest) Descriptor() ([]byte, []int) {
return file_app_observatory_command_command_proto_rawDescGZIP(), []int{0}
}
type GetOutboundStatusResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Status *observatory.ObservationResult `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
}
func (x *GetOutboundStatusResponse) Reset() {
*x = GetOutboundStatusResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_command_command_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetOutboundStatusResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetOutboundStatusResponse) ProtoMessage() {}
func (x *GetOutboundStatusResponse) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_command_command_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetOutboundStatusResponse.ProtoReflect.Descriptor instead.
func (*GetOutboundStatusResponse) Descriptor() ([]byte, []int) {
return file_app_observatory_command_command_proto_rawDescGZIP(), []int{1}
}
func (x *GetOutboundStatusResponse) GetStatus() *observatory.ObservationResult {
if x != nil {
return x.Status
}
return nil
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_command_command_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_command_command_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_observatory_command_command_proto_rawDescGZIP(), []int{2}
}
var File_app_observatory_command_command_proto protoreflect.FileDescriptor
var file_app_observatory_command_command_proto_rawDesc = []byte{
0x0a, 0x25, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x21, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
0x72, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x1c, 0x61, 0x70, 0x70, 0x2f,
0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x63, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1a, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x4f,
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x22, 0x61, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x44, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x4f, 0x62,
0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52,
0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x32, 0xa7, 0x01, 0x0a, 0x12, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x90, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74,
0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3b,
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f,
0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3c, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65,
0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
0x47, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x80, 0x01, 0x0a, 0x25,
0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f,
0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
0x72, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x21, 0x58, 0x72, 0x61,
0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72,
0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_observatory_command_command_proto_rawDescOnce sync.Once
file_app_observatory_command_command_proto_rawDescData = file_app_observatory_command_command_proto_rawDesc
)
func file_app_observatory_command_command_proto_rawDescGZIP() []byte {
file_app_observatory_command_command_proto_rawDescOnce.Do(func() {
file_app_observatory_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_observatory_command_command_proto_rawDescData)
})
return file_app_observatory_command_command_proto_rawDescData
}
var file_app_observatory_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_app_observatory_command_command_proto_goTypes = []interface{}{
(*GetOutboundStatusRequest)(nil), // 0: xray.core.app.observatory.command.GetOutboundStatusRequest
(*GetOutboundStatusResponse)(nil), // 1: xray.core.app.observatory.command.GetOutboundStatusResponse
(*Config)(nil), // 2: xray.core.app.observatory.command.Config
(*observatory.ObservationResult)(nil), // 3: xray.core.app.observatory.ObservationResult
}
var file_app_observatory_command_command_proto_depIdxs = []int32{
3, // 0: xray.core.app.observatory.command.GetOutboundStatusResponse.status:type_name -> xray.core.app.observatory.ObservationResult
0, // 1: xray.core.app.observatory.command.ObservatoryService.GetOutboundStatus:input_type -> xray.core.app.observatory.command.GetOutboundStatusRequest
1, // 2: xray.core.app.observatory.command.ObservatoryService.GetOutboundStatus:output_type -> xray.core.app.observatory.command.GetOutboundStatusResponse
2, // [2:3] is the sub-list for method output_type
1, // [1:2] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension 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_app_observatory_command_command_proto_init() }
func file_app_observatory_command_command_proto_init() {
if File_app_observatory_command_command_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_observatory_command_command_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetOutboundStatusRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_observatory_command_command_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetOutboundStatusResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_observatory_command_command_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_observatory_command_command_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_app_observatory_command_command_proto_goTypes,
DependencyIndexes: file_app_observatory_command_command_proto_depIdxs,
MessageInfos: file_app_observatory_command_command_proto_msgTypes,
}.Build()
File_app_observatory_command_command_proto = out.File
file_app_observatory_command_command_proto_rawDesc = nil
file_app_observatory_command_command_proto_goTypes = nil
file_app_observatory_command_command_proto_depIdxs = nil
}

View File

@@ -0,0 +1,24 @@
syntax = "proto3";
package xray.core.app.observatory.command;
option csharp_namespace = "Xray.Core.App.Observatory.Command";
option go_package = "github.com/xtls/xray-core/app/observatory/command";
option java_package = "com.xray.core.app.observatory.command";
option java_multiple_files = true;
import "app/observatory/config.proto";
message GetOutboundStatusRequest {
}
message GetOutboundStatusResponse {
xray.core.app.observatory.ObservationResult status = 1;
}
service ObservatoryService {
rpc GetOutboundStatus(GetOutboundStatusRequest)
returns (GetOutboundStatusResponse) {}
}
message Config {}

View File

@@ -0,0 +1,101 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package command
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// ObservatoryServiceClient is the client API for ObservatoryService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type ObservatoryServiceClient interface {
GetOutboundStatus(ctx context.Context, in *GetOutboundStatusRequest, opts ...grpc.CallOption) (*GetOutboundStatusResponse, error)
}
type observatoryServiceClient struct {
cc grpc.ClientConnInterface
}
func NewObservatoryServiceClient(cc grpc.ClientConnInterface) ObservatoryServiceClient {
return &observatoryServiceClient{cc}
}
func (c *observatoryServiceClient) GetOutboundStatus(ctx context.Context, in *GetOutboundStatusRequest, opts ...grpc.CallOption) (*GetOutboundStatusResponse, error) {
out := new(GetOutboundStatusResponse)
err := c.cc.Invoke(ctx, "/xray.core.app.observatory.command.ObservatoryService/GetOutboundStatus", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ObservatoryServiceServer is the server API for ObservatoryService service.
// All implementations must embed UnimplementedObservatoryServiceServer
// for forward compatibility
type ObservatoryServiceServer interface {
GetOutboundStatus(context.Context, *GetOutboundStatusRequest) (*GetOutboundStatusResponse, error)
mustEmbedUnimplementedObservatoryServiceServer()
}
// UnimplementedObservatoryServiceServer must be embedded to have forward compatible implementations.
type UnimplementedObservatoryServiceServer struct {
}
func (UnimplementedObservatoryServiceServer) GetOutboundStatus(context.Context, *GetOutboundStatusRequest) (*GetOutboundStatusResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetOutboundStatus not implemented")
}
func (UnimplementedObservatoryServiceServer) mustEmbedUnimplementedObservatoryServiceServer() {}
// UnsafeObservatoryServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ObservatoryServiceServer will
// result in compilation errors.
type UnsafeObservatoryServiceServer interface {
mustEmbedUnimplementedObservatoryServiceServer()
}
func RegisterObservatoryServiceServer(s grpc.ServiceRegistrar, srv ObservatoryServiceServer) {
s.RegisterService(&ObservatoryService_ServiceDesc, srv)
}
func _ObservatoryService_GetOutboundStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetOutboundStatusRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ObservatoryServiceServer).GetOutboundStatus(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/xray.core.app.observatory.command.ObservatoryService/GetOutboundStatus",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ObservatoryServiceServer).GetOutboundStatus(ctx, req.(*GetOutboundStatusRequest))
}
return interceptor(ctx, in, info, handler)
}
// ObservatoryService_ServiceDesc is the grpc.ServiceDesc for ObservatoryService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ObservatoryService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "xray.core.app.observatory.command.ObservatoryService",
HandlerType: (*ObservatoryServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetOutboundStatus",
Handler: _ObservatoryService_GetOutboundStatus_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "app/observatory/command/command.proto",
}

View File

@@ -2,7 +2,6 @@ package observatory
import ( import (
"context" "context"
"github.com/xtls/xray-core/core"
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
@@ -17,6 +16,7 @@ import (
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/done"
"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/features/extension" "github.com/xtls/xray-core/features/extension"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/transport/internet/tagged" "github.com/xtls/xray-core/transport/internet/tagged"
@@ -66,22 +66,45 @@ func (o *Observer) background() {
} }
outbounds := hs.Select(o.config.SubjectSelector) outbounds := hs.Select(o.config.SubjectSelector)
sort.Strings(outbounds)
o.updateStatus(outbounds) o.updateStatus(outbounds)
sleepTime := time.Second * 10
if o.config.ProbeInterval != 0 {
sleepTime = time.Duration(o.config.ProbeInterval)
}
if !o.config.EnableConcurrency {
sort.Strings(outbounds)
for _, v := range outbounds {
result := o.probe(v)
o.updateStatusForResult(v, &result)
if o.finished.Done() {
return
}
time.Sleep(sleepTime)
}
continue
}
ch := make(chan struct{}, len(outbounds))
for _, v := range outbounds { for _, v := range outbounds {
result := o.probe(v) go func(v string) {
o.updateStatusForResult(v, &result) result := o.probe(v)
if o.finished.Done() { o.updateStatusForResult(v, &result)
ch <- struct{}{}
}(v)
}
for range outbounds {
select {
case <-ch:
case <-o.finished.Wait():
return return
} }
sleepTime := time.Second * 10
if o.config.ProbeInterval != 0 {
sleepTime = time.Duration(o.config.ProbeInterval)
}
time.Sleep(sleepTime)
} }
time.Sleep(sleepTime)
} }
} }
@@ -102,7 +125,7 @@ func (o *Observer) probe(outbound string) ProbeResult {
DialContext: func(ctx context.Context, network string, addr string) (net.Conn, error) { DialContext: func(ctx context.Context, network string, addr string) (net.Conn, error) {
var connection net.Conn var connection net.Conn
taskErr := task.Run(ctx, func() error { taskErr := task.Run(ctx, func() error {
// MUST use V2Fly's built in context system // MUST use Xray's built in context system
dest, err := v2net.ParseDestination(network + ":" + addr) dest, err := v2net.ParseDestination(network + ":" + addr)
if err != nil { if err != nil {
return newError("cannot understand address").Base(err) return newError("cannot understand address").Base(err)
@@ -133,7 +156,7 @@ func (o *Observer) probe(outbound string) ProbeResult {
var GETTime time.Duration var GETTime time.Duration
err := task.Run(o.ctx, func() error { err := task.Run(o.ctx, func() error {
startTime := time.Now() startTime := time.Now()
probeURL := "https://api.v2fly.org/checkConnection.svgz" probeURL := "https://www.google.com/generate_204"
if o.config.ProbeUrl != "" { if o.config.ProbeUrl != "" {
probeURL = o.config.ProbeUrl probeURL = o.config.ProbeUrl
} }

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.27.1 // protoc-gen-go v1.27.1
// protoc v3.18.0 // protoc v3.19.1
// source: app/proxyman/config.proto // source: app/proxyman/config.proto
package proxyman package proxyman
@@ -238,7 +238,8 @@ type SniffingConfig struct {
DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"` DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
DomainsExcluded []string `protobuf:"bytes,3,rep,name=domains_excluded,json=domainsExcluded,proto3" json:"domains_excluded,omitempty"` DomainsExcluded []string `protobuf:"bytes,3,rep,name=domains_excluded,json=domainsExcluded,proto3" json:"domains_excluded,omitempty"`
// Whether should only try to sniff metadata without waiting for client input. // Whether should only try to sniff metadata without waiting for client input.
// Can be used to support SMTP like protocol where server send the first message. // Can be used to support SMTP like protocol where server send the first
// message.
MetadataOnly bool `protobuf:"varint,4,opt,name=metadata_only,json=metadataOnly,proto3" json:"metadata_only,omitempty"` MetadataOnly bool `protobuf:"varint,4,opt,name=metadata_only,json=metadataOnly,proto3" json:"metadata_only,omitempty"`
RouteOnly bool `protobuf:"varint,5,opt,name=route_only,json=routeOnly,proto3" json:"route_only,omitempty"` RouteOnly bool `protobuf:"varint,5,opt,name=route_only,json=routeOnly,proto3" json:"route_only,omitempty"`
} }
@@ -315,8 +316,8 @@ type ReceiverConfig struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// PortRange specifies the ports which the Receiver should listen on. // PortList specifies the ports which the Receiver should listen on.
PortRange *net.PortRange `protobuf:"bytes,1,opt,name=port_range,json=portRange,proto3" json:"port_range,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"` AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy,proto3" json:"allocation_strategy,omitempty"`
@@ -362,9 +363,9 @@ func (*ReceiverConfig) Descriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{3} return file_app_proxyman_config_proto_rawDescGZIP(), []int{3}
} }
func (x *ReceiverConfig) GetPortRange() *net.PortRange { func (x *ReceiverConfig) GetPortList() *net.PortList {
if x != nil { if x != nil {
return x.PortRange return x.PortList
} }
return nil return nil
} }
@@ -790,86 +791,86 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f, 0x61, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f,
0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65,
0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x90, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x8d, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f,
0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72,
0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12,
0x67, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69,
0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61,
0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x4e, 0x0a, 0x0f,
0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,
0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69,
0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72,
0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72,
0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4b,
0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x42, 0x02, 0x18,
0x01, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
0x65, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65,
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e,
0x2e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
0x10, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x73, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74,
0x61, 0x67, 0x12, 0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x73, 0x12, 0x47, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54,
0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75,
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xb0, 0x02, 0x0a,
0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a,
0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f,
0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f,
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 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, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 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, 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, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x1c,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69,
0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e,
0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4b, 0x6e, 0x6f, 0x77,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e,
0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x4e,
0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
0x50, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e,
0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e,
0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x79, 0x2a, 0x23, 0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a,
0x6f, 0x6c, 0x73, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12,
0x03, 0x54, 0x4c, 0x53, 0x10, 0x01, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74,
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61,
0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e,
0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x10, 0x72, 0x65,
0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47,
0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x72, 0x6f, 0x74, 0x6f, 0x33, 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, 0xb0, 0x02, 0x0a, 0x0c, 0x53, 0x65,
0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x03, 0x76, 0x69,
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72,
0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72,
0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78,
0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65,
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70,
0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78,
0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69,
0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x50, 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,
0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2a, 0x23,
0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73,
0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x4c,
0x53, 0x10, 0x01, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f,
0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70,
0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
} }
var ( var (
@@ -899,7 +900,7 @@ var file_app_proxyman_config_proto_goTypes = []interface{}{
(*MultiplexingConfig)(nil), // 9: xray.app.proxyman.MultiplexingConfig (*MultiplexingConfig)(nil), // 9: xray.app.proxyman.MultiplexingConfig
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency (*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 11: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh (*AllocationStrategy_AllocationStrategyRefresh)(nil), // 11: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
(*net.PortRange)(nil), // 12: xray.common.net.PortRange (*net.PortList)(nil), // 12: xray.common.net.PortList
(*net.IPOrDomain)(nil), // 13: xray.common.net.IPOrDomain (*net.IPOrDomain)(nil), // 13: xray.common.net.IPOrDomain
(*internet.StreamConfig)(nil), // 14: xray.transport.internet.StreamConfig (*internet.StreamConfig)(nil), // 14: xray.transport.internet.StreamConfig
(*serial.TypedMessage)(nil), // 15: xray.common.serial.TypedMessage (*serial.TypedMessage)(nil), // 15: xray.common.serial.TypedMessage
@@ -909,7 +910,7 @@ var file_app_proxyman_config_proto_depIdxs = []int32{
1, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type 1, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type
10, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency 10, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
11, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh 11, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
12, // 3: xray.app.proxyman.ReceiverConfig.port_range:type_name -> xray.common.net.PortRange 12, // 3: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList
13, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain 13, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
3, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy 3, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy
14, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig 14, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig

View File

@@ -27,17 +27,13 @@ message AllocationStrategy {
Type type = 1; Type type = 1;
message AllocationStrategyConcurrency { message AllocationStrategyConcurrency { uint32 value = 1; }
uint32 value = 1;
}
// Number of handlers (ports) running in parallel. // Number of handlers (ports) running in parallel.
// Default value is 3 if unset. // Default value is 3 if unset.
AllocationStrategyConcurrency concurrency = 2; AllocationStrategyConcurrency concurrency = 2;
message AllocationStrategyRefresh { message AllocationStrategyRefresh { uint32 value = 1; }
uint32 value = 1;
}
// Number of minutes before a handler is regenerated. // Number of minutes before a handler is regenerated.
// Default value is 5 if unset. // Default value is 5 if unset.
@@ -59,15 +55,16 @@ message SniffingConfig {
repeated string domains_excluded = 3; repeated string domains_excluded = 3;
// Whether should only try to sniff metadata without waiting for client input. // Whether should only try to sniff metadata without waiting for client input.
// Can be used to support SMTP like protocol where server send the first message. // Can be used to support SMTP like protocol where server send the first
// message.
bool metadata_only = 4; bool metadata_only = 4;
bool route_only = 5; bool route_only = 5;
} }
message ReceiverConfig { message ReceiverConfig {
// PortRange specifies the ports which the Receiver should listen on. // PortList specifies the ports which the Receiver should listen on.
xray.common.net.PortRange port_range = 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; AllocationStrategy allocation_strategy = 3;
@@ -76,7 +73,7 @@ message ReceiverConfig {
reserved 6; reserved 6;
// Override domains for the given protocol. // Override domains for the given protocol.
// Deprecated. Use sniffing_settings. // Deprecated. Use sniffing_settings.
repeated KnownProtocols domain_override = 7 [deprecated = true]; repeated KnownProtocols domain_override = 7 [ deprecated = true ];
SniffingConfig sniffing_settings = 8; SniffingConfig sniffing_settings = 8;
} }

View File

@@ -67,7 +67,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
uplinkCounter, downlinkCounter := getStatCounter(core.MustFromContext(ctx), tag) uplinkCounter, downlinkCounter := getStatCounter(core.MustFromContext(ctx), tag)
nl := p.Network() nl := p.Network()
pr := receiverConfig.PortRange pl := receiverConfig.PortList
address := receiverConfig.Listen.AsAddress() address := receiverConfig.Listen.AsAddress()
if address == nil { if address == nil {
address = net.AnyIP address = net.AnyIP
@@ -87,7 +87,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
} }
mss.SocketSettings.ReceiveOriginalDestAddress = true mss.SocketSettings.ReceiveOriginalDestAddress = true
} }
if pr == nil { if pl == nil {
if net.HasNetwork(nl, net.Network_UNIX) { if net.HasNetwork(nl, net.Network_UNIX) {
newError("creating unix domain socket worker on ", address).AtDebug().WriteToLog() newError("creating unix domain socket worker on ", address).AtDebug().WriteToLog()
@@ -105,43 +105,46 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
h.workers = append(h.workers, worker) h.workers = append(h.workers, worker)
} }
} }
if pr != nil { if pl != nil {
for port := pr.From; port <= pr.To; port++ { for _, pr := range pl.Range {
if net.HasNetwork(nl, net.Network_TCP) { for port := pr.From; port <= pr.To; port++ {
newError("creating stream worker on ", address, ":", port).AtDebug().WriteToLog() if net.HasNetwork(nl, net.Network_TCP) {
newError("creating stream worker on ", address, ":", port).AtDebug().WriteToLog()
worker := &tcpWorker{ worker := &tcpWorker{
address: address, address: address,
port: net.Port(port), port: net.Port(port),
proxy: p, proxy: p,
stream: mss, stream: mss,
recvOrigDest: receiverConfig.ReceiveOriginalDestination, recvOrigDest: receiverConfig.ReceiveOriginalDestination,
tag: tag, tag: tag,
dispatcher: h.mux, dispatcher: h.mux,
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(), sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
ctx: ctx, ctx: ctx,
}
h.workers = append(h.workers, worker)
} }
h.workers = append(h.workers, worker)
}
if net.HasNetwork(nl, net.Network_UDP) { if net.HasNetwork(nl, net.Network_UDP) {
worker := &udpWorker{ worker := &udpWorker{
tag: tag, tag: tag,
proxy: p, proxy: p,
address: address, address: address,
port: net.Port(port), port: net.Port(port),
dispatcher: h.mux, dispatcher: h.mux,
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(), sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
stream: mss, stream: mss,
ctx: ctx, ctx: ctx,
}
h.workers = append(h.workers, worker)
} }
h.workers = append(h.workers, worker)
} }
} }
} }
return h, nil return h, nil

View File

@@ -69,21 +69,25 @@ func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *p
} }
func (h *DynamicInboundHandler) allocatePort() net.Port { func (h *DynamicInboundHandler) allocatePort() net.Port {
from := int(h.receiverConfig.PortRange.From) allPorts := []int32{}
delta := int(h.receiverConfig.PortRange.To) - from + 1 for _, pr := range h.receiverConfig.PortList.Range {
for i := pr.From; i <= pr.To; i++ {
allPorts = append(allPorts, int32(i))
}
}
h.portMutex.Lock() h.portMutex.Lock()
defer h.portMutex.Unlock() defer h.portMutex.Unlock()
for { for {
r := dice.Roll(delta) r := dice.Roll(len(allPorts))
port := net.Port(from + r) port := net.Port(allPorts[r])
_, used := h.portsInUse[port] _, used := h.portsInUse[port]
if !used { if !used {
h.portsInUse[port] = true h.portsInUse[port] = true
return port return port
} }
} }
} }
func (h *DynamicInboundHandler) closeWorkers(workers []worker) { func (h *DynamicInboundHandler) closeWorkers(workers []worker) {

View File

@@ -6,8 +6,6 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"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/buf" "github.com/xtls/xray-core/common/buf"
@@ -20,6 +18,7 @@ import (
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/proxy" "github.com/xtls/xray-core/proxy"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tcp" "github.com/xtls/xray-core/transport/internet/tcp"
"github.com/xtls/xray-core/transport/internet/udp" "github.com/xtls/xray-core/transport/internet/udp"
"github.com/xtls/xray-core/transport/pipe" "github.com/xtls/xray-core/transport/pipe"

View File

@@ -3,8 +3,6 @@ package outbound
import ( import (
"context" "context"
"github.com/xtls/xray-core/transport/internet/stat"
"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/mux" "github.com/xtls/xray-core/common/mux"
@@ -18,6 +16,7 @@ import (
"github.com/xtls/xray-core/proxy" "github.com/xtls/xray-core/proxy"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"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" "github.com/xtls/xray-core/transport/pipe"
) )
@@ -136,13 +135,17 @@ func (h *Handler) Tag() string {
func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) { func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
if h.mux != nil && (h.mux.Enabled || session.MuxPreferedFromContext(ctx)) { if h.mux != nil && (h.mux.Enabled || session.MuxPreferedFromContext(ctx)) {
if err := h.mux.Dispatch(ctx, link); err != nil { if err := h.mux.Dispatch(ctx, link); err != nil {
newError("failed to process mux outbound traffic").Base(err).WriteToLog(session.ExportIDToError(ctx)) err := newError("failed to process mux outbound traffic").Base(err)
session.SubmitOutboundErrorToOriginator(ctx, err)
err.WriteToLog(session.ExportIDToError(ctx))
common.Interrupt(link.Writer) common.Interrupt(link.Writer)
} }
} else { } else {
if err := h.proxy.Process(ctx, link, h); err != nil { if err := h.proxy.Process(ctx, link, h); err != nil {
// Ensure outbound ray is properly closed. // Ensure outbound ray is properly closed.
newError("failed to process outbound traffic").Base(err).WriteToLog(session.ExportIDToError(ctx)) err := newError("failed to process outbound traffic").Base(err)
session.SubmitOutboundErrorToOriginator(ctx, err)
err.WriteToLog(session.ExportIDToError(ctx))
common.Interrupt(link.Writer) common.Interrupt(link.Writer)
} else { } else {
common.Must(common.Close(link.Writer)) common.Must(common.Close(link.Writer))

View File

@@ -4,8 +4,6 @@ import (
"context" "context"
"testing" "testing"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/app/policy" "github.com/xtls/xray-core/app/policy"
. "github.com/xtls/xray-core/app/proxyman/outbound" . "github.com/xtls/xray-core/app/proxyman/outbound"
"github.com/xtls/xray-core/app/stats" "github.com/xtls/xray-core/app/stats"
@@ -14,6 +12,7 @@ import (
core "github.com/xtls/xray-core/core" core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/proxy/freedom" "github.com/xtls/xray-core/proxy/freedom"
"github.com/xtls/xray-core/transport/internet/stat"
) )
func TestInterfaces(t *testing.T) { func TestInterfaces(t *testing.T) {

View File

@@ -284,7 +284,7 @@ func TestSerivceTestRoute(t *testing.T) {
r := new(router.Router) r := new(router.Router)
mockCtl := gomock.NewController(t) mockCtl := gomock.NewController(t)
defer mockCtl.Finish() defer mockCtl.Finish()
common.Must(r.Init(&router.Config{ common.Must(r.Init(context.TODO(), &router.Config{
Rule: []*router.RoutingRule{ Rule: []*router.RoutingRule{
{ {
InboundTag: []string{"in"}, InboundTag: []string{"in"},

View File

@@ -158,9 +158,21 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
} }
func (br *BalancingRule) Build(ohm outbound.Manager) (*Balancer, error) { func (br *BalancingRule) Build(ohm outbound.Manager) (*Balancer, error) {
return &Balancer{ switch br.Strategy {
selectors: br.OutboundSelector, case "leastPing":
strategy: &RandomStrategy{}, return &Balancer{
ohm: ohm, selectors: br.OutboundSelector,
}, nil strategy: &LeastPingStrategy{},
ohm: ohm,
}, nil
case "random":
fallthrough
default:
return &Balancer{
selectors: br.OutboundSelector,
strategy: &RandomStrategy{},
ohm: ohm,
}, nil
}
} }

View File

@@ -29,7 +29,7 @@ type Route struct {
} }
// Init initializes the Router. // Init initializes the Router.
func (r *Router) Init(config *Config, d dns.Client, ohm outbound.Manager) error { func (r *Router) Init(ctx context.Context, config *Config, d dns.Client, ohm outbound.Manager) error {
r.domainStrategy = config.DomainStrategy r.domainStrategy = config.DomainStrategy
r.dns = d r.dns = d
@@ -39,6 +39,7 @@ func (r *Router) Init(config *Config, d dns.Client, ohm outbound.Manager) error
if err != nil { if err != nil {
return err return err
} }
balancer.InjectContext(ctx)
r.balancers[rule.Tag] = balancer r.balancers[rule.Tag] = balancer
} }
@@ -140,7 +141,7 @@ func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
r := new(Router) r := new(Router)
if err := core.RequireFeatures(ctx, func(d dns.Client, ohm outbound.Manager) error { if err := core.RequireFeatures(ctx, func(d dns.Client, ohm outbound.Manager) error {
return r.Init(config.(*Config), d, ohm) return r.Init(ctx, config.(*Config), d, ohm)
}); err != nil { }); err != nil {
return nil, err return nil, err
} }

View File

@@ -4,14 +4,13 @@ import (
"context" "context"
"testing" "testing"
"github.com/xtls/xray-core/features/dns"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
. "github.com/xtls/xray-core/app/router" . "github.com/xtls/xray-core/app/router"
"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/net"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
routing_session "github.com/xtls/xray-core/features/routing/session" routing_session "github.com/xtls/xray-core/features/routing/session"
"github.com/xtls/xray-core/testing/mocks" "github.com/xtls/xray-core/testing/mocks"
@@ -42,7 +41,7 @@ func TestSimpleRouter(t *testing.T) {
mockHs := mocks.NewOutboundHandlerSelector(mockCtl) mockHs := mocks.NewOutboundHandlerSelector(mockCtl)
r := new(Router) r := new(Router)
common.Must(r.Init(config, mockDNS, &mockOutboundManager{ common.Must(r.Init(context.TODO(), config, mockDNS, &mockOutboundManager{
Manager: mockOhm, Manager: mockOhm,
HandlerSelector: mockHs, HandlerSelector: mockHs,
})) }))
@@ -83,7 +82,7 @@ func TestSimpleBalancer(t *testing.T) {
mockHs.EXPECT().Select(gomock.Eq([]string{"test-"})).Return([]string{"test"}) mockHs.EXPECT().Select(gomock.Eq([]string{"test-"})).Return([]string{"test"})
r := new(Router) r := new(Router)
common.Must(r.Init(config, mockDNS, &mockOutboundManager{ common.Must(r.Init(context.TODO(), config, mockDNS, &mockOutboundManager{
Manager: mockOhm, Manager: mockOhm,
HandlerSelector: mockHs, HandlerSelector: mockHs,
})) }))
@@ -125,7 +124,7 @@ func TestIPOnDemand(t *testing.T) {
}).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes() }).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
r := new(Router) r := new(Router)
common.Must(r.Init(config, mockDNS, nil)) common.Must(r.Init(context.TODO(), config, mockDNS, nil))
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("example.com"), 80)}) ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("example.com"), 80)})
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx)) route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
@@ -164,7 +163,7 @@ func TestIPIfNonMatchDomain(t *testing.T) {
}).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes() }).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
r := new(Router) r := new(Router)
common.Must(r.Init(config, mockDNS, nil)) common.Must(r.Init(context.TODO(), config, mockDNS, nil))
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("example.com"), 80)}) ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("example.com"), 80)})
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx)) route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
@@ -198,7 +197,7 @@ func TestIPIfNonMatchIP(t *testing.T) {
mockDNS := mocks.NewDNSClient(mockCtl) mockDNS := mocks.NewDNSClient(mockCtl)
r := new(Router) r := new(Router)
common.Must(r.Init(config, mockDNS, nil)) common.Must(r.Init(context.TODO(), config, mockDNS, nil))
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 80)}) ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 80)})
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx)) route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))

View File

@@ -2,10 +2,10 @@ package router
import ( import (
"context" "context"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/app/observatory" "github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/extension" "github.com/xtls/xray-core/features/extension"
) )
@@ -15,14 +15,17 @@ type LeastPingStrategy struct {
} }
func (l *LeastPingStrategy) InjectContext(ctx context.Context) { func (l *LeastPingStrategy) InjectContext(ctx context.Context) {
common.Must(core.RequireFeatures(ctx, func(observatory extension.Observatory) error {
l.observatory = observatory
return nil
}))
l.ctx = ctx l.ctx = ctx
} }
func (l *LeastPingStrategy) PickOutbound(strings []string) string { func (l *LeastPingStrategy) PickOutbound(strings []string) string {
if l.observatory == nil {
common.Must(core.RequireFeatures(l.ctx, func(observatory extension.Observatory) error {
l.observatory = observatory
return nil
}))
}
observeReport, err := l.observatory.GetObservation(l.ctx) observeReport, err := l.observatory.GetObservation(l.ctx)
if err != nil { if err != nil {
newError("cannot get observe report").Base(err).WriteToLog() newError("cannot get observe report").Base(err).WriteToLog()
@@ -36,6 +39,7 @@ func (l *LeastPingStrategy) PickOutbound(strings []string) string {
for _, v := range status { for _, v := range status {
if outboundsList.contains(v.OutboundTag) && v.Alive && v.Delay < leastPing { if outboundsList.contains(v.OutboundTag) && v.Alive && v.Delay < leastPing {
selectedOutboundName = v.OutboundTag selectedOutboundName = v.OutboundTag
leastPing = v.Delay
} }
} }
return selectedOutboundName return selectedOutboundName

View File

@@ -7,9 +7,8 @@ import (
"io" "io"
"syscall" "syscall"
"github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/common/platform" "github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/features/stats"
) )
type allocStrategy struct { type allocStrategy struct {

View File

@@ -9,7 +9,6 @@ import (
"testing" "testing"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"

View File

@@ -5,10 +5,9 @@ import (
"net" "net"
"sync" "sync"
"github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/features/stats"
) )
// BufferToBytesWriter is a Writer that writes alloc.Buffer into underlying writer. // BufferToBytesWriter is a Writer that writes alloc.Buffer into underlying writer.

View File

@@ -39,10 +39,6 @@ func GenerateIncreasingNonce(nonce []byte) BytesGenerator {
} }
} }
func GenerateInitialAEADNonce() BytesGenerator {
return GenerateIncreasingNonce([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})
}
func GenerateAEADNonceWithSize(nonceSize int) BytesGenerator { func GenerateAEADNonceWithSize(nonceSize int) BytesGenerator {
c := make([]byte, nonceSize) c := make([]byte, nonceSize)
for i := 0; i < nonceSize; i++ { for i := 0; i < nonceSize; i++ {

10
common/drain/drain.go Normal file
View File

@@ -0,0 +1,10 @@
package drain
import "io"
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
type Drainer interface {
AcknowledgeReceive(size int)
Drain(reader io.Reader) error
}

62
common/drain/drainer.go Normal file
View File

@@ -0,0 +1,62 @@
package drain
import (
"io"
"io/ioutil"
"github.com/xtls/xray-core/common/dice"
)
type BehaviorSeedLimitedDrainer struct {
DrainSize int
}
func NewBehaviorSeedLimitedDrainer(behaviorSeed int64, drainFoundation, maxBaseDrainSize, maxRandDrain int) (Drainer, error) {
behaviorRand := dice.NewDeterministicDice(behaviorSeed)
BaseDrainSize := behaviorRand.Roll(maxBaseDrainSize)
RandDrainMax := behaviorRand.Roll(maxRandDrain) + 1
RandDrainRolled := dice.Roll(RandDrainMax)
DrainSize := drainFoundation + BaseDrainSize + RandDrainRolled
return &BehaviorSeedLimitedDrainer{DrainSize: DrainSize}, nil
}
func (d *BehaviorSeedLimitedDrainer) AcknowledgeReceive(size int) {
d.DrainSize -= size
}
func (d *BehaviorSeedLimitedDrainer) Drain(reader io.Reader) error {
if d.DrainSize > 0 {
err := drainReadN(reader, d.DrainSize)
if err == nil {
return newError("drained connection")
}
return newError("unable to drain connection").Base(err)
}
return nil
}
func drainReadN(reader io.Reader, n int) error {
_, err := io.CopyN(ioutil.Discard, reader, int64(n))
return err
}
func WithError(drainer Drainer, reader io.Reader, err error) error {
drainErr := drainer.Drain(reader)
if drainErr == nil {
return err
}
return newError(drainErr).Base(err)
}
type NopDrainer struct{}
func (n NopDrainer) AcknowledgeReceive(size int) {
}
func (n NopDrainer) Drain(reader io.Reader) error {
return nil
}
func NewNopDrainer() Drainer {
return &NopDrainer{}
}

View File

@@ -0,0 +1,9 @@
package drain
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -38,6 +38,8 @@ const (
RequestOptionChunkMasking bitmask.Byte = 0x04 RequestOptionChunkMasking bitmask.Byte = 0x04
RequestOptionGlobalPadding bitmask.Byte = 0x08 RequestOptionGlobalPadding bitmask.Byte = 0x08
RequestOptionAuthenticatedLength bitmask.Byte = 0x10
) )
type RequestHeader struct { type RequestHeader struct {

100
common/units/bytesize.go Normal file
View File

@@ -0,0 +1,100 @@
package units
import (
"errors"
"strconv"
"strings"
"unicode"
)
var (
errInvalidSize = errors.New("invalid size")
errInvalidUnit = errors.New("invalid or unsupported unit")
)
// ByteSize is the size of bytes
type ByteSize uint64
const (
_ = iota
// KB = 1KB
KB ByteSize = 1 << (10 * iota)
// MB = 1MB
MB
// GB = 1GB
GB
// TB = 1TB
TB
// PB = 1PB
PB
// EB = 1EB
EB
)
func (b ByteSize) String() string {
unit := ""
value := float64(0)
switch {
case b == 0:
return "0"
case b < KB:
unit = "B"
value = float64(b)
case b < MB:
unit = "KB"
value = float64(b) / float64(KB)
case b < GB:
unit = "MB"
value = float64(b) / float64(MB)
case b < TB:
unit = "GB"
value = float64(b) / float64(GB)
case b < PB:
unit = "TB"
value = float64(b) / float64(TB)
case b < EB:
unit = "PB"
value = float64(b) / float64(PB)
default:
unit = "EB"
value = float64(b) / float64(EB)
}
result := strconv.FormatFloat(value, 'f', 2, 64)
result = strings.TrimSuffix(result, ".0")
return result + unit
}
// Parse parses ByteSize from string
func (b *ByteSize) Parse(s string) error {
s = strings.TrimSpace(s)
s = strings.ToUpper(s)
i := strings.IndexFunc(s, unicode.IsLetter)
if i == -1 {
return errInvalidUnit
}
bytesString, multiple := s[:i], s[i:]
bytes, err := strconv.ParseFloat(bytesString, 64)
if err != nil || bytes <= 0 {
return errInvalidSize
}
switch multiple {
case "B":
*b = ByteSize(bytes)
case "K", "KB", "KIB":
*b = ByteSize(bytes * float64(KB))
case "M", "MB", "MIB":
*b = ByteSize(bytes * float64(MB))
case "G", "GB", "GIB":
*b = ByteSize(bytes * float64(GB))
case "T", "TB", "TIB":
*b = ByteSize(bytes * float64(TB))
case "P", "PB", "PIB":
*b = ByteSize(bytes * float64(PB))
case "E", "EB", "EIB":
*b = ByteSize(bytes * float64(EB))
default:
return errInvalidUnit
}
return nil
}

View File

@@ -0,0 +1,66 @@
package units_test
import (
"testing"
"github.com/xtls/xray-core/common/units"
)
func TestByteSizes(t *testing.T) {
size := units.ByteSize(0)
assertSizeString(t, size, "0")
size++
assertSizeValue(t,
assertSizeString(t, size, "1.00B"),
size,
)
size <<= 10
assertSizeValue(t,
assertSizeString(t, size, "1.00KB"),
size,
)
size <<= 10
assertSizeValue(t,
assertSizeString(t, size, "1.00MB"),
size,
)
size <<= 10
assertSizeValue(t,
assertSizeString(t, size, "1.00GB"),
size,
)
size <<= 10
assertSizeValue(t,
assertSizeString(t, size, "1.00TB"),
size,
)
size <<= 10
assertSizeValue(t,
assertSizeString(t, size, "1.00PB"),
size,
)
size <<= 10
assertSizeValue(t,
assertSizeString(t, size, "1.00EB"),
size,
)
}
func assertSizeValue(t *testing.T, size string, expected units.ByteSize) {
actual := units.ByteSize(0)
err := actual.Parse(size)
if err != nil {
t.Error(err)
}
if actual != expected {
t.Errorf("expect %s, but got %s", expected, actual)
}
}
func assertSizeString(t *testing.T, size units.ByteSize, expected string) string {
actual := size.String()
if actual != expected {
t.Errorf("expect %s, but got %s", expected, actual)
}
return expected
}

View File

@@ -18,7 +18,7 @@ import (
) )
var ( var (
version = "1.5.0" version = "1.5.2"
build = "Custom" build = "Custom"
codename = "Xray, Penetrates Everything." codename = "Xray, Penetrates Everything."
intro = "A unified platform for anti-censorship." intro = "A unified platform for anti-censorship."

View File

@@ -49,8 +49,10 @@ func TestXrayClose(t *testing.T) {
Inbound: []*InboundHandlerConfig{ Inbound: []*InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(port), PortList: &net.PortList{
Listen: net.NewIPOrDomain(net.LocalHostIP), Range: []*net.PortRange{net.SinglePortRange(port)},
},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(net.LocalHostIP), Address: net.NewIPOrDomain(net.LocalHostIP),

17
go.mod
View File

@@ -12,17 +12,17 @@ require (
github.com/miekg/dns v1.1.43 github.com/miekg/dns v1.1.43
github.com/pelletier/go-toml v1.9.4 github.com/pelletier/go-toml v1.9.4
github.com/pires/go-proxyproto v0.6.1 github.com/pires/go-proxyproto v0.6.1
github.com/refraction-networking/utls v0.0.0-20210713165636-0b2885c8c0d4 github.com/refraction-networking/utls v1.0.0
github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672 github.com/xtls/go v0.0.0-20210920065950-d4af136d3672
go.starlark.net v0.0.0-20211013185944-b0039bd2cfe3 go.starlark.net v0.0.0-20211203141949-70c0e40ae128
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b
golang.org/x/net v0.0.0-20211020060615-d418f374d309 golang.org/x/net v0.0.0-20211209124913-491a49abca63
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20211020064051-0ec99a608a1b golang.org/x/sys v0.0.0-20211214234402-4825e8c3871d
google.golang.org/grpc v1.41.0 google.golang.org/grpc v1.43.0
google.golang.org/protobuf v1.27.1 google.golang.org/protobuf v1.27.1
h12.io/socks v1.0.3 h12.io/socks v1.0.3
) )
@@ -39,11 +39,12 @@ require (
github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/ginkgo v1.16.5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/stretchr/objx v0.3.0 // indirect
golang.org/x/mod v0.5.1 // indirect golang.org/x/mod v0.5.1 // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.7 // indirect golang.org/x/tools v0.1.8 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/genproto v0.0.0-20211019152133-63b7e35f4404 // indirect google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect

27
go.sum
View File

@@ -25,8 +25,11 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -163,6 +166,8 @@ github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7q
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/refraction-networking/utls v0.0.0-20210713165636-0b2885c8c0d4 h1:n9NMHJusHylTmtaJ0Qe0VV9dkTZLiwAxHmrI/l98GeE= github.com/refraction-networking/utls v0.0.0-20210713165636-0b2885c8c0d4 h1:n9NMHJusHylTmtaJ0Qe0VV9dkTZLiwAxHmrI/l98GeE=
github.com/refraction-networking/utls v0.0.0-20210713165636-0b2885c8c0d4/go.mod h1:tz9gX959MEFfFN5whTIocCLUG57WiILqtdVxI8c6Wj0= github.com/refraction-networking/utls v0.0.0-20210713165636-0b2885c8c0d4/go.mod h1:tz9gX959MEFfFN5whTIocCLUG57WiILqtdVxI8c6Wj0=
github.com/refraction-networking/utls v1.0.0 h1:6XQHSjDmeBCF9sPq8p2zMVGq7Ud3rTD2q88Fw8Tz1tA=
github.com/refraction-networking/utls v1.0.0/go.mod h1:tz9gX959MEFfFN5whTIocCLUG57WiILqtdVxI8c6Wj0=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
@@ -195,8 +200,12 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
@@ -215,6 +224,8 @@ go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.starlark.net v0.0.0-20211013185944-b0039bd2cfe3 h1:oBcONsksxvpeodDrLjiMDaKHXKAVVfAydhe/792CE/o= go.starlark.net v0.0.0-20211013185944-b0039bd2cfe3 h1:oBcONsksxvpeodDrLjiMDaKHXKAVVfAydhe/792CE/o=
go.starlark.net v0.0.0-20211013185944-b0039bd2cfe3/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= go.starlark.net v0.0.0-20211013185944-b0039bd2cfe3/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0=
go.starlark.net v0.0.0-20211203141949-70c0e40ae128 h1:bxH+EXOo87zEOwKDdZ8Tevgi6irRbqheRm/fr293c58=
go.starlark.net v0.0.0-20211203141949-70c0e40ae128/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -226,6 +237,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b h1:QAqMVf3pSa6eeTsuklijukjXBlj7Es2QQplab+/RbQ4=
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -256,6 +269,8 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211020060615-d418f374d309 h1:A0lJIi+hcTR6aajJH4YqKWwohY4aW9RO7oRMcdv+HKI= golang.org/x/net v0.0.0-20211020060615-d418f374d309 h1:A0lJIi+hcTR6aajJH4YqKWwohY4aW9RO7oRMcdv+HKI=
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY=
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -295,6 +310,8 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211020064051-0ec99a608a1b h1:byBDhtWGQmWDrv1MlEv/BzGRMkw36h9QqsNnZQcDhRw= golang.org/x/sys v0.0.0-20211020064051-0ec99a608a1b h1:byBDhtWGQmWDrv1MlEv/BzGRMkw36h9QqsNnZQcDhRw=
golang.org/x/sys v0.0.0-20211020064051-0ec99a608a1b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020064051-0ec99a608a1b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211214234402-4825e8c3871d h1:1oIt9o40TWWI9FUaveVpUvBe13FNqBNVXy3ue2fcfkw=
golang.org/x/sys v0.0.0-20211214234402-4825e8c3871d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -319,6 +336,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -341,6 +360,8 @@ google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20211019152133-63b7e35f4404 h1:ZB48alYoIN+Soc1OcXirVKYOhOOf6Pek+iN+L+pzQI4= google.golang.org/genproto v0.0.0-20211019152133-63b7e35f4404 h1:ZB48alYoIN+Soc1OcXirVKYOhOOf6Pek+iN+L+pzQI4=
google.golang.org/genproto v0.0.0-20211019152133-63b7e35f4404/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211019152133-63b7e35f4404/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
@@ -351,8 +372,10 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E= google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A=
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View File

@@ -5,6 +5,7 @@ import (
"github.com/xtls/xray-core/app/commander" "github.com/xtls/xray-core/app/commander"
loggerservice "github.com/xtls/xray-core/app/log/command" loggerservice "github.com/xtls/xray-core/app/log/command"
observatoryservice "github.com/xtls/xray-core/app/observatory/command"
handlerservice "github.com/xtls/xray-core/app/proxyman/command" handlerservice "github.com/xtls/xray-core/app/proxyman/command"
statsservice "github.com/xtls/xray-core/app/stats/command" statsservice "github.com/xtls/xray-core/app/stats/command"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
@@ -31,6 +32,8 @@ func (c *APIConfig) Build() (*commander.Config, error) {
services = append(services, serial.ToTypedMessage(&loggerservice.Config{})) services = append(services, serial.ToTypedMessage(&loggerservice.Config{}))
case "statsservice": case "statsservice":
services = append(services, serial.ToTypedMessage(&statsservice.Config{})) services = append(services, serial.ToTypedMessage(&statsservice.Config{}))
case "observatoryservice":
services = append(services, serial.ToTypedMessage(&observatoryservice.Config{}))
} }
} }

View File

@@ -2,6 +2,7 @@ package conf
import ( import (
"encoding/json" "encoding/json"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"

View File

@@ -0,0 +1,33 @@
package duration
import (
"encoding/json"
"fmt"
"time"
)
type Duration int64
func (d *Duration) MarshalJSON() ([]byte, error) {
dr := time.Duration(*d)
return json.Marshal(dr.String())
}
func (d *Duration) UnmarshalJSON(b []byte) error {
var v interface{}
if err := json.Unmarshal(b, &v); err != nil {
return err
}
switch value := v.(type) {
case string:
var err error
dr, err := time.ParseDuration(value)
if err != nil {
return err
}
*d = Duration(dr)
return nil
default:
return fmt.Errorf("invalid duration: %v", v)
}
}

View File

@@ -0,0 +1,33 @@
package duration_test
import (
"encoding/json"
"testing"
"time"
"github.com/xtls/xray-core/infra/conf/cfgcommon/duration"
)
type testWithDuration struct {
Duration duration.Duration
}
func TestDurationJSON(t *testing.T) {
expected := &testWithDuration{
Duration: duration.Duration(time.Hour),
}
data, err := json.Marshal(expected)
if err != nil {
t.Error(err)
return
}
actual := &testWithDuration{}
err = json.Unmarshal(data, &actual)
if err != nil {
t.Error(err)
return
}
if actual.Duration != expected.Duration {
t.Errorf("expected: %s, actual: %s", time.Duration(expected.Duration), time.Duration(actual.Duration))
}
}

View File

@@ -209,8 +209,7 @@ func TestUserParsing(t *testing.T) {
common.Must(json.Unmarshal([]byte(`{ common.Must(json.Unmarshal([]byte(`{
"id": "96edb838-6d68-42ef-a933-25f7ac3a9d09", "id": "96edb838-6d68-42ef-a933-25f7ac3a9d09",
"email": "love@example.com", "email": "love@example.com",
"level": 1, "level": 1
"alterId": 100
}`), user)) }`), user))
nUser := user.Build() nUser := user.Build()

View File

@@ -68,10 +68,10 @@ func (FakeDNSPostProcessingStage) Process(config *Config) error {
} }
switch strings.ToLower(config.DNSConfig.QueryStrategy) { switch strings.ToLower(config.DNSConfig.QueryStrategy) {
case "useip4", "useipv4", "use_ip4", "use_ipv4", "use_ip_v4", "use-ip4", "use-ipv4", "use-ip-v4": case "useip4", "useipv4", "use_ip4", "use_ipv4", "use_ip_v4", "use-ip4", "use-ipv4", "use-ip-v4":
isIPv4Enable, isIPv6Enable = true, false isIPv4Enable, isIPv6Enable = true, false
case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6": case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6":
isIPv4Enable, isIPv6Enable = false, true isIPv4Enable, isIPv6Enable = false, true
} }
} }

View File

@@ -12,6 +12,7 @@ type GRPCConfig struct {
IdleTimeout int32 `json:"idle_timeout"` IdleTimeout int32 `json:"idle_timeout"`
HealthCheckTimeout int32 `json:"health_check_timeout"` HealthCheckTimeout int32 `json:"health_check_timeout"`
PermitWithoutStream bool `json:"permit_without_stream"` PermitWithoutStream bool `json:"permit_without_stream"`
InitialWindowsSize int32 `json:"initial_windows_size"`
} }
func (g *GRPCConfig) Build() (proto.Message, error) { func (g *GRPCConfig) Build() (proto.Message, error) {
@@ -21,11 +22,17 @@ func (g *GRPCConfig) Build() (proto.Message, error) {
if g.HealthCheckTimeout <= 0 { if g.HealthCheckTimeout <= 0 {
g.HealthCheckTimeout = 0 g.HealthCheckTimeout = 0
} }
if g.InitialWindowsSize < 0 {
// default window size of gRPC-go
g.InitialWindowsSize = 0
}
return &grpc.Config{ return &grpc.Config{
ServiceName: g.ServiceName, ServiceName: g.ServiceName,
MultiMode: g.MultiMode, MultiMode: g.MultiMode,
IdleTimeout: g.IdleTimeout, IdleTimeout: g.IdleTimeout,
HealthCheckTimeout: g.HealthCheckTimeout, HealthCheckTimeout: g.HealthCheckTimeout,
PermitWithoutStream: g.PermitWithoutStream, PermitWithoutStream: g.PermitWithoutStream,
InitialWindowsSize: g.InitialWindowsSize,
}, nil }, nil
} }

View File

@@ -2,13 +2,18 @@ package conf
import ( import (
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/app/observatory" "github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/infra/conf/cfgcommon/duration"
) )
type ObservatoryConfig struct { type ObservatoryConfig struct {
SubjectSelector []string `json:"subjectSelector"` SubjectSelector []string `json:"subjectSelector"`
ProbeURL string `json:"probeURL"`
ProbeInterval duration.Duration `json:"probeInterval"`
EnableConcurrency bool `json:"enableConcurrency"`
} }
func (o ObservatoryConfig) Build() (proto.Message, error) { func (o *ObservatoryConfig) Build() (proto.Message, error) {
return &observatory.Config{SubjectSelector: o.SubjectSelector}, nil return &observatory.Config{SubjectSelector: o.SubjectSelector, ProbeUrl: o.ProbeURL, ProbeInterval: int64(o.ProbeInterval), EnableConcurrency: o.EnableConcurrency}, nil
} }

View File

@@ -18,9 +18,16 @@ type RouterRulesConfig struct {
DomainStrategy string `json:"domainStrategy"` DomainStrategy string `json:"domainStrategy"`
} }
// StrategyConfig represents a strategy config
type StrategyConfig struct {
Type string `json:"type"`
Settings *json.RawMessage `json:"settings"`
}
type BalancingRule struct { type BalancingRule struct {
Tag string `json:"tag"` Tag string `json:"tag"`
Selectors StringList `json:"selector"` Selectors StringList `json:"selector"`
Strategy StrategyConfig `json:"strategy"`
} }
func (r *BalancingRule) Build() (*router.BalancingRule, error) { func (r *BalancingRule) Build() (*router.BalancingRule, error) {
@@ -31,9 +38,20 @@ func (r *BalancingRule) Build() (*router.BalancingRule, error) {
return nil, newError("empty selector list") return nil, newError("empty selector list")
} }
var strategy string
switch strings.ToLower(r.Strategy.Type) {
case strategyRandom, "":
strategy = strategyRandom
case strategyLeastPing:
strategy = "leastPing"
default:
return nil, newError("unknown balancing strategy: " + r.Strategy.Type)
}
return &router.BalancingRule{ return &router.BalancingRule{
Tag: r.Tag, Tag: r.Tag,
OutboundSelector: []string(r.Selectors), OutboundSelector: []string(r.Selectors),
Strategy: strategy,
}, nil }, nil
} }

View File

@@ -0,0 +1,6 @@
package conf
const (
strategyRandom string = "random"
strategyLeastPing string = "leastping"
)

View File

@@ -107,6 +107,7 @@ func TestRouterConfig(t *testing.T) {
{ {
Tag: "b1", Tag: "b1",
OutboundSelector: []string{"test"}, OutboundSelector: []string{"test"},
Strategy: "random",
}, },
}, },
Rule: []*router.RoutingRule{ Rule: []*router.RoutingRule{

View File

@@ -59,7 +59,7 @@ func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
return nil, newError("Shadowsocks password is not specified.") return nil, newError("Shadowsocks password is not specified.")
} }
if account.CipherType < shadowsocks.CipherType_AES_128_GCM || if account.CipherType < shadowsocks.CipherType_AES_128_GCM ||
account.CipherType > shadowsocks.CipherType_CHACHA20_POLY1305 { account.CipherType > shadowsocks.CipherType_XCHACHA20_POLY1305 {
return nil, newError("unsupported cipher method: ", user.Cipher) return nil, newError("unsupported cipher method: ", user.Cipher)
} }
config.Users = append(config.Users, &protocol.User{ config.Users = append(config.Users, &protocol.User{

View File

@@ -15,9 +15,10 @@ import (
) )
type VMessAccount struct { type VMessAccount struct {
ID string `json:"id"` ID string `json:"id"`
AlterIds uint16 `json:"alterId"` AlterIds uint16 `json:"alterId"`
Security string `json:"security"` Security string `json:"security"`
Experiments string `json:"experiments"`
} }
// Build implements Buildable // Build implements Buildable
@@ -43,6 +44,7 @@ func (a *VMessAccount) Build() *vmess.Account {
SecuritySettings: &protocol.SecurityConfig{ SecuritySettings: &protocol.SecurityConfig{
Type: st, Type: st,
}, },
TestsEnabled: a.Experiments,
} }
} }

View File

@@ -47,8 +47,7 @@ func TestVMessOutbound(t *testing.T) {
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",
AlterId: 0,
SecuritySettings: &protocol.SecurityConfig{ SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AUTO, Type: protocol.SecurityType_AUTO,
}, },
@@ -74,14 +73,12 @@ func TestVMessInbound(t *testing.T) {
{ {
"id": "27848739-7e62-4138-9fd3-098a63964b6b", "id": "27848739-7e62-4138-9fd3-098a63964b6b",
"level": 0, "level": 0,
"alterId": 16,
"email": "love@example.com", "email": "love@example.com",
"security": "aes-128-gcm" "security": "aes-128-gcm"
} }
], ],
"default": { "default": {
"level": 0, "level": 0
"alterId": 32
}, },
"detour": { "detour": {
"to": "tag_to_detour" "to": "tag_to_detour"
@@ -95,8 +92,7 @@ func TestVMessInbound(t *testing.T) {
Level: 0, Level: 0,
Email: "love@example.com", Email: "love@example.com",
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
Id: "27848739-7e62-4138-9fd3-098a63964b6b", Id: "27848739-7e62-4138-9fd3-098a63964b6b",
AlterId: 16,
SecuritySettings: &protocol.SecurityConfig{ SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM, Type: protocol.SecurityType_AES128_GCM,
}, },
@@ -104,8 +100,7 @@ func TestVMessInbound(t *testing.T) {
}, },
}, },
Default: &inbound.DefaultConfig{ Default: &inbound.DefaultConfig{
Level: 0, Level: 0,
AlterId: 32,
}, },
Detour: &inbound.DetourConfig{ Detour: &inbound.DetourConfig{
To: "tag_to_detour", To: "tag_to_detour",

View File

@@ -2,6 +2,7 @@ package conf
import ( import (
"encoding/json" "encoding/json"
"fmt"
"log" "log"
"os" "os"
"strings" "strings"
@@ -10,9 +11,8 @@ import (
"github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/app/stats" "github.com/xtls/xray-core/app/stats"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/transport/internet"
core "github.com/xtls/xray-core/core" core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/xtls" "github.com/xtls/xray-core/transport/internet/xtls"
) )
@@ -162,7 +162,7 @@ func (c *InboundDetourAllocationConfig) Build() (*proxyman.AllocationStrategy, e
type InboundDetourConfig struct { type InboundDetourConfig struct {
Protocol string `json:"protocol"` Protocol string `json:"protocol"`
PortRange *PortRange `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"`
@@ -177,27 +177,27 @@ func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
receiverSettings := &proxyman.ReceiverConfig{} receiverSettings := &proxyman.ReceiverConfig{}
if c.ListenOn == nil { if c.ListenOn == nil {
// Listen on anyip, must set PortRange // Listen on anyip, must set PortList
if c.PortRange == nil { if c.PortList == nil {
return nil, newError("Listen on AnyIP but no Port(s) set in InboundDetour.") return nil, newError("Listen on AnyIP but no Port(s) set in InboundDetour.")
} }
receiverSettings.PortRange = c.PortRange.Build() receiverSettings.PortList = c.PortList.Build()
} else { } else {
// Listen on specific IP or Unix Domain Socket // Listen on specific IP or Unix Domain Socket
receiverSettings.Listen = c.ListenOn.Build() receiverSettings.Listen = c.ListenOn.Build()
listenDS := c.ListenOn.Family().IsDomain() && (c.ListenOn.Domain()[0] == '/' || c.ListenOn.Domain()[0] == '@') listenDS := c.ListenOn.Family().IsDomain() && (c.ListenOn.Domain()[0] == '/' || c.ListenOn.Domain()[0] == '@')
listenIP := c.ListenOn.Family().IsIP() || (c.ListenOn.Family().IsDomain() && c.ListenOn.Domain() == "localhost") listenIP := c.ListenOn.Family().IsIP() || (c.ListenOn.Family().IsDomain() && c.ListenOn.Domain() == "localhost")
if listenIP { if listenIP {
// Listen on specific IP, must set PortRange // Listen on specific IP, must set PortList
if c.PortRange == nil { if c.PortList == nil {
return nil, newError("Listen on specific ip without port in InboundDetour.") return nil, newError("Listen on specific ip without port in InboundDetour.")
} }
// Listen on IP:Port // Listen on IP:Port
receiverSettings.PortRange = c.PortRange.Build() receiverSettings.PortList = c.PortList.Build()
} else if listenDS { } else if listenDS {
if c.PortRange != nil { if c.PortList != nil {
// Listen on Unix Domain Socket, PortRange should be nil // Listen on Unix Domain Socket, PortList should be nil
receiverSettings.PortRange = nil receiverSettings.PortList = nil
} }
} else { } else {
return nil, newError("unable to listen on domain address: ", c.ListenOn.Domain()) return nil, newError("unable to listen on domain address: ", c.ListenOn.Domain())
@@ -209,9 +209,17 @@ func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
if c.Allocation.Concurrency != nil && c.Allocation.Strategy == "random" { if c.Allocation.Concurrency != nil && c.Allocation.Strategy == "random" {
concurrency = int(*c.Allocation.Concurrency) concurrency = int(*c.Allocation.Concurrency)
} }
portRange := int(c.PortRange.To - c.PortRange.From + 1) portRange := 0
for _, pr := range c.PortList.Range {
portRange += int(pr.To - pr.From + 1)
}
if concurrency >= 0 && concurrency >= portRange { if concurrency >= 0 && concurrency >= portRange {
return nil, newError("not enough ports. concurrency = ", concurrency, " ports: ", c.PortRange.From, " - ", c.PortRange.To) var ports strings.Builder
for _, pr := range c.PortList.Range {
fmt.Fprintf(&ports, "%d-%d ", pr.From, pr.To)
}
return nil, newError("not enough ports. concurrency = ", concurrency, " ports: ", ports.String())
} }
as, err := c.Allocation.Build() as, err := c.Allocation.Build()
@@ -464,6 +472,10 @@ func (c *Config) Override(o *Config, fn string) {
c.FakeDNS = o.FakeDNS c.FakeDNS = o.FakeDNS
} }
if o.Observatory != nil {
c.Observatory = o.Observatory
}
// deprecated attrs... keep them for now // deprecated attrs... keep them for now
if o.InboundConfig != nil { if o.InboundConfig != nil {
c.InboundConfig = o.InboundConfig c.InboundConfig = o.InboundConfig
@@ -636,11 +648,11 @@ func (c *Config) Build() (*core.Config, error) {
} }
// Backward compatibility. // Backward compatibility.
if len(inbounds) > 0 && inbounds[0].PortRange == nil && c.Port > 0 { if len(inbounds) > 0 && inbounds[0].PortList == nil && c.Port > 0 {
inbounds[0].PortRange = &PortRange{ inbounds[0].PortList = &PortList{[]PortRange{{
From: uint32(c.Port), From: uint32(c.Port),
To: uint32(c.Port), To: uint32(c.Port),
} }}}
} }
for _, rawInboundConfig := range inbounds { for _, rawInboundConfig := range inbounds {

View File

@@ -72,7 +72,6 @@ func TestXrayConfig(t *testing.T) {
"settings": { "settings": {
"clients": [ "clients": [
{ {
"alterId": 100,
"security": "aes-128-gcm", "security": "aes-128-gcm",
"id": "0cdf8a45-303d-4fed-9780-29aa7f54175e" "id": "0cdf8a45-303d-4fed-9780-29aa7f54175e"
} }
@@ -102,7 +101,6 @@ func TestXrayConfig(t *testing.T) {
"settings": { "settings": {
"clients": [ "clients": [
{ {
"alterId": 100,
"security": "aes-128-gcm", "security": "aes-128-gcm",
"id": "0cdf8a45-303d-4fed-9780-29aa7f54175e" "id": "0cdf8a45-303d-4fed-9780-29aa7f54175e"
} }
@@ -231,10 +229,7 @@ func TestXrayConfig(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: &net.PortRange{ PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(443)}},
From: 443,
To: 443,
},
StreamSettings: &internet.StreamConfig{ StreamSettings: &internet.StreamConfig{
ProtocolName: "websocket", ProtocolName: "websocket",
TransportSettings: []*internet.TransportConfig{ TransportSettings: []*internet.TransportConfig{
@@ -269,8 +264,7 @@ func TestXrayConfig(t *testing.T) {
{ {
Level: 0, Level: 0,
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
Id: "0cdf8a45-303d-4fed-9780-29aa7f54175e", Id: "0cdf8a45-303d-4fed-9780-29aa7f54175e",
AlterId: 100,
SecuritySettings: &protocol.SecurityConfig{ SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM, Type: protocol.SecurityType_AES128_GCM,
}, },
@@ -281,10 +275,10 @@ func TestXrayConfig(t *testing.T) {
}, },
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: &net.PortRange{ PortList: &net.PortList{Range: []*net.PortRange{{
From: 443, From: 443,
To: 500, To: 500,
}, }}},
AllocationStrategy: &proxyman.AllocationStrategy{ AllocationStrategy: &proxyman.AllocationStrategy{
Type: proxyman.AllocationStrategy_Random, Type: proxyman.AllocationStrategy_Random,
Concurrency: &proxyman.AllocationStrategy_AllocationStrategyConcurrency{ Concurrency: &proxyman.AllocationStrategy_AllocationStrategyConcurrency{
@@ -325,8 +319,7 @@ func TestXrayConfig(t *testing.T) {
{ {
Level: 0, Level: 0,
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
Id: "0cdf8a45-303d-4fed-9780-29aa7f54175e", Id: "0cdf8a45-303d-4fed-9780-29aa7f54175e",
AlterId: 100,
SecuritySettings: &protocol.SecurityConfig{ SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM, Type: protocol.SecurityType_AES128_GCM,
}, },

View File

@@ -14,6 +14,9 @@ import (
_ "github.com/xtls/xray-core/app/proxyman/command" _ "github.com/xtls/xray-core/app/proxyman/command"
_ "github.com/xtls/xray-core/app/stats/command" _ "github.com/xtls/xray-core/app/stats/command"
// Developer preview services
_ "github.com/xtls/xray-core/app/observatory/command"
// Other optional features. // Other optional features.
_ "github.com/xtls/xray-core/app/dns" _ "github.com/xtls/xray-core/app/dns"
_ "github.com/xtls/xray-core/app/dns/fakedns" _ "github.com/xtls/xray-core/app/dns/fakedns"
@@ -26,6 +29,9 @@ import (
// Fix dependency cycle caused by core import in internet package // Fix dependency cycle caused by core import in internet package
_ "github.com/xtls/xray-core/transport/internet/tagged/taggedimpl" _ "github.com/xtls/xray-core/transport/internet/tagged/taggedimpl"
// Developer preview features
_ "github.com/xtls/xray-core/app/observatory"
// Inbound and outbound proxies. // Inbound and outbound proxies.
_ "github.com/xtls/xray-core/proxy/blackhole" _ "github.com/xtls/xray-core/proxy/blackhole"
_ "github.com/xtls/xray-core/proxy/dns" _ "github.com/xtls/xray-core/proxy/dns"

View File

@@ -6,8 +6,6 @@ import (
"sync" "sync"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"golang.org/x/net/dns/dnsmessage" "golang.org/x/net/dns/dnsmessage"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
@@ -22,6 +20,7 @@ import (
"github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
) )
func init() { func init() {

View File

@@ -117,8 +117,8 @@ func TestUDPDNSTunnel(t *testing.T) {
Networks: []net.Network{net.Network_UDP}, Networks: []net.Network{net.Network_UDP},
}), }),
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
}, },
}, },
@@ -236,8 +236,8 @@ func TestTCPDNSTunnel(t *testing.T) {
Networks: []net.Network{net.Network_TCP}, Networks: []net.Network{net.Network_TCP},
}), }),
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
}, },
}, },
@@ -322,8 +322,8 @@ func TestUDP2TCPDNSTunnel(t *testing.T) {
Networks: []net.Network{net.Network_TCP}, Networks: []net.Network{net.Network_TCP},
}), }),
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
}, },
}, },

View File

@@ -7,8 +7,6 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"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/log" "github.com/xtls/xray-core/common/log"
@@ -20,6 +18,7 @@ import (
"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/features/routing"
"github.com/xtls/xray-core/transport/internet/stat"
) )
func init() { func init() {

View File

@@ -6,8 +6,6 @@ import (
"context" "context"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"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/dice" "github.com/xtls/xray-core/common/dice"
@@ -22,6 +20,7 @@ import (
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
) )
func init() { func init() {

View File

@@ -9,8 +9,6 @@ import (
"net/url" "net/url"
"sync" "sync"
"github.com/xtls/xray-core/transport/internet/stat"
"golang.org/x/net/http2" "golang.org/x/net/http2"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
@@ -26,6 +24,7 @@ import (
"github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
) )

View File

@@ -9,8 +9,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"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"
@@ -24,6 +22,7 @@ import (
"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/features/routing"
"github.com/xtls/xray-core/transport/internet/stat"
) )
// Server is an HTTP proxy server. // Server is an HTTP proxy server.

View File

@@ -2,11 +2,11 @@ package loopback
import ( import (
"context" "context"
"github.com/xtls/xray-core/common/net/cnc"
"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/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/retry" "github.com/xtls/xray-core/common/retry"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"

View File

@@ -5,8 +5,6 @@ import (
"context" "context"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/common/crypto"
@@ -18,6 +16,7 @@ import (
"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/features/routing"
"github.com/xtls/xray-core/transport/internet/stat"
) )
var dcList = []net.Address{ var dcList = []net.Address{

View File

@@ -8,13 +8,12 @@ package proxy
import ( import (
"context" "context"
"github.com/xtls/xray-core/transport/internet/stat"
"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/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/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
) )
// An Inbound processes inbound connections. // An Inbound processes inbound connections.

View File

@@ -4,8 +4,6 @@ import (
"context" "context"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"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/net" "github.com/xtls/xray-core/common/net"
@@ -18,6 +16,7 @@ import (
"github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
) )
// Client is a inbound handler for Shadowsocks protocol // Client is a inbound handler for Shadowsocks protocol

View File

@@ -7,8 +7,6 @@ import (
"crypto/md5" "crypto/md5"
"crypto/sha1" "crypto/sha1"
"io" "io"
"reflect"
"strconv"
"golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/hkdf" "golang.org/x/crypto/hkdf"
@@ -28,6 +26,10 @@ type MemoryAccount struct {
replayFilter antireplay.GeneralizedReplayFilter replayFilter antireplay.GeneralizedReplayFilter
} }
var (
ErrIVNotUnique = newError("IV is not unique")
)
// Equals implements protocol.Account.Equals(). // Equals implements protocol.Account.Equals().
func (a *MemoryAccount) Equals(another protocol.Account) bool { func (a *MemoryAccount) Equals(another protocol.Account) bool {
if account, ok := another.(*MemoryAccount); ok { if account, ok := another.(*MemoryAccount); ok {
@@ -43,24 +45,7 @@ func (a *MemoryAccount) CheckIV(iv []byte) error {
if a.replayFilter.Check(iv) { if a.replayFilter.Check(iv) {
return nil return nil
} }
return newError("IV is not unique") return ErrIVNotUnique
}
func (a *MemoryAccount) GetCipherName() string {
switch a.Cipher.(type) {
case *AEADCipher:
switch reflect.ValueOf(a.Cipher.(*AEADCipher).AEADAuthCreator).Pointer() {
case reflect.ValueOf(createAesGcm).Pointer():
keyBytes := a.Cipher.(*AEADCipher).KeyBytes
return "AES_" + strconv.FormatInt(int64(keyBytes*8), 10) + "_GCM"
case reflect.ValueOf(createChaCha20Poly1305).Pointer():
return "CHACHA20_POLY1305"
}
case *NoneCipher:
return "NONE"
}
return ""
} }
func createAesGcm(key []byte) cipher.AEAD { func createAesGcm(key []byte) cipher.AEAD {

View File

@@ -1,7 +1,6 @@
package shadowsocks package shadowsocks
import ( import (
"crypto/cipher"
"crypto/hmac" "crypto/hmac"
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
@@ -11,7 +10,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/crypto" "github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/drain"
"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"
) )
@@ -54,83 +53,55 @@ func (r *FullReader) Read(p []byte) (n int, err error) {
// ReadTCPSession reads a Shadowsocks TCP session from the given reader, returns its header and remaining parts. // ReadTCPSession reads a Shadowsocks TCP session from the given reader, returns its header and remaining parts.
func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) { func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {
hashkdf := hmac.New(sha256.New, []byte("SSBSKDF")) behaviorSeed := validator.GetBehaviorSeed()
drainer, errDrain := drain.NewBehaviorSeedLimitedDrainer(int64(behaviorSeed), 16+38, 3266, 64)
behaviorSeed := crc32.ChecksumIEEE(hashkdf.Sum(nil)) if errDrain != nil {
return nil, nil, newError("failed to initialize drainer").Base(errDrain)
}
behaviorRand := dice.NewDeterministicDice(int64(behaviorSeed)) var r buf.Reader
BaseDrainSize := behaviorRand.Roll(3266)
RandDrainMax := behaviorRand.Roll(64) + 1
RandDrainRolled := dice.Roll(RandDrainMax)
DrainSize := BaseDrainSize + 16 + 38 + RandDrainRolled
readSizeRemain := DrainSize
var r2 buf.Reader
buffer := buf.New() buffer := buf.New()
defer buffer.Release() defer buffer.Release()
var user *protocol.MemoryUser if _, err := buffer.ReadFullFrom(reader, 50); err != nil {
var ivLen int32 drainer.AcknowledgeReceive(int(buffer.Len()))
var iv []byte return nil, nil, drain.WithError(drainer, reader, newError("failed to read 50 bytes").Base(err))
var err error }
count := validator.Count() bs := buffer.Bytes()
if count == 0 { user, aead, _, ivLen, err := validator.Get(bs, protocol.RequestCommandTCP)
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("invalid user")
} else if count > 1 {
var aead cipher.AEAD
if _, err := buffer.ReadFullFrom(reader, 50); err != nil { switch err {
readSizeRemain -= int(buffer.Len()) case ErrNotFound:
DrainConnN(reader, readSizeRemain) drainer.AcknowledgeReceive(int(buffer.Len()))
return nil, nil, newError("failed to read 50 bytes").Base(err) return nil, nil, drain.WithError(drainer, reader, newError("failed to match an user").Base(err))
} case ErrIVNotUnique:
drainer.AcknowledgeReceive(int(buffer.Len()))
return nil, nil, drain.WithError(drainer, reader, newError("failed iv check").Base(err))
default:
reader = &FullReader{reader, bs[ivLen:]}
drainer.AcknowledgeReceive(int(ivLen))
bs := buffer.Bytes() if aead != nil {
user, aead, _, ivLen, err = validator.Get(bs, protocol.RequestCommandTCP)
if user != nil {
if ivLen > 0 {
iv = append([]byte(nil), bs[:ivLen]...)
}
reader = &FullReader{reader, bs[ivLen:]}
auth := &crypto.AEADAuthenticator{ auth := &crypto.AEADAuthenticator{
AEAD: aead, AEAD: aead,
NonceGenerator: crypto.GenerateInitialAEADNonce(), NonceGenerator: crypto.GenerateAEADNonceWithSize(aead.NonceSize()),
} }
r2 = crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{ r = crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
Auth: auth, Auth: auth,
}, reader, protocol.TransferTypeStream, nil) }, reader, protocol.TransferTypeStream, nil)
} else { } else {
readSizeRemain -= int(buffer.Len()) account := user.Account.(*MemoryAccount)
DrainConnN(reader, readSizeRemain) iv := append([]byte(nil), buffer.BytesTo(ivLen)...)
return nil, nil, newError("failed to match an user").Base(err) r, err = account.Cipher.NewDecryptionReader(account.Key, iv, reader)
} if err != nil {
} else { return nil, nil, drain.WithError(drainer, reader, newError("failed to initialize decoding stream").Base(err).AtError())
user, ivLen = validator.GetOnlyUser()
account := user.Account.(*MemoryAccount)
hashkdf.Write(account.Key)
if ivLen > 0 {
if _, err := buffer.ReadFullFrom(reader, ivLen); err != nil {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed to read IV").Base(err)
} }
iv = append([]byte(nil), buffer.BytesTo(ivLen)...)
} }
r, err := account.Cipher.NewDecryptionReader(account.Key, iv, reader)
if err != nil {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed to initialize decoding stream").Base(err).AtError()
}
r2 = r
} }
br := &buf.BufferedReader{Reader: r2} br := &buf.BufferedReader{Reader: r}
request := &protocol.RequestHeader{ request := &protocol.RequestHeader{
Version: Version, Version: Version,
@@ -138,40 +109,25 @@ func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHe
Command: protocol.RequestCommandTCP, Command: protocol.RequestCommandTCP,
} }
readSizeRemain -= int(buffer.Len())
buffer.Clear() buffer.Clear()
addr, port, err := addrParser.ReadAddressPort(buffer, br) addr, port, err := addrParser.ReadAddressPort(buffer, br)
if err != nil { if err != nil {
readSizeRemain -= int(buffer.Len()) drainer.AcknowledgeReceive(int(buffer.Len()))
DrainConnN(reader, readSizeRemain) return nil, nil, drain.WithError(drainer, reader, newError("failed to read address").Base(err))
return nil, nil, newError("failed to read address").Base(err)
} }
request.Address = addr request.Address = addr
request.Port = port request.Port = port
if request.Address == nil { if request.Address == nil {
readSizeRemain -= int(buffer.Len()) drainer.AcknowledgeReceive(int(buffer.Len()))
DrainConnN(reader, readSizeRemain) return nil, nil, drain.WithError(drainer, reader, newError("invalid remote address."))
return nil, nil, newError("invalid remote address.")
}
account := user.Account.(*MemoryAccount)
if ivError := account.CheckIV(iv); ivError != nil {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed iv check").Base(ivError)
} }
return request, br, nil return request, br, nil
} }
func DrainConnN(reader io.Reader, n int) error {
_, err := io.CopyN(io.Discard, reader, int64(n))
return err
}
// WriteTCPRequest writes Shadowsocks request into the given writer, and returns a writer for body. // WriteTCPRequest writes Shadowsocks request into the given writer, and returns a writer for body.
func WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (buf.Writer, error) { func WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (buf.Writer, error) {
user := request.User user := request.User
@@ -210,16 +166,29 @@ func WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (buf.Wri
func ReadTCPResponse(user *protocol.MemoryUser, reader io.Reader) (buf.Reader, error) { func ReadTCPResponse(user *protocol.MemoryUser, reader io.Reader) (buf.Reader, error) {
account := user.Account.(*MemoryAccount) account := user.Account.(*MemoryAccount)
hashkdf := hmac.New(sha256.New, []byte("SSBSKDF"))
hashkdf.Write(account.Key)
behaviorSeed := crc32.ChecksumIEEE(hashkdf.Sum(nil))
drainer, err := drain.NewBehaviorSeedLimitedDrainer(int64(behaviorSeed), 16+38, 3266, 64)
if err != nil {
return nil, newError("failed to initialize drainer").Base(err)
}
var iv []byte var iv []byte
if account.Cipher.IVSize() > 0 { if account.Cipher.IVSize() > 0 {
iv = make([]byte, account.Cipher.IVSize()) iv = make([]byte, account.Cipher.IVSize())
if _, err := io.ReadFull(reader, iv); err != nil { if n, err := io.ReadFull(reader, iv); err != nil {
return nil, newError("failed to read IV").Base(err) return nil, newError("failed to read IV").Base(err)
} else { // nolint: golint
drainer.AcknowledgeReceive(n)
} }
} }
if ivError := account.CheckIV(iv); ivError != nil { if ivError := account.CheckIV(iv); ivError != nil {
return nil, newError("failed iv check").Base(ivError) return nil, drain.WithError(drainer, reader, newError("failed iv check").Base(ivError))
} }
return account.Cipher.NewDecryptionReader(account.Key, iv, reader) return account.Cipher.NewDecryptionReader(account.Key, iv, reader)
@@ -273,34 +242,25 @@ func DecodeUDPPacket(validator *Validator, payload *buf.Buffer) (*protocol.Reque
return nil, nil, newError("len(bs) <= 32") return nil, nil, newError("len(bs) <= 32")
} }
var user *protocol.MemoryUser user, _, d, _, err := validator.Get(bs, protocol.RequestCommandUDP)
var err error switch err {
case ErrIVNotUnique:
count := validator.Count() return nil, nil, newError("failed iv check").Base(err)
if count == 0 { case ErrNotFound:
return nil, nil, newError("invalid user") return nil, nil, newError("failed to match an user").Base(err)
} else if count > 1 { default:
var d []byte account := user.Account.(*MemoryAccount)
user, _, d, _, err = validator.Get(bs, protocol.RequestCommandUDP) if account.Cipher.IsAEAD() {
if user != nil {
payload.Clear() payload.Clear()
payload.Write(d) payload.Write(d)
} else { } else {
return nil, nil, newError("failed to decrypt UDP payload").Base(err) if account.Cipher.IVSize() > 0 {
} iv := make([]byte, account.Cipher.IVSize())
} else { copy(iv, payload.BytesTo(account.Cipher.IVSize()))
user, _ = validator.GetOnlyUser() }
account := user.Account.(*MemoryAccount) if err = account.Cipher.DecodePacket(account.Key, payload); err != nil {
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
var iv []byte }
if !account.Cipher.IsAEAD() && account.Cipher.IVSize() > 0 {
// Keep track of IV as it gets removed from payload in DecodePacket.
iv = make([]byte, account.Cipher.IVSize())
copy(iv, payload.BytesTo(account.Cipher.IVSize()))
}
if err = account.Cipher.DecodePacket(account.Key, payload); err != nil {
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
} }
} }

View File

@@ -4,8 +4,6 @@ import (
"context" "context"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"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/log" "github.com/xtls/xray-core/common/log"
@@ -18,6 +16,7 @@ import (
"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/features/routing"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/udp" "github.com/xtls/xray-core/transport/internet/udp"
) )
@@ -115,10 +114,6 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dis
panic("no inbound metadata") panic("no inbound metadata")
} }
if s.validator.Count() == 1 {
inbound.User, _ = s.validator.GetOnlyUser()
}
var dest *net.Destination var dest *net.Destination
reader := buf.NewPacketReader(conn) reader := buf.NewPacketReader(conn)

View File

@@ -2,112 +2,127 @@ package shadowsocks
import ( import (
"crypto/cipher" "crypto/cipher"
"crypto/hmac"
"crypto/sha256"
"hash/crc64"
"strings" "strings"
"sync" "sync"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
) )
// Validator stores valid Shadowsocks users. // Validator stores valid Shadowsocks users.
type Validator struct { type Validator struct {
// Considering email's usage here, map + sync.Mutex/RWMutex may have better performance. sync.RWMutex
email sync.Map users []*protocol.MemoryUser
users sync.Map
behaviorSeed uint64
behaviorFused bool
} }
// Add a Shadowsocks user, Email must be empty or unique. var (
ErrNotFound = newError("Not Found")
)
// Add a Shadowsocks user.
func (v *Validator) Add(u *protocol.MemoryUser) error { func (v *Validator) Add(u *protocol.MemoryUser) error {
v.Lock()
defer v.Unlock()
account := u.Account.(*MemoryAccount) account := u.Account.(*MemoryAccount)
if !account.Cipher.IsAEAD() && len(v.users) > 0 {
return newError("The cipher is not support Single-port Multi-user")
}
v.users = append(v.users, u)
if !account.Cipher.IsAEAD() && v.Count() > 0 { if !v.behaviorFused {
return newError("The cipher do not support Single-port Multi-user") hashkdf := hmac.New(sha256.New, []byte("SSBSKDF"))
hashkdf.Write(account.Key)
v.behaviorSeed = crc64.Update(v.behaviorSeed, crc64.MakeTable(crc64.ECMA), hashkdf.Sum(nil))
} }
if u.Email != "" {
_, loaded := v.email.LoadOrStore(strings.ToLower(u.Email), u)
if loaded {
return newError("User ", u.Email, " already exists.")
}
}
v.users.Store(string(account.Key)+"&"+account.GetCipherName(), u)
return nil return nil
} }
// Del a Shadowsocks user with a non-empty Email. // Del a Shadowsocks user with a non-empty Email.
func (v *Validator) Del(e string) error { func (v *Validator) Del(email string) error {
if e == "" { if email == "" {
return newError("Email must not be empty.") return newError("Email must not be empty.")
} }
le := strings.ToLower(e)
u, _ := v.email.Load(le) v.Lock()
if u == nil { defer v.Unlock()
return newError("User ", e, " not found.")
email = strings.ToLower(email)
idx := -1
for i, u := range v.users {
if strings.EqualFold(u.Email, email) {
idx = i
break
}
} }
account := u.(*protocol.MemoryUser).Account.(*MemoryAccount)
v.email.Delete(le) if idx == -1 {
v.users.Delete(string(account.Key) + "&" + account.GetCipherName()) return newError("User ", email, " not found.")
}
ulen := len(v.users)
v.users[idx] = v.users[ulen-1]
v.users[ulen-1] = nil
v.users = v.users[:ulen-1]
return nil return nil
} }
// Count the number of Shadowsocks users // Get a Shadowsocks user.
func (v *Validator) Count() int {
length := 0
v.users.Range(func(_, _ interface{}) bool {
length++
return true
})
return length
}
// Get a Shadowsocks user and the user's cipher.
func (v *Validator) Get(bs []byte, command protocol.RequestCommand) (u *protocol.MemoryUser, aead cipher.AEAD, ret []byte, ivLen int32, err error) { func (v *Validator) Get(bs []byte, command protocol.RequestCommand) (u *protocol.MemoryUser, aead cipher.AEAD, ret []byte, ivLen int32, err error) {
var dataSize int v.RLock()
defer v.RUnlock()
switch command { for _, user := range v.users {
case protocol.RequestCommandTCP: if account := user.Account.(*MemoryAccount); account.Cipher.IsAEAD() {
dataSize = 16 aeadCipher := account.Cipher.(*AEADCipher)
case protocol.RequestCommandUDP: ivLen = aeadCipher.IVSize()
dataSize = 8192 iv := bs[:ivLen]
subkey := make([]byte, 32)
subkey = subkey[:aeadCipher.KeyBytes]
hkdfSHA1(account.Key, iv, subkey)
aead = aeadCipher.AEADAuthCreator(subkey)
var matchErr error
switch command {
case protocol.RequestCommandTCP:
data := make([]byte, 4+aead.NonceSize())
ret, matchErr = aead.Open(data[:0], data[4:], bs[ivLen:ivLen+18], nil)
case protocol.RequestCommandUDP:
data := make([]byte, 8192)
ret, matchErr = aead.Open(data[:0], data[8192-aead.NonceSize():8192], bs[ivLen:], nil)
}
if matchErr == nil {
u = user
err = account.CheckIV(iv)
return
}
} else {
u = user
ivLen = user.Account.(*MemoryAccount).Cipher.IVSize()
// err = user.Account.(*MemoryAccount).CheckIV(bs[:ivLen]) // The IV size of None Cipher is 0.
return
}
} }
var aeadCipher *AEADCipher return nil, nil, nil, 0, ErrNotFound
subkey := make([]byte, 32)
data := make([]byte, dataSize)
v.users.Range(func(key, user interface{}) bool {
account := user.(*protocol.MemoryUser).Account.(*MemoryAccount)
aeadCipher = account.Cipher.(*AEADCipher)
ivLen = aeadCipher.IVSize()
subkey = subkey[:aeadCipher.KeyBytes]
hkdfSHA1(account.Key, bs[:ivLen], subkey)
aead = aeadCipher.AEADAuthCreator(subkey)
switch command {
case protocol.RequestCommandTCP:
ret, err = aead.Open(data[:0], data[4:16], bs[ivLen:ivLen+18], nil)
case protocol.RequestCommandUDP:
ret, err = aead.Open(data[:0], data[8180:8192], bs[ivLen:], nil)
}
if err == nil {
u = user.(*protocol.MemoryUser)
return false
}
return true
})
return
} }
// Get the only user without authentication func (v *Validator) GetBehaviorSeed() uint64 {
func (v *Validator) GetOnlyUser() (u *protocol.MemoryUser, ivLen int32) { v.Lock()
v.users.Range(func(_, user interface{}) bool { defer v.Unlock()
u = user.(*protocol.MemoryUser)
return false
})
ivLen = u.Account.(*MemoryAccount).Cipher.IVSize()
return v.behaviorFused = true
if v.behaviorSeed == 0 {
v.behaviorSeed = dice.RollUint64()
}
return v.behaviorSeed
} }

View File

@@ -4,8 +4,6 @@ import (
"context" "context"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"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/net" "github.com/xtls/xray-core/common/net"
@@ -19,6 +17,7 @@ import (
"github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
) )
// Client is a Socks5 client. // Client is a Socks5 client.

View File

@@ -5,8 +5,6 @@ import (
"io" "io"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"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/log" "github.com/xtls/xray-core/common/log"
@@ -20,6 +18,7 @@ import (
"github.com/xtls/xray-core/features" "github.com/xtls/xray-core/features"
"github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/udp" "github.com/xtls/xray-core/transport/internet/udp"
) )

View File

@@ -5,8 +5,6 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"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"
@@ -22,6 +20,7 @@ import (
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/xtls" "github.com/xtls/xray-core/transport/internet/xtls"
) )

View File

@@ -8,8 +8,6 @@ import (
"runtime" "runtime"
"syscall" "syscall"
"github.com/xtls/xray-core/transport/internet/stat"
"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/net"
@@ -17,6 +15,7 @@ import (
"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/features/stats" "github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/xtls" "github.com/xtls/xray-core/transport/internet/xtls"
) )

View File

@@ -8,8 +8,6 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"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"
@@ -26,6 +24,7 @@ import (
"github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/features/stats"
"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/internet/udp" "github.com/xtls/xray-core/transport/internet/udp"
"github.com/xtls/xray-core/transport/internet/xtls" "github.com/xtls/xray-core/transport/internet/xtls"

View File

@@ -9,8 +9,6 @@ import (
"runtime" "runtime"
"syscall" "syscall"
"github.com/xtls/xray-core/transport/internet/stat"
"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/net"
@@ -19,6 +17,7 @@ import (
"github.com/xtls/xray-core/common/signal" "github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/proxy/vless" "github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/xtls" "github.com/xtls/xray-core/transport/internet/xtls"
) )

View File

@@ -10,8 +10,6 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"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"
@@ -31,6 +29,7 @@ import (
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/features/stats"
"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"
"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/internet/xtls" "github.com/xtls/xray-core/transport/internet/xtls"
) )

View File

@@ -7,8 +7,6 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"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/net" "github.com/xtls/xray-core/common/net"
@@ -26,6 +24,7 @@ import (
"github.com/xtls/xray-core/proxy/vless/encoding" "github.com/xtls/xray-core/proxy/vless/encoding"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/xtls" "github.com/xtls/xray-core/transport/internet/xtls"
) )

View File

@@ -1,6 +1,8 @@
package vmess package vmess
import ( import (
"strings"
"github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/uuid" "github.com/xtls/xray-core/common/uuid"
@@ -14,6 +16,9 @@ type MemoryAccount struct {
AlterIDs []*protocol.ID AlterIDs []*protocol.ID
// Security type of the account. Used for client connections. // Security type of the account. Used for client connections.
Security protocol.SecurityType Security protocol.SecurityType
AuthenticatedLengthExperiment bool
NoTerminationSignal bool
} }
// AnyValidID returns an ID that is either the main ID or one of the alternative IDs if any. // AnyValidID returns an ID that is either the main ID or one of the alternative IDs if any.
@@ -41,9 +46,18 @@ func (a *Account) AsAccount() (protocol.Account, error) {
return nil, newError("failed to parse ID").Base(err).AtError() return nil, newError("failed to parse ID").Base(err).AtError()
} }
protoID := protocol.NewID(id) protoID := protocol.NewID(id)
var AuthenticatedLength, NoTerminationSignal bool
if strings.Contains(a.TestsEnabled, "AuthenticatedLength") {
AuthenticatedLength = true
}
if strings.Contains(a.TestsEnabled, "NoTerminationSignal") {
NoTerminationSignal = true
}
return &MemoryAccount{ return &MemoryAccount{
ID: protoID, ID: protoID,
AlterIDs: protocol.NewAlterIDs(protoID, uint16(a.AlterId)), AlterIDs: protocol.NewAlterIDs(protoID, uint16(a.AlterId)),
Security: a.SecuritySettings.GetSecurityType(), Security: a.SecuritySettings.GetSecurityType(),
AuthenticatedLengthExperiment: AuthenticatedLength,
NoTerminationSignal: NoTerminationSignal,
}, nil }, nil
} }

View File

@@ -5,9 +5,10 @@ import (
"encoding/binary" "encoding/binary"
"hash/fnv" "hash/fnv"
"github.com/xtls/xray-core/common"
"golang.org/x/crypto/sha3" "golang.org/x/crypto/sha3"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/crypto"
) )
// Authenticate authenticates a byte array using Fnv hash. // Authenticate authenticates a byte array using Fnv hash.
@@ -116,3 +117,11 @@ func (s *ShakeSizeParser) NextPaddingLen() uint16 {
func (s *ShakeSizeParser) MaxPaddingLen() uint16 { func (s *ShakeSizeParser) MaxPaddingLen() uint16 {
return 64 return 64
} }
type AEADSizeParser struct {
crypto.AEADChunkSizeParser
}
func NewAEADSizeParser(auth *crypto.AEADAuthenticator) *AEADSizeParser {
return &AEADSizeParser{crypto.AEADChunkSizeParser{Auth: auth}}
}

View File

@@ -20,6 +20,7 @@ import (
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/drain"
"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/serial"
"github.com/xtls/xray-core/proxy/vmess" "github.com/xtls/xray-core/proxy/vmess"
@@ -44,10 +45,12 @@ type ClientSession struct {
responseBodyIV [16]byte responseBodyIV [16]byte
responseReader io.Reader responseReader io.Reader
responseHeader byte responseHeader byte
readDrainer drain.Drainer
} }
// NewClientSession creates a new ClientSession. // NewClientSession creates a new ClientSession.
func NewClientSession(ctx context.Context, isAEAD bool, idHash protocol.IDHash) *ClientSession { func NewClientSession(ctx context.Context, isAEAD bool, idHash protocol.IDHash, behaviorSeed int64) *ClientSession {
session := &ClientSession{ session := &ClientSession{
isAEAD: isAEAD, isAEAD: isAEAD,
idHash: idHash, idHash: idHash,
@@ -68,6 +71,14 @@ func NewClientSession(ctx context.Context, isAEAD bool, idHash protocol.IDHash)
BodyIV := sha256.Sum256(session.requestBodyIV[:]) BodyIV := sha256.Sum256(session.requestBodyIV[:])
copy(session.responseBodyIV[:], BodyIV[:16]) copy(session.responseBodyIV[:], BodyIV[:16])
} }
{
var err error
session.readDrainer, err = drain.NewBehaviorSeedLimitedDrainer(behaviorSeed, 18, 3266, 64)
if err != nil {
newError("unable to initialize drainer").Base(err).WriteToLog()
session.readDrainer = drain.NewNopDrainer()
}
}
return session return session
} }
@@ -171,6 +182,17 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())), NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(), AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
} }
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
AuthenticatedLengthKey := vmessaead.KDF16(c.requestBodyKey[:], "auth_len")
AuthenticatedLengthKeyAEAD := crypto.NewAesGcm(AuthenticatedLengthKey)
lengthAuth := &crypto.AEADAuthenticator{
AEAD: AuthenticatedLengthKeyAEAD,
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
sizeParser = NewAEADSizeParser(lengthAuth)
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding) return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
case protocol.SecurityType_CHACHA20_POLY1305: case protocol.SecurityType_CHACHA20_POLY1305:
aead, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.requestBodyKey[:])) aead, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.requestBodyKey[:]))
@@ -181,6 +203,18 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())), NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(), AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
} }
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
AuthenticatedLengthKey := vmessaead.KDF16(c.requestBodyKey[:], "auth_len")
AuthenticatedLengthKeyAEAD, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(AuthenticatedLengthKey))
common.Must(err)
lengthAuth := &crypto.AEADAuthenticator{
AEAD: AuthenticatedLengthKeyAEAD,
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
sizeParser = NewAEADSizeParser(lengthAuth)
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding) return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
default: default:
panic("Unknown security type.") panic("Unknown security type.")
@@ -202,12 +236,15 @@ func (c *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.Respon
var decryptedResponseHeaderLength int var decryptedResponseHeaderLength int
var decryptedResponseHeaderLengthBinaryDeserializeBuffer uint16 var decryptedResponseHeaderLengthBinaryDeserializeBuffer uint16
if _, err := io.ReadFull(reader, aeadEncryptedResponseHeaderLength[:]); err != nil { if n, err := io.ReadFull(reader, aeadEncryptedResponseHeaderLength[:]); err != nil {
return nil, newError("Unable to Read Header Len").Base(err) c.readDrainer.AcknowledgeReceive(n)
return nil, drain.WithError(c.readDrainer, reader, newError("Unable to Read Header Len").Base(err))
} else { // nolint: golint
c.readDrainer.AcknowledgeReceive(n)
} }
if decryptedResponseHeaderLengthBinaryBuffer, err := aeadResponseHeaderLengthEncryptionAEAD.Open(nil, aeadResponseHeaderLengthEncryptionIV, aeadEncryptedResponseHeaderLength[:], nil); err != nil { if decryptedResponseHeaderLengthBinaryBuffer, err := aeadResponseHeaderLengthEncryptionAEAD.Open(nil, aeadResponseHeaderLengthEncryptionIV, aeadEncryptedResponseHeaderLength[:], nil); err != nil {
return nil, newError("Failed To Decrypt Length").Base(err) return nil, drain.WithError(c.readDrainer, reader, newError("Failed To Decrypt Length").Base(err))
} else { } else { // nolint: golint
common.Must(binary.Read(bytes.NewReader(decryptedResponseHeaderLengthBinaryBuffer), binary.BigEndian, &decryptedResponseHeaderLengthBinaryDeserializeBuffer)) common.Must(binary.Read(bytes.NewReader(decryptedResponseHeaderLengthBinaryBuffer), binary.BigEndian, &decryptedResponseHeaderLengthBinaryDeserializeBuffer))
decryptedResponseHeaderLength = int(decryptedResponseHeaderLengthBinaryDeserializeBuffer) decryptedResponseHeaderLength = int(decryptedResponseHeaderLengthBinaryDeserializeBuffer)
} }
@@ -220,13 +257,16 @@ func (c *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.Respon
encryptedResponseHeaderBuffer := make([]byte, decryptedResponseHeaderLength+16) encryptedResponseHeaderBuffer := make([]byte, decryptedResponseHeaderLength+16)
if _, err := io.ReadFull(reader, encryptedResponseHeaderBuffer); err != nil { if n, err := io.ReadFull(reader, encryptedResponseHeaderBuffer); err != nil {
return nil, newError("Unable to Read Header Data").Base(err) c.readDrainer.AcknowledgeReceive(n)
return nil, drain.WithError(c.readDrainer, reader, newError("Unable to Read Header Data").Base(err))
} else { // nolint: golint
c.readDrainer.AcknowledgeReceive(n)
} }
if decryptedResponseHeaderBuffer, err := aeadResponseHeaderPayloadEncryptionAEAD.Open(nil, aeadResponseHeaderPayloadEncryptionIV, encryptedResponseHeaderBuffer, nil); err != nil { if decryptedResponseHeaderBuffer, err := aeadResponseHeaderPayloadEncryptionAEAD.Open(nil, aeadResponseHeaderPayloadEncryptionIV, encryptedResponseHeaderBuffer, nil); err != nil {
return nil, newError("Failed To Decrypt Payload").Base(err) return nil, drain.WithError(c.readDrainer, reader, newError("Failed To Decrypt Payload").Base(err))
} else { } else { // nolint: golint
c.responseReader = bytes.NewReader(decryptedResponseHeaderBuffer) c.responseReader = bytes.NewReader(decryptedResponseHeaderBuffer)
} }
} }
@@ -312,6 +352,17 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
NonceGenerator: GenerateChunkNonce(c.responseBodyIV[:], uint32(aead.NonceSize())), NonceGenerator: GenerateChunkNonce(c.responseBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(), AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
} }
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
AuthenticatedLengthKey := vmessaead.KDF16(c.requestBodyKey[:], "auth_len")
AuthenticatedLengthKeyAEAD := crypto.NewAesGcm(AuthenticatedLengthKey)
lengthAuth := &crypto.AEADAuthenticator{
AEAD: AuthenticatedLengthKeyAEAD,
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
sizeParser = NewAEADSizeParser(lengthAuth)
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding) return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
case protocol.SecurityType_CHACHA20_POLY1305: case protocol.SecurityType_CHACHA20_POLY1305:
aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.responseBodyKey[:])) aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.responseBodyKey[:]))
@@ -321,6 +372,18 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
NonceGenerator: GenerateChunkNonce(c.responseBodyIV[:], uint32(aead.NonceSize())), NonceGenerator: GenerateChunkNonce(c.responseBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(), AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
} }
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
AuthenticatedLengthKey := vmessaead.KDF16(c.requestBodyKey[:], "auth_len")
AuthenticatedLengthKeyAEAD, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(AuthenticatedLengthKey))
common.Must(err)
lengthAuth := &crypto.AEADAuthenticator{
AEAD: AuthenticatedLengthKeyAEAD,
NonceGenerator: GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
sizeParser = NewAEADSizeParser(lengthAuth)
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding) return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
default: default:
panic("Unknown security type.") panic("Unknown security type.")

View File

@@ -139,7 +139,7 @@ func (f *CommandSwitchAccountFactory) Unmarshal(data []byte) (interface{}, error
} }
cmd.Level = uint32(data[levelStart]) cmd.Level = uint32(data[levelStart])
timeStart := levelStart + 1 timeStart := levelStart + 1
if len(data) < timeStart { if len(data) < timeStart+1 {
return nil, newError("insufficient length.") return nil, newError("insufficient length.")
} }
cmd.ValidMin = data[timeStart] cmd.ValidMin = data[timeStart]

View File

@@ -4,6 +4,7 @@ import (
"testing" "testing"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
"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"
@@ -35,3 +36,23 @@ func TestSwitchAccount(t *testing.T) {
t.Error(r) t.Error(r)
} }
} }
func TestSwitchAccountBugOffByOne(t *testing.T) {
sa := &protocol.CommandSwitchAccount{
Port: 1234,
ID: uuid.New(),
AlterIds: 1024,
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)
}

View File

@@ -28,8 +28,7 @@ func TestRequestSerialization(t *testing.T) {
} }
id := uuid.New() id := uuid.New()
account := &vmess.Account{ account := &vmess.Account{
Id: id.String(), Id: id.String(),
AlterId: 0,
} }
user.Account = toAccount(account) user.Account = toAccount(account)
@@ -43,7 +42,7 @@ func TestRequestSerialization(t *testing.T) {
} }
buffer := buf.New() buffer := buf.New()
client := NewClientSession(context.TODO(), true, protocol.DefaultIDHash) client := NewClientSession(context.TODO(), true, protocol.DefaultIDHash, 0)
common.Must(client.EncodeRequestHeader(expectedRequest, buffer)) common.Must(client.EncodeRequestHeader(expectedRequest, buffer))
buffer2 := buf.New() buffer2 := buf.New()
@@ -78,8 +77,7 @@ func TestInvalidRequest(t *testing.T) {
} }
id := uuid.New() id := uuid.New()
account := &vmess.Account{ account := &vmess.Account{
Id: id.String(), Id: id.String(),
AlterId: 0,
} }
user.Account = toAccount(account) user.Account = toAccount(account)
@@ -93,7 +91,7 @@ func TestInvalidRequest(t *testing.T) {
} }
buffer := buf.New() buffer := buf.New()
client := NewClientSession(context.TODO(), true, protocol.DefaultIDHash) client := NewClientSession(context.TODO(), true, protocol.DefaultIDHash, 0)
common.Must(client.EncodeRequestHeader(expectedRequest, buffer)) common.Must(client.EncodeRequestHeader(expectedRequest, buffer))
buffer2 := buf.New() buffer2 := buf.New()
@@ -120,8 +118,7 @@ func TestMuxRequest(t *testing.T) {
} }
id := uuid.New() id := uuid.New()
account := &vmess.Account{ account := &vmess.Account{
Id: id.String(), Id: id.String(),
AlterId: 0,
} }
user.Account = toAccount(account) user.Account = toAccount(account)
@@ -134,7 +131,7 @@ func TestMuxRequest(t *testing.T) {
} }
buffer := buf.New() buffer := buf.New()
client := NewClientSession(context.TODO(), true, protocol.DefaultIDHash) client := NewClientSession(context.TODO(), true, protocol.DefaultIDHash, 0)
common.Must(client.EncodeRequestHeader(expectedRequest, buffer)) common.Must(client.EncodeRequestHeader(expectedRequest, buffer))
buffer2 := buf.New() buffer2 := buf.New()

View File

@@ -18,7 +18,7 @@ import (
"github.com/xtls/xray-core/common/bitmask" "github.com/xtls/xray-core/common/bitmask"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/drain"
"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/task" "github.com/xtls/xray-core/common/task"
@@ -138,22 +138,18 @@ func parseSecurityType(b byte) protocol.SecurityType {
// DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream. // DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream.
func (s *ServerSession) DecodeRequestHeader(reader io.Reader, isDrain bool) (*protocol.RequestHeader, error) { func (s *ServerSession) DecodeRequestHeader(reader io.Reader, isDrain bool) (*protocol.RequestHeader, error) {
buffer := buf.New() buffer := buf.New()
behaviorRand := dice.NewDeterministicDice(int64(s.userValidator.GetBehaviorSeed()))
BaseDrainSize := behaviorRand.Roll(3266) drainer, err := drain.NewBehaviorSeedLimitedDrainer(int64(s.userValidator.GetBehaviorSeed()), 16+38, 3266, 64)
RandDrainMax := behaviorRand.Roll(64) + 1
RandDrainRolled := dice.Roll(RandDrainMax) if err != nil {
DrainSize := BaseDrainSize + 16 + 38 + RandDrainRolled return nil, newError("failed to initialize drainer").Base(err)
readSizeRemain := DrainSize }
drainConnection := func(e error) error { drainConnection := func(e error) error {
// We read a deterministic generated length of data before closing the connection to offset padding read pattern // We read a deterministic generated length of data before closing the connection to offset padding read pattern
readSizeRemain -= int(buffer.Len()) drainer.AcknowledgeReceive(int(buffer.Len()))
if readSizeRemain > 0 && isDrain { if isDrain {
err := s.DrainConnN(reader, readSizeRemain) return drain.WithError(drainer, reader, e)
if err != nil {
return newError("failed to drain connection DrainSize = ", BaseDrainSize, " ", RandDrainMax, " ", RandDrainRolled).Base(err).Base(e)
}
return newError("connection drained DrainSize = ", BaseDrainSize, " ", RandDrainMax, " ", RandDrainRolled).Base(e)
} }
return e return e
} }
@@ -182,7 +178,7 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader, isDrain bool) (*pr
aeadData, shouldDrain, bytesRead, errorReason := vmessaead.OpenVMessAEADHeader(fixedSizeCmdKey, fixedSizeAuthID, reader) aeadData, shouldDrain, bytesRead, errorReason := vmessaead.OpenVMessAEADHeader(fixedSizeCmdKey, fixedSizeAuthID, reader)
if errorReason != nil { if errorReason != nil {
if shouldDrain { if shouldDrain {
readSizeRemain -= bytesRead drainer.AcknowledgeReceive(bytesRead)
return nil, drainConnection(newError("AEAD read failed").Base(errorReason)) return nil, drainConnection(newError("AEAD read failed").Base(errorReason))
} else { } else {
return nil, drainConnection(newError("AEAD read failed, drain skipped").Base(errorReason)) return nil, drainConnection(newError("AEAD read failed, drain skipped").Base(errorReason))
@@ -213,7 +209,7 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader, isDrain bool) (*pr
return nil, drainConnection(newError("invalid user").Base(errorAEAD)) return nil, drainConnection(newError("invalid user").Base(errorAEAD))
} }
readSizeRemain -= int(buffer.Len()) drainer.AcknowledgeReceive(int(buffer.Len()))
buffer.Clear() buffer.Clear()
if _, err := buffer.ReadFullFrom(decryptor, 38); err != nil { if _, err := buffer.ReadFullFrom(decryptor, 38); err != nil {
return nil, newError("failed to read request header").Base(err) return nil, newError("failed to read request header").Base(err)
@@ -362,6 +358,17 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())), NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(), AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
} }
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
AuthenticatedLengthKey := vmessaead.KDF16(s.requestBodyKey[:], "auth_len")
AuthenticatedLengthKeyAEAD := crypto.NewAesGcm(AuthenticatedLengthKey)
lengthAuth := &crypto.AEADAuthenticator{
AEAD: AuthenticatedLengthKeyAEAD,
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
sizeParser = NewAEADSizeParser(lengthAuth)
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding) return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
case protocol.SecurityType_CHACHA20_POLY1305: case protocol.SecurityType_CHACHA20_POLY1305:
@@ -372,6 +379,18 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())), NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(), AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
} }
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
AuthenticatedLengthKey := vmessaead.KDF16(s.requestBodyKey[:], "auth_len")
AuthenticatedLengthKeyAEAD, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(AuthenticatedLengthKey))
common.Must(err)
lengthAuth := &crypto.AEADAuthenticator{
AEAD: AuthenticatedLengthKeyAEAD,
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
sizeParser = NewAEADSizeParser(lengthAuth)
}
return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding) return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)
default: default:
@@ -480,6 +499,17 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())), NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(), AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
} }
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
AuthenticatedLengthKey := vmessaead.KDF16(s.requestBodyKey[:], "auth_len")
AuthenticatedLengthKeyAEAD := crypto.NewAesGcm(AuthenticatedLengthKey)
lengthAuth := &crypto.AEADAuthenticator{
AEAD: AuthenticatedLengthKeyAEAD,
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
sizeParser = NewAEADSizeParser(lengthAuth)
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding) return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
case protocol.SecurityType_CHACHA20_POLY1305: case protocol.SecurityType_CHACHA20_POLY1305:
@@ -490,14 +520,21 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())), NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(), AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
} }
if request.Option.Has(protocol.RequestOptionAuthenticatedLength) {
AuthenticatedLengthKey := vmessaead.KDF16(s.requestBodyKey[:], "auth_len")
AuthenticatedLengthKeyAEAD, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(AuthenticatedLengthKey))
common.Must(err)
lengthAuth := &crypto.AEADAuthenticator{
AEAD: AuthenticatedLengthKeyAEAD,
NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
}
sizeParser = NewAEADSizeParser(lengthAuth)
}
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding) return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)
default: default:
panic("Unknown security type.") panic("Unknown security type.")
} }
} }
func (s *ServerSession) DrainConnN(reader io.Reader, n int) error {
_, err := io.CopyN(io.Discard, reader, int64(n))
return err
}

View File

@@ -9,8 +9,6 @@ import (
"sync" "sync"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"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"
@@ -28,6 +26,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/internet/stat"
) )
var ( var (
@@ -207,7 +206,9 @@ func transferResponse(timer signal.ActivityUpdater, session *encoding.ServerSess
return err return err
} }
if request.Option.Has(protocol.RequestOptionChunkStream) { account := request.User.Account.(*vmess.MemoryAccount)
if request.Option.Has(protocol.RequestOptionChunkStream) && !account.NoTerminationSignal {
if err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil { if err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {
return err return err
} }

View File

@@ -4,10 +4,11 @@ package outbound
import ( import (
"context" "context"
"crypto/hmac"
"crypto/sha256"
"hash/crc64"
"time" "time"
"github.com/xtls/xray-core/transport/internet/stat"
"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/net" "github.com/xtls/xray-core/common/net"
@@ -24,6 +25,7 @@ import (
"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"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
) )
// Handler is an outbound connection handler for VMess protocol. // Handler is an outbound connection handler for VMess protocol.
@@ -119,6 +121,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
request.Option.Clear(protocol.RequestOptionChunkMasking) request.Option.Clear(protocol.RequestOptionChunkMasking)
} }
if account.AuthenticatedLengthExperiment {
request.Option.Set(protocol.RequestOptionAuthenticatedLength)
}
input := link.Reader input := link.Reader
output := link.Writer output := link.Writer
@@ -127,7 +133,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
isAEAD = true isAEAD = true
} }
session := encoding.NewClientSession(ctx, isAEAD, protocol.DefaultIDHash) hashkdf := hmac.New(sha256.New, []byte("VMessBF"))
hashkdf.Write(account.ID.Bytes())
behaviorSeed := crc64.Checksum(hashkdf.Sum(nil), crc64.MakeTable(crc64.ISO))
session := encoding.NewClientSession(ctx, isAEAD, protocol.DefaultIDHash, int64(behaviorSeed))
sessionPolicy := h.policyManager.ForLevel(request.User.Level) sessionPolicy := h.policyManager.ForLevel(request.User.Level)
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
@@ -164,7 +175,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return err return err
} }
if request.Option.Has(protocol.RequestOptionChunkStream) { if request.Option.Has(protocol.RequestOptionChunkStream) && !account.NoTerminationSignal {
if err := bodyWriter2.WriteMultiBuffer(buf.MultiBuffer{}); err != nil { if err := bodyWriter2.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {
return err return err
} }

View File

@@ -71,6 +71,11 @@ func NewTimedUserValidator(hasher protocol.IDHash) *TimedUserValidator {
return tuv return tuv
} }
// visible for testing
func (v *TimedUserValidator) GetBaseTime() protocol.Timestamp {
return v.baseTime
}
func (v *TimedUserValidator) generateNewHashes(nowSec protocol.Timestamp, user *user) { func (v *TimedUserValidator) generateNewHashes(nowSec protocol.Timestamp, user *user) {
var hashValue [16]byte var hashValue [16]byte
genEndSec := nowSec + cacheDurationSec genEndSec := nowSec + cacheDurationSec

View File

@@ -2,7 +2,6 @@ package vmess_test
import ( import (
"testing" "testing"
"time"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
@@ -26,15 +25,14 @@ func TestUserValidator(t *testing.T) {
user := &protocol.MemoryUser{ user := &protocol.MemoryUser{
Email: "test", Email: "test",
Account: toAccount(&Account{ Account: toAccount(&Account{
Id: id.String(), Id: id.String(),
AlterId: 8,
}), }),
} }
common.Must(v.Add(user)) common.Must(v.Add(user))
{ {
testSmallLag := func(lag time.Duration) { testSmallLag := func(lag int64) {
ts := protocol.Timestamp(time.Now().Add(time.Second * lag).Unix()) ts := int64(v.GetBaseTime()) + lag + 240
idHash := hasher(id.Bytes()) idHash := hasher(id.Bytes())
common.Must2(serial.WriteUint64(idHash, uint64(ts))) common.Must2(serial.WriteUint64(idHash, uint64(ts)))
userHash := idHash.Sum(nil) userHash := idHash.Sum(nil)
@@ -46,7 +44,7 @@ func TestUserValidator(t *testing.T) {
if euser.Email != user.Email { if euser.Email != user.Email {
t.Error("unexpected user email: ", euser.Email, " want ", user.Email) t.Error("unexpected user email: ", euser.Email, " want ", user.Email)
} }
if ets != ts { if int64(ets) != ts {
t.Error("unexpected timestamp: ", ets, " want ", ts) t.Error("unexpected timestamp: ", ets, " want ", ts)
} }
} }
@@ -61,8 +59,8 @@ func TestUserValidator(t *testing.T) {
} }
{ {
testBigLag := func(lag time.Duration) { testBigLag := func(lag int64) {
ts := protocol.Timestamp(time.Now().Add(time.Second * lag).Unix()) ts := int64(v.GetBaseTime()) + lag + 240
idHash := hasher(id.Bytes()) idHash := hasher(id.Bytes())
common.Must2(serial.WriteUint64(idHash, uint64(ts))) common.Must2(serial.WriteUint64(idHash, uint64(ts)))
userHash := idHash.Sum(nil) userHash := idHash.Sum(nil)
@@ -99,8 +97,7 @@ func BenchmarkUserValidator(b *testing.B) {
v.Add(&protocol.MemoryUser{ v.Add(&protocol.MemoryUser{
Email: "test", Email: "test",
Account: toAccount(&Account{ Account: toAccount(&Account{
Id: id.String(), Id: id.String(),
AlterId: 16,
}), }),
}) })
} }

View File

@@ -66,8 +66,8 @@ func TestCommanderRemoveHandler(t *testing.T) {
{ {
Tag: "d", Tag: "d",
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(clientPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
@@ -78,8 +78,8 @@ func TestCommanderRemoveHandler(t *testing.T) {
{ {
Tag: "api", Tag: "api",
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(cmdPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(cmdPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
@@ -174,15 +174,14 @@ func TestCommanderAddRemoveUser(t *testing.T) {
{ {
Tag: "v", Tag: "v",
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&inbound.Config{ ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
Id: u1.String(), Id: u1.String(),
AlterId: 64,
}), }),
}, },
}, },
@@ -191,8 +190,8 @@ func TestCommanderAddRemoveUser(t *testing.T) {
{ {
Tag: "api", Tag: "api",
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(cmdPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(cmdPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
@@ -226,8 +225,8 @@ func TestCommanderAddRemoveUser(t *testing.T) {
{ {
Tag: "d", Tag: "d",
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(clientPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
@@ -248,8 +247,7 @@ func TestCommanderAddRemoveUser(t *testing.T) {
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
Id: u2.String(), Id: u2.String(),
AlterId: 64,
SecuritySettings: &protocol.SecurityConfig{ SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM, Type: protocol.SecurityType_AES128_GCM,
}, },
@@ -285,8 +283,7 @@ func TestCommanderAddRemoveUser(t *testing.T) {
User: &protocol.User{ User: &protocol.User{
Email: "test@example.com", Email: "test@example.com",
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
Id: u2.String(), Id: u2.String(),
AlterId: 64,
}), }),
}, },
}), }),
@@ -367,8 +364,8 @@ func TestCommanderStats(t *testing.T) {
{ {
Tag: "vmess", Tag: "vmess",
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&inbound.Config{ ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
@@ -376,8 +373,7 @@ func TestCommanderStats(t *testing.T) {
Level: 1, Level: 1,
Email: "test", Email: "test",
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(), Id: userID.String(),
AlterId: 64,
}), }),
}, },
}, },
@@ -386,8 +382,8 @@ func TestCommanderStats(t *testing.T) {
{ {
Tag: "api", Tag: "api",
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(cmdPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(cmdPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
@@ -410,8 +406,8 @@ func TestCommanderStats(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(clientPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
@@ -432,8 +428,7 @@ func TestCommanderStats(t *testing.T) {
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(), Id: userID.String(),
AlterId: 64,
SecuritySettings: &protocol.SecurityConfig{ SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM, Type: protocol.SecurityType_AES128_GCM,
}, },

View File

@@ -23,6 +23,7 @@ import (
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"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/serial"
"github.com/xtls/xray-core/common/units"
core "github.com/xtls/xray-core/core" core "github.com/xtls/xray-core/core"
) )
@@ -198,7 +199,18 @@ func testUDPConn(port net.Port, payloadSize int, timeout time.Duration) func() e
} }
func testTCPConn2(conn net.Conn, payloadSize int, timeout time.Duration) func() error { func testTCPConn2(conn net.Conn, payloadSize int, timeout time.Duration) func() error {
return func() error { return func() (err1 error) {
start := time.Now()
defer func() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
// For info on each, see: https://golang.org/pkg/runtime/#MemStats
fmt.Println("testConn finishes:", time.Since(start).Milliseconds(), "ms\t",
err1, "\tAlloc =", units.ByteSize(m.Alloc).String(),
"\tTotalAlloc =", units.ByteSize(m.TotalAlloc).String(),
"\tSys =", units.ByteSize(m.Sys).String(),
"\tNumGC =", m.NumGC)
}()
payload := make([]byte, payloadSize) payload := make([]byte, payloadSize)
common.Must2(rand.Read(payload)) common.Must2(rand.Read(payload))

View File

@@ -56,8 +56,8 @@ func TestResolveIP(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&socks.ServerConfig{ ProxySettings: serial.ToTypedMessage(&socks.ServerConfig{
AuthType: socks.AuthType_NO_AUTH, AuthType: socks.AuthType_NO_AUTH,

View File

@@ -44,8 +44,8 @@ func TestDokodemoTCP(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&inbound.Config{ ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
@@ -77,8 +77,8 @@ func TestDokodemoTCP(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: &net.PortRange{From: clientPort, To: clientPort + clientPortRange}, PortList: &net.PortList{Range: []*net.PortRange{{From: clientPort, To: clientPort + clientPortRange}}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
@@ -135,8 +135,8 @@ func TestDokodemoUDP(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&inbound.Config{ ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
@@ -162,8 +162,8 @@ func TestDokodemoUDP(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: &net.PortRange{From: clientPort, To: clientPort + clientPortRange}, PortList: &net.PortList{Range: []*net.PortRange{{From: clientPort, To: clientPort + clientPortRange}}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),

View File

@@ -50,8 +50,8 @@ func TestPassiveConnection(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
@@ -107,8 +107,8 @@ func TestProxy(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&inbound.Config{ ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
@@ -134,8 +134,8 @@ func TestProxy(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(proxyPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(proxyPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&inbound.Config{ ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
@@ -160,8 +160,8 @@ func TestProxy(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(clientPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
@@ -239,8 +239,8 @@ func TestProxyOverKCP(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
StreamSettings: &internet.StreamConfig{ StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_MKCP, Protocol: internet.TransportProtocol_MKCP,
}, },
@@ -269,8 +269,8 @@ func TestProxyOverKCP(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(proxyPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(proxyPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&inbound.Config{ ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
@@ -300,8 +300,8 @@ func TestProxyOverKCP(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(clientPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
@@ -389,8 +389,8 @@ func TestBlackhole(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
@@ -402,8 +402,8 @@ func TestBlackhole(t *testing.T) {
}, },
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort2), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort2)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest2.Address), Address: net.NewIPOrDomain(dest2.Address),
@@ -460,8 +460,8 @@ func TestForward(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&socks.ServerConfig{ ProxySettings: serial.ToTypedMessage(&socks.ServerConfig{
AuthType: socks.AuthType_NO_AUTH, AuthType: socks.AuthType_NO_AUTH,
@@ -517,8 +517,8 @@ func TestUDPConnection(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(clientPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address), Address: net.NewIPOrDomain(dest.Address),
@@ -559,8 +559,8 @@ func TestDomainSniffing(t *testing.T) {
{ {
Tag: "snif", Tag: "snif",
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(sniffingPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(sniffingPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
DomainOverride: []proxyman.KnownProtocols{ DomainOverride: []proxyman.KnownProtocols{
proxyman.KnownProtocols_TLS, proxyman.KnownProtocols_TLS,
}, },
@@ -576,8 +576,8 @@ func TestDomainSniffing(t *testing.T) {
{ {
Tag: "http", Tag: "http",
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(httpPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(httpPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}), ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
}, },
@@ -666,15 +666,14 @@ func TestDialXray(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&inbound.Config{ ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(), Id: userID.String(),
AlterId: 64,
}), }),
}, },
}, },
@@ -705,8 +704,7 @@ func TestDialXray(t *testing.T) {
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(), Id: userID.String(),
AlterId: 64,
SecuritySettings: &protocol.SecurityConfig{ SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AES128_GCM, Type: protocol.SecurityType_AES128_GCM,
}, },

View File

@@ -39,8 +39,8 @@ func TestHttpConformance(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}), ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
}, },
@@ -100,8 +100,8 @@ func TestHttpError(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}), ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
}, },
@@ -149,8 +149,8 @@ func TestHTTPConnectMethod(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}), ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
}, },
@@ -229,8 +229,8 @@ func TestHttpPost(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}), ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
}, },
@@ -295,8 +295,8 @@ func TestHttpBasicAuth(t *testing.T) {
Inbound: []*core.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{ ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{
Accounts: map[string]string{ Accounts: map[string]string{

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