Remove includes of darkstat.h, add cdefs.h where needed.
[darkstat.git] / 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 "cdefs.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: */