Add optional LWIP stack support
This commit is contained in:
parent
a937ff2d8d
commit
0fd822f913
18 changed files with 300 additions and 57 deletions
2
go.mod
2
go.mod
|
|
@ -5,7 +5,7 @@ go 1.18
|
||||||
require (
|
require (
|
||||||
github.com/eycorsican/go-tun2socks v1.16.11
|
github.com/eycorsican/go-tun2socks v1.16.11
|
||||||
github.com/sagernet/netlink v0.0.0-20220803045538-bdac49abf805
|
github.com/sagernet/netlink v0.0.0-20220803045538-bdac49abf805
|
||||||
github.com/sagernet/sing v0.0.0-20220801112236-1bb95f9661fc
|
github.com/sagernet/sing v0.0.0-20220807085721-583e78e0b86a
|
||||||
golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48
|
golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48
|
||||||
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418
|
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418
|
||||||
gvisor.dev/gvisor v0.0.0-20220801010827-addd1f7b3e97
|
gvisor.dev/gvisor v0.0.0-20220801010827-addd1f7b3e97
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -4,8 +4,8 @@ github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||||
github.com/sagernet/netlink v0.0.0-20220803045538-bdac49abf805 h1:hE+vtsjBCCPmxkRz9jZA+CicHgVkDT6H+Av5ZzskVxs=
|
github.com/sagernet/netlink v0.0.0-20220803045538-bdac49abf805 h1:hE+vtsjBCCPmxkRz9jZA+CicHgVkDT6H+Av5ZzskVxs=
|
||||||
github.com/sagernet/netlink v0.0.0-20220803045538-bdac49abf805/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
github.com/sagernet/netlink v0.0.0-20220803045538-bdac49abf805/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||||
github.com/sagernet/sing v0.0.0-20220801112236-1bb95f9661fc h1:x7H64IiqyrpxPWl/KrWkknzEK4GmpqgfZeVKFVw6E/M=
|
github.com/sagernet/sing v0.0.0-20220807085721-583e78e0b86a h1:EeaiaHqcGiGQdgRPHf8FPIKb17VADrncz1P27Jfli2w=
|
||||||
github.com/sagernet/sing v0.0.0-20220801112236-1bb95f9661fc/go.mod h1:GbtQfZSpmtD3cXeD1qX2LCMwY8dH+bnnInDTqd92IsM=
|
github.com/sagernet/sing v0.0.0-20220807085721-583e78e0b86a/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||||
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
|
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
|
||||||
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=
|
||||||
|
|
|
||||||
13
gvisor.go
13
gvisor.go
|
|
@ -29,18 +29,23 @@ type GVisor struct {
|
||||||
tun GVisorTun
|
tun GVisorTun
|
||||||
tunMtu uint32
|
tunMtu uint32
|
||||||
endpointIndependentNat bool
|
endpointIndependentNat bool
|
||||||
endpointIndependentNatTimeout int64
|
udpTimeout int64
|
||||||
handler Handler
|
handler Handler
|
||||||
stack *stack.Stack
|
stack *stack.Stack
|
||||||
endpoint stack.LinkEndpoint
|
endpoint stack.LinkEndpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GVisorTun interface {
|
||||||
|
Tun
|
||||||
|
NewEndpoint() (stack.LinkEndpoint, error)
|
||||||
|
}
|
||||||
|
|
||||||
func NewGVisor(
|
func NewGVisor(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
tun Tun,
|
tun Tun,
|
||||||
tunMtu uint32,
|
tunMtu uint32,
|
||||||
endpointIndependentNat bool,
|
endpointIndependentNat bool,
|
||||||
endpointIndependentNatTimeout int64,
|
udpTimeout int64,
|
||||||
handler Handler,
|
handler Handler,
|
||||||
) (Stack, error) {
|
) (Stack, error) {
|
||||||
gTun, isGTun := tun.(GVisorTun)
|
gTun, isGTun := tun.(GVisorTun)
|
||||||
|
|
@ -53,7 +58,7 @@ func NewGVisor(
|
||||||
tun: gTun,
|
tun: gTun,
|
||||||
tunMtu: tunMtu,
|
tunMtu: tunMtu,
|
||||||
endpointIndependentNat: endpointIndependentNat,
|
endpointIndependentNat: endpointIndependentNat,
|
||||||
endpointIndependentNatTimeout: endpointIndependentNatTimeout,
|
udpTimeout: udpTimeout,
|
||||||
handler: handler,
|
handler: handler,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -166,7 +171,7 @@ func (t *GVisor) Start() error {
|
||||||
}()
|
}()
|
||||||
}).HandlePacket)
|
}).HandlePacket)
|
||||||
} else {
|
} else {
|
||||||
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, NewUDPForwarder(t.ctx, ipStack, t.handler, t.endpointIndependentNatTimeout).HandlePacket)
|
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, NewUDPForwarder(t.ctx, ipStack, t.handler, t.udpTimeout).HandlePacket)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.stack = ipStack
|
t.stack = ipStack
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build no_gvisor && !(linux || windows || darwin)
|
//go:build !no_gvisor && !(linux || windows || darwin)
|
||||||
|
|
||||||
package tun
|
package tun
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build no_gvisor && (linux || windows || darwin)
|
//go:build no_gvisor
|
||||||
|
|
||||||
package tun
|
package tun
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
//go:build !(no_gvisor || !(linux || windows || darwin))
|
|
||||||
|
|
||||||
package tun
|
|
||||||
|
|
||||||
import "gvisor.dev/gvisor/pkg/tcpip/stack"
|
|
||||||
|
|
||||||
type GVisorTun interface {
|
|
||||||
Tun
|
|
||||||
NewEndpoint() (stack.LinkEndpoint, error)
|
|
||||||
}
|
|
||||||
|
|
@ -31,7 +31,7 @@ func NewUDPForwarder(ctx context.Context, stack *stack.Stack, handler Handler, u
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
stack: stack,
|
stack: stack,
|
||||||
handler: handler,
|
handler: handler,
|
||||||
udpNat: udpnat.New[netip.AddrPort](udpTimeout, nopErrorHandler{handler}),
|
udpNat: udpnat.New[netip.AddrPort](udpTimeout, handler),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,10 +120,3 @@ func (w *UDPBackWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr)
|
||||||
route.Stats().UDP.PacketsSent.Increment()
|
route.Stats().UDP.PacketsSent.Increment()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type nopErrorHandler struct {
|
|
||||||
Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h nopErrorHandler) NewError(ctx context.Context, err error) {
|
|
||||||
}
|
|
||||||
|
|
|
||||||
147
lwip.go
Normal file
147
lwip.go
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
//go:build with_lwip
|
||||||
|
|
||||||
|
package tun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
"github.com/sagernet/sing/common/udpnat"
|
||||||
|
|
||||||
|
lwip "github.com/eycorsican/go-tun2socks/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LWIP struct {
|
||||||
|
ctx context.Context
|
||||||
|
tun Tun
|
||||||
|
tunMtu uint32
|
||||||
|
udpTimeout int64
|
||||||
|
handler Handler
|
||||||
|
stack lwip.LWIPStack
|
||||||
|
udpNat *udpnat.Service[netip.AddrPort]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLWIP(
|
||||||
|
ctx context.Context,
|
||||||
|
tun Tun,
|
||||||
|
tunMtu uint32,
|
||||||
|
udpTimeout int64,
|
||||||
|
handler Handler,
|
||||||
|
) (Stack, error) {
|
||||||
|
return &LWIP{
|
||||||
|
ctx: ctx,
|
||||||
|
tun: tun,
|
||||||
|
tunMtu: tunMtu,
|
||||||
|
handler: handler,
|
||||||
|
stack: lwip.NewLWIPStack(),
|
||||||
|
udpNat: udpnat.New[netip.AddrPort](udpTimeout, handler),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LWIP) Start() error {
|
||||||
|
lwip.RegisterTCPConnHandler(l)
|
||||||
|
lwip.RegisterUDPConnHandler(l)
|
||||||
|
lwip.RegisterOutputFn(l.tun.Write)
|
||||||
|
go l.loopIn()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LWIP) loopIn() {
|
||||||
|
mtu := int(l.tunMtu)
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
mtu += 4
|
||||||
|
}
|
||||||
|
_buffer := buf.StackNewSize(mtu)
|
||||||
|
defer common.KeepAlive(_buffer)
|
||||||
|
buffer := common.Dup(_buffer)
|
||||||
|
defer buffer.Release()
|
||||||
|
data := buffer.FreeBytes()
|
||||||
|
for {
|
||||||
|
n, err := l.tun.Read(data)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var packet []byte
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
packet = data[4:n]
|
||||||
|
} else {
|
||||||
|
packet = data[:n]
|
||||||
|
}
|
||||||
|
_, err = l.stack.Write(packet)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "stack closed" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l.handler.NewError(context.Background(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LWIP) Close() error {
|
||||||
|
lwip.RegisterTCPConnHandler(nil)
|
||||||
|
lwip.RegisterUDPConnHandler(nil)
|
||||||
|
lwip.RegisterOutputFn(func(bytes []byte) (int, error) {
|
||||||
|
return 0, os.ErrClosed
|
||||||
|
})
|
||||||
|
return l.stack.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LWIP) Handle(conn net.Conn, target *net.TCPAddr) error {
|
||||||
|
lAddr := conn.LocalAddr()
|
||||||
|
rAddr := conn.RemoteAddr()
|
||||||
|
if lAddr == nil || rAddr == nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
var metadata M.Metadata
|
||||||
|
metadata.Source = M.SocksaddrFromNet(lAddr)
|
||||||
|
metadata.Destination = M.SocksaddrFromNet(rAddr)
|
||||||
|
hErr := l.handler.NewConnection(l.ctx, conn, metadata)
|
||||||
|
if hErr != nil {
|
||||||
|
conn.(lwip.TCPConn).Abort()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LWIP) Connect(conn lwip.UDPConn, target *net.UDPAddr) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LWIP) ReceiveTo(conn lwip.UDPConn, data []byte, addr *net.UDPAddr) error {
|
||||||
|
var upstreamMetadata M.Metadata
|
||||||
|
upstreamMetadata.Source = M.SocksaddrFromNet(conn.LocalAddr())
|
||||||
|
upstreamMetadata.Destination = M.SocksaddrFromNet(addr)
|
||||||
|
|
||||||
|
l.udpNat.NewPacket(
|
||||||
|
l.ctx,
|
||||||
|
upstreamMetadata.Source.AddrPort(),
|
||||||
|
buf.As(data).ToOwned(),
|
||||||
|
upstreamMetadata,
|
||||||
|
func(natConn N.PacketConn) N.PacketWriter {
|
||||||
|
return &LWIPUDPBackWriter{conn}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type LWIPUDPBackWriter struct {
|
||||||
|
conn lwip.UDPConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *LWIPUDPBackWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
||||||
|
defer buffer.Release()
|
||||||
|
return common.Error(w.conn.WriteFrom(buffer.Bytes(), destination.UDPAddr()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *LWIPUDPBackWriter) Close() error {
|
||||||
|
return w.conn.Close()
|
||||||
|
}
|
||||||
15
lwip_stub.go
Normal file
15
lwip_stub.go
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
//go:build !with_lwip
|
||||||
|
|
||||||
|
package tun
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
func NewLWIP(
|
||||||
|
ctx context.Context,
|
||||||
|
tun Tun,
|
||||||
|
tunMtu uint32,
|
||||||
|
udpTimeout int64,
|
||||||
|
handler Handler,
|
||||||
|
) (Stack, error) {
|
||||||
|
return nil, ErrLWIPNotIncluded
|
||||||
|
}
|
||||||
27
stack.go
27
stack.go
|
|
@ -1,12 +1,37 @@
|
||||||
package tun
|
package tun
|
||||||
|
|
||||||
import E "github.com/sagernet/sing/common/exceptions"
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrGVisorNotIncluded = E.New("gVisor is disabled in current build, try build without -tags `no_gvisor`")
|
ErrGVisorNotIncluded = E.New("gVisor is disabled in current build, try build without -tags `no_gvisor`")
|
||||||
ErrGVisorUnsupported = E.New("gVisor stack is unsupported on current platform")
|
ErrGVisorUnsupported = E.New("gVisor stack is unsupported on current platform")
|
||||||
|
ErrLWIPNotIncluded = E.New("LWIP stack is disabled in current build, try build with -tags `with_lwip` and CGO_ENABLED=1")
|
||||||
)
|
)
|
||||||
|
|
||||||
type Stack interface {
|
type Stack interface {
|
||||||
|
Start() error
|
||||||
Close() error
|
Close() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewStack(
|
||||||
|
ctx context.Context,
|
||||||
|
stack string,
|
||||||
|
tun Tun,
|
||||||
|
tunMtu uint32,
|
||||||
|
endpointIndependentNat bool,
|
||||||
|
udpTimeout int64,
|
||||||
|
handler Handler,
|
||||||
|
) (Stack, error) {
|
||||||
|
switch stack {
|
||||||
|
case "gvisor", "":
|
||||||
|
return NewGVisor(ctx, tun, tunMtu, endpointIndependentNat, udpTimeout, handler)
|
||||||
|
case "lwip":
|
||||||
|
return NewLWIP(ctx, tun, tunMtu, udpTimeout, handler)
|
||||||
|
default:
|
||||||
|
return nil, E.New("unknown stack: ", stack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
5
tun.go
5
tun.go
|
|
@ -1,14 +1,19 @@
|
||||||
package tun
|
package tun
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Handler interface {
|
type Handler interface {
|
||||||
N.TCPConnectionHandler
|
N.TCPConnectionHandler
|
||||||
N.UDPConnectionHandler
|
N.UDPConnectionHandler
|
||||||
|
E.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tun interface {
|
type Tun interface {
|
||||||
|
io.ReadWriter
|
||||||
Close() error
|
Close() error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,15 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/rw"
|
||||||
|
|
||||||
|
"golang.org/x/net/ipv4"
|
||||||
"golang.org/x/net/route"
|
"golang.org/x/net/route"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
@ -41,13 +44,45 @@ func Open(name string, inet4Address netip.Prefix, inet6Address netip.Prefix, mtu
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &NativeTun{
|
nativeTun := &NativeTun{
|
||||||
tunFd: uintptr(tunFd),
|
tunFd: uintptr(tunFd),
|
||||||
tunFile: os.NewFile(uintptr(tunFd), "utun"),
|
tunFile: os.NewFile(uintptr(tunFd), "utun"),
|
||||||
inet4Address: string(inet4Address.Addr().AsSlice()),
|
inet4Address: string(inet4Address.Addr().AsSlice()),
|
||||||
inet6Address: string(inet6Address.Addr().AsSlice()),
|
inet6Address: string(inet6Address.Addr().AsSlice()),
|
||||||
mtu: mtu,
|
mtu: mtu,
|
||||||
}, nil
|
}
|
||||||
|
runtime.SetFinalizer(nativeTun.tunFile, nil)
|
||||||
|
return nativeTun, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *NativeTun) Read(p []byte) (n int, err error) {
|
||||||
|
/*n, err = t.tunFile.Read(p)
|
||||||
|
if n < 4 {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(p[:], p[4:])
|
||||||
|
return n - 4, err*/
|
||||||
|
return t.tunFile.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
packetHeader4 = [4]byte{0x00, 0x00, 0x00, unix.AF_INET}
|
||||||
|
packetHeader6 = [4]byte{0x00, 0x00, 0x00, unix.AF_INET6}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t *NativeTun) Write(p []byte) (n int, err error) {
|
||||||
|
var packetHeader []byte
|
||||||
|
if p[0]>>4 == ipv4.Version {
|
||||||
|
packetHeader = packetHeader4[:]
|
||||||
|
} else {
|
||||||
|
packetHeader = packetHeader6[:]
|
||||||
|
}
|
||||||
|
_, err = rw.WriteV(t.tunFd, [][]byte{packetHeader, p})
|
||||||
|
if err == nil {
|
||||||
|
n = len(p)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *NativeTun) Close() error {
|
func (t *NativeTun) Close() error {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/sagernet/sing/common/buf"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/rw"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
"gvisor.dev/gvisor/pkg/bufferv2"
|
"gvisor.dev/gvisor/pkg/bufferv2"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
|
|
@ -113,11 +112,6 @@ func (e *DarwinEndpoint) ARPHardwareType() header.ARPHardwareType {
|
||||||
func (e *DarwinEndpoint) AddHeader(buffer *stack.PacketBuffer) {
|
func (e *DarwinEndpoint) AddHeader(buffer *stack.PacketBuffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
packetHeader4 = [4]byte{0x00, 0x00, 0x00, unix.AF_INET}
|
|
||||||
packetHeader6 = [4]byte{0x00, 0x00, 0x00, unix.AF_INET6}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (e *DarwinEndpoint) WritePackets(packetBufferList stack.PacketBufferList) (int, tcpip.Error) {
|
func (e *DarwinEndpoint) WritePackets(packetBufferList stack.PacketBufferList) (int, tcpip.Error) {
|
||||||
var n int
|
var n int
|
||||||
for _, packet := range packetBufferList.AsSlice() {
|
for _, packet := range packetBufferList.AsSlice() {
|
||||||
|
|
|
||||||
20
tun_linux.go
20
tun_linux.go
|
|
@ -3,6 +3,8 @@ package tun
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/sagernet/netlink"
|
"github.com/sagernet/netlink"
|
||||||
|
|
@ -14,7 +16,8 @@ import (
|
||||||
|
|
||||||
type NativeTun struct {
|
type NativeTun struct {
|
||||||
name string
|
name string
|
||||||
fd int
|
tunFd int
|
||||||
|
tunFile *os.File
|
||||||
inet4Address netip.Prefix
|
inet4Address netip.Prefix
|
||||||
inet6Address netip.Prefix
|
inet6Address netip.Prefix
|
||||||
mtu uint32
|
mtu uint32
|
||||||
|
|
@ -32,12 +35,14 @@ func Open(name string, inet4Address netip.Prefix, inet6Address netip.Prefix, mtu
|
||||||
}
|
}
|
||||||
nativeTun := &NativeTun{
|
nativeTun := &NativeTun{
|
||||||
name: name,
|
name: name,
|
||||||
fd: tunFd,
|
tunFd: tunFd,
|
||||||
|
tunFile: os.NewFile(uintptr(tunFd), "tun"),
|
||||||
mtu: mtu,
|
mtu: mtu,
|
||||||
inet4Address: inet4Address,
|
inet4Address: inet4Address,
|
||||||
inet6Address: inet6Address,
|
inet6Address: inet6Address,
|
||||||
autoRoute: autoRoute,
|
autoRoute: autoRoute,
|
||||||
}
|
}
|
||||||
|
runtime.SetFinalizer(nativeTun.tunFile, nil)
|
||||||
err = nativeTun.configure(tunLink)
|
err = nativeTun.configure(tunLink)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Errors(err, unix.Close(tunFd))
|
return nil, E.Errors(err, unix.Close(tunFd))
|
||||||
|
|
@ -45,6 +50,14 @@ func Open(name string, inet4Address netip.Prefix, inet6Address netip.Prefix, mtu
|
||||||
return nativeTun, nil
|
return nativeTun, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *NativeTun) Read(p []byte) (n int, err error) {
|
||||||
|
return t.tunFile.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *NativeTun) Write(p []byte) (n int, err error) {
|
||||||
|
return t.tunFile.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
var controlPath string
|
var controlPath string
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -131,8 +144,7 @@ func (t *NativeTun) Close() error {
|
||||||
if t.autoRoute {
|
if t.autoRoute {
|
||||||
errors = append(errors, t.unsetRoute())
|
errors = append(errors, t.unsetRoute())
|
||||||
}
|
}
|
||||||
errors = append(errors, unix.Close(t.fd))
|
return E.Errors(append(errors, t.tunFile.Close())...)
|
||||||
return E.Errors(errors...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const tunTableIndex = 2022
|
const tunTableIndex = 2022
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ var _ GVisorTun = (*NativeTun)(nil)
|
||||||
|
|
||||||
func (t *NativeTun) NewEndpoint() (stack.LinkEndpoint, error) {
|
func (t *NativeTun) NewEndpoint() (stack.LinkEndpoint, error) {
|
||||||
return fdbased.New(&fdbased.Options{
|
return fdbased.New(&fdbased.Options{
|
||||||
FDs: []int{t.fd},
|
FDs: []int{t.tunFd},
|
||||||
MTU: t.mtu,
|
MTU: t.mtu,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build no_gvisor || !(linux || windows || darwin)
|
//go:build !(linux || windows || darwin)
|
||||||
|
|
||||||
package tun
|
package tun
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,29 @@ retry:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *NativeTun) Write(packetElementList [][]byte) (n int, err error) {
|
func (t *NativeTun) Write(p []byte) (n int, err error) {
|
||||||
|
t.running.Add(1)
|
||||||
|
defer t.running.Done()
|
||||||
|
if atomic.LoadInt32(&t.close) == 1 {
|
||||||
|
return 0, os.ErrClosed
|
||||||
|
}
|
||||||
|
t.rate.update(uint64(len(p)))
|
||||||
|
packet, err := t.session.AllocateSendPacket(len(p))
|
||||||
|
copy(packet, p)
|
||||||
|
if err == nil {
|
||||||
|
t.session.SendPacket(packet)
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
switch err {
|
||||||
|
case windows.ERROR_HANDLE_EOF:
|
||||||
|
return 0, os.ErrClosed
|
||||||
|
case windows.ERROR_BUFFER_OVERFLOW:
|
||||||
|
return 0, nil // Dropping when ring is full.
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("write failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *NativeTun) write(packetElementList [][]byte) (n int, err error) {
|
||||||
t.running.Add(1)
|
t.running.Add(1)
|
||||||
defer t.running.Done()
|
defer t.running.Done()
|
||||||
if atomic.LoadInt32(&t.close) == 1 {
|
if atomic.LoadInt32(&t.close) == 1 {
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ func (e *WintunEndpoint) dispatchLoop() {
|
||||||
case header.IPv6Version:
|
case header.IPv6Version:
|
||||||
networkProtocol = header.IPv6ProtocolNumber
|
networkProtocol = header.IPv6ProtocolNumber
|
||||||
default:
|
default:
|
||||||
e.tun.Write([][]byte{packet})
|
e.tun.Write(packet)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||||
|
|
@ -111,7 +111,7 @@ func (e *WintunEndpoint) AddHeader(buffer *stack.PacketBuffer) {
|
||||||
func (e *WintunEndpoint) WritePackets(packetBufferList stack.PacketBufferList) (int, tcpip.Error) {
|
func (e *WintunEndpoint) WritePackets(packetBufferList stack.PacketBufferList) (int, tcpip.Error) {
|
||||||
var n int
|
var n int
|
||||||
for _, packet := range packetBufferList.AsSlice() {
|
for _, packet := range packetBufferList.AsSlice() {
|
||||||
_, err := e.tun.Write(packet.AsSlices())
|
_, err := e.tun.write(packet.AsSlices())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, &tcpip.ErrAborted{}
|
return n, &tcpip.ErrAborted{}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue