2 * copyright (c) 2001-2007 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 #include <net/if.h> /* struct ifreq */
50 #include <netinet/in_systm.h> /* n_long */
51 #include <netinet/ip.h> /* struct ip */
53 #include <netinet/tcp.h> /* struct tcphdr */
54 #include <netinet/udp.h> /* struct udphdr */
56 extern int want_pppoe
;
58 static void decode_ether(u_char
*, const struct pcap_pkthdr
*,
60 static void decode_loop(u_char
*, const struct pcap_pkthdr
*,
62 static void decode_ppp(u_char
*, const struct pcap_pkthdr
*,
64 static void decode_pppoe(u_char
*, const struct pcap_pkthdr
*,
66 static void decode_pppoe_real(const u_char
*pdata
, const uint32_t len
,
68 static void decode_linux_sll(u_char
*, const struct pcap_pkthdr
*,
70 static void decode_ip(const u_char
*pdata
, const uint32_t len
,
73 /* Link-type header information */
74 static const linkhdr_t linkhdrs
[] = {
75 /* linktype hdrlen handler */
76 { DLT_EN10MB
, ETHER_HDR_LEN
, decode_ether
},
77 { DLT_LOOP
, NULL_HDR_LEN
, decode_loop
},
78 { DLT_NULL
, NULL_HDR_LEN
, decode_loop
},
79 { DLT_PPP
, PPP_HDR_LEN
, decode_ppp
},
80 #if defined(__NetBSD__)
81 { DLT_PPP_SERIAL
, PPP_HDR_LEN
, decode_ppp
},
83 { DLT_FDDI
, FDDI_HDR_LEN
, NULL
},
84 { DLT_PPP_ETHER
, PPPOE_HDR_LEN
, decode_pppoe
},
86 { DLT_LINUX_SLL
, SLL_HDR_LEN
, decode_linux_sll
},
92 * Returns a pointer to the linkhdr_t record matching the given linktype, or
93 * NULL if no matching entry found.
96 getlinkhdr(int linktype
)
100 for (i
=0; linkhdrs
[i
].linktype
!= -1; i
++)
101 if (linkhdrs
[i
].linktype
== linktype
)
102 return (&(linkhdrs
[i
]));
107 * Returns the minimum caplen needed to decode everything up to the TCP/UDP
108 * packet headers. Argument lh is not allowed to be NULL.
111 getcaplen(const linkhdr_t
*lh
)
114 return (lh
->hdrlen
+ IP_HDR_LEN
+ max(TCP_HDR_LEN
, UDP_HDR_LEN
));
118 * Convert IP address to a numbers-and-dots notation in a static buffer
119 * provided by inet_ntoa().
122 ip_to_str(const in_addr_t ip
)
127 return (inet_ntoa(in
));
130 /* Decoding functions. */
132 decode_ether(u_char
*user _unused_
,
133 const struct pcap_pkthdr
*pheader
,
137 const struct ether_header
*hdr
= (const struct ether_header
*)pdata
;
139 memset(&sm
, 0, sizeof(sm
));
140 sm
.time
= pheader
->ts
.tv_sec
;
142 if (pheader
->caplen
< ETHER_HDR_LEN
) {
143 verbosef("ether: packet too short (%u bytes)", pheader
->caplen
);
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
));
151 memcpy(sm
.src_mac
, hdr
->ether_shost
, sizeof(sm
.src_mac
));
152 memcpy(sm
.dst_mac
, hdr
->ether_dhost
, sizeof(sm
.dst_mac
));
155 type
= ntohs( hdr
->ether_type
);
159 decode_ip(pdata
+ ETHER_HDR_LEN
,
160 pheader
->caplen
- ETHER_HDR_LEN
, &sm
);
163 verbosef("ether: discarded IP packet, expecting PPPoE instead");
166 /* known protocol, don't complain about it. */
168 case ETHERTYPE_PPPOE
:
170 decode_pppoe_real(pdata
+ ETHER_HDR_LEN
,
171 pheader
->caplen
- ETHER_HDR_LEN
, &sm
);
173 verbosef("ether: got PPPoE frame: maybe you want --pppoe");
176 verbosef("ether: unknown protocol (0x%04x)", type
);
181 decode_loop(u_char
*user _unused_
,
182 const struct pcap_pkthdr
*pheader
,
187 memset(&sm
, 0, sizeof(sm
));
189 if (pheader
->caplen
< NULL_HDR_LEN
) {
190 verbosef("loop: packet too short (%u bytes)", pheader
->caplen
);
193 family
= *(const uint32_t *)pdata
;
195 family
= ntohl(family
);
197 if (family
== AF_INET
) {
198 /* OpenBSD tun or FreeBSD tun or FreeBSD lo */
199 decode_ip(pdata
+ NULL_HDR_LEN
, pheader
->caplen
- NULL_HDR_LEN
, &sm
);
200 sm
.time
= pheader
->ts
.tv_sec
;
204 verbosef("loop: unknown family (%x)", family
);
208 decode_ppp(u_char
*user _unused_
,
209 const struct pcap_pkthdr
*pheader
,
213 memset(&sm
, 0, sizeof(sm
));
215 if (pheader
->caplen
< PPPOE_HDR_LEN
) {
216 verbosef("ppp: packet too short (%u bytes)", pheader
->caplen
);
220 if (pdata
[2] == 0x00 && pdata
[3] == 0x21) {
221 decode_ip(pdata
+ PPP_HDR_LEN
, pheader
->caplen
- PPP_HDR_LEN
, &sm
);
222 sm
.time
= pheader
->ts
.tv_sec
;
225 verbosef("non-IP PPP packet; ignoring.");
229 decode_pppoe(u_char
*user _unused_
,
230 const struct pcap_pkthdr
*pheader
,
234 memset(&sm
, 0, sizeof(sm
));
235 sm
.time
= pheader
->ts
.tv_sec
;
236 decode_pppoe_real(pdata
, pheader
->caplen
, &sm
);
240 decode_pppoe_real(const u_char
*pdata
, const uint32_t len
,
243 if (len
< PPPOE_HDR_LEN
) {
244 verbosef("pppoe: packet too short (%u bytes)", len
);
248 if (pdata
[1] != 0x00) {
249 verbosef("pppoe: code = 0x%02x, expecting 0; ignoring.", pdata
[1]);
253 if ((pdata
[6] == 0xc0) && (pdata
[7] == 0x21)) return; /* LCP */
254 if ((pdata
[6] == 0xc0) && (pdata
[7] == 0x25)) return; /* LQR */
256 if ((pdata
[6] == 0x00) && (pdata
[7] == 0x21)) {
257 decode_ip(pdata
+ PPPOE_HDR_LEN
, len
- PPPOE_HDR_LEN
, sm
);
260 verbosef("pppoe: non-IP PPPoE packet (0x%02x%02x); ignoring.",
264 /* very similar to decode_ether ... */
266 decode_linux_sll(u_char
*user _unused_
,
267 const struct pcap_pkthdr
*pheader
,
270 const struct sll_header
{
271 uint16_t packet_type
;
272 uint16_t device_type
;
273 uint16_t addr_length
;
274 #define SLL_MAX_ADDRLEN 8
275 uint8_t addr
[SLL_MAX_ADDRLEN
];
277 } *hdr
= (const struct sll_header
*)pdata
;
280 memset(&sm
, 0, sizeof(sm
));
282 if (pheader
->caplen
< SLL_HDR_LEN
) {
283 verbosef("linux_sll: packet too short (%u bytes)", pheader
->caplen
);
287 type
= ntohs( hdr
->ether_type
);
290 decode_ip(pdata
+ SLL_HDR_LEN
, pheader
->caplen
- SLL_HDR_LEN
, &sm
);
291 sm
.time
= pheader
->ts
.tv_sec
;
295 /* known protocol, don't complain about it. */
298 verbosef("linux_sll: unknown protocol (%04x)", type
);
303 decode_ip(const u_char
*pdata
, const uint32_t len
, pktsummary
*sm
)
305 const struct ip
*hdr
= (const struct ip
*)pdata
;
307 if (len
< IP_HDR_LEN
) {
308 verbosef("ip: packet too short (%u bytes)", len
);
311 if (hdr
->ip_v
!= 4) {
312 verbosef("ip: version %d (expecting 4)", hdr
->ip_v
);
316 sm
->len
= ntohs(hdr
->ip_len
);
317 sm
->proto
= hdr
->ip_p
;
318 sm
->src_ip
= hdr
->ip_src
.s_addr
;
319 sm
->dest_ip
= hdr
->ip_dst
.s_addr
;
323 const struct tcphdr
*thdr
=
324 (const struct tcphdr
*)(pdata
+ IP_HDR_LEN
);
325 if (len
< IP_HDR_LEN
+ TCP_HDR_LEN
) {
326 verbosef("tcp: packet too short (%u bytes)", len
);
329 sm
->src_port
= ntohs(thdr
->th_sport
);
330 sm
->dest_port
= ntohs(thdr
->th_dport
);
331 sm
->tcp_flags
= thdr
->th_flags
&
332 (TH_FIN
|TH_SYN
|TH_RST
|TH_PUSH
|TH_ACK
|TH_URG
);
337 const struct udphdr
*uhdr
=
338 (const struct udphdr
*)(pdata
+ IP_HDR_LEN
);
339 if (len
< IP_HDR_LEN
+ UDP_HDR_LEN
) {
340 verbosef("udp: packet too short (%u bytes)", len
);
343 sm
->src_port
= ntohs(uhdr
->uh_sport
);
344 sm
->dest_port
= ntohs(uhdr
->uh_dport
);
349 /* known protocol, don't complain about it */
353 verbosef("ip: unknown protocol %d", sm
->proto
);
357 /* vim:set ts=3 sw=3 tw=78 expandtab: */