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