Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

给 Xray 的 gRPC 添加 TCP Brutal 支持 #3135

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions infra/conf/transport_internet.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
}

Expand Down
81 changes: 51 additions & 30 deletions transport/internet/config.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions transport/internet/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,8 @@ message SocketConfig {
bool tcp_no_delay = 18;

bool tcp_mptcp = 19;

uint64 brutal_rate = 20;

uint32 brutal_gain = 21;
}
15 changes: 15 additions & 0 deletions transport/internet/grpc/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package grpc
import (
"context"
"time"
_ "unsafe"

goreality "github.com/xtls/reality"
"github.com/xtls/xray-core/common"
Expand All @@ -17,24 +18,36 @@ 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()
return nil
}

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()
Expand All @@ -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(),
Expand All @@ -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(),
Expand Down
28 changes: 28 additions & 0 deletions transport/internet/memory_settings.go
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -9,6 +15,28 @@
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 {

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / test (windows-latest)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / test (macos-latest)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / build (windows, amd64)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / build (windows, 386)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / build (freebsd, amd64)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / build (freebsd, 386)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / build (openbsd, amd64)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / build (openbsd, 386)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / build (darwin, amd64)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / build (darwin, arm64)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / build (windows, arm64)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / build (windows, arm, 7)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / build (freebsd, arm64)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / build (freebsd, arm, 7)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / build (openbsd, arm64)

undefined: ApplyBrutalParams

Check failure on line 26 in transport/internet/memory_settings.go

View workflow job for this annotation

GitHub Actions / build (openbsd, arm, 7)

undefined: ApplyBrutalParams
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()
Expand Down
21 changes: 21 additions & 0 deletions transport/internet/sockopt_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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(&params), 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()
Expand Down
7 changes: 7 additions & 0 deletions transport/internet/tcp/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
Loading