github.com/yaling888/clash@v1.53.0/component/ebpf/bpf/tc.c (about)

     1  #include <stdbool.h>
     2  #include <linux/bpf.h>
     3  #include <linux/if_ether.h>
     4  #include <linux/ip.h>
     5  #include <linux/in.h>
     6  //#include <linux/tcp.h>
     7  //#include <linux/udp.h>
     8  #include <linux/pkt_cls.h>
     9  
    10  #include "bpf_endian.h"
    11  #include "bpf_helpers.h"
    12  
    13  struct {
    14      __uint(type, BPF_MAP_TYPE_ARRAY);
    15      __type(key, __u32);
    16      __type(value, __u32);
    17      __uint(max_entries, 2);
    18      __uint(pinning, LIBBPF_PIN_BY_NAME);
    19  } tc_params_map SEC(".maps");
    20  
    21  static __always_inline bool is_lan_ip(__be32 addr) {
    22      if (addr == 0xffffffff)
    23          return true;
    24  
    25      __u8 fist = (__u8)(addr & 0xff);
    26  
    27      if (fist == 127 || fist == 10)
    28          return true;
    29  
    30      __u8 second = (__u8)((addr >> 8) & 0xff);
    31  
    32      if (fist == 172 && second >= 16 && second <= 31)
    33          return true;
    34  
    35      if (fist == 192 && second == 168)
    36          return true;
    37  
    38      return false;
    39  }
    40  
    41  SEC("tc_clash_redirect_to_tun")
    42  int tc_tun_func(struct __sk_buff *skb) {
    43      void *data          = (void *)(long)skb->data;
    44      void *data_end      = (void *)(long)skb->data_end;
    45      struct ethhdr *eth  = data;
    46  
    47      if ((void *)(eth + 1) > data_end)
    48          return TC_ACT_OK;
    49  
    50      if (eth->h_proto == bpf_htons(ETH_P_ARP))
    51          return TC_ACT_OK;
    52  
    53      __u32 key = 0, *clash_mark, *tun_ifindex;
    54  
    55      clash_mark = bpf_map_lookup_elem(&tc_params_map, &key);
    56      if (!clash_mark)
    57          return TC_ACT_OK;
    58  
    59      if (skb->mark == *clash_mark)
    60          return TC_ACT_OK;
    61  
    62      if (eth->h_proto == bpf_htons(ETH_P_IP)) {
    63          struct iphdr *iph = (struct iphdr *)(eth + 1);
    64          if ((void *)(iph + 1) > data_end)
    65              return TC_ACT_OK;
    66  
    67          if (iph->protocol == IPPROTO_ICMP)
    68              return TC_ACT_OK;
    69  
    70          __be32 daddr = iph->daddr;
    71  
    72          if (is_lan_ip(daddr))
    73              return TC_ACT_OK;
    74  
    75  //        if (iph->protocol == IPPROTO_TCP) {
    76  //            struct tcphdr *tcph = (struct tcphdr *)(iph + 1);
    77  //            if ((void *)(tcph + 1) > data_end)
    78  //                return TC_ACT_OK;
    79  //
    80  //            __u16 source = bpf_ntohs(tcph->source);
    81  //            if (source == 22 || source == 80 || source == 443 || source == 8080 || source == 8443 || source == 9090 || (source >= 7890 && source <= 7895))
    82  //                return TC_ACT_OK;
    83  //        } else if (iph->protocol == IPPROTO_UDP) {
    84  //            struct udphdr *udph = (struct udphdr *)(iph + 1);
    85  //            if ((void *)(udph + 1) > data_end)
    86  //                return TC_ACT_OK;
    87  //
    88  //            __u16 source = bpf_ntohs(udph->source);
    89  //            if (source == 53 || (source >= 135 && source <= 139))
    90  //                return TC_ACT_OK;
    91  //        }
    92      }
    93  
    94      key = 1;
    95      tun_ifindex = bpf_map_lookup_elem(&tc_params_map, &key);
    96      if (!tun_ifindex)
    97          return TC_ACT_OK;
    98  
    99      //return bpf_redirect(*tun_ifindex, BPF_F_INGRESS); // __bpf_rx_skb
   100      return bpf_redirect(*tun_ifindex, 0); // __bpf_tx_skb / __dev_xmit_skb
   101  }
   102  
   103  char _license[] SEC("license") = "GPL";