Last active
October 12, 2024 21:01
-
-
Save chrisaycock/f0e064314cdfe48d5d662fd188332b74 to your computer and use it in GitHub Desktop.
Example for accessing UDP packets in a pcap file
This file contains hidden or 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
// answer to https://quant.stackexchange.com/q/55088/35 | |
// compile with c++ pcap_udp.cpp -lpcap | |
#include <iostream> | |
#include <pcap/pcap.h> | |
#include <netinet/if_ether.h> | |
#include <netinet/ip.h> | |
#include <netinet/udp.h> | |
// return payload and length by skipping headers in a packet | |
const u_char* get_payload(const u_char *packet, u_int *length) { | |
const ip* ip_; | |
const udphdr* udphdr_; | |
u_int ip_length; | |
u_int udphdr_length; | |
// Ethernet header starts with destination and source addresses | |
const u_char* payload = packet; | |
payload += 12; | |
// search for IP header; assume all other Ethernet types are vlan | |
while (ntohs(*reinterpret_cast<const u_short*>(payload)) != ETHERTYPE_IP) { | |
payload += 4; | |
} | |
payload += 2; | |
// IP header can vary in length | |
ip_ = reinterpret_cast<const ip*>(payload); | |
ip_length = ip_->ip_hl * 4; | |
payload += ip_length; | |
// ensure this is UDP | |
if (ip_->ip_p != IPPROTO_UDP) { | |
*length = 0; | |
payload = nullptr; | |
} | |
else { | |
// UDP header is static length | |
udphdr_ = reinterpret_cast<const udphdr*>(payload); | |
udphdr_length = sizeof(udphdr); | |
*length = ntohs(udphdr_->uh_ulen) - udphdr_length; | |
payload += udphdr_length; | |
} | |
return payload; | |
} | |
int main(int argc, char* argv[]) { | |
// verify parameters | |
if (argc != 2) { | |
std::cerr << "Usage: " << argv[0] << " file.pcap" << std::endl; | |
return 1; | |
} | |
// open the pcap file | |
char errbuf[PCAP_ERRBUF_SIZE]; | |
pcap_t* p = pcap_open_offline(argv[1], errbuf); | |
if (p == nullptr) { | |
std::cerr << "Error: " << errbuf << std::endl; | |
return 1; | |
} | |
bool done = false; | |
while (!done) { | |
// read a packet | |
pcap_pkthdr* header; | |
const u_char* packet; | |
const u_char* payload; | |
u_int payload_length; | |
int ret = pcap_next_ex(p, &header, &packet); | |
// handle packet | |
switch (ret) { | |
case 1: | |
// legitimate packet | |
payload = get_payload(packet, &payload_length); | |
std::cout << "Got data of length " << payload_length << std::endl; | |
break; | |
case 0: | |
// timeout | |
break; | |
case -1: | |
// error | |
std::cerr << "Error: " << pcap_geterr(p) << std::endl; | |
return 1; | |
case -2: | |
// end of file | |
done = true; | |
break; | |
} | |
} | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I see. Thank you so much. Wow, this is more work than I thought. I was hoping I could cast the payload to some human readable format such as a string and use string operators (or regex) to extract the fields.
But I guess I have to decode each field separately using byte operations. As always, I am beyond grateful for your help here. I will get back to you on Empirical later this week.