mirror of
https://github.com/SagerNet/sing-tun.git
synced 2025-04-05 04:47:41 +03:00
Update gVisor to release-20230605.0-21-g457c1c36d
This commit is contained in:
parent
b02f252916
commit
e881f21013
20 changed files with 71 additions and 550 deletions
6
go.mod
6
go.mod
|
@ -9,9 +9,9 @@ require (
|
||||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97
|
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97
|
||||||
github.com/sagernet/sing v0.2.4
|
github.com/sagernet/sing v0.2.4
|
||||||
github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9
|
github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9
|
||||||
golang.org/x/net v0.9.0
|
golang.org/x/net v0.10.0
|
||||||
golang.org/x/sys v0.7.0
|
golang.org/x/sys v0.8.0
|
||||||
gvisor.dev/gvisor v0.0.0-20230415003630-3981d5d5e523
|
gvisor.dev/gvisor v0.0.0-20230609002524-f143e1baf0bb
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
12
go.sum
12
go.sum
|
@ -15,15 +15,15 @@ github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh
|
||||||
github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s=
|
github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s=
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||||
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
|
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
|
||||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
gvisor.dev/gvisor v0.0.0-20230415003630-3981d5d5e523 h1:zUQYeyyPLnSR6yMvLSOmLH37xDWCZ7BqlpE69fE5K3Q=
|
gvisor.dev/gvisor v0.0.0-20230609002524-f143e1baf0bb h1:A5Zr25mHIiXEZUjN92wAopvMv2XL4jTbl2/+9D4ATgE=
|
||||||
gvisor.dev/gvisor v0.0.0-20230415003630-3981d5d5e523/go.mod h1:pzr6sy8gDLfVmDAg8OYrlKvGEHw5C3PGTiBXBTCx76Q=
|
gvisor.dev/gvisor v0.0.0-20230609002524-f143e1baf0bb/go.mod h1:sQuqOkxbfJq/GS2uSnqHphtXclHyk/ZrAGhZBxxsq6g=
|
||||||
|
|
102
gvisor.go
102
gvisor.go
|
@ -4,8 +4,7 @@ package tun
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net/netip"
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
|
@ -36,12 +35,10 @@ type GVisor struct {
|
||||||
tunMtu uint32
|
tunMtu uint32
|
||||||
endpointIndependentNat bool
|
endpointIndependentNat bool
|
||||||
udpTimeout int64
|
udpTimeout int64
|
||||||
router Router
|
|
||||||
handler Handler
|
handler Handler
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
stack *stack.Stack
|
stack *stack.Stack
|
||||||
endpoint stack.LinkEndpoint
|
endpoint stack.LinkEndpoint
|
||||||
routeMapping *RouteMapping
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type GVisorTun interface {
|
type GVisorTun interface {
|
||||||
|
@ -63,13 +60,9 @@ func NewGVisor(
|
||||||
tunMtu: options.MTU,
|
tunMtu: options.MTU,
|
||||||
endpointIndependentNat: options.EndpointIndependentNat,
|
endpointIndependentNat: options.EndpointIndependentNat,
|
||||||
udpTimeout: options.UDPTimeout,
|
udpTimeout: options.UDPTimeout,
|
||||||
router: options.Router,
|
|
||||||
handler: options.Handler,
|
handler: options.Handler,
|
||||||
logger: options.Logger,
|
logger: options.Logger,
|
||||||
}
|
}
|
||||||
if gStack.router != nil {
|
|
||||||
gStack.routeMapping = NewRouteMapping(options.UDPTimeout)
|
|
||||||
}
|
|
||||||
return gStack, nil
|
return gStack, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,44 +148,7 @@ func (t *GVisor) Start() error {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
})
|
})
|
||||||
ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, func(id stack.TransportEndpointID, buffer stack.PacketBufferPtr) bool {
|
ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, tcpForwarder.HandlePacket)
|
||||||
if t.router != nil {
|
|
||||||
var routeSession RouteSession
|
|
||||||
routeSession.Network = syscall.IPPROTO_TCP
|
|
||||||
var ipHdr header.Network
|
|
||||||
if buffer.NetworkProtocolNumber == header.IPv4ProtocolNumber {
|
|
||||||
routeSession.IPVersion = 4
|
|
||||||
ipHdr = header.IPv4(buffer.NetworkHeader().Slice())
|
|
||||||
} else {
|
|
||||||
routeSession.IPVersion = 6
|
|
||||||
ipHdr = header.IPv6(buffer.NetworkHeader().Slice())
|
|
||||||
}
|
|
||||||
tcpHdr := header.TCP(buffer.TransportHeader().Slice())
|
|
||||||
routeSession.Source = M.AddrPortFrom(net.IP(ipHdr.SourceAddress()), tcpHdr.SourcePort())
|
|
||||||
routeSession.Destination = M.AddrPortFrom(net.IP(ipHdr.DestinationAddress()), tcpHdr.DestinationPort())
|
|
||||||
action := t.routeMapping.Lookup(routeSession, func() RouteAction {
|
|
||||||
if routeSession.IPVersion == 4 {
|
|
||||||
return t.router.RouteConnection(routeSession, &systemTCPDirectPacketWriter4{t.tun, routeSession.Source})
|
|
||||||
} else {
|
|
||||||
return t.router.RouteConnection(routeSession, &systemTCPDirectPacketWriter6{t.tun, routeSession.Source})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
switch actionType := action.(type) {
|
|
||||||
case *ActionBlock:
|
|
||||||
// TODO: send icmp unreachable
|
|
||||||
return true
|
|
||||||
case *ActionDirect:
|
|
||||||
buffer.IncRef()
|
|
||||||
err = actionType.WritePacketBuffer(buffer)
|
|
||||||
if err != nil {
|
|
||||||
t.logger.Trace("route gvisor tcp packet: ", err)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tcpForwarder.HandlePacket(id, buffer)
|
|
||||||
})
|
|
||||||
|
|
||||||
if !t.endpointIndependentNat {
|
if !t.endpointIndependentNat {
|
||||||
udpForwarder := udp.NewForwarder(ipStack, func(request *udp.ForwarderRequest) {
|
udpForwarder := udp.NewForwarder(ipStack, func(request *udp.ForwarderRequest) {
|
||||||
var wq waiter.Queue
|
var wq waiter.Queue
|
||||||
|
@ -218,43 +174,7 @@ func (t *GVisor) Start() error {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
})
|
})
|
||||||
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, func(id stack.TransportEndpointID, buffer stack.PacketBufferPtr) bool {
|
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, udpForwarder.HandlePacket)
|
||||||
if t.router != nil {
|
|
||||||
var routeSession RouteSession
|
|
||||||
routeSession.Network = syscall.IPPROTO_UDP
|
|
||||||
var ipHdr header.Network
|
|
||||||
if buffer.NetworkProtocolNumber == header.IPv4ProtocolNumber {
|
|
||||||
routeSession.IPVersion = 4
|
|
||||||
ipHdr = header.IPv4(buffer.NetworkHeader().Slice())
|
|
||||||
} else {
|
|
||||||
routeSession.IPVersion = 6
|
|
||||||
ipHdr = header.IPv6(buffer.NetworkHeader().Slice())
|
|
||||||
}
|
|
||||||
udpHdr := header.UDP(buffer.TransportHeader().Slice())
|
|
||||||
routeSession.Source = M.AddrPortFrom(net.IP(ipHdr.SourceAddress()), udpHdr.SourcePort())
|
|
||||||
routeSession.Destination = M.AddrPortFrom(net.IP(ipHdr.DestinationAddress()), udpHdr.DestinationPort())
|
|
||||||
action := t.routeMapping.Lookup(routeSession, func() RouteAction {
|
|
||||||
if routeSession.IPVersion == 4 {
|
|
||||||
return t.router.RouteConnection(routeSession, &systemUDPDirectPacketWriter4{t.tun, routeSession.Source})
|
|
||||||
} else {
|
|
||||||
return t.router.RouteConnection(routeSession, &systemUDPDirectPacketWriter6{t.tun, routeSession.Source})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
switch actionType := action.(type) {
|
|
||||||
case *ActionBlock:
|
|
||||||
// TODO: send icmp unreachable
|
|
||||||
return true
|
|
||||||
case *ActionDirect:
|
|
||||||
buffer.IncRef()
|
|
||||||
err = actionType.WritePacketBuffer(buffer)
|
|
||||||
if err != nil {
|
|
||||||
t.logger.Trace("route gvisor udp packet: ", err)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return udpForwarder.HandlePacket(id, buffer)
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -272,3 +192,19 @@ func (t *GVisor) Close() error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ package tun
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
@ -13,7 +12,7 @@ import (
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
"github.com/sagernet/sing/common/udpnat"
|
"github.com/sagernet/sing/common/udpnat"
|
||||||
|
|
||||||
"gvisor.dev/gvisor/pkg/bufferv2"
|
"gvisor.dev/gvisor/pkg/buffer"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
|
@ -36,8 +35,8 @@ func NewUDPForwarder(ctx context.Context, stack *stack.Stack, handler Handler, u
|
||||||
|
|
||||||
func (f *UDPForwarder) HandlePacket(id stack.TransportEndpointID, pkt stack.PacketBufferPtr) bool {
|
func (f *UDPForwarder) HandlePacket(id stack.TransportEndpointID, pkt stack.PacketBufferPtr) bool {
|
||||||
var upstreamMetadata M.Metadata
|
var upstreamMetadata M.Metadata
|
||||||
upstreamMetadata.Source = M.SocksaddrFrom(M.AddrFromIP(net.IP(id.RemoteAddress)), id.RemotePort)
|
upstreamMetadata.Source = M.SocksaddrFrom(AddrFromAddress(id.RemoteAddress), id.RemotePort)
|
||||||
upstreamMetadata.Destination = M.SocksaddrFrom(M.AddrFromIP(net.IP(id.LocalAddress)), id.LocalPort)
|
upstreamMetadata.Destination = M.SocksaddrFrom(AddrFromAddress(id.LocalAddress), id.LocalPort)
|
||||||
var netProto tcpip.NetworkProtocolNumber
|
var netProto tcpip.NetworkProtocolNumber
|
||||||
if upstreamMetadata.Source.IsIPv4() {
|
if upstreamMetadata.Source.IsIPv4() {
|
||||||
netProto = header.IPv4ProtocolNumber
|
netProto = header.IPv4ProtocolNumber
|
||||||
|
@ -63,12 +62,12 @@ type UDPBackWriter struct {
|
||||||
sourceNetwork tcpip.NetworkProtocolNumber
|
sourceNetwork tcpip.NetworkProtocolNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *UDPBackWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
func (w *UDPBackWriter) WritePacket(packetBuffer *buf.Buffer, destination M.Socksaddr) error {
|
||||||
defer buffer.Release()
|
defer packetBuffer.Release()
|
||||||
|
|
||||||
route, err := w.stack.FindRoute(
|
route, err := w.stack.FindRoute(
|
||||||
defaultNIC,
|
defaultNIC,
|
||||||
tcpip.Address(destination.Addr.AsSlice()),
|
AddressFromAddr(destination.Addr),
|
||||||
w.source,
|
w.source,
|
||||||
w.sourceNetwork,
|
w.sourceNetwork,
|
||||||
false,
|
false,
|
||||||
|
@ -80,7 +79,7 @@ func (w *UDPBackWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr)
|
||||||
|
|
||||||
packet := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
packet := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||||
ReserveHeaderBytes: header.UDPMinimumSize + int(route.MaxHeaderLength()),
|
ReserveHeaderBytes: header.UDPMinimumSize + int(route.MaxHeaderLength()),
|
||||||
Payload: bufferv2.MakeWithData(buffer.Bytes()),
|
Payload: buffer.MakeWithData(packetBuffer.Bytes()),
|
||||||
})
|
})
|
||||||
defer packet.DecRef()
|
defer packet.DecRef()
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
# fdbased
|
# fdbased
|
||||||
|
|
||||||
Version: release-20230417.0
|
Version: release-20230605.0-21-g457c1c36d
|
|
@ -45,7 +45,7 @@ import (
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"gvisor.dev/gvisor/pkg/atomicbitops"
|
"gvisor.dev/gvisor/pkg/atomicbitops"
|
||||||
"gvisor.dev/gvisor/pkg/bufferv2"
|
"gvisor.dev/gvisor/pkg/buffer"
|
||||||
"gvisor.dev/gvisor/pkg/sync"
|
"gvisor.dev/gvisor/pkg/sync"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
|
@ -545,7 +545,7 @@ func (e *endpoint) writePacket(pkt stack.PacketBufferPtr) tcpip.Error {
|
||||||
vnetHdr.csumStart = header.EthernetMinimumSize + pkt.GSOOptions.L3HdrLen
|
vnetHdr.csumStart = header.EthernetMinimumSize + pkt.GSOOptions.L3HdrLen
|
||||||
vnetHdr.csumOffset = pkt.GSOOptions.CsumOffset
|
vnetHdr.csumOffset = pkt.GSOOptions.CsumOffset
|
||||||
}
|
}
|
||||||
if pkt.GSOOptions.Type != stack.GSONone && uint16(pkt.Data().Size()) > pkt.GSOOptions.MSS {
|
if uint16(pkt.Data().Size()) > pkt.GSOOptions.MSS {
|
||||||
switch pkt.GSOOptions.Type {
|
switch pkt.GSOOptions.Type {
|
||||||
case stack.GSOTCPv4:
|
case stack.GSOTCPv4:
|
||||||
vnetHdr.gsoType = _VIRTIO_NET_HDR_GSO_TCPV4
|
vnetHdr.gsoType = _VIRTIO_NET_HDR_GSO_TCPV4
|
||||||
|
@ -732,7 +732,7 @@ func (e *endpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InjectOutbound implements stack.InjectableEndpoint.InjectOutbound.
|
// InjectOutbound implements stack.InjectableEndpoint.InjectOutbound.
|
||||||
func (e *endpoint) InjectOutbound(dest tcpip.Address, packet *bufferv2.View) tcpip.Error {
|
func (e *endpoint) InjectOutbound(dest tcpip.Address, packet *buffer.View) tcpip.Error {
|
||||||
return rawfile.NonBlockingWrite(e.fds[0].fd, packet.AsSlice())
|
return rawfile.NonBlockingWrite(e.fds[0].fd, packet.AsSlice())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,7 +756,7 @@ func (e *endpoint) GSOMaxSize() uint32 {
|
||||||
return e.gsoMaxSize
|
return e.gsoMaxSize
|
||||||
}
|
}
|
||||||
|
|
||||||
// SupportsHWGSO implements stack.GSOEndpoint.
|
// SupportedGSO implements stack.GSOEndpoint.
|
||||||
func (e *endpoint) SupportedGSO() stack.SupportedGSO {
|
func (e *endpoint) SupportedGSO() stack.SupportedGSO {
|
||||||
return e.gsoKind
|
return e.gsoKind
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ import (
|
||||||
"github.com/sagernet/sing-tun/internal/fdbased/stopfd"
|
"github.com/sagernet/sing-tun/internal/fdbased/stopfd"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"gvisor.dev/gvisor/pkg/bufferv2"
|
"gvisor.dev/gvisor/pkg/buffer"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/link/rawfile"
|
"gvisor.dev/gvisor/pkg/tcpip/link/rawfile"
|
||||||
|
@ -135,7 +135,7 @@ type packetMMapDispatcher struct {
|
||||||
|
|
||||||
func (*packetMMapDispatcher) release() {}
|
func (*packetMMapDispatcher) release() {}
|
||||||
|
|
||||||
func (d *packetMMapDispatcher) readMMappedPacket() (*bufferv2.View, bool, tcpip.Error) {
|
func (d *packetMMapDispatcher) readMMappedPacket() (*buffer.View, bool, tcpip.Error) {
|
||||||
hdr := tPacketHdr(d.ringBuffer[d.ringOffset*tpFrameSize:])
|
hdr := tPacketHdr(d.ringBuffer[d.ringOffset*tpFrameSize:])
|
||||||
for hdr.tpStatus()&tpStatusUser == 0 {
|
for hdr.tpStatus()&tpStatusUser == 0 {
|
||||||
stopped, errno := rawfile.BlockingPollUntilStopped(d.EFD, d.fd, unix.POLLIN|unix.POLLERR)
|
stopped, errno := rawfile.BlockingPollUntilStopped(d.EFD, d.fd, unix.POLLIN|unix.POLLERR)
|
||||||
|
@ -159,7 +159,7 @@ func (d *packetMMapDispatcher) readMMappedPacket() (*bufferv2.View, bool, tcpip.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy out the packet from the mmapped frame to a locally owned buffer.
|
// Copy out the packet from the mmapped frame to a locally owned buffer.
|
||||||
pkt := bufferv2.NewView(int(hdr.tpSnapLen()))
|
pkt := buffer.NewView(int(hdr.tpSnapLen()))
|
||||||
pkt.Write(hdr.Payload())
|
pkt.Write(hdr.Payload())
|
||||||
// Release packet to kernel.
|
// Release packet to kernel.
|
||||||
hdr.setTPStatus(tpStatusKernel)
|
hdr.setTPStatus(tpStatusKernel)
|
||||||
|
@ -191,7 +191,7 @@ func (d *packetMMapDispatcher) dispatch() (bool, tcpip.Error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pbuf := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
pbuf := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||||
Payload: bufferv2.MakeWithView(pkt),
|
Payload: buffer.MakeWithView(pkt),
|
||||||
})
|
})
|
||||||
defer pbuf.DecRef()
|
defer pbuf.DecRef()
|
||||||
if d.e.hdrSize > 0 {
|
if d.e.hdrSize > 0 {
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"github.com/sagernet/sing-tun/internal/fdbased/stopfd"
|
"github.com/sagernet/sing-tun/internal/fdbased/stopfd"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"gvisor.dev/gvisor/pkg/bufferv2"
|
"gvisor.dev/gvisor/pkg/buffer"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/link/rawfile"
|
"gvisor.dev/gvisor/pkg/tcpip/link/rawfile"
|
||||||
|
@ -35,7 +35,7 @@ type iovecBuffer struct {
|
||||||
// buffer is the actual buffer that holds the packet contents. Some contents
|
// buffer is the actual buffer that holds the packet contents. Some contents
|
||||||
// are reused across calls to pullBuffer if number of requested bytes is
|
// are reused across calls to pullBuffer if number of requested bytes is
|
||||||
// smaller than the number of bytes allocated in the buffer.
|
// smaller than the number of bytes allocated in the buffer.
|
||||||
views []*bufferv2.View
|
views []*buffer.View
|
||||||
|
|
||||||
// iovecs are initialized with base pointers/len of the corresponding
|
// iovecs are initialized with base pointers/len of the corresponding
|
||||||
// entries in the views defined above, except when GSO is enabled
|
// entries in the views defined above, except when GSO is enabled
|
||||||
|
@ -59,7 +59,7 @@ type iovecBuffer struct {
|
||||||
|
|
||||||
func newIovecBuffer(sizes []int, skipsVnetHdr bool) *iovecBuffer {
|
func newIovecBuffer(sizes []int, skipsVnetHdr bool) *iovecBuffer {
|
||||||
b := &iovecBuffer{
|
b := &iovecBuffer{
|
||||||
views: make([]*bufferv2.View, len(sizes)),
|
views: make([]*buffer.View, len(sizes)),
|
||||||
sizes: sizes,
|
sizes: sizes,
|
||||||
skipsVnetHdr: skipsVnetHdr,
|
skipsVnetHdr: skipsVnetHdr,
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ func (b *iovecBuffer) nextIovecs() []unix.Iovec {
|
||||||
if b.views[i] != nil {
|
if b.views[i] != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v := bufferv2.NewViewSize(b.sizes[i])
|
v := buffer.NewViewSize(b.sizes[i])
|
||||||
b.views[i] = v
|
b.views[i] = v
|
||||||
b.iovecs[i+vnetHdrOff] = unix.Iovec{Base: v.BasePtr()}
|
b.iovecs[i+vnetHdrOff] = unix.Iovec{Base: v.BasePtr()}
|
||||||
b.iovecs[i+vnetHdrOff].SetLen(v.Size())
|
b.iovecs[i+vnetHdrOff].SetLen(v.Size())
|
||||||
|
@ -100,14 +100,14 @@ func (b *iovecBuffer) nextIovecs() []unix.Iovec {
|
||||||
// that holds the storage, and updates pulledIndex to indicate which part
|
// that holds the storage, and updates pulledIndex to indicate which part
|
||||||
// of b.buffer's storage must be reallocated during the next call to
|
// of b.buffer's storage must be reallocated during the next call to
|
||||||
// nextIovecs.
|
// nextIovecs.
|
||||||
func (b *iovecBuffer) pullBuffer(n int) bufferv2.Buffer {
|
func (b *iovecBuffer) pullBuffer(n int) buffer.Buffer {
|
||||||
var views []*bufferv2.View
|
var views []*buffer.View
|
||||||
c := 0
|
c := 0
|
||||||
if b.skipsVnetHdr {
|
if b.skipsVnetHdr {
|
||||||
c += virtioNetHdrSize
|
c += virtioNetHdrSize
|
||||||
if c >= n {
|
if c >= n {
|
||||||
// Nothing in the packet.
|
// Nothing in the packet.
|
||||||
return bufferv2.Buffer{}
|
return buffer.Buffer{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remove the used views from the buffer.
|
// Remove the used views from the buffer.
|
||||||
|
@ -126,7 +126,7 @@ func (b *iovecBuffer) pullBuffer(n int) bufferv2.Buffer {
|
||||||
// Exclude the size of the vnet header.
|
// Exclude the size of the vnet header.
|
||||||
n -= virtioNetHdrSize
|
n -= virtioNetHdrSize
|
||||||
}
|
}
|
||||||
pulled := bufferv2.Buffer{}
|
pulled := buffer.Buffer{}
|
||||||
for _, v := range views {
|
for _, v := range views {
|
||||||
pulled.Append(v)
|
pulled.Append(v)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
// automatically generated by stateify.
|
|
||||||
|
|
||||||
//go:build (linux && amd64) || (linux && arm64)
|
|
||||||
// +build linux,amd64 linux,arm64
|
|
||||||
|
|
||||||
package stopfd
|
|
92
route.go
92
route.go
|
@ -1,92 +0,0 @@
|
||||||
package tun
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/netip"
|
|
||||||
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ActionType = uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
ActionTypeUnknown ActionType = iota
|
|
||||||
ActionTypeReturn
|
|
||||||
ActionTypeBlock
|
|
||||||
ActionTypeDirect
|
|
||||||
)
|
|
||||||
|
|
||||||
func ParseActionType(action string) (ActionType, error) {
|
|
||||||
switch action {
|
|
||||||
case "return":
|
|
||||||
return ActionTypeReturn, nil
|
|
||||||
case "block":
|
|
||||||
return ActionTypeBlock, nil
|
|
||||||
case "direct":
|
|
||||||
return ActionTypeDirect, nil
|
|
||||||
default:
|
|
||||||
return 0, E.New("unknown action: ", action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ActionTypeName(actionType ActionType) (string, error) {
|
|
||||||
switch actionType {
|
|
||||||
case ActionTypeUnknown:
|
|
||||||
return "", nil
|
|
||||||
case ActionTypeReturn:
|
|
||||||
return "return", nil
|
|
||||||
case ActionTypeBlock:
|
|
||||||
return "block", nil
|
|
||||||
case ActionTypeDirect:
|
|
||||||
return "direct", nil
|
|
||||||
default:
|
|
||||||
return "", E.New("unknown action: ", actionType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type RouteSession struct {
|
|
||||||
IPVersion uint8
|
|
||||||
Network uint8
|
|
||||||
Source netip.AddrPort
|
|
||||||
Destination netip.AddrPort
|
|
||||||
}
|
|
||||||
|
|
||||||
type RouteContext interface {
|
|
||||||
WritePacket(packet []byte) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type Router interface {
|
|
||||||
RouteConnection(session RouteSession, context RouteContext) RouteAction
|
|
||||||
}
|
|
||||||
|
|
||||||
type RouteAction interface {
|
|
||||||
ActionType() ActionType
|
|
||||||
Timeout() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type ActionReturn struct{}
|
|
||||||
|
|
||||||
func (r *ActionReturn) ActionType() ActionType {
|
|
||||||
return ActionTypeReturn
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ActionReturn) Timeout() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type ActionBlock struct{}
|
|
||||||
|
|
||||||
func (r *ActionBlock) ActionType() ActionType {
|
|
||||||
return ActionTypeBlock
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ActionBlock) Timeout() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type ActionDirect struct {
|
|
||||||
DirectDestination
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ActionDirect) ActionType() ActionType {
|
|
||||||
return ActionTypeDirect
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
//go:build with_gvisor
|
|
||||||
|
|
||||||
package tun
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/sagernet/sing/common/buf"
|
|
||||||
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DirectDestination interface {
|
|
||||||
WritePacket(buffer *buf.Buffer) error
|
|
||||||
WritePacketBuffer(buffer stack.PacketBufferPtr) error
|
|
||||||
Close() error
|
|
||||||
Timeout() bool
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
package tun
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
"github.com/sagernet/sing/common/cache"
|
|
||||||
)
|
|
||||||
|
|
||||||
type RouteMapping struct {
|
|
||||||
status *cache.LruCache[RouteSession, RouteAction]
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRouteMapping(maxAge int64) *RouteMapping {
|
|
||||||
return &RouteMapping{
|
|
||||||
status: cache.New(
|
|
||||||
cache.WithAge[RouteSession, RouteAction](maxAge),
|
|
||||||
cache.WithUpdateAgeOnGet[RouteSession, RouteAction](),
|
|
||||||
cache.WithEvict[RouteSession, RouteAction](func(key RouteSession, conn RouteAction) {
|
|
||||||
common.Close(conn)
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *RouteMapping) Lookup(session RouteSession, constructor func() RouteAction) RouteAction {
|
|
||||||
action, _ := m.status.LoadOrStore(session, constructor)
|
|
||||||
if action.Timeout() {
|
|
||||||
common.Close(action)
|
|
||||||
action = constructor()
|
|
||||||
m.status.Store(session, action)
|
|
||||||
}
|
|
||||||
return action
|
|
||||||
}
|
|
119
route_nat.go
119
route_nat.go
|
@ -1,119 +0,0 @@
|
||||||
package tun
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/netip"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-tun/internal/clashtcpip"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NatMapping struct {
|
|
||||||
access sync.RWMutex
|
|
||||||
sessions map[RouteSession]RouteContext
|
|
||||||
ipRewrite bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewNatMapping(ipRewrite bool) *NatMapping {
|
|
||||||
return &NatMapping{
|
|
||||||
sessions: make(map[RouteSession]RouteContext),
|
|
||||||
ipRewrite: ipRewrite,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *NatMapping) CreateSession(session RouteSession, context RouteContext) {
|
|
||||||
if m.ipRewrite {
|
|
||||||
session.Source = netip.AddrPort{}
|
|
||||||
}
|
|
||||||
m.access.Lock()
|
|
||||||
m.sessions[session] = context
|
|
||||||
m.access.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *NatMapping) DeleteSession(session RouteSession) {
|
|
||||||
if m.ipRewrite {
|
|
||||||
session.Source = netip.AddrPort{}
|
|
||||||
}
|
|
||||||
m.access.Lock()
|
|
||||||
delete(m.sessions, session)
|
|
||||||
m.access.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *NatMapping) WritePacket(packet []byte) (bool, error) {
|
|
||||||
var routeSession RouteSession
|
|
||||||
var ipHdr clashtcpip.IP
|
|
||||||
switch ipVersion := packet[0] >> 4; ipVersion {
|
|
||||||
case 4:
|
|
||||||
routeSession.IPVersion = 4
|
|
||||||
ipHdr = clashtcpip.IPv4Packet(packet)
|
|
||||||
case 6:
|
|
||||||
routeSession.IPVersion = 6
|
|
||||||
ipHdr = clashtcpip.IPv6Packet(packet)
|
|
||||||
default:
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
routeSession.Network = ipHdr.Protocol()
|
|
||||||
switch routeSession.Network {
|
|
||||||
case clashtcpip.TCP:
|
|
||||||
tcpHdr := clashtcpip.TCPPacket(ipHdr.Payload())
|
|
||||||
routeSession.Destination = netip.AddrPortFrom(ipHdr.SourceIP(), tcpHdr.SourcePort())
|
|
||||||
if !m.ipRewrite {
|
|
||||||
routeSession.Source = netip.AddrPortFrom(ipHdr.DestinationIP(), tcpHdr.DestinationPort())
|
|
||||||
}
|
|
||||||
case clashtcpip.UDP:
|
|
||||||
udpHdr := clashtcpip.UDPPacket(ipHdr.Payload())
|
|
||||||
routeSession.Destination = netip.AddrPortFrom(ipHdr.SourceIP(), udpHdr.SourcePort())
|
|
||||||
if !m.ipRewrite {
|
|
||||||
routeSession.Source = netip.AddrPortFrom(ipHdr.DestinationIP(), udpHdr.DestinationPort())
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
routeSession.Destination = netip.AddrPortFrom(ipHdr.SourceIP(), 0)
|
|
||||||
if !m.ipRewrite {
|
|
||||||
routeSession.Source = netip.AddrPortFrom(ipHdr.DestinationIP(), 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.access.RLock()
|
|
||||||
context, loaded := m.sessions[routeSession]
|
|
||||||
m.access.RUnlock()
|
|
||||||
if !loaded {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return true, context.WritePacket(packet)
|
|
||||||
}
|
|
||||||
|
|
||||||
type NatWriter struct {
|
|
||||||
inet4Address netip.Addr
|
|
||||||
inet6Address netip.Addr
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewNatWriter(inet4Address netip.Addr, inet6Address netip.Addr) *NatWriter {
|
|
||||||
return &NatWriter{
|
|
||||||
inet4Address: inet4Address,
|
|
||||||
inet6Address: inet6Address,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *NatWriter) RewritePacket(packet []byte) {
|
|
||||||
var ipHdr clashtcpip.IP
|
|
||||||
var bindAddr netip.Addr
|
|
||||||
switch ipVersion := packet[0] >> 4; ipVersion {
|
|
||||||
case 4:
|
|
||||||
ipHdr = clashtcpip.IPv4Packet(packet)
|
|
||||||
bindAddr = w.inet4Address
|
|
||||||
case 6:
|
|
||||||
ipHdr = clashtcpip.IPv6Packet(packet)
|
|
||||||
bindAddr = w.inet6Address
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ipHdr.SetSourceIP(bindAddr)
|
|
||||||
switch ipHdr.Protocol() {
|
|
||||||
case clashtcpip.TCP:
|
|
||||||
tcpHdr := clashtcpip.TCPPacket(ipHdr.Payload())
|
|
||||||
tcpHdr.ResetChecksum(ipHdr.PseudoSum())
|
|
||||||
case clashtcpip.UDP:
|
|
||||||
udpHdr := clashtcpip.UDPPacket(ipHdr.Payload())
|
|
||||||
udpHdr.ResetChecksum(ipHdr.PseudoSum())
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
ipHdr.ResetChecksum()
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
//go:build with_gvisor
|
|
||||||
|
|
||||||
package tun
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (w *NatWriter) RewritePacketBuffer(packetBuffer stack.PacketBufferPtr) {
|
|
||||||
var bindAddr tcpip.Address
|
|
||||||
if packetBuffer.NetworkProtocolNumber == header.IPv4ProtocolNumber {
|
|
||||||
bindAddr = tcpip.Address(w.inet4Address.AsSlice())
|
|
||||||
} else {
|
|
||||||
bindAddr = tcpip.Address(w.inet6Address.AsSlice())
|
|
||||||
}
|
|
||||||
var ipHdr header.Network
|
|
||||||
switch packetBuffer.NetworkProtocolNumber {
|
|
||||||
case header.IPv4ProtocolNumber:
|
|
||||||
ipHdr = header.IPv4(packetBuffer.NetworkHeader().Slice())
|
|
||||||
case header.IPv6ProtocolNumber:
|
|
||||||
ipHdr = header.IPv6(packetBuffer.NetworkHeader().Slice())
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
oldAddr := ipHdr.SourceAddress()
|
|
||||||
if checksumHdr, needChecksum := ipHdr.(header.ChecksummableNetwork); needChecksum {
|
|
||||||
checksumHdr.SetSourceAddressWithChecksumUpdate(bindAddr)
|
|
||||||
} else {
|
|
||||||
ipHdr.SetSourceAddress(bindAddr)
|
|
||||||
}
|
|
||||||
switch packetBuffer.TransportProtocolNumber {
|
|
||||||
case header.TCPProtocolNumber:
|
|
||||||
tcpHdr := header.TCP(packetBuffer.TransportHeader().Slice())
|
|
||||||
tcpHdr.UpdateChecksumPseudoHeaderAddress(oldAddr, bindAddr, true)
|
|
||||||
case header.UDPProtocolNumber:
|
|
||||||
udpHdr := header.UDP(packetBuffer.TransportHeader().Slice())
|
|
||||||
udpHdr.UpdateChecksumPseudoHeaderAddress(oldAddr, bindAddr, true)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
//go:build !with_gvisor
|
|
||||||
|
|
||||||
package tun
|
|
||||||
|
|
||||||
import "github.com/sagernet/sing/common/buf"
|
|
||||||
|
|
||||||
type DirectDestination interface {
|
|
||||||
WritePacket(buffer *buf.Buffer) error
|
|
||||||
Close() error
|
|
||||||
Timeout() bool
|
|
||||||
}
|
|
1
stack.go
1
stack.go
|
@ -23,7 +23,6 @@ type StackOptions struct {
|
||||||
Inet6Address []netip.Prefix
|
Inet6Address []netip.Prefix
|
||||||
EndpointIndependentNat bool
|
EndpointIndependentNat bool
|
||||||
UDPTimeout int64
|
UDPTimeout int64
|
||||||
Router Router
|
|
||||||
Handler Handler
|
Handler Handler
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
ForwarderBindInterface bool
|
ForwarderBindInterface bool
|
||||||
|
|
96
system.go
96
system.go
|
@ -23,7 +23,6 @@ type System struct {
|
||||||
tun Tun
|
tun Tun
|
||||||
tunName string
|
tunName string
|
||||||
mtu uint32
|
mtu uint32
|
||||||
router Router
|
|
||||||
handler Handler
|
handler Handler
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
inet4Prefixes []netip.Prefix
|
inet4Prefixes []netip.Prefix
|
||||||
|
@ -39,7 +38,6 @@ type System struct {
|
||||||
tcpPort6 uint16
|
tcpPort6 uint16
|
||||||
tcpNat *TCPNat
|
tcpNat *TCPNat
|
||||||
udpNat *udpnat.Service[netip.AddrPort]
|
udpNat *udpnat.Service[netip.AddrPort]
|
||||||
routeMapping *RouteMapping
|
|
||||||
bindInterface bool
|
bindInterface bool
|
||||||
interfaceFinder control.InterfaceFinder
|
interfaceFinder control.InterfaceFinder
|
||||||
}
|
}
|
||||||
|
@ -58,7 +56,6 @@ func NewSystem(options StackOptions) (Stack, error) {
|
||||||
tunName: options.Name,
|
tunName: options.Name,
|
||||||
mtu: options.MTU,
|
mtu: options.MTU,
|
||||||
udpTimeout: options.UDPTimeout,
|
udpTimeout: options.UDPTimeout,
|
||||||
router: options.Router,
|
|
||||||
handler: options.Handler,
|
handler: options.Handler,
|
||||||
logger: options.Logger,
|
logger: options.Logger,
|
||||||
inet4Prefixes: options.Inet4Address,
|
inet4Prefixes: options.Inet4Address,
|
||||||
|
@ -66,9 +63,6 @@ func NewSystem(options StackOptions) (Stack, error) {
|
||||||
bindInterface: options.ForwarderBindInterface,
|
bindInterface: options.ForwarderBindInterface,
|
||||||
interfaceFinder: options.InterfaceFinder,
|
interfaceFinder: options.InterfaceFinder,
|
||||||
}
|
}
|
||||||
if stack.router != nil {
|
|
||||||
stack.routeMapping = NewRouteMapping(options.UDPTimeout)
|
|
||||||
}
|
|
||||||
if len(options.Inet4Address) > 0 {
|
if len(options.Inet4Address) > 0 {
|
||||||
if options.Inet4Address[0].Bits() == 32 {
|
if options.Inet4Address[0].Bits() == 32 {
|
||||||
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")
|
||||||
|
@ -275,21 +269,6 @@ func (s *System) processIPv4TCP(packet clashtcpip.IPv4Packet, header clashtcpip.
|
||||||
packet.SetDestinationIP(session.Source.Addr())
|
packet.SetDestinationIP(session.Source.Addr())
|
||||||
header.SetDestinationPort(session.Source.Port())
|
header.SetDestinationPort(session.Source.Port())
|
||||||
} else {
|
} else {
|
||||||
if s.router != nil {
|
|
||||||
session := RouteSession{4, syscall.IPPROTO_TCP, source, destination}
|
|
||||||
action := s.routeMapping.Lookup(session, func() RouteAction {
|
|
||||||
return s.router.RouteConnection(session, &systemTCPDirectPacketWriter4{s.tun, source})
|
|
||||||
})
|
|
||||||
switch actionType := action.(type) {
|
|
||||||
case *ActionBlock:
|
|
||||||
// TODO: send ICMP unreachable
|
|
||||||
return nil
|
|
||||||
case *ActionDirect:
|
|
||||||
return E.Append(nil, actionType.WritePacket(buf.As(packet).ToOwned()), func(err error) error {
|
|
||||||
return E.Cause(err, "route ipv4 tcp packet")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
natPort := s.tcpNat.Lookup(source, destination)
|
natPort := s.tcpNat.Lookup(source, destination)
|
||||||
packet.SetSourceIP(s.inet4Address)
|
packet.SetSourceIP(s.inet4Address)
|
||||||
header.SetSourcePort(natPort)
|
header.SetSourcePort(natPort)
|
||||||
|
@ -316,21 +295,6 @@ func (s *System) processIPv6TCP(packet clashtcpip.IPv6Packet, header clashtcpip.
|
||||||
packet.SetDestinationIP(session.Source.Addr())
|
packet.SetDestinationIP(session.Source.Addr())
|
||||||
header.SetDestinationPort(session.Source.Port())
|
header.SetDestinationPort(session.Source.Port())
|
||||||
} else {
|
} else {
|
||||||
if s.router != nil {
|
|
||||||
session := RouteSession{6, syscall.IPPROTO_TCP, source, destination}
|
|
||||||
action := s.routeMapping.Lookup(session, func() RouteAction {
|
|
||||||
return s.router.RouteConnection(session, &systemTCPDirectPacketWriter6{s.tun, source})
|
|
||||||
})
|
|
||||||
switch actionType := action.(type) {
|
|
||||||
case *ActionBlock:
|
|
||||||
// TODO: send RST
|
|
||||||
return nil
|
|
||||||
case *ActionDirect:
|
|
||||||
return E.Append(nil, actionType.WritePacket(buf.As(packet).ToOwned()), func(err error) error {
|
|
||||||
return E.Cause(err, "route ipv6 tcp packet")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
natPort := s.tcpNat.Lookup(source, destination)
|
natPort := s.tcpNat.Lookup(source, destination)
|
||||||
packet.SetSourceIP(s.inet6Address)
|
packet.SetSourceIP(s.inet6Address)
|
||||||
header.SetSourcePort(natPort)
|
header.SetSourcePort(natPort)
|
||||||
|
@ -354,21 +318,6 @@ func (s *System) processIPv4UDP(packet clashtcpip.IPv4Packet, header clashtcpip.
|
||||||
if !destination.Addr().IsGlobalUnicast() {
|
if !destination.Addr().IsGlobalUnicast() {
|
||||||
return common.Error(s.tun.Write(packet))
|
return common.Error(s.tun.Write(packet))
|
||||||
}
|
}
|
||||||
if s.router != nil {
|
|
||||||
routeSession := RouteSession{4, syscall.IPPROTO_UDP, source, destination}
|
|
||||||
action := s.routeMapping.Lookup(routeSession, func() RouteAction {
|
|
||||||
return s.router.RouteConnection(routeSession, &systemUDPDirectPacketWriter4{s.tun, source})
|
|
||||||
})
|
|
||||||
switch actionType := action.(type) {
|
|
||||||
case *ActionBlock:
|
|
||||||
// TODO: send icmp unreachable
|
|
||||||
return nil
|
|
||||||
case *ActionDirect:
|
|
||||||
return E.Append(nil, actionType.WritePacket(buf.As(packet).ToOwned()), func(err error) error {
|
|
||||||
return E.Cause(err, "route ipv4 udp packet")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data := buf.As(header.Payload())
|
data := buf.As(header.Payload())
|
||||||
if data.Len() == 0 {
|
if data.Len() == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -392,21 +341,6 @@ func (s *System) processIPv6UDP(packet clashtcpip.IPv6Packet, header clashtcpip.
|
||||||
if !destination.Addr().IsGlobalUnicast() {
|
if !destination.Addr().IsGlobalUnicast() {
|
||||||
return common.Error(s.tun.Write(packet))
|
return common.Error(s.tun.Write(packet))
|
||||||
}
|
}
|
||||||
if s.router != nil {
|
|
||||||
routeSession := RouteSession{6, syscall.IPPROTO_UDP, source, destination}
|
|
||||||
action := s.routeMapping.Lookup(routeSession, func() RouteAction {
|
|
||||||
return s.router.RouteConnection(routeSession, &systemUDPDirectPacketWriter6{s.tun, source})
|
|
||||||
})
|
|
||||||
switch actionType := action.(type) {
|
|
||||||
case *ActionBlock:
|
|
||||||
// TODO: send icmp unreachable
|
|
||||||
return nil
|
|
||||||
case *ActionDirect:
|
|
||||||
return E.Append(nil, actionType.WritePacket(buf.As(packet).ToOwned()), func(err error) error {
|
|
||||||
return E.Cause(err, "route ipv6 udp packet")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data := buf.As(header.Payload())
|
data := buf.As(header.Payload())
|
||||||
if data.Len() == 0 {
|
if data.Len() == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -425,21 +359,6 @@ func (s *System) processIPv6UDP(packet clashtcpip.IPv6Packet, header clashtcpip.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *System) processIPv4ICMP(packet clashtcpip.IPv4Packet, header clashtcpip.ICMPPacket) error {
|
func (s *System) processIPv4ICMP(packet clashtcpip.IPv4Packet, header clashtcpip.ICMPPacket) error {
|
||||||
if s.router != nil {
|
|
||||||
routeSession := RouteSession{4, clashtcpip.ICMP, netip.AddrPortFrom(packet.SourceIP(), 0), netip.AddrPortFrom(packet.DestinationIP(), 0)}
|
|
||||||
action := s.routeMapping.Lookup(routeSession, func() RouteAction {
|
|
||||||
return s.router.RouteConnection(routeSession, &systemICMPDirectPacketWriter4{s.tun, packet.SourceIP()})
|
|
||||||
})
|
|
||||||
switch actionType := action.(type) {
|
|
||||||
case *ActionBlock:
|
|
||||||
// TODO: send icmp unreachable
|
|
||||||
return nil
|
|
||||||
case *ActionDirect:
|
|
||||||
return E.Append(nil, actionType.WritePacket(buf.As(packet).ToOwned()), func(err error) error {
|
|
||||||
return E.Cause(err, "route ipv4 icmp packet")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if header.Type() != clashtcpip.ICMPTypePingRequest || header.Code() != 0 {
|
if header.Type() != clashtcpip.ICMPTypePingRequest || header.Code() != 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -453,21 +372,6 @@ func (s *System) processIPv4ICMP(packet clashtcpip.IPv4Packet, header clashtcpip
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *System) processIPv6ICMP(packet clashtcpip.IPv6Packet, header clashtcpip.ICMPv6Packet) error {
|
func (s *System) processIPv6ICMP(packet clashtcpip.IPv6Packet, header clashtcpip.ICMPv6Packet) error {
|
||||||
if s.router != nil {
|
|
||||||
routeSession := RouteSession{6, clashtcpip.ICMPv6, netip.AddrPortFrom(packet.SourceIP(), 0), netip.AddrPortFrom(packet.DestinationIP(), 0)}
|
|
||||||
action := s.routeMapping.Lookup(routeSession, func() RouteAction {
|
|
||||||
return s.router.RouteConnection(routeSession, &systemICMPDirectPacketWriter6{s.tun, packet.SourceIP()})
|
|
||||||
})
|
|
||||||
switch actionType := action.(type) {
|
|
||||||
case *ActionBlock:
|
|
||||||
// TODO: send icmp unreachable
|
|
||||||
return nil
|
|
||||||
case *ActionDirect:
|
|
||||||
return E.Append(nil, actionType.WritePacket(buf.As(packet).ToOwned()), func(err error) error {
|
|
||||||
return E.Cause(err, "route ipv6 icmp packet")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if header.Type() != clashtcpip.ICMPv6EchoRequest || header.Code() != 0 {
|
if header.Type() != clashtcpip.ICMPv6EchoRequest || header.Code() != 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ type NativeTun struct {
|
||||||
tunFile *os.File
|
tunFile *os.File
|
||||||
tunWriter N.VectorisedWriter
|
tunWriter N.VectorisedWriter
|
||||||
mtu uint32
|
mtu uint32
|
||||||
inet4Address string
|
inet4Address [4]byte
|
||||||
inet6Address string
|
inet6Address [16]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(options Options) (Tun, error) {
|
func New(options Options) (Tun, error) {
|
||||||
|
@ -57,10 +57,10 @@ func New(options Options) (Tun, error) {
|
||||||
mtu: options.MTU,
|
mtu: options.MTU,
|
||||||
}
|
}
|
||||||
if len(options.Inet4Address) > 0 {
|
if len(options.Inet4Address) > 0 {
|
||||||
nativeTun.inet4Address = string(options.Inet4Address[0].Addr().AsSlice())
|
nativeTun.inet4Address = options.Inet4Address[0].Addr().As4()
|
||||||
}
|
}
|
||||||
if len(options.Inet6Address) > 0 {
|
if len(options.Inet6Address) > 0 {
|
||||||
nativeTun.inet6Address = string(options.Inet6Address[0].Addr().AsSlice())
|
nativeTun.inet6Address = options.Inet6Address[0].Addr().As16()
|
||||||
}
|
}
|
||||||
var ok bool
|
var ok bool
|
||||||
nativeTun.tunWriter, ok = bufio.CreateVectorisedWriter(nativeTun.tunFile)
|
nativeTun.tunWriter, ok = bufio.CreateVectorisedWriter(nativeTun.tunFile)
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/sagernet/sing/common/buf"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
|
|
||||||
"gvisor.dev/gvisor/pkg/bufferv2"
|
"gvisor.dev/gvisor/pkg/buffer"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
|
@ -56,9 +56,9 @@ func (e *DarwinEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||||
func (e *DarwinEndpoint) dispatchLoop() {
|
func (e *DarwinEndpoint) dispatchLoop() {
|
||||||
_buffer := buf.StackNewSize(int(e.tun.mtu) + 4)
|
_buffer := buf.StackNewSize(int(e.tun.mtu) + 4)
|
||||||
defer common.KeepAlive(_buffer)
|
defer common.KeepAlive(_buffer)
|
||||||
buffer := common.Dup(_buffer)
|
packetBuffer := common.Dup(_buffer)
|
||||||
defer buffer.Release()
|
defer packetBuffer.Release()
|
||||||
data := buffer.FreeBytes()
|
data := packetBuffer.FreeBytes()
|
||||||
for {
|
for {
|
||||||
n, err := e.tun.tunFile.Read(data)
|
n, err := e.tun.tunFile.Read(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -69,13 +69,13 @@ func (e *DarwinEndpoint) dispatchLoop() {
|
||||||
switch header.IPVersion(packet) {
|
switch header.IPVersion(packet) {
|
||||||
case header.IPv4Version:
|
case header.IPv4Version:
|
||||||
networkProtocol = header.IPv4ProtocolNumber
|
networkProtocol = header.IPv4ProtocolNumber
|
||||||
if header.IPv4(packet).DestinationAddress() == tcpip.Address(e.tun.inet4Address) {
|
if header.IPv4(packet).DestinationAddress().As4() == e.tun.inet4Address {
|
||||||
e.tun.tunFile.Write(data[:n])
|
e.tun.tunFile.Write(data[:n])
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case header.IPv6Version:
|
case header.IPv6Version:
|
||||||
networkProtocol = header.IPv6ProtocolNumber
|
networkProtocol = header.IPv6ProtocolNumber
|
||||||
if header.IPv6(packet).DestinationAddress() == tcpip.Address(e.tun.inet6Address) {
|
if header.IPv6(packet).DestinationAddress().As16() == e.tun.inet6Address {
|
||||||
e.tun.tunFile.Write(data[:n])
|
e.tun.tunFile.Write(data[:n])
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ func (e *DarwinEndpoint) dispatchLoop() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||||
Payload: bufferv2.MakeWithData(data[4:n]),
|
Payload: buffer.MakeWithData(data[4:n]),
|
||||||
IsForwardedPacket: true,
|
IsForwardedPacket: true,
|
||||||
})
|
})
|
||||||
pkt.NetworkProtocolNumber = networkProtocol
|
pkt.NetworkProtocolNumber = networkProtocol
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
package tun
|
package tun
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gvisor.dev/gvisor/pkg/bufferv2"
|
"gvisor.dev/gvisor/pkg/buffer"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
|
@ -51,16 +51,16 @@ func (e *WintunEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||||
|
|
||||||
func (e *WintunEndpoint) dispatchLoop() {
|
func (e *WintunEndpoint) dispatchLoop() {
|
||||||
for {
|
for {
|
||||||
var buffer bufferv2.Buffer
|
var packetBuffer buffer.Buffer
|
||||||
err := e.tun.ReadFunc(func(b []byte) {
|
err := e.tun.ReadFunc(func(b []byte) {
|
||||||
buffer = bufferv2.MakeWithData(b)
|
packetBuffer = buffer.MakeWithData(b)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
ihl, ok := buffer.PullUp(0, 1)
|
ihl, ok := packetBuffer.PullUp(0, 1)
|
||||||
if !ok {
|
if !ok {
|
||||||
buffer.Release()
|
packetBuffer.Release()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var networkProtocol tcpip.NetworkProtocolNumber
|
var networkProtocol tcpip.NetworkProtocolNumber
|
||||||
|
@ -70,12 +70,12 @@ func (e *WintunEndpoint) dispatchLoop() {
|
||||||
case header.IPv6Version:
|
case header.IPv6Version:
|
||||||
networkProtocol = header.IPv6ProtocolNumber
|
networkProtocol = header.IPv6ProtocolNumber
|
||||||
default:
|
default:
|
||||||
e.tun.Write(buffer.Flatten())
|
e.tun.Write(packetBuffer.Flatten())
|
||||||
buffer.Release()
|
packetBuffer.Release()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||||
Payload: buffer,
|
Payload: packetBuffer,
|
||||||
IsForwardedPacket: true,
|
IsForwardedPacket: true,
|
||||||
})
|
})
|
||||||
dispatcher := e.dispatcher
|
dispatcher := e.dispatcher
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue