Network Tracing
TCP Packet Okuma - HTTP
Önceki alıştırmada TCP bağlantı tamamlanmasını takip etmek için kprobe’ları kullandık. Şimdi gönderilen HTTP verisini yakalayacağız.
sendto() syscall’ına bağlanabilirdik, ancak bu aynı zamanda DEBUG_* çağrılarını da içeren vsock transfer’lerini de yakalar, bu da oldukça zahmetli bir deneyim yaratır.
Ayrıca bu, kprobe bölümüne hiç uymaz!
Bunun yerine yalnızca TCP trafiği için çağrılan tcp_sendmsg() fonksiyonuna bağlanalım.
tcp_sendmsg’den veri okuma
tcp_sendmsg’in imzasını net/ipv4/tcp.c dosyasında bulabiliriz:
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
Userspace buffer’a msg parametresi üzerinden erişebiliriz, ancak bu biraz karmaşıktır.
struct msghdr’nin basitleştirilmiş tanımı:
struct msghdr {
struct iov_iter msg_iter; // Iterator containing buffer info
// ...
};
struct iov_iter {
union {
struct iovec __ubuf_iovec; // Userspace buffer base/len
// ...
};
};
struct iovec {
void *iov_base;
u64 iov_len;
};
Yani msg->msg_iter->__ubuf_iovec.iov_base içinde saklanan adresi kullanarak userspace buffer’ı okuyacağız.
Pointer’ları doğrudan dereference edemeyeceğimizi unutmayın, bu yüzden her dolaylama seviyesini manuel olarak okumanız gerekecek. Her pointer’ın address space’ini göz önünde bulundurun.
HTTP request yapısı
HTTP request’leri metin tabanlıdır:
POST /api/data HTTP/1.1
Host: example.com
Authorization: Bearer secret_token_here
Content-Type: application/json
Header’lar \r\n (CRLF) ile ayrılır. Her header Name: Value formatındadır.
Geçmişte, eBPF’te herhangi bir string tabanlı protokol üzerinde işlem yapmak son derece zahmetliydi. Şanslısınız, Haziran 2025’ten bu yana bazı string operasyonlarını doğrudan yapabiliyoruz.
Bu alıştırmada iki fonksiyon kullanacağız:
bpf_strstr(char *haystack, char *needle): Substring bulur, index veya hata durumunda negatif değer döndürürbpf_strchr(char* str, char c): Karakter bulur, index veya hata durumunda negatif değer döndürür
Örneğin,
int auth_pos = bpf_strstr(buf, "Authorization: Bearer ");
auth_pos, bulunursa needle’ın konumunu içerecektir.
Biraz matematik ile token’ın nerede başlaması gerektiğini bulabilir ve oradan satır sonuna (\r ile işaretlenmiş) kadar okuyabilirsiniz.
Satır sonuna ulaşmak için şunu kullanabilirsiniz:
int token_pos = bpf_strchr(&buf[token_start], '\r');
Bu size token_ptr’den başlayarak ilk \r’nin konumunu verecektir.
Görev
Bir program Authorization: Bearer <token> header’ı ile HTTP request’i yapıyor.
Yapmanız gereken
Header’daki token’ı gönderin.
Extract the Nth parameter from kprobe context
- Args:
struct pt_regs* ctxkprobe context containing CPU registers
Read string from user space into kernel buffer
- Args:
void* dstkernel buffer to read intou32 sizemaximum bytes to readconst void* srcuser space pointer to string
Read bytes from user space into kernel buffer
- Args:
void* dstkernel buffer to read intou32 sizebytes to readconst void* srcuser space pointer
Read bytes from kernel space into kernel buffer
- Args:
void* dstkernel buffer to read intou32 sizebytes to readconst void* srckernel space pointer
Read string from kernel space into kernel buffer
- Args:
void* dstkernel buffer to read intou32 sizemaximum bytes to readconst void* srckernel space pointer to string