2 * copyright (c) 2001-2011 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)
20 #include <sys/ioctl.h>
21 #include <sys/socket.h>
26 #include <arpa/inet.h> /* inet_ntoa() */
27 #include <net/if.h> /* struct ifreq */
29 /* need struct ether_header */
30 #ifdef __NetBSD__ /* works for NetBSD 5.1.2 */
31 # include <netinet/if_ether.h>
34 # include <sys/queue.h>
35 # include <net/if_arp.h>
36 # include <netinet/if_ether.h>
39 # include <sys/ethernet.h>
40 # define ETHER_HDR_LEN 14
43 # include <netinet/if_ether.h>
44 # define ETHER_HDR_LEN 14
46 # include <net/ethernet.h>
52 #ifndef ETHERTYPE_PPPOE
53 # define ETHERTYPE_PPPOE 0x8864
55 #ifndef ETHERTYPE_IPV6
56 # define ETHERTYPE_IPV6 0x86DD
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 */
67 #define IPV6_VERSION 0x60
70 #ifndef IPV6_VERSION_MASK
71 #define IPV6_VERSION_MASK 0xf0
74 static void decode_ether(u_char
*, const struct pcap_pkthdr
*,
76 static void decode_loop(u_char
*, const struct pcap_pkthdr
*,
78 static void decode_null(u_char
*, const struct pcap_pkthdr
*,
80 static void decode_ppp(u_char
*, const struct pcap_pkthdr
*,
82 static void decode_pppoe(u_char
*, const struct pcap_pkthdr
*,
84 static void decode_pppoe_real(const u_char
*pdata
, const uint32_t len
,
85 struct pktsummary
*sm
);
87 static void decode_linux_sll(u_char
*, const struct pcap_pkthdr
*,
90 static void decode_raw(u_char
*, const struct pcap_pkthdr
*,
92 static int decode_ip(const u_char
*pdata
, const uint32_t len
,
93 struct pktsummary
*sm
);
94 static int decode_ipv6(const u_char
*pdata
, const uint32_t len
,
95 struct pktsummary
*sm
);
97 /* Link-type header information */
98 static const struct linkhdr linkhdrs
[] = {
99 /* linktype hdrlen handler */
100 { DLT_EN10MB
, ETHER_HDR_LEN
, decode_ether
},
101 { DLT_LOOP
, NULL_HDR_LEN
, decode_loop
},
102 { DLT_NULL
, NULL_HDR_LEN
, decode_null
},
103 { DLT_PPP
, PPP_HDR_LEN
, decode_ppp
},
104 #if defined(__NetBSD__)
105 { DLT_PPP_SERIAL
, PPP_HDR_LEN
, decode_ppp
},
107 { DLT_FDDI
, FDDI_HDR_LEN
, NULL
},
108 { DLT_PPP_ETHER
, PPPOE_HDR_LEN
, decode_pppoe
},
110 { DLT_LINUX_SLL
, SLL_HDR_LEN
, decode_linux_sll
},
112 { DLT_RAW
, RAW_HDR_LEN
, decode_raw
},
117 * Returns a pointer to the linkhdr record matching the given linktype, or
118 * NULL if no matching entry found.
120 const struct linkhdr
*
121 getlinkhdr(const int linktype
)
125 for (i
=0; linkhdrs
[i
].linktype
!= -1; i
++)
126 if (linkhdrs
[i
].linktype
== linktype
)
127 return (&(linkhdrs
[i
]));
132 * Returns the minimum snaplen needed to decode everything up to the TCP/UDP
133 * packet headers. The IPv6 header is normative. The argument lh is not
134 * allowed to be NULL.
137 getsnaplen(const struct linkhdr
*lh
)
139 return (int)(lh
->hdrlen
+ IPV6_HDR_LEN
+ MAX(TCP_HDR_LEN
, UDP_HDR_LEN
));
142 /* Decoding functions. */
144 decode_ether(u_char
*user _unused_
,
145 const struct pcap_pkthdr
*pheader
,
149 const struct ether_header
*hdr
= (const struct ether_header
*)pdata
;
150 struct pktsummary sm
;
151 memset(&sm
, 0, sizeof(sm
));
152 sm
.time
= pheader
->ts
.tv_sec
;
154 if (pheader
->caplen
< ETHER_HDR_LEN
) {
155 verbosef("ether: packet too short (%u bytes)", pheader
->caplen
);
160 memcpy(sm
.src_mac
, hdr
->ether_shost
.ether_addr_octet
, sizeof(sm
.src_mac
));
161 memcpy(sm
.dst_mac
, hdr
->ether_dhost
.ether_addr_octet
, sizeof(sm
.dst_mac
));
163 memcpy(sm
.src_mac
, hdr
->ether_shost
, sizeof(sm
.src_mac
));
164 memcpy(sm
.dst_mac
, hdr
->ether_dhost
, sizeof(sm
.dst_mac
));
167 type
= ntohs( hdr
->ether_type
);
171 if (!opt_want_pppoe
) {
172 if (decode_ip(pdata
+ ETHER_HDR_LEN
,
173 pheader
->caplen
- ETHER_HDR_LEN
, &sm
)) {
177 verbosef("ether: discarded IP packet, expecting PPPoE instead");
180 /* known protocol, don't complain about it. */
182 case ETHERTYPE_PPPOE
:
184 decode_pppoe_real(pdata
+ ETHER_HDR_LEN
,
185 pheader
->caplen
- ETHER_HDR_LEN
, &sm
);
187 verbosef("ether: got PPPoE frame: maybe you want --pppoe");
190 verbosef("ether: unknown protocol (0x%04x)", type
);
194 /* Very similar to decode_null, except on OpenBSD we need to think
195 * about family endianness.
198 decode_loop(u_char
*user _unused_
,
199 const struct pcap_pkthdr
*pheader
,
203 struct pktsummary sm
;
204 memset(&sm
, 0, sizeof(sm
));
205 sm
.time
= pheader
->ts
.tv_sec
;
207 if (pheader
->caplen
< NULL_HDR_LEN
) {
208 verbosef("loop: packet too short (%u bytes)", pheader
->caplen
);
211 family
= *(const uint32_t *)pdata
;
213 family
= ntohl(family
);
215 if (family
== AF_INET
) {
216 if (decode_ip(pdata
+ NULL_HDR_LEN
,
217 pheader
->caplen
- NULL_HDR_LEN
, &sm
)) {
221 else if (family
== AF_INET6
) {
222 if (decode_ipv6(pdata
+ NULL_HDR_LEN
,
223 pheader
->caplen
- NULL_HDR_LEN
, &sm
)) {
228 verbosef("loop: unknown family (%x)", family
);
232 decode_null(u_char
*user _unused_
,
233 const struct pcap_pkthdr
*pheader
,
237 struct pktsummary sm
;
238 memset(&sm
, 0, sizeof(sm
));
239 sm
.time
= pheader
->ts
.tv_sec
;
241 if (pheader
->caplen
< NULL_HDR_LEN
) {
242 verbosef("null: packet too short (%u bytes)", pheader
->caplen
);
245 family
= *(const uint32_t *)pdata
;
246 if (family
== AF_INET
) {
247 if (decode_ip(pdata
+ NULL_HDR_LEN
,
248 pheader
->caplen
- NULL_HDR_LEN
, &sm
)) {
252 else if (family
== AF_INET6
) {
253 if (decode_ipv6(pdata
+ NULL_HDR_LEN
,
254 pheader
->caplen
- NULL_HDR_LEN
, &sm
)) {
259 verbosef("null: unknown family (%x)", family
);
263 decode_ppp(u_char
*user _unused_
,
264 const struct pcap_pkthdr
*pheader
,
267 struct pktsummary sm
;
268 memset(&sm
, 0, sizeof(sm
));
269 sm
.time
= pheader
->ts
.tv_sec
;
271 if (pheader
->caplen
< PPPOE_HDR_LEN
) {
272 verbosef("ppp: packet too short (%u bytes)", pheader
->caplen
);
276 if (pdata
[2] == 0x00 && pdata
[3] == 0x21) {
277 if (decode_ip(pdata
+ PPP_HDR_LEN
, pheader
->caplen
- PPP_HDR_LEN
, &sm
)) {
281 verbosef("non-IP PPP packet; ignoring.");
285 decode_pppoe(u_char
*user _unused_
,
286 const struct pcap_pkthdr
*pheader
,
289 struct pktsummary sm
;
290 memset(&sm
, 0, sizeof(sm
));
291 sm
.time
= pheader
->ts
.tv_sec
;
292 decode_pppoe_real(pdata
, pheader
->caplen
, &sm
);
296 decode_pppoe_real(const u_char
*pdata
, const uint32_t len
,
297 struct pktsummary
*sm
)
299 if (len
< PPPOE_HDR_LEN
) {
300 verbosef("pppoe: packet too short (%u bytes)", len
);
304 if (pdata
[1] != 0x00) {
305 verbosef("pppoe: code = 0x%02x, expecting 0; ignoring.", pdata
[1]);
309 if ((pdata
[6] == 0xc0) && (pdata
[7] == 0x21)) return; /* LCP */
310 if ((pdata
[6] == 0xc0) && (pdata
[7] == 0x25)) return; /* LQR */
312 if ((pdata
[6] == 0x00) && (pdata
[7] == 0x21)) {
313 if (decode_ip(pdata
+ PPPOE_HDR_LEN
, len
- PPPOE_HDR_LEN
, sm
)) {
317 verbosef("pppoe: non-IP PPPoE packet (0x%02x%02x); ignoring.",
322 /* very similar to decode_ether ... */
324 decode_linux_sll(u_char
*user _unused_
,
325 const struct pcap_pkthdr
*pheader
,
328 const struct sll_header
{
329 uint16_t packet_type
;
330 uint16_t device_type
;
331 uint16_t addr_length
;
332 #define SLL_MAX_ADDRLEN 8
333 uint8_t addr
[SLL_MAX_ADDRLEN
];
335 } *hdr
= (const struct sll_header
*)pdata
;
337 struct pktsummary sm
;
338 memset(&sm
, 0, sizeof(sm
));
339 sm
.time
= pheader
->ts
.tv_sec
;
341 if (pheader
->caplen
< SLL_HDR_LEN
) {
342 verbosef("linux_sll: packet too short (%u bytes)", pheader
->caplen
);
346 type
= ntohs(hdr
->ether_type
);
350 if (decode_ip(pdata
+ SLL_HDR_LEN
, pheader
->caplen
- SLL_HDR_LEN
, &sm
)) {
355 /* known protocol, don't complain about it. */
358 verbosef("linux_sll: unknown protocol (%04x)", type
);
364 decode_raw(u_char
*user _unused_
,
365 const struct pcap_pkthdr
*pheader
,
368 struct pktsummary sm
;
369 memset(&sm
, 0, sizeof(sm
));
370 sm
.time
= pheader
->ts
.tv_sec
;
372 if (decode_ip(pdata
, pheader
->caplen
, &sm
))
376 static void decode_ip_payload(const u_char
*pdata
, const uint32_t len
,
377 struct pktsummary
*sm
);
380 decode_ip(const u_char
*pdata
, const uint32_t len
, struct pktsummary
*sm
)
382 const struct ip
*hdr
= (const struct ip
*)pdata
;
384 if (hdr
->ip_v
== 6) {
385 /* Redirect parsing of IPv6 packets. */
386 return decode_ipv6(pdata
, len
, sm
);
388 if (len
< IP_HDR_LEN
) {
389 verbosef("ip: packet too short (%u bytes)", len
);
392 if (hdr
->ip_v
!= 4) {
393 verbosef("ip: version %d (expecting 4 or 6)", hdr
->ip_v
);
397 sm
->len
= ntohs(hdr
->ip_len
);
398 sm
->proto
= hdr
->ip_p
;
400 sm
->src
.family
= IPv4
;
401 sm
->src
.ip
.v4
= hdr
->ip_src
.s_addr
;
403 sm
->dst
.family
= IPv4
;
404 sm
->dst
.ip
.v4
= hdr
->ip_dst
.s_addr
;
406 decode_ip_payload(pdata
+ IP_HDR_LEN
, len
- IP_HDR_LEN
, sm
);
411 decode_ipv6(const u_char
*pdata
, const uint32_t len
, struct pktsummary
*sm
)
413 const struct ip6_hdr
*hdr
= (const struct ip6_hdr
*)pdata
;
415 if (len
< IPV6_HDR_LEN
) {
416 verbosef("ipv6: packet too short (%u bytes)", len
);
420 if ((hdr
->ip6_vfc
& IPV6_VERSION_MASK
) != IPV6_VERSION
) {
421 verbosef("ipv6: bad version (%02x, expecting %02x)",
422 hdr
->ip6_vfc
& IPV6_VERSION_MASK
,
427 sm
->len
= ntohs(hdr
->ip6_plen
) + IPV6_HDR_LEN
;
428 sm
->proto
= hdr
->ip6_nxt
;
430 sm
->src
.family
= IPv6
;
431 memcpy(&sm
->src
.ip
.v6
, &hdr
->ip6_src
, sizeof(sm
->src
.ip
.v6
));
433 sm
->dst
.family
= IPv6
;
434 memcpy(&sm
->dst
.ip
.v6
, &hdr
->ip6_dst
, sizeof(sm
->dst
.ip
.v6
));
436 /* Ignore this packet if it uses extension headers. */
438 case 0: /* Hop-by-Hop Options */
440 case IPPROTO_DSTOPTS
:
441 case IPPROTO_ROUTING
:
442 case IPPROTO_FRAGMENT
:
445 case 135: /* Mobility */
446 sm
->proto
= IPPROTO_INVALID
; /* don't do proto accounting! */
447 return 1; /* but we have addresses, so host accounting is ok */
450 decode_ip_payload(pdata
+ IPV6_HDR_LEN
, len
- IPV6_HDR_LEN
, sm
);
456 decode_ip_payload(const u_char
*pdata
, const uint32_t len
,
457 struct pktsummary
*sm
)
461 const struct tcphdr
*thdr
= (const struct tcphdr
*)pdata
;
462 if (len
< TCP_HDR_LEN
) {
463 verbosef("tcp: packet too short (%u bytes)", len
);
464 sm
->proto
= IPPROTO_INVALID
; /* don't do accounting! */
467 sm
->src_port
= ntohs(thdr
->th_sport
);
468 sm
->dst_port
= ntohs(thdr
->th_dport
);
469 sm
->tcp_flags
= thdr
->th_flags
&
470 (TH_FIN
|TH_SYN
|TH_RST
|TH_PUSH
|TH_ACK
|TH_URG
);
475 const struct udphdr
*uhdr
= (const struct udphdr
*)pdata
;
476 if (len
< UDP_HDR_LEN
) {
477 verbosef("udp: packet too short (%u bytes)", len
);
478 sm
->proto
= IPPROTO_INVALID
; /* don't do accounting! */
481 sm
->src_port
= ntohs(uhdr
->uh_sport
);
482 sm
->dst_port
= ntohs(uhdr
->uh_dport
);
490 /* known protocol, don't complain about it */
491 sm
->proto
= IPPROTO_INVALID
; /* also don't do accounting */
495 verbosef("ip_payload: unknown protocol %d", sm
->proto
);
499 /* vim:set ts=3 sw=3 tw=78 expandtab: */