[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/dev"
|
||||||
"github.com/Dreamacro/clash/listener/tun/ipstack"
|
"github.com/Dreamacro/clash/listener/tun/ipstack"
|
||||||
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor"
|
"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/listener/tun/ipstack/system"
|
||||||
"github.com/Dreamacro/clash/log"
|
"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")
|
return nil, errors.New("unable to get device mtu")
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.EqualFold(stack, "lwip") {
|
if strings.EqualFold(stack, "system") {
|
||||||
tunAdapter, err = lwip.NewAdapter(device, conf, mtu, tcpIn, udpIn)
|
|
||||||
} else if strings.EqualFold(stack, "system") {
|
|
||||||
tunAdapter, err = system.NewAdapter(device, conf, mtu, tunAddress, tunAddress, func() {}, tcpIn, udpIn)
|
tunAdapter, err = system.NewAdapter(device, conf, mtu, tunAddress, tunAddress, func() {}, tcpIn, udpIn)
|
||||||
} else if strings.EqualFold(stack, "gvisor") {
|
} else if strings.EqualFold(stack, "gvisor") {
|
||||||
tunAdapter, err = gvisor.NewAdapter(device, conf, tunAddress, tcpIn, udpIn)
|
tunAdapter, err = gvisor.NewAdapter(device, conf, tunAddress, tcpIn, udpIn)
|
||||||
|
|
Loading…
Reference in a new issue