package proxy import ( "fmt" "golang.org/x/exp/slices" "net" "sort" "strconv" "sync" "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/component/ebpf" "github.com/Dreamacro/clash/config" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/listener/autoredir" "github.com/Dreamacro/clash/listener/http" "github.com/Dreamacro/clash/listener/inner" "github.com/Dreamacro/clash/listener/mixed" "github.com/Dreamacro/clash/listener/redir" "github.com/Dreamacro/clash/listener/sing_shadowsocks" "github.com/Dreamacro/clash/listener/sing_tun" "github.com/Dreamacro/clash/listener/sing_vmess" "github.com/Dreamacro/clash/listener/socks" "github.com/Dreamacro/clash/listener/tproxy" "github.com/Dreamacro/clash/listener/tunnel" "github.com/Dreamacro/clash/log" ) var ( allowLan = false bindAddress = "*" inboundTfo = false socksListener *socks.Listener socksUDPListener *socks.UDPListener httpListener *http.Listener redirListener *redir.Listener redirUDPListener *tproxy.UDPListener tproxyListener *tproxy.Listener tproxyUDPListener *tproxy.UDPListener mixedListener *mixed.Listener mixedUDPLister *socks.UDPListener tunLister *sing_tun.Listener shadowSocksListener C.AdvanceListener vmessListener *sing_vmess.Listener tcpTunListener *tunnel.Listener udpTunListener *tunnel.UdpListener autoRedirListener *autoredir.Listener autoRedirProgram *ebpf.TcEBpfProgram tcProgram *ebpf.TcEBpfProgram // lock for recreate function socksMux sync.Mutex httpMux sync.Mutex redirMux sync.Mutex tproxyMux sync.Mutex mixedMux sync.Mutex tunMux sync.Mutex ssMux sync.Mutex vmessMux sync.Mutex tcpTunMux sync.Mutex udpTunMux sync.Mutex autoRedirMux sync.Mutex tcMux sync.Mutex LastTunConf config.Tun ) type Ports struct { Port int `json:"port"` SocksPort int `json:"socks-port"` RedirPort int `json:"redir-port"` TProxyPort int `json:"tproxy-port"` MixedPort int `json:"mixed-port"` ShadowSocksConfig string `json:"ss-config"` VmessConfig string `json:"vmess-config"` TcpTunConfig string `json:"tcptun-config"` UdpTunConfig string `json:"udptun-config"` } func GetTunConf() config.Tun { if tunLister == nil { return config.Tun{ Enable: false, } } return tunLister.Config() } func AllowLan() bool { return allowLan } func BindAddress() string { return bindAddress } func SetAllowLan(al bool) { allowLan = al } func SetBindAddress(host string) { bindAddress = host } func SetInboundTfo(itfo bool) { inboundTfo = itfo } func NewInner(tcpIn chan<- C.ConnContext) { inner.New(tcpIn) } func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) { httpMux.Lock() defer httpMux.Unlock() var err error defer func() { if err != nil { log.Errorln("Start HTTP server error: %s", err.Error()) } }() addr := genAddr(bindAddress, port, allowLan) if httpListener != nil { if httpListener.RawAddress() == addr { return } httpListener.Close() httpListener = nil } if portIsZero(addr) { return } httpListener, err = http.New(addr, inboundTfo, tcpIn) if err != nil { log.Errorln("Start HTTP server error: %s", err.Error()) return } log.Infoln("HTTP proxy listening at: %s", httpListener.Address()) } func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { socksMux.Lock() defer socksMux.Unlock() var err error defer func() { if err != nil { log.Errorln("Start SOCKS server error: %s", err.Error()) } }() addr := genAddr(bindAddress, port, allowLan) shouldTCPIgnore := false shouldUDPIgnore := false if socksListener != nil { if socksListener.RawAddress() != addr { socksListener.Close() socksListener = nil } else { shouldTCPIgnore = true } } if socksUDPListener != nil { if socksUDPListener.RawAddress() != addr { socksUDPListener.Close() socksUDPListener = nil } else { shouldUDPIgnore = true } } if shouldTCPIgnore && shouldUDPIgnore { return } if portIsZero(addr) { return } tcpListener, err := socks.New(addr, inboundTfo, tcpIn) if err != nil { return } udpListener, err := socks.NewUDP(addr, udpIn) if err != nil { tcpListener.Close() return } socksListener = tcpListener socksUDPListener = udpListener log.Infoln("SOCKS proxy listening at: %s", socksListener.Address()) } func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { redirMux.Lock() defer redirMux.Unlock() var err error defer func() { if err != nil { log.Errorln("Start Redir server error: %s", err.Error()) } }() addr := genAddr(bindAddress, port, allowLan) if redirListener != nil { if redirListener.RawAddress() == addr { return } redirListener.Close() redirListener = nil } if redirUDPListener != nil { if redirUDPListener.RawAddress() == addr { return } redirUDPListener.Close() redirUDPListener = nil } if portIsZero(addr) { return } redirListener, err = redir.New(addr, tcpIn) if err != nil { return } redirUDPListener, err = tproxy.NewUDP(addr, udpIn) if err != nil { log.Warnln("Failed to start Redir UDP Listener: %s", err) } log.Infoln("Redirect proxy listening at: %s", redirListener.Address()) } func ReCreateShadowSocks(shadowSocksConfig string, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { ssMux.Lock() defer ssMux.Unlock() var err error defer func() { if err != nil { log.Errorln("Start ShadowSocks server error: %s", err.Error()) } }() shouldIgnore := false if shadowSocksListener != nil { if shadowSocksListener.Config() != shadowSocksConfig { shadowSocksListener.Close() shadowSocksListener = nil } else { shouldIgnore = true } } if shouldIgnore { return } if len(shadowSocksConfig) == 0 { return } listener, err := sing_shadowsocks.New(shadowSocksConfig, inboundTfo, tcpIn, udpIn) if err != nil { return } shadowSocksListener = listener return } func ReCreateVmess(vmessConfig string, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { vmessMux.Lock() defer vmessMux.Unlock() var err error defer func() { if err != nil { log.Errorln("Start Vmess server error: %s", err.Error()) } }() shouldIgnore := false if vmessListener != nil { if vmessListener.Config() != vmessConfig { vmessListener.Close() vmessListener = nil } else { shouldIgnore = true } } if shouldIgnore { return } if len(vmessConfig) == 0 { return } listener, err := sing_vmess.New(vmessConfig, inboundTfo, tcpIn, udpIn) if err != nil { return } vmessListener = listener return } func ReCreateTcpTun(config string, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { tcpTunMux.Lock() defer tcpTunMux.Unlock() shouldIgnore := false var err error defer func() { if err != nil { log.Errorln("Start TcpTun server error: %s", err.Error()) } }() if tcpTunListener != nil { if tcpTunListener.Config() != config { tcpTunListener.Close() tcpTunListener = nil } else { shouldIgnore = true } } if shouldIgnore { return } tcpListener, err := tunnel.New(config, tcpIn) if err != nil { return } tcpTunListener = tcpListener return } func ReCreateUdpTun(config string, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { udpTunMux.Lock() defer udpTunMux.Unlock() shouldIgnore := false var err error defer func() { if err != nil { log.Errorln("Start UdpTun server error: %s", err.Error()) } }() if udpTunListener != nil { if udpTunListener.Config() != config { udpTunListener.Close() udpTunListener = nil } else { shouldIgnore = true } } if shouldIgnore { return } udpListener, err := tunnel.NewUdp(config, udpIn) if err != nil { return } udpTunListener = udpListener return } func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { tproxyMux.Lock() defer tproxyMux.Unlock() var err error defer func() { if err != nil { log.Errorln("Start TProxy server error: %s", err.Error()) } }() addr := genAddr(bindAddress, port, allowLan) if tproxyListener != nil { if tproxyListener.RawAddress() == addr { return } tproxyListener.Close() tproxyListener = nil } if tproxyUDPListener != nil { if tproxyUDPListener.RawAddress() == addr { return } tproxyUDPListener.Close() tproxyUDPListener = nil } if portIsZero(addr) { return } tproxyListener, err = tproxy.New(addr, tcpIn) if err != nil { return } tproxyUDPListener, err = tproxy.NewUDP(addr, udpIn) if err != nil { log.Warnln("Failed to start TProxy UDP Listener: %s", err) } log.Infoln("TProxy server listening at: %s", tproxyListener.Address()) } func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { mixedMux.Lock() defer mixedMux.Unlock() var err error defer func() { if err != nil { log.Errorln("Start Mixed(http+socks) server error: %s", err.Error()) } }() addr := genAddr(bindAddress, port, allowLan) shouldTCPIgnore := false shouldUDPIgnore := false if mixedListener != nil { if mixedListener.RawAddress() != addr { mixedListener.Close() mixedListener = nil } else { shouldTCPIgnore = true } } if mixedUDPLister != nil { if mixedUDPLister.RawAddress() != addr { mixedUDPLister.Close() mixedUDPLister = nil } else { shouldUDPIgnore = true } } if shouldTCPIgnore && shouldUDPIgnore { return } if portIsZero(addr) { return } mixedListener, err = mixed.New(addr, inboundTfo, tcpIn) if err != nil { return } mixedUDPLister, err = socks.NewUDP(addr, udpIn) if err != nil { mixedListener.Close() return } log.Infoln("Mixed(http+socks) proxy listening at: %s", mixedListener.Address()) } func ReCreateTun(tunConf config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { tunMux.Lock() defer func() { LastTunConf = tunConf tunMux.Unlock() }() var err error defer func() { if err != nil { log.Errorln("Start TUN listening error: %s", err.Error()) Cleanup(false) } }() if !hasTunConfigChange(&tunConf) { if tunLister != nil { tunLister.FlushDefaultInterface() } return } Cleanup(true) if !tunConf.Enable { return } tunLister, err = sing_tun.New(tunConf, tcpIn, udpIn) } 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 } tunConf := GetTunConf() if !tunConf.Enable { return } program, err := ebpf.NewTcEBpfProgram(nicArr, tunConf.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()) } 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 autoRedirListener != nil { _ = autoRedirListener.Close() autoRedirListener = 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 autoRedirListener != nil && autoRedirProgram != nil { _ = autoRedirListener.Close() autoRedirProgram.Close() autoRedirListener = nil autoRedirProgram = nil } if len(nicArr) == 0 { return } defaultRouteInterfaceName, err := ebpf.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()) } // GetPorts return the ports of proxy servers func GetPorts() *Ports { ports := &Ports{} if httpListener != nil { _, portStr, _ := net.SplitHostPort(httpListener.Address()) port, _ := strconv.Atoi(portStr) ports.Port = port } if socksListener != nil { _, portStr, _ := net.SplitHostPort(socksListener.Address()) port, _ := strconv.Atoi(portStr) ports.SocksPort = port } if redirListener != nil { _, portStr, _ := net.SplitHostPort(redirListener.Address()) port, _ := strconv.Atoi(portStr) ports.RedirPort = port } if tproxyListener != nil { _, portStr, _ := net.SplitHostPort(tproxyListener.Address()) port, _ := strconv.Atoi(portStr) ports.TProxyPort = port } if mixedListener != nil { _, portStr, _ := net.SplitHostPort(mixedListener.Address()) port, _ := strconv.Atoi(portStr) ports.MixedPort = port } if shadowSocksListener != nil { ports.ShadowSocksConfig = shadowSocksListener.Config() } if vmessListener != nil { ports.VmessConfig = vmessListener.Config() } if tcpTunListener != nil { ports.TcpTunConfig = tcpTunListener.Config() } if udpTunListener != nil { ports.UdpTunConfig = udpTunListener.Config() } return ports } func portIsZero(addr string) bool { _, port, err := net.SplitHostPort(addr) if port == "0" || port == "" || err != nil { return true } return false } func genAddr(host string, port int, allowLan bool) string { if allowLan { if host == "*" { return fmt.Sprintf(":%d", port) } return fmt.Sprintf("%s:%d", host, port) } return fmt.Sprintf("127.0.0.1:%d", port) } func hasTunConfigChange(tunConf *config.Tun) bool { if LastTunConf.Enable != tunConf.Enable || LastTunConf.Device != tunConf.Device || LastTunConf.Stack != tunConf.Stack || LastTunConf.AutoRoute != tunConf.AutoRoute || LastTunConf.AutoDetectInterface != tunConf.AutoDetectInterface || LastTunConf.MTU != tunConf.MTU || LastTunConf.StrictRoute != tunConf.StrictRoute || LastTunConf.EndpointIndependentNat != tunConf.EndpointIndependentNat || LastTunConf.UDPTimeout != tunConf.UDPTimeout { return true } if len(LastTunConf.DNSHijack) != len(tunConf.DNSHijack) { return true } sort.Slice(tunConf.DNSHijack, func(i, j int) bool { return tunConf.DNSHijack[i].Addr().Less(tunConf.DNSHijack[j].Addr()) }) sort.Slice(tunConf.Inet4Address, func(i, j int) bool { return tunConf.Inet4Address[i].Build().String() < tunConf.Inet4Address[j].Build().String() }) sort.Slice(tunConf.Inet6Address, func(i, j int) bool { return tunConf.Inet6Address[i].Build().String() < tunConf.Inet6Address[j].Build().String() }) sort.Slice(tunConf.Inet4RouteAddress, func(i, j int) bool { return tunConf.Inet4RouteAddress[i].Build().String() < tunConf.Inet4RouteAddress[j].Build().String() }) sort.Slice(tunConf.Inet6RouteAddress, func(i, j int) bool { return tunConf.Inet6RouteAddress[i].Build().String() < tunConf.Inet6RouteAddress[j].Build().String() }) sort.Slice(tunConf.IncludeUID, func(i, j int) bool { return tunConf.IncludeUID[i] < tunConf.IncludeUID[j] }) sort.Slice(tunConf.IncludeUIDRange, func(i, j int) bool { return tunConf.IncludeUIDRange[i] < tunConf.IncludeUIDRange[j] }) sort.Slice(tunConf.ExcludeUID, func(i, j int) bool { return tunConf.ExcludeUID[i] < tunConf.ExcludeUID[j] }) sort.Slice(tunConf.ExcludeUIDRange, func(i, j int) bool { return tunConf.ExcludeUIDRange[i] < tunConf.ExcludeUIDRange[j] }) sort.Slice(tunConf.IncludeAndroidUser, func(i, j int) bool { return tunConf.IncludeAndroidUser[i] < tunConf.IncludeAndroidUser[j] }) sort.Slice(tunConf.IncludePackage, func(i, j int) bool { return tunConf.IncludePackage[i] < tunConf.IncludePackage[j] }) sort.Slice(tunConf.ExcludePackage, func(i, j int) bool { return tunConf.ExcludePackage[i] < tunConf.ExcludePackage[j] }) if !slices.Equal(tunConf.DNSHijack, LastTunConf.DNSHijack) || !slices.Equal(tunConf.Inet4Address, LastTunConf.Inet4Address) || !slices.Equal(tunConf.Inet6Address, LastTunConf.Inet6Address) || !slices.Equal(tunConf.Inet4RouteAddress, LastTunConf.Inet4RouteAddress) || !slices.Equal(tunConf.Inet6RouteAddress, LastTunConf.Inet6RouteAddress) || !slices.Equal(tunConf.IncludeUID, LastTunConf.IncludeUID) || !slices.Equal(tunConf.IncludeUIDRange, LastTunConf.IncludeUIDRange) || !slices.Equal(tunConf.ExcludeUID, LastTunConf.ExcludeUID) || !slices.Equal(tunConf.ExcludeUIDRange, LastTunConf.ExcludeUIDRange) || !slices.Equal(tunConf.IncludeAndroidUser, LastTunConf.IncludeAndroidUser) || !slices.Equal(tunConf.IncludePackage, LastTunConf.IncludePackage) || !slices.Equal(tunConf.ExcludePackage, LastTunConf.ExcludePackage) { return true } return false } func Cleanup(wait bool) { if tunLister != nil { tunLister.Close() tunLister = nil } LastTunConf = config.Tun{} }