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)
17 #include <sys/ioctl.h>
18 #include <sys/socket.h>
24 #include <arpa/inet.h> /* inet_ntoa() */
26 /* need struct ether_header */
27 #if defined(__NetBSD__) || defined(__OpenBSD__)
28 # include <sys/queue.h>
30 # include <net/if_arp.h>
31 # include <netinet/if_ether.h>
34 # include <sys/ethernet.h>
35 # define ETHER_HDR_LEN 14
38 # include <netinet/if_ether.h>
39 # define ETHER_HDR_LEN 14
41 # include <net/ethernet.h>
45 #ifndef ETHERTYPE_PPPOE
46 #define ETHERTYPE_PPPOE 0x8864
49 #ifndef ETHERTYPE_IPV6
50 # ifdef HAVE_NET_IF_ETHER_H
51 # include <net/if_ether.h> /* ETH_P_IPV6 for GNU/kfreebsd */
54 # define ETHERTYPE_IPV6 ETH_P_IPV6
58 #include <net/if.h> /* struct ifreq */
59 #include <netinet/in_systm.h> /* n_long */
60 #include <netinet/ip.h> /* struct ip */
61 #include <netinet/ip6.h> /* struct ip6_hdr */
63 #include <netinet/tcp.h> /* struct tcphdr */
64 #include <netinet/udp.h> /* struct udphdr */
66 extern int want_pppoe
;
68 static void decode_ether(u_char
*, const struct pcap_pkthdr
*,
70 static void decode_loop(u_char
*, const struct pcap_pkthdr
*,
72 static void decode_ppp(u_char
*, const struct pcap_pkthdr
*,
74 static void decode_pppoe(u_char
*, const struct pcap_pkthdr
*,
76 static void decode_pppoe_real(const u_char
*pdata
, const uint32_t len
,
78 static void decode_linux_sll(u_char
*, const struct pcap_pkthdr
*,
80 static void decode_raw(u_char
*, const struct pcap_pkthdr
*,
82 static void decode_ip(const u_char
*pdata
, const uint32_t len
,
84 static void decode_ipv6(const u_char
*pdata
, const uint32_t len
,
87 /* Link-type header information */
88 static const linkhdr_t 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
},
97 { DLT_FDDI
, FDDI_HDR_LEN
, NULL
},
98 { DLT_PPP_ETHER
, PPPOE_HDR_LEN
, decode_pppoe
},
100 { DLT_LINUX_SLL
, SLL_HDR_LEN
, decode_linux_sll
},
102 { DLT_RAW
, RAW_HDR_LEN
, decode_raw
},
107 * Returns a pointer to the linkhdr_t record matching the given linktype, or
108 * NULL if no matching entry found.
111 getlinkhdr(int linktype
)
115 for (i
=0; linkhdrs
[i
].linktype
!= -1; i
++)
116 if (linkhdrs
[i
].linktype
== linktype
)
117 return (&(linkhdrs
[i
]));
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.
127 getsnaplen(const linkhdr_t
*lh
)
130 /* TODO MEA Investigate why the supplementary value 20 is needed on GNU/Linux. */
131 return (20 + lh
->hdrlen
+ IPV6_HDR_LEN
+ max(TCP_HDR_LEN
, UDP_HDR_LEN
));
135 * Convert IP address to a presentation notation in a static buffer
136 * using inet_ntop(3).
138 char ipstr
[INET6_ADDRSTRLEN
]; /* TODO Reentrant? */
141 ip_to_str(const struct addr46
*const ip
)
144 inet_ntop(ip
->af
, &ip
->addr
.ip6
, ipstr
, sizeof(ipstr
));
150 ip_to_str_af(const void *const addr
, sa_family_t af
)
153 inet_ntop(af
, addr
, ipstr
, sizeof(ipstr
));
158 /* Decoding functions. */
160 decode_ether(u_char
*user _unused_
,
161 const struct pcap_pkthdr
*pheader
,
165 const struct ether_header
*hdr
= (const struct ether_header
*)pdata
;
167 memset(&sm
, 0, sizeof(sm
));
168 sm
.time
= pheader
->ts
.tv_sec
;
170 if (pheader
->caplen
< ETHER_HDR_LEN
) {
171 verbosef("ether: packet too short (%u bytes)", pheader
->caplen
);
176 memcpy(sm
.src_mac
, hdr
->ether_shost
.ether_addr_octet
, sizeof(sm
.src_mac
));
177 memcpy(sm
.dst_mac
, hdr
->ether_dhost
.ether_addr_octet
, sizeof(sm
.dst_mac
));
179 memcpy(sm
.src_mac
, hdr
->ether_shost
, sizeof(sm
.src_mac
));
180 memcpy(sm
.dst_mac
, hdr
->ether_dhost
, sizeof(sm
.dst_mac
));
183 type
= ntohs( hdr
->ether_type
);
188 decode_ip(pdata
+ ETHER_HDR_LEN
,
189 pheader
->caplen
- ETHER_HDR_LEN
, &sm
);
192 verbosef("ether: discarded IP packet, expecting PPPoE instead");
195 /* known protocol, don't complain about it. */
197 case ETHERTYPE_PPPOE
:
199 decode_pppoe_real(pdata
+ ETHER_HDR_LEN
,
200 pheader
->caplen
- ETHER_HDR_LEN
, &sm
);
202 verbosef("ether: got PPPoE frame: maybe you want --pppoe");
205 verbosef("ether: unknown protocol (0x%04x)", type
);
210 decode_loop(u_char
*user _unused_
,
211 const struct pcap_pkthdr
*pheader
,
216 memset(&sm
, 0, sizeof(sm
));
218 if (pheader
->caplen
< NULL_HDR_LEN
) {
219 verbosef("loop: packet too short (%u bytes)", pheader
->caplen
);
222 family
= *(const uint32_t *)pdata
;
224 family
= ntohl(family
);
226 if (family
== AF_INET
) {
227 /* OpenBSD tun or FreeBSD tun or FreeBSD lo */
228 decode_ip(pdata
+ NULL_HDR_LEN
, pheader
->caplen
- NULL_HDR_LEN
, &sm
);
229 sm
.time
= pheader
->ts
.tv_sec
;
232 else if (family
== AF_INET6
) {
233 /* XXX: Check this! */
234 decode_ip(pdata
+ NULL_HDR_LEN
, pheader
->caplen
- NULL_HDR_LEN
, &sm
);
235 sm
.time
= pheader
->ts
.tv_sec
;
239 verbosef("loop: unknown family (%x)", family
);
243 decode_ppp(u_char
*user _unused_
,
244 const struct pcap_pkthdr
*pheader
,
248 memset(&sm
, 0, sizeof(sm
));
250 if (pheader
->caplen
< PPPOE_HDR_LEN
) {
251 verbosef("ppp: packet too short (%u bytes)", pheader
->caplen
);
255 if (pdata
[2] == 0x00 && pdata
[3] == 0x21) {
256 decode_ip(pdata
+ PPP_HDR_LEN
, pheader
->caplen
- PPP_HDR_LEN
, &sm
);
257 sm
.time
= pheader
->ts
.tv_sec
;
260 verbosef("non-IP PPP packet; ignoring.");
264 decode_pppoe(u_char
*user _unused_
,
265 const struct pcap_pkthdr
*pheader
,
269 memset(&sm
, 0, sizeof(sm
));
270 sm
.time
= pheader
->ts
.tv_sec
;
271 decode_pppoe_real(pdata
, pheader
->caplen
, &sm
);
275 decode_pppoe_real(const u_char
*pdata
, const uint32_t len
,
278 if (len
< PPPOE_HDR_LEN
) {
279 verbosef("pppoe: packet too short (%u bytes)", len
);
283 if (pdata
[1] != 0x00) {
284 verbosef("pppoe: code = 0x%02x, expecting 0; ignoring.", pdata
[1]);
288 if ((pdata
[6] == 0xc0) && (pdata
[7] == 0x21)) return; /* LCP */
289 if ((pdata
[6] == 0xc0) && (pdata
[7] == 0x25)) return; /* LQR */
291 if ((pdata
[6] == 0x00) && (pdata
[7] == 0x21)) {
292 decode_ip(pdata
+ PPPOE_HDR_LEN
, len
- PPPOE_HDR_LEN
, sm
);
295 verbosef("pppoe: non-IP PPPoE packet (0x%02x%02x); ignoring.",
299 /* very similar to decode_ether ... */
301 decode_linux_sll(u_char
*user _unused_
,
302 const struct pcap_pkthdr
*pheader
,
305 const struct sll_header
{
306 uint16_t packet_type
;
307 uint16_t device_type
;
308 uint16_t addr_length
;
309 #define SLL_MAX_ADDRLEN 8
310 uint8_t addr
[SLL_MAX_ADDRLEN
];
312 } *hdr
= (const struct sll_header
*)pdata
;
315 memset(&sm
, 0, sizeof(sm
));
317 if (pheader
->caplen
< SLL_HDR_LEN
) {
318 verbosef("linux_sll: packet too short (%u bytes)", pheader
->caplen
);
322 type
= ntohs( hdr
->ether_type
);
326 decode_ip(pdata
+ SLL_HDR_LEN
, pheader
->caplen
- SLL_HDR_LEN
, &sm
);
327 sm
.time
= pheader
->ts
.tv_sec
;
331 /* known protocol, don't complain about it. */
334 verbosef("linux_sll: unknown protocol (%04x)", type
);
339 decode_raw(u_char
*user _unused_
,
340 const struct pcap_pkthdr
*pheader
,
344 memset(&sm
, 0, sizeof(sm
));
346 decode_ip(pdata
, pheader
->caplen
, &sm
);
347 sm
.time
= pheader
->ts
.tv_sec
;
352 decode_ip(const u_char
*pdata
, const uint32_t len
, pktsummary
*sm
)
354 const struct ip
*hdr
= (const struct ip
*)pdata
;
356 if (hdr
->ip_v
== 6) {
357 /* Redirect parsing of IPv6 packets. */
358 decode_ipv6(pdata
, len
, sm
);
361 if (len
< IP_HDR_LEN
) {
362 verbosef("ip: packet too short (%u bytes)", len
);
365 if (hdr
->ip_v
!= 4) {
366 verbosef("ip: version %d (expecting 4 or 6)", hdr
->ip_v
);
370 sm
->len
= ntohs(hdr
->ip_len
);
372 sm
->proto
= hdr
->ip_p
;
373 memcpy(&sm
->src_ip
, &hdr
->ip_src
, sizeof(sm
->src_ip
));
374 memcpy(&sm
->dest_ip
, &hdr
->ip_dst
, sizeof(sm
->dest_ip
));
378 const struct tcphdr
*thdr
=
379 (const struct tcphdr
*)(pdata
+ IP_HDR_LEN
);
380 if (len
< IP_HDR_LEN
+ TCP_HDR_LEN
) {
381 verbosef("tcp: packet too short (%u bytes)", len
);
384 sm
->src_port
= ntohs(thdr
->th_sport
);
385 sm
->dest_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
);
392 const struct udphdr
*uhdr
=
393 (const struct udphdr
*)(pdata
+ IP_HDR_LEN
);
394 if (len
< IP_HDR_LEN
+ UDP_HDR_LEN
) {
395 verbosef("udp: packet too short (%u bytes)", len
);
398 sm
->src_port
= ntohs(uhdr
->uh_sport
);
399 sm
->dest_port
= ntohs(uhdr
->uh_dport
);
404 /* known protocol, don't complain about it */
408 verbosef("ip: unknown protocol %d", sm
->proto
);
413 decode_ipv6(const u_char
*pdata
, const uint32_t len
, pktsummary
*sm
)
415 const struct ip6_hdr
*hdr
= (const struct ip6_hdr
*)pdata
;
417 if (len
< IPV6_HDR_LEN
) {
418 verbosef("ipv6: packet too short (%u bytes)", len
);
422 sm
->len
= ntohs(hdr
->ip6_plen
) + IPV6_HDR_LEN
;
424 sm
->proto
= hdr
->ip6_nxt
;
425 memcpy(&sm
->src_ip6
, &hdr
->ip6_src
, sizeof(sm
->src_ip6
));
426 memcpy(&sm
->dest_ip6
, &hdr
->ip6_dst
, sizeof(sm
->dest_ip6
));
430 const struct tcphdr
*thdr
=
431 (const struct tcphdr
*)(pdata
+ IPV6_HDR_LEN
);
432 if (len
< IPV6_HDR_LEN
+ TCP_HDR_LEN
) {
433 verbosef("tcp6: packet too short (%u bytes)", len
);
436 sm
->src_port
= ntohs(thdr
->th_sport
);
437 sm
->dest_port
= ntohs(thdr
->th_dport
);
438 sm
->tcp_flags
= thdr
->th_flags
&
439 (TH_FIN
|TH_SYN
|TH_RST
|TH_PUSH
|TH_ACK
|TH_URG
);
444 const struct udphdr
*uhdr
=
445 (const struct udphdr
*)(pdata
+ IPV6_HDR_LEN
);
446 if (len
< IPV6_HDR_LEN
+ UDP_HDR_LEN
) {
447 verbosef("udp6: packet too short (%u bytes)", len
);
450 sm
->src_port
= ntohs(uhdr
->uh_sport
);
451 sm
->dest_port
= ntohs(uhdr
->uh_dport
);
456 /* known protocol, don't complain about it */
460 verbosef("ipv6: unknown protocol %d", sm
->proto
);
464 /* vim:set ts=3 sw=3 tw=78 expandtab: */