2 * copyright (c) 2001-2009 Emil Mikulic.
4 * decode.c: packet decoding.
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
9 * You may use, modify and redistribute this file under the terms of the
10 * GNU General Public License version 2. (see COPYING.GPL)
19 #include <sys/ioctl.h>
20 #include <sys/socket.h>
25 #include <arpa/inet.h> /* inet_ntoa() */
27 /* need struct ether_header */
28 #if defined(__NetBSD__) || defined(__OpenBSD__)
29 # include <sys/queue.h>
31 # include <net/if_arp.h>
32 # include <netinet/if_ether.h>
35 # include <sys/ethernet.h>
36 # define ETHER_HDR_LEN 14
39 # include <netinet/if_ether.h>
40 # define ETHER_HDR_LEN 14
42 # include <net/ethernet.h>
46 #ifndef ETHERTYPE_PPPOE
47 #define ETHERTYPE_PPPOE 0x8864
50 #ifndef ETHERTYPE_IPV6
51 # ifdef HAVE_NET_IF_ETHER_H
52 # include <net/if_ether.h> /* ETH_P_IPV6 for GNU/kfreebsd */
55 # define ETHERTYPE_IPV6 ETH_P_IPV6
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 */
64 #include <netinet/tcp.h> /* struct tcphdr */
65 #include <netinet/udp.h> /* struct udphdr */
67 extern int want_pppoe
;
69 static void decode_ether(u_char
*, const struct pcap_pkthdr
*,
71 static void decode_loop(u_char
*, const struct pcap_pkthdr
*,
73 static void decode_ppp(u_char
*, const struct pcap_pkthdr
*,
75 static void decode_pppoe(u_char
*, const struct pcap_pkthdr
*,
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
*,
81 static void decode_raw(u_char
*, const struct pcap_pkthdr
*,
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
);
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
},
98 { DLT_FDDI
, FDDI_HDR_LEN
, NULL
},
99 { DLT_PPP_ETHER
, PPPOE_HDR_LEN
, decode_pppoe
},
101 { DLT_LINUX_SLL
, SLL_HDR_LEN
, decode_linux_sll
},
103 { DLT_RAW
, RAW_HDR_LEN
, decode_raw
},
108 * Returns a pointer to the linkhdr record matching the given linktype, or
109 * NULL if no matching entry found.
111 const struct linkhdr
*
112 getlinkhdr(const int linktype
)
116 for (i
=0; linkhdrs
[i
].linktype
!= -1; i
++)
117 if (linkhdrs
[i
].linktype
== linktype
)
118 return (&(linkhdrs
[i
]));
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.
128 getsnaplen(const struct linkhdr
*lh
)
131 /* TODO MEA Investigate why the supplementary value 20 is needed on GNU/Linux. */
132 return (20 + lh
->hdrlen
+ IPV6_HDR_LEN
+ max(TCP_HDR_LEN
, UDP_HDR_LEN
));
135 /* Decoding functions. */
137 decode_ether(u_char
*user _unused_
,
138 const struct pcap_pkthdr
*pheader
,
142 const struct ether_header
*hdr
= (const struct ether_header
*)pdata
;
143 struct pktsummary sm
;
144 memset(&sm
, 0, sizeof(sm
));
145 sm
.time
= pheader
->ts
.tv_sec
;
147 if (pheader
->caplen
< ETHER_HDR_LEN
) {
148 verbosef("ether: packet too short (%u bytes)", pheader
->caplen
);
153 memcpy(sm
.src_mac
, hdr
->ether_shost
.ether_addr_octet
, sizeof(sm
.src_mac
));
154 memcpy(sm
.dst_mac
, hdr
->ether_dhost
.ether_addr_octet
, sizeof(sm
.dst_mac
));
156 memcpy(sm
.src_mac
, hdr
->ether_shost
, sizeof(sm
.src_mac
));
157 memcpy(sm
.dst_mac
, hdr
->ether_dhost
, sizeof(sm
.dst_mac
));
160 type
= ntohs( hdr
->ether_type
);
165 decode_ip(pdata
+ ETHER_HDR_LEN
,
166 pheader
->caplen
- ETHER_HDR_LEN
, &sm
);
169 verbosef("ether: discarded IP packet, expecting PPPoE instead");
172 /* known protocol, don't complain about it. */
174 case ETHERTYPE_PPPOE
:
176 decode_pppoe_real(pdata
+ ETHER_HDR_LEN
,
177 pheader
->caplen
- ETHER_HDR_LEN
, &sm
);
179 verbosef("ether: got PPPoE frame: maybe you want --pppoe");
182 verbosef("ether: unknown protocol (0x%04x)", type
);
187 decode_loop(u_char
*user _unused_
,
188 const struct pcap_pkthdr
*pheader
,
192 struct pktsummary sm
;
193 memset(&sm
, 0, sizeof(sm
));
195 if (pheader
->caplen
< NULL_HDR_LEN
) {
196 verbosef("loop: packet too short (%u bytes)", pheader
->caplen
);
199 family
= *(const uint32_t *)pdata
;
201 family
= ntohl(family
);
203 if (family
== AF_INET
) {
204 /* OpenBSD tun or FreeBSD tun or FreeBSD lo */
205 decode_ip(pdata
+ NULL_HDR_LEN
, pheader
->caplen
- NULL_HDR_LEN
, &sm
);
206 sm
.time
= pheader
->ts
.tv_sec
;
209 else if (family
== AF_INET6
) {
210 /* XXX: Check this! */
211 decode_ip(pdata
+ NULL_HDR_LEN
, pheader
->caplen
- NULL_HDR_LEN
, &sm
);
212 sm
.time
= pheader
->ts
.tv_sec
;
216 verbosef("loop: unknown family (%x)", family
);
220 decode_ppp(u_char
*user _unused_
,
221 const struct pcap_pkthdr
*pheader
,
224 struct pktsummary sm
;
225 memset(&sm
, 0, sizeof(sm
));
227 if (pheader
->caplen
< PPPOE_HDR_LEN
) {
228 verbosef("ppp: packet too short (%u bytes)", pheader
->caplen
);
232 if (pdata
[2] == 0x00 && pdata
[3] == 0x21) {
233 decode_ip(pdata
+ PPP_HDR_LEN
, pheader
->caplen
- PPP_HDR_LEN
, &sm
);
234 sm
.time
= pheader
->ts
.tv_sec
;
237 verbosef("non-IP PPP packet; ignoring.");
241 decode_pppoe(u_char
*user _unused_
,
242 const struct pcap_pkthdr
*pheader
,
245 struct pktsummary sm
;
246 memset(&sm
, 0, sizeof(sm
));
247 sm
.time
= pheader
->ts
.tv_sec
;
248 decode_pppoe_real(pdata
, pheader
->caplen
, &sm
);
252 decode_pppoe_real(const u_char
*pdata
, const uint32_t len
,
253 struct pktsummary
*sm
)
255 if (len
< PPPOE_HDR_LEN
) {
256 verbosef("pppoe: packet too short (%u bytes)", len
);
260 if (pdata
[1] != 0x00) {
261 verbosef("pppoe: code = 0x%02x, expecting 0; ignoring.", pdata
[1]);
265 if ((pdata
[6] == 0xc0) && (pdata
[7] == 0x21)) return; /* LCP */
266 if ((pdata
[6] == 0xc0) && (pdata
[7] == 0x25)) return; /* LQR */
268 if ((pdata
[6] == 0x00) && (pdata
[7] == 0x21)) {
269 decode_ip(pdata
+ PPPOE_HDR_LEN
, len
- PPPOE_HDR_LEN
, sm
);
272 verbosef("pppoe: non-IP PPPoE packet (0x%02x%02x); ignoring.",
276 /* very similar to decode_ether ... */
278 decode_linux_sll(u_char
*user _unused_
,
279 const struct pcap_pkthdr
*pheader
,
282 const struct sll_header
{
283 uint16_t packet_type
;
284 uint16_t device_type
;
285 uint16_t addr_length
;
286 #define SLL_MAX_ADDRLEN 8
287 uint8_t addr
[SLL_MAX_ADDRLEN
];
289 } *hdr
= (const struct sll_header
*)pdata
;
291 struct pktsummary sm
;
292 memset(&sm
, 0, sizeof(sm
));
294 if (pheader
->caplen
< SLL_HDR_LEN
) {
295 verbosef("linux_sll: packet too short (%u bytes)", pheader
->caplen
);
299 type
= ntohs( hdr
->ether_type
);
303 decode_ip(pdata
+ SLL_HDR_LEN
, pheader
->caplen
- SLL_HDR_LEN
, &sm
);
304 sm
.time
= pheader
->ts
.tv_sec
;
308 /* known protocol, don't complain about it. */
311 verbosef("linux_sll: unknown protocol (%04x)", type
);
316 decode_raw(u_char
*user _unused_
,
317 const struct pcap_pkthdr
*pheader
,
320 struct pktsummary sm
;
321 memset(&sm
, 0, sizeof(sm
));
323 decode_ip(pdata
, pheader
->caplen
, &sm
);
324 sm
.time
= pheader
->ts
.tv_sec
;
328 static void decode_ip_payload(const u_char
*pdata
, const uint32_t len
,
329 struct pktsummary
*sm
);
332 decode_ip(const u_char
*pdata
, const uint32_t len
, struct pktsummary
*sm
)
334 const struct ip
*hdr
= (const struct ip
*)pdata
;
336 if (hdr
->ip_v
== 6) {
337 /* Redirect parsing of IPv6 packets. */
338 decode_ipv6(pdata
, len
, sm
);
341 if (len
< IP_HDR_LEN
) {
342 verbosef("ip: packet too short (%u bytes)", len
);
345 if (hdr
->ip_v
!= 4) {
346 verbosef("ip: version %d (expecting 4 or 6)", hdr
->ip_v
);
350 sm
->len
= ntohs(hdr
->ip_len
);
351 sm
->proto
= hdr
->ip_p
;
353 sm
->src
.family
= IPv4
;
354 sm
->src
.ip
.v4
= hdr
->ip_src
.s_addr
;
356 sm
->dst
.family
= IPv4
;
357 sm
->dst
.ip
.v4
= hdr
->ip_dst
.s_addr
;
359 decode_ip_payload(pdata
+ IP_HDR_LEN
, len
- IP_HDR_LEN
, sm
);
363 decode_ipv6(const u_char
*pdata
, const uint32_t len
, struct pktsummary
*sm
)
365 const struct ip6_hdr
*hdr
= (const struct ip6_hdr
*)pdata
;
367 if (len
< IPV6_HDR_LEN
) {
368 verbosef("ipv6: packet too short (%u bytes)", len
);
372 sm
->len
= ntohs(hdr
->ip6_plen
) + IPV6_HDR_LEN
;
373 sm
->proto
= hdr
->ip6_nxt
;
375 sm
->src
.family
= IPv6
;
376 memcpy(&sm
->src
.ip
.v6
, &hdr
->ip6_src
, sizeof(sm
->src
.ip
.v6
));
378 sm
->dst
.family
= IPv6
;
379 memcpy(&sm
->dst
.ip
.v6
, &hdr
->ip6_dst
, sizeof(sm
->dst
.ip
.v6
));
381 decode_ip_payload(pdata
+ IPV6_HDR_LEN
, len
- IPV6_HDR_LEN
, sm
);
385 decode_ip_payload(const u_char
*pdata
, const uint32_t len
,
386 struct pktsummary
*sm
)
390 const struct tcphdr
*thdr
= (const struct tcphdr
*)pdata
;
391 if (len
< TCP_HDR_LEN
) {
392 verbosef("tcp: packet too short (%u bytes)", len
);
393 sm
->proto
= IPPROTO_INVALID
; /* don't do accounting! */
396 sm
->src_port
= ntohs(thdr
->th_sport
);
397 sm
->dst_port
= ntohs(thdr
->th_dport
);
398 sm
->tcp_flags
= thdr
->th_flags
&
399 (TH_FIN
|TH_SYN
|TH_RST
|TH_PUSH
|TH_ACK
|TH_URG
);
404 const struct udphdr
*uhdr
= (const struct udphdr
*)pdata
;
405 if (len
< UDP_HDR_LEN
) {
406 verbosef("udp: packet too short (%u bytes)", len
);
407 sm
->proto
= IPPROTO_INVALID
; /* don't do accounting! */
410 sm
->src_port
= ntohs(uhdr
->uh_sport
);
411 sm
->dst_port
= ntohs(uhdr
->uh_dport
);
420 /* known protocol, don't complain about it */
424 verbosef("ip: unknown protocol %d", sm
->proto
);
428 /* vim:set ts=3 sw=3 tw=78 expandtab: */