github.com/MerlinKodo/sing-tun@v0.1.15/stack_lwip.go (about)

     1  //go:build with_lwip
     2  
     3  package tun
     4  
     5  import (
     6  	"context"
     7  	"net"
     8  	"net/netip"
     9  	"os"
    10  
    11  	lwip "github.com/sagernet/go-tun2socks/core"
    12  	"github.com/sagernet/sing/common"
    13  	"github.com/sagernet/sing/common/buf"
    14  	M "github.com/sagernet/sing/common/metadata"
    15  	N "github.com/sagernet/sing/common/network"
    16  	"github.com/sagernet/sing/common/udpnat"
    17  )
    18  
    19  type LWIP struct {
    20  	ctx        context.Context
    21  	tun        Tun
    22  	tunMtu     uint32
    23  	udpTimeout int64
    24  	handler    Handler
    25  	stack      lwip.LWIPStack
    26  	udpNat     *udpnat.Service[netip.AddrPort]
    27  }
    28  
    29  func NewLWIP(
    30  	options StackOptions,
    31  ) (Stack, error) {
    32  	return &LWIP{
    33  		ctx:     options.Context,
    34  		tun:     options.Tun,
    35  		tunMtu:  options.MTU,
    36  		handler: options.Handler,
    37  		stack:   lwip.NewLWIPStack(),
    38  		udpNat:  udpnat.New[netip.AddrPort](options.UDPTimeout, options.Handler),
    39  	}, nil
    40  }
    41  
    42  func (l *LWIP) Start() error {
    43  	lwip.RegisterTCPConnHandler(l)
    44  	lwip.RegisterUDPConnHandler(l)
    45  	lwip.RegisterOutputFn(l.tun.Write)
    46  	go l.loopIn()
    47  	return nil
    48  }
    49  
    50  func (l *LWIP) loopIn() {
    51  	if winTun, isWintun := l.tun.(WinTun); isWintun {
    52  		l.loopInWintun(winTun)
    53  		return
    54  	}
    55  	buffer := make([]byte, int(l.tunMtu)+PacketOffset)
    56  	for {
    57  		n, err := l.tun.Read(buffer)
    58  		if err != nil {
    59  			return
    60  		}
    61  		_, err = l.stack.Write(buffer[PacketOffset:n])
    62  		if err != nil {
    63  			if err.Error() == "stack closed" {
    64  				return
    65  			}
    66  			l.handler.NewError(context.Background(), err)
    67  		}
    68  	}
    69  }
    70  
    71  func (l *LWIP) loopInWintun(tun WinTun) {
    72  	for {
    73  		packet, release, err := tun.ReadPacket()
    74  		if err != nil {
    75  			return
    76  		}
    77  		_, err = l.stack.Write(packet)
    78  		release()
    79  		if err != nil {
    80  			if err.Error() == "stack closed" {
    81  				return
    82  			}
    83  			l.handler.NewError(context.Background(), err)
    84  		}
    85  	}
    86  }
    87  
    88  func (l *LWIP) Close() error {
    89  	lwip.RegisterTCPConnHandler(nil)
    90  	lwip.RegisterUDPConnHandler(nil)
    91  	lwip.RegisterOutputFn(func(bytes []byte) (int, error) {
    92  		return 0, os.ErrClosed
    93  	})
    94  	return l.stack.Close()
    95  }
    96  
    97  func (l *LWIP) Handle(conn net.Conn) error {
    98  	lAddr := conn.LocalAddr()
    99  	rAddr := conn.RemoteAddr()
   100  	if lAddr == nil || rAddr == nil {
   101  		conn.Close()
   102  		return nil
   103  	}
   104  	go func() {
   105  		var metadata M.Metadata
   106  		metadata.Source = M.SocksaddrFromNet(lAddr)
   107  		metadata.Destination = M.SocksaddrFromNet(rAddr)
   108  		hErr := l.handler.NewConnection(l.ctx, conn, metadata)
   109  		if hErr != nil {
   110  			conn.(lwip.TCPConn).Abort()
   111  		}
   112  	}()
   113  	return nil
   114  }
   115  
   116  func (l *LWIP) ReceiveTo(conn lwip.UDPConn, data []byte, addr M.Socksaddr) error {
   117  	var upstreamMetadata M.Metadata
   118  	upstreamMetadata.Source = conn.LocalAddr()
   119  	upstreamMetadata.Destination = addr
   120  
   121  	l.udpNat.NewPacket(
   122  		l.ctx,
   123  		upstreamMetadata.Source.AddrPort(),
   124  		buf.As(data).ToOwned(),
   125  		upstreamMetadata,
   126  		func(natConn N.PacketConn) N.PacketWriter {
   127  			return &LWIPUDPBackWriter{conn}
   128  		},
   129  	)
   130  	return nil
   131  }
   132  
   133  type LWIPUDPBackWriter struct {
   134  	conn lwip.UDPConn
   135  }
   136  
   137  func (w *LWIPUDPBackWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
   138  	defer buffer.Release()
   139  	return common.Error(w.conn.WriteFrom(buffer.Bytes(), destination))
   140  }
   141  
   142  func (w *LWIPUDPBackWriter) Close() error {
   143  	return w.conn.Close()
   144  }