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