Files
sing-tun/stack_gvisor.go

198 lines
5.9 KiB
Go
Raw Normal View History

2022-09-15 11:19:31 +08:00
//go:build with_gvisor
2022-08-04 18:23:58 +08:00
2022-07-11 17:15:22 +08:00
package tun
import (
"context"
"net/netip"
"runtime"
2022-07-25 23:34:12 +08:00
"time"
2022-07-11 17:15:22 +08:00
"github.com/sagernet/gvisor/pkg/tcpip"
"github.com/sagernet/gvisor/pkg/tcpip/adapters/gonet"
"github.com/sagernet/gvisor/pkg/tcpip/header"
"github.com/sagernet/gvisor/pkg/tcpip/network/ipv4"
"github.com/sagernet/gvisor/pkg/tcpip/network/ipv6"
"github.com/sagernet/gvisor/pkg/tcpip/stack"
"github.com/sagernet/gvisor/pkg/tcpip/transport/icmp"
2025-08-24 10:36:16 +08:00
"github.com/sagernet/gvisor/pkg/tcpip/transport/raw"
"github.com/sagernet/gvisor/pkg/tcpip/transport/tcp"
"github.com/sagernet/gvisor/pkg/tcpip/transport/udp"
2022-07-13 18:59:09 +08:00
E "github.com/sagernet/sing/common/exceptions"
2023-03-21 15:31:43 +08:00
"github.com/sagernet/sing/common/logger"
2022-07-11 17:15:22 +08:00
)
2022-09-15 11:19:31 +08:00
const WithGVisor = true
2024-11-21 18:12:21 +08:00
const DefaultNIC tcpip.NICID = 1
2022-07-11 17:15:22 +08:00
2022-08-07 15:40:46 +08:00
type GVisor struct {
2025-06-09 18:51:17 +08:00
ctx context.Context
tun GVisorTun
2025-08-23 16:37:46 +08:00
inet4Address netip.Addr
inet6Address netip.Addr
2025-06-09 18:51:17 +08:00
inet4LoopbackAddress []netip.Addr
inet6LoopbackAddress []netip.Addr
udpTimeout time.Duration
broadcastAddr netip.Addr
handler Handler
logger logger.Logger
stack *stack.Stack
endpoint stack.LinkEndpoint
2022-08-07 17:15:29 +08:00
}
type GVisorTun interface {
Tun
2025-07-17 17:33:41 +08:00
WritePacket(pkt *stack.PacketBuffer) (int, error)
2025-07-02 19:16:14 +08:00
NewEndpoint() (stack.LinkEndpoint, stack.NICOptions, error)
2022-07-11 17:15:22 +08:00
}
2022-07-26 19:15:04 +08:00
func NewGVisor(
2022-09-06 19:24:47 +08:00
options StackOptions,
2022-08-07 15:40:46 +08:00
) (Stack, error) {
2022-09-06 19:24:47 +08:00
gTun, isGTun := options.Tun.(GVisorTun)
2022-08-07 15:40:46 +08:00
if !isGTun {
2022-09-15 11:19:31 +08:00
return nil, E.New("gVisor stack is unsupported on current platform")
2022-08-07 15:40:46 +08:00
}
2025-08-23 16:37:46 +08:00
var (
inet4Address netip.Addr
inet6Address netip.Addr
)
if len(options.TunOptions.Inet4Address) > 0 {
inet4Address = options.TunOptions.Inet4Address[0].Addr()
}
if len(options.TunOptions.Inet6Address) > 0 {
inet6Address = options.TunOptions.Inet6Address[0].Addr()
}
2023-04-18 21:21:59 +08:00
gStack := &GVisor{
2025-06-09 18:51:17 +08:00
ctx: options.Context,
tun: gTun,
2025-08-23 16:37:46 +08:00
inet4Address: inet4Address,
inet6Address: inet6Address,
2025-06-09 18:51:17 +08:00
inet4LoopbackAddress: options.TunOptions.Inet4LoopbackAddress,
inet6LoopbackAddress: options.TunOptions.Inet6LoopbackAddress,
udpTimeout: options.UDPTimeout,
broadcastAddr: BroadcastAddr(options.TunOptions.Inet4Address),
handler: options.Handler,
logger: options.Logger,
2023-04-18 21:21:59 +08:00
}
return gStack, nil
2022-07-11 17:15:22 +08:00
}
2022-08-07 15:40:46 +08:00
func (t *GVisor) Start() error {
2025-07-02 19:16:14 +08:00
linkEndpoint, nicOptions, err := t.tun.NewEndpoint()
2022-07-11 17:15:22 +08:00
if err != nil {
return err
}
2023-12-10 00:00:14 +08:00
linkEndpoint = &LinkEndpointFilter{linkEndpoint, t.broadcastAddr, t.tun}
2025-08-24 10:36:16 +08:00
ipStack, err := NewGVisorStackWithOptions(linkEndpoint, nicOptions, false)
if err != nil {
return err
2022-07-11 17:15:22 +08:00
}
2025-06-09 18:51:17 +08:00
ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, NewTCPForwarderWithLoopback(t.ctx, ipStack, t.handler, t.inet4LoopbackAddress, t.inet6LoopbackAddress, t.tun).HandlePacket)
2024-11-27 18:04:39 +08:00
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, NewUDPForwarder(t.ctx, ipStack, t.handler, t.udpTimeout).HandlePacket)
2025-08-24 10:36:16 +08:00
icmpForwarder := NewICMPForwarder(t.ctx, ipStack, t.handler, t.udpTimeout)
icmpForwarder.SetLocalAddresses(t.inet4Address, t.inet6Address)
2025-02-17 21:56:18 +08:00
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber4, icmpForwarder.HandlePacket)
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber6, icmpForwarder.HandlePacket)
2022-07-11 17:15:22 +08:00
t.stack = ipStack
2022-07-31 19:55:51 +08:00
t.endpoint = linkEndpoint
2022-07-11 17:15:22 +08:00
return nil
}
2022-08-07 15:40:46 +08:00
func (t *GVisor) Close() error {
2024-11-12 10:30:18 +08:00
if t.stack == nil {
return nil
}
2022-07-31 19:55:51 +08:00
t.endpoint.Attach(nil)
2022-07-30 14:12:11 +08:00
t.stack.Close()
for _, endpoint := range t.stack.CleanupEndpoints() {
endpoint.Abort()
}
return nil
2022-07-11 17:15:22 +08:00
}
func AddressFromAddr(destination netip.Addr) tcpip.Address {
if destination.Is6() {
return tcpip.AddrFrom16(destination.As16())
} else {
return tcpip.AddrFrom4(destination.As4())
}
}
func AddrFromAddress(address tcpip.Address) netip.Addr {
if address.Len() == 16 {
return netip.AddrFrom16(address.As16())
} else {
return netip.AddrFrom4(address.As4())
}
}
2024-11-21 18:12:21 +08:00
func NewGVisorStack(ep stack.LinkEndpoint) (*stack.Stack, error) {
2025-08-24 10:36:16 +08:00
return NewGVisorStackWithOptions(ep, stack.NICOptions{}, false)
2025-07-02 19:16:14 +08:00
}
2025-08-24 10:36:16 +08:00
func NewGVisorStackWithOptions(ep stack.LinkEndpoint, opts stack.NICOptions, allowRawEndpoint bool) (*stack.Stack, error) {
stackOptions := stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{
ipv4.NewProtocol,
ipv6.NewProtocol,
},
TransportProtocols: []stack.TransportProtocolFactory{
tcp.NewProtocol,
udp.NewProtocol,
icmp.NewProtocol4,
icmp.NewProtocol6,
},
2025-08-24 10:36:16 +08:00
}
if allowRawEndpoint {
stackOptions.RawFactory = new(raw.EndpointFactory)
}
ipStack := stack.New(stackOptions)
2025-07-02 19:16:14 +08:00
err := ipStack.CreateNICWithOptions(DefaultNIC, ep, opts)
if err != nil {
return nil, gonet.TranslateNetstackError(err)
}
ipStack.SetRouteTable([]tcpip.Route{
2024-11-21 18:12:21 +08:00
{Destination: header.IPv4EmptySubnet, NIC: DefaultNIC},
{Destination: header.IPv6EmptySubnet, NIC: DefaultNIC},
})
2024-11-21 18:12:21 +08:00
err = ipStack.SetSpoofing(DefaultNIC, true)
if err != nil {
return nil, gonet.TranslateNetstackError(err)
}
2024-11-21 18:12:21 +08:00
err = ipStack.SetPromiscuousMode(DefaultNIC, true)
if err != nil {
return nil, gonet.TranslateNetstackError(err)
}
sOpt := tcpip.TCPSACKEnabled(true)
ipStack.SetTransportProtocolOption(tcp.ProtocolNumber, &sOpt)
mOpt := tcpip.TCPModerateReceiveBufferOption(true)
ipStack.SetTransportProtocolOption(tcp.ProtocolNumber, &mOpt)
if runtime.GOOS == "windows" {
tcpRecoveryOpt := tcpip.TCPRecovery(0)
err = ipStack.SetTransportProtocolOption(tcp.ProtocolNumber, &tcpRecoveryOpt)
}
tcpRXBufOpt := tcpip.TCPReceiveBufferSizeRangeOption{
Min: tcpRXBufMinSize,
Default: tcpRXBufDefSize,
Max: tcpRXBufMaxSize,
}
err = ipStack.SetTransportProtocolOption(tcp.ProtocolNumber, &tcpRXBufOpt)
if err != nil {
return nil, gonet.TranslateNetstackError(err)
}
tcpTXBufOpt := tcpip.TCPSendBufferSizeRangeOption{
Min: tcpTXBufMinSize,
Default: tcpTXBufDefSize,
Max: tcpTXBufMaxSize,
}
err = ipStack.SetTransportProtocolOption(tcp.ProtocolNumber, &tcpTXBufOpt)
if err != nil {
return nil, gonet.TranslateNetstackError(err)
}
return ipStack, nil
}