1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2026-04-08 14:55:28 -04:00
Files
2026-03-14 16:16:00 +00:00

177 lines
4.7 KiB
Go

package gvisorstack
import (
"context"
"fmt"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
"github.com/v2fly/v2ray-core/v5/common/packetswitch"
)
//go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
type WrappedStack struct {
config *Config
ctx context.Context
stack *stack.Stack
stackTCPListeners []*gonet.TCPListener
}
func NewStack(ctx context.Context, config *Config) (*WrappedStack, error) {
return &WrappedStack{
config: config,
ctx: ctx,
}, nil
}
func (w *WrappedStack) CreateStackFromNetworkLayerDevice(packetSwitchDevice packetswitch.NetworkLayerDevice) error {
// Validate
if w == nil || w.config == nil {
return fmt.Errorf("no config")
}
// Determine MTU from config (0 means unspecified)
mtu := int(w.config.GetMtu())
// Create adaptor that implements stack.LinkEndpoint
adaptor := NewNetworkLayerDeviceToGvisorLinkEndpointAdaptor(w.ctx, mtu, packetSwitchDevice)
// Create stack using adaptor as link endpoint
s, err := w.createStack(adaptor)
if err != nil {
// cleanup adaptor on error
adaptor.Close()
return fmt.Errorf("failed to create gvisor stack: %v", err)
}
// When the adaptor is closed, close the stack as well.
adaptor.SetOnCloseAction(func() {
if s != nil {
s.Close()
}
})
w.stack = s
if err := w.ApplyListeners(); err != nil {
return fmt.Errorf("failed to apply listeners: %v", err)
}
return nil
}
func (w *WrappedStack) createStack(linkedEndpoint stack.LinkEndpoint) (*stack.Stack, error) {
// Machine Generated
if w == nil || w.config == nil {
return nil, fmt.Errorf("no config")
}
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{
ipv4.NewProtocol,
ipv6.NewProtocol,
},
TransportProtocols: []stack.TransportProtocolFactory{
tcp.NewProtocol,
udp.NewProtocol,
icmp.NewProtocol4,
icmp.NewProtocol6,
},
})
nicID := s.NextNICID()
// Create NIC
if err := s.CreateNICWithOptions(nicID, linkedEndpoint, stack.NICOptions{Disabled: false, QDisc: nil}); err != nil {
return nil, fmt.Errorf("failed to create NIC: %v", err)
}
// Add protocol addresses
for _, ip := range w.config.Ips {
tcpIPAddr := tcpip.AddrFromSlice(ip.Ip)
protocolAddress := tcpip.ProtocolAddress{
AddressWithPrefix: tcpip.AddressWithPrefix{
Address: tcpIPAddr,
PrefixLen: int(ip.Prefix),
},
}
switch tcpIPAddr.Len() {
case 4:
protocolAddress.Protocol = ipv4.ProtocolNumber
case 16:
protocolAddress.Protocol = ipv6.ProtocolNumber
default:
return nil, fmt.Errorf("invalid IP address length: %d", tcpIPAddr.Len())
}
if err := s.AddProtocolAddress(nicID, protocolAddress, stack.AddressProperties{}); err != nil {
return nil, fmt.Errorf("failed to add protocol address: %v", err)
}
}
// Set route table
s.SetRouteTable(func() (table []tcpip.Route) {
for _, cidrs := range w.config.Routes {
subnet := tcpip.AddressWithPrefix{
Address: tcpip.AddrFromSlice(cidrs.Ip),
PrefixLen: int(cidrs.Prefix),
}.Subnet()
route := tcpip.Route{
Destination: subnet,
NIC: nicID,
}
table = append(table, route)
}
return
}())
// Promiscuous & spoofing
if err := s.SetPromiscuousMode(nicID, w.config.EnablePromiscuousMode); err != nil {
return nil, fmt.Errorf("failed to set promiscuous mode: %v", err)
}
if err := s.SetSpoofing(nicID, w.config.EnableSpoofing); err != nil {
return nil, fmt.Errorf("failed to set spoofing: %v", err)
}
// Apply socket buffer sizes if provided
if w.config.SocketSettings != nil {
if size := w.config.SocketSettings.TxBufSize; size != 0 {
sendBufferSizeRangeOption := tcpip.TCPSendBufferSizeRangeOption{Min: tcp.MinBufferSize, Default: int(size), Max: tcp.MaxBufferSize}
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, &sendBufferSizeRangeOption); err != nil {
return nil, fmt.Errorf("failed to set tcp send buffer size: %v", err)
}
}
if size := w.config.SocketSettings.RxBufSize; size != 0 {
receiveBufferSizeRangeOption := tcpip.TCPReceiveBufferSizeRangeOption{Min: tcp.MinBufferSize, Default: int(size), Max: tcp.MaxBufferSize}
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, &receiveBufferSizeRangeOption); err != nil {
return nil, fmt.Errorf("failed to set tcp receive buffer size: %v", err)
}
}
}
return s, nil
}
func (w *WrappedStack) Close() error {
if w == nil || w.stack == nil {
return nil
}
for _, l := range w.stackTCPListeners {
l.Close()
}
w.stackTCPListeners = nil
w.stack.Close()
w.stack = nil
return nil
}