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