[style]
This commit is contained in:
parent
cb52682790
commit
885f69b81d
5 changed files with 1 additions and 347 deletions
|
@ -1,87 +0,0 @@
|
|||
package lwip
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/component/resolver"
|
||||
D "github.com/Dreamacro/clash/listener/tun/ipstack/commons"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
"github.com/yaling888/go-lwip"
|
||||
)
|
||||
|
||||
const defaultDnsReadTimeout = time.Second * 8
|
||||
|
||||
func shouldHijackDns(dnsIP net.IP, targetIp net.IP, targetPort int) bool {
|
||||
if targetPort != 53 {
|
||||
return false
|
||||
}
|
||||
|
||||
return dnsIP.Equal(net.IPv4zero) || dnsIP.Equal(targetIp)
|
||||
}
|
||||
|
||||
func hijackUDPDns(conn golwip.UDPConn, pkt []byte, addr *net.UDPAddr) {
|
||||
go func() {
|
||||
defer func(conn golwip.UDPConn) {
|
||||
_ = conn.Close()
|
||||
}(conn)
|
||||
|
||||
answer, err := D.RelayDnsPacket(pkt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, _ = conn.WriteFrom(answer, addr)
|
||||
}()
|
||||
}
|
||||
|
||||
func hijackTCPDns(conn net.Conn) {
|
||||
go func() {
|
||||
defer func(conn net.Conn) {
|
||||
_ = conn.Close()
|
||||
}(conn)
|
||||
|
||||
if err := conn.SetDeadline(time.Now().Add(defaultDnsReadTimeout)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
var length uint16
|
||||
if binary.Read(conn, binary.BigEndian, &length) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data := make([]byte, length)
|
||||
|
||||
_, err := io.ReadFull(conn, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
rb, err := D.RelayDnsPacket(data)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if binary.Write(conn, binary.BigEndian, uint16(len(rb))) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = conn.Write(rb); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
type dnsHandler struct{}
|
||||
|
||||
func newDnsHandler() golwip.DnsHandler {
|
||||
return &dnsHandler{}
|
||||
}
|
||||
|
||||
func (d dnsHandler) ResolveIP(host string) (net.IP, error) {
|
||||
log.Debugln("[TUN] lwip resolve ip for host: %s", host)
|
||||
return resolver.ResolveIP(host)
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package lwip
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/context"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
"github.com/yaling888/go-lwip"
|
||||
)
|
||||
|
||||
type tcpHandler struct {
|
||||
dnsIP net.IP
|
||||
tcpIn chan<- C.ConnContext
|
||||
}
|
||||
|
||||
func newTCPHandler(dnsIP net.IP, tcpIn chan<- C.ConnContext) golwip.TCPConnHandler {
|
||||
return &tcpHandler{dnsIP, tcpIn}
|
||||
}
|
||||
|
||||
func (h *tcpHandler) Handle(conn net.Conn, target *net.TCPAddr) error {
|
||||
if shouldHijackDns(h.dnsIP, target.IP, target.Port) {
|
||||
hijackTCPDns(conn)
|
||||
log.Debugln("[TUN] hijack dns tcp: %s:%d", target.IP.String(), target.Port)
|
||||
return nil
|
||||
}
|
||||
|
||||
if conn.RemoteAddr() == nil {
|
||||
_ = conn.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
src, _ := conn.LocalAddr().(*net.TCPAddr)
|
||||
dst, _ := conn.RemoteAddr().(*net.TCPAddr)
|
||||
|
||||
addrType := C.AtypIPv4
|
||||
if dst.IP.To4() == nil {
|
||||
addrType = C.AtypIPv6
|
||||
}
|
||||
|
||||
metadata := &C.Metadata{
|
||||
NetWork: C.TCP,
|
||||
Type: C.TUN,
|
||||
SrcIP: src.IP,
|
||||
DstIP: dst.IP,
|
||||
SrcPort: strconv.Itoa(src.Port),
|
||||
DstPort: strconv.Itoa(dst.Port),
|
||||
AddrType: addrType,
|
||||
Host: "",
|
||||
}
|
||||
|
||||
go func(conn net.Conn, metadata *C.Metadata) {
|
||||
//if c, ok := conn.(*net.TCPConn); ok {
|
||||
// c.SetKeepAlive(true)
|
||||
//}
|
||||
h.tcpIn <- context.NewConnContext(conn, metadata)
|
||||
}(conn, metadata)
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
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{}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
package lwip
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter/inbound"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
"github.com/Dreamacro/clash/transport/socks5"
|
||||
"github.com/yaling888/go-lwip"
|
||||
)
|
||||
|
||||
type udpPacket struct {
|
||||
source *net.UDPAddr
|
||||
payload []byte
|
||||
sender golwip.UDPConn
|
||||
}
|
||||
|
||||
func (u *udpPacket) Data() []byte {
|
||||
return u.payload
|
||||
}
|
||||
|
||||
func (u *udpPacket) WriteBack(b []byte, addr net.Addr) (n int, err error) {
|
||||
_, ok := addr.(*net.UDPAddr)
|
||||
if !ok {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
|
||||
return u.sender.WriteFrom(b, u.source)
|
||||
}
|
||||
|
||||
func (u *udpPacket) Drop() {
|
||||
}
|
||||
|
||||
func (u *udpPacket) LocalAddr() net.Addr {
|
||||
return u.source
|
||||
}
|
||||
|
||||
type udpHandler struct {
|
||||
dnsIP net.IP
|
||||
udpIn chan<- *inbound.PacketAdapter
|
||||
}
|
||||
|
||||
func newUDPHandler(dnsIP net.IP, udpIn chan<- *inbound.PacketAdapter) golwip.UDPConnHandler {
|
||||
return &udpHandler{dnsIP, udpIn}
|
||||
}
|
||||
|
||||
func (h *udpHandler) Connect(golwip.UDPConn, *net.UDPAddr) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *udpHandler) ReceiveTo(conn golwip.UDPConn, data []byte, addr *net.UDPAddr) error {
|
||||
if shouldHijackDns(h.dnsIP, addr.IP, addr.Port) {
|
||||
hijackUDPDns(conn, data, addr)
|
||||
log.Debugln("[TUN] hijack dns udp: %s:%d", addr.IP.String(), addr.Port)
|
||||
return nil
|
||||
}
|
||||
|
||||
packet := &udpPacket{
|
||||
source: conn.LocalAddr(),
|
||||
payload: data,
|
||||
sender: conn,
|
||||
}
|
||||
|
||||
go func(addr *net.UDPAddr, packet *udpPacket) {
|
||||
select {
|
||||
case h.udpIn <- inbound.NewPacket(socks5.ParseAddrToSocksAddr(addr), packet, C.TUN):
|
||||
default:
|
||||
}
|
||||
}(addr, packet)
|
||||
|
||||
return nil
|
||||
}
|
|
@ -11,7 +11,6 @@ import (
|
|||
"github.com/Dreamacro/clash/listener/tun/dev"
|
||||
"github.com/Dreamacro/clash/listener/tun/ipstack"
|
||||
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor"
|
||||
"github.com/Dreamacro/clash/listener/tun/ipstack/lwip"
|
||||
"github.com/Dreamacro/clash/listener/tun/ipstack/system"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
)
|
||||
|
@ -34,9 +33,7 @@ func New(conf config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.Pack
|
|||
return nil, errors.New("unable to get device mtu")
|
||||
}
|
||||
|
||||
if strings.EqualFold(stack, "lwip") {
|
||||
tunAdapter, err = lwip.NewAdapter(device, conf, mtu, tcpIn, udpIn)
|
||||
} else if strings.EqualFold(stack, "system") {
|
||||
if strings.EqualFold(stack, "system") {
|
||||
tunAdapter, err = system.NewAdapter(device, conf, mtu, tunAddress, tunAddress, func() {}, tcpIn, udpIn)
|
||||
} else if strings.EqualFold(stack, "gvisor") {
|
||||
tunAdapter, err = gvisor.NewAdapter(device, conf, tunAddress, tcpIn, udpIn)
|
||||
|
|
Loading…
Reference in a new issue