github.com/metacubex/mihomo@v1.18.5/listener/tproxy/tproxy_iptables.go (about) 1 package tproxy 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "runtime" 8 9 "github.com/metacubex/mihomo/common/cmd" 10 "github.com/metacubex/mihomo/component/dialer" 11 "github.com/metacubex/mihomo/log" 12 ) 13 14 var ( 15 dnsPort uint16 16 tProxyPort uint16 17 interfaceName string 18 DnsRedirect bool 19 ) 20 21 const ( 22 PROXY_FWMARK = "0x2d0" 23 PROXY_ROUTE_TABLE = "0x2d0" 24 ) 25 26 func SetTProxyIPTables(ifname string, bypass []string, tport uint16, dnsredir bool, dport uint16) error { 27 if _, err := cmd.ExecCmd("iptables -V"); err != nil { 28 return fmt.Errorf("current operations system [%s] are not support iptables or command iptables does not exist", runtime.GOOS) 29 } 30 31 if ifname == "" { 32 return errors.New("the 'interface-name' can not be empty") 33 } 34 35 interfaceName = ifname 36 tProxyPort = tport 37 DnsRedirect = dnsredir 38 dnsPort = dport 39 40 // add route 41 execCmd(fmt.Sprintf("ip -f inet rule add fwmark %s lookup %s", PROXY_FWMARK, PROXY_ROUTE_TABLE)) 42 execCmd(fmt.Sprintf("ip -f inet route add local default dev %s table %s", interfaceName, PROXY_ROUTE_TABLE)) 43 44 // set FORWARD 45 if interfaceName != "lo" { 46 execCmd("sysctl -w net.ipv4.ip_forward=1") 47 execCmd(fmt.Sprintf("iptables -t filter -A FORWARD -o %s -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT", interfaceName)) 48 execCmd(fmt.Sprintf("iptables -t filter -A FORWARD -o %s -j ACCEPT", interfaceName)) 49 execCmd(fmt.Sprintf("iptables -t filter -A FORWARD -i %s ! -o %s -j ACCEPT", interfaceName, interfaceName)) 50 execCmd(fmt.Sprintf("iptables -t filter -A FORWARD -i %s -o %s -j ACCEPT", interfaceName, interfaceName)) 51 } 52 53 // set mihomo divert 54 execCmd("iptables -t mangle -N mihomo_divert") 55 execCmd("iptables -t mangle -F mihomo_divert") 56 execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_divert -j MARK --set-mark %s", PROXY_FWMARK)) 57 execCmd("iptables -t mangle -A mihomo_divert -j ACCEPT") 58 59 // set pre routing 60 execCmd("iptables -t mangle -N mihomo_prerouting") 61 execCmd("iptables -t mangle -F mihomo_prerouting") 62 execCmd("iptables -t mangle -A mihomo_prerouting -s 172.17.0.0/16 -j RETURN") 63 if DnsRedirect { 64 execCmd("iptables -t mangle -A mihomo_prerouting -p udp --dport 53 -j ACCEPT") 65 execCmd("iptables -t mangle -A mihomo_prerouting -p tcp --dport 53 -j ACCEPT") 66 } 67 execCmd("iptables -t mangle -A mihomo_prerouting -m addrtype --dst-type LOCAL -j RETURN") 68 addLocalnetworkToChain("mihomo_prerouting", bypass) 69 execCmd("iptables -t mangle -A mihomo_prerouting -p tcp -m socket -j mihomo_divert") 70 execCmd("iptables -t mangle -A mihomo_prerouting -p udp -m socket -j mihomo_divert") 71 execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_prerouting -p tcp -j TPROXY --on-port %d --tproxy-mark %s/%s", tProxyPort, PROXY_FWMARK, PROXY_FWMARK)) 72 execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_prerouting -p udp -j TPROXY --on-port %d --tproxy-mark %s/%s", tProxyPort, PROXY_FWMARK, PROXY_FWMARK)) 73 execCmd("iptables -t mangle -A PREROUTING -j mihomo_prerouting") 74 75 if DnsRedirect { 76 execCmd(fmt.Sprintf("iptables -t nat -I PREROUTING ! -s 172.17.0.0/16 ! -d 127.0.0.0/8 -p tcp --dport 53 -j REDIRECT --to %d", dnsPort)) 77 execCmd(fmt.Sprintf("iptables -t nat -I PREROUTING ! -s 172.17.0.0/16 ! -d 127.0.0.0/8 -p udp --dport 53 -j REDIRECT --to %d", dnsPort)) 78 } 79 80 // set post routing 81 if interfaceName != "lo" { 82 execCmd(fmt.Sprintf("iptables -t nat -A POSTROUTING -o %s -m addrtype ! --src-type LOCAL -j MASQUERADE", interfaceName)) 83 } 84 85 // set output 86 execCmd("iptables -t mangle -N mihomo_output") 87 execCmd("iptables -t mangle -F mihomo_output") 88 execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_output -m mark --mark %#x -j RETURN", dialer.DefaultRoutingMark.Load())) 89 if DnsRedirect { 90 execCmd("iptables -t mangle -A mihomo_output -p udp -m multiport --dports 53,123,137 -j ACCEPT") 91 execCmd("iptables -t mangle -A mihomo_output -p tcp --dport 53 -j ACCEPT") 92 } 93 execCmd("iptables -t mangle -A mihomo_output -m addrtype --dst-type LOCAL -j RETURN") 94 execCmd("iptables -t mangle -A mihomo_output -m addrtype --dst-type BROADCAST -j RETURN") 95 addLocalnetworkToChain("mihomo_output", bypass) 96 execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_output -p tcp -j MARK --set-mark %s", PROXY_FWMARK)) 97 execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_output -p udp -j MARK --set-mark %s", PROXY_FWMARK)) 98 execCmd(fmt.Sprintf("iptables -t mangle -I OUTPUT -o %s -j mihomo_output", interfaceName)) 99 100 // set dns output 101 if DnsRedirect { 102 execCmd("iptables -t nat -N mihomo_dns_output") 103 execCmd("iptables -t nat -F mihomo_dns_output") 104 execCmd(fmt.Sprintf("iptables -t nat -A mihomo_dns_output -m mark --mark %#x -j RETURN", dialer.DefaultRoutingMark.Load())) 105 execCmd("iptables -t nat -A mihomo_dns_output -s 172.17.0.0/16 -j RETURN") 106 execCmd(fmt.Sprintf("iptables -t nat -A mihomo_dns_output -p udp -j REDIRECT --to-ports %d", dnsPort)) 107 execCmd(fmt.Sprintf("iptables -t nat -A mihomo_dns_output -p tcp -j REDIRECT --to-ports %d", dnsPort)) 108 execCmd("iptables -t nat -I OUTPUT -p tcp --dport 53 -j mihomo_dns_output") 109 execCmd("iptables -t nat -I OUTPUT -p udp --dport 53 -j mihomo_dns_output") 110 } 111 112 return nil 113 } 114 115 func CleanupTProxyIPTables() { 116 if runtime.GOOS != "linux" || interfaceName == "" || tProxyPort == 0 { 117 return 118 } 119 120 log.Warnln("Cleanup tproxy linux iptables") 121 122 if int(dialer.DefaultRoutingMark.Load()) == 2158 { 123 dialer.DefaultRoutingMark.Store(0) 124 } 125 126 if _, err := cmd.ExecCmd("iptables -t mangle -L mihomo_divert"); err != nil { 127 return 128 } 129 130 // clean route 131 execCmd(fmt.Sprintf("ip -f inet rule del fwmark %s lookup %s", PROXY_FWMARK, PROXY_ROUTE_TABLE)) 132 execCmd(fmt.Sprintf("ip -f inet route del local default dev %s table %s", interfaceName, PROXY_ROUTE_TABLE)) 133 134 // clean FORWARD 135 if interfaceName != "lo" { 136 execCmd(fmt.Sprintf("iptables -t filter -D FORWARD -i %s ! -o %s -j ACCEPT", interfaceName, interfaceName)) 137 execCmd(fmt.Sprintf("iptables -t filter -D FORWARD -i %s -o %s -j ACCEPT", interfaceName, interfaceName)) 138 execCmd(fmt.Sprintf("iptables -t filter -D FORWARD -o %s -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT", interfaceName)) 139 execCmd(fmt.Sprintf("iptables -t filter -D FORWARD -o %s -j ACCEPT", interfaceName)) 140 } 141 142 // clean PREROUTING 143 if DnsRedirect { 144 execCmd(fmt.Sprintf("iptables -t nat -D PREROUTING ! -s 172.17.0.0/16 ! -d 127.0.0.0/8 -p tcp --dport 53 -j REDIRECT --to %d", dnsPort)) 145 execCmd(fmt.Sprintf("iptables -t nat -D PREROUTING ! -s 172.17.0.0/16 ! -d 127.0.0.0/8 -p udp --dport 53 -j REDIRECT --to %d", dnsPort)) 146 } 147 execCmd("iptables -t mangle -D PREROUTING -j mihomo_prerouting") 148 149 // clean POSTROUTING 150 if interfaceName != "lo" { 151 execCmd(fmt.Sprintf("iptables -t nat -D POSTROUTING -o %s -m addrtype ! --src-type LOCAL -j MASQUERADE", interfaceName)) 152 } 153 154 // clean OUTPUT 155 execCmd(fmt.Sprintf("iptables -t mangle -D OUTPUT -o %s -j mihomo_output", interfaceName)) 156 if DnsRedirect { 157 execCmd("iptables -t nat -D OUTPUT -p tcp --dport 53 -j mihomo_dns_output") 158 execCmd("iptables -t nat -D OUTPUT -p udp --dport 53 -j mihomo_dns_output") 159 } 160 161 // clean chain 162 execCmd("iptables -t mangle -F mihomo_prerouting") 163 execCmd("iptables -t mangle -X mihomo_prerouting") 164 execCmd("iptables -t mangle -F mihomo_divert") 165 execCmd("iptables -t mangle -X mihomo_divert") 166 execCmd("iptables -t mangle -F mihomo_output") 167 execCmd("iptables -t mangle -X mihomo_output") 168 if DnsRedirect { 169 execCmd("iptables -t nat -F mihomo_dns_output") 170 execCmd("iptables -t nat -X mihomo_dns_output") 171 } 172 interfaceName = "" 173 tProxyPort = 0 174 dnsPort = 0 175 } 176 177 func addLocalnetworkToChain(chain string, bypass []string) { 178 for _, bp := range bypass { 179 _, _, err := net.ParseCIDR(bp) 180 if err != nil { 181 log.Warnln("[IPTABLES] %s", err) 182 continue 183 } 184 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d %s -j RETURN", chain, bp)) 185 } 186 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 0.0.0.0/8 -j RETURN", chain)) 187 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 10.0.0.0/8 -j RETURN", chain)) 188 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 100.64.0.0/10 -j RETURN", chain)) 189 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 127.0.0.0/8 -j RETURN", chain)) 190 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 169.254.0.0/16 -j RETURN", chain)) 191 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 172.16.0.0/12 -j RETURN", chain)) 192 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 192.0.0.0/24 -j RETURN", chain)) 193 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 192.0.2.0/24 -j RETURN", chain)) 194 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 192.88.99.0/24 -j RETURN", chain)) 195 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 192.168.0.0/16 -j RETURN", chain)) 196 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 198.51.100.0/24 -j RETURN", chain)) 197 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 203.0.113.0/24 -j RETURN", chain)) 198 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 224.0.0.0/4 -j RETURN", chain)) 199 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 240.0.0.0/4 -j RETURN", chain)) 200 execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 255.255.255.255/32 -j RETURN", chain)) 201 } 202 203 func execCmd(cmdStr string) { 204 log.Debugln("[IPTABLES] %s", cmdStr) 205 206 _, err := cmd.ExecCmd(cmdStr) 207 if err != nil { 208 log.Warnln("[IPTABLES] exec cmd: %v", err) 209 } 210 }