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