diff --git a/xdp-dns/xdp_dns.bpf.c b/xdp-dns/xdp_dns.bpf.c index 8339aeaa..77445c86 100644 --- a/xdp-dns/xdp_dns.bpf.c +++ b/xdp-dns/xdp_dns.bpf.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, NLnet Labs. All rights reserved. + * Copyright (c) 2024, BPFire. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,7 +41,7 @@ // do not use libc includes because this causes clang // to include 32bit headers on 64bit ( only ) systems. #define memcpy __builtin_memcpy -#define MAX_DOMAIN_SIZE 18 +#define MAX_DOMAIN_SIZE 128 struct meta_data { __u16 eth_proto; @@ -49,14 +50,22 @@ struct meta_data { __u16 unused; }; +/* Define the LPM Trie Map for domain names */ +struct domain_key { + struct bpf_lpm_trie_key lpm_key; + char data[MAX_DOMAIN_SIZE + 1]; +}; + struct { - __uint(type, BPF_MAP_TYPE_HASH); - __type(key, char[MAX_DOMAIN_SIZE + 1]); + __uint(type, BPF_MAP_TYPE_LPM_TRIE); + __type(key, struct domain_key); __type(value, __u8); - __uint(max_entries, 1024); + __uint(max_entries, 10000); __uint(pinning, LIBBPF_PIN_BY_NAME); + __uint(map_flags, BPF_F_NO_PREALLOC); } domain_denylist SEC(".maps"); + /* * Store the VLAN header */ @@ -191,8 +200,16 @@ static __always_inline __u8 custom_strlen(const char *str, struct cursor *c) { return len; } +static __always_inline void reverse_string(char *str, __u8 len) { + for (int i = 0; i < (len - 1) / 2; i++) { + char temp = str[i]; + str[i] = str[len - 1 - i]; + str[len - 1 - i] = temp; + } +} + SEC("xdp") -int xdp_dns(struct xdp_md *ctx) +int xdp_dns_denylist(struct xdp_md *ctx) { struct meta_data *md = (void *)(long)ctx->data_meta; struct cursor c; @@ -201,9 +218,10 @@ int xdp_dns(struct xdp_md *ctx) struct udphdr *udp; struct dnshdr *dns; char *qname; -// __u8 value = 1; + //__u8 value = 1; __u8 len = 0; - char domain_key[MAX_DOMAIN_SIZE + 1 ] = {0}; // Buffer for map lookup + + struct domain_key dkey = {0}; // LPM trie key if (bpf_xdp_adjust_meta(ctx, -(int)sizeof(struct meta_data))) return XDP_PASS; @@ -246,26 +264,29 @@ int xdp_dns(struct xdp_md *ctx) return XDP_ABORTED; // Return FORMERR? int copy_len = len < MAX_DOMAIN_SIZE ? len : MAX_DOMAIN_SIZE; - custom_memcpy(domain_key, qname, copy_len); - domain_key[MAX_DOMAIN_SIZE] = '\0'; // Ensure null-termination + custom_memcpy(dkey.data, qname, copy_len); + dkey.data[MAX_DOMAIN_SIZE] = '\0'; // Ensure null-termination + reverse_string(dkey.data, copy_len); + + // Set the LPM key prefix length (the length of the domain name string) + dkey.lpm_key.prefixlen = copy_len * 8; // Prefix length in bits + + bpf_printk("domain_key %s copy_len is %d from %pI4", dkey.data, copy_len, &ipv4->saddr); + + if (bpf_map_lookup_elem(&domain_denylist, &dkey)) { + bpf_printk("Domain %s found in denylist, dropping packet\n", dkey.data); + return XDP_DROP; + } else { + bpf_printk("Domain %s not found in denylist\n", dkey.data); + } /* - bpf_printk("domain_key %s copy_len is %d from %pI4", domain_key, copy_len, &ipv4->saddr); - - if (bpf_map_update_elem(&domain_denylist, &domain_key, &value, BPF_ANY) < 0) { - bpf_printk("Domain %s not updated in denylist\n", domain_key); + if (bpf_map_update_elem(&domain_denylist, &dkey, &value, BPF_ANY) < 0) { + bpf_printk("Domain %s not updated in denylist\n", dkey.data); } else { - bpf_printk("Domain %s updated in denylist\n", domain_key); + bpf_printk("Domain %s updated in denylist\n", dkey.data); } - */ - if (bpf_map_lookup_elem(&domain_denylist, domain_key)) { - bpf_printk("Domain %s found in denylist, dropping packet\n", domain_key); - return XDP_DROP; - } - else { - bpf_printk("Domain %s not found in denylist\n", domain_key); - } break; } diff --git a/xdp-dns/xdp_dns.c b/xdp-dns/xdp_dns.c index 666aea6a..5ecd3b9f 100644 --- a/xdp-dns/xdp_dns.c +++ b/xdp-dns/xdp_dns.c @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2024, BPFire. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include #include #include @@ -7,6 +24,11 @@ #define MAX_DOMAIN_SIZE 128 // Increased size to handle larger domains +struct domain_key { + struct bpf_lpm_trie_key lpm_key; + char data[MAX_DOMAIN_SIZE + 1]; +}; + // Function to encode a domain name with label lengths static void encode_domain(const char *domain, char *encoded) { const char *ptr = domain; @@ -33,9 +55,18 @@ static void encode_domain(const char *domain, char *encoded) { *enc_ptr++ = 0; } +static void reverse_string(char *str) { + int len = strlen(str); + for (int i = 0; i < len / 2; i++) { + char temp = str[i]; + str[i] = str[len - i - 1]; + str[len - i - 1] = temp; + } +} + int main(int argc, char *argv[]) { int map_fd; - char domain_key[MAX_DOMAIN_SIZE + 1] = {0}; + struct domain_key dkey = {0}; __u8 value = 1; // Check for proper number of arguments @@ -45,7 +76,11 @@ int main(int argc, char *argv[]) { } // Encode the domain name with label lengths - encode_domain(argv[1], domain_key); + encode_domain(argv[1], dkey.data); + reverse_string(dkey.data); + + // Set the LPM trie key prefix length + dkey.lpm_key.prefixlen = strlen(dkey.data) * 8; // Open the BPF map map_fd = bpf_obj_get("/sys/fs/bpf/xdp-dns/domain_denylist"); @@ -55,7 +90,7 @@ int main(int argc, char *argv[]) { } // Update the map with the encoded domain name - if (bpf_map_update_elem(map_fd, domain_key, &value, BPF_ANY) != 0) { + if (bpf_map_update_elem(map_fd, &dkey, &value, BPF_ANY) != 0) { fprintf(stderr, "Failed to update map: %s\n", strerror(errno)); return 1; }