mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-09-16 13:52:32 +00:00
121 lines
2.5 KiB
Go
121 lines
2.5 KiB
Go
package lwip
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
"sync"
|
|
|
|
"github.com/Dreamacro/clash/adapter/inbound"
|
|
"github.com/Dreamacro/clash/common/pool"
|
|
"github.com/Dreamacro/clash/config"
|
|
C "github.com/Dreamacro/clash/constant"
|
|
"github.com/Dreamacro/clash/listener/tun/dev"
|
|
"github.com/Dreamacro/clash/listener/tun/ipstack"
|
|
"github.com/Dreamacro/clash/log"
|
|
"github.com/yaling888/go-lwip"
|
|
)
|
|
|
|
type lwipAdapter struct {
|
|
device dev.TunDevice
|
|
lwipStack golwip.LWIPStack
|
|
lock sync.Mutex
|
|
mtu int
|
|
stackName string
|
|
dnsListen string
|
|
autoRoute bool
|
|
}
|
|
|
|
func NewAdapter(device dev.TunDevice, conf config.Tun, mtu int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.TunAdapter, error) {
|
|
adapter := &lwipAdapter{
|
|
device: device,
|
|
mtu: mtu,
|
|
stackName: conf.Stack,
|
|
dnsListen: conf.DNSListen,
|
|
autoRoute: conf.AutoRoute,
|
|
}
|
|
|
|
adapter.lock.Lock()
|
|
defer adapter.lock.Unlock()
|
|
|
|
dnsHost, _, err := net.SplitHostPort(conf.DNSListen)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dnsIP := net.ParseIP(dnsHost)
|
|
|
|
// Register output function, write packets from lwip stack to tun device
|
|
golwip.RegisterOutputFn(func(data []byte) (int, error) {
|
|
return device.Write(data)
|
|
})
|
|
|
|
// Set custom buffer pool
|
|
golwip.SetPoolAllocator(newLWIPPool())
|
|
|
|
// Setup TCP/IP stack.
|
|
lwipStack, err := golwip.NewLWIPStack(mtu)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
adapter.lwipStack = lwipStack
|
|
|
|
golwip.RegisterDnsHandler(newDnsHandler())
|
|
golwip.RegisterTCPConnHandler(newTCPHandler(dnsIP, tcpIn))
|
|
golwip.RegisterUDPConnHandler(newUDPHandler(dnsIP, udpIn))
|
|
|
|
// Copy packets from tun device to lwip stack, it's the loop.
|
|
go func(lwipStack golwip.LWIPStack, device dev.TunDevice, mtu int) {
|
|
_, err := io.CopyBuffer(lwipStack.(io.Writer), device, make([]byte, mtu))
|
|
if err != nil {
|
|
log.Debugln("copying data failed: %v", err)
|
|
}
|
|
}(lwipStack, device, mtu)
|
|
|
|
return adapter, nil
|
|
}
|
|
|
|
func (l *lwipAdapter) Stack() string {
|
|
return l.stackName
|
|
}
|
|
|
|
func (l *lwipAdapter) AutoRoute() bool {
|
|
return l.autoRoute
|
|
}
|
|
|
|
func (l *lwipAdapter) DNSListen() string {
|
|
return l.dnsListen
|
|
}
|
|
|
|
func (l *lwipAdapter) Close() {
|
|
l.lock.Lock()
|
|
defer l.lock.Unlock()
|
|
|
|
l.stopLocked()
|
|
}
|
|
|
|
func (l *lwipAdapter) stopLocked() {
|
|
if l.lwipStack != nil {
|
|
_ = l.lwipStack.Close()
|
|
}
|
|
|
|
if l.device != nil {
|
|
_ = l.device.Close()
|
|
}
|
|
|
|
l.lwipStack = nil
|
|
l.device = nil
|
|
}
|
|
|
|
type lwipPool struct{}
|
|
|
|
func (p lwipPool) Get(size int) []byte {
|
|
return pool.Get(size)
|
|
}
|
|
|
|
func (p lwipPool) Put(buf []byte) error {
|
|
return pool.Put(buf)
|
|
}
|
|
|
|
func newLWIPPool() golwip.LWIPPool {
|
|
return &lwipPool{}
|
|
}
|