github.com/kelleygo/clashcore@v1.0.2/component/ebpf/bpf/redir.c (about) 1 #include <stdint.h> 2 #include <stdbool.h> 3 //#include <linux/types.h> 4 5 #include <linux/bpf.h> 6 #include <linux/if_ether.h> 7 //#include <linux/if_packet.h> 8 //#include <linux/if_vlan.h> 9 #include <linux/ip.h> 10 #include <linux/in.h> 11 #include <linux/tcp.h> 12 //#include <linux/udp.h> 13 14 #include <linux/pkt_cls.h> 15 16 #include "bpf_endian.h" 17 #include "bpf_helpers.h" 18 19 #define IP_CSUM_OFF (ETH_HLEN + offsetof(struct iphdr, check)) 20 #define IP_DST_OFF (ETH_HLEN + offsetof(struct iphdr, daddr)) 21 #define IP_SRC_OFF (ETH_HLEN + offsetof(struct iphdr, saddr)) 22 #define IP_PROTO_OFF (ETH_HLEN + offsetof(struct iphdr, protocol)) 23 #define TCP_CSUM_OFF (ETH_HLEN + sizeof(struct iphdr) + offsetof(struct tcphdr, check)) 24 #define TCP_SRC_OFF (ETH_HLEN + sizeof(struct iphdr) + offsetof(struct tcphdr, source)) 25 #define TCP_DST_OFF (ETH_HLEN + sizeof(struct iphdr) + offsetof(struct tcphdr, dest)) 26 //#define UDP_CSUM_OFF (ETH_HLEN + sizeof(struct iphdr) + offsetof(struct udphdr, check)) 27 //#define UDP_SRC_OFF (ETH_HLEN + sizeof(struct iphdr) + offsetof(struct udphdr, source)) 28 //#define UDP_DST_OFF (ETH_HLEN + sizeof(struct iphdr) + offsetof(struct udphdr, dest)) 29 #define IS_PSEUDO 0x10 30 31 struct origin_info { 32 __be32 ip; 33 __be16 port; 34 __u16 pad; 35 }; 36 37 struct origin_info *origin_info_unused __attribute__((unused)); 38 39 struct redir_info { 40 __be32 sip; 41 __be32 dip; 42 __be16 sport; 43 __be16 dport; 44 }; 45 46 struct redir_info *redir_info_unused __attribute__((unused)); 47 48 struct { 49 __uint(type, BPF_MAP_TYPE_LRU_HASH); 50 __type(key, struct redir_info); 51 __type(value, struct origin_info); 52 __uint(max_entries, 65535); 53 __uint(pinning, LIBBPF_PIN_BY_NAME); 54 } pair_original_dst_map SEC(".maps"); 55 56 struct { 57 __uint(type, BPF_MAP_TYPE_ARRAY); 58 __type(key, __u32); 59 __type(value, __u32); 60 __uint(max_entries, 3); 61 __uint(pinning, LIBBPF_PIN_BY_NAME); 62 } redir_params_map SEC(".maps"); 63 64 static __always_inline int rewrite_ip(struct __sk_buff *skb, __be32 new_ip, bool is_dest) { 65 int ret, off = 0, flags = IS_PSEUDO; 66 __be32 old_ip; 67 68 if (is_dest) 69 ret = bpf_skb_load_bytes(skb, IP_DST_OFF, &old_ip, 4); 70 else 71 ret = bpf_skb_load_bytes(skb, IP_SRC_OFF, &old_ip, 4); 72 73 if (ret < 0) { 74 return ret; 75 } 76 77 off = TCP_CSUM_OFF; 78 // __u8 proto; 79 // 80 // ret = bpf_skb_load_bytes(skb, IP_PROTO_OFF, &proto, 1); 81 // if (ret < 0) { 82 // return BPF_DROP; 83 // } 84 // 85 // switch (proto) { 86 // case IPPROTO_TCP: 87 // off = TCP_CSUM_OFF; 88 // break; 89 // 90 // case IPPROTO_UDP: 91 // off = UDP_CSUM_OFF; 92 // flags |= BPF_F_MARK_MANGLED_0; 93 // break; 94 // 95 // case IPPROTO_ICMPV6: 96 // off = offsetof(struct icmp6hdr, icmp6_cksum); 97 // break; 98 // } 99 // 100 // if (off) { 101 ret = bpf_l4_csum_replace(skb, off, old_ip, new_ip, flags | sizeof(new_ip)); 102 if (ret < 0) { 103 return ret; 104 } 105 // } 106 107 ret = bpf_l3_csum_replace(skb, IP_CSUM_OFF, old_ip, new_ip, sizeof(new_ip)); 108 if (ret < 0) { 109 return ret; 110 } 111 112 if (is_dest) 113 ret = bpf_skb_store_bytes(skb, IP_DST_OFF, &new_ip, sizeof(new_ip), 0); 114 else 115 ret = bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof(new_ip), 0); 116 117 if (ret < 0) { 118 return ret; 119 } 120 121 return 1; 122 } 123 124 static __always_inline int rewrite_port(struct __sk_buff *skb, __be16 new_port, bool is_dest) { 125 int ret, off = 0; 126 __be16 old_port; 127 128 if (is_dest) 129 ret = bpf_skb_load_bytes(skb, TCP_DST_OFF, &old_port, 2); 130 else 131 ret = bpf_skb_load_bytes(skb, TCP_SRC_OFF, &old_port, 2); 132 133 if (ret < 0) { 134 return ret; 135 } 136 137 off = TCP_CSUM_OFF; 138 139 ret = bpf_l4_csum_replace(skb, off, old_port, new_port, sizeof(new_port)); 140 if (ret < 0) { 141 return ret; 142 } 143 144 if (is_dest) 145 ret = bpf_skb_store_bytes(skb, TCP_DST_OFF, &new_port, sizeof(new_port), 0); 146 else 147 ret = bpf_skb_store_bytes(skb, TCP_SRC_OFF, &new_port, sizeof(new_port), 0); 148 149 if (ret < 0) { 150 return ret; 151 } 152 153 return 1; 154 } 155 156 static __always_inline bool is_lan_ip(__be32 addr) { 157 if (addr == 0xffffffff) 158 return true; 159 160 __u8 fist = (__u8)(addr & 0xff); 161 162 if (fist == 127 || fist == 10) 163 return true; 164 165 __u8 second = (__u8)((addr >> 8) & 0xff); 166 167 if (fist == 172 && second >= 16 && second <= 31) 168 return true; 169 170 if (fist == 192 && second == 168) 171 return true; 172 173 return false; 174 } 175 176 SEC("tc_yiclashcore_auto_redir_ingress") 177 int tc_redir_ingress_func(struct __sk_buff *skb) { 178 void *data = (void *)(long)skb->data; 179 void *data_end = (void *)(long)skb->data_end; 180 struct ethhdr *eth = data; 181 182 if ((void *)(eth + 1) > data_end) 183 return TC_ACT_OK; 184 185 if (eth->h_proto != bpf_htons(ETH_P_IP)) 186 return TC_ACT_OK; 187 188 struct iphdr *iph = (struct iphdr *)(eth + 1); 189 if ((void *)(iph + 1) > data_end) 190 return TC_ACT_OK; 191 192 __u32 key = 0, *route_index, *redir_ip, *redir_port; 193 194 route_index = bpf_map_lookup_elem(&redir_params_map, &key); 195 if (!route_index) 196 return TC_ACT_OK; 197 198 if (iph->protocol == IPPROTO_ICMP && *route_index != 0) 199 return bpf_redirect(*route_index, 0); 200 201 if (iph->protocol != IPPROTO_TCP) 202 return TC_ACT_OK; 203 204 struct tcphdr *tcph = (struct tcphdr *)(iph + 1); 205 if ((void *)(tcph + 1) > data_end) 206 return TC_ACT_SHOT; 207 208 key = 1; 209 redir_ip = bpf_map_lookup_elem(&redir_params_map, &key); 210 if (!redir_ip) 211 return TC_ACT_OK; 212 213 key = 2; 214 redir_port = bpf_map_lookup_elem(&redir_params_map, &key); 215 if (!redir_port) 216 return TC_ACT_OK; 217 218 __be32 new_ip = bpf_htonl(*redir_ip); 219 __be16 new_port = bpf_htonl(*redir_port) >> 16; 220 __be32 old_ip = iph->daddr; 221 __be16 old_port = tcph->dest; 222 223 if (old_ip == new_ip || is_lan_ip(old_ip) || bpf_ntohs(old_port) == 53) { 224 return TC_ACT_OK; 225 } 226 227 struct redir_info p_key = { 228 .sip = iph->saddr, 229 .sport = tcph->source, 230 .dip = new_ip, 231 .dport = new_port, 232 }; 233 234 if (tcph->syn && !tcph->ack) { 235 struct origin_info origin = { 236 .ip = old_ip, 237 .port = old_port, 238 }; 239 240 bpf_map_update_elem(&pair_original_dst_map, &p_key, &origin, BPF_NOEXIST); 241 242 if (rewrite_ip(skb, new_ip, true) < 0) { 243 return TC_ACT_SHOT; 244 } 245 246 if (rewrite_port(skb, new_port, true) < 0) { 247 return TC_ACT_SHOT; 248 } 249 } else { 250 struct origin_info *origin = bpf_map_lookup_elem(&pair_original_dst_map, &p_key); 251 if (!origin) { 252 return TC_ACT_OK; 253 } 254 255 if (rewrite_ip(skb, new_ip, true) < 0) { 256 return TC_ACT_SHOT; 257 } 258 259 if (rewrite_port(skb, new_port, true) < 0) { 260 return TC_ACT_SHOT; 261 } 262 } 263 264 return TC_ACT_OK; 265 } 266 267 SEC("tc_yiclashcore_auto_redir_egress") 268 int tc_redir_egress_func(struct __sk_buff *skb) { 269 void *data = (void *)(long)skb->data; 270 void *data_end = (void *)(long)skb->data_end; 271 struct ethhdr *eth = data; 272 273 if ((void *)(eth + 1) > data_end) 274 return TC_ACT_OK; 275 276 if (eth->h_proto != bpf_htons(ETH_P_IP)) 277 return TC_ACT_OK; 278 279 __u32 key = 0, *redir_ip, *redir_port; // *yiclashcore_mark 280 281 // yiclashcore_mark = bpf_map_lookup_elem(&redir_params_map, &key); 282 // if (yiclashcore_mark && *yiclashcore_mark != 0 && *yiclashcore_mark == skb->mark) 283 // return TC_ACT_OK; 284 285 struct iphdr *iph = (struct iphdr *)(eth + 1); 286 if ((void *)(iph + 1) > data_end) 287 return TC_ACT_OK; 288 289 if (iph->protocol != IPPROTO_TCP) 290 return TC_ACT_OK; 291 292 struct tcphdr *tcph = (struct tcphdr *)(iph + 1); 293 if ((void *)(tcph + 1) > data_end) 294 return TC_ACT_SHOT; 295 296 key = 1; 297 redir_ip = bpf_map_lookup_elem(&redir_params_map, &key); 298 if (!redir_ip) 299 return TC_ACT_OK; 300 301 key = 2; 302 redir_port = bpf_map_lookup_elem(&redir_params_map, &key); 303 if (!redir_port) 304 return TC_ACT_OK; 305 306 __be32 new_ip = bpf_htonl(*redir_ip); 307 __be16 new_port = bpf_htonl(*redir_port) >> 16; 308 __be32 old_ip = iph->saddr; 309 __be16 old_port = tcph->source; 310 311 if (old_ip != new_ip || old_port != new_port) { 312 return TC_ACT_OK; 313 } 314 315 struct redir_info p_key = { 316 .sip = iph->daddr, 317 .sport = tcph->dest, 318 .dip = iph->saddr, 319 .dport = tcph->source, 320 }; 321 322 struct origin_info *origin = bpf_map_lookup_elem(&pair_original_dst_map, &p_key); 323 if (!origin) { 324 return TC_ACT_OK; 325 } 326 327 if (tcph->fin && tcph->ack) { 328 bpf_map_delete_elem(&pair_original_dst_map, &p_key); 329 } 330 331 if (rewrite_ip(skb, origin->ip, false) < 0) { 332 return TC_ACT_SHOT; 333 } 334 335 if (rewrite_port(skb, origin->port, false) < 0) { 336 return TC_ACT_SHOT; 337 } 338 339 return TC_ACT_OK; 340 } 341 342 char _license[] SEC("license") = "GPL";