support ebpf

This commit is contained in:
zhudan
2022-07-29 09:08:35 +08:00
parent 57a15088c2
commit 31f4d20477
30 changed files with 6270 additions and 8 deletions

86
listener/autoredir/tcp.go Normal file
View 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
}

View File

@@ -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{}