tc_l2_redirect_kern.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /* Copyright (c) 2016 Facebook
  2. *
  3. * This program is free software; you can redistribute it and/or
  4. * modify it under the terms of version 2 of the GNU General Public
  5. * License as published by the Free Software Foundation.
  6. */
  7. #define KBUILD_MODNAME "foo"
  8. #include <uapi/linux/bpf.h>
  9. #include <uapi/linux/if_ether.h>
  10. #include <uapi/linux/if_packet.h>
  11. #include <uapi/linux/ip.h>
  12. #include <uapi/linux/ipv6.h>
  13. #include <uapi/linux/in.h>
  14. #include <uapi/linux/tcp.h>
  15. #include <uapi/linux/filter.h>
  16. #include <uapi/linux/pkt_cls.h>
  17. #include <net/ipv6.h>
  18. #include <bpf/bpf_helpers.h>
  19. #define _htonl __builtin_bswap32
  20. #define PIN_GLOBAL_NS 2
  21. struct bpf_elf_map {
  22. __u32 type;
  23. __u32 size_key;
  24. __u32 size_value;
  25. __u32 max_elem;
  26. __u32 flags;
  27. __u32 id;
  28. __u32 pinning;
  29. };
  30. /* copy of 'struct ethhdr' without __packed */
  31. struct eth_hdr {
  32. unsigned char h_dest[ETH_ALEN];
  33. unsigned char h_source[ETH_ALEN];
  34. unsigned short h_proto;
  35. };
  36. struct bpf_elf_map SEC("maps") tun_iface = {
  37. .type = BPF_MAP_TYPE_ARRAY,
  38. .size_key = sizeof(int),
  39. .size_value = sizeof(int),
  40. .pinning = PIN_GLOBAL_NS,
  41. .max_elem = 1,
  42. };
  43. static __always_inline bool is_vip_addr(__be16 eth_proto, __be32 daddr)
  44. {
  45. if (eth_proto == htons(ETH_P_IP))
  46. return (_htonl(0xffffff00) & daddr) == _htonl(0x0a0a0100);
  47. else if (eth_proto == htons(ETH_P_IPV6))
  48. return (daddr == _htonl(0x2401face));
  49. return false;
  50. }
  51. SEC("l2_to_iptun_ingress_forward")
  52. int _l2_to_iptun_ingress_forward(struct __sk_buff *skb)
  53. {
  54. struct bpf_tunnel_key tkey = {};
  55. void *data = (void *)(long)skb->data;
  56. struct eth_hdr *eth = data;
  57. void *data_end = (void *)(long)skb->data_end;
  58. int key = 0, *ifindex;
  59. int ret;
  60. if (data + sizeof(*eth) > data_end)
  61. return TC_ACT_OK;
  62. ifindex = bpf_map_lookup_elem(&tun_iface, &key);
  63. if (!ifindex)
  64. return TC_ACT_OK;
  65. if (eth->h_proto == htons(ETH_P_IP)) {
  66. char fmt4[] = "ingress forward to ifindex:%d daddr4:%x\n";
  67. struct iphdr *iph = data + sizeof(*eth);
  68. if (data + sizeof(*eth) + sizeof(*iph) > data_end)
  69. return TC_ACT_OK;
  70. if (iph->protocol != IPPROTO_IPIP)
  71. return TC_ACT_OK;
  72. bpf_trace_printk(fmt4, sizeof(fmt4), *ifindex,
  73. _htonl(iph->daddr));
  74. return bpf_redirect(*ifindex, BPF_F_INGRESS);
  75. } else if (eth->h_proto == htons(ETH_P_IPV6)) {
  76. char fmt6[] = "ingress forward to ifindex:%d daddr6:%x::%x\n";
  77. struct ipv6hdr *ip6h = data + sizeof(*eth);
  78. if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
  79. return TC_ACT_OK;
  80. if (ip6h->nexthdr != IPPROTO_IPIP &&
  81. ip6h->nexthdr != IPPROTO_IPV6)
  82. return TC_ACT_OK;
  83. bpf_trace_printk(fmt6, sizeof(fmt6), *ifindex,
  84. _htonl(ip6h->daddr.s6_addr32[0]),
  85. _htonl(ip6h->daddr.s6_addr32[3]));
  86. return bpf_redirect(*ifindex, BPF_F_INGRESS);
  87. }
  88. return TC_ACT_OK;
  89. }
  90. SEC("l2_to_iptun_ingress_redirect")
  91. int _l2_to_iptun_ingress_redirect(struct __sk_buff *skb)
  92. {
  93. struct bpf_tunnel_key tkey = {};
  94. void *data = (void *)(long)skb->data;
  95. struct eth_hdr *eth = data;
  96. void *data_end = (void *)(long)skb->data_end;
  97. int key = 0, *ifindex;
  98. int ret;
  99. if (data + sizeof(*eth) > data_end)
  100. return TC_ACT_OK;
  101. ifindex = bpf_map_lookup_elem(&tun_iface, &key);
  102. if (!ifindex)
  103. return TC_ACT_OK;
  104. if (eth->h_proto == htons(ETH_P_IP)) {
  105. char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n";
  106. struct iphdr *iph = data + sizeof(*eth);
  107. __be32 daddr = iph->daddr;
  108. if (data + sizeof(*eth) + sizeof(*iph) > data_end)
  109. return TC_ACT_OK;
  110. if (!is_vip_addr(eth->h_proto, daddr))
  111. return TC_ACT_OK;
  112. bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(daddr), *ifindex);
  113. } else {
  114. return TC_ACT_OK;
  115. }
  116. tkey.tunnel_id = 10000;
  117. tkey.tunnel_ttl = 64;
  118. tkey.remote_ipv4 = 0x0a020166; /* 10.2.1.102 */
  119. bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), 0);
  120. return bpf_redirect(*ifindex, 0);
  121. }
  122. SEC("l2_to_ip6tun_ingress_redirect")
  123. int _l2_to_ip6tun_ingress_redirect(struct __sk_buff *skb)
  124. {
  125. struct bpf_tunnel_key tkey = {};
  126. void *data = (void *)(long)skb->data;
  127. struct eth_hdr *eth = data;
  128. void *data_end = (void *)(long)skb->data_end;
  129. int key = 0, *ifindex;
  130. if (data + sizeof(*eth) > data_end)
  131. return TC_ACT_OK;
  132. ifindex = bpf_map_lookup_elem(&tun_iface, &key);
  133. if (!ifindex)
  134. return TC_ACT_OK;
  135. if (eth->h_proto == htons(ETH_P_IP)) {
  136. char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n";
  137. struct iphdr *iph = data + sizeof(*eth);
  138. if (data + sizeof(*eth) + sizeof(*iph) > data_end)
  139. return TC_ACT_OK;
  140. if (!is_vip_addr(eth->h_proto, iph->daddr))
  141. return TC_ACT_OK;
  142. bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(iph->daddr),
  143. *ifindex);
  144. } else if (eth->h_proto == htons(ETH_P_IPV6)) {
  145. char fmt6[] = "e/ingress redirect daddr6:%x to ifindex:%d\n";
  146. struct ipv6hdr *ip6h = data + sizeof(*eth);
  147. if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
  148. return TC_ACT_OK;
  149. if (!is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0]))
  150. return TC_ACT_OK;
  151. bpf_trace_printk(fmt6, sizeof(fmt6),
  152. _htonl(ip6h->daddr.s6_addr32[0]), *ifindex);
  153. } else {
  154. return TC_ACT_OK;
  155. }
  156. tkey.tunnel_id = 10000;
  157. tkey.tunnel_ttl = 64;
  158. /* 2401:db02:0:0:0:0:0:66 */
  159. tkey.remote_ipv6[0] = _htonl(0x2401db02);
  160. tkey.remote_ipv6[1] = 0;
  161. tkey.remote_ipv6[2] = 0;
  162. tkey.remote_ipv6[3] = _htonl(0x00000066);
  163. bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), BPF_F_TUNINFO_IPV6);
  164. return bpf_redirect(*ifindex, 0);
  165. }
  166. SEC("drop_non_tun_vip")
  167. int _drop_non_tun_vip(struct __sk_buff *skb)
  168. {
  169. struct bpf_tunnel_key tkey = {};
  170. void *data = (void *)(long)skb->data;
  171. struct eth_hdr *eth = data;
  172. void *data_end = (void *)(long)skb->data_end;
  173. if (data + sizeof(*eth) > data_end)
  174. return TC_ACT_OK;
  175. if (eth->h_proto == htons(ETH_P_IP)) {
  176. struct iphdr *iph = data + sizeof(*eth);
  177. if (data + sizeof(*eth) + sizeof(*iph) > data_end)
  178. return TC_ACT_OK;
  179. if (is_vip_addr(eth->h_proto, iph->daddr))
  180. return TC_ACT_SHOT;
  181. } else if (eth->h_proto == htons(ETH_P_IPV6)) {
  182. struct ipv6hdr *ip6h = data + sizeof(*eth);
  183. if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
  184. return TC_ACT_OK;
  185. if (is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0]))
  186. return TC_ACT_SHOT;
  187. }
  188. return TC_ACT_OK;
  189. }
  190. char _license[] SEC("license") = "GPL";