github.com/yaling888/clash@v1.53.0/listener/tun/tun_adapter.go (about) 1 package tun 2 3 import ( 4 "errors" 5 "fmt" 6 "net/netip" 7 "net/url" 8 "runtime" 9 "strings" 10 11 "github.com/phuslu/log" 12 13 "github.com/yaling888/clash/adapter/inbound" 14 "github.com/yaling888/clash/common/cmd" 15 "github.com/yaling888/clash/component/dialer" 16 "github.com/yaling888/clash/component/resolver" 17 C "github.com/yaling888/clash/constant" 18 "github.com/yaling888/clash/listener/tun/device" 19 "github.com/yaling888/clash/listener/tun/device/tun" 20 "github.com/yaling888/clash/listener/tun/ipstack" 21 "github.com/yaling888/clash/listener/tun/ipstack/commons" 22 "github.com/yaling888/clash/listener/tun/ipstack/gvisor" 23 "github.com/yaling888/clash/listener/tun/ipstack/system" 24 ) 25 26 // New TunAdapter 27 func New( 28 tunConf *C.Tun, 29 tcpIn chan<- C.ConnContext, 30 udpIn chan<- *inbound.PacketAdapter, 31 tunChangeCallback C.TUNChangeCallback, 32 ) (ipstack.Stack, error) { 33 var ( 34 tunAddress = netip.Prefix{} 35 devName = tunConf.Device 36 stackType = tunConf.Stack 37 autoRoute = tunConf.AutoRoute 38 mtu = 1<<16 - 1 39 40 tunDevice device.Device 41 tunStack ipstack.Stack 42 43 err error 44 ) 45 46 defer func() { 47 if err != nil { 48 if tunStack != nil { 49 _ = tunStack.Close() 50 } else if tunDevice != nil { 51 _ = tunDevice.Close() 52 } 53 } 54 }() 55 56 defaultInterface := dialer.DefaultInterface.Load() 57 if tunConf.AutoDetectInterface { 58 commons.SetTunChangeCallback(tunChangeCallback) 59 commons.StartDefaultInterfaceChangeMonitor() 60 if defaultInterface == "" { 61 commons.SetTunStatus(C.TunPaused) 62 return nil, nil 63 } 64 } else if defaultInterface == "" { 65 return nil, errors.New( 66 "default interface not found, please assign value to `interface-name` or enable `auto-detect-interface`", 67 ) 68 } 69 70 if devName == "" { 71 devName = generateDeviceName() 72 } 73 74 if tunConf.TunAddressPrefix != nil { 75 tunAddress = *tunConf.TunAddressPrefix 76 } 77 78 if !tunAddress.IsValid() || !tunAddress.Addr().Is4() { 79 tunAddress = netip.MustParsePrefix("198.18.0.1/16") 80 } 81 82 // open tun device 83 tunDevice, err = parseDevice(devName, uint32(mtu)) 84 if err != nil { 85 return nil, fmt.Errorf("can't open tun: %w", err) 86 } 87 88 devName = tunDevice.Name() 89 90 // new ip stack 91 switch stackType { 92 case C.TunGvisor: 93 err = tunDevice.UseEndpoint() 94 if err != nil { 95 return nil, fmt.Errorf("can't attach endpoint to tun: %w", err) 96 } 97 98 tunStack, err = gvisor.New(tunDevice, tunConf.DNSHijack, tunAddress, tcpIn, udpIn) 99 if err != nil { 100 return nil, fmt.Errorf("can't New gvisor stack: %w", err) 101 } 102 case C.TunSystem: 103 err = tunDevice.UseIOBased() 104 if err != nil { 105 return nil, fmt.Errorf("can't New system stack: %w", err) 106 } 107 108 tunStack, err = system.New(tunDevice, tunConf.DNSHijack, tunAddress, tcpIn, udpIn) 109 if err != nil { 110 return nil, fmt.Errorf("can't New system stack: %w", err) 111 } 112 default: 113 return nil, errors.New("unknown ip stack") 114 } 115 116 // setting address and routing 117 err = commons.ConfigInterfaceAddress(tunDevice, tunAddress, mtu, autoRoute) 118 if err != nil { 119 return nil, fmt.Errorf("setting interface address and routing failed: %w", err) 120 } 121 122 if autoRoute { 123 resolver.DisableIPv6 = true 124 } 125 126 tunConf.Device = devName 127 setAtLatest(stackType, devName) 128 129 log.Info(). 130 Str("iface", devName). 131 NetIPAddr("gateway", tunAddress.Masked().Addr().Next()). 132 Uint32("mtu", tunDevice.MTU()). 133 Int("batchSize", tunDevice.BatchSize()). 134 Bool("autoRoute", autoRoute). 135 Bool("autoDetectInterface", tunConf.AutoDetectInterface). 136 Str("ipStack", stackType.String()). 137 Msg("[Inbound] tun listening") 138 return tunStack, nil 139 } 140 141 func generateDeviceName() string { 142 switch runtime.GOOS { 143 case "darwin": 144 return tun.Driver + "://utun" 145 case "windows": 146 return tun.Driver + "://Clash" 147 default: 148 return tun.Driver + "://clash0" 149 } 150 } 151 152 func parseDevice(s string, mtu uint32) (device.Device, error) { 153 if !strings.Contains(s, "://") { 154 s = fmt.Sprintf("%s://%s", tun.Driver /* default driver */, s) 155 } 156 157 u, err := url.Parse(s) 158 if err != nil { 159 return nil, err 160 } 161 162 name := u.Host 163 return tun.Open(name, mtu) 164 } 165 166 func setAtLatest(stackType C.TUNStack, devName string) { 167 switch runtime.GOOS { 168 case "darwin": 169 // _, _ = cmd.ExecCmd("/usr/sbin/sysctl -w net.inet.ip.forwarding=1") 170 // _, _ = cmd.ExecCmd("/usr/sbin/sysctl -w net.inet6.ip6.forwarding=1") 171 _, _ = cmd.ExecCmd("/bin/launchctl limit maxfiles 10240 unlimited") 172 case "windows": 173 if stackType != C.TunSystem { 174 return 175 } 176 _, _ = cmd.ExecCmd("ipconfig /renew") 177 case "linux": 178 _, _ = cmd.ExecCmd("sysctl -w net.ipv4.ip_forward=1") 179 _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.forwarding=1") 180 _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.accept_local=1") 181 _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.accept_redirects=1") 182 _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.rp_filter=0") 183 _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.forwarding=1", devName)) 184 _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.accept_local=1", devName)) 185 _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.accept_redirects=1", devName)) 186 _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.rp_filter=0", devName)) 187 //_, _ = cmd.ExecCmd("iptables -t filter -P FORWARD ACCEPT") 188 } 189 }