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