12 #include <pcap/pcap.h>
15 #include <sys/socket.h>
21 static void show_usage(
const char *arg0,
const char *errmsg) {
22 cout <<
"Usage: " << arg0 <<
" [-i <intf>] [-F <file>] [-h|--help] <expression>\n\n"
23 <<
" -i <intf> only capture packets from <intf> (default: all)\n\n"
25 <<
" -F <file> reads in a filter expression from <file>\n"
26 <<
" <expression> is ignored if -F is supplied.\n\n"
28 <<
" -h, --help show this message\n\n"
29 <<
" <expression> a filter expression in pcap-filter(7) syntax\n";
31 if (errmsg !=
nullptr) {
32 cout <<
'\n' << errmsg;
37 static void check_arg(
char *arg0,
int argc,
int curr,
const char *errmsg) {
38 if (curr + 1 >= argc) {
47 if (
strncmp(
"-i", argv[curr], 3) == 0) {
48 check_arg(argv[0], argc, curr,
"ERROR: -i requires an argument");
49 *dev_ptr = argv[curr + 1];
52 }
else if ((
strncmp(
"-h", argv[curr], 3) == 0) || (
strncmp(
"--help", argv[curr], 7) == 0)) {
66 auto *addr =
reinterpret_cast<const in_addr *
>(data);
67 if (inet_ntop(AF_INET, addr,
static_cast<char *
>(addrbuf), 128) ==
nullptr) {
70 return string(
static_cast<char *
>(addrbuf));
75 auto *addr =
reinterpret_cast<const in6_addr *
>(data);
76 if (inet_ntop(AF_INET6, addr,
static_cast<char *
>(addrbuf), 128) ==
nullptr) {
79 return string(
static_cast<char *
>(addrbuf));
88 const uint8_t pt = data[0] & 0xf0;
91 data_offset = (data[0] & 0x0f) * 4;
92 if (
len < data_offset) {
95 if (data[9] != 0x11) {
101 }
else if (pt == 0x60) {
108 while (nxt != 0x11) {
109 if (nxt != 0 && nxt != 43 && nxt != 60) {
110 cerr <<
"Not UDP or fragmented; ";
113 nxt = data[data_offset];
114 data_offset += 8 * (1 + data[data_offset + 1]);
115 if (
len < data_offset + 2) {
125 return data_offset + 8;
128 int main(
int argc,
char **argv) {
133 if (dev !=
nullptr) {
134 cout <<
"Capturing on interface " << dev;
136 cout <<
"Capturing on all interfaces";
138 pcap_t *p_hdl =
nullptr;
139 const int dl_type = [&] {
140 char errbuf[PCAP_ERRBUF_SIZE] = {
143 p_hdl = pcap_open_live(dev, 65535, 0, 100,
static_cast<char *
>(errbuf));
144 if (p_hdl ==
nullptr) {
145 cout <<
"\nError initiating capture: " <<
static_cast<char *
>(errbuf) <<
endl;
148 int dlt = pcap_datalink(p_hdl);
150 if (dlt != DLT_RAW && dlt != DLT_NULL && dlt != DLT_EN10MB && dlt != DLT_LINUX_SLL
151 #ifdef DLT_LINUX_SLL2
152 && dlt != DLT_LINUX_SLL2
155 cout <<
"\nError: unsupported datalink type " << pcap_datalink_val_to_description(dlt) <<
endl;
158 cout <<
" (type: " << pcap_datalink_val_to_description(dlt) <<
")\n";
164 struct bpf_program p_flt {};
166 for (
int i = exp_start; i < argc; ++i) {
167 f_stream << argv[i] <<
' ';
169 string filter_expression = f_stream.
str();
170 cout <<
"Using filter expression: " << filter_expression <<
"\n";
171 if (pcap_compile(p_hdl, &p_flt, filter_expression.c_str(), 1, PCAP_NETMASK_UNKNOWN) != 0) {
172 cout <<
"Error compiling filter expression: " << pcap_geterr(p_hdl) <<
endl;
175 if (pcap_setfilter(p_hdl, &p_flt) != 0) {
176 cout <<
"Error configuring packet filter: " << pcap_geterr(p_hdl) <<
endl;
179 pcap_freecode(&p_flt);
183 struct pcap_pkthdr *pkt_hdr =
nullptr;
184 const uint8_t *pkt_data =
nullptr;
186 while ((next_ret = pcap_next_ex(p_hdl, &pkt_hdr, &pkt_data)) >= 0) {
195 if (dl_type == DLT_NULL) {
197 if (pkt_hdr->caplen < hdr_off) {
198 cerr <<
"[INFO] Skipping malformed packet.\n";
201 const uint8_t pt = pkt_data[3];
202 if (pt != 2 && pt != 24 && pt != 28 && pt != 30) {
203 cerr <<
"[INFO] Skipping non-IP packet.\n";
206 }
else if (dl_type == DLT_EN10MB) {
208 if (pkt_hdr->caplen < hdr_off) {
209 cerr <<
"[INFO] Skipping malformed packet.\n";
212 const uint16_t pt = (pkt_data[12] << 8) | pkt_data[13];
213 if (pt != 0x0800 && pt != 0x86dd) {
214 cerr <<
"[INFO] Skipping non-IP packet.\n";
217 }
else if (dl_type == DLT_LINUX_SLL) {
219 if (pkt_hdr->caplen < hdr_off) {
220 cerr <<
"[INFO] Skipping malformed packet.\n";
223 const uint16_t pt = (pkt_data[14] << 8) | pkt_data[15];
224 if (pt != 0x0800 && pt != 0x86dd) {
225 cerr <<
"[INFO] Skipping non-IP packet.\n";
228 #ifdef DLT_LINUX_SLL2
229 }
else if (dl_type == DLT_LINUX_SLL2) {
230 if (pkt_hdr->caplen < 20) {
231 cerr <<
"[INFO] Skipping malformed packet.\n";
234 const uint16_t pt = (pkt_data[0] << 8) | pkt_data[1];
236 if (pt != 0x0800 && pt != 0x86dd) {
237 cerr <<
"[INFO] Skipping non-IP packet.\n";
241 }
else if (dl_type != DLT_RAW) {
242 cerr <<
"Mysterious datalink type. Giving up.";
248 if ((start_off =
process_ipv4_ipv6(pkt_hdr->caplen - hdr_off, pkt_data + hdr_off, src, dst)) < 0) {
249 cerr <<
"Error parsing IPv4/IPv6 packet. Skipping.\n";
254 const size_t payload_off = hdr_off + start_off;
255 const size_t payload_len = pkt_hdr->caplen - payload_off;
257 string_view payload{
reinterpret_cast<const char *
>(pkt_data) + payload_off, payload_len};
262 cout <<
"(did not recognize TCP header) src: " << src <<
" dst: " << dst <<
'\n';
265 uint32_t seqlen = seg.length_in_sequence_space();
267 cout << src <<
':' << tcp_hdr.
sport <<
" > " << dst <<
':' << tcp_hdr.
dport <<
"\n Flags ["
269 << (tcp_hdr.
urg ?
"U" :
"") << (tcp_hdr.
psh ?
"P" :
"") << (tcp_hdr.
rst ?
"R" :
"")
270 << (tcp_hdr.
syn ?
"S" :
"") << (tcp_hdr.
fin ?
"F" :
"") << (tcp_hdr.
ack ?
"." :
"")
275 <<
" seq " << tcp_hdr.
seqno;
281 cout <<
" ack " << tcp_hdr.
ackno <<
" win " << tcp_hdr.
win <<
" length " << payload_len <<
endl;
283 hexdump(payload.data(), payload.size(), 8);
287 if (next_ret == -1) {
288 cout <<
"Error listening for packet: " << pcap_geterr(p_hdl) <<
endl;