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