]> git.ipfire.org Git - thirdparty/pdns.git/blobdiff - pdns/bpf-filter.ebpf.src
Merge pull request #7734 from franklouwers/docs2
[thirdparty/pdns.git] / pdns / bpf-filter.ebpf.src
index eaaf492bc3187a9ecf07879d427b7d0802892f72..f1c5effcbe49bcadc688cc7324cf5079a1ca73be 100644 (file)
@@ -59,82 +59,25 @@ struct QNameValue
   u16 qtype;
 };
 
-#define IP_MF 0x2000
-#define IP_OFFSET 0x1FFF
-
 BPF_TABLE("hash", u32, u64, v4filter, 1024);
 BPF_TABLE("hash", struct KeyV6, u64, v6filter, 1024);
 BPF_TABLE("hash", struct QNameKey, struct QNameValue, qnamefilter, 1024);
+BPF_TABLE("prog", int, int, progsarray, 1);
 
-int bpf_dns_filter(struct __sk_buff *skb) {
-  u8 ip_proto;
-  u32 proto_off;
-  int nh_off = BPF_LL_OFF + ETH_HLEN;
-
-  if (skb->protocol == ntohs(0x0800)) {
-    u32 key;
-    int off = nh_off + offsetof(struct iphdr, saddr);
-    key = load_word(skb, off);
-
-    u64* counter = v4filter.lookup(&key);
-    if (counter) {
-      __sync_fetch_and_add(counter, 1);
-      return 0;
-    }
-
-#if 0
-    if (load_half(skb, (nh_off + (int32_t)offsetof(struct iphdr, frag_off)) & (IP_MF | IP_OFFSET))) {
-      /* fragment */
-      return 2147483647;
-    }
-#endif
-    ip_proto = load_byte(skb, nh_off + offsetof(struct iphdr, protocol));
-    proto_off = nh_off + sizeof(struct iphdr);
-  }
-  else if (skb->protocol == ntohs(0x86DD)) {
-    struct KeyV6 key;
-    int off = nh_off + offsetof(struct ipv6hdr, saddr);
-    key.src[0] = load_byte(skb, off++);
-    key.src[1] = load_byte(skb, off++);
-    key.src[2] = load_byte(skb, off++);
-    key.src[3] = load_byte(skb, off++);
-    key.src[4] = load_byte(skb, off++);
-    key.src[5] = load_byte(skb, off++);
-    key.src[6] = load_byte(skb, off++);
-    key.src[7] = load_byte(skb, off++);
-    key.src[8] = load_byte(skb, off++);
-    key.src[9] = load_byte(skb, off++);
-    key.src[10] = load_byte(skb, off++);
-    key.src[11] = load_byte(skb, off++);
-    key.src[12] = load_byte(skb, off++);
-    key.src[13] = load_byte(skb, off++);
-    key.src[14] = load_byte(skb, off++);
-    key.src[15] = load_byte(skb, off++);
-
-    u64* counter = v6filter.lookup(&key);
-    if (counter) {
-      __sync_fetch_and_add(counter, 1);
-      return 0;
-    }
-
-    ip_proto = load_byte(skb, nh_off + offsetof(struct ipv6hdr, nexthdr));
-    proto_off = nh_off + sizeof(struct ipv6hdr);
+int bpf_qname_filter(struct __sk_buff *skb)
+{
+  uint32_t qname_off = skb->cb[0];
+  ssize_t labellen = skb->cb[3];
+  size_t idx = 2;
+  struct QNameKey qkey = { 0 };
+  u32 val = skb->cb[1];
+  if (val) {
+    qkey.qname[0] = val;
   }
-  else {
-    /* neither IPv4 not IPv6, well */
-    return 2147483647;
+  val = skb->cb[2];
+  if (val) {
+    qkey.qname[1] = val;
   }
-
-  /* allow TCP */
-  if (ip_proto == IPPROTO_TCP) {
-    return 2147483647;
-  }
-
-  int dns_off = proto_off + sizeof(struct udphdr);
-  int qname_off = dns_off + sizeof(struct dnsheader);
-  size_t idx = 0;
-  struct QNameKey qkey = { 0 };
-  int32_t labellen = 0;
   uint8_t temp;
 
 #define FILL_ONE_KEY                                    \
@@ -145,11 +88,13 @@ int bpf_dns_filter(struct __sk_buff *skb) {
     if (labellen == 0) {                                \
       goto end;                                         \
     }                                                   \
+  } else if (temp >= 'A' && temp <= 'Z') {              \
+    temp += ('a' - 'A');                                \
   }                                                     \
   qkey.qname[idx] = temp;                               \
   idx++;
 
-  /* 0 - 50 */
+  /* 2 - 52 */
   FILL_ONE_KEY
   FILL_ONE_KEY
   FILL_ONE_KEY
@@ -205,7 +150,7 @@ int bpf_dns_filter(struct __sk_buff *skb) {
   FILL_ONE_KEY
   FILL_ONE_KEY
 
-  /* 50 - 100 */
+  /* 52 - 102 */
   FILL_ONE_KEY
   FILL_ONE_KEY
   FILL_ONE_KEY
@@ -261,7 +206,7 @@ int bpf_dns_filter(struct __sk_buff *skb) {
   FILL_ONE_KEY
   FILL_ONE_KEY
 
-  /* 100 - 150 */
+  /* 102 - 152 */
   FILL_ONE_KEY
   FILL_ONE_KEY
   FILL_ONE_KEY
@@ -317,7 +262,7 @@ int bpf_dns_filter(struct __sk_buff *skb) {
   FILL_ONE_KEY
   FILL_ONE_KEY
 
-  /* 150 - 200 */
+  /* 152 - 202 */
   FILL_ONE_KEY
   FILL_ONE_KEY
   FILL_ONE_KEY
@@ -373,7 +318,7 @@ int bpf_dns_filter(struct __sk_buff *skb) {
   FILL_ONE_KEY
   FILL_ONE_KEY
 
-  /* 200 - 250 */
+  /* 202 - 252 */
   FILL_ONE_KEY
   FILL_ONE_KEY
   FILL_ONE_KEY
@@ -429,21 +374,18 @@ int bpf_dns_filter(struct __sk_buff *skb) {
   FILL_ONE_KEY
   FILL_ONE_KEY
 
-  /* 250 - 255 */
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
+  /* 252 - 254 */
   FILL_ONE_KEY
   FILL_ONE_KEY
 
+  /* the only value that makes sense for
+     qkey.qname[255] is 0, and it's already
+     there */
   end:
 
   {
-    if (idx < 255) {
-      idx++;
-    }
+    idx++;
     u16 qtype = load_half(skb, (qname_off + idx));
-    idx += 2;
 
     struct QNameValue* qvalue = qnamefilter.lookup(&qkey);
     if (qvalue &&
@@ -455,3 +397,101 @@ int bpf_dns_filter(struct __sk_buff *skb) {
 
   return 2147483647;
 }
+
+int bpf_dns_filter(struct __sk_buff *skb) {
+  u8 ip_proto;
+  int proto_off;
+  int nh_off = BPF_LL_OFF + ETH_HLEN;
+
+  if (skb->protocol == ntohs(0x0800)) {
+    u32 key;
+    int off = nh_off + offsetof(struct iphdr, saddr);
+    key = load_word(skb, off);
+
+    u64* counter = v4filter.lookup(&key);
+    if (counter) {
+      __sync_fetch_and_add(counter, 1);
+      return 0;
+    }
+
+    ip_proto = load_byte(skb, nh_off + offsetof(struct iphdr, protocol));
+    proto_off = nh_off + sizeof(struct iphdr);
+  }
+  else if (skb->protocol == ntohs(0x86DD)) {
+    struct KeyV6 key;
+    int off = nh_off + offsetof(struct ipv6hdr, saddr);
+    key.src[0] = load_byte(skb, off++);
+    key.src[1] = load_byte(skb, off++);
+    key.src[2] = load_byte(skb, off++);
+    key.src[3] = load_byte(skb, off++);
+    key.src[4] = load_byte(skb, off++);
+    key.src[5] = load_byte(skb, off++);
+    key.src[6] = load_byte(skb, off++);
+    key.src[7] = load_byte(skb, off++);
+    key.src[8] = load_byte(skb, off++);
+    key.src[9] = load_byte(skb, off++);
+    key.src[10] = load_byte(skb, off++);
+    key.src[11] = load_byte(skb, off++);
+    key.src[12] = load_byte(skb, off++);
+    key.src[13] = load_byte(skb, off++);
+    key.src[14] = load_byte(skb, off++);
+    key.src[15] = load_byte(skb, off++);
+
+    u64* counter = v6filter.lookup(&key);
+    if (counter) {
+      __sync_fetch_and_add(counter, 1);
+      return 0;
+    }
+
+    ip_proto = load_byte(skb, nh_off + offsetof(struct ipv6hdr, nexthdr));
+    proto_off = nh_off + sizeof(struct ipv6hdr);
+  }
+  else {
+    /* neither IPv4 not IPv6, well */
+    return 2147483647;
+  }
+
+  /* allow TCP */
+  if (ip_proto == IPPROTO_TCP) {
+    return 2147483647;
+  }
+
+  struct QNameKey qkey = { 0 };
+  int dns_off = proto_off + sizeof(struct udphdr);
+  int qname_off = dns_off + sizeof(struct dnsheader);
+  skb->cb[0] = (uint32_t) qname_off;
+  u16 qtype;
+
+  uint8_t temp = load_byte(skb, qname_off);
+  if (temp > 63) {
+    return 0;
+  }
+
+  if (temp == 0) {
+    /* root, nothing else to see */
+    qtype = load_half(skb, (qname_off + 1));
+
+    struct QNameValue* qvalue = qnamefilter.lookup(&qkey);
+    if (qvalue &&
+      (qvalue->qtype == 255 || qtype == qvalue->qtype)) {
+      __sync_fetch_and_add(&qvalue->counter, 1);
+      return 0;
+    }
+    return 2147483647;
+  }
+
+  ssize_t labellen = temp;
+  skb->cb[1] = temp;
+  qkey.qname[0] = temp;
+
+  temp = load_byte(skb, qname_off + 1);
+  labellen--;
+  if (temp >= 'A' && temp <= 'Z') {
+    temp += ('a' - 'A');
+  }
+  skb->cb[2] = temp;
+  skb->cb[3] = labellen;
+  progsarray.call(skb, 0);
+
+  return 2147483647;
+}