support ebpf
This commit is contained in:
86
listener/autoredir/tcp.go
Normal file
86
listener/autoredir/tcp.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package autoredir
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter/inbound"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
"github.com/Dreamacro/clash/transport/socks5"
|
||||
)
|
||||
|
||||
type Listener struct {
|
||||
listener net.Listener
|
||||
addr string
|
||||
closed bool
|
||||
lookupFunc func(netip.AddrPort) (socks5.Addr, error)
|
||||
}
|
||||
|
||||
// RawAddress implements C.Listener
|
||||
func (l *Listener) RawAddress() string {
|
||||
return l.addr
|
||||
}
|
||||
|
||||
// Address implements C.Listener
|
||||
func (l *Listener) Address() string {
|
||||
return l.listener.Addr().String()
|
||||
}
|
||||
|
||||
// Close implements C.Listener
|
||||
func (l *Listener) Close() error {
|
||||
l.closed = true
|
||||
return l.listener.Close()
|
||||
}
|
||||
|
||||
func (l *Listener) TCPAddr() netip.AddrPort {
|
||||
return l.listener.Addr().(*net.TCPAddr).AddrPort()
|
||||
}
|
||||
|
||||
func (l *Listener) SetLookupFunc(lookupFunc func(netip.AddrPort) (socks5.Addr, error)) {
|
||||
l.lookupFunc = lookupFunc
|
||||
}
|
||||
|
||||
func (l *Listener) handleRedir(conn net.Conn, in chan<- C.ConnContext) {
|
||||
if l.lookupFunc == nil {
|
||||
log.Errorln("[Auto Redirect] lookup function is nil")
|
||||
return
|
||||
}
|
||||
|
||||
target, err := l.lookupFunc(conn.RemoteAddr().(*net.TCPAddr).AddrPort())
|
||||
if err != nil {
|
||||
log.Warnln("[Auto Redirect] %v", err)
|
||||
_ = conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
_ = conn.(*net.TCPConn).SetKeepAlive(true)
|
||||
|
||||
in <- inbound.NewSocket(target, conn, C.REDIR)
|
||||
}
|
||||
|
||||
func New(addr string, in chan<- C.ConnContext) (*Listener, error) {
|
||||
l, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rl := &Listener{
|
||||
listener: l,
|
||||
addr: addr,
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
if rl.closed {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
go rl.handleRedir(c, in)
|
||||
}
|
||||
}()
|
||||
|
||||
return rl, nil
|
||||
}
|
||||
@@ -2,8 +2,11 @@ package proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Dreamacro/clash/component/ebpf"
|
||||
"github.com/Dreamacro/clash/listener/autoredir"
|
||||
"github.com/Dreamacro/clash/listener/inner"
|
||||
"github.com/Dreamacro/clash/listener/tun/ipstack/commons"
|
||||
"golang.org/x/exp/slices"
|
||||
"net"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -38,14 +41,19 @@ var (
|
||||
mixedListener *mixed.Listener
|
||||
mixedUDPLister *socks.UDPListener
|
||||
tunStackListener ipstack.Stack
|
||||
tcProgram *ebpf.TcEBpfProgram
|
||||
autoRedirListener *autoredir.Listener
|
||||
autoRedirProgram *ebpf.TcEBpfProgram
|
||||
|
||||
// lock for recreate function
|
||||
socksMux sync.Mutex
|
||||
httpMux sync.Mutex
|
||||
redirMux sync.Mutex
|
||||
tproxyMux sync.Mutex
|
||||
mixedMux sync.Mutex
|
||||
tunMux sync.Mutex
|
||||
socksMux sync.Mutex
|
||||
httpMux sync.Mutex
|
||||
redirMux sync.Mutex
|
||||
tproxyMux sync.Mutex
|
||||
mixedMux sync.Mutex
|
||||
tunMux sync.Mutex
|
||||
autoRedirMux sync.Mutex
|
||||
tcMux sync.Mutex
|
||||
)
|
||||
|
||||
type Ports struct {
|
||||
@@ -356,6 +364,93 @@ func ReCreateTun(tunConf *config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *
|
||||
lastTunConf = tunConf
|
||||
}
|
||||
|
||||
func ReCreateAutoRedir(ifaceNames []string, tcpIn chan<- C.ConnContext, _ chan<- *inbound.PacketAdapter) {
|
||||
autoRedirMux.Lock()
|
||||
defer autoRedirMux.Unlock()
|
||||
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if redirListener != nil {
|
||||
_ = redirListener.Close()
|
||||
redirListener = nil
|
||||
}
|
||||
if autoRedirProgram != nil {
|
||||
autoRedirProgram.Close()
|
||||
autoRedirProgram = nil
|
||||
}
|
||||
log.Errorln("Start auto redirect server error: %s", err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
nicArr := ifaceNames
|
||||
slices.Sort(nicArr)
|
||||
nicArr = slices.Compact(nicArr)
|
||||
|
||||
if redirListener != nil && autoRedirProgram != nil {
|
||||
_ = redirListener.Close()
|
||||
autoRedirProgram.Close()
|
||||
redirListener = nil
|
||||
autoRedirProgram = nil
|
||||
}
|
||||
|
||||
if len(nicArr) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
defaultRouteInterfaceName, err := commons.GetAutoDetectInterface()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
addr := genAddr("*", C.TcpAutoRedirPort, true)
|
||||
|
||||
autoRedirListener, err = autoredir.New(addr, tcpIn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
autoRedirProgram, err = ebpf.NewRedirEBpfProgram(nicArr, autoRedirListener.TCPAddr().Port(), defaultRouteInterfaceName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
autoRedirListener.SetLookupFunc(autoRedirProgram.Lookup)
|
||||
|
||||
log.Infoln("Auto redirect proxy listening at: %s, attached tc ebpf program to interfaces %v", autoRedirListener.Address(), autoRedirProgram.RawNICs())
|
||||
}
|
||||
|
||||
func ReCreateRedirToTun(ifaceNames []string) {
|
||||
tcMux.Lock()
|
||||
defer tcMux.Unlock()
|
||||
|
||||
nicArr := ifaceNames
|
||||
slices.Sort(nicArr)
|
||||
nicArr = slices.Compact(nicArr)
|
||||
|
||||
if tcProgram != nil {
|
||||
tcProgram.Close()
|
||||
tcProgram = nil
|
||||
}
|
||||
|
||||
if len(nicArr) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if lastTunConf == nil || !lastTunConf.Enable {
|
||||
return
|
||||
}
|
||||
|
||||
program, err := ebpf.NewTcEBpfProgram(nicArr, lastTunConf.Device)
|
||||
if err != nil {
|
||||
log.Errorln("Attached tc ebpf program error: %v", err)
|
||||
return
|
||||
}
|
||||
tcProgram = program
|
||||
|
||||
log.Infoln("Attached tc ebpf program to interfaces %v", tcProgram.RawNICs())
|
||||
}
|
||||
|
||||
// GetPorts return the ports of proxy servers
|
||||
func GetPorts() *Ports {
|
||||
ports := &Ports{}
|
||||
|
||||
Reference in New Issue
Block a user