redir.c 8.6 KB

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