Fix ping response for tun address

This commit is contained in:
世界
2025-08-23 16:37:46 +08:00
parent f46791bc0d
commit a256dca36b
3 changed files with 129 additions and 94 deletions

View File

@@ -28,6 +28,8 @@ const DefaultNIC tcpip.NICID = 1
type GVisor struct { type GVisor struct {
ctx context.Context ctx context.Context
tun GVisorTun tun GVisorTun
inet4Address netip.Addr
inet6Address netip.Addr
inet4LoopbackAddress []netip.Addr inet4LoopbackAddress []netip.Addr
inet6LoopbackAddress []netip.Addr inet6LoopbackAddress []netip.Addr
udpTimeout time.Duration udpTimeout time.Duration
@@ -52,9 +54,22 @@ func NewGVisor(
return nil, E.New("gVisor stack is unsupported on current platform") return nil, E.New("gVisor stack is unsupported on current platform")
} }
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()
}
gStack := &GVisor{ gStack := &GVisor{
ctx: options.Context, ctx: options.Context,
tun: gTun, tun: gTun,
inet4Address: inet4Address,
inet6Address: inet6Address,
inet4LoopbackAddress: options.TunOptions.Inet4LoopbackAddress, inet4LoopbackAddress: options.TunOptions.Inet4LoopbackAddress,
inet6LoopbackAddress: options.TunOptions.Inet6LoopbackAddress, inet6LoopbackAddress: options.TunOptions.Inet6LoopbackAddress,
udpTimeout: options.UDPTimeout, udpTimeout: options.UDPTimeout,
@@ -77,7 +92,7 @@ func (t *GVisor) Start() error {
} }
ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, NewTCPForwarderWithLoopback(t.ctx, ipStack, t.handler, t.inet4LoopbackAddress, t.inet6LoopbackAddress, t.tun).HandlePacket) ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, NewTCPForwarderWithLoopback(t.ctx, ipStack, t.handler, t.inet4LoopbackAddress, t.inet6LoopbackAddress, t.tun).HandlePacket)
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, NewUDPForwarder(t.ctx, ipStack, t.handler, t.udpTimeout).HandlePacket) ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, NewUDPForwarder(t.ctx, ipStack, t.handler, t.udpTimeout).HandlePacket)
icmpForwarder := NewICMPForwarder(t.ctx, ipStack, t.handler, t.udpTimeout) icmpForwarder := NewICMPForwarder(t.ctx, ipStack, t.inet4Address, t.inet6Address, t.handler, t.udpTimeout)
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber4, icmpForwarder.HandlePacket) ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber4, icmpForwarder.HandlePacket)
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber6, icmpForwarder.HandlePacket) ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber6, icmpForwarder.HandlePacket)
t.stack = ipStack t.stack = ipStack

View File

@@ -4,6 +4,7 @@ package tun
import ( import (
"context" "context"
"net/netip"
"sync" "sync"
"time" "time"
@@ -21,18 +22,29 @@ import (
) )
type ICMPForwarder struct { type ICMPForwarder struct {
ctx context.Context ctx context.Context
stack *stack.Stack stack *stack.Stack
handler Handler inet4Address netip.Addr
directNat *RouteMapping inet6Address netip.Addr
handler Handler
directNat *RouteMapping
} }
func NewICMPForwarder(ctx context.Context, stack *stack.Stack, handler Handler, timeout time.Duration) *ICMPForwarder { func NewICMPForwarder(
ctx context.Context,
stack *stack.Stack,
inet4Address netip.Addr,
inet6Address netip.Addr,
handler Handler,
timeout time.Duration,
) *ICMPForwarder {
return &ICMPForwarder{ return &ICMPForwarder{
ctx: ctx, ctx: ctx,
stack: stack, stack: stack,
handler: handler, inet4Address: inet4Address,
directNat: NewRouteMapping(timeout), inet6Address: inet6Address,
handler: handler,
directNat: NewRouteMapping(timeout),
} }
} }
@@ -45,26 +57,28 @@ func (f *ICMPForwarder) HandlePacket(id stack.TransportEndpointID, pkt *stack.Pa
} }
sourceAddr := M.AddrFromIP(ipHdr.SourceAddressSlice()) sourceAddr := M.AddrFromIP(ipHdr.SourceAddressSlice())
destinationAddr := M.AddrFromIP(ipHdr.DestinationAddressSlice()) destinationAddr := M.AddrFromIP(ipHdr.DestinationAddressSlice())
action, err := f.directNat.Lookup(DirectRouteSession{Source: sourceAddr, Destination: destinationAddr}, func() (DirectRouteDestination, error) { if destinationAddr != f.inet4Address {
return f.handler.PrepareConnection( action, err := f.directNat.Lookup(DirectRouteSession{Source: sourceAddr, Destination: destinationAddr}, func() (DirectRouteDestination, error) {
N.NetworkICMPv4, return f.handler.PrepareConnection(
M.SocksaddrFrom(sourceAddr, 0), N.NetworkICMPv4,
M.SocksaddrFrom(destinationAddr, 0), M.SocksaddrFrom(sourceAddr, 0),
&ICMPBackWriter{ M.SocksaddrFrom(destinationAddr, 0),
stack: f.stack, &ICMPBackWriter{
packet: pkt, stack: f.stack,
source: ipHdr.SourceAddress(), packet: pkt,
sourceNetwork: header.IPv4ProtocolNumber, source: ipHdr.SourceAddress(),
}, sourceNetwork: header.IPv4ProtocolNumber,
) },
}) )
if err != nil { })
return true if err != nil {
} return true
if action != nil { }
// TODO: handle error if action != nil {
_ = icmpWritePacketBuffer(action, pkt) // TODO: handle error
return true _ = icmpWritePacketBuffer(action, pkt)
return true
}
} }
icmpHdr.SetType(header.ICMPv4EchoReply) icmpHdr.SetType(header.ICMPv4EchoReply)
sourceAddress := ipHdr.SourceAddress() sourceAddress := ipHdr.SourceAddress()
@@ -101,27 +115,29 @@ func (f *ICMPForwarder) HandlePacket(id stack.TransportEndpointID, pkt *stack.Pa
} }
sourceAddr := M.AddrFromIP(ipHdr.SourceAddressSlice()) sourceAddr := M.AddrFromIP(ipHdr.SourceAddressSlice())
destinationAddr := M.AddrFromIP(ipHdr.DestinationAddressSlice()) destinationAddr := M.AddrFromIP(ipHdr.DestinationAddressSlice())
action, err := f.directNat.Lookup(DirectRouteSession{Source: sourceAddr, Destination: destinationAddr}, func() (DirectRouteDestination, error) { if destinationAddr != f.inet6Address {
return f.handler.PrepareConnection( action, err := f.directNat.Lookup(DirectRouteSession{Source: sourceAddr, Destination: destinationAddr}, func() (DirectRouteDestination, error) {
N.NetworkICMPv6, return f.handler.PrepareConnection(
M.SocksaddrFrom(sourceAddr, 0), N.NetworkICMPv6,
M.SocksaddrFrom(destinationAddr, 0), M.SocksaddrFrom(sourceAddr, 0),
&ICMPBackWriter{ M.SocksaddrFrom(destinationAddr, 0),
stack: f.stack, &ICMPBackWriter{
packet: pkt, stack: f.stack,
source: ipHdr.SourceAddress(), packet: pkt,
sourceNetwork: header.IPv6ProtocolNumber, source: ipHdr.SourceAddress(),
}, sourceNetwork: header.IPv6ProtocolNumber,
) },
}) )
if err != nil { })
return true if err != nil {
} return true
if action != nil { }
// TODO: handle error if action != nil {
pkt.IncRef() // TODO: handle error
_ = icmpWritePacketBuffer(action, pkt) pkt.IncRef()
return true _ = icmpWritePacketBuffer(action, pkt)
return true
}
} }
icmpHdr.SetType(header.ICMPv6EchoReply) icmpHdr.SetType(header.ICMPv6EchoReply)
sourceAddress := ipHdr.SourceAddress() sourceAddress := ipHdr.SourceAddress()

View File

@@ -31,10 +31,10 @@ type System struct {
logger logger.Logger logger logger.Logger
inet4Prefixes []netip.Prefix inet4Prefixes []netip.Prefix
inet6Prefixes []netip.Prefix inet6Prefixes []netip.Prefix
inet4ServerAddress netip.Addr
inet4Address netip.Addr inet4Address netip.Addr
inet6ServerAddress netip.Addr inet4NextAddress netip.Addr
inet6Address netip.Addr inet6Address netip.Addr
inet6NextAddress netip.Addr
broadcastAddr netip.Addr broadcastAddr netip.Addr
inet4LoopbackAddress []netip.Addr inet4LoopbackAddress []netip.Addr
inet6LoopbackAddress []netip.Addr inet6LoopbackAddress []netip.Addr
@@ -82,17 +82,17 @@ func NewSystem(options StackOptions) (Stack, error) {
if !HasNextAddress(options.TunOptions.Inet4Address[0], 1) { if !HasNextAddress(options.TunOptions.Inet4Address[0], 1) {
return nil, E.New("need one more IPv4 address in first prefix for system stack") return nil, E.New("need one more IPv4 address in first prefix for system stack")
} }
stack.inet4ServerAddress = options.TunOptions.Inet4Address[0].Addr() stack.inet4Address = options.TunOptions.Inet4Address[0].Addr()
stack.inet4Address = stack.inet4ServerAddress.Next() stack.inet4NextAddress = stack.inet4Address.Next()
} }
if len(options.TunOptions.Inet6Address) > 0 { if len(options.TunOptions.Inet6Address) > 0 {
if !HasNextAddress(options.TunOptions.Inet6Address[0], 1) { if !HasNextAddress(options.TunOptions.Inet6Address[0], 1) {
return nil, E.New("need one more IPv6 address in first prefix for system stack") return nil, E.New("need one more IPv6 address in first prefix for system stack")
} }
stack.inet6ServerAddress = options.TunOptions.Inet6Address[0].Addr() stack.inet6Address = options.TunOptions.Inet6Address[0].Addr()
stack.inet6Address = stack.inet6ServerAddress.Next() stack.inet6NextAddress = stack.inet6Address.Next()
} }
if !stack.inet4Address.IsValid() && !stack.inet6Address.IsValid() { if !stack.inet4NextAddress.IsValid() && !stack.inet6NextAddress.IsValid() {
return nil, E.New("missing interface address") return nil, E.New("missing interface address")
} }
return stack, nil return stack, nil
@@ -128,9 +128,9 @@ func (s *System) start() error {
} }
var tcpListener net.Listener var tcpListener net.Listener
var err error var err error
if s.inet4Address.IsValid() { if s.inet4NextAddress.IsValid() {
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
tcpListener, err = listener.Listen(s.ctx, "tcp4", net.JoinHostPort(s.inet4ServerAddress.String(), "0")) tcpListener, err = listener.Listen(s.ctx, "tcp4", net.JoinHostPort(s.inet4Address.String(), "0"))
if !retryableListenError(err) { if !retryableListenError(err) {
break break
} }
@@ -143,9 +143,9 @@ func (s *System) start() error {
s.tcpPort = M.SocksaddrFromNet(tcpListener.Addr()).Port s.tcpPort = M.SocksaddrFromNet(tcpListener.Addr()).Port
go s.acceptLoop(tcpListener) go s.acceptLoop(tcpListener)
} }
if s.inet6Address.IsValid() { if s.inet6NextAddress.IsValid() {
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
tcpListener, err = listener.Listen(s.ctx, "tcp6", net.JoinHostPort(s.inet6ServerAddress.String(), "0")) tcpListener, err = listener.Listen(s.ctx, "tcp6", net.JoinHostPort(s.inet6Address.String(), "0"))
if !retryableListenError(err) { if !retryableListenError(err) {
break break
} }
@@ -395,7 +395,7 @@ func (s *System) processIPv4TCP(ipHdr header.IPv4, tcpHdr header.TCP) (bool, err
destination := netip.AddrPortFrom(ipHdr.DestinationAddr(), tcpHdr.DestinationPort()) destination := netip.AddrPortFrom(ipHdr.DestinationAddr(), tcpHdr.DestinationPort())
if !destination.Addr().IsGlobalUnicast() { if !destination.Addr().IsGlobalUnicast() {
return false, nil return false, nil
} else if source.Addr() == s.inet4ServerAddress && source.Port() == s.tcpPort { } else if source.Addr() == s.inet4Address && source.Port() == s.tcpPort {
session := s.tcpNat.LookupBack(destination.Port()) session := s.tcpNat.LookupBack(destination.Port())
if session == nil { if session == nil {
return false, E.New("ipv4: tcp: session not found: ", destination.Port()) return false, E.New("ipv4: tcp: session not found: ", destination.Port())
@@ -423,9 +423,9 @@ func (s *System) processIPv4TCP(ipHdr header.IPv4, tcpHdr header.TCP) (bool, err
return false, s.resetIPv4TCP(ipHdr, tcpHdr) return false, s.resetIPv4TCP(ipHdr, tcpHdr)
} }
} }
ipHdr.SetSourceAddr(s.inet4Address) ipHdr.SetSourceAddr(s.inet4NextAddress)
tcpHdr.SetSourcePort(natPort) tcpHdr.SetSourcePort(natPort)
ipHdr.SetDestinationAddr(s.inet4ServerAddress) ipHdr.SetDestinationAddr(s.inet4Address)
tcpHdr.SetDestinationPort(s.tcpPort) tcpHdr.SetDestinationPort(s.tcpPort)
} }
} }
@@ -493,7 +493,7 @@ func (s *System) processIPv6TCP(ipHdr header.IPv6, tcpHdr header.TCP) (bool, err
destination := netip.AddrPortFrom(ipHdr.DestinationAddr(), tcpHdr.DestinationPort()) destination := netip.AddrPortFrom(ipHdr.DestinationAddr(), tcpHdr.DestinationPort())
if !destination.Addr().IsGlobalUnicast() { if !destination.Addr().IsGlobalUnicast() {
return false, nil return false, nil
} else if source.Addr() == s.inet6ServerAddress && source.Port() == s.tcpPort6 { } else if source.Addr() == s.inet6Address && source.Port() == s.tcpPort6 {
session := s.tcpNat.LookupBack(destination.Port()) session := s.tcpNat.LookupBack(destination.Port())
if session == nil { if session == nil {
return false, E.New("ipv6: tcp: session not found: ", destination.Port()) return false, E.New("ipv6: tcp: session not found: ", destination.Port())
@@ -521,9 +521,9 @@ func (s *System) processIPv6TCP(ipHdr header.IPv6, tcpHdr header.TCP) (bool, err
return false, s.resetIPv6TCP(ipHdr, tcpHdr) return false, s.resetIPv6TCP(ipHdr, tcpHdr)
} }
} }
ipHdr.SetSourceAddr(s.inet6Address) ipHdr.SetSourceAddr(s.inet6NextAddress)
tcpHdr.SetSourcePort(natPort) tcpHdr.SetSourcePort(natPort)
ipHdr.SetDestinationAddr(s.inet6ServerAddress) ipHdr.SetDestinationAddr(s.inet6Address)
tcpHdr.SetDestinationPort(s.tcpPort6) tcpHdr.SetDestinationPort(s.tcpPort6)
} }
} }
@@ -657,19 +657,21 @@ func (s *System) processIPv4ICMP(ipHdr header.IPv4, icmpHdr header.ICMPv4) (bool
} }
sourceAddr := ipHdr.SourceAddr() sourceAddr := ipHdr.SourceAddr()
destinationAddr := ipHdr.DestinationAddr() destinationAddr := ipHdr.DestinationAddr()
action, err := s.directNat.Lookup(DirectRouteSession{Source: sourceAddr, Destination: destinationAddr}, func() (DirectRouteDestination, error) { if destinationAddr != s.inet4Address {
return s.handler.PrepareConnection( action, err := s.directNat.Lookup(DirectRouteSession{Source: sourceAddr, Destination: destinationAddr}, func() (DirectRouteDestination, error) {
N.NetworkICMPv4, return s.handler.PrepareConnection(
M.SocksaddrFrom(sourceAddr, 0), N.NetworkICMPv4,
M.SocksaddrFrom(destinationAddr, 0), M.SocksaddrFrom(sourceAddr, 0),
&systemICMPDirectPacketWriter4{s.tun, s.frontHeadroom + PacketOffset, sourceAddr}, M.SocksaddrFrom(destinationAddr, 0),
) &systemICMPDirectPacketWriter4{s.tun, s.frontHeadroom + PacketOffset, sourceAddr},
}) )
if err != nil { })
return false, nil if err != nil {
} return false, nil
if action != nil { }
return false, action.WritePacket(buf.As(ipHdr).ToOwned()) if action != nil {
return false, action.WritePacket(buf.As(ipHdr).ToOwned())
}
} }
icmpHdr.SetType(header.ICMPv4EchoReply) icmpHdr.SetType(header.ICMPv4EchoReply)
sourceAddress := ipHdr.SourceAddr() sourceAddress := ipHdr.SourceAddr()
@@ -726,19 +728,21 @@ func (s *System) processIPv6ICMP(ipHdr header.IPv6, icmpHdr header.ICMPv6) (bool
} }
sourceAddr := ipHdr.SourceAddr() sourceAddr := ipHdr.SourceAddr()
destinationAddr := ipHdr.DestinationAddr() destinationAddr := ipHdr.DestinationAddr()
action, err := s.directNat.Lookup(DirectRouteSession{Source: sourceAddr, Destination: destinationAddr}, func() (DirectRouteDestination, error) { if destinationAddr != s.inet6Address {
return s.handler.PrepareConnection( action, err := s.directNat.Lookup(DirectRouteSession{Source: sourceAddr, Destination: destinationAddr}, func() (DirectRouteDestination, error) {
N.NetworkICMPv6, return s.handler.PrepareConnection(
M.SocksaddrFrom(sourceAddr, 0), N.NetworkICMPv6,
M.SocksaddrFrom(destinationAddr, 0), M.SocksaddrFrom(sourceAddr, 0),
&systemICMPDirectPacketWriter6{s.tun, s.frontHeadroom + PacketOffset, sourceAddr}, M.SocksaddrFrom(destinationAddr, 0),
) &systemICMPDirectPacketWriter6{s.tun, s.frontHeadroom + PacketOffset, sourceAddr},
}) )
if err != nil { })
return false, nil if err != nil {
} return false, nil
if action != nil { }
return false, action.WritePacket(buf.As(ipHdr).ToOwned()) if action != nil {
return false, action.WritePacket(buf.As(ipHdr).ToOwned())
}
} }
icmpHdr.SetType(header.ICMPv6EchoReply) icmpHdr.SetType(header.ICMPv6EchoReply)
sourceAddress := ipHdr.SourceAddr() sourceAddress := ipHdr.SourceAddr()