Quantcast
Channel: Recent Questions - Stack Overflow
Viewing all articles
Browse latest Browse all 22484

How do i use AF_XDP, XDP and eBPF to send DNSpackets to resolver_addr

$
0
0

I am a XDP newbie and not much of a C guy, this program will be called from Golang using https://github.com/cilium/ebpf.What i want is to use XDP to send DNS resolution packets to a specified resolver_addr and receive a response. This wil be a high thoroughput program.

Reading and reviewing docs shows it's not going to be easy to send using XDP, so alternatively i was thinking of trying out io_uring to send and receive with AF_XDP.

Couldn't get this to work as sendto() isn't allow at that kernel level.

#include <linux/bpf.h>         // BPF helper functions and macros#include <bpf/bpf_helpers.h>#include <linux/if_ether.h>    // Ethernet header struct#include <linux/ip.h>          // IP header struct#include <linux/udp.h>         // UDP header struct#include <string.h>#include <stdlib.h>#include <stdio.h>#include <netinet/in.h>#include <unistd.h>#define ETH_HLEN 14            // Ethernet header length// DNS header structstruct dns_hdr {    __u16 id;    __u16 flags;    __u16 qdcount;    __u16 ancount;    __u16 nscount;    __u16 arcount;};// DNS query structstruct query {    __u16 qtype;    __u16 qclass;};// Key struct for perf event mapstruct dns_key {    __u32 saddr;    __u32 daddr;    __u16 sport;    __u16 dport;};// Define perf event mapstruct {    __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);    __uint(max_entries, 10240);} dns_results SEC(".maps");// Function to perform DNS resolution__u32 resolve_dns(char *domain, char *resolver_addr) {    // Open a raw socket for sending DNS queries    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);    if (sockfd < 0) {        perror("socket");        return 0;    }    // Set up the destination address for the resolver server    struct sockaddr_in dest_addr;    dest_addr.sin_family = AF_INET;    dest_addr.sin_port = htons(53); // DNS port    inet_pton(AF_INET, resolver_addr, &dest_addr.sin_addr);    // Create DNS query packet    size_t query_len = strlen(domain) + 2; // domain length + NULL byte + 1 byte for query type    __u8 *dns_query = (__u8 *)malloc(sizeof(struct dns_hdr) + query_len + sizeof(struct query));    if (!dns_query) {        perror("malloc");        close(sockfd);        return 0;    }    // Construct DNS query header    struct dns_hdr *header = (struct dns_hdr *)dns_query;    memset(header, 0, sizeof(struct dns_hdr));    header->id = htons(1234); // Random query ID    header->flags = htons(0x0100); // Standard query    header->qdcount = htons(1); // One question    __u8 *query = dns_query + sizeof(struct dns_hdr);    // Copy domain name into query    strcpy((char *)query, domain);    // Add query type (A record)    query += strlen(domain) + 1; // Move pointer past domain name    *(__u16 *)query = htons(1); // A record type    *(__u16 *)(query + 2) = htons(1); // IN class    // Send DNS query packet    if (sendto(sockfd, dns_query, sizeof(struct dns_hdr) + query_len + sizeof(struct query), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) < 0) {        perror("sendto");        free(dns_query);        close(sockfd);        return 0;    }    // Receive DNS response    __u8 dns_response[2048]; // Adjust the buffer size as needed    ssize_t num_bytes = recv(sockfd, dns_response, sizeof(dns_response), 0);    if (num_bytes < 0) {        perror("recv");        free(dns_query);        close(sockfd);        return 0;    }    // Parse DNS response and extract IP address    struct dns_hdr *resp_header = (struct dns_hdr *)dns_response;    if (ntohs(resp_header->ancount) < 1) {        free(dns_query);        close(sockfd);        return 0;    }    __u8 *answer_ptr = dns_response + sizeof(struct dns_hdr) + query_len + sizeof(struct query);    answer_ptr += 10; // Skip the name and type/class fields    __u32 ip_addr = 0;    memcpy(&ip_addr, answer_ptr, sizeof(ip_addr));    // Close socket and free memory    free(dns_query);    close(sockfd);    return ip_addr;}// XDP programSEC("xdp_dns")int dns_resolver(struct xdp_md *ctx, char *resolver_addr) {    void *data_end = (void *)(long)ctx->data_end;    void *data = (void *)(long)ctx->data;    struct ethhdr *eth = data;                    // Ethernet header    struct iphdr *ip = data + sizeof(struct ethhdr);  // IP header    struct udphdr *udp = (void *)ip + sizeof(struct iphdr);  // UDP header    struct dns_hdr *dns = (void *)udp + sizeof(struct udphdr);  // DNS header    struct query *q = (void *)dns + sizeof(struct dns_hdr);  // DNS query    // Check packet boundaries    if ((void *)ip + sizeof(struct iphdr) > data_end ||         (void *)udp + sizeof(struct udphdr) > data_end ||         (void *)dns + sizeof(struct dns_hdr) > data_end) {        return XDP_PASS;    }    // Check if UDP and DNS packet    if (ip->protocol != IPPROTO_UDP || ntohs(udp->dest) != 53) {        return XDP_PASS;    }    // Parse DNS query    if (ntohs(dns->qdcount) != 1) {        return XDP_PASS;    }    // Extract domain name from DNS query    char domain[256];    __u8 *ptr = (__u8 *)q;    int len = 0;    while (*ptr != 0 && (void *)ptr < data_end) {        int label_len = *ptr;        ptr++;        for (int i = 0; i < label_len && (void *)ptr < data_end; i++) {            domain[len++] = *ptr++;        }        domain[len++] = '.';    }    domain[len - 1] = '\0';    // Perform DNS resolution (pseudo code)    __u32 ip_addr = resolve_dns(domain, resolver_addr);    // Send result back to user space    struct dns_key key = {        .saddr = ip->saddr,        .daddr = ip->daddr,        .sport = udp->source,        .dport = udp->dest,    };    int ret = bpf_map_update_elem(&dns_results, &key, &ip_addr, BPF_ANY);    if (ret) {        // Error handling        return XDP_ABORTED; // Or another appropriate action    }    bpf_perf_event_output(ctx, &dns_results, BPF_F_CURRENT_CPU, &ip_addr, sizeof(ip_addr));    return XDP_PASS;}// Licensechar _license[] SEC("license") = "MIT";

Viewing all articles
Browse latest Browse all 22484

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>