mirror of
https://github.com/SagerNet/sing-tun.git
synced 2025-04-02 19:37:40 +03:00
144 lines
3 KiB
Go
144 lines
3 KiB
Go
//go:build with_lwip
|
|
|
|
package tun
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"net/netip"
|
|
"os"
|
|
|
|
lwip "github.com/sagernet/go-tun2socks/core"
|
|
"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"
|
|
)
|
|
|
|
type LWIP struct {
|
|
ctx context.Context
|
|
tun Tun
|
|
tunMtu uint32
|
|
udpTimeout int64
|
|
handler Handler
|
|
stack lwip.LWIPStack
|
|
udpNat *udpnat.Service[netip.AddrPort]
|
|
}
|
|
|
|
func NewLWIP(
|
|
options StackOptions,
|
|
) (Stack, error) {
|
|
return &LWIP{
|
|
ctx: options.Context,
|
|
tun: options.Tun,
|
|
tunMtu: options.MTU,
|
|
handler: options.Handler,
|
|
stack: lwip.NewLWIPStack(),
|
|
udpNat: udpnat.New[netip.AddrPort](options.UDPTimeout, options.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() {
|
|
if winTun, isWintun := l.tun.(WinTun); isWintun {
|
|
l.loopInWintun(winTun)
|
|
return
|
|
}
|
|
buffer := make([]byte, int(l.tunMtu)+PacketOffset)
|
|
for {
|
|
n, err := l.tun.Read(buffer)
|
|
if err != nil {
|
|
return
|
|
}
|
|
_, err = l.stack.Write(buffer[PacketOffset:n])
|
|
if err != nil {
|
|
if err.Error() == "stack closed" {
|
|
return
|
|
}
|
|
l.handler.NewError(context.Background(), err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (l *LWIP) loopInWintun(tun WinTun) {
|
|
for {
|
|
packet, release, err := tun.ReadPacket()
|
|
if err != nil {
|
|
return
|
|
}
|
|
_, err = l.stack.Write(packet)
|
|
release()
|
|
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) 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) ReceiveTo(conn lwip.UDPConn, data []byte, addr M.Socksaddr) error {
|
|
var upstreamMetadata M.Metadata
|
|
upstreamMetadata.Source = conn.LocalAddr()
|
|
upstreamMetadata.Destination = 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))
|
|
}
|
|
|
|
func (w *LWIPUDPBackWriter) Close() error {
|
|
return w.conn.Close()
|
|
}
|