Small IPv6 corrections and an IPv6 hash function.
[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 linkhdr_t 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_t record matching the given linktype, or
108 * NULL if no matching entry found.
109 */
110 const linkhdr_t *
111 getlinkhdr(int linktype)
112 {
113 int 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 linkhdr_t *lh)
128 {
129 assert(lh != NULL);
130 return (lh->hdrlen + IPV6_HDR_LEN + max(TCP_HDR_LEN, UDP_HDR_LEN));
131 }
132
133 /*
134 * Convert IP address to a numbers-and-dots notation in a static buffer
135 * provided by inet_ntoa().
136 */
137 char *
138 ip_to_str(const in_addr_t ip)
139 {
140 struct in_addr in;
141
142 in.s_addr = ip;
143 return (inet_ntoa(in));
144 }
145
146 char ip6str[INET6_ADDRSTRLEN];
147
148 char *
149 ip6_to_str(const struct in6_addr *ip6)
150 {
151 ip6str[0] = '\0';
152 inet_ntop(AF_INET6, ip6, ip6str, sizeof(ip6str));
153
154 return (ip6str);
155 }
156
157 /* Decoding functions. */
158 static void
159 decode_ether(u_char *user _unused_,
160 const struct pcap_pkthdr *pheader,
161 const u_char *pdata)
162 {
163 u_short type;
164 const struct ether_header *hdr = (const struct ether_header *)pdata;
165 pktsummary sm;
166 memset(&sm, 0, sizeof(sm));
167 sm.time = pheader->ts.tv_sec;
168
169 if (pheader->caplen < ETHER_HDR_LEN) {
170 verbosef("ether: packet too short (%u bytes)", pheader->caplen);
171 return;
172 }
173
174 #ifdef __sun
175 memcpy(sm.src_mac, hdr->ether_shost.ether_addr_octet, sizeof(sm.src_mac));
176 memcpy(sm.dst_mac, hdr->ether_dhost.ether_addr_octet, sizeof(sm.dst_mac));
177 #else
178 memcpy(sm.src_mac, hdr->ether_shost, sizeof(sm.src_mac));
179 memcpy(sm.dst_mac, hdr->ether_dhost, sizeof(sm.dst_mac));
180 #endif
181
182 type = ntohs( hdr->ether_type );
183 switch (type) {
184 case ETHERTYPE_IP:
185 case ETHERTYPE_IPV6:
186 if (!want_pppoe) {
187 decode_ip(pdata + ETHER_HDR_LEN,
188 pheader->caplen - ETHER_HDR_LEN, &sm);
189 acct_for(&sm);
190 } else
191 verbosef("ether: discarded IP packet, expecting PPPoE instead");
192 break;
193 case ETHERTYPE_ARP:
194 /* known protocol, don't complain about it. */
195 break;
196 case ETHERTYPE_PPPOE:
197 if (want_pppoe)
198 decode_pppoe_real(pdata + ETHER_HDR_LEN,
199 pheader->caplen - ETHER_HDR_LEN, &sm);
200 else
201 verbosef("ether: got PPPoE frame: maybe you want --pppoe");
202 break;
203 default:
204 verbosef("ether: unknown protocol (0x%04x)", type);
205 }
206 }
207
208 static void
209 decode_loop(u_char *user _unused_,
210 const struct pcap_pkthdr *pheader,
211 const u_char *pdata)
212 {
213 uint32_t family;
214 pktsummary sm;
215 memset(&sm, 0, sizeof(sm));
216
217 if (pheader->caplen < NULL_HDR_LEN) {
218 verbosef("loop: packet too short (%u bytes)", pheader->caplen);
219 return;
220 }
221 family = *(const uint32_t *)pdata;
222 #ifdef __OpenBSD__
223 family = ntohl(family);
224 #endif
225 if (family == AF_INET) {
226 /* OpenBSD tun or FreeBSD tun or FreeBSD lo */
227 decode_ip(pdata + NULL_HDR_LEN, pheader->caplen - NULL_HDR_LEN, &sm);
228 sm.time = pheader->ts.tv_sec;
229 acct_for(&sm);
230 }
231 else if (family == AF_INET6) {
232 /* XXX: Check this! */
233 decode_ip(pdata + NULL_HDR_LEN, pheader->caplen - NULL_HDR_LEN, &sm);
234 sm.time = pheader->ts.tv_sec;
235 acct_for(&sm);
236 }
237 else
238 verbosef("loop: unknown family (%x)", family);
239 }
240
241 static void
242 decode_ppp(u_char *user _unused_,
243 const struct pcap_pkthdr *pheader,
244 const u_char *pdata)
245 {
246 pktsummary sm;
247 memset(&sm, 0, sizeof(sm));
248
249 if (pheader->caplen < PPPOE_HDR_LEN) {
250 verbosef("ppp: packet too short (%u bytes)", pheader->caplen);
251 return;
252 }
253
254 if (pdata[2] == 0x00 && pdata[3] == 0x21) {
255 decode_ip(pdata + PPP_HDR_LEN, pheader->caplen - PPP_HDR_LEN, &sm);
256 sm.time = pheader->ts.tv_sec;
257 acct_for(&sm);
258 } else
259 verbosef("non-IP PPP packet; ignoring.");
260 }
261
262 static void
263 decode_pppoe(u_char *user _unused_,
264 const struct pcap_pkthdr *pheader,
265 const u_char *pdata)
266 {
267 pktsummary sm;
268 memset(&sm, 0, sizeof(sm));
269 sm.time = pheader->ts.tv_sec;
270 decode_pppoe_real(pdata, pheader->caplen, &sm);
271 }
272
273 static void
274 decode_pppoe_real(const u_char *pdata, const uint32_t len,
275 pktsummary *sm)
276 {
277 if (len < PPPOE_HDR_LEN) {
278 verbosef("pppoe: packet too short (%u bytes)", len);
279 return;
280 }
281
282 if (pdata[1] != 0x00) {
283 verbosef("pppoe: code = 0x%02x, expecting 0; ignoring.", pdata[1]);
284 return;
285 }
286
287 if ((pdata[6] == 0xc0) && (pdata[7] == 0x21)) return; /* LCP */
288 if ((pdata[6] == 0xc0) && (pdata[7] == 0x25)) return; /* LQR */
289
290 if ((pdata[6] == 0x00) && (pdata[7] == 0x21)) {
291 decode_ip(pdata + PPPOE_HDR_LEN, len - PPPOE_HDR_LEN, sm);
292 acct_for(sm);
293 } else
294 verbosef("pppoe: non-IP PPPoE packet (0x%02x%02x); ignoring.",
295 pdata[6], pdata[7]);
296 }
297
298 /* very similar to decode_ether ... */
299 static void
300 decode_linux_sll(u_char *user _unused_,
301 const struct pcap_pkthdr *pheader,
302 const u_char *pdata)
303 {
304 const struct sll_header {
305 uint16_t packet_type;
306 uint16_t device_type;
307 uint16_t addr_length;
308 #define SLL_MAX_ADDRLEN 8
309 uint8_t addr[SLL_MAX_ADDRLEN];
310 uint16_t ether_type;
311 } *hdr = (const struct sll_header *)pdata;
312 u_short type;
313 pktsummary sm;
314 memset(&sm, 0, sizeof(sm));
315
316 if (pheader->caplen < SLL_HDR_LEN) {
317 verbosef("linux_sll: packet too short (%u bytes)", pheader->caplen);
318 return;
319 }
320
321 type = ntohs( hdr->ether_type );
322 switch (type) {
323 case ETHERTYPE_IP:
324 case ETHERTYPE_IPV6:
325 decode_ip(pdata + SLL_HDR_LEN, pheader->caplen - SLL_HDR_LEN, &sm);
326 sm.time = pheader->ts.tv_sec;
327 acct_for(&sm);
328 break;
329 case ETHERTYPE_ARP:
330 /* known protocol, don't complain about it. */
331 break;
332 default:
333 verbosef("linux_sll: unknown protocol (%04x)", type);
334 }
335 }
336
337 static void
338 decode_raw(u_char *user _unused_,
339 const struct pcap_pkthdr *pheader,
340 const u_char *pdata)
341 {
342 pktsummary sm;
343 memset(&sm, 0, sizeof(sm));
344
345 decode_ip(pdata, pheader->caplen, &sm);
346 sm.time = pheader->ts.tv_sec;
347 acct_for(&sm);
348 }
349
350 static void
351 decode_ip(const u_char *pdata, const uint32_t len, pktsummary *sm)
352 {
353 const struct ip *hdr = (const struct ip *)pdata;
354
355 if (hdr->ip_v == 6) {
356 /* Redirect parsing of IPv6 packets. */
357 decode_ipv6(pdata, len, sm);
358 return;
359 }
360 if (len < IP_HDR_LEN) {
361 verbosef("ip: packet too short (%u bytes)", len);
362 return;
363 }
364 if (hdr->ip_v != 4) {
365 verbosef("ip: version %d (expecting 4 or 6)", hdr->ip_v);
366 return;
367 }
368
369 sm->len = ntohs(hdr->ip_len);
370 sm->af = AF_INET;
371 sm->proto = hdr->ip_p;
372 sm->src_ip = hdr->ip_src.s_addr;
373 sm->dest_ip = hdr->ip_dst.s_addr;
374
375 switch (sm->proto) {
376 case IPPROTO_TCP: {
377 const struct tcphdr *thdr =
378 (const struct tcphdr *)(pdata + IP_HDR_LEN);
379 if (len < IP_HDR_LEN + TCP_HDR_LEN) {
380 verbosef("tcp: packet too short (%u bytes)", len);
381 return;
382 }
383 sm->src_port = ntohs(thdr->th_sport);
384 sm->dest_port = ntohs(thdr->th_dport);
385 sm->tcp_flags = thdr->th_flags &
386 (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG);
387 break;
388 }
389
390 case IPPROTO_UDP: {
391 const struct udphdr *uhdr =
392 (const struct udphdr *)(pdata + IP_HDR_LEN);
393 if (len < IP_HDR_LEN + UDP_HDR_LEN) {
394 verbosef("udp: packet too short (%u bytes)", len);
395 return;
396 }
397 sm->src_port = ntohs(uhdr->uh_sport);
398 sm->dest_port = ntohs(uhdr->uh_dport);
399 break;
400 }
401
402 case IPPROTO_ICMP:
403 /* known protocol, don't complain about it */
404 break;
405
406 default:
407 verbosef("ip: unknown protocol %d", sm->proto);
408 }
409 }
410
411 static void
412 decode_ipv6(const u_char *pdata, const uint32_t len, pktsummary *sm)
413 {
414 const struct ip6_hdr *hdr = (const struct ip6_hdr *)pdata;
415
416 if (len < IPV6_HDR_LEN) {
417 verbosef("ipv6: packet too short (%u bytes)", len);
418 return;
419 }
420
421 sm->len = ntohs(hdr->ip6_plen) + IPV6_HDR_LEN;
422 sm->af = AF_INET6;
423 sm->proto = hdr->ip6_nxt;
424 memcpy(&sm->src_ip6, &hdr->ip6_src, sizeof(sm->src_ip6));
425 memcpy(&sm->dest_ip6, &hdr->ip6_dst, sizeof(sm->dest_ip6));
426
427 switch (sm->proto) {
428 case IPPROTO_TCP: {
429 const struct tcphdr *thdr =
430 (const struct tcphdr *)(pdata + IPV6_HDR_LEN);
431 if (len < IPV6_HDR_LEN + TCP_HDR_LEN) {
432 verbosef("tcp6: packet too short (%u bytes)", len);
433 return;
434 }
435 sm->src_port = ntohs(thdr->th_sport);
436 sm->dest_port = ntohs(thdr->th_dport);
437 sm->tcp_flags = thdr->th_flags &
438 (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG);
439 break;
440 }
441
442 case IPPROTO_UDP: {
443 const struct udphdr *uhdr =
444 (const struct udphdr *)(pdata + IPV6_HDR_LEN);
445 if (len < IPV6_HDR_LEN + UDP_HDR_LEN) {
446 verbosef("udp6: packet too short (%u bytes)", len);
447 return;
448 }
449 sm->src_port = ntohs(uhdr->uh_sport);
450 sm->dest_port = ntohs(uhdr->uh_dport);
451 break;
452 }
453
454 case IPPROTO_ICMPV6:
455 /* known protocol, don't complain about it */
456 break;
457
458 default:
459 verbosef("ipv6: unknown protocol %d", sm->proto);
460 }
461 }
462
463 /* vim:set ts=3 sw=3 tw=78 expandtab: */