Don't hide that linkhdr_t is a struct.
[darkstat] / decode.c
1 /* darkstat 3
2 * copyright (c) 2001-2009 Emil Mikulic.
3 *
4 * decode.c: packet decoding.
5 *
6 * Given a captured packet, decode it and fill out a pktsummary struct which
7 * will be sent to the accounting code in acct.c
8 *
9 * You may use, modify and redistribute this file under the terms of the
10 * GNU General Public License version 2. (see COPYING.GPL)
11 */
12
13 #include "darkstat.h"
14 #include "acct.h"
15 #include "cap.h"
16
17 #include <sys/ioctl.h>
18 #include <sys/socket.h>
19 #include <assert.h>
20 #include "err.h"
21 #include <pcap.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <arpa/inet.h> /* inet_ntoa() */
25
26 /* need struct ether_header */
27 #if defined(__NetBSD__) || defined(__OpenBSD__)
28 # include <sys/queue.h>
29 # include <net/if.h>
30 # include <net/if_arp.h>
31 # include <netinet/if_ether.h>
32 #else
33 # ifdef __sun
34 # include <sys/ethernet.h>
35 # define ETHER_HDR_LEN 14
36 # else
37 # ifdef _AIX
38 # include <netinet/if_ether.h>
39 # define ETHER_HDR_LEN 14
40 # else
41 # include <net/ethernet.h>
42 # endif
43 # endif
44 #endif
45 #ifndef ETHERTYPE_PPPOE
46 #define ETHERTYPE_PPPOE 0x8864
47 #endif
48
49 #ifndef ETHERTYPE_IPV6
50 # ifdef HAVE_NET_IF_ETHER_H
51 # include <net/if_ether.h> /* ETH_P_IPV6 for GNU/kfreebsd */
52 # endif
53 # ifdef ETH_P_IPV6
54 # define ETHERTYPE_IPV6 ETH_P_IPV6
55 # endif
56 #endif
57
58 #include <net/if.h> /* struct ifreq */
59 #include <netinet/in_systm.h> /* n_long */
60 #include <netinet/ip.h> /* struct ip */
61 #include <netinet/ip6.h> /* struct ip6_hdr */
62 #define __FAVOR_BSD
63 #include <netinet/tcp.h> /* struct tcphdr */
64 #include <netinet/udp.h> /* struct udphdr */
65
66 extern int want_pppoe;
67
68 static void decode_ether(u_char *, const struct pcap_pkthdr *,
69 const u_char *);
70 static void decode_loop(u_char *, const struct pcap_pkthdr *,
71 const u_char *);
72 static void decode_ppp(u_char *, const struct pcap_pkthdr *,
73 const u_char *);
74 static void decode_pppoe(u_char *, const struct pcap_pkthdr *,
75 const u_char *);
76 static void decode_pppoe_real(const u_char *pdata, const uint32_t len,
77 pktsummary *sm);
78 static void decode_linux_sll(u_char *, const struct pcap_pkthdr *,
79 const u_char *);
80 static void decode_raw(u_char *, const struct pcap_pkthdr *,
81 const u_char *);
82 static void decode_ip(const u_char *pdata, const uint32_t len,
83 pktsummary *sm);
84 static void decode_ipv6(const u_char *pdata, const uint32_t len,
85 pktsummary *sm);
86
87 /* Link-type header information */
88 static const struct linkhdr linkhdrs[] = {
89 /* linktype hdrlen handler */
90 { DLT_EN10MB, ETHER_HDR_LEN, decode_ether },
91 { DLT_LOOP, NULL_HDR_LEN, decode_loop },
92 { DLT_NULL, NULL_HDR_LEN, decode_loop },
93 { DLT_PPP, PPP_HDR_LEN, decode_ppp },
94 #if defined(__NetBSD__)
95 { DLT_PPP_SERIAL, PPP_HDR_LEN, decode_ppp },
96 #endif
97 { DLT_FDDI, FDDI_HDR_LEN, NULL },
98 { DLT_PPP_ETHER, PPPOE_HDR_LEN, decode_pppoe },
99 #ifdef DLT_LINUX_SLL
100 { DLT_LINUX_SLL, SLL_HDR_LEN, decode_linux_sll },
101 #endif
102 { DLT_RAW, RAW_HDR_LEN, decode_raw },
103 { -1, -1, NULL }
104 };
105
106 /*
107 * Returns a pointer to the linkhdr record matching the given linktype, or
108 * NULL if no matching entry found.
109 */
110 const struct linkhdr *
111 getlinkhdr(const int linktype)
112 {
113 size_t i;
114
115 for (i=0; linkhdrs[i].linktype != -1; i++)
116 if (linkhdrs[i].linktype == linktype)
117 return (&(linkhdrs[i]));
118 return (NULL);
119 }
120
121 /*
122 * Returns the minimum snaplen needed to decode everything up to the TCP/UDP
123 * packet headers. The IPv6 header is normative. The argument lh is not
124 * allowed to be NULL.
125 */
126 int
127 getsnaplen(const struct linkhdr *lh)
128 {
129 assert(lh != NULL);
130 /* TODO MEA Investigate why the supplementary value 20 is needed on GNU/Linux. */
131 return (20 + lh->hdrlen + IPV6_HDR_LEN + max(TCP_HDR_LEN, UDP_HDR_LEN));
132 }
133
134 /*
135 * Convert IP address to a presentation notation in a static buffer
136 * using inet_ntop(3).
137 */
138 char ipstr[INET6_ADDRSTRLEN]; /* TODO Reentrant? */
139
140 char *
141 ip_to_str(const struct addr46 *const ip)
142 {
143 ipstr[0] = '\0';
144 inet_ntop(ip->af, &ip->addr.ip6, ipstr, sizeof(ipstr));
145
146 return (ipstr);
147 }
148
149 char *
150 ip_to_str_af(const void *const addr, sa_family_t af)
151 {
152 ipstr[0] = '\0';
153 inet_ntop(af, addr, ipstr, sizeof(ipstr));
154
155 return (ipstr);
156 }
157
158 /* Decoding functions. */
159 static void
160 decode_ether(u_char *user _unused_,
161 const struct pcap_pkthdr *pheader,
162 const u_char *pdata)
163 {
164 u_short type;
165 const struct ether_header *hdr = (const struct ether_header *)pdata;
166 pktsummary sm;
167 memset(&sm, 0, sizeof(sm));
168 sm.time = pheader->ts.tv_sec;
169
170 if (pheader->caplen < ETHER_HDR_LEN) {
171 verbosef("ether: packet too short (%u bytes)", pheader->caplen);
172 return;
173 }
174
175 #ifdef __sun
176 memcpy(sm.src_mac, hdr->ether_shost.ether_addr_octet, sizeof(sm.src_mac));
177 memcpy(sm.dst_mac, hdr->ether_dhost.ether_addr_octet, sizeof(sm.dst_mac));
178 #else
179 memcpy(sm.src_mac, hdr->ether_shost, sizeof(sm.src_mac));
180 memcpy(sm.dst_mac, hdr->ether_dhost, sizeof(sm.dst_mac));
181 #endif
182
183 type = ntohs( hdr->ether_type );
184 switch (type) {
185 case ETHERTYPE_IP:
186 case ETHERTYPE_IPV6:
187 if (!want_pppoe) {
188 decode_ip(pdata + ETHER_HDR_LEN,
189 pheader->caplen - ETHER_HDR_LEN, &sm);
190 acct_for(&sm);
191 } else
192 verbosef("ether: discarded IP packet, expecting PPPoE instead");
193 break;
194 case ETHERTYPE_ARP:
195 /* known protocol, don't complain about it. */
196 break;
197 case ETHERTYPE_PPPOE:
198 if (want_pppoe)
199 decode_pppoe_real(pdata + ETHER_HDR_LEN,
200 pheader->caplen - ETHER_HDR_LEN, &sm);
201 else
202 verbosef("ether: got PPPoE frame: maybe you want --pppoe");
203 break;
204 default:
205 verbosef("ether: unknown protocol (0x%04x)", type);
206 }
207 }
208
209 static void
210 decode_loop(u_char *user _unused_,
211 const struct pcap_pkthdr *pheader,
212 const u_char *pdata)
213 {
214 uint32_t family;
215 pktsummary sm;
216 memset(&sm, 0, sizeof(sm));
217
218 if (pheader->caplen < NULL_HDR_LEN) {
219 verbosef("loop: packet too short (%u bytes)", pheader->caplen);
220 return;
221 }
222 family = *(const uint32_t *)pdata;
223 #ifdef __OpenBSD__
224 family = ntohl(family);
225 #endif
226 if (family == AF_INET) {
227 /* OpenBSD tun or FreeBSD tun or FreeBSD lo */
228 decode_ip(pdata + NULL_HDR_LEN, pheader->caplen - NULL_HDR_LEN, &sm);
229 sm.time = pheader->ts.tv_sec;
230 acct_for(&sm);
231 }
232 else if (family == AF_INET6) {
233 /* XXX: Check this! */
234 decode_ip(pdata + NULL_HDR_LEN, pheader->caplen - NULL_HDR_LEN, &sm);
235 sm.time = pheader->ts.tv_sec;
236 acct_for(&sm);
237 }
238 else
239 verbosef("loop: unknown family (%x)", family);
240 }
241
242 static void
243 decode_ppp(u_char *user _unused_,
244 const struct pcap_pkthdr *pheader,
245 const u_char *pdata)
246 {
247 pktsummary sm;
248 memset(&sm, 0, sizeof(sm));
249
250 if (pheader->caplen < PPPOE_HDR_LEN) {
251 verbosef("ppp: packet too short (%u bytes)", pheader->caplen);
252 return;
253 }
254
255 if (pdata[2] == 0x00 && pdata[3] == 0x21) {
256 decode_ip(pdata + PPP_HDR_LEN, pheader->caplen - PPP_HDR_LEN, &sm);
257 sm.time = pheader->ts.tv_sec;
258 acct_for(&sm);
259 } else
260 verbosef("non-IP PPP packet; ignoring.");
261 }
262
263 static void
264 decode_pppoe(u_char *user _unused_,
265 const struct pcap_pkthdr *pheader,
266 const u_char *pdata)
267 {
268 pktsummary sm;
269 memset(&sm, 0, sizeof(sm));
270 sm.time = pheader->ts.tv_sec;
271 decode_pppoe_real(pdata, pheader->caplen, &sm);
272 }
273
274 static void
275 decode_pppoe_real(const u_char *pdata, const uint32_t len,
276 pktsummary *sm)
277 {
278 if (len < PPPOE_HDR_LEN) {
279 verbosef("pppoe: packet too short (%u bytes)", len);
280 return;
281 }
282
283 if (pdata[1] != 0x00) {
284 verbosef("pppoe: code = 0x%02x, expecting 0; ignoring.", pdata[1]);
285 return;
286 }
287
288 if ((pdata[6] == 0xc0) && (pdata[7] == 0x21)) return; /* LCP */
289 if ((pdata[6] == 0xc0) && (pdata[7] == 0x25)) return; /* LQR */
290
291 if ((pdata[6] == 0x00) && (pdata[7] == 0x21)) {
292 decode_ip(pdata + PPPOE_HDR_LEN, len - PPPOE_HDR_LEN, sm);
293 acct_for(sm);
294 } else
295 verbosef("pppoe: non-IP PPPoE packet (0x%02x%02x); ignoring.",
296 pdata[6], pdata[7]);
297 }
298
299 /* very similar to decode_ether ... */
300 static void
301 decode_linux_sll(u_char *user _unused_,
302 const struct pcap_pkthdr *pheader,
303 const u_char *pdata)
304 {
305 const struct sll_header {
306 uint16_t packet_type;
307 uint16_t device_type;
308 uint16_t addr_length;
309 #define SLL_MAX_ADDRLEN 8
310 uint8_t addr[SLL_MAX_ADDRLEN];
311 uint16_t ether_type;
312 } *hdr = (const struct sll_header *)pdata;
313 u_short type;
314 pktsummary sm;
315 memset(&sm, 0, sizeof(sm));
316
317 if (pheader->caplen < SLL_HDR_LEN) {
318 verbosef("linux_sll: packet too short (%u bytes)", pheader->caplen);
319 return;
320 }
321
322 type = ntohs( hdr->ether_type );
323 switch (type) {
324 case ETHERTYPE_IP:
325 case ETHERTYPE_IPV6:
326 decode_ip(pdata + SLL_HDR_LEN, pheader->caplen - SLL_HDR_LEN, &sm);
327 sm.time = pheader->ts.tv_sec;
328 acct_for(&sm);
329 break;
330 case ETHERTYPE_ARP:
331 /* known protocol, don't complain about it. */
332 break;
333 default:
334 verbosef("linux_sll: unknown protocol (%04x)", type);
335 }
336 }
337
338 static void
339 decode_raw(u_char *user _unused_,
340 const struct pcap_pkthdr *pheader,
341 const u_char *pdata)
342 {
343 pktsummary sm;
344 memset(&sm, 0, sizeof(sm));
345
346 decode_ip(pdata, pheader->caplen, &sm);
347 sm.time = pheader->ts.tv_sec;
348 acct_for(&sm);
349 }
350
351 static void
352 decode_ip(const u_char *pdata, const uint32_t len, pktsummary *sm)
353 {
354 const struct ip *hdr = (const struct ip *)pdata;
355
356 if (hdr->ip_v == 6) {
357 /* Redirect parsing of IPv6 packets. */
358 decode_ipv6(pdata, len, sm);
359 return;
360 }
361 if (len < IP_HDR_LEN) {
362 verbosef("ip: packet too short (%u bytes)", len);
363 return;
364 }
365 if (hdr->ip_v != 4) {
366 verbosef("ip: version %d (expecting 4 or 6)", hdr->ip_v);
367 return;
368 }
369
370 sm->len = ntohs(hdr->ip_len);
371 sm->af = AF_INET;
372 sm->proto = hdr->ip_p;
373 memcpy(&sm->src_ip, &hdr->ip_src, sizeof(sm->src_ip));
374 memcpy(&sm->dest_ip, &hdr->ip_dst, sizeof(sm->dest_ip));
375
376 switch (sm->proto) {
377 case IPPROTO_TCP: {
378 const struct tcphdr *thdr =
379 (const struct tcphdr *)(pdata + IP_HDR_LEN);
380 if (len < IP_HDR_LEN + TCP_HDR_LEN) {
381 verbosef("tcp: packet too short (%u bytes)", len);
382 return;
383 }
384 sm->src_port = ntohs(thdr->th_sport);
385 sm->dest_port = ntohs(thdr->th_dport);
386 sm->tcp_flags = thdr->th_flags &
387 (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG);
388 break;
389 }
390
391 case IPPROTO_UDP: {
392 const struct udphdr *uhdr =
393 (const struct udphdr *)(pdata + IP_HDR_LEN);
394 if (len < IP_HDR_LEN + UDP_HDR_LEN) {
395 verbosef("udp: packet too short (%u bytes)", len);
396 return;
397 }
398 sm->src_port = ntohs(uhdr->uh_sport);
399 sm->dest_port = ntohs(uhdr->uh_dport);
400 break;
401 }
402
403 case IPPROTO_ICMP:
404 case IPPROTO_AH:
405 case IPPROTO_ESP:
406 case IPPROTO_OSPF:
407 /* known protocol, don't complain about it */
408 break;
409
410 default:
411 verbosef("ip: unknown protocol %d", sm->proto);
412 }
413 }
414
415 static void
416 decode_ipv6(const u_char *pdata, const uint32_t len, pktsummary *sm)
417 {
418 const struct ip6_hdr *hdr = (const struct ip6_hdr *)pdata;
419
420 if (len < IPV6_HDR_LEN) {
421 verbosef("ipv6: packet too short (%u bytes)", len);
422 return;
423 }
424
425 sm->len = ntohs(hdr->ip6_plen) + IPV6_HDR_LEN;
426 sm->af = AF_INET6;
427 sm->proto = hdr->ip6_nxt;
428 memcpy(&sm->src_ip6, &hdr->ip6_src, sizeof(sm->src_ip6));
429 memcpy(&sm->dest_ip6, &hdr->ip6_dst, sizeof(sm->dest_ip6));
430
431 switch (sm->proto) {
432 case IPPROTO_TCP: {
433 const struct tcphdr *thdr =
434 (const struct tcphdr *)(pdata + IPV6_HDR_LEN);
435 if (len < IPV6_HDR_LEN + TCP_HDR_LEN) {
436 verbosef("tcp6: packet too short (%u bytes)", len);
437 return;
438 }
439 sm->src_port = ntohs(thdr->th_sport);
440 sm->dest_port = ntohs(thdr->th_dport);
441 sm->tcp_flags = thdr->th_flags &
442 (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG);
443 break;
444 }
445
446 case IPPROTO_UDP: {
447 const struct udphdr *uhdr =
448 (const struct udphdr *)(pdata + IPV6_HDR_LEN);
449 if (len < IPV6_HDR_LEN + UDP_HDR_LEN) {
450 verbosef("udp6: packet too short (%u bytes)", len);
451 return;
452 }
453 sm->src_port = ntohs(uhdr->uh_sport);
454 sm->dest_port = ntohs(uhdr->uh_dport);
455 break;
456 }
457
458 case IPPROTO_ICMPV6:
459 case IPPROTO_AH:
460 case IPPROTO_ESP:
461 case IPPROTO_OSPF:
462 /* known protocol, don't complain about it */
463 break;
464
465 default:
466 verbosef("ipv6: unknown protocol %d", sm->proto);
467 }
468 }
469
470 /* vim:set ts=3 sw=3 tw=78 expandtab: */