summaryrefslogtreecommitdiffstats
path: root/bpf-filter.ebpf.src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:34:30 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:34:30 +0000
commit4fc2f55f761d71aae1f145d5aa94ba929cc39676 (patch)
tree5c1e1db3b46dd4edbe11f612d93cb94b96891ce3 /bpf-filter.ebpf.src
parentInitial commit. (diff)
downloaddnsdist-4fc2f55f761d71aae1f145d5aa94ba929cc39676.tar.xz
dnsdist-4fc2f55f761d71aae1f145d5aa94ba929cc39676.zip
Adding upstream version 1.7.3.upstream/1.7.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'bpf-filter.ebpf.src')
-rw-r--r--bpf-filter.ebpf.src503
1 files changed, 503 insertions, 0 deletions
diff --git a/bpf-filter.ebpf.src b/bpf-filter.ebpf.src
new file mode 100644
index 0000000..9f58669
--- /dev/null
+++ b/bpf-filter.ebpf.src
@@ -0,0 +1,503 @@
+
+#include <net/sock.h>
+#include <linux/types.h>
+#include <uapi/linux/tcp.h>
+#include <uapi/linux/udp.h>
+#include <uapi/linux/ip.h>
+#include <uapi/linux/ipv6.h>
+#include <bcc/proto.h>
+
+struct dnsheader {
+ unsigned id :16; /* query identification number */
+#if BYTE_ORDER == BIG_ENDIAN
+ /* fields in third byte */
+ unsigned qr: 1; /* response flag */
+ unsigned opcode: 4; /* purpose of message */
+ unsigned aa: 1; /* authoritative answer */
+ unsigned tc: 1; /* truncated message */
+ unsigned rd: 1; /* recursion desired */
+ /* fields in fourth byte */
+ unsigned ra: 1; /* recursion available */
+ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
+ unsigned ad: 1; /* authentic data from named */
+ unsigned cd: 1; /* checking disabled by resolver */
+ unsigned rcode :4; /* response code */
+#elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
+ /* fields in third byte */
+ unsigned rd :1; /* recursion desired */
+ unsigned tc :1; /* truncated message */
+ unsigned aa :1; /* authoritative answer */
+ unsigned opcode :4; /* purpose of message */
+ unsigned qr :1; /* response flag */
+ /* fields in fourth byte */
+ unsigned rcode :4; /* response code */
+ unsigned cd: 1; /* checking disabled by resolver */
+ unsigned ad: 1; /* authentic data from named */
+ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
+ unsigned ra :1; /* recursion available */
+#endif
+ /* remaining bytes */
+ unsigned qdcount :16; /* number of question entries */
+ unsigned ancount :16; /* number of answer entries */
+ unsigned nscount :16; /* number of authority entries */
+ unsigned arcount :16; /* number of resource entries */
+};
+
+struct QNameKey
+{
+ uint8_t qname[255];
+};
+
+struct KeyV6
+{
+ uint8_t src[16];
+};
+
+struct QNameValue
+{
+ u64 counter;
+ u16 qtype;
+};
+
+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_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;
+ }
+ val = skb->cb[2];
+ if (val) {
+ qkey.qname[1] = val;
+ }
+ uint8_t temp;
+
+#define FILL_ONE_KEY \
+ temp = load_byte(skb, qname_off + idx); \
+ labellen--; \
+ if (labellen < 0) { \
+ labellen = temp; \
+ if (labellen == 0) { \
+ goto end; \
+ } \
+ } else if (temp >= 'A' && temp <= 'Z') { \
+ temp += ('a' - 'A'); \
+ } \
+ qkey.qname[idx] = temp; \
+ idx++;
+
+ /* 2 - 52 */
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ /* 52 - 102 */
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ /* 102 - 152 */
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ /* 152 - 202 */
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ /* 202 - 252 */
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ 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:
+
+ {
+ idx++;
+ u16 qtype = load_half(skb, (qname_off + idx));
+
+ 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;
+}
+
+int bpf_dns_filter(struct __sk_buff *skb) {
+ u8 ip_proto;
+ int proto_off;
+ /* nh_off will contain a negative offset, used in BPF to get access to
+ the MAC/network layers, as positive values are used to get access to
+ the transport layer */
+ 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 };
+ /* switch to positive offsets here, as we have seen some issues
+ when accessing the content of the transport layer with negative offsets
+ https://github.com/PowerDNS/pdns/issues/9626 */
+ int dns_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;
+}