github.com/igoogolx/clash@v1.19.8/listener/listener.go (about) 1 package listener 2 3 import ( 4 "fmt" 5 "net" 6 "strconv" 7 "strings" 8 "sync" 9 10 "github.com/igoogolx/clash/adapter/inbound" 11 "github.com/igoogolx/clash/config" 12 C "github.com/igoogolx/clash/constant" 13 "github.com/igoogolx/clash/listener/http" 14 "github.com/igoogolx/clash/listener/mixed" 15 "github.com/igoogolx/clash/listener/redir" 16 "github.com/igoogolx/clash/listener/socks" 17 "github.com/igoogolx/clash/listener/tproxy" 18 "github.com/igoogolx/clash/listener/tunnel" 19 "github.com/igoogolx/clash/log" 20 21 "github.com/samber/lo" 22 ) 23 24 var ( 25 allowLan = false 26 bindAddress = "*" 27 28 tcpListeners = map[C.Inbound]C.Listener{} 29 udpListeners = map[C.Inbound]C.Listener{} 30 31 tunnelTCPListeners = map[string]*tunnel.Listener{} 32 tunnelUDPListeners = map[string]*tunnel.PacketConn{} 33 34 // lock for recreate function 35 recreateMux sync.Mutex 36 tunnelMux sync.Mutex 37 ) 38 39 type Ports struct { 40 Port int `json:"port"` 41 SocksPort int `json:"socks-port"` 42 RedirPort int `json:"redir-port"` 43 TProxyPort int `json:"tproxy-port"` 44 MixedPort int `json:"mixed-port"` 45 } 46 47 var tcpListenerCreators = map[C.InboundType]tcpListenerCreator{ 48 C.InboundTypeHTTP: http.New, 49 C.InboundTypeSocks: socks.New, 50 C.InboundTypeRedir: redir.New, 51 C.InboundTypeTproxy: tproxy.New, 52 C.InboundTypeMixed: mixed.New, 53 } 54 55 var udpListenerCreators = map[C.InboundType]udpListenerCreator{ 56 C.InboundTypeSocks: socks.NewUDP, 57 C.InboundTypeRedir: tproxy.NewUDP, 58 C.InboundTypeTproxy: tproxy.NewUDP, 59 C.InboundTypeMixed: socks.NewUDP, 60 } 61 62 type ( 63 tcpListenerCreator func(addr string, tcpIn chan<- C.ConnContext) (C.Listener, error) 64 udpListenerCreator func(addr string, udpIn chan<- *inbound.PacketAdapter) (C.Listener, error) 65 ) 66 67 func AllowLan() bool { 68 return allowLan 69 } 70 71 func BindAddress() string { 72 return bindAddress 73 } 74 75 func SetAllowLan(al bool) { 76 allowLan = al 77 } 78 79 func SetBindAddress(host string) { 80 bindAddress = host 81 } 82 83 func createListener(inbound C.Inbound, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { 84 addr := inbound.BindAddress 85 if portIsZero(addr) { 86 return 87 } 88 tcpCreator := tcpListenerCreators[inbound.Type] 89 udpCreator := udpListenerCreators[inbound.Type] 90 if tcpCreator == nil && udpCreator == nil { 91 log.Errorln("inbound type %s is not supported", inbound.Type) 92 return 93 } 94 if tcpCreator != nil { 95 tcpListener, err := tcpCreator(addr, tcpIn) 96 if err != nil { 97 log.Errorln("create addr %s tcp listener error: %v", addr, err) 98 return 99 } 100 tcpListeners[inbound] = tcpListener 101 } 102 if udpCreator != nil { 103 udpListener, err := udpCreator(addr, udpIn) 104 if err != nil { 105 log.Errorln("create addr %s udp listener error: %v", addr, err) 106 return 107 } 108 udpListeners[inbound] = udpListener 109 } 110 log.Infoln("inbound %s created successfully", inbound.ToAlias()) 111 } 112 113 func closeListener(inbound C.Inbound) { 114 listener := tcpListeners[inbound] 115 if listener != nil { 116 if err := listener.Close(); err != nil { 117 log.Errorln("close tcp address `%s` error: %s", inbound.ToAlias(), err.Error()) 118 } 119 delete(tcpListeners, inbound) 120 } 121 listener = udpListeners[inbound] 122 if listener != nil { 123 if err := listener.Close(); err != nil { 124 log.Errorln("close udp address `%s` error: %s", inbound.ToAlias(), err.Error()) 125 } 126 delete(udpListeners, inbound) 127 } 128 } 129 130 func getNeedCloseAndCreateInbound(originInbounds []C.Inbound, newInbounds []C.Inbound) ([]C.Inbound, []C.Inbound) { 131 needCloseMap := map[C.Inbound]bool{} 132 needClose := []C.Inbound{} 133 needCreate := []C.Inbound{} 134 135 for _, inbound := range originInbounds { 136 needCloseMap[inbound] = true 137 } 138 for _, inbound := range newInbounds { 139 if needCloseMap[inbound] { 140 delete(needCloseMap, inbound) 141 } else { 142 needCreate = append(needCreate, inbound) 143 } 144 } 145 for inbound := range needCloseMap { 146 needClose = append(needClose, inbound) 147 } 148 return needClose, needCreate 149 } 150 151 // only recreate inbound config listener 152 func ReCreateListeners(inbounds []C.Inbound, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { 153 newInbounds := []C.Inbound{} 154 newInbounds = append(newInbounds, inbounds...) 155 for _, inbound := range getInbounds() { 156 if inbound.IsFromPortCfg { 157 newInbounds = append(newInbounds, inbound) 158 } 159 } 160 reCreateListeners(newInbounds, tcpIn, udpIn) 161 } 162 163 // only recreate ports config listener 164 func ReCreatePortsListeners(ports Ports, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { 165 newInbounds := []C.Inbound{} 166 newInbounds = append(newInbounds, GetInbounds()...) 167 newInbounds = addPortInbound(newInbounds, C.InboundTypeHTTP, ports.Port) 168 newInbounds = addPortInbound(newInbounds, C.InboundTypeSocks, ports.SocksPort) 169 newInbounds = addPortInbound(newInbounds, C.InboundTypeRedir, ports.RedirPort) 170 newInbounds = addPortInbound(newInbounds, C.InboundTypeTproxy, ports.TProxyPort) 171 newInbounds = addPortInbound(newInbounds, C.InboundTypeMixed, ports.MixedPort) 172 reCreateListeners(newInbounds, tcpIn, udpIn) 173 } 174 175 func addPortInbound(inbounds []C.Inbound, inboundType C.InboundType, port int) []C.Inbound { 176 if port != 0 { 177 inbounds = append(inbounds, C.Inbound{ 178 Type: inboundType, 179 BindAddress: genAddr(bindAddress, port, allowLan), 180 IsFromPortCfg: true, 181 }) 182 } 183 return inbounds 184 } 185 186 func reCreateListeners(inbounds []C.Inbound, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { 187 recreateMux.Lock() 188 defer recreateMux.Unlock() 189 needClose, needCreate := getNeedCloseAndCreateInbound(getInbounds(), inbounds) 190 for _, inbound := range needClose { 191 closeListener(inbound) 192 } 193 for _, inbound := range needCreate { 194 createListener(inbound, tcpIn, udpIn) 195 } 196 } 197 198 func PatchTunnel(tunnels []config.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { 199 tunnelMux.Lock() 200 defer tunnelMux.Unlock() 201 202 type addrProxy struct { 203 network string 204 addr string 205 target string 206 proxy string 207 } 208 209 tcpOld := lo.Map( 210 lo.Keys(tunnelTCPListeners), 211 func(key string, _ int) addrProxy { 212 parts := strings.Split(key, "/") 213 return addrProxy{ 214 network: "tcp", 215 addr: parts[0], 216 target: parts[1], 217 proxy: parts[2], 218 } 219 }, 220 ) 221 udpOld := lo.Map( 222 lo.Keys(tunnelUDPListeners), 223 func(key string, _ int) addrProxy { 224 parts := strings.Split(key, "/") 225 return addrProxy{ 226 network: "udp", 227 addr: parts[0], 228 target: parts[1], 229 proxy: parts[2], 230 } 231 }, 232 ) 233 oldElm := lo.Union(tcpOld, udpOld) 234 235 newElm := lo.FlatMap( 236 tunnels, 237 func(tunnel config.Tunnel, _ int) []addrProxy { 238 return lo.Map( 239 tunnel.Network, 240 func(network string, _ int) addrProxy { 241 return addrProxy{ 242 network: network, 243 addr: tunnel.Address, 244 target: tunnel.Target, 245 proxy: tunnel.Proxy, 246 } 247 }, 248 ) 249 }, 250 ) 251 252 needClose, needCreate := lo.Difference(oldElm, newElm) 253 254 for _, elm := range needClose { 255 key := fmt.Sprintf("%s/%s/%s", elm.addr, elm.target, elm.proxy) 256 if elm.network == "tcp" { 257 tunnelTCPListeners[key].Close() 258 delete(tunnelTCPListeners, key) 259 } else { 260 tunnelUDPListeners[key].Close() 261 delete(tunnelUDPListeners, key) 262 } 263 } 264 265 for _, elm := range needCreate { 266 key := fmt.Sprintf("%s/%s/%s", elm.addr, elm.target, elm.proxy) 267 if elm.network == "tcp" { 268 l, err := tunnel.New(elm.addr, elm.target, elm.proxy, tcpIn) 269 if err != nil { 270 log.Errorln("Start tunnel %s error: %s", elm.target, err.Error()) 271 continue 272 } 273 tunnelTCPListeners[key] = l 274 log.Infoln("Tunnel(tcp/%s) proxy %s listening at: %s", elm.target, elm.proxy, tunnelTCPListeners[key].Address()) 275 } else { 276 l, err := tunnel.NewUDP(elm.addr, elm.target, elm.proxy, udpIn) 277 if err != nil { 278 log.Errorln("Start tunnel %s error: %s", elm.target, err.Error()) 279 continue 280 } 281 tunnelUDPListeners[key] = l 282 log.Infoln("Tunnel(udp/%s) proxy %s listening at: %s", elm.target, elm.proxy, tunnelUDPListeners[key].Address()) 283 } 284 } 285 } 286 287 func GetInbounds() []C.Inbound { 288 return lo.Filter(getInbounds(), func(inbound C.Inbound, idx int) bool { 289 return !inbound.IsFromPortCfg 290 }) 291 } 292 293 // GetInbounds return the inbounds of proxy servers 294 func getInbounds() []C.Inbound { 295 var inbounds []C.Inbound 296 for inbound := range tcpListeners { 297 inbounds = append(inbounds, inbound) 298 } 299 for inbound := range udpListeners { 300 if _, ok := tcpListeners[inbound]; !ok { 301 inbounds = append(inbounds, inbound) 302 } 303 } 304 return inbounds 305 } 306 307 // GetPorts return the ports of proxy servers 308 func GetPorts() *Ports { 309 ports := &Ports{} 310 for _, inbound := range getInbounds() { 311 fillPort(inbound, ports) 312 } 313 return ports 314 } 315 316 func fillPort(inbound C.Inbound, ports *Ports) { 317 if inbound.IsFromPortCfg { 318 port := getPort(inbound.BindAddress) 319 switch inbound.Type { 320 case C.InboundTypeHTTP: 321 ports.Port = port 322 case C.InboundTypeSocks: 323 ports.SocksPort = port 324 case C.InboundTypeTproxy: 325 ports.TProxyPort = port 326 case C.InboundTypeRedir: 327 ports.RedirPort = port 328 case C.InboundTypeMixed: 329 ports.MixedPort = port 330 default: 331 // do nothing 332 } 333 } 334 } 335 336 func portIsZero(addr string) bool { 337 _, port, err := net.SplitHostPort(addr) 338 if port == "0" || port == "" || err != nil { 339 return true 340 } 341 return false 342 } 343 344 func genAddr(host string, port int, allowLan bool) string { 345 if allowLan { 346 if host == "*" { 347 return fmt.Sprintf(":%d", port) 348 } 349 return fmt.Sprintf("%s:%d", host, port) 350 } 351 352 return fmt.Sprintf("127.0.0.1:%d", port) 353 } 354 355 func getPort(addr string) int { 356 _, portStr, err := net.SplitHostPort(addr) 357 if err != nil { 358 return 0 359 } 360 port, err := strconv.Atoi(portStr) 361 if err != nil { 362 return 0 363 } 364 return port 365 }