Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b33fde2e44 | |||
| 65da3d9c9d |
@@ -70,7 +70,6 @@
|
||||
- [Xray_bash_onekey](https://github.com/hello-yunshu/Xray_bash_onekey), [XTool](https://github.com/LordPenguin666/XTool), [VPainLess](https://github.com/vpainless/vpainless)
|
||||
- [v2ray-agent](https://github.com/mack-a/v2ray-agent), [Xray_onekey](https://github.com/wulabing/Xray_onekey), [ProxySU](https://github.com/proxysu/ProxySU)
|
||||
- Magisk
|
||||
- [NetProxy-Magisk](https://github.com/Fanju6/NetProxy-Magisk)
|
||||
- [Xray4Magisk](https://github.com/Asterisk4Magisk/Xray4Magisk)
|
||||
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
|
||||
- Homebrew
|
||||
@@ -107,15 +106,12 @@
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
- [GenyConnect](https://github.com/genyleap/GenyConnect)
|
||||
- Android
|
||||
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
||||
- [X-flutter](https://github.com/XTLS/X-flutter)
|
||||
- [SaeedDev94/Xray](https://github.com/SaeedDev94/Xray)
|
||||
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
||||
- [XrayFA](https://github.com/Q7DF1/XrayFA)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
- [NetProxy-Magisk](https://github.com/Fanju6/NetProxy-Magisk)
|
||||
- iOS & macOS arm64 & tvOS
|
||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215) | [Happ RU](https://apps.apple.com/ru/app/happ-proxy-utility-plus/id6746188973) | [Happ tvOS](https://apps.apple.com/us/app/happ-proxy-utility-for-tv/id6748297274)
|
||||
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)
|
||||
@@ -129,7 +125,6 @@
|
||||
- [GoXRay](https://github.com/goxray/desktop)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
||||
- [GenyConnect](https://github.com/genyleap/GenyConnect)
|
||||
- Linux
|
||||
- [v2rayA](https://github.com/v2rayA/v2rayA)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
@@ -137,7 +132,6 @@
|
||||
- [GoXRay](https://github.com/goxray/desktop)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
||||
- [GenyConnect](https://github.com/genyleap/GenyConnect)
|
||||
|
||||
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
||||
|
||||
|
||||
@@ -411,6 +411,7 @@ type MultiplexingConfig struct {
|
||||
XudpConcurrency int32 `protobuf:"varint,3,opt,name=xudpConcurrency,proto3" json:"xudpConcurrency,omitempty"`
|
||||
// "reject" (default), "allow" or "skip".
|
||||
XudpProxyUDP443 string `protobuf:"bytes,4,opt,name=xudpProxyUDP443,proto3" json:"xudpProxyUDP443,omitempty"`
|
||||
BrutalBPS uint64 `protobuf:"varint,5,opt,name=brutalBPS,proto3" json:"brutalBPS,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -473,6 +474,13 @@ func (x *MultiplexingConfig) GetXudpProxyUDP443() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *MultiplexingConfig) GetBrutalBPS() uint64 {
|
||||
if x != nil {
|
||||
return x.BrutalBPS
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_app_proxyman_config_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_app_proxyman_config_proto_rawDesc = "" +
|
||||
@@ -503,12 +511,13 @@ const file_app_proxyman_config_proto_rawDesc = "" +
|
||||
"\x0eproxy_settings\x18\x03 \x01(\v2$.xray.transport.internet.ProxyConfigR\rproxySettings\x12T\n" +
|
||||
"\x12multiplex_settings\x18\x04 \x01(\v2%.xray.app.proxyman.MultiplexingConfigR\x11multiplexSettings\x12\x19\n" +
|
||||
"\bvia_cidr\x18\x05 \x01(\tR\aviaCidr\x12P\n" +
|
||||
"\x0ftarget_strategy\x18\x06 \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0etargetStrategy\"\xa4\x01\n" +
|
||||
"\x0ftarget_strategy\x18\x06 \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0etargetStrategy\"\xc2\x01\n" +
|
||||
"\x12MultiplexingConfig\x12\x18\n" +
|
||||
"\aenabled\x18\x01 \x01(\bR\aenabled\x12 \n" +
|
||||
"\vconcurrency\x18\x02 \x01(\x05R\vconcurrency\x12(\n" +
|
||||
"\x0fxudpConcurrency\x18\x03 \x01(\x05R\x0fxudpConcurrency\x12(\n" +
|
||||
"\x0fxudpProxyUDP443\x18\x04 \x01(\tR\x0fxudpProxyUDP443BU\n" +
|
||||
"\x0fxudpProxyUDP443\x18\x04 \x01(\tR\x0fxudpProxyUDP443\x12\x1c\n" +
|
||||
"\tbrutalBPS\x18\x05 \x01(\x04R\tbrutalBPSBU\n" +
|
||||
"\x15com.xray.app.proxymanP\x01Z&github.com/xtls/xray-core/app/proxyman\xaa\x02\x11Xray.App.Proxymanb\x06proto3"
|
||||
|
||||
var (
|
||||
|
||||
@@ -68,4 +68,5 @@ message MultiplexingConfig {
|
||||
int32 xudpConcurrency = 3;
|
||||
// "reject" (default), "allow" or "skip".
|
||||
string xudpProxyUDP443 = 4;
|
||||
uint64 brutalBPS = 5;
|
||||
}
|
||||
|
||||
@@ -136,7 +136,8 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
||||
Dialer: h,
|
||||
Strategy: mux.ClientStrategy{
|
||||
MaxConcurrency: uint32(config.Concurrency),
|
||||
MaxConnection: 128,
|
||||
MaxReuseTimes: 32768,
|
||||
BrutalBPS: config.BrutalBPS,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -157,7 +158,8 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
||||
Dialer: h,
|
||||
Strategy: mux.ClientStrategy{
|
||||
MaxConcurrency: uint32(config.XudpConcurrency),
|
||||
MaxConnection: 128,
|
||||
MaxReuseTimes: 32768,
|
||||
BrutalBPS: config.BrutalBPS,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -75,6 +75,12 @@ func (mb MultiBuffer) Copy(b []byte) int {
|
||||
return total
|
||||
}
|
||||
|
||||
func (mb MultiBuffer) Bytes() []byte {
|
||||
b := make([]byte, mb.Len())
|
||||
mb.Copy(b)
|
||||
return b
|
||||
}
|
||||
|
||||
// ReadFrom reads all content from reader until EOF.
|
||||
func ReadFrom(reader io.Reader) (MultiBuffer, error) {
|
||||
mb := make(MultiBuffer, 0, 16)
|
||||
|
||||
+29
-2
@@ -2,6 +2,7 @@ package mux
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
goerrors "errors"
|
||||
"io"
|
||||
"sync"
|
||||
@@ -9,6 +10,7 @@ import (
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
@@ -170,7 +172,8 @@ func (f *DialingWorkerFactory) Create() (*ClientWorker, error) {
|
||||
|
||||
type ClientStrategy struct {
|
||||
MaxConcurrency uint32
|
||||
MaxConnection uint32
|
||||
MaxReuseTimes uint32
|
||||
BrutalBPS uint64
|
||||
}
|
||||
|
||||
type ClientWorker struct {
|
||||
@@ -198,6 +201,9 @@ func NewClientWorker(stream transport.Link, s ClientStrategy) (*ClientWorker, er
|
||||
|
||||
go c.fetchOutput()
|
||||
go c.monitor()
|
||||
if s.BrutalBPS > 0 {
|
||||
go c.sendSetBrutal(s.BrutalBPS)
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
@@ -288,7 +294,7 @@ func fetchInput(ctx context.Context, s *Session, output buf.Writer) {
|
||||
|
||||
func (m *ClientWorker) IsClosing() bool {
|
||||
sm := m.sessionManager
|
||||
if m.strategy.MaxConnection > 0 && sm.Count() >= int(m.strategy.MaxConnection) {
|
||||
if m.strategy.MaxReuseTimes > 0 && sm.Count() >= int(m.strategy.MaxReuseTimes) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -417,3 +423,24 @@ func (m *ClientWorker) fetchOutput() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *ClientWorker) sendSetBrutal(sendBPS uint64) {
|
||||
meta := FrameMetadata{
|
||||
SessionID: 91,
|
||||
SessionStatus: SessionStatusSetBrutal,
|
||||
}
|
||||
meta.Option.Set(OptionData)
|
||||
frame := buf.New()
|
||||
common.Must(meta.WriteTo(frame))
|
||||
lengthByte := frame.Extend(2)
|
||||
speedByte := frame.Extend(int32(200 + dice.Roll(200)))
|
||||
binary.BigEndian.PutUint64(speedByte, sendBPS)
|
||||
binary.BigEndian.PutUint16(lengthByte, uint16(len(speedByte)))
|
||||
errors.LogError(context.Background(), "Start sending SetBrutal frame with speed: ", sendBPS)
|
||||
err := m.link.Writer.WriteMultiBuffer(buf.MultiBuffer{frame})
|
||||
if err != nil {
|
||||
frame.Release()
|
||||
errors.LogError(context.Background(), "failed to send SetBrutal frame: ", err)
|
||||
}
|
||||
errors.LogInfo(context.Background(), "SetBrutal frame sent successfully")
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ func TestClientWorkerClose(t *testing.T) {
|
||||
Writer: w1,
|
||||
}, mux.ClientStrategy{
|
||||
MaxConcurrency: 4,
|
||||
MaxConnection: 4,
|
||||
MaxReuseTimes: 4,
|
||||
})
|
||||
common.Must(err)
|
||||
|
||||
@@ -68,7 +68,7 @@ func TestClientWorkerClose(t *testing.T) {
|
||||
Writer: w2,
|
||||
}, mux.ClientStrategy{
|
||||
MaxConcurrency: 4,
|
||||
MaxConnection: 4,
|
||||
MaxReuseTimes: 4,
|
||||
})
|
||||
common.Must(err)
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ const (
|
||||
SessionStatusKeep SessionStatus = 0x02
|
||||
SessionStatusEnd SessionStatus = 0x03
|
||||
SessionStatusKeepAlive SessionStatus = 0x04
|
||||
|
||||
SessionStatusSetBrutal SessionStatus = 0x91
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -2,6 +2,7 @@ package mux
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/internet/brutal"
|
||||
"github.com/xtls/xray-core/transport/pipe"
|
||||
)
|
||||
|
||||
@@ -333,6 +335,40 @@ func (w *ServerWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.Buffered
|
||||
return nil
|
||||
}
|
||||
|
||||
// note: do not return error, just log it
|
||||
func (w *ServerWorker) HandleSetBrutal(ctx context.Context, meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||
if meta.Option.Has(OptionData) == false {
|
||||
errors.LogError(ctx, "SetBrutal frame missing data")
|
||||
return nil
|
||||
}
|
||||
chunkReader := NewStreamReader(reader)
|
||||
data, err := chunkReader.ReadMultiBuffer()
|
||||
if err != nil {
|
||||
errors.LogError(ctx, "unexpected error when reading brutal data: ", err)
|
||||
}
|
||||
speed := binary.BigEndian.Uint64(data.Bytes())
|
||||
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound == nil || inbound.Conn == nil {
|
||||
errors.LogError(ctx, "no inbound connection found for brutal set")
|
||||
return nil
|
||||
}
|
||||
conn := inbound.Conn
|
||||
tcpConn, ok := conn.(*net.TCPConn)
|
||||
if !ok {
|
||||
errors.LogError(ctx, "brutal can only be set on TCP connections")
|
||||
return nil
|
||||
}
|
||||
err = brutal.SetBrutal(tcpConn, speed)
|
||||
if err != nil {
|
||||
errors.LogError(ctx, "failed to set brutal: ", err)
|
||||
return nil
|
||||
} else {
|
||||
errors.LogInfo(ctx, "successfully set brutal speed: ", speed)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedReader) error {
|
||||
var meta FrameMetadata
|
||||
err := meta.Unmarshal(reader, session.IsReverseMuxFromContext(ctx))
|
||||
@@ -349,6 +385,8 @@ func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedRead
|
||||
err = w.handleStatusNew(session.ContextWithIsReverseMux(ctx, false), &meta, reader)
|
||||
case SessionStatusKeep:
|
||||
err = w.handleStatusKeep(&meta, reader)
|
||||
case SessionStatusSetBrutal:
|
||||
err = w.HandleSetBrutal(ctx, &meta, reader)
|
||||
default:
|
||||
status := meta.SessionStatus
|
||||
return errors.New("unknown status: ", status).AtError()
|
||||
|
||||
@@ -56,11 +56,12 @@ func (m *SessionManager) Allocate(Strategy *ClientStrategy) *Session {
|
||||
defer m.Unlock()
|
||||
|
||||
MaxConcurrency := int(Strategy.MaxConcurrency)
|
||||
MaxConnection := uint16(Strategy.MaxConnection)
|
||||
MaxReuseTimes := uint16(Strategy.MaxReuseTimes)
|
||||
|
||||
if m.closed || (MaxConcurrency > 0 && len(m.sessions) >= MaxConcurrency) || (MaxConnection > 0 && m.count >= MaxConnection) {
|
||||
if m.closed || (MaxConcurrency > 0 && len(m.sessions) >= MaxConcurrency) || (MaxReuseTimes > 0 && m.count >= MaxReuseTimes) {
|
||||
return nil
|
||||
}
|
||||
errors.LogInfo(context.Background(), "Allocated mux.cool session id ", m.count, "/", MaxReuseTimes)
|
||||
|
||||
m.count++
|
||||
s := &Session{
|
||||
|
||||
@@ -27,7 +27,7 @@ require (
|
||||
golang.org/x/sys v0.41.0
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/grpc v1.78.0
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0
|
||||
h12.io/socks v1.0.3
|
||||
@@ -48,9 +48,7 @@ require (
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
golang.org/x/tools v0.41.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
replace github.com/refraction-networking/utls => github.com/fangliding/utls v0.0.0-20260223095720-1ba92b0f6acd
|
||||
|
||||
@@ -2,15 +2,11 @@ github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sx
|
||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/apernet/quic-go v0.57.2-0.20260111184307-eec823306178 h1:bSq8n+gX4oO/qnM3MKf4kroW75n+phO9Qp6nigJKZ1E=
|
||||
github.com/apernet/quic-go v0.57.2-0.20260111184307-eec823306178/go.mod h1:N1WIjPphkqs4efXWuyDNQ6OjjIK04vM3h+bEgwV+eVU=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
||||
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fangliding/utls v0.0.0-20260223095720-1ba92b0f6acd h1:gOZhm1IpArbRLXkLzT5m11HU/HLJmp1aI6/WQLZ85+Y=
|
||||
github.com/fangliding/utls v0.0.0-20260223095720-1ba92b0f6acd/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
@@ -53,6 +49,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||
github.com/refraction-networking/utls v1.8.2 h1:j4Q1gJj0xngdeH+Ox/qND11aEfhpgoEvV+S9iJ2IdQo=
|
||||
github.com/refraction-networking/utls v1.8.2/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
||||
@@ -70,16 +68,16 @@ github.com/xtls/reality v0.0.0-20251014195629-e4eec4520535/go.mod h1:vbHCV/3VWUv
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||
@@ -133,10 +131,10 @@ 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=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda h1:i/Q+bfisr7gq6feoJnS/DlpdwEL4ihp41fvRiM3Ork0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -102,6 +102,7 @@ func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {
|
||||
type MuxConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Concurrency int16 `json:"concurrency"`
|
||||
BrutalBPS uint64 `json:"brutalBPS"`
|
||||
XudpConcurrency int16 `json:"xudpConcurrency"`
|
||||
XudpProxyUDP443 string `json:"xudpProxyUDP443"`
|
||||
}
|
||||
@@ -118,6 +119,7 @@ func (m *MuxConfig) Build() (*proxyman.MultiplexingConfig, error) {
|
||||
return &proxyman.MultiplexingConfig{
|
||||
Enabled: m.Enabled,
|
||||
Concurrency: int32(m.Concurrency),
|
||||
BrutalBPS: m.BrutalBPS,
|
||||
XudpConcurrency: int32(m.XudpConcurrency),
|
||||
XudpProxyUDP443: m.XudpProxyUDP443,
|
||||
}, nil
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
//go:build linux
|
||||
|
||||
package brutal
|
||||
|
||||
import (
|
||||
"os"
|
||||
"unsafe"
|
||||
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
//go:linkname setsockopt syscall.setsockopt
|
||||
func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
|
||||
|
||||
const (
|
||||
TCP_BRUTAL_PARAMS = 23301
|
||||
)
|
||||
|
||||
type TCPBrutalParams struct {
|
||||
Rate uint64
|
||||
CwndGain uint32
|
||||
}
|
||||
|
||||
func setBrutalFD(fd uintptr, sendBPS uint64) error {
|
||||
err := unix.SetsockoptString(int(fd), unix.IPPROTO_TCP, unix.TCP_CONGESTION, "brutal")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := TCPBrutalParams{
|
||||
Rate: sendBPS,
|
||||
CwndGain: 20, // hysteria2 default
|
||||
}
|
||||
err = setsockopt(int(fd), unix.IPPROTO_TCP, TCP_BRUTAL_PARAMS, unsafe.Pointer(¶ms), unsafe.Sizeof(params))
|
||||
if err != nil {
|
||||
return os.NewSyscallError("setsockopt IPPROTO_TCP TCP_BRUTAL_PARAMS", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetBrutal(conn *net.TCPConn, sendBPS uint64) error {
|
||||
syscallConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
syscallConn.Control(func(fd uintptr) {
|
||||
err = setBrutalFD(fd, sendBPS)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
//go:build !linux
|
||||
|
||||
package brutal
|
||||
|
||||
import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
)
|
||||
|
||||
func SetBrutal(conn *net.TCPConn, sendBPS uint64) error {
|
||||
return errors.New("brutal not available on this platform")
|
||||
}
|
||||
@@ -1,12 +1,9 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
func TestConfig_GetServiceName(t *testing.T) {
|
||||
@@ -118,12 +115,3 @@ func TestConfig_GetTunMultiStreamName(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetUserAgent(t *testing.T) {
|
||||
ua := "Test/1.0"
|
||||
conn, err := grpc.NewClient("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithUserAgent(ua))
|
||||
assert.NoError(t, err)
|
||||
defer conn.Close()
|
||||
setUserAgent(conn, ua)
|
||||
assert.Equal(t, ua, reflect.ValueOf(conn).Elem().FieldByName("dopts").FieldByName("copts").FieldByName("UserAgent").String())
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -169,6 +168,12 @@ func getGrpcClient(ctx context.Context, dest net.Destination, streamSettings *in
|
||||
dialOptions = append(dialOptions, grpc.WithInitialWindowSize(grpcSettings.InitialWindowsSize))
|
||||
}
|
||||
|
||||
userAgent := grpcSettings.UserAgent
|
||||
if userAgent == "" {
|
||||
userAgent = utils.ChromeUA
|
||||
}
|
||||
dialOptions = append(dialOptions, grpc.WithUserAgent(userAgent))
|
||||
|
||||
var grpcDestHost string
|
||||
if dest.Address.Family().IsDomain() {
|
||||
grpcDestHost = dest.Address.Domain()
|
||||
@@ -176,26 +181,10 @@ func getGrpcClient(ctx context.Context, dest net.Destination, streamSettings *in
|
||||
grpcDestHost = dest.Address.IP().String()
|
||||
}
|
||||
|
||||
conn, err := grpc.NewClient(
|
||||
"passthrough:///"+net.JoinHostPort(grpcDestHost, dest.Port.String()),
|
||||
conn, err := grpc.Dial(
|
||||
net.JoinHostPort(grpcDestHost, dest.Port.String()),
|
||||
dialOptions...,
|
||||
)
|
||||
if err == nil {
|
||||
userAgent := grpcSettings.UserAgent
|
||||
if userAgent == "" {
|
||||
userAgent = utils.ChromeUA
|
||||
}
|
||||
setUserAgent(conn, userAgent)
|
||||
conn.Connect()
|
||||
}
|
||||
globalDialerMap[dialerConf{dest, streamSettings}] = conn
|
||||
return conn, err
|
||||
}
|
||||
|
||||
// setUserAgent overrides the user-agent on a ClientConn to remove the
|
||||
// "grpc-go/version" suffix that grpc.WithUserAgent unconditionally appends.
|
||||
func setUserAgent(conn *grpc.ClientConn, ua string) {
|
||||
if f := reflect.ValueOf(conn).Elem().FieldByName("dopts").FieldByName("copts").FieldByName("UserAgent"); f.IsValid() {
|
||||
*(*string)(f.Addr().UnsafePointer()) = ua
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
utls "github.com/refraction-networking/utls"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/utils"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
@@ -98,12 +97,6 @@ func (c *UConn) WebsocketHandshakeContext(ctx context.Context) error {
|
||||
if err := c.BuildHandshakeState(); err != nil {
|
||||
return err
|
||||
}
|
||||
config := *utils.AccessField[*utls.Config](c, "config")
|
||||
// Do not modify outer ALPN to http/1.1 if ECH is used
|
||||
// Outer ALPN will be h2,http/1.1, and real ALPN in config will be hidden in ECH
|
||||
if config.EncryptedClientHelloConfigList != nil {
|
||||
return c.HandshakeContext(ctx)
|
||||
}
|
||||
// Iterate over extensions and check for utls.ALPNExtension
|
||||
hasALPNExtension := false
|
||||
for _, extension := range c.Extensions {
|
||||
@@ -138,7 +131,7 @@ func GeneraticUClient(c net.Conn, config *tls.Config) *utls.UConn {
|
||||
}
|
||||
|
||||
func copyConfig(c *tls.Config) *utls.Config {
|
||||
config := &utls.Config{
|
||||
return &utls.Config{
|
||||
Rand: c.Rand,
|
||||
RootCAs: c.RootCAs,
|
||||
ServerName: c.ServerName,
|
||||
@@ -147,10 +140,6 @@ func copyConfig(c *tls.Config) *utls.Config {
|
||||
KeyLogWriter: c.KeyLogWriter,
|
||||
EncryptedClientHelloConfigList: c.EncryptedClientHelloConfigList,
|
||||
}
|
||||
if config.EncryptedClientHelloConfigList != nil {
|
||||
config.NextProtos = c.NextProtos
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
Reference in New Issue
Block a user