Add loopback address support

This commit is contained in:
世界 2025-06-09 18:51:17 +08:00
parent f57754918d
commit 5e343c4b66
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
7 changed files with 524 additions and 183 deletions

View file

@ -5,31 +5,75 @@ package tun
import (
"context"
"errors"
"net/netip"
"github.com/sagernet/gvisor/pkg/tcpip"
"github.com/sagernet/gvisor/pkg/tcpip/header"
"github.com/sagernet/gvisor/pkg/tcpip/stack"
"github.com/sagernet/gvisor/pkg/tcpip/transport/tcp"
"github.com/sagernet/sing-tun/internal/gtcpip/checksum"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)
type TCPForwarder struct {
ctx context.Context
stack *stack.Stack
handler Handler
forwarder *tcp.Forwarder
ctx context.Context
stack *stack.Stack
handler Handler
inet4LoopbackAddress []tcpip.Address
inet6LoopbackAddress []tcpip.Address
tun GVisorTun
forwarder *tcp.Forwarder
}
func NewTCPForwarder(ctx context.Context, stack *stack.Stack, handler Handler) *TCPForwarder {
return NewTCPForwarderWithLoopback(ctx, stack, handler, nil, nil, nil)
}
func NewTCPForwarderWithLoopback(ctx context.Context, stack *stack.Stack, handler Handler, inet4LoopbackAddress []netip.Addr, inet6LoopbackAddress []netip.Addr, tun GVisorTun) *TCPForwarder {
forwarder := &TCPForwarder{
ctx: ctx,
stack: stack,
handler: handler,
ctx: ctx,
stack: stack,
handler: handler,
inet4LoopbackAddress: common.Map(inet4LoopbackAddress, AddressFromAddr),
inet6LoopbackAddress: common.Map(inet6LoopbackAddress, AddressFromAddr),
tun: tun,
}
forwarder.forwarder = tcp.NewForwarder(stack, 0, 1024, forwarder.Forward)
return forwarder
}
func (f *TCPForwarder) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool {
for _, inet4LoopbackAddress := range f.inet4LoopbackAddress {
if id.LocalAddress == inet4LoopbackAddress {
ipHdr := pkt.Network().(header.IPv4)
ipHdr.SetDestinationAddressWithChecksumUpdate(ipHdr.SourceAddress())
ipHdr.SetSourceAddressWithChecksumUpdate(inet4LoopbackAddress)
tcpHdr := header.TCP(pkt.TransportHeader().Slice())
tcpHdr.SetChecksum(0)
tcpHdr.SetChecksum(^checksum.Checksum(tcpHdr.Payload(), tcpHdr.CalculateChecksum(
header.PseudoHeaderChecksum(header.TCPProtocolNumber, ipHdr.SourceAddress(), ipHdr.DestinationAddress(), ipHdr.PayloadLength()),
)))
bufio.WriteVectorised(f.tun, pkt.AsSlices())
return true
}
}
for _, inet6LoopbackAddress := range f.inet6LoopbackAddress {
if id.LocalAddress == inet6LoopbackAddress {
ipHdr := pkt.Network().(header.IPv6)
ipHdr.SetDestinationAddress(ipHdr.SourceAddress())
ipHdr.SetSourceAddress(inet6LoopbackAddress)
tcpHdr := header.TCP(pkt.TransportHeader().Slice())
tcpHdr.SetChecksum(0)
tcpHdr.SetChecksum(^checksum.Checksum(tcpHdr.Payload(), tcpHdr.CalculateChecksum(
header.PseudoHeaderChecksum(header.TCPProtocolNumber, ipHdr.SourceAddress(), ipHdr.DestinationAddress(), ipHdr.PayloadLength()),
)))
bufio.WriteVectorised(f.tun, pkt.AsSlices())
return true
}
}
return f.forwarder.HandlePacket(id, pkt)
}