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