diff --git a/core/adapter/handler.go b/core/adapter/handler.go index 9e4962f4..22fc591c 100644 --- a/core/adapter/handler.go +++ b/core/adapter/handler.go @@ -1,14 +1,8 @@ package adapter // TransportHandler is a TCP/UDP connection handler that implements -// HandleTCPConn and HandleUDPConn methods. +// HandleTCP and HandleUDP methods. type TransportHandler interface { HandleTCP(TCPConn) HandleUDP(UDPConn) } - -// TCPHandleFunc handles incoming TCP connection. -type TCPHandleFunc func(TCPConn) - -// UDPHandleFunc handles incoming UDP connection. -type UDPHandleFunc func(UDPConn) diff --git a/core/stack.go b/core/stack.go index 8c7610bf..987e32c6 100644 --- a/core/stack.go +++ b/core/stack.go @@ -13,8 +13,36 @@ import ( "gvisor.dev/gvisor/pkg/tcpip/transport/udp" ) -// CreateStackWithOptions creates *stack.Stack with given options. -func CreateStackWithOptions(linkEP stack.LinkEndpoint, handler adapter.TransportHandler, opts ...option.Option) (*stack.Stack, error) { +// Config is the configuration to create *stack.Stack. +type Config struct { + // LinkEndpoints is the interface implemented by + // data link layer protocols. + LinkEndpoint stack.LinkEndpoint + + // TransportHandler is the handler used by internal + // stack to set transport handlers. + TransportHandler adapter.TransportHandler + + // ErrorFunc is the function that will be called + // when internal stack encounters errors. + ErrorFunc func(tcpip.Error) + + // Options are supplement options to apply settings + // for the internal stack. + Options []option.Option +} + +// CreateStack creates *stack.Stack with given config. +func CreateStack(cfg *Config) (*stack.Stack, error) { + if cfg.ErrorFunc == nil { + cfg.ErrorFunc = func(tcpip.Error) {} + } + + opts := cfg.Options + if len(opts) == 0 { + opts = []option.Option{option.WithDefault()} + } + s := stack.New(stack.Options{ NetworkProtocols: []stack.NetworkProtocolFactory{ ipv4.NewProtocol, @@ -33,7 +61,7 @@ func CreateStackWithOptions(linkEP stack.LinkEndpoint, handler adapter.Transport opts = append(opts, // Create stack NIC and then bind link endpoint to it. - withCreatingNIC(nicID, linkEP), + withCreatingNIC(nicID, cfg.LinkEndpoint), // In the past we did s.AddAddressRange to assign 0.0.0.0/0 // onto the interface. We need that to be able to terminate @@ -63,7 +91,8 @@ func CreateStackWithOptions(linkEP stack.LinkEndpoint, handler adapter.Transport withRouteTable(nicID), // Initiate transport protocol (TCP/UDP) with given handler. - withTCPHandler(handler.HandleTCP), withUDPHandler(handler.HandleUDP), + withTCPHandler(cfg.TransportHandler.HandleTCP, cfg.ErrorFunc), + withUDPHandler(cfg.TransportHandler.HandleUDP, cfg.ErrorFunc), ) for _, opt := range opts { diff --git a/core/tcp.go b/core/tcp.go index c7b2de3f..305d759c 100644 --- a/core/tcp.go +++ b/core/tcp.go @@ -39,11 +39,22 @@ const ( tcpKeepaliveInterval = 30 * time.Second ) -func withTCPHandler(handle adapter.TCPHandleFunc) option.Option { +func withTCPHandler(handle func(adapter.TCPConn), callback func(tcpip.Error)) option.Option { return func(s *stack.Stack) error { tcpForwarder := tcp.NewForwarder(s, defaultWndSize, maxConnAttempts, func(r *tcp.ForwarderRequest) { - var wq waiter.Queue - ep, err := r.CreateEndpoint(&wq) + var ( + wq waiter.Queue + ep tcpip.Endpoint + err tcpip.Error + ) + + defer func() { + if err != nil { + callback(err) + } + }() + + ep, err = r.CreateEndpoint(&wq) if err != nil { // RST: prevent potential half-open TCP connection leak. r.Complete(true) @@ -51,7 +62,8 @@ func withTCPHandler(handle adapter.TCPHandleFunc) option.Option { } defer r.Complete(false) - setKeepalive(ep) + // TCP Keepalive + err = setKeepalive(ep) conn := &tcpConn{ TCPConn: gonet.NewTCPConn(&wq, ep), diff --git a/core/udp.go b/core/udp.go index dd5bb6be..3c2436b8 100644 --- a/core/udp.go +++ b/core/udp.go @@ -4,19 +4,20 @@ import ( "github.com/xjasonlyu/tun2socks/v2/core/adapter" "github.com/xjasonlyu/tun2socks/v2/core/option" + "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet" "gvisor.dev/gvisor/pkg/tcpip/stack" "gvisor.dev/gvisor/pkg/tcpip/transport/udp" "gvisor.dev/gvisor/pkg/waiter" ) -func withUDPHandler(handle adapter.UDPHandleFunc) option.Option { +func withUDPHandler(handle func(adapter.UDPConn), callback func(tcpip.Error)) option.Option { return func(s *stack.Stack) error { udpForwarder := udp.NewForwarder(s, func(r *udp.ForwarderRequest) { var wq waiter.Queue ep, err := r.CreateEndpoint(&wq) if err != nil { - // TODO: handler errors in the future. + callback(err) return } diff --git a/engine/engine.go b/engine/engine.go index 0ee43627..0a5173f2 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -7,13 +7,13 @@ import ( "github.com/xjasonlyu/tun2socks/v2/component/dialer" "github.com/xjasonlyu/tun2socks/v2/core" "github.com/xjasonlyu/tun2socks/v2/core/device" - "github.com/xjasonlyu/tun2socks/v2/core/option" _ "github.com/xjasonlyu/tun2socks/v2/dns" "github.com/xjasonlyu/tun2socks/v2/log" "github.com/xjasonlyu/tun2socks/v2/proxy" "github.com/xjasonlyu/tun2socks/v2/stats" "github.com/xjasonlyu/tun2socks/v2/tunnel" + "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/stack" ) @@ -169,6 +169,12 @@ func (e *engine) applyStack() (err error) { } }() - e.stack, err = core.CreateStackWithOptions(e.device, &fakeTunnel{}, option.WithDefault()) + e.stack, err = core.CreateStack(&core.Config{ + LinkEndpoint: e.device, + TransportHandler: &fakeTunnel{}, + ErrorFunc: func(err tcpip.Error) { + log.Warnf("[STACK] %s", err) + }, + }) return }