Compare commits

...

24 Commits

Author SHA1 Message Date
RPRX
a35d5719f4 v24.9.16 2024-09-16 12:48:28 +00:00
dragonbreath2000
363e86c585 UDP noises: Add base64 and multi-packet support (#3794)
https://github.com/XTLS/Xray-core/pull/3794#issuecomment-2351329251

---------

Co-authored-by: 风扇滑翔翼 <Fangliding.fshxy@outlook.com>
Co-authored-by: mmmray <142015632+mmmray@users.noreply.github.com>
2024-09-16 12:46:30 +00:00
ll11l1lIllIl1lll
b1c6471eeb SplitHTTP client: Add xmux (multiplex controller) for H3 & H2 (#3613)
https://github.com/XTLS/Xray-core/pull/3613#issuecomment-2351954957

Closes https://github.com/XTLS/Xray-core/issues/3560#issuecomment-2247495778

---------

Co-authored-by: mmmray <142015632+mmmray@users.noreply.github.com>
2024-09-16 12:42:01 +00:00
Dmitry Anderson
a931507dd6 SplitHTTP: Read and validate HTTP/1.1 responses (#3797) 2024-09-16 12:33:03 +00:00
dependabot[bot]
67c2a29065 Bump github.com/sagernet/sing from 0.4.1 to 0.4.3 (#3818)
Bumps [github.com/sagernet/sing](https://github.com/sagernet/sing) from 0.4.1 to 0.4.3.
- [Commits](https://github.com/sagernet/sing/compare/v0.4.1...v0.4.3)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-15 21:20:12 -04:00
Kobe Arthur Scofield
5f0642a671 Errors: Add PrintRemovedFeatureError & PrintDeprecatedFeatureWarning (#3804) 2024-09-15 04:55:54 +00:00
风扇滑翔翼
3fed0c773f DNS outbound: Add blockTypes (#3812) 2024-09-15 04:21:51 +00:00
Kuzmin Vladimir
d7c5a0fc5f Fix int overflow on x32 processors causing panic (#3810)
During the roll, "duration" is converted to int, causing overflow on x32 processors. The value may be very small or negative, causing a panic in rand.Intn.
2024-09-14 23:47:16 -04:00
风扇滑翔翼
781aaee21f QUIC sniffer: handle multiple initial packets (#3802)
* QUIC sniffer: handle multiple initial packets
Basically copied from Vigilans/v2ray-core@8f33db0

Co-Authored-By: Vigilans <vigilans@foxmail.com>

* Remove unnecessary file

---------

Co-authored-by: Vigilans <vigilans@foxmail.com>
2024-09-13 13:32:43 -04:00
风扇滑翔翼
7970f240de Log: show the matching rule tag (#3809) 2024-09-13 13:05:19 -04:00
风扇滑翔翼
88ae774cce Sniff: Routing “attrs” support non http inbound (#3808)
* Sniff: Support attrs route in non http inbound

* Add capability to sniff method and path

* Fix test

* Skip HTTP inbound PlainHTTP mode

* Fix test
again
2024-09-13 12:26:36 -04:00
Torikki
c259e4e4a6 Allow to inject custom validator in VLESS controller (#3453)
* Make Validator an interface

* Move validator creation away from VLESS inbound controller
2024-09-13 10:51:26 -04:00
vnxme
3a8c5f38e8 Routing: Add regexp syntax support to UserMatcher (#3799) 2024-09-12 10:48:41 -04:00
dependabot[bot]
12c3908e8c Bump google.golang.org/grpc from 1.66.1 to 1.66.2 (#3798)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.66.1 to 1.66.2.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.66.1...v1.66.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-12 10:38:51 -04:00
Kobe Arthur Scofield
1919a1e86f Log: Improve feature deprecation/removal logs (#3793)
* Improve feature deprecation/removal logs

* Add a note about the new feature

* When the feature has removed, this should be an error not a warning
2024-09-12 10:38:17 -04:00
风扇滑翔翼
1b607ff874 DNS: Do not hit cache if encounted err (#3784) 2024-09-12 10:34:45 -04:00
Kobe Arthur Scofield
7496413e5c Remove remnants of global transport (#3792)
* Remove remenants

* Generate pb.go

* Remove function
2024-09-11 14:06:11 -04:00
dependabot[bot]
297a9ae7bd Bump google.golang.org/grpc from 1.66.0 to 1.66.1 (#3786)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.66.0 to 1.66.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.66.0...v1.66.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-11 11:34:03 -04:00
风扇滑翔翼
a247997e38 Log: Add MaskAddress option to hide IP addresses (#3783)
* Log: Add maskAddress option

* Correct IPv6 subnet
2024-09-11 10:45:47 -04:00
Kobe Arthur Scofield
6b1bf312d7 Config: Remove legacy config fields again (#3782)
* Remove more lecacy fields

* Patch missing bracket

* Fix tests

* Fix missing comma

* Fix buried test bomb

* Cleanup test after removed legacy test content
2024-09-11 10:37:25 -04:00
yu
c90affe7db Fix: RPC call causes xray panic problem using wrong account type (#3744)
* fix:RPC call causes xray panic problem. Problem details: add a VMess protocol user in an inbound proxy. If inTag: "VMess-xxx", but the developer carelessly calls the add user method of vless or other protocols, such as xrayCtl.AddVlessUser(user), causing xray panic

* fix:use xray log system return error

---------

Co-authored-by: chengtao@snqu.com <chengtao@snqu.com>
2024-09-09 11:44:22 -04:00
风扇滑翔翼
3d0feae462 Transport: Add REALITY TLS1.3 support warning (#3774) 2024-09-09 11:37:39 -04:00
Kobe Arthur Scofield
f04cb0b288 Config: Remove some legacy fields from V2Ray 3.x era (#3776)
https://github.com/XTLS/Xray-core/pull/3776#issue-2512316726
2024-09-09 06:03:21 +00:00
mmmray
9438517130 README.md: Add SaeedDev94/Xray to Android clients
Closes https://github.com/XTLS/Xray-core/issues/3778
2024-09-09 05:59:12 +00:00
71 changed files with 1325 additions and 1092 deletions

3
.gitignore vendored
View File

@@ -28,3 +28,6 @@ errorgen
*.dat
.vscode
/build_assets
# Output from dlv test
**/debug.*

View File

@@ -77,6 +77,7 @@
- Android
- [v2rayNG](https://github.com/2dust/v2rayNG)
- [X-flutter](https://github.com/XTLS/X-flutter)
- [SaeedDev94/Xray](https://github.com/SaeedDev94/Xray)
- iOS & macOS arm64
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)

View File

@@ -10,8 +10,8 @@ import (
"time"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
@@ -41,8 +41,14 @@ func (r *cachedReader) Cache(b *buf.Buffer) {
if !mb.IsEmpty() {
r.cache, _ = buf.MergeMulti(r.cache, mb)
}
b.Clear()
rawBytes := b.Extend(buf.Size)
cacheLen := r.cache.Len()
if cacheLen <= b.Cap() {
b.Clear()
} else {
b.Release()
*b = *buf.NewWithSize(cacheLen)
}
rawBytes := b.Extend(cacheLen)
n := r.cache.Copy(rawBytes)
b.Resize(0, int32(n))
r.Unlock()
@@ -421,7 +427,11 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
outTag := route.GetOutboundTag()
if h := d.ohm.GetHandler(outTag); h != nil {
isPickRoute = 2
errors.LogInfo(ctx, "taking detour [", outTag, "] for [", destination, "]")
if route.GetRuleTag() == "" {
errors.LogInfo(ctx, "taking detour [", outTag, "] for [", destination, "]")
} else {
errors.LogInfo(ctx, "Hit route rule: [", route.GetRuleTag(), "] so taking detour [", outTag, "] for [", destination, "]")
}
handler = h
} else {
errors.LogWarning(ctx, "non existing outTag: ", outTag)

View File

@@ -35,7 +35,7 @@ type Sniffer struct {
func NewSniffer(ctx context.Context) *Sniffer {
ret := &Sniffer{
sniffer: []protocolSnifferWithMetadata{
{func(c context.Context, b []byte) (SniffResult, error) { return http.SniffHTTP(b) }, false, net.Network_TCP},
{func(c context.Context, b []byte) (SniffResult, error) { return http.SniffHTTP(b, c) }, false, net.Network_TCP},
{func(c context.Context, b []byte) (SniffResult, error) { return tls.SniffTLS(b) }, false, net.Network_TCP},
{func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffBittorrent(b) }, false, net.Network_TCP},
{func(c context.Context, b []byte) (SniffResult, error) { return quic.SniffQUIC(b) }, false, net.Network_UDP},

View File

@@ -15,7 +15,6 @@ import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/strmatcher"
"github.com/xtls/xray-core/features"
"github.com/xtls/xray-core/features/dns"
)
@@ -96,7 +95,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
geoipContainer := router.GeoIPMatcherContainer{}
for _, endpoint := range config.NameServers {
features.PrintDeprecatedFeatureWarning("simple DNS server")
errors.PrintDeprecatedFeatureWarning("simple DNS server", "")
client, err := NewSimpleClient(ctx, endpoint, clientIP)
if err != nil {
return nil, errors.New("failed to create client").Base(err)

View File

@@ -7,7 +7,6 @@ import (
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/strmatcher"
"github.com/xtls/xray-core/features"
"github.com/xtls/xray-core/features/dns"
)
@@ -26,7 +25,7 @@ func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDoma
}
if legacy != nil {
features.PrintDeprecatedFeatureWarning("simple host mapping")
errors.PrintDeprecatedFeatureWarning("simple host mapping", "")
for domain, ip := range legacy {
matcher, err := strmatcher.Full.New(domain)

View File

@@ -365,7 +365,7 @@ func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
} else {
ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound {
if err == nil || err == dns_feature.ErrEmptyResponse {
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
return ips, err

View File

@@ -300,7 +300,7 @@ func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP ne
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
} else {
ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound {
if err == nil || err == dns_feature.ErrEmptyResponse {
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
return ips, err

View File

@@ -323,7 +323,7 @@ func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, clientIP net
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
} else {
ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound {
if err == nil || err == dns_feature.ErrEmptyResponse {
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
return ips, err

View File

@@ -250,7 +250,7 @@ func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP
errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
} else {
ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound {
if err == nil || err == dns_feature.ErrEmptyResponse {
errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
return ips, err

View File

@@ -84,6 +84,7 @@ type Config struct {
AccessLogType LogType `protobuf:"varint,4,opt,name=access_log_type,json=accessLogType,proto3,enum=xray.app.log.LogType" json:"access_log_type,omitempty"`
AccessLogPath string `protobuf:"bytes,5,opt,name=access_log_path,json=accessLogPath,proto3" json:"access_log_path,omitempty"`
EnableDnsLog bool `protobuf:"varint,6,opt,name=enable_dns_log,json=enableDnsLog,proto3" json:"enable_dns_log,omitempty"`
MaskAddress string `protobuf:"bytes,7,opt,name=mask_address,json=maskAddress,proto3" json:"mask_address,omitempty"`
}
func (x *Config) Reset() {
@@ -160,13 +161,20 @@ func (x *Config) GetEnableDnsLog() bool {
return false
}
func (x *Config) GetMaskAddress() string {
if x != nil {
return x.MaskAddress
}
return ""
}
var File_app_log_config_proto protoreflect.FileDescriptor
var file_app_log_config_proto_rawDesc = []byte{
0x0a, 0x14, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x6c, 0x6f, 0x67, 0x1a, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6c, 0x6f, 0x67,
0x2f, 0x6c, 0x6f, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xbb, 0x02, 0x0a, 0x06, 0x43,
0x2f, 0x6c, 0x6f, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xde, 0x02, 0x0a, 0x06, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3b, 0x0a, 0x0e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6c,
0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x4c, 0x6f, 0x67,
@@ -186,15 +194,18 @@ var file_app_log_config_proto_rawDesc = []byte{
0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x50, 0x61,
0x74, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x6e, 0x73,
0x5f, 0x6c, 0x6f, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x65, 0x6e, 0x61, 0x62,
0x6c, 0x65, 0x44, 0x6e, 0x73, 0x4c, 0x6f, 0x67, 0x2a, 0x35, 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x54,
0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00, 0x12, 0x0b, 0x0a,
0x07, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x69,
0x6c, 0x65, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x10, 0x03, 0x42,
0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
0x6c, 0x6f, 0x67, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65,
0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0xaa, 0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e,
0x41, 0x70, 0x70, 0x2e, 0x4c, 0x6f, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6c, 0x65, 0x44, 0x6e, 0x73, 0x4c, 0x6f, 0x67, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x73, 0x6b,
0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
0x6d, 0x61, 0x73, 0x6b, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2a, 0x35, 0x0a, 0x07, 0x4c,
0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00,
0x12, 0x0b, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x10, 0x01, 0x12, 0x08, 0x0a,
0x04, 0x46, 0x69, 0x6c, 0x65, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74,
0x10, 0x03, 0x42, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63,
0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0xaa, 0x02, 0x0c, 0x58, 0x72,
0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4c, 0x6f, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (

View File

@@ -23,4 +23,5 @@ message Config {
LogType access_log_type = 4;
string access_log_path = 5;
bool enable_dns_log = 6;
string mask_address= 7;
}

View File

@@ -4,6 +4,9 @@ package log
import (
"context"
"fmt"
"regexp"
"strings"
"sync"
"github.com/xtls/xray-core/common"
@@ -101,18 +104,25 @@ func (g *Instance) Handle(msg log.Message) {
return
}
var Msg log.Message
if g.config.MaskAddress != "" {
Msg = &MaskedMsgWrapper{Message: msg, config: g.config}
} else {
Msg = msg
}
switch msg := msg.(type) {
case *log.AccessMessage:
if g.accessLogger != nil {
g.accessLogger.Handle(msg)
g.accessLogger.Handle(Msg)
}
case *log.DNSLog:
if g.dns && g.accessLogger != nil {
g.accessLogger.Handle(msg)
g.accessLogger.Handle(Msg)
}
case *log.GeneralMessage:
if g.errorLogger != nil && msg.Severity <= g.config.ErrorLogLevel {
g.errorLogger.Handle(msg)
g.errorLogger.Handle(Msg)
}
default:
// Swallow
@@ -141,6 +151,56 @@ func (g *Instance) Close() error {
return nil
}
// MaskedMsgWrapper is to wrap the string() method to mask IP addresses in the log.
type MaskedMsgWrapper struct {
log.Message
config *Config
}
func (m *MaskedMsgWrapper) String() string {
str := m.Message.String()
ipv4Regex := regexp.MustCompile(`(\d{1,3}\.){3}\d{1,3}`)
ipv6Regex := regexp.MustCompile(`((?:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}){2,7})(?:[\/\\%](\d{1,3}))?`)
// Process ipv4
maskedMsg := ipv4Regex.ReplaceAllStringFunc(str, func(ip string) string {
parts := strings.Split(ip, ".")
switch m.config.MaskAddress {
case "half":
return fmt.Sprintf("%s.%s.*.*", parts[0], parts[1])
case "quarter":
return fmt.Sprintf("%s.*.*.*", parts[0])
case "full":
return "[Masked IPv4]"
default:
return ip
}
})
// process ipv6
maskedMsg = ipv6Regex.ReplaceAllStringFunc(maskedMsg, func(ip string) string {
parts := strings.Split(ip, ":")
switch m.config.MaskAddress {
case "half":
if len(parts) >= 2 {
return fmt.Sprintf("%s:%s::/32", parts[0], parts[1])
}
case "quarter":
if len(parts) >= 1 {
return fmt.Sprintf("%s::/16", parts[0])
}
case "full":
return "Masked IPv6" // Do not use [Masked IPv6] like ipv4, or you will get "[[Masked IPv6]]" (v6 address already has [])
default:
return ip
}
return ip
})
return maskedMsg
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))

View File

@@ -156,7 +156,7 @@ func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int)
for i := 0; i < rounds; i++ {
delay := time.Duration(0)
if duration > 0 {
delay = time.Duration(dice.Roll(int(duration)))
delay = time.Duration(dice.RollInt63n(int64(duration)))
}
time.AfterFunc(delay, func() {
errors.LogDebug(h.ctx, "checking ", handler)

View File

@@ -19,21 +19,5 @@ func (c *ReceiverConfig) GetEffectiveSniffingSettings() *SniffingConfig {
return c.SniffingSettings
}
if len(c.DomainOverride) > 0 {
var p []string
for _, kd := range c.DomainOverride {
switch kd {
case KnownProtocols_HTTP:
p = append(p, "http")
case KnownProtocols_TLS:
p = append(p, "tls")
}
}
return &SniffingConfig{
Enabled: true,
DestinationOverride: p,
}
}
return nil
}

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.2
// protoc v5.27.0
// protoc v5.28.0
// source: app/proxyman/config.proto
package proxyman
@@ -23,52 +23,6 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type KnownProtocols int32
const (
KnownProtocols_HTTP KnownProtocols = 0
KnownProtocols_TLS KnownProtocols = 1
)
// Enum value maps for KnownProtocols.
var (
KnownProtocols_name = map[int32]string{
0: "HTTP",
1: "TLS",
}
KnownProtocols_value = map[string]int32{
"HTTP": 0,
"TLS": 1,
}
)
func (x KnownProtocols) Enum() *KnownProtocols {
p := new(KnownProtocols)
*p = x
return p
}
func (x KnownProtocols) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (KnownProtocols) Descriptor() protoreflect.EnumDescriptor {
return file_app_proxyman_config_proto_enumTypes[0].Descriptor()
}
func (KnownProtocols) Type() protoreflect.EnumType {
return &file_app_proxyman_config_proto_enumTypes[0]
}
func (x KnownProtocols) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use KnownProtocols.Descriptor instead.
func (KnownProtocols) EnumDescriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{0}
}
type AllocationStrategy_Type int32
const (
@@ -105,11 +59,11 @@ func (x AllocationStrategy_Type) String() string {
}
func (AllocationStrategy_Type) Descriptor() protoreflect.EnumDescriptor {
return file_app_proxyman_config_proto_enumTypes[1].Descriptor()
return file_app_proxyman_config_proto_enumTypes[0].Descriptor()
}
func (AllocationStrategy_Type) Type() protoreflect.EnumType {
return &file_app_proxyman_config_proto_enumTypes[1]
return &file_app_proxyman_config_proto_enumTypes[0]
}
func (x AllocationStrategy_Type) Number() protoreflect.EnumNumber {
@@ -323,12 +277,7 @@ type ReceiverConfig struct {
AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy,proto3" json:"allocation_strategy,omitempty"`
StreamSettings *internet.StreamConfig `protobuf:"bytes,4,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
ReceiveOriginalDestination bool `protobuf:"varint,5,opt,name=receive_original_destination,json=receiveOriginalDestination,proto3" json:"receive_original_destination,omitempty"`
// Override domains for the given protocol.
// Deprecated. Use sniffing_settings.
//
// Deprecated: Marked as deprecated in app/proxyman/config.proto.
DomainOverride []KnownProtocols `protobuf:"varint,7,rep,packed,name=domain_override,json=domainOverride,proto3,enum=xray.app.proxyman.KnownProtocols" json:"domain_override,omitempty"`
SniffingSettings *SniffingConfig `protobuf:"bytes,8,opt,name=sniffing_settings,json=sniffingSettings,proto3" json:"sniffing_settings,omitempty"`
SniffingSettings *SniffingConfig `protobuf:"bytes,7,opt,name=sniffing_settings,json=sniffingSettings,proto3" json:"sniffing_settings,omitempty"`
}
func (x *ReceiverConfig) Reset() {
@@ -398,14 +347,6 @@ func (x *ReceiverConfig) GetReceiveOriginalDestination() bool {
return false
}
// Deprecated: Marked as deprecated in app/proxyman/config.proto.
func (x *ReceiverConfig) GetDomainOverride() []KnownProtocols {
if x != nil {
return x.DomainOverride
}
return nil
}
func (x *ReceiverConfig) GetSniffingSettings() *SniffingConfig {
if x != nil {
return x.SniffingSettings
@@ -817,7 +758,7 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f,
0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65,
0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x8d, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
0x4f, 0x6e, 0x6c, 0x79, 0x22, 0xbd, 0x03, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f,
0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72,
@@ -840,13 +781,8 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
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,
0x6e, 0x67, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e,
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e,
0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04,
@@ -894,16 +830,13 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
0x01, 0x28, 0x05, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72,
0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78,
0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x78,
0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 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,
0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x42, 0x55,
0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d,
0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f,
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -918,48 +851,46 @@ func file_app_proxyman_config_proto_rawDescGZIP() []byte {
return file_app_proxyman_config_proto_rawDescData
}
var file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_app_proxyman_config_proto_goTypes = []any{
(KnownProtocols)(0), // 0: xray.app.proxyman.KnownProtocols
(AllocationStrategy_Type)(0), // 1: xray.app.proxyman.AllocationStrategy.Type
(*InboundConfig)(nil), // 2: xray.app.proxyman.InboundConfig
(*AllocationStrategy)(nil), // 3: xray.app.proxyman.AllocationStrategy
(*SniffingConfig)(nil), // 4: xray.app.proxyman.SniffingConfig
(*ReceiverConfig)(nil), // 5: xray.app.proxyman.ReceiverConfig
(*InboundHandlerConfig)(nil), // 6: xray.app.proxyman.InboundHandlerConfig
(*OutboundConfig)(nil), // 7: xray.app.proxyman.OutboundConfig
(*SenderConfig)(nil), // 8: xray.app.proxyman.SenderConfig
(*MultiplexingConfig)(nil), // 9: xray.app.proxyman.MultiplexingConfig
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 11: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
(*net.PortList)(nil), // 12: xray.common.net.PortList
(*net.IPOrDomain)(nil), // 13: xray.common.net.IPOrDomain
(*internet.StreamConfig)(nil), // 14: xray.transport.internet.StreamConfig
(*serial.TypedMessage)(nil), // 15: xray.common.serial.TypedMessage
(*internet.ProxyConfig)(nil), // 16: xray.transport.internet.ProxyConfig
(AllocationStrategy_Type)(0), // 0: xray.app.proxyman.AllocationStrategy.Type
(*InboundConfig)(nil), // 1: xray.app.proxyman.InboundConfig
(*AllocationStrategy)(nil), // 2: xray.app.proxyman.AllocationStrategy
(*SniffingConfig)(nil), // 3: xray.app.proxyman.SniffingConfig
(*ReceiverConfig)(nil), // 4: xray.app.proxyman.ReceiverConfig
(*InboundHandlerConfig)(nil), // 5: xray.app.proxyman.InboundHandlerConfig
(*OutboundConfig)(nil), // 6: xray.app.proxyman.OutboundConfig
(*SenderConfig)(nil), // 7: xray.app.proxyman.SenderConfig
(*MultiplexingConfig)(nil), // 8: xray.app.proxyman.MultiplexingConfig
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 9: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
(*net.PortList)(nil), // 11: xray.common.net.PortList
(*net.IPOrDomain)(nil), // 12: xray.common.net.IPOrDomain
(*internet.StreamConfig)(nil), // 13: xray.transport.internet.StreamConfig
(*serial.TypedMessage)(nil), // 14: xray.common.serial.TypedMessage
(*internet.ProxyConfig)(nil), // 15: xray.transport.internet.ProxyConfig
}
var file_app_proxyman_config_proto_depIdxs = []int32{
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
11, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
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
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
0, // 7: xray.app.proxyman.ReceiverConfig.domain_override:type_name -> xray.app.proxyman.KnownProtocols
4, // 8: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
15, // 9: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
15, // 10: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
13, // 11: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
14, // 12: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
16, // 13: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
9, // 14: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
15, // [15:15] is the sub-list for method output_type
15, // [15:15] is the sub-list for method input_type
15, // [15:15] is the sub-list for extension type_name
15, // [15:15] is the sub-list for extension extendee
0, // [0:15] is the sub-list for field type_name
0, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type
9, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
10, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
11, // 3: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList
12, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
2, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy
13, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
3, // 7: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
14, // 8: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
14, // 9: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
12, // 10: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
13, // 11: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
15, // 12: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
8, // 13: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
14, // [14:14] is the sub-list for method output_type
14, // [14:14] is the sub-list for method input_type
14, // [14:14] is the sub-list for extension type_name
14, // [14:14] is the sub-list for extension extendee
0, // [0:14] is the sub-list for field type_name
}
func init() { file_app_proxyman_config_proto_init() }
@@ -1094,7 +1025,7 @@ func file_app_proxyman_config_proto_init() {
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_proxyman_config_proto_rawDesc,
NumEnums: 2,
NumEnums: 1,
NumMessages: 10,
NumExtensions: 0,
NumServices: 0,

View File

@@ -40,11 +40,6 @@ message AllocationStrategy {
AllocationStrategyRefresh refresh = 3;
}
enum KnownProtocols {
HTTP = 0;
TLS = 1;
}
message SniffingConfig {
// Whether or not to enable content sniffing on an inbound connection.
bool enabled = 1;
@@ -71,10 +66,7 @@ message ReceiverConfig {
xray.transport.internet.StreamConfig stream_settings = 4;
bool receive_original_destination = 5;
reserved 6;
// Override domains for the given protocol.
// Deprecated. Use sniffing_settings.
repeated KnownProtocols domain_override = 7 [ deprecated = true ];
SniffingConfig sniffing_settings = 8;
SniffingConfig sniffing_settings = 7;
}
message InboundHandlerConfig {

View File

@@ -28,6 +28,10 @@ func (c routingContext) GetTargetPort() net.Port {
return net.Port(c.RoutingContext.GetTargetPort())
}
func (c routingContext) GetRuleTag() string {
return ""
}
// GetSkipDNSResolve is a mock implementation here to match the interface,
// SkipDNSResolve is set from dns module, no use if coming from a protobuf object?
// TODO: please confirm @Vigilans

View File

@@ -192,18 +192,28 @@ func (v NetworkMatcher) Apply(ctx routing.Context) bool {
}
type UserMatcher struct {
user []string
user []string
pattern []*regexp.Regexp
}
func NewUserMatcher(users []string) *UserMatcher {
usersCopy := make([]string, 0, len(users))
patternsCopy := make([]*regexp.Regexp, 0, len(users))
for _, user := range users {
if len(user) > 0 {
if len(user) > 7 && strings.HasPrefix(user, "regexp:") {
if re, err := regexp.Compile(user[7:]); err != nil {
patternsCopy = append(patternsCopy, re)
}
// Items of users slice with an invalid regexp syntax are ignored.
continue
}
usersCopy = append(usersCopy, user)
}
}
return &UserMatcher{
user: usersCopy,
user: usersCopy,
pattern: patternsCopy,
}
}
@@ -218,6 +228,11 @@ func (v *UserMatcher) Apply(ctx routing.Context) bool {
return true
}
}
for _, re := range v.pattern {
if re.MatchString(user) {
return true
}
}
return false
}

View File

@@ -34,6 +34,7 @@ type Route struct {
routing.Context
outboundGroupTags []string
outboundTag string
ruleTag string
}
// Init initializes the Router.
@@ -89,7 +90,7 @@ func (r *Router) PickRoute(ctx routing.Context) (routing.Route, error) {
if err != nil {
return nil, err
}
return &Route{Context: ctx, outboundTag: tag}, nil
return &Route{Context: ctx, outboundTag: tag, ruleTag: rule.RuleTag}, nil
}
// AddRule implements routing.Router.
@@ -239,6 +240,10 @@ func (r *Route) GetOutboundTag() string {
return r.outboundTag
}
func (r *Route) GetRuleTag() string {
return r.ruleTag
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
r := new(Router)

View File

@@ -207,6 +207,21 @@ func (b *Buffer) Len() int32 {
return b.end - b.start
}
// Cap returns the capacity of the buffer content.
func (b *Buffer) Cap() int32 {
if b == nil {
return 0
}
return int32(len(b.v))
}
// NewWithSize creates a Buffer with 0 length and capacity with at least the given size.
func NewWithSize(size int32) *Buffer {
return &Buffer{
v: bytespool.Alloc(size),
}
}
// IsEmpty returns true if the buffer is empty.
func (b *Buffer) IsEmpty() bool {
return b.Len() == 0

View File

@@ -14,6 +14,14 @@ func Roll(n int) int {
return rand.Intn(n)
}
// RollInt63n returns a non-negative number between 0 (inclusive) and n (exclusive).
func RollInt63n(n int64) int64 {
if n == 1 {
return 0
}
return rand.Int63n(n)
}
// Roll returns a non-negative number between 0 (inclusive) and n (exclusive).
func RollDeterministic(n int, seed int64) int {
if n == 1 {

View File

@@ -0,0 +1,25 @@
package errors
import (
"context"
)
// PrintDeprecatedFeatureWarning prints a warning for deprecated and going to be removed feature.
// Do not remove this function even there is no reference to it.
func PrintDeprecatedFeatureWarning(feature string, migrateFeature string) {
if len(migrateFeature) > 0 {
LogWarning(context.Background(), "This feature " + feature + " is deprecated and being migrated to " + migrateFeature + ". Please update your config(s) according to release note and documentation before removal.")
} else {
LogWarning(context.Background(), "This feature " + feature + " is deprecated. Please update your config(s) according to release note and documentation before removal.")
}
}
// PrintRemovedFeatureError prints an error message for removed feature then return an error. And after long enough time the message can also be removed, uses as an indicator.
// Do not remove this function even there is no reference to it.
func PrintRemovedFeatureError(feature string, migrateFeature string) (error) {
if len(migrateFeature) > 0 {
return New("The feature " + feature + " has been removed and migrated to " + migrateFeature + ". Please update your config(s) according to release note and documentation.")
} else {
return New("The feature " + feature + " has been removed. Please update your config(s) according to release note and documentation.")
}
}

View File

@@ -2,11 +2,13 @@ package http
import (
"bytes"
"context"
"errors"
"strings"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session"
)
type version byte
@@ -56,7 +58,14 @@ func beginWithHTTPMethod(b []byte) error {
return errNotHTTPMethod
}
func SniffHTTP(b []byte) (*SniffHeader, error) {
func SniffHTTP(b []byte, c context.Context) (*SniffHeader, error) {
content := session.ContentFromContext(c)
ShouldSniffAttr := true
// If content.Attributes have information, that means it comes from HTTP inbound PlainHTTP mode.
// It will set attributes, so skip it.
if content == nil || len(content.Attributes) != 0 {
ShouldSniffAttr = false
}
if err := beginWithHTTPMethod(b); err != nil {
return nil, err
}
@@ -76,8 +85,12 @@ func SniffHTTP(b []byte) (*SniffHeader, error) {
continue
}
key := strings.ToLower(string(parts[0]))
value := string(bytes.TrimSpace(parts[1]))
if ShouldSniffAttr {
content.SetAttribute(key, value) // Put header in attribute
}
if key == "host" {
rawHost := strings.ToLower(string(bytes.TrimSpace(parts[1])))
rawHost := strings.ToLower(value)
dest, err := ParseHost(rawHost, net.Port(80))
if err != nil {
return nil, err
@@ -85,6 +98,16 @@ func SniffHTTP(b []byte) (*SniffHeader, error) {
sh.host = dest.Address.String()
}
}
// Parse request line
// Request line is like this
// "GET /homo/114514 HTTP/1.1"
if len(headers) > 0 && ShouldSniffAttr {
RequestLineParts := bytes.Split(headers[0], []byte{' '})
if len(RequestLineParts) == 3 {
content.SetAttribute(":method", string(RequestLineParts[0]))
content.SetAttribute(":path", string(RequestLineParts[1]))
}
}
if len(sh.host) > 0 {
return sh, nil

View File

@@ -1,6 +1,7 @@
package http_test
import (
"context"
"testing"
. "github.com/xtls/xray-core/common/protocol/http"
@@ -88,7 +89,7 @@ first_name=John&last_name=Doe&action=Submit`,
}
for _, test := range cases {
header, err := SniffHTTP([]byte(test.input))
header, err := SniffHTTP([]byte(test.input), context.TODO())
if test.err {
if err == nil {
t.Errorf("Expect error but nil, in test: %v", test)

View File

@@ -47,206 +47,224 @@ var (
)
func SniffQUIC(b []byte) (*SniffHeader, error) {
buffer := buf.FromBytes(b)
typeByte, err := buffer.ReadByte()
if err != nil {
return nil, errNotQuic
}
isLongHeader := typeByte&0x80 > 0
if !isLongHeader || typeByte&0x40 == 0 {
return nil, errNotQuicInitial
}
// Crypto data separated across packets
cryptoLen := 0
cryptoData := bytespool.Alloc(int32(len(b)))
defer bytespool.Free(cryptoData)
vb, err := buffer.ReadBytes(4)
if err != nil {
return nil, errNotQuic
}
// Parse QUIC packets
for len(b) > 0 {
buffer := buf.FromBytes(b)
typeByte, err := buffer.ReadByte()
if err != nil {
return nil, errNotQuic
}
versionNumber := binary.BigEndian.Uint32(vb)
isLongHeader := typeByte&0x80 > 0
if !isLongHeader || typeByte&0x40 == 0 {
return nil, errNotQuicInitial
}
if versionNumber != 0 && typeByte&0x40 == 0 {
return nil, errNotQuic
} else if versionNumber != versionDraft29 && versionNumber != version1 {
return nil, errNotQuic
}
vb, err := buffer.ReadBytes(4)
if err != nil {
return nil, errNotQuic
}
if (typeByte&0x30)>>4 != 0x0 {
return nil, errNotQuicInitial
}
versionNumber := binary.BigEndian.Uint32(vb)
if versionNumber != 0 && typeByte&0x40 == 0 {
return nil, errNotQuic
} else if versionNumber != versionDraft29 && versionNumber != version1 {
return nil, errNotQuic
}
var destConnID []byte
if l, err := buffer.ReadByte(); err != nil {
return nil, errNotQuic
} else if destConnID, err = buffer.ReadBytes(int32(l)); err != nil {
return nil, errNotQuic
}
packetType := (typeByte & 0x30) >> 4
isQuicInitial := packetType == 0x0
if l, err := buffer.ReadByte(); err != nil {
return nil, errNotQuic
} else if common.Error2(buffer.ReadBytes(int32(l))) != nil {
return nil, errNotQuic
}
var destConnID []byte
if l, err := buffer.ReadByte(); err != nil {
return nil, errNotQuic
} else if destConnID, err = buffer.ReadBytes(int32(l)); err != nil {
return nil, errNotQuic
}
tokenLen, err := quicvarint.Read(buffer)
if err != nil || tokenLen > uint64(len(b)) {
return nil, errNotQuic
}
if l, err := buffer.ReadByte(); err != nil {
return nil, errNotQuic
} else if common.Error2(buffer.ReadBytes(int32(l))) != nil {
return nil, errNotQuic
}
if _, err = buffer.ReadBytes(int32(tokenLen)); err != nil {
return nil, errNotQuic
}
tokenLen, err := quicvarint.Read(buffer)
if err != nil || tokenLen > uint64(len(b)) {
return nil, errNotQuic
}
packetLen, err := quicvarint.Read(buffer)
if err != nil {
return nil, errNotQuic
}
if _, err = buffer.ReadBytes(int32(tokenLen)); err != nil {
return nil, errNotQuic
}
hdrLen := len(b) - int(buffer.Len())
packetLen, err := quicvarint.Read(buffer)
if err != nil {
return nil, errNotQuic
}
origPNBytes := make([]byte, 4)
copy(origPNBytes, b[hdrLen:hdrLen+4])
hdrLen := len(b) - int(buffer.Len())
if len(b) < hdrLen+int(packetLen) {
return nil, common.ErrNoClue // Not enough data to read as a QUIC packet. QUIC is UDP-based, so this is unlikely to happen.
}
var salt []byte
if versionNumber == version1 {
salt = quicSalt
} else {
salt = quicSaltOld
}
initialSecret := hkdf.Extract(crypto.SHA256.New, destConnID, salt)
secret := hkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "client in", crypto.SHA256.Size())
hpKey := hkdfExpandLabel(initialSuite.Hash, secret, []byte{}, "quic hp", initialSuite.KeyLen)
block, err := aes.NewCipher(hpKey)
if err != nil {
return nil, err
}
restPayload := b[hdrLen+int(packetLen):]
if !isQuicInitial { // Skip this packet if it's not initial packet
b = restPayload
continue
}
cache := buf.New()
defer cache.Release()
origPNBytes := make([]byte, 4)
copy(origPNBytes, b[hdrLen:hdrLen+4])
mask := cache.Extend(int32(block.BlockSize()))
block.Encrypt(mask, b[hdrLen+4:hdrLen+4+16])
b[0] ^= mask[0] & 0xf
for i := range b[hdrLen : hdrLen+4] {
b[hdrLen+i] ^= mask[i+1]
}
packetNumberLength := b[0]&0x3 + 1
if packetNumberLength != 1 {
return nil, errNotQuicInitial
}
var packetNumber uint32
{
n, err := buffer.ReadByte()
var salt []byte
if versionNumber == version1 {
salt = quicSalt
} else {
salt = quicSaltOld
}
initialSecret := hkdf.Extract(crypto.SHA256.New, destConnID, salt)
secret := hkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "client in", crypto.SHA256.Size())
hpKey := hkdfExpandLabel(initialSuite.Hash, secret, []byte{}, "quic hp", initialSuite.KeyLen)
block, err := aes.NewCipher(hpKey)
if err != nil {
return nil, err
}
packetNumber = uint32(n)
}
if packetNumber != 0 && packetNumber != 1 {
return nil, errNotQuicInitial
}
cache := buf.New()
defer cache.Release()
extHdrLen := hdrLen + int(packetNumberLength)
copy(b[extHdrLen:hdrLen+4], origPNBytes[packetNumberLength:])
data := b[extHdrLen : int(packetLen)+hdrLen]
key := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic key", 16)
iv := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic iv", 12)
cipher := AEADAESGCMTLS13(key, iv)
nonce := cache.Extend(int32(cipher.NonceSize()))
binary.BigEndian.PutUint64(nonce[len(nonce)-8:], uint64(packetNumber))
decrypted, err := cipher.Open(b[extHdrLen:extHdrLen], nonce, data, b[:extHdrLen])
if err != nil {
return nil, err
}
buffer = buf.FromBytes(decrypted)
cryptoLen := uint(0)
cryptoData := bytespool.Alloc(buffer.Len())
defer bytespool.Free(cryptoData)
for i := 0; !buffer.IsEmpty(); i++ {
frameType := byte(0x0) // Default to PADDING frame
for frameType == 0x0 && !buffer.IsEmpty() {
frameType, _ = buffer.ReadByte()
mask := cache.Extend(int32(block.BlockSize()))
block.Encrypt(mask, b[hdrLen+4:hdrLen+4+16])
b[0] ^= mask[0] & 0xf
for i := range b[hdrLen : hdrLen+4] {
b[hdrLen+i] ^= mask[i+1]
}
switch frameType {
case 0x00: // PADDING frame
case 0x01: // PING frame
case 0x02, 0x03: // ACK frame
if _, err = quicvarint.Read(buffer); err != nil { // Field: Largest Acknowledged
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Delay
return nil, io.ErrUnexpectedEOF
}
ackRangeCount, err := quicvarint.Read(buffer) // Field: ACK Range Count
if err != nil {
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: First ACK Range
return nil, io.ErrUnexpectedEOF
}
for i := 0; i < int(ackRangeCount); i++ { // Field: ACK Range
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Range -> Gap
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Range -> ACK Range Length
return nil, io.ErrUnexpectedEOF
}
}
if frameType == 0x03 {
if _, err = quicvarint.Read(buffer); err != nil { // Field: ECN Counts -> ECT0 Count
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: ECN Counts -> ECT1 Count
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { //nolint:misspell // Field: ECN Counts -> ECT-CE Count
return nil, io.ErrUnexpectedEOF
}
}
case 0x06: // CRYPTO frame, we will use this frame
offset, err := quicvarint.Read(buffer) // Field: Offset
if err != nil {
return nil, io.ErrUnexpectedEOF
}
length, err := quicvarint.Read(buffer) // Field: Length
if err != nil || length > uint64(buffer.Len()) {
return nil, io.ErrUnexpectedEOF
}
if cryptoLen < uint(offset+length) {
cryptoLen = uint(offset + length)
}
if _, err := buffer.Read(cryptoData[offset : offset+length]); err != nil { // Field: Crypto Data
return nil, io.ErrUnexpectedEOF
}
case 0x1c: // CONNECTION_CLOSE frame, only 0x1c is permitted in initial packet
if _, err = quicvarint.Read(buffer); err != nil { // Field: Error Code
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: Frame Type
return nil, io.ErrUnexpectedEOF
}
length, err := quicvarint.Read(buffer) // Field: Reason Phrase Length
if err != nil {
return nil, io.ErrUnexpectedEOF
}
if _, err := buffer.ReadBytes(int32(length)); err != nil { // Field: Reason Phrase
return nil, io.ErrUnexpectedEOF
}
default:
// Only above frame types are permitted in initial packet.
// See https://www.rfc-editor.org/rfc/rfc9000.html#section-17.2.2-8
packetNumberLength := b[0]&0x3 + 1
if packetNumberLength != 1 {
return nil, errNotQuicInitial
}
}
var packetNumber uint32
{
n, err := buffer.ReadByte()
if err != nil {
return nil, err
}
packetNumber = uint32(n)
}
tlsHdr := &ptls.SniffHeader{}
err = ptls.ReadClientHello(cryptoData[:cryptoLen], tlsHdr)
if err != nil {
return nil, err
extHdrLen := hdrLen + int(packetNumberLength)
copy(b[extHdrLen:hdrLen+4], origPNBytes[packetNumberLength:])
data := b[extHdrLen : int(packetLen)+hdrLen]
key := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic key", 16)
iv := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic iv", 12)
cipher := AEADAESGCMTLS13(key, iv)
nonce := cache.Extend(int32(cipher.NonceSize()))
binary.BigEndian.PutUint64(nonce[len(nonce)-8:], uint64(packetNumber))
decrypted, err := cipher.Open(b[extHdrLen:extHdrLen], nonce, data, b[:extHdrLen])
if err != nil {
return nil, err
}
buffer = buf.FromBytes(decrypted)
for i := 0; !buffer.IsEmpty(); i++ {
frameType := byte(0x0) // Default to PADDING frame
for frameType == 0x0 && !buffer.IsEmpty() {
frameType, _ = buffer.ReadByte()
}
switch frameType {
case 0x00: // PADDING frame
case 0x01: // PING frame
case 0x02, 0x03: // ACK frame
if _, err = quicvarint.Read(buffer); err != nil { // Field: Largest Acknowledged
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Delay
return nil, io.ErrUnexpectedEOF
}
ackRangeCount, err := quicvarint.Read(buffer) // Field: ACK Range Count
if err != nil {
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: First ACK Range
return nil, io.ErrUnexpectedEOF
}
for i := 0; i < int(ackRangeCount); i++ { // Field: ACK Range
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Range -> Gap
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Range -> ACK Range Length
return nil, io.ErrUnexpectedEOF
}
}
if frameType == 0x03 {
if _, err = quicvarint.Read(buffer); err != nil { // Field: ECN Counts -> ECT0 Count
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: ECN Counts -> ECT1 Count
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { //nolint:misspell // Field: ECN Counts -> ECT-CE Count
return nil, io.ErrUnexpectedEOF
}
}
case 0x06: // CRYPTO frame, we will use this frame
offset, err := quicvarint.Read(buffer) // Field: Offset
if err != nil {
return nil, io.ErrUnexpectedEOF
}
length, err := quicvarint.Read(buffer) // Field: Length
if err != nil || length > uint64(buffer.Len()) {
return nil, io.ErrUnexpectedEOF
}
if cryptoLen < int(offset+length) {
cryptoLen = int(offset + length)
if len(cryptoData) < cryptoLen {
newCryptoData := bytespool.Alloc(int32(cryptoLen))
copy(newCryptoData, cryptoData)
bytespool.Free(cryptoData)
cryptoData = newCryptoData
}
}
if _, err := buffer.Read(cryptoData[offset : offset+length]); err != nil { // Field: Crypto Data
return nil, io.ErrUnexpectedEOF
}
case 0x1c: // CONNECTION_CLOSE frame, only 0x1c is permitted in initial packet
if _, err = quicvarint.Read(buffer); err != nil { // Field: Error Code
return nil, io.ErrUnexpectedEOF
}
if _, err = quicvarint.Read(buffer); err != nil { // Field: Frame Type
return nil, io.ErrUnexpectedEOF
}
length, err := quicvarint.Read(buffer) // Field: Reason Phrase Length
if err != nil {
return nil, io.ErrUnexpectedEOF
}
if _, err := buffer.ReadBytes(int32(length)); err != nil { // Field: Reason Phrase
return nil, io.ErrUnexpectedEOF
}
default:
// Only above frame types are permitted in initial packet.
// See https://www.rfc-editor.org/rfc/rfc9000.html#section-17.2.2-8
return nil, errNotQuicInitial
}
}
tlsHdr := &ptls.SniffHeader{}
err = ptls.ReadClientHello(cryptoData[:cryptoLen], tlsHdr)
if err != nil {
// The crypto data may have not been fully recovered in current packets,
// So we continue to sniff rest packets.
b = restPayload
continue
}
return &SniffHeader{domain: tlsHdr.Domain()}, nil
}
return &SniffHeader{domain: tlsHdr.Domain()}, nil
return nil, common.ErrNoClue
}
func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, length int) []byte {

View File

@@ -1,14 +1,13 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.2
// protoc v5.27.0
// protoc v5.28.0
// source: core/config.proto
package core
import (
serial "github.com/xtls/xray-core/common/serial"
global "github.com/xtls/xray-core/transport/global"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
@@ -38,12 +37,6 @@ type Config struct {
// implement the Feature interface, and its config type must be registered
// through common.RegisterConfig.
App []*serial.TypedMessage `protobuf:"bytes,4,rep,name=app,proto3" json:"app,omitempty"`
// Transport settings.
// Deprecated. Each inbound and outbound should choose their own transport
// config. Date to remove: 2020-01-13
//
// Deprecated: Marked as deprecated in core/config.proto.
Transport *global.Config `protobuf:"bytes,5,opt,name=transport,proto3" json:"transport,omitempty"`
// Configuration for extensions. The config may not work if corresponding
// extension is not loaded into Xray. Xray will ignore such config during
// initialization.
@@ -103,14 +96,6 @@ func (x *Config) GetApp() []*serial.TypedMessage {
return nil
}
// Deprecated: Marked as deprecated in core/config.proto.
func (x *Config) GetTransport() *global.Config {
if x != nil {
return x.Transport
}
return nil
}
func (x *Config) GetExtension() []*serial.TypedMessage {
if x != nil {
return x.Extension
@@ -278,60 +263,54 @@ var file_core_config_proto_rawDesc = []byte{
0x6f, 0x74, 0x6f, 0x12, 0x09, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x1a, 0x21,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79,
0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x1a, 0x1d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x67, 0x6c, 0x6f,
0x62, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x22, 0xb5, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x07, 0x69,
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x69,
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x3c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75,
0x6e, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e,
0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x12, 0x32, 0x0a, 0x03, 0x61, 0x70, 0x70, 0x18, 0x04, 0x20, 0x03, 0x28,
0x6f, 0x22, 0xfb, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x07,
0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07,
0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x3c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61,
0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x6f, 0x75, 0x74,
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x32, 0x0a, 0x03, 0x61, 0x70, 0x70, 0x18, 0x04, 0x20, 0x03,
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, 0x03, 0x61, 0x70, 0x70, 0x12, 0x3e, 0x0a, 0x09, 0x65, 0x78, 0x74,
0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61,
0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09,
0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 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, 0x03, 0x61, 0x70, 0x70, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
0x72, 0x74, 0x12, 0x3e, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18,
0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64,
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
0x6f, 0x6e, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 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, 0xef, 0x01, 0x0a, 0x15,
0x4f, 0x75, 0x74, 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, 0x49, 0x0a, 0x0f, 0x73, 0x65, 0x6e, 0x64, 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, 0x0e, 0x73, 0x65, 0x6e, 0x64, 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, 0x12, 0x16, 0x0a, 0x06, 0x65,
0x78, 0x70, 0x69, 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x65, 0x78, 0x70,
0x69, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x3d, 0x0a,
0x0d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x50, 0x01,
0x5a, 0x1e, 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, 0x63, 0x6f, 0x72, 0x65,
0xaa, 0x02, 0x09, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x22, 0xef, 0x01, 0x0a, 0x15, 0x4f, 0x75, 0x74, 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, 0x49,
0x0a, 0x0f, 0x73, 0x65, 0x6e, 0x64, 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, 0x0e, 0x73, 0x65, 0x6e, 0x64, 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, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x18, 0x04, 0x20, 0x01,
0x28, 0x03, 0x52, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f,
0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d,
0x6d, 0x65, 0x6e, 0x74, 0x42, 0x3d, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x50, 0x01, 0x5a, 0x1e, 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, 0x63, 0x6f, 0x72, 0x65, 0xaa, 0x02, 0x09, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x43,
0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -352,23 +331,21 @@ var file_core_config_proto_goTypes = []any{
(*InboundHandlerConfig)(nil), // 1: xray.core.InboundHandlerConfig
(*OutboundHandlerConfig)(nil), // 2: xray.core.OutboundHandlerConfig
(*serial.TypedMessage)(nil), // 3: xray.common.serial.TypedMessage
(*global.Config)(nil), // 4: xray.transport.Config
}
var file_core_config_proto_depIdxs = []int32{
1, // 0: xray.core.Config.inbound:type_name -> xray.core.InboundHandlerConfig
2, // 1: xray.core.Config.outbound:type_name -> xray.core.OutboundHandlerConfig
3, // 2: xray.core.Config.app:type_name -> xray.common.serial.TypedMessage
4, // 3: xray.core.Config.transport:type_name -> xray.transport.Config
3, // 4: xray.core.Config.extension:type_name -> xray.common.serial.TypedMessage
3, // 5: xray.core.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
3, // 6: xray.core.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
3, // 7: xray.core.OutboundHandlerConfig.sender_settings:type_name -> xray.common.serial.TypedMessage
3, // 8: xray.core.OutboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
9, // [9:9] is the sub-list for method output_type
9, // [9:9] is the sub-list for method input_type
9, // [9:9] is the sub-list for extension type_name
9, // [9:9] is the sub-list for extension extendee
0, // [0:9] is the sub-list for field type_name
3, // 3: xray.core.Config.extension:type_name -> xray.common.serial.TypedMessage
3, // 4: xray.core.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
3, // 5: xray.core.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
3, // 6: xray.core.OutboundHandlerConfig.sender_settings:type_name -> xray.common.serial.TypedMessage
3, // 7: xray.core.OutboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
8, // [8:8] is the sub-list for method output_type
8, // [8:8] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
}
func init() { file_core_config_proto_init() }

View File

@@ -7,7 +7,6 @@ option java_package = "com.xray.core";
option java_multiple_files = true;
import "common/serial/typed_message.proto";
import "transport/global/config.proto";
// Config is the master config of Xray. Xray takes this config as input and
// functions accordingly.
@@ -26,15 +25,15 @@ message Config {
// through common.RegisterConfig.
repeated xray.common.serial.TypedMessage app = 4;
// Transport settings.
// Deprecated. Each inbound and outbound should choose their own transport
// config. Date to remove: 2020-01-13
xray.transport.Config transport = 5 [deprecated = true];
// Configuration for extensions. The config may not work if corresponding
// extension is not loaded into Xray. Xray will ignore such config during
// initialization.
repeated xray.common.serial.TypedMessage extension = 6;
// Transport settings.
// Deprecated. Each inbound and outbound should choose their own transport
// config. Date to remove: 2020-01-13
// xray.transport.Config transport = 5 [deprecated = true];
}
// InboundHandlerConfig is the configuration for inbound handler.

View File

@@ -21,7 +21,7 @@ import (
var (
Version_x byte = 24
Version_y byte = 9
Version_z byte = 7
Version_z byte = 16
)
var (

View File

@@ -185,13 +185,6 @@ func initInstanceWithConfig(config *Config, server *Instance) (bool, error) {
server.ctx = context.WithValue(server.ctx, "cone",
platform.NewEnvFlag(platform.UseCone).GetValue(func() string { return "" }) != "true")
if config.Transport != nil {
features.PrintDeprecatedFeatureWarning("global transport settings")
}
if err := config.Transport.Apply(); err != nil {
return true, err
}
for _, appSettings := range config.App {
settings, err := appSettings.GetInstance()
if err != nil {

View File

@@ -1,22 +1,12 @@
package features
import (
"context"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
)
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
// Feature is the interface for Xray features. All features must implement this interface.
// All existing features have an implementation in app directory. These features can be replaced by third-party ones.
type Feature interface {
common.HasType
common.Runnable
}
// PrintDeprecatedFeatureWarning prints a warning for deprecated feature.
func PrintDeprecatedFeatureWarning(feature string) {
errors.LogInfo(context.Background(), "You are using a deprecated feature: " + feature + ". Please update your config file with latest configuration format, or update your client software.")
}

View File

@@ -30,6 +30,9 @@ type Route interface {
// GetOutboundTag returns the tag of the outbound the connection was dispatched to.
GetOutboundTag() string
// GetRuleTag returns the matching rule tag for debugging if exists
GetRuleTag() string
}
// RouterType return the type of Router interface. Can be used to implement common.HasType.

4
go.mod
View File

@@ -14,7 +14,7 @@ require (
github.com/pires/go-proxyproto v0.7.0
github.com/quic-go/quic-go v0.46.0
github.com/refraction-networking/utls v1.6.7
github.com/sagernet/sing v0.4.1
github.com/sagernet/sing v0.4.3
github.com/sagernet/sing-shadowsocks v0.2.7
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771
github.com/stretchr/testify v1.9.0
@@ -27,7 +27,7 @@ require (
golang.org/x/sync v0.8.0
golang.org/x/sys v0.25.0
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
google.golang.org/grpc v1.66.0
google.golang.org/grpc v1.66.2
google.golang.org/protobuf v1.34.2
gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489
h12.io/socks v1.0.3

8
go.sum
View File

@@ -54,8 +54,8 @@ github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
github.com/sagernet/sing v0.4.1 h1:zVlpE+7k7AFoC2pv6ReqLf0PIHjihL/jsBl5k05PQFk=
github.com/sagernet/sing v0.4.1/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls=
github.com/sagernet/sing v0.4.3 h1:Ty/NAiNnVd6844k7ujlL5lkzydhcTH5Psc432jXA4Y8=
github.com/sagernet/sing v0.4.3/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls=
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 h1:emzAzMZ1L9iaKCTxdy3Em8Wv4ChIAGnfiz18Cda70g4=
@@ -127,8 +127,8 @@ golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uI
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo=
google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

View File

@@ -13,6 +13,7 @@ type DNSOutboundConfig struct {
Port uint16 `json:"port"`
UserLevel uint32 `json:"userLevel"`
NonIPQuery string `json:"nonIPQuery"`
BlockTypes []int32 `json:"blockTypes"`
}
func (c *DNSOutboundConfig) Build() (proto.Message, error) {
@@ -34,5 +35,6 @@ func (c *DNSOutboundConfig) Build() (proto.Message, error) {
return nil, errors.New(`unknown "nonIPQuery": `, c.NonIPQuery)
}
config.Non_IPQuery = c.NonIPQuery
config.BlockTypes = c.BlockTypes
return config, nil
}

View File

@@ -1,6 +1,7 @@
package conf
import (
"encoding/base64"
"net"
"strconv"
"strings"
@@ -19,6 +20,7 @@ type FreedomConfig struct {
UserLevel uint32 `json:"userLevel"`
Fragment *Fragment `json:"fragment"`
Noise *Noise `json:"noise"`
Noises []*Noise `json:"noises"`
ProxyProtocol uint32 `json:"proxyProtocol"`
}
@@ -29,8 +31,9 @@ type Fragment struct {
}
type Noise struct {
Packet string `json:"packet"`
Delay string `json:"delay"`
Type string `json:"type"`
Packet string `json:"packet"`
Delay *Int32Range `json:"delay"`
}
// Build implements Buildable
@@ -149,74 +152,18 @@ func (c *FreedomConfig) Build() (proto.Message, error) {
}
}
}
if c.Noise != nil {
config.Noise = new(freedom.Noise)
var err, err2 error
p := strings.Split(strings.ToLower(c.Noise.Packet), ":")
if len(p) != 2 {
return nil, errors.New("invalid type for packet")
}
switch p[0] {
case "rand":
randValue := strings.Split(p[1], "-")
if len(randValue) > 2 {
return nil, errors.New("Only 2 values are allowed for rand")
}
if len(randValue) == 2 {
config.Noise.LengthMin, err = strconv.ParseUint(randValue[0], 10, 64)
config.Noise.LengthMax, err2 = strconv.ParseUint(randValue[1], 10, 64)
}
if len(randValue) == 1 {
config.Noise.LengthMin, err = strconv.ParseUint(randValue[0], 10, 64)
config.Noise.LengthMax = config.Noise.LengthMin
}
return nil, errors.PrintRemovedFeatureError("noise = { ... }", "noises = [ { ... } ]")
}
if c.Noises != nil {
for _, n := range c.Noises {
NConfig, err := ParseNoise(n)
if err != nil {
return nil, errors.New("invalid value for rand LengthMin").Base(err)
return nil, err
}
if err2 != nil {
return nil, errors.New("invalid value for rand LengthMax").Base(err2)
}
if config.Noise.LengthMin > config.Noise.LengthMax {
config.Noise.LengthMin, config.Noise.LengthMax = config.Noise.LengthMax, config.Noise.LengthMin
}
if config.Noise.LengthMin == 0 {
return nil, errors.New("rand lengthMin or lengthMax cannot be 0")
}
case "str":
//user input string
config.Noise.StrNoise = strings.TrimSpace(p[1])
default:
return nil, errors.New("Invalid packet,only rand and str are supported")
}
if c.Noise.Delay != "" {
d := strings.Split(strings.ToLower(c.Noise.Delay), "-")
if len(d) > 2 {
return nil, errors.New("Invalid delay value")
}
if len(d) == 2 {
config.Noise.DelayMin, err = strconv.ParseUint(d[0], 10, 64)
config.Noise.DelayMax, err2 = strconv.ParseUint(d[1], 10, 64)
} else {
config.Noise.DelayMin, err = strconv.ParseUint(d[0], 10, 64)
config.Noise.DelayMax = config.Noise.DelayMin
}
if err != nil {
return nil, errors.New("Invalid value for DelayMin").Base(err)
}
if err2 != nil {
return nil, errors.New("Invalid value for DelayMax").Base(err2)
}
if config.Noise.DelayMin > config.Noise.DelayMax {
config.Noise.DelayMin, config.Noise.DelayMax = config.Noise.DelayMax, config.Noise.DelayMin
}
if config.Noise.DelayMin == 0 {
return nil, errors.New("DelayMin or DelayMax cannot be 0")
}
} else {
config.Noise.DelayMin = 0
config.Noises = append(config.Noises, NConfig)
}
}
@@ -248,3 +195,67 @@ func (c *FreedomConfig) Build() (proto.Message, error) {
}
return config, nil
}
func ParseNoise(noise *Noise) (*freedom.Noise, error) {
var err, err2 error
NConfig := new(freedom.Noise)
switch strings.ToLower(noise.Type) {
case "rand":
randValue := strings.Split(noise.Packet, "-")
if len(randValue) > 2 {
return nil, errors.New("Only 2 values are allowed for rand")
}
if len(randValue) == 2 {
NConfig.LengthMin, err = strconv.ParseUint(randValue[0], 10, 64)
NConfig.LengthMax, err2 = strconv.ParseUint(randValue[1], 10, 64)
}
if len(randValue) == 1 {
NConfig.LengthMin, err = strconv.ParseUint(randValue[0], 10, 64)
NConfig.LengthMax = NConfig.LengthMin
}
if err != nil {
return nil, errors.New("invalid value for rand LengthMin").Base(err)
}
if err2 != nil {
return nil, errors.New("invalid value for rand LengthMax").Base(err2)
}
if NConfig.LengthMin > NConfig.LengthMax {
NConfig.LengthMin, NConfig.LengthMax = NConfig.LengthMax, NConfig.LengthMin
}
if NConfig.LengthMin == 0 {
return nil, errors.New("rand lengthMin or lengthMax cannot be 0")
}
case "str":
//user input string
NConfig.StrNoise = []byte(strings.TrimSpace(noise.Packet))
case "base64":
//user input base64
NConfig.StrNoise, err = base64.StdEncoding.DecodeString(strings.TrimSpace(noise.Packet))
if err != nil {
return nil, errors.New("Invalid base64 string")
}
default:
return nil, errors.New("Invalid packet,only rand,str,base64 are supported")
}
if noise.Delay != nil {
if noise.Delay.From != 0 && noise.Delay.To != 0 {
NConfig.DelayMin = uint64(noise.Delay.From)
NConfig.DelayMax = uint64(noise.Delay.To)
if NConfig.DelayMin > NConfig.LengthMax {
NConfig.DelayMin, NConfig.DelayMax = NConfig.LengthMax, NConfig.DelayMin
}
} else {
return nil, errors.New("DelayMin or DelayMax cannot be zero")
}
} else {
NConfig.DelayMin = 0
NConfig.DelayMax = 0
}
return NConfig, nil
}

View File

@@ -16,10 +16,11 @@ func DefaultLogConfig() *log.Config {
}
type LogConfig struct {
AccessLog string `json:"access"`
ErrorLog string `json:"error"`
LogLevel string `json:"loglevel"`
DNSLog bool `json:"dnsLog"`
AccessLog string `json:"access"`
ErrorLog string `json:"error"`
LogLevel string `json:"loglevel"`
DNSLog bool `json:"dnsLog"`
MaskAddress string `json:"maskAddress"`
}
func (v *LogConfig) Build() *log.Config {
@@ -59,5 +60,6 @@ func (v *LogConfig) Build() *log.Config {
default:
config.ErrorLogLevel = clog.Severity_Warning
}
config.MaskAddress = v.MaskAddress
return config
}

View File

@@ -14,11 +14,6 @@ import (
"google.golang.org/protobuf/proto"
)
type RouterRulesConfig struct {
RuleList []json.RawMessage `json:"rules"`
DomainStrategy string `json:"domainStrategy"`
}
// StrategyConfig represents a strategy config
type StrategyConfig struct {
Type string `json:"type"`
@@ -76,7 +71,6 @@ func (r *BalancingRule) Build() (*router.BalancingRule, error) {
}
type RouterConfig struct {
Settings *RouterRulesConfig `json:"settings"` // Deprecated
RuleList []json.RawMessage `json:"rules"`
DomainStrategy *string `json:"domainStrategy"`
Balancers []*BalancingRule `json:"balancers"`
@@ -88,8 +82,6 @@ func (c *RouterConfig) getDomainStrategy() router.Config_DomainStrategy {
ds := ""
if c.DomainStrategy != nil {
ds = *c.DomainStrategy
} else if c.Settings != nil {
ds = c.Settings.DomainStrategy
}
switch strings.ToLower(ds) {
@@ -111,10 +103,6 @@ func (c *RouterConfig) Build() (*router.Config, error) {
var rawRuleList []json.RawMessage
if c != nil {
rawRuleList = c.RuleList
if c.Settings != nil {
c.RuleList = append(c.RuleList, c.Settings.RuleList...)
rawRuleList = c.RuleList
}
}
for _, rawRule := range rawRuleList {

View File

@@ -64,36 +64,33 @@ func TestRouterConfig(t *testing.T) {
runMultiTestCase(t, []TestCase{
{
Input: `{
"strategy": "rules",
"settings": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": [
"baidu.com",
"qq.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"10.0.0.0/8",
"::1/128"
],
"outboundTag": "test"
},{
"type": "field",
"port": "53, 443, 1000-2000",
"outboundTag": "test"
},{
"type": "field",
"port": 123,
"outboundTag": "test"
}
]
},
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": [
"baidu.com",
"qq.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"10.0.0.0/8",
"::1/128"
],
"outboundTag": "test"
},{
"type": "field",
"port": "53, 443, 1000-2000",
"outboundTag": "test"
},{
"type": "field",
"port": 123,
"outboundTag": "test"
}
],
"balancers": [
{
"tag": "b1",
@@ -225,28 +222,25 @@ func TestRouterConfig(t *testing.T) {
},
{
Input: `{
"strategy": "rules",
"settings": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": [
"baidu.com",
"qq.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"10.0.0.0/8",
"::1/128"
],
"outboundTag": "test"
}
]
}
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": [
"baidu.com",
"qq.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"10.0.0.0/8",
"::1/128"
],
"outboundTag": "test"
}
]
}`,
Parser: createParser(),
Output: &router.Config{
@@ -289,68 +283,5 @@ func TestRouterConfig(t *testing.T) {
},
},
},
{
Input: `{
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": [
"baidu.com",
"qq.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"10.0.0.0/8",
"::1/128"
],
"outboundTag": "test"
}
]
}`,
Parser: createParser(),
Output: &router.Config{
DomainStrategy: router.Config_AsIs,
Rule: []*router.RoutingRule{
{
Domain: []*router.Domain{
{
Type: router.Domain_Plain,
Value: "baidu.com",
},
{
Type: router.Domain_Plain,
Value: "qq.com",
},
},
TargetTag: &router.RoutingRule_Tag{
Tag: "direct",
},
},
{
Geoip: []*router.GeoIP{
{
Cidr: []*router.CIDR{
{
Ip: []byte{10, 0, 0, 0},
Prefix: 8,
},
{
Ip: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
Prefix: 128,
},
},
},
},
TargetTag: &router.RoutingRule_Tag{
Tag: "test",
},
},
},
},
},
})
}

View File

@@ -231,6 +231,14 @@ type SplitHTTPConfig struct {
ScMinPostsIntervalMs *Int32Range `json:"scMinPostsIntervalMs"`
NoSSEHeader bool `json:"noSSEHeader"`
XPaddingBytes *Int32Range `json:"xPaddingBytes"`
Xmux Xmux `json:"xmux"`
}
type Xmux struct {
maxConnections *Int32Range `json:"maxConnections"`
maxConcurrency *Int32Range `json:"maxConcurrency"`
cMaxReuseTimes *Int32Range `json:"cMaxReuseTimes"`
cMaxLifetimeMs *Int32Range `json:"cMaxLifetimeMs"`
}
func splithttpNewRandRangeConfig(input *Int32Range) *splithttp.RandRangeConfig {
@@ -254,6 +262,19 @@ func (c *SplitHTTPConfig) Build() (proto.Message, error) {
} else if c.Host == "" && c.Headers["Host"] != "" {
c.Host = c.Headers["Host"]
}
if c.Xmux.maxConnections != nil && c.Xmux.maxConcurrency != nil {
return nil, errors.New("maxConnections cannot be specified together with maxConcurrency")
}
// Multiplexing config
muxProtobuf := splithttp.Multiplexing{
MaxConnections: splithttpNewRandRangeConfig(c.Xmux.maxConnections),
MaxConcurrency: splithttpNewRandRangeConfig(c.Xmux.maxConcurrency),
CMaxReuseTimes: splithttpNewRandRangeConfig(c.Xmux.cMaxReuseTimes),
CMaxLifetimeMs: splithttpNewRandRangeConfig(c.Xmux.cMaxLifetimeMs),
}
config := &splithttp.Config{
Path: c.Path,
Host: c.Host,
@@ -263,6 +284,7 @@ func (c *SplitHTTPConfig) Build() (proto.Message, error) {
ScMinPostsIntervalMs: splithttpNewRandRangeConfig(c.ScMinPostsIntervalMs),
NoSSEHeader: c.NoSSEHeader,
XPaddingBytes: splithttpNewRandRangeConfig(c.XPaddingBytes),
Xmux: &muxProtobuf,
}
return config, nil
}
@@ -813,7 +835,7 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
config.SecuritySettings = append(config.SecuritySettings, tm)
config.SecurityType = tm.Type
case "xtls":
return nil, errors.New(`Please use VLESS flow "xtls-rprx-vision" with TLS or REALITY.`)
return nil, errors.PrintRemovedFeatureError(`Legacy XTLS`, `xtls-rprx-vision with TLS or REALITY`)
default:
return nil, errors.New(`Unknown security "` + c.Security + `".`)
}

View File

@@ -52,7 +52,7 @@ func (c *TrojanClientConfig) Build() (proto.Message, error) {
return nil, errors.New("Trojan password is not specified.")
}
if rec.Flow != "" {
return nil, errors.New(`Trojan doesn't support "flow" anymore.`)
return nil, errors.PrintRemovedFeatureError(`Flow for Trojan`, ``)
}
config.Server[idx] = &protocol.ServerEndpoint{
@@ -106,7 +106,7 @@ func (c *TrojanServerConfig) Build() (proto.Message, error) {
for idx, rawUser := range c.Clients {
if rawUser.Flow != "" {
return nil, errors.New(`Trojan doesn't support "flow" anymore.`)
return nil, errors.PrintRemovedFeatureError(`Flow for Trojan`, ``)
}
config.Users[idx] = &protocol.User{

View File

@@ -57,10 +57,6 @@ func (c *VMessDetourConfig) Build() *inbound.DetourConfig {
}
}
type FeaturesConfig struct {
Detour *VMessDetourConfig `json:"detour"`
}
type VMessDefaultConfig struct {
Level byte `json:"level"`
}
@@ -74,7 +70,6 @@ func (c *VMessDefaultConfig) Build() *inbound.DefaultConfig {
type VMessInboundConfig struct {
Users []json.RawMessage `json:"clients"`
Features *FeaturesConfig `json:"features"`
Defaults *VMessDefaultConfig `json:"default"`
DetourConfig *VMessDetourConfig `json:"detour"`
}
@@ -89,8 +84,6 @@ func (c *VMessInboundConfig) Build() (proto.Message, error) {
if c.DetourConfig != nil {
config.Detour = c.DetourConfig.Build()
} else if c.Features != nil && c.Features.Detour != nil {
config.Detour = c.Features.Detour.Build()
}
config.User = make([]*protocol.User, len(c.Users))

View File

@@ -48,21 +48,6 @@ var (
ctllog = log.New(os.Stderr, "xctl> ", 0)
)
func toProtocolList(s []string) ([]proxyman.KnownProtocols, error) {
kp := make([]proxyman.KnownProtocols, 0, 8)
for _, p := range s {
switch strings.ToLower(p) {
case "http":
kp = append(kp, proxyman.KnownProtocols_HTTP)
case "https", "tls", "ssl":
kp = append(kp, proxyman.KnownProtocols_TLS)
default:
return nil, errors.New("Unknown protocol: ", p)
}
}
return kp, nil
}
type SniffingConfig struct {
Enabled bool `json:"enabled"`
DestOverride *StringList `json:"destOverride"`
@@ -175,7 +160,6 @@ type InboundDetourConfig struct {
Tag string `json:"tag"`
Allocation *InboundDetourAllocationConfig `json:"allocate"`
StreamSetting *StreamConfig `json:"streamSettings"`
DomainOverride *StringList `json:"domainOverride"`
SniffingConfig *SniffingConfig `json:"sniffing"`
}
@@ -249,13 +233,6 @@ func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
}
receiverSettings.SniffingSettings = s
}
if c.DomainOverride != nil {
kp, err := toProtocolList(*c.DomainOverride)
if err != nil {
return nil, errors.New("failed to parse inbound detour config").Base(err)
}
receiverSettings.DomainOverride = kp
}
settings := []byte("{}")
if c.Settings != nil {
@@ -384,11 +361,6 @@ func (c *StatsConfig) Build() (*stats.Config, error) {
}
type Config struct {
// Port of this Point server.
// Deprecated: Port exists for historical compatibility
// and should not be used.
Port uint16 `json:"port"`
// Deprecated: Global transport config is no longer used
// left for returning error
Transport map[string]json.RawMessage `json:"transport"`
@@ -620,16 +592,8 @@ func (c *Config) Build() (*core.Config, error) {
inbounds = append(inbounds, c.InboundConfigs...)
}
// Backward compatibility.
if len(inbounds) > 0 && inbounds[0].PortList == nil && c.Port > 0 {
inbounds[0].PortList = &PortList{[]PortRange{{
From: uint32(c.Port),
To: uint32(c.Port),
}}}
}
if len(c.Transport) > 0 {
return nil, errors.New("Global transport config is deprecated")
return nil, errors.PrintRemovedFeatureError("Global transport config", "streamSettings in inbounds and outbounds")
}
for _, rawInboundConfig := range inbounds {

View File

@@ -74,18 +74,15 @@ func TestXrayConfig(t *testing.T) {
}
}],
"routing": {
"strategy": "rules",
"settings": {
"rules": [
{
"ip": [
"10.0.0.0/8"
],
"type": "field",
"outboundTag": "blocked"
}
]
}
"rules": [
{
"ip": [
"10.0.0.0/8"
],
"type": "field",
"outboundTag": "blocked"
}
]
}
}`,
Parser: createParser(),

View File

@@ -31,6 +31,7 @@ type Config struct {
Server *net.Endpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
UserLevel uint32 `protobuf:"varint,2,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
Non_IPQuery string `protobuf:"bytes,3,opt,name=non_IP_query,json=nonIPQuery,proto3" json:"non_IP_query,omitempty"`
BlockTypes []int32 `protobuf:"varint,4,rep,packed,name=block_types,json=blockTypes,proto3" json:"block_types,omitempty"`
}
func (x *Config) Reset() {
@@ -86,6 +87,13 @@ func (x *Config) GetNon_IPQuery() string {
return ""
}
func (x *Config) GetBlockTypes() []int32 {
if x != nil {
return x.BlockTypes
}
return nil
}
var File_proxy_dns_config_proto protoreflect.FileDescriptor
var file_proxy_dns_config_proto_rawDesc = []byte{
@@ -93,20 +101,22 @@ var file_proxy_dns_config_proto_rawDesc = []byte{
0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7c, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x12, 0x31, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e,
0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65,
0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76,
0x65, 0x6c, 0x12, 0x20, 0x0a, 0x0c, 0x6e, 0x6f, 0x6e, 0x5f, 0x49, 0x50, 0x5f, 0x71, 0x75, 0x65,
0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x6f, 0x6e, 0x49, 0x50, 0x51,
0x75, 0x65, 0x72, 0x79, 0x42, 0x4c, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x23, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72,
0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x64, 0x6e,
0x73, 0xaa, 0x02, 0x0e, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x44,
0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9d, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x12, 0x31, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76,
0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65,
0x76, 0x65, 0x6c, 0x12, 0x20, 0x0a, 0x0c, 0x6e, 0x6f, 0x6e, 0x5f, 0x49, 0x50, 0x5f, 0x71, 0x75,
0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x6f, 0x6e, 0x49, 0x50,
0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74,
0x79, 0x70, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x05, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63,
0x6b, 0x54, 0x79, 0x70, 0x65, 0x73, 0x42, 0x4c, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x23,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f,
0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f,
0x64, 0x6e, 0x73, 0xaa, 0x02, 0x0e, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79,
0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@@ -14,4 +14,5 @@ message Config {
xray.common.net.Endpoint server = 1;
uint32 user_level = 2;
string non_IP_query = 3;
repeated int32 block_types = 4;
}

View File

@@ -49,6 +49,7 @@ type Handler struct {
server net.Destination
timeout time.Duration
nonIPQuery string
blockTypes []int32
}
func (h *Handler) Init(config *Config, dnsClient dns.Client, policyManager policy.Manager) error {
@@ -63,6 +64,7 @@ func (h *Handler) Init(config *Config, dnsClient dns.Client, policyManager polic
h.server = config.Server.AsDestination()
}
h.nonIPQuery = config.Non_IPQuery
h.blockTypes = config.BlockTypes
return nil
}
@@ -84,12 +86,12 @@ func parseIPQuery(b []byte) (r bool, domain string, id uint16, qType dnsmessage.
errors.LogInfoInner(context.Background(), err, "question")
return
}
domain = q.Name.String()
qType = q.Type
if qType != dnsmessage.TypeA && qType != dnsmessage.TypeAAAA {
return
}
domain = q.Name.String()
r = true
return
}
@@ -181,10 +183,18 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.
if !h.isOwnLink(ctx) {
isIPQuery, domain, id, qType := parseIPQuery(b.Bytes())
if len(h.blockTypes) > 0 {
for _, blocktype := range h.blockTypes {
if blocktype == int32(qType) {
errors.LogInfo(ctx, "blocked type ", qType, " query for domain ", domain)
return nil
}
}
}
if isIPQuery {
go h.handleIPQuery(id, qType, domain, writer)
}
if isIPQuery || h.nonIPQuery == "drop" || qType == 65 {
if isIPQuery || h.nonIPQuery == "drop" {
b.Release()
continue
}

View File

@@ -237,7 +237,7 @@ type Noise struct {
LengthMax uint64 `protobuf:"varint,2,opt,name=length_max,json=lengthMax,proto3" json:"length_max,omitempty"`
DelayMin uint64 `protobuf:"varint,3,opt,name=delay_min,json=delayMin,proto3" json:"delay_min,omitempty"`
DelayMax uint64 `protobuf:"varint,4,opt,name=delay_max,json=delayMax,proto3" json:"delay_max,omitempty"`
StrNoise string `protobuf:"bytes,5,opt,name=str_noise,json=strNoise,proto3" json:"str_noise,omitempty"`
StrNoise []byte `protobuf:"bytes,5,opt,name=str_noise,json=strNoise,proto3" json:"str_noise,omitempty"`
}
func (x *Noise) Reset() {
@@ -300,11 +300,11 @@ func (x *Noise) GetDelayMax() uint64 {
return 0
}
func (x *Noise) GetStrNoise() string {
func (x *Noise) GetStrNoise() []byte {
if x != nil {
return x.StrNoise
}
return ""
return nil
}
type Config struct {
@@ -319,7 +319,7 @@ type Config struct {
UserLevel uint32 `protobuf:"varint,4,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
Fragment *Fragment `protobuf:"bytes,5,opt,name=fragment,proto3" json:"fragment,omitempty"`
ProxyProtocol uint32 `protobuf:"varint,6,opt,name=proxy_protocol,json=proxyProtocol,proto3" json:"proxy_protocol,omitempty"`
Noise *Noise `protobuf:"bytes,7,opt,name=noise,proto3" json:"noise,omitempty"`
Noises []*Noise `protobuf:"bytes,7,rep,name=noises,proto3" json:"noises,omitempty"`
}
func (x *Config) Reset() {
@@ -397,9 +397,9 @@ func (x *Config) GetProxyProtocol() uint32 {
return 0
}
func (x *Config) GetNoise() *Noise {
func (x *Config) GetNoises() []*Noise {
if x != nil {
return x.Noise
return x.Noises
}
return nil
}
@@ -439,8 +439,8 @@ var file_proxy_freedom_config_proto_rawDesc = []byte{
0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x69, 0x6e,
0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20,
0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x61, 0x78, 0x12, 0x1b, 0x0a,
0x09, 0x73, 0x74, 0x72, 0x5f, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x73, 0x74, 0x72, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x22, 0xb3, 0x04, 0x0a, 0x06, 0x43,
0x09, 0x73, 0x74, 0x72, 0x5f, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x08, 0x73, 0x74, 0x72, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x22, 0xb5, 0x04, 0x0a, 0x06, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x52, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f,
0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29,
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65,
@@ -462,27 +462,27 @@ var file_proxy_freedom_config_proto_rawDesc = []byte{
0x6e, 0x74, 0x52, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x06,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x12, 0x2f, 0x0a, 0x05, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x52, 0x05, 0x6e,
0x6f, 0x69, 0x73, 0x65, 0x22, 0xa9, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53,
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x49, 0x53,
0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, 0x0b,
0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55,
0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f,
0x49, 0x50, 0x34, 0x36, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50,
0x36, 0x34, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50,
0x10, 0x06, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10,
0x07, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x08,
0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10, 0x09,
0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, 0x10, 0x0a,
0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72,
0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x66, 0x72,
0x65, 0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f,
0x78, 0x79, 0x2e, 0x46, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
0x63, 0x6f, 0x6c, 0x12, 0x31, 0x0a, 0x06, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x18, 0x07, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x52, 0x06,
0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x22, 0xa9, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f,
0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01,
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a,
0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53,
0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f,
0x49, 0x50, 0x36, 0x34, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f,
0x49, 0x50, 0x10, 0x06, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50,
0x34, 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36,
0x10, 0x08, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36,
0x10, 0x09, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34,
0x10, 0x0a, 0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x50, 0x01, 0x5a, 0x27,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f,
0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f,
0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50,
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x46, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -512,7 +512,7 @@ var file_proxy_freedom_config_proto_depIdxs = []int32{
0, // 1: xray.proxy.freedom.Config.domain_strategy:type_name -> xray.proxy.freedom.Config.DomainStrategy
1, // 2: xray.proxy.freedom.Config.destination_override:type_name -> xray.proxy.freedom.DestinationOverride
2, // 3: xray.proxy.freedom.Config.fragment:type_name -> xray.proxy.freedom.Fragment
3, // 4: xray.proxy.freedom.Config.noise:type_name -> xray.proxy.freedom.Noise
3, // 4: xray.proxy.freedom.Config.noises:type_name -> xray.proxy.freedom.Noise
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name

View File

@@ -25,7 +25,7 @@ message Noise {
uint64 length_max = 2;
uint64 delay_min = 3;
uint64 delay_max = 4;
string str_noise = 5;
bytes str_noise = 5;
}
message Config {
@@ -48,5 +48,5 @@ message Config {
uint32 user_level = 4;
Fragment fragment = 5;
uint32 proxy_protocol = 6;
Noise noise = 7;
repeated Noise noises = 7;
}

View File

@@ -208,12 +208,11 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
}
} else {
writer = NewPacketWriter(conn, h, ctx, UDPOverride)
if h.config.Noise != nil {
errors.LogDebug(ctx, "NOISE", h.config.Noise.StrNoise, h.config.Noise.LengthMin, h.config.Noise.LengthMax,
h.config.Noise.DelayMin, h.config.Noise.DelayMax)
if h.config.Noises != nil {
errors.LogDebug(ctx, "NOISE", h.config.Noises)
writer = &NoisePacketWriter{
Writer: writer,
noise: h.config.Noise,
noises: h.config.Noises,
firstWrite: true,
UDPOverride: UDPOverride,
}
@@ -396,12 +395,12 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
type NoisePacketWriter struct {
buf.Writer
noise *Noise
noises []*Noise
firstWrite bool
UDPOverride net.Destination
}
// MultiBuffer writer with Noise in first packet
// MultiBuffer writer with Noise before first packet
func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
if w.firstWrite {
w.firstWrite = false
@@ -411,22 +410,23 @@ func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
}
var noise []byte
var err error
//User input string
if w.noise.StrNoise != "" {
noise = []byte(w.noise.StrNoise)
} else {
//Random noise
noise, err = GenerateRandomBytes(randBetween(int64(w.noise.LengthMin),
int64(w.noise.LengthMax)))
}
for _, n := range w.noises {
//User input string or base64 encoded string
if n.StrNoise != nil {
noise = n.StrNoise
} else {
//Random noise
noise, err = GenerateRandomBytes(randBetween(int64(n.LengthMin),
int64(n.LengthMax)))
}
if err != nil {
return err
}
w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)})
if err != nil {
return err
}
w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)})
if w.noise.DelayMin != 0 {
time.Sleep(time.Duration(randBetween(int64(w.noise.DelayMin), int64(w.noise.DelayMax))) * time.Millisecond)
if n.DelayMin != 0 {
time.Sleep(time.Duration(randBetween(int64(n.DelayMin), int64(n.DelayMax))) * time.Millisecond)
}
}
}

View File

@@ -16,7 +16,6 @@ import (
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features"
"github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/proxy/http"
@@ -56,7 +55,7 @@ func (s *Server) policy() policy.Session {
config := s.config
p := s.policyManager.ForLevel(config.UserLevel)
if config.Timeout > 0 {
features.PrintDeprecatedFeatureWarning("Socks timeout")
errors.PrintDeprecatedFeatureWarning("Socks timeout", "Policy level")
}
if config.Timeout > 0 && config.UserLevel == 0 {
p.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second

View File

@@ -64,7 +64,7 @@ func EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requ
}
// DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream.
func DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validator *vless.Validator) (*protocol.RequestHeader, *Addons, bool, error) {
func DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validator vless.Validator) (*protocol.RequestHeader, *Addons, bool, error) {
buffer := buf.StackNew()
defer buffer.Release()

View File

@@ -42,7 +42,7 @@ func TestRequestSerialization(t *testing.T) {
buffer := buf.StackNew()
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
Validator := new(vless.Validator)
Validator := new(vless.MemoryValidator)
Validator.Add(user)
actualRequest, actualAddons, _, err := DecodeRequestHeader(false, nil, &buffer, Validator)
@@ -83,7 +83,7 @@ func TestInvalidRequest(t *testing.T) {
buffer := buf.StackNew()
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
Validator := new(vless.Validator)
Validator := new(vless.MemoryValidator)
Validator.Add(user)
_, _, _, err := DecodeRequestHeader(false, nil, &buffer, Validator)
@@ -114,7 +114,7 @@ func TestMuxRequest(t *testing.T) {
buffer := buf.StackNew()
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
Validator := new(vless.Validator)
Validator := new(vless.MemoryValidator)
Validator.Add(user)
actualRequest, actualAddons, _, err := DecodeRequestHeader(false, nil, &buffer, Validator)

View File

@@ -45,7 +45,21 @@ func init() {
}); err != nil {
return nil, err
}
return New(ctx, config.(*Config), dc)
c := config.(*Config)
validator := new(vless.MemoryValidator)
for _, user := range c.Clients {
u, err := user.ToMemoryUser()
if err != nil {
return nil, errors.New("failed to get VLESS user").Base(err).AtError()
}
if err := validator.Add(u); err != nil {
return nil, errors.New("failed to initiate user").Base(err).AtError()
}
}
return New(ctx, c, dc, validator)
}))
}
@@ -53,30 +67,20 @@ func init() {
type Handler struct {
inboundHandlerManager feature_inbound.Manager
policyManager policy.Manager
validator *vless.Validator
validator vless.Validator
dns dns.Client
fallbacks map[string]map[string]map[string]*Fallback // or nil
// regexps map[string]*regexp.Regexp // or nil
}
// New creates a new VLess inbound handler.
func New(ctx context.Context, config *Config, dc dns.Client) (*Handler, error) {
func New(ctx context.Context, config *Config, dc dns.Client, validator vless.Validator) (*Handler, error) {
v := core.MustFromContext(ctx)
handler := &Handler{
inboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
validator: new(vless.Validator),
dns: dc,
}
for _, user := range config.Clients {
u, err := user.ToMemoryUser()
if err != nil {
return nil, errors.New("failed to get VLESS user").Base(err).AtError()
}
if err := handler.AddUser(ctx, u); err != nil {
return nil, errors.New("failed to initiate user").Base(err).AtError()
}
validator: validator,
}
if config.Fallbacks != nil {

View File

@@ -9,15 +9,21 @@ import (
"github.com/xtls/xray-core/common/uuid"
)
// Validator stores valid VLESS users.
type Validator struct {
type Validator interface {
Get(id uuid.UUID) *protocol.MemoryUser
Add(u *protocol.MemoryUser) error
Del(email string) error
}
// MemoryValidator stores valid VLESS users.
type MemoryValidator struct {
// Considering email's usage here, map + sync.Mutex/RWMutex may have better performance.
email sync.Map
users sync.Map
}
// Add a VLESS user, Email must be empty or unique.
func (v *Validator) Add(u *protocol.MemoryUser) error {
func (v *MemoryValidator) Add(u *protocol.MemoryUser) error {
if u.Email != "" {
_, loaded := v.email.LoadOrStore(strings.ToLower(u.Email), u)
if loaded {
@@ -29,7 +35,7 @@ func (v *Validator) Add(u *protocol.MemoryUser) error {
}
// Del a VLESS user with a non-empty Email.
func (v *Validator) Del(e string) error {
func (v *MemoryValidator) Del(e string) error {
if e == "" {
return errors.New("Email must not be empty.")
}
@@ -44,7 +50,7 @@ func (v *Validator) Del(e string) error {
}
// Get a VLESS user with UUID, nil if user doesn't exist.
func (v *Validator) Get(id uuid.UUID) *protocol.MemoryUser {
func (v *MemoryValidator) Get(id uuid.UUID) *protocol.MemoryUser {
u, _ := v.users.Load(id)
if u != nil {
return u.(*protocol.MemoryUser)

View File

@@ -39,7 +39,10 @@ func (v *TimedUserValidator) Add(u *protocol.MemoryUser) error {
v.users = append(v.users, u)
account := u.Account.(*MemoryAccount)
account, ok := u.Account.(*MemoryAccount)
if !ok {
return errors.New("account type is incorrect")
}
if !v.behaviorFused {
hashkdf := hmac.New(sha256.New, []byte("VMESSBSKDF"))
hashkdf.Write(account.ID.Bytes())

View File

@@ -560,8 +560,9 @@ func TestDomainSniffing(t *testing.T) {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(sniffingPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
DomainOverride: []proxyman.KnownProtocols{
proxyman.KnownProtocols_TLS,
SniffingSettings: &proxyman.SniffingConfig{
Enabled: true,
DestinationOverride: []string{"tls"},
},
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{

View File

@@ -1,13 +0,0 @@
package global
import (
"github.com/xtls/xray-core/transport/internet"
)
// Apply applies this Config.
func (c *Config) Apply() error {
if c == nil {
return nil
}
return internet.ApplyGlobalTransportSettings(c.TransportSettings)
}

View File

@@ -1,162 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.2
// protoc v5.27.0
// source: transport/global/config.proto
package global
import (
internet "github.com/xtls/xray-core/transport/internet"
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)
)
// Global transport settings. This affects all type of connections that go
// through Xray. Deprecated. Use each settings in StreamConfig.
//
// Deprecated: Marked as deprecated in transport/global/config.proto.
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
TransportSettings []*internet.TransportConfig `protobuf:"bytes,1,rep,name=transport_settings,json=transportSettings,proto3" json:"transport_settings,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_transport_global_config_proto_msgTypes[0]
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_transport_global_config_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 Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_transport_global_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetTransportSettings() []*internet.TransportConfig {
if x != nil {
return x.TransportSettings
}
return nil
}
var File_transport_global_config_proto protoreflect.FileDescriptor
var file_transport_global_config_proto_rawDesc = []byte{
0x0a, 0x1d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x67, 0x6c, 0x6f, 0x62,
0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x0e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x1a,
0x1f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x22, 0x65, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x57, 0x0a, 0x12, 0x74, 0x72,
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 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, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x52, 0x11, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69,
0x6e, 0x67, 0x73, 0x3a, 0x02, 0x18, 0x01, 0x42, 0x61, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x67, 0x6c,
0x6f, 0x62, 0x61, 0x6c, 0x50, 0x01, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72,
0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x67, 0x6c, 0x6f, 0x62,
0x61, 0x6c, 0xaa, 0x02, 0x15, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70,
0x6f, 0x72, 0x74, 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_transport_global_config_proto_rawDescOnce sync.Once
file_transport_global_config_proto_rawDescData = file_transport_global_config_proto_rawDesc
)
func file_transport_global_config_proto_rawDescGZIP() []byte {
file_transport_global_config_proto_rawDescOnce.Do(func() {
file_transport_global_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_global_config_proto_rawDescData)
})
return file_transport_global_config_proto_rawDescData
}
var file_transport_global_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_global_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.Config
(*internet.TransportConfig)(nil), // 1: xray.transport.internet.TransportConfig
}
var file_transport_global_config_proto_depIdxs = []int32{
1, // 0: xray.transport.Config.transport_settings:type_name -> xray.transport.internet.TransportConfig
1, // [1:1] is the sub-list for method output_type
1, // [1:1] 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_transport_global_config_proto_init() }
func file_transport_global_config_proto_init() {
if File_transport_global_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_transport_global_config_proto_msgTypes[0].Exporter = func(v any, i int) any {
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_transport_global_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_global_config_proto_goTypes,
DependencyIndexes: file_transport_global_config_proto_depIdxs,
MessageInfos: file_transport_global_config_proto_msgTypes,
}.Build()
File_transport_global_config_proto = out.File
file_transport_global_config_proto_rawDesc = nil
file_transport_global_config_proto_goTypes = nil
file_transport_global_config_proto_depIdxs = nil
}

View File

@@ -1,16 +0,0 @@
syntax = "proto3";
package xray.transport;
option csharp_namespace = "Xray.Transport.Global";
option go_package = "github.com/xtls/xray-core/transport/global";
option java_package = "com.xray.transport.global";
option java_multiple_files = true;
import "transport/internet/config.proto";
// Global transport settings. This affects all type of connections that go
// through Xray. Deprecated. Use each settings in StreamConfig.
message Config {
option deprecated = true;
repeated xray.transport.internet.TransportConfig transport_settings = 1;
}

View File

@@ -3,14 +3,12 @@ package internet
import (
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/features"
)
type ConfigCreator func() interface{}
var (
globalTransportConfigCreatorCache = make(map[string]ConfigCreator)
globalTransportSettings []*TransportConfig
)
var strategy = [][]byte{
@@ -105,12 +103,6 @@ func (c *StreamConfig) GetTransportSettingsFor(protocol string) (interface{}, er
}
}
for _, settings := range globalTransportSettings {
if settings.GetUnifiedProtocolName() == protocol {
return settings.GetTypedSettings()
}
}
return CreateTransportConfig(protocol)
}
@@ -127,12 +119,6 @@ func (c *StreamConfig) HasSecuritySettings() bool {
return len(c.SecurityType) > 0
}
func ApplyGlobalTransportSettings(settings []*TransportConfig) error {
features.PrintDeprecatedFeatureWarning("global transport settings")
globalTransportSettings = settings
return nil
}
func (c *ProxyConfig) HasTag() bool {
return c != nil && len(c.Tag) > 0
}

View File

@@ -140,6 +140,9 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
if err != nil {
return nil, errors.New("REALITY: publicKey == nil")
}
if uConn.HandshakeState.State13.EcdheKey == nil {
return nil, errors.New("Current fingerprint ", uConn.ClientHelloID.Client, uConn.ClientHelloID.Version, " does not support TLS 1.3, REALITY handshake cannot establish.")
}
uConn.AuthKey, _ = uConn.HandshakeState.State13.EcdheKey.ECDH(publicKey)
if uConn.AuthKey == nil {
return nil, errors.New("REALITY: SharedKey == nil")

View File

@@ -3,6 +3,7 @@ package splithttp
import (
"bytes"
"context"
"fmt"
"io"
gonet "net"
"net/http"
@@ -29,8 +30,7 @@ type DialerClient interface {
// implements splithttp.DialerClient in terms of direct network connections
type DefaultDialerClient struct {
transportConfig *Config
download *http.Client
upload *http.Client
client *http.Client
isH2 bool
isH3 bool
// pool of net.Conn, created using dialUploadConn
@@ -79,7 +79,7 @@ func (c *DefaultDialerClient) OpenDownload(ctx context.Context, baseURL string)
req.Header = c.transportConfig.GetRequestHeader()
response, err := c.download.Do(req)
response, err := c.client.Do(req)
gotConn.Close()
if err != nil {
errors.LogInfoInner(ctx, err, "failed to send download http request")
@@ -137,7 +137,7 @@ func (c *DefaultDialerClient) SendUploadRequest(ctx context.Context, url string,
req.Header = c.transportConfig.GetRequestHeader()
if c.isH2 || c.isH3 {
resp, err := c.upload.Do(req)
resp, err := c.client.Do(req)
if err != nil {
return err
}
@@ -152,23 +152,39 @@ func (c *DefaultDialerClient) SendUploadRequest(ctx context.Context, url string,
// safely retried. if instead req.Write is called multiple
// times, the body is already drained after the first
// request
requestBytes := new(bytes.Buffer)
common.Must(req.Write(requestBytes))
requestBuff := new(bytes.Buffer)
common.Must(req.Write(requestBuff))
var uploadConn any
var h1UploadConn *H1Conn
for {
uploadConn = c.uploadRawPool.Get()
newConnection := uploadConn == nil
if newConnection {
uploadConn, err = c.dialUploadConn(context.WithoutCancel(ctx))
newConn, err := c.dialUploadConn(context.WithoutCancel(ctx))
if err != nil {
return err
}
h1UploadConn = NewH1Conn(newConn)
uploadConn = h1UploadConn
} else {
h1UploadConn = uploadConn.(*H1Conn)
// TODO: Replace 0 here with a config value later
// Or add some other condition for optimization purposes
if h1UploadConn.UnreadedResponsesCount > 0 {
resp, err := http.ReadResponse(h1UploadConn.RespBufReader, req)
if err != nil {
return fmt.Errorf("error while reading response: %s", err.Error())
}
if resp.StatusCode != 200 {
return fmt.Errorf("got non-200 error response code: %d", resp.StatusCode)
}
}
}
_, err = uploadConn.(net.Conn).Write(requestBytes.Bytes())
_, err := h1UploadConn.Write(requestBuff.Bytes())
// if the write failed, we try another connection from
// the pool, until the write on a new connection fails.
// failed writes to a pooled connection are normal when

View File

@@ -105,6 +105,49 @@ func (c *Config) GetNormalizedXPaddingBytes() RandRangeConfig {
return *c.XPaddingBytes
}
func (m *Multiplexing) GetNormalizedCMaxReuseTimes() RandRangeConfig {
if m.CMaxReuseTimes == nil {
return RandRangeConfig{
From: 0,
To: 0,
}
}
return *m.CMaxReuseTimes
}
func (m *Multiplexing) GetNormalizedCMaxLifetimeMs() RandRangeConfig {
if m.CMaxLifetimeMs == nil || m.CMaxLifetimeMs.To == 0 {
return RandRangeConfig{
From: 0,
To: 0,
}
}
return *m.CMaxLifetimeMs
}
func (m *Multiplexing) GetNormalizedMaxConnections() RandRangeConfig {
if m.MaxConnections == nil {
return RandRangeConfig{
From: 0,
To: 0,
}
}
return *m.MaxConnections
}
func (m *Multiplexing) GetNormalizedMaxConcurrency() RandRangeConfig {
if m.MaxConcurrency == nil {
return RandRangeConfig{
From: 0,
To: 0,
}
}
return *m.MaxConcurrency
}
func init() {
common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
return new(Config)

View File

@@ -33,6 +33,7 @@ type Config struct {
ScMinPostsIntervalMs *RandRangeConfig `protobuf:"bytes,6,opt,name=scMinPostsIntervalMs,proto3" json:"scMinPostsIntervalMs,omitempty"`
NoSSEHeader bool `protobuf:"varint,7,opt,name=noSSEHeader,proto3" json:"noSSEHeader,omitempty"`
XPaddingBytes *RandRangeConfig `protobuf:"bytes,8,opt,name=xPaddingBytes,proto3" json:"xPaddingBytes,omitempty"`
Xmux *Multiplexing `protobuf:"bytes,9,opt,name=xmux,proto3" json:"xmux,omitempty"`
}
func (x *Config) Reset() {
@@ -123,6 +124,13 @@ func (x *Config) GetXPaddingBytes() *RandRangeConfig {
return nil
}
func (x *Config) GetXmux() *Multiplexing {
if x != nil {
return x.Xmux
}
return nil
}
type RandRangeConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -178,6 +186,77 @@ func (x *RandRangeConfig) GetTo() int32 {
return 0
}
type Multiplexing struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
MaxConnections *RandRangeConfig `protobuf:"bytes,1,opt,name=maxConnections,proto3" json:"maxConnections,omitempty"`
MaxConcurrency *RandRangeConfig `protobuf:"bytes,2,opt,name=maxConcurrency,proto3" json:"maxConcurrency,omitempty"`
CMaxReuseTimes *RandRangeConfig `protobuf:"bytes,3,opt,name=cMaxReuseTimes,proto3" json:"cMaxReuseTimes,omitempty"`
CMaxLifetimeMs *RandRangeConfig `protobuf:"bytes,4,opt,name=cMaxLifetimeMs,proto3" json:"cMaxLifetimeMs,omitempty"`
}
func (x *Multiplexing) Reset() {
*x = Multiplexing{}
if protoimpl.UnsafeEnabled {
mi := &file_transport_internet_splithttp_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Multiplexing) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Multiplexing) ProtoMessage() {}
func (x *Multiplexing) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_splithttp_config_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 Multiplexing.ProtoReflect.Descriptor instead.
func (*Multiplexing) Descriptor() ([]byte, []int) {
return file_transport_internet_splithttp_config_proto_rawDescGZIP(), []int{2}
}
func (x *Multiplexing) GetMaxConnections() *RandRangeConfig {
if x != nil {
return x.MaxConnections
}
return nil
}
func (x *Multiplexing) GetMaxConcurrency() *RandRangeConfig {
if x != nil {
return x.MaxConcurrency
}
return nil
}
func (x *Multiplexing) GetCMaxReuseTimes() *RandRangeConfig {
if x != nil {
return x.CMaxReuseTimes
}
return nil
}
func (x *Multiplexing) GetCMaxLifetimeMs() *RandRangeConfig {
if x != nil {
return x.CMaxLifetimeMs
}
return nil
}
var File_transport_internet_splithttp_config_proto protoreflect.FileDescriptor
var file_transport_internet_splithttp_config_proto_rawDesc = []byte{
@@ -185,8 +264,8 @@ var file_transport_internet_splithttp_config_proto_rawDesc = []byte{
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x21, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x22, 0xea,
0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73,
0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x22, 0xaf,
0x05, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73,
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a,
0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74,
0x68, 0x12, 0x4d, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28,
@@ -221,23 +300,51 @@ var file_transport_internet_splithttp_config_proto_rawDesc = []byte{
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74,
0x70, 0x2e, 0x52, 0x61, 0x6e, 0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x52, 0x0d, 0x78, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x42, 0x79, 0x74, 0x65, 0x73,
0x1a, 0x39, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x35, 0x0a, 0x0f, 0x52,
0x61, 0x6e, 0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12,
0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x66, 0x72,
0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02,
0x74, 0x6f, 0x42, 0x85, 0x01, 0x0a, 0x25, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x12, 0x43, 0x0a, 0x04, 0x78, 0x6d, 0x75, 0x78, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f,
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74,
0x74, 0x70, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x52,
0x04, 0x78, 0x6d, 0x75, 0x78, 0x1a, 0x39, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
0x22, 0x35, 0x0a, 0x0f, 0x52, 0x61, 0x6e, 0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28,
0x05, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20,
0x01, 0x28, 0x05, 0x52, 0x02, 0x74, 0x6f, 0x22, 0xfe, 0x02, 0x0a, 0x0c, 0x4d, 0x75, 0x6c, 0x74,
0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x12, 0x5a, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x43,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x32, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74,
0x68, 0x74, 0x74, 0x70, 0x2e, 0x52, 0x61, 0x6e, 0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x12, 0x5a, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x63, 0x75,
0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70,
0x2e, 0x52, 0x61, 0x6e, 0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x52, 0x0e, 0x6d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79,
0x12, 0x5a, 0x0a, 0x0e, 0x63, 0x4d, 0x61, 0x78, 0x52, 0x65, 0x75, 0x73, 0x65, 0x54, 0x69, 0x6d,
0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x50, 0x01, 0x5a, 0x36,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f,
0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x73, 0x70, 0x6c,
0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0xaa, 0x02, 0x21, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
0x2e, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x48, 0x74, 0x74, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x52, 0x61, 0x6e,
0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x63, 0x4d,
0x61, 0x78, 0x52, 0x65, 0x75, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x12, 0x5a, 0x0a, 0x0e,
0x63, 0x4d, 0x61, 0x78, 0x4c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x18, 0x04,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73,
0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x52, 0x61, 0x6e, 0x64, 0x52, 0x61, 0x6e,
0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x63, 0x4d, 0x61, 0x78, 0x4c, 0x69,
0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x42, 0x85, 0x01, 0x0a, 0x25, 0x63, 0x6f, 0x6d,
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74,
0x74, 0x70, 0x50, 0x01, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x65, 0x74, 0x2f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0xaa, 0x02, 0x21, 0x58,
0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x48, 0x74, 0x74, 0x70,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -252,23 +359,29 @@ func file_transport_internet_splithttp_config_proto_rawDescGZIP() []byte {
return file_transport_internet_splithttp_config_proto_rawDescData
}
var file_transport_internet_splithttp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_transport_internet_splithttp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_transport_internet_splithttp_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.splithttp.Config
(*RandRangeConfig)(nil), // 1: xray.transport.internet.splithttp.RandRangeConfig
nil, // 2: xray.transport.internet.splithttp.Config.HeaderEntry
(*Multiplexing)(nil), // 2: xray.transport.internet.splithttp.Multiplexing
nil, // 3: xray.transport.internet.splithttp.Config.HeaderEntry
}
var file_transport_internet_splithttp_config_proto_depIdxs = []int32{
2, // 0: xray.transport.internet.splithttp.Config.header:type_name -> xray.transport.internet.splithttp.Config.HeaderEntry
1, // 1: xray.transport.internet.splithttp.Config.scMaxConcurrentPosts:type_name -> xray.transport.internet.splithttp.RandRangeConfig
1, // 2: xray.transport.internet.splithttp.Config.scMaxEachPostBytes:type_name -> xray.transport.internet.splithttp.RandRangeConfig
1, // 3: xray.transport.internet.splithttp.Config.scMinPostsIntervalMs:type_name -> xray.transport.internet.splithttp.RandRangeConfig
1, // 4: xray.transport.internet.splithttp.Config.xPaddingBytes:type_name -> xray.transport.internet.splithttp.RandRangeConfig
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
3, // 0: xray.transport.internet.splithttp.Config.header:type_name -> xray.transport.internet.splithttp.Config.HeaderEntry
1, // 1: xray.transport.internet.splithttp.Config.scMaxConcurrentPosts:type_name -> xray.transport.internet.splithttp.RandRangeConfig
1, // 2: xray.transport.internet.splithttp.Config.scMaxEachPostBytes:type_name -> xray.transport.internet.splithttp.RandRangeConfig
1, // 3: xray.transport.internet.splithttp.Config.scMinPostsIntervalMs:type_name -> xray.transport.internet.splithttp.RandRangeConfig
1, // 4: xray.transport.internet.splithttp.Config.xPaddingBytes:type_name -> xray.transport.internet.splithttp.RandRangeConfig
2, // 5: xray.transport.internet.splithttp.Config.xmux:type_name -> xray.transport.internet.splithttp.Multiplexing
1, // 6: xray.transport.internet.splithttp.Multiplexing.maxConnections:type_name -> xray.transport.internet.splithttp.RandRangeConfig
1, // 7: xray.transport.internet.splithttp.Multiplexing.maxConcurrency:type_name -> xray.transport.internet.splithttp.RandRangeConfig
1, // 8: xray.transport.internet.splithttp.Multiplexing.cMaxReuseTimes:type_name -> xray.transport.internet.splithttp.RandRangeConfig
1, // 9: xray.transport.internet.splithttp.Multiplexing.cMaxLifetimeMs:type_name -> xray.transport.internet.splithttp.RandRangeConfig
10, // [10:10] is the sub-list for method output_type
10, // [10:10] is the sub-list for method input_type
10, // [10:10] is the sub-list for extension type_name
10, // [10:10] is the sub-list for extension extendee
0, // [0:10] is the sub-list for field type_name
}
func init() { file_transport_internet_splithttp_config_proto_init() }
@@ -301,6 +414,18 @@ func file_transport_internet_splithttp_config_proto_init() {
return nil
}
}
file_transport_internet_splithttp_config_proto_msgTypes[2].Exporter = func(v any, i int) any {
switch v := v.(*Multiplexing); 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{
@@ -308,7 +433,7 @@ func file_transport_internet_splithttp_config_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_transport_internet_splithttp_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},

View File

@@ -15,9 +15,17 @@ message Config {
RandRangeConfig scMinPostsIntervalMs = 6;
bool noSSEHeader = 7;
RandRangeConfig xPaddingBytes = 8;
Multiplexing xmux = 9;
}
message RandRangeConfig {
int32 from = 1;
int32 to = 2;
}
message Multiplexing {
RandRangeConfig maxConnections = 1;
RandRangeConfig maxConcurrency = 2;
RandRangeConfig cMaxReuseTimes = 3;
RandRangeConfig cMaxLifetimeMs = 4;
}

View File

@@ -11,6 +11,7 @@ type splitConn struct {
reader io.ReadCloser
remoteAddr net.Addr
localAddr net.Addr
onClose func()
}
func (c *splitConn) Write(b []byte) (int, error) {
@@ -22,6 +23,10 @@ func (c *splitConn) Read(b []byte) (int, error) {
}
func (c *splitConn) Close() error {
if c.onClose != nil {
c.onClose()
}
err := c.writer.Close()
err2 := c.reader.Close()
if err != nil {

View File

@@ -41,32 +41,51 @@ type dialerConf struct {
}
var (
globalDialerMap map[dialerConf]DialerClient
globalDialerMap map[dialerConf]*muxManager
globalDialerAccess sync.Mutex
)
func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) DialerClient {
func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (DialerClient, *muxResource) {
if browser_dialer.HasBrowserDialer() {
return &BrowserDialerClient{}
return &BrowserDialerClient{}, nil
}
tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
isH2 := tlsConfig != nil && !(len(tlsConfig.NextProtocol) == 1 && tlsConfig.NextProtocol[0] == "http/1.1")
isH3 := tlsConfig != nil && (len(tlsConfig.NextProtocol) == 1 && tlsConfig.NextProtocol[0] == "h3")
globalDialerAccess.Lock()
defer globalDialerAccess.Unlock()
if globalDialerMap == nil {
globalDialerMap = make(map[dialerConf]DialerClient)
globalDialerMap = make(map[dialerConf]*muxManager)
}
key := dialerConf{dest, streamSettings}
muxManager, found := globalDialerMap[key]
if !found {
transportConfig := streamSettings.ProtocolSettings.(*Config)
var mux Multiplexing
if transportConfig.Xmux != nil {
mux = *transportConfig.Xmux
}
muxManager = NewMuxManager(mux, func() interface{} {
return createHTTPClient(dest, streamSettings)
})
globalDialerMap[key] = muxManager
}
res := muxManager.GetResource(ctx)
return res.Resource.(DialerClient), res
}
func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStreamConfig) DialerClient {
tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
isH2 := tlsConfig != nil && !(len(tlsConfig.NextProtocol) == 1 && tlsConfig.NextProtocol[0] == "http/1.1")
isH3 := tlsConfig != nil && (len(tlsConfig.NextProtocol) == 1 && tlsConfig.NextProtocol[0] == "h3")
if isH3 {
dest.Network = net.Network_UDP
}
if client, found := globalDialerMap[dialerConf{dest, streamSettings}]; found {
return client
}
var gotlsConfig *gotls.Config
@@ -74,6 +93,8 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in
gotlsConfig = tlsConfig.GetTLSConfig(tls.WithDestination(dest))
}
transportConfig := streamSettings.ProtocolSettings.(*Config)
dialContext := func(ctxInner context.Context) (net.Conn, error) {
conn, err := internet.DialSystem(ctxInner, dest, streamSettings.SocketSettings)
if err != nil {
@@ -94,8 +115,7 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in
return conn, nil
}
var downloadTransport http.RoundTripper
var uploadTransport http.RoundTripper
var transport http.RoundTripper
if isH3 {
quicConfig := &quic.Config{
@@ -107,7 +127,7 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in
MaxIncomingStreams: -1,
KeepAlivePeriod: h3KeepalivePeriod,
}
roundTripper := &http3.RoundTripper{
transport = &http3.RoundTripper{
QUICConfig: quicConfig,
TLSClientConfig: gotlsConfig,
Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
@@ -147,23 +167,20 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in
return quic.DialEarly(ctx, udpConn, udpAddr, tlsCfg, cfg)
},
}
downloadTransport = roundTripper
uploadTransport = roundTripper
} else if isH2 {
downloadTransport = &http2.Transport{
transport = &http2.Transport{
DialTLSContext: func(ctxInner context.Context, network string, addr string, cfg *gotls.Config) (net.Conn, error) {
return dialContext(ctxInner)
},
IdleConnTimeout: connIdleTimeout,
ReadIdleTimeout: h2KeepalivePeriod,
}
uploadTransport = downloadTransport
} else {
httpDialContext := func(ctxInner context.Context, network string, addr string) (net.Conn, error) {
return dialContext(ctxInner)
}
downloadTransport = &http.Transport{
transport = &http.Transport{
DialTLSContext: httpDialContext,
DialContext: httpDialContext,
IdleConnTimeout: connIdleTimeout,
@@ -171,17 +188,12 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in
// http.Client and our custom dial context.
DisableKeepAlives: true,
}
// we use uploadRawPool for that
uploadTransport = nil
}
client := &DefaultDialerClient{
transportConfig: streamSettings.ProtocolSettings.(*Config),
download: &http.Client{
Transport: downloadTransport,
},
upload: &http.Client{
Transport: uploadTransport,
transportConfig: transportConfig,
client: &http.Client{
Transport: transport,
},
isH2: isH2,
isH3: isH3,
@@ -189,7 +201,6 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in
dialUploadConn: dialContext,
}
globalDialerMap[dialerConf{dest, streamSettings}] = client
return client
}
@@ -223,7 +234,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
requestURL.Path = transportConfiguration.GetNormalizedPath() + sessionIdUuid.String()
requestURL.RawQuery = transportConfiguration.GetNormalizedQuery()
httpClient := getHTTPClient(ctx, dest, streamSettings)
httpClient, muxResource := getHTTPClient(ctx, dest, streamSettings)
maxUploadSize := scMaxEachPostBytes.roll()
// WithSizeLimit(0) will still allow single bytes to pass, and a lot of
@@ -231,7 +242,15 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
// uploadWriter wrapper, exact size limits can be enforced
uploadPipeReader, uploadPipeWriter := pipe.New(pipe.WithSizeLimit(maxUploadSize - 1))
if muxResource != nil {
muxResource.OpenRequests.Add(1)
}
go func() {
if muxResource != nil {
defer muxResource.OpenRequests.Add(-1)
}
requestsLimiter := semaphore.New(int(scMaxConcurrentPosts.roll()))
var requestCounter int64
@@ -267,7 +286,6 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
&buf.MultiBufferContainer{MultiBuffer: chunk},
int64(chunk.Len()),
)
if err != nil {
errors.LogInfoInner(ctx, err, "failed to send upload")
uploadPipeReader.Interrupt()

View File

@@ -0,0 +1,19 @@
package splithttp
import (
"bufio"
"net"
)
type H1Conn struct {
UnreadedResponsesCount int
RespBufReader *bufio.Reader
net.Conn
}
func NewH1Conn(conn net.Conn) *H1Conn {
return &H1Conn{
RespBufReader: bufio.NewReader(conn),
Conn: conn,
}
}

View File

@@ -0,0 +1,102 @@
package splithttp
import (
"context"
"math/rand"
"sync/atomic"
"time"
"github.com/xtls/xray-core/common/errors"
)
type muxResource struct {
Resource interface{}
OpenRequests atomic.Int32
leftUsage int32
expirationTime time.Time
}
type muxManager struct {
newResourceFn func() interface{}
config Multiplexing
concurrency int32
connections int32
instances []*muxResource
}
func NewMuxManager(config Multiplexing, newResource func() interface{}) *muxManager {
return &muxManager{
config: config,
concurrency: config.GetNormalizedMaxConcurrency().roll(),
connections: config.GetNormalizedMaxConnections().roll(),
newResourceFn: newResource,
instances: make([]*muxResource, 0),
}
}
func (m *muxManager) GetResource(ctx context.Context) *muxResource {
m.removeExpiredConnections(ctx)
if m.connections > 0 && len(m.instances) < int(m.connections) {
errors.LogDebug(ctx, "xmux: creating client, connections=", len(m.instances))
return m.newResource()
}
if len(m.instances) == 0 {
errors.LogDebug(ctx, "xmux: creating client because instances is empty, connections=", len(m.instances))
return m.newResource()
}
clients := make([]*muxResource, 0)
if m.concurrency > 0 {
for _, client := range m.instances {
openRequests := client.OpenRequests.Load()
if openRequests < m.concurrency {
clients = append(clients, client)
}
}
} else {
clients = m.instances
}
if len(clients) == 0 {
errors.LogDebug(ctx, "xmux: creating client because concurrency was hit, total clients=", len(m.instances))
return m.newResource()
}
client := clients[rand.Intn(len(clients))]
if client.leftUsage > 0 {
client.leftUsage -= 1
}
return client
}
func (m *muxManager) newResource() *muxResource {
leftUsage := int32(-1)
if x := m.config.GetNormalizedCMaxReuseTimes().roll(); x > 0 {
leftUsage = x - 1
}
expirationTime := time.UnixMilli(0)
if x := m.config.GetNormalizedCMaxLifetimeMs().roll(); x > 0 {
expirationTime = time.Now().Add(time.Duration(x) * time.Millisecond)
}
client := &muxResource{
Resource: m.newResourceFn(),
leftUsage: leftUsage,
expirationTime: expirationTime,
}
m.instances = append(m.instances, client)
return client
}
func (m *muxManager) removeExpiredConnections(ctx context.Context) {
for i := 0; i < len(m.instances); i++ {
client := m.instances[i]
if client.leftUsage == 0 || (client.expirationTime != time.UnixMilli(0) && time.Now().After(client.expirationTime)) {
errors.LogDebug(ctx, "xmux: removing client, leftUsage = ", client.leftUsage, ", expirationTime = ", client.expirationTime)
m.instances = append(m.instances[:i], m.instances[i+1:]...)
i--
}
}
}

View File

@@ -0,0 +1,88 @@
package splithttp_test
import (
"context"
"testing"
. "github.com/xtls/xray-core/transport/internet/splithttp"
)
type fakeRoundTripper struct{}
func TestMaxConnections(t *testing.T) {
config := Multiplexing{
MaxConnections: &RandRangeConfig{From: 4, To: 4},
}
mux := NewMuxManager(config, func() interface{} {
return &fakeRoundTripper{}
})
clients := make(map[interface{}]struct{})
for i := 0; i < 8; i++ {
clients[mux.GetResource(context.Background())] = struct{}{}
}
if len(clients) != 4 {
t.Error("did not get 4 distinct clients, got ", len(clients))
}
}
func TestCMaxReuseTimes(t *testing.T) {
config := Multiplexing{
CMaxReuseTimes: &RandRangeConfig{From: 2, To: 2},
}
mux := NewMuxManager(config, func() interface{} {
return &fakeRoundTripper{}
})
clients := make(map[interface{}]struct{})
for i := 0; i < 64; i++ {
clients[mux.GetResource(context.Background())] = struct{}{}
}
if len(clients) != 32 {
t.Error("did not get 32 distinct clients, got ", len(clients))
}
}
func TestMaxConcurrency(t *testing.T) {
config := Multiplexing{
MaxConcurrency: &RandRangeConfig{From: 2, To: 2},
}
mux := NewMuxManager(config, func() interface{} {
return &fakeRoundTripper{}
})
clients := make(map[interface{}]struct{})
for i := 0; i < 64; i++ {
client := mux.GetResource(context.Background())
client.OpenRequests.Add(1)
clients[client] = struct{}{}
}
if len(clients) != 32 {
t.Error("did not get 32 distinct clients, got ", len(clients))
}
}
func TestDefault(t *testing.T) {
config := Multiplexing{}
mux := NewMuxManager(config, func() interface{} {
return &fakeRoundTripper{}
})
clients := make(map[interface{}]struct{})
for i := 0; i < 64; i++ {
client := mux.GetResource(context.Background())
client.OpenRequests.Add(1)
clients[client] = struct{}{}
}
if len(clients) != 1 {
t.Error("did not get 1 distinct clients, got ", len(clients))
}
}