forked from xdp-project/xdp-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add DNS XDP program as tail called program Signed-off-by: Vincent Li <[email protected]>
- Loading branch information
1 parent
ad2a4e6
commit 74f1856
Showing
5 changed files
with
641 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
/* | ||
* 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 <https://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <bpf/bpf.h> | ||
#include <bpf/libbpf.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <errno.h> | ||
#include <stdlib.h> | ||
|
||
#define MAX_DOMAIN_SIZE 63 // 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; | ||
char *enc_ptr = encoded; | ||
size_t label_len; | ||
|
||
while (*ptr) { | ||
// Find the length of the current label | ||
label_len = strcspn(ptr, "."); | ||
if (label_len > 0) { | ||
// Set the length of the label | ||
*enc_ptr++ = (char)label_len; | ||
// Copy the label itself | ||
memcpy(enc_ptr, ptr, label_len); | ||
enc_ptr += label_len; | ||
} | ||
// Move to the next label | ||
ptr += label_len; | ||
if (*ptr == '.') { | ||
ptr++; // Skip the dot | ||
} | ||
} | ||
// Append a zero-length label to mark the end of the domain name | ||
*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; | ||
struct domain_key dkey = { 0 }; | ||
__u8 value = 1; | ||
|
||
// Check for proper number of arguments | ||
if (argc != 4) { | ||
fprintf(stderr, "Usage: %s <map_path> <add|delete> <domain>\n", argv[0]); | ||
return 1; | ||
} | ||
|
||
// Encode the domain name with label lengths | ||
encode_domain(argv[3], 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 | ||
const char *map_path = argv[1]; | ||
map_fd = bpf_obj_get(map_path); | ||
if (map_fd < 0) { | ||
fprintf(stderr, "Failed to open map at %s: %s\n", map_path, strerror(errno)); | ||
return 1; | ||
} | ||
|
||
// Add or delete the domain based on the first argument | ||
if (strcmp(argv[2], "add") == 0) { | ||
// Update the map with the encoded domain name | ||
if (bpf_map_update_elem(map_fd, &dkey, &value, BPF_ANY) != 0) { | ||
fprintf(stderr, "Failed to add domain to map: %s\n", | ||
strerror(errno)); | ||
return 1; | ||
} | ||
printf("Domain %s added to denylist\n", argv[3]); | ||
} else if (strcmp(argv[2], "delete") == 0) { | ||
// Remove the domain from the map | ||
if (bpf_map_delete_elem(map_fd, &dkey) != 0) { | ||
fprintf(stderr, | ||
"Failed to remove domain from map: %s\n", | ||
strerror(errno)); | ||
return 1; | ||
} | ||
printf("Domain %s removed from denylist\n", argv[3]); | ||
} else { | ||
fprintf(stderr, "Invalid command: %s. Use 'add' or 'delete'.\n", | ||
argv[2]); | ||
return 1; | ||
} | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
#define DNS_PORT 53 | ||
#define RR_TYPE_OPT 41 | ||
|
||
#define FRAME_SIZE 1000000000 | ||
|
||
/* | ||
* Store the DNS header | ||
*/ | ||
struct dnshdr { | ||
__u16 id; | ||
union { | ||
struct { | ||
__u8 rd : 1; | ||
__u8 tc : 1; | ||
__u8 aa : 1; | ||
__u8 opcode : 4; | ||
__u8 qr : 1; | ||
|
||
__u8 rcode : 4; | ||
__u8 cd : 1; | ||
__u8 ad : 1; | ||
__u8 z : 1; | ||
__u8 ra : 1; | ||
} as_bits_and_pieces; | ||
__u16 as_value; | ||
} flags; | ||
__u16 qdcount; | ||
__u16 ancount; | ||
__u16 nscount; | ||
__u16 arcount; | ||
}; | ||
|
||
struct dns_qrr { | ||
__u16 qtype; | ||
__u16 qclass; | ||
}; | ||
|
||
struct dns_rr { | ||
__u16 type; | ||
__u16 class; | ||
__u32 ttl; | ||
__u16 rdata_len; | ||
} __attribute__((packed)); | ||
|
||
struct option { | ||
__u16 code; | ||
__u16 len; | ||
__u8 data[]; | ||
} __attribute__((packed)); | ||
|
||
/* | ||
* Recalculate the checksum | ||
*/ | ||
static __always_inline | ||
void update_checksum(__u16 *csum, __u16 old_val, __u16 new_val) | ||
{ | ||
__u32 new_csum_value; | ||
__u32 new_csum_comp; | ||
__u32 undo; | ||
|
||
undo = ~((__u32)*csum) + ~((__u32)old_val); | ||
new_csum_value = undo + (undo < ~((__u32)old_val)) + (__u32)new_val; | ||
new_csum_comp = new_csum_value + (new_csum_value < ((__u32)new_val)); | ||
new_csum_comp = (new_csum_comp & 0xFFFF) + (new_csum_comp >> 16); | ||
new_csum_comp = (new_csum_comp & 0xFFFF) + (new_csum_comp >> 16); | ||
*csum = (__u16)~new_csum_comp; | ||
} | ||
|
||
|
||
//TCP | ||
|
||
#define NSEC_PER_SEC 1000000000L | ||
|
||
#define ETH_ALEN 6 | ||
#define ETH_P_IP 0x0800 | ||
#define ETH_P_IPV6 0x86DD | ||
|
||
#define IP_DF 0x4000 | ||
#define IP_MF 0x2000 | ||
#define IP_OFFSET 0x1fff | ||
|
||
#define swap(a, b) \ | ||
do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) | ||
|
||
#define __get_unaligned_t(type, ptr) ({ \ | ||
const struct { type x; } __attribute__((__packed__)) *__pptr = (typeof(__pptr))(ptr); \ | ||
__pptr->x; \ | ||
}) | ||
|
||
#define get_unaligned(ptr) __get_unaligned_t(typeof(*(ptr)), (ptr)) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* | ||
* 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 <https://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <stdio.h> | ||
#include <arpa/inet.h> | ||
#include <bpf/libbpf.h> | ||
#include <bpf/bpf.h> | ||
#include <syslog.h> | ||
|
||
#define MAX_DOMAIN_SIZE 63 | ||
|
||
struct qname_event { | ||
__u8 len; | ||
__u32 src_ip; // IPv4 address | ||
char qname[MAX_DOMAIN_SIZE + 1]; | ||
}; | ||
|
||
// Helper function to convert DNS label to a standard domain format | ||
void dns_label_to_dot_notation(char *dns_name, char *output, size_t len) | ||
{ | ||
size_t pos = 0, out_pos = 0; | ||
|
||
while (pos < len) { | ||
__u8 label_len = dns_name[pos]; | ||
if (label_len == 0) | ||
break; // End of domain name | ||
|
||
if (out_pos != 0) { | ||
output[out_pos++] = '.'; // Add a dot between labels | ||
} | ||
|
||
// Copy the label | ||
for (int i = 1; i <= label_len; i++) { | ||
output[out_pos++] = dns_name[pos + i]; | ||
} | ||
|
||
pos += label_len + 1; // Move to the next label | ||
} | ||
|
||
output[out_pos] = '\0'; // Null-terminate the result | ||
} | ||
|
||
// Corrected handle_event function to match the signature expected by ring_buffer__new | ||
int handle_event(void *ctx __attribute__((unused)), void *data, | ||
size_t data_sz __attribute__((unused))) | ||
{ | ||
struct qname_event *event = (struct qname_event *)data; | ||
|
||
char src_ip_str[INET_ADDRSTRLEN]; | ||
inet_ntop(AF_INET, &event->src_ip, src_ip_str, sizeof(src_ip_str)); | ||
|
||
char domain_str[MAX_DOMAIN_SIZE] = { 0 }; | ||
dns_label_to_dot_notation(event->qname, domain_str, event->len); | ||
|
||
syslog(LOG_INFO, "Received qname: %s from source IP: %s", domain_str, | ||
src_ip_str); | ||
|
||
return 0; // Return 0 to indicate success | ||
} | ||
|
||
int main(int argc, char *argv[]) | ||
{ | ||
if (argc != 2) { | ||
fprintf(stderr, "Usage: %s <path_to_ringbuf>\n", argv[0]); | ||
return 1; | ||
} | ||
|
||
const char *ringbuf_path = argv[1]; | ||
struct ring_buffer *rb; | ||
int ringbuf_fd; | ||
|
||
openlog("qname_logger", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); | ||
|
||
// Open the ring buffer | ||
ringbuf_fd = bpf_obj_get(ringbuf_path); | ||
if (ringbuf_fd < 0) { | ||
perror("Failed to open ring buffer"); | ||
return 1; | ||
} | ||
|
||
// Set up ring buffer polling with the corrected function signature | ||
rb = ring_buffer__new(ringbuf_fd, handle_event, NULL, NULL); | ||
if (!rb) { | ||
perror("Failed to create ring buffer"); | ||
return 1; | ||
} | ||
|
||
// Poll the ring buffer | ||
while (1) { | ||
ring_buffer__poll(rb, -1); // Block indefinitely | ||
} | ||
|
||
ring_buffer__free(rb); | ||
closelog(); | ||
return 0; | ||
} |
Oops, something went wrong.