Network Tracing

DNS Packet Parsing

Syscall buffer’larından dosya içeriğini okuduk. Şimdi network verisini okuyalım, özellikle IP adreslerini çıkarmak için DNS response’larını.

recvfrom syscall

DNS client’ları UDP response’larını almak için recvfrom() kullanır:

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);

read() gibi, entry/exit ilişkilendirmesine ihtiyacımız var:

  • Entry noktasında: Buffer boş, ancak ctx->args[1] adresindeki pointer’a sahibiz
  • Exit noktasında: Buffer DNS response ile dolmuş, ctx->ret = alınan byte sayısı

DNS paket yapısı

struct dns_header {
    u16 id;
    u16 flags;
    u16 qdcount;   // Question count
    u16 ancount;   // Answer count
    u16 nscount;
    u16 arcount;
};

Header’dan sonra: Question section (domain adı) - Answer section (IP adresi).

Domain adı encoding’i

DNS, domain’leri uzunluk ön ekli label’lar olarak encode eder: \x07ebpfhub\x03dev\x00 “ebpfhub.dev” için.

Parsing için:

int pos = sizeof(struct dns_header);
char domain[64];
int out = 0;

#pragma unroll
for (int i = 0; i < 10; i++) {  // Max 10 labels
    u8 len = buf[pos++];
    if (len == 0) break;

    #pragma unroll
    for (int j = 0; j < 63; j++) {
        if (j >= len) break;
        domain[out++] = buf[pos++];
    }

    if (buf[pos] != 0) domain[out++] = '.';
}

Answer section yapısı

Question’dan sonra (domain + QTYPE + QCLASS), answer şunları içerir:

// NAME (variable, often a pointer)
// TYPE (2 bytes) - 0x0001 for A record (IPv4)
// CLASS (2 bytes)
// TTL (4 bytes)
// RDLENGTH (2 bytes) - should be 4 for IPv4
// RDATA (4 bytes) - the IP address

A record’lar için RDATA, network byte order’daki IPv4 adresidir.

Görev

Bir program DNS sorguları yapıyor. “ebpfhub.dev” için gelen response’u bulun ve IP adresini gönderin.

recvfrom entry noktasında buffer pointer’ı saklayın. Exit noktasında DNS response’unu okuyun, question section’dan domain adını parse edin, bpf_strncmp() ile “ebpfhub.dev” ile eşleşip eşleşmediğini kontrol edin, ardından answer section’dan IPv4 adresini çıkarıp gönderin.

IP adresi network byte order’da 4 byte’tır. bpf_ntohl() ile u32’ye dönüştürün ve SUBMIT_NUM() ile gönderin.

Run your code to see execution events here