diff --git a/infra/conf/transport_internet.go b/infra/conf/transport_internet.go index 9ab34cf595c3..769a09ddcd64 100644 --- a/infra/conf/transport_internet.go +++ b/infra/conf/transport_internet.go @@ -649,6 +649,8 @@ type SocketConfig struct { V6only bool `json:"v6only"` Interface string `json:"interface"` TcpMptcp bool `json:"tcpMptcp"` + BrutalRate uint64 `json:"brutalRate"` + BrutalGain uint32 `json:"brutalGain"` } // Build implements Buildable. @@ -723,6 +725,8 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) { V6Only: c.V6only, Interface: c.Interface, TcpMptcp: c.TcpMptcp, + BrutalRate: c.BrutalRate, + BrutalGain: c.BrutalGain, }, nil } diff --git a/transport/internet/config.pb.go b/transport/internet/config.pb.go index 3c8e36f5cf43..bc0a2fca596b 100644 --- a/transport/internet/config.pb.go +++ b/transport/internet/config.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.23.1 +// protoc-gen-go v1.33.0 +// protoc v4.25.3 // source: transport/internet/config.proto package internet @@ -453,6 +453,8 @@ type SocketConfig struct { TcpMaxSeg int32 `protobuf:"varint,17,opt,name=tcp_max_seg,json=tcpMaxSeg,proto3" json:"tcp_max_seg,omitempty"` TcpNoDelay bool `protobuf:"varint,18,opt,name=tcp_no_delay,json=tcpNoDelay,proto3" json:"tcp_no_delay,omitempty"` TcpMptcp bool `protobuf:"varint,19,opt,name=tcp_mptcp,json=tcpMptcp,proto3" json:"tcp_mptcp,omitempty"` + BrutalRate uint64 `protobuf:"varint,20,opt,name=brutal_rate,json=brutalRate,proto3" json:"brutal_rate,omitempty"` + BrutalGain uint32 `protobuf:"varint,21,opt,name=brutal_gain,json=brutalGain,proto3" json:"brutal_gain,omitempty"` } func (x *SocketConfig) Reset() { @@ -620,6 +622,20 @@ func (x *SocketConfig) GetTcpMptcp() bool { return false } +func (x *SocketConfig) GetBrutalRate() uint64 { + if x != nil { + return x.BrutalRate + } + return 0 +} + +func (x *SocketConfig) GetBrutalGain() uint32 { + if x != nil { + return x.BrutalGain + } + return 0 +} + var File_transport_internet_config_proto protoreflect.FileDescriptor var file_transport_internet_config_proto_rawDesc = []byte{ @@ -672,7 +688,7 @@ var file_transport_internet_config_proto_rawDesc = []byte{ 0x12, 0x30, 0x0a, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x50, 0x72, 0x6f, - 0x78, 0x79, 0x22, 0xd1, 0x06, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e, + 0x78, 0x79, 0x22, 0x93, 0x07, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x74, 0x66, 0x6f, 0x12, 0x48, 0x0a, 0x06, 0x74, 0x70, 0x72, @@ -722,33 +738,38 @@ var file_transport_internet_config_proto_rawDesc = []byte{ 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x74, 0x63, 0x70, 0x4e, 0x6f, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x63, 0x70, 0x5f, 0x6d, 0x70, 0x74, 0x63, 0x70, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x63, 0x70, - 0x4d, 0x70, 0x74, 0x63, 0x70, 0x22, 0x2f, 0x0a, 0x0a, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, - 0x6f, 0x64, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x66, 0x66, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, - 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x69, - 0x72, 0x65, 0x63, 0x74, 0x10, 0x02, 0x2a, 0x5a, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, - 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x07, 0x0a, 0x03, 0x54, - 0x43, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x01, 0x12, 0x08, 0x0a, - 0x04, 0x4d, 0x4b, 0x43, 0x50, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x57, 0x65, 0x62, 0x53, 0x6f, - 0x63, 0x6b, 0x65, 0x74, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x04, - 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, - 0x10, 0x05, 0x2a, 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, 0x67, - 0x0a, 0x1b, 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, 0x50, 0x01, 0x5a, - 0x2c, 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, 0xaa, 0x02, 0x17, - 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x4d, 0x70, 0x74, 0x63, 0x70, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x72, 0x75, 0x74, 0x61, 0x6c, 0x5f, + 0x72, 0x61, 0x74, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x62, 0x72, 0x75, 0x74, + 0x61, 0x6c, 0x52, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x72, 0x75, 0x74, 0x61, 0x6c, + 0x5f, 0x67, 0x61, 0x69, 0x6e, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x62, 0x72, 0x75, + 0x74, 0x61, 0x6c, 0x47, 0x61, 0x69, 0x6e, 0x22, 0x2f, 0x0a, 0x0a, 0x54, 0x50, 0x72, 0x6f, 0x78, + 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x66, 0x66, 0x10, 0x00, 0x12, 0x0a, + 0x0a, 0x06, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10, 0x02, 0x2a, 0x5a, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x07, 0x0a, + 0x03, 0x54, 0x43, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x01, 0x12, + 0x08, 0x0a, 0x04, 0x4d, 0x4b, 0x43, 0x50, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x57, 0x65, 0x62, + 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, + 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x6f, 0x63, 0x6b, + 0x65, 0x74, 0x10, 0x05, 0x2a, 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, 0x67, 0x0a, 0x1b, 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, 0x50, + 0x01, 0x5a, 0x2c, 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, 0xaa, + 0x02, 0x17, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/transport/internet/config.proto b/transport/internet/config.proto index f596d19f7e42..945fc73ec0d8 100644 --- a/transport/internet/config.proto +++ b/transport/internet/config.proto @@ -119,4 +119,8 @@ message SocketConfig { bool tcp_no_delay = 18; bool tcp_mptcp = 19; + + uint64 brutal_rate = 20; + + uint32 brutal_gain = 21; } diff --git a/transport/internet/grpc/hub.go b/transport/internet/grpc/hub.go index e55f6f77c2e6..fb48c5216946 100644 --- a/transport/internet/grpc/hub.go +++ b/transport/internet/grpc/hub.go @@ -3,6 +3,7 @@ package grpc import ( "context" "time" + _ "unsafe" goreality "github.com/xtls/reality" "github.com/xtls/xray-core/common" @@ -17,17 +18,25 @@ import ( "google.golang.org/grpc/keepalive" ) +//go:linkname GetConnection google.golang.org/grpc/internal/transport.GetConnection +func GetConnection(ctx context.Context) net.Conn + type Listener struct { encoding.UnimplementedGRPCServiceServer ctx context.Context handler internet.ConnHandler local net.Addr config *Config + stream *internet.MemoryStreamConfig s *grpc.Server } func (l Listener) Tun(server encoding.GRPCService_TunServer) error { + if l.stream != nil { + conn := GetConnection(server.Context()) + l.stream.ApplyBrutalSettings(conn) + } tunCtx, cancel := context.WithCancel(l.ctx) l.handler(encoding.NewHunkConn(server, cancel)) <-tunCtx.Done() @@ -35,6 +44,10 @@ func (l Listener) Tun(server encoding.GRPCService_TunServer) error { } func (l Listener) TunMulti(server encoding.GRPCService_TunMultiServer) error { + if l.stream != nil { + conn := GetConnection(server.Context()) + l.stream.ApplyBrutalSettings(conn) + } tunCtx, cancel := context.WithCancel(l.ctx) l.handler(encoding.NewMultiHunkConn(server, cancel)) <-tunCtx.Done() @@ -55,6 +68,7 @@ func Listen(ctx context.Context, address net.Address, port net.Port, settings *i var listener *Listener if port == net.Port(0) { // unix listener = &Listener{ + stream: settings, handler: handler, local: &net.UnixAddr{ Name: address.Domain(), @@ -64,6 +78,7 @@ func Listen(ctx context.Context, address net.Address, port net.Port, settings *i } } else { // tcp listener = &Listener{ + stream: settings, handler: handler, local: &net.TCPAddr{ IP: address.IP(), diff --git a/transport/internet/memory_settings.go b/transport/internet/memory_settings.go index 3c4770d2f373..0e1c34d50bb2 100644 --- a/transport/internet/memory_settings.go +++ b/transport/internet/memory_settings.go @@ -1,5 +1,11 @@ package internet +import ( + "syscall" + sing_common "github.com/sagernet/sing/common" + "github.com/xtls/xray-core/common/net" +) + // MemoryStreamConfig is a parsed form of StreamConfig. This is used to reduce number of Protobuf parsing. type MemoryStreamConfig struct { ProtocolName string @@ -9,6 +15,28 @@ type MemoryStreamConfig struct { SocketSettings *SocketConfig } +func (m *MemoryStreamConfig) ApplyBrutalSettings(conn net.Conn) { + if m.SocketSettings != nil && m.SocketSettings.TcpCongestion == "brutal" { + sc, loaded := sing_common.Cast[syscall.Conn](conn) + if loaded { + if rawConn, e0 := sc.SyscallConn(); e0 != nil { + newError("sc.SyscallConn failed ", e0).AtError().WriteToLog() + } else { + if e1 := rawConn.Control(func(fd uintptr) { + if e2 := ApplyBrutalParams(int(fd), m.SocketSettings); e2 != nil { + newError("internet.ApplyBrutalParams failed ", e2).AtError().WriteToLog() + } + }); e1 != nil { + newError("rawConn.Control failed ", e1).AtError().WriteToLog() + } + } + } else { + newError("cast conn to syscall.Conn failed").AtWarning().WriteToLog() + } + newError("Brutal Rate: ", m.SocketSettings.BrutalRate, ", Gain: ", m.SocketSettings.BrutalGain).WriteToLog() + } +} + // ToMemoryStreamConfig converts a StreamConfig to MemoryStreamConfig. It returns a default non-nil MemoryStreamConfig for nil input. func ToMemoryStreamConfig(s *StreamConfig) (*MemoryStreamConfig, error) { ets, err := s.GetEffectiveTransportSettings() diff --git a/transport/internet/sockopt_linux.go b/transport/internet/sockopt_linux.go index 56f24be8bad8..23ba90b47c92 100644 --- a/transport/internet/sockopt_linux.go +++ b/transport/internet/sockopt_linux.go @@ -3,10 +3,19 @@ package internet import ( "net" "syscall" + "unsafe" "golang.org/x/sys/unix" ) +type TCPBrutalParams struct { + Rate uint64 + Gain uint32 +} + +//go:linkname setsockopt syscall.setsockopt +func setsockopt(s, level, name int, val unsafe.Pointer, vallen uintptr) (err error) + func bindAddr(fd uintptr, ip []byte, port uint32) error { setReuseAddr(fd) setReusePort(fd) @@ -200,6 +209,18 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) return nil } +func ApplyBrutalParams(fd int, config *SocketConfig) error { + var params TCPBrutalParams + + params.Rate = config.BrutalRate + params.Gain = config.BrutalGain + + if err := setsockopt(fd, unix.IPPROTO_TCP, 23301, unsafe.Pointer(¶ms), unsafe.Sizeof(params)); err != nil { + return err + } + return nil +} + func setReuseAddr(fd uintptr) error { if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil { return newError("failed to set SO_REUSEADDR").Base(err).AtWarning() diff --git a/transport/internet/tcp/hub.go b/transport/internet/tcp/hub.go index d4b4f8b5ef04..3ebb0ea7d46e 100644 --- a/transport/internet/tcp/hub.go +++ b/transport/internet/tcp/hub.go @@ -24,12 +24,14 @@ type Listener struct { authConfig internet.ConnectionAuthenticator config *Config addConn internet.ConnHandler + stream *internet.MemoryStreamConfig } // ListenTCP creates a new Listener based on configurations. func ListenTCP(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) { l := &Listener{ addConn: handler, + stream: streamSettings, } tcpSettings := streamSettings.ProtocolSettings.(*Config) l.config = tcpSettings @@ -104,6 +106,11 @@ func (v *Listener) keepAccepting() { } continue } + + if v.stream != nil { + v.stream.ApplyBrutalSettings(conn) + } + go func() { if v.tlsConfig != nil { conn = tls.Server(conn, v.tlsConfig)