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>
46
#include <net/if.h> /* struct ifreq */
47
#include <netinet/in_systm.h> /* n_long */
48
#include <netinet/ip.h> /* struct ip */
50
#include <netinet/tcp.h> /* struct tcphdr */
51
#include <netinet/udp.h> /* struct udphdr */
53
static void decode_ether(u_char *, const struct pcap_pkthdr *,
55
static void decode_loop(u_char *, const struct pcap_pkthdr *,
57
static void decode_ppp(u_char *, const struct pcap_pkthdr *,
59
static void decode_pppoe(u_char *, const struct pcap_pkthdr *,
61
static void decode_linux_sll(u_char *, const struct pcap_pkthdr *,
63
static void decode_ip(const u_char *pdata, const uint32_t len,
66
/* Link-type header information */
67
static const linkhdr_t linkhdrs[] = {
68
/* linktype hdrlen handler */
69
{ DLT_EN10MB, ETHER_HDR_LEN, decode_ether },
70
{ DLT_LOOP, NULL_HDR_LEN, decode_loop },
71
{ DLT_NULL, NULL_HDR_LEN, decode_loop },
72
{ DLT_PPP, PPP_HDR_LEN, decode_ppp },
73
#if defined(__NetBSD__)
74
{ DLT_PPP_SERIAL, PPP_HDR_LEN, decode_ppp },
76
{ DLT_FDDI, FDDI_HDR_LEN, NULL },
77
{ DLT_PPP_ETHER, PPPOE_HDR_LEN, decode_pppoe },
79
{ DLT_LINUX_SLL, SLL_HDR_LEN, decode_linux_sll },
85
* Returns a pointer to the linkhdr_t record matching the given linktype, or
86
* NULL if no matching entry found.
89
getlinkhdr(int linktype)
93
for (i=0; linkhdrs[i].linktype != -1; i++)
94
if (linkhdrs[i].linktype == linktype)
95
return (&(linkhdrs[i]));
100
* Returns the minimum caplen needed to decode everything up to the TCP/UDP
101
* packet headers. Argument lh is not allowed to be NULL.
104
getcaplen(const linkhdr_t *lh)
107
return (lh->hdrlen + IP_HDR_LEN + max(TCP_HDR_LEN, UDP_HDR_LEN));
111
* Convert IP address to a numbers-and-dots notation in a static buffer
112
* provided by inet_ntoa().
115
ip_to_str(const in_addr_t ip)
120
return (inet_ntoa(in));
123
/* Decoding functions. */
125
decode_ether(u_char *user _unused_,
126
const struct pcap_pkthdr *pheader,
130
const struct ether_header *hdr = (const struct ether_header *)pdata;
132
memset(&sm, 0, sizeof(sm));
134
if (pheader->caplen < ETHER_HDR_LEN) {
135
verbosef("ether: packet too short (%u bytes)", pheader->caplen);
140
memcpy(sm.src_mac, hdr->ether_shost.ether_addr_octet, sizeof(sm.src_mac));
141
memcpy(sm.dst_mac, hdr->ether_dhost.ether_addr_octet, sizeof(sm.dst_mac));
143
memcpy(sm.src_mac, hdr->ether_shost, sizeof(sm.src_mac));
144
memcpy(sm.dst_mac, hdr->ether_dhost, sizeof(sm.dst_mac));
147
type = ntohs( hdr->ether_type );
150
decode_ip(pdata + ETHER_HDR_LEN, pheader->caplen - ETHER_HDR_LEN, &sm);
151
sm.time = pheader->ts.tv_sec;
155
/* known protocol, don't complain about it. */
158
verbosef("ether: unknown protocol (%04x)", type);
163
decode_loop(u_char *user _unused_,
164
const struct pcap_pkthdr *pheader,
169
memset(&sm, 0, sizeof(sm));
171
if (pheader->caplen < NULL_HDR_LEN) {
172
verbosef("loop: packet too short (%u bytes)", pheader->caplen);
175
family = *(const uint32_t *)pdata;
177
family = ntohl(family);
179
if (family == AF_INET) {
180
/* OpenBSD tun or FreeBSD tun or FreeBSD lo */
181
decode_ip(pdata + NULL_HDR_LEN, pheader->caplen - NULL_HDR_LEN, &sm);
182
sm.time = pheader->ts.tv_sec;
186
verbosef("loop: unknown family (%x)", family);
190
decode_ppp(u_char *user _unused_,
191
const struct pcap_pkthdr *pheader,
195
memset(&sm, 0, sizeof(sm));
197
if (pdata[2] == 0x00 && pdata[3] == 0x21) {
198
decode_ip(pdata + PPP_HDR_LEN, pheader->caplen - PPP_HDR_LEN, &sm);
199
sm.time = pheader->ts.tv_sec;
202
verbosef("non-IP PPP packet; ignoring.");
206
decode_pppoe(u_char *user _unused_,
207
const struct pcap_pkthdr *pheader,
211
memset(&sm, 0, sizeof(sm));
213
if (pheader->caplen < PPPOE_HDR_LEN) {
214
verbosef("loop: packet too short (%u bytes)", pheader->caplen);
219
* First, check if this is a session PPPoE packet
220
* by checking the CODE part of the header
221
* (2nd byte in header)
223
if (pdata[1] == 0x00) {
225
* Next, check if PPP packet type is 0x0021,
228
if (pdata[6] == 0x00 && pdata[7] == 0x21) {
229
decode_ip(pdata + PPPOE_HDR_LEN, pheader->caplen - PPPOE_HDR_LEN, &sm);
230
sm.time = pheader->ts.tv_sec;
234
verbosef("non-IP PPPoE packet; ignoring.");
237
verbosef("non-session PPPoE packet; ignoring.");
240
/* very similar to decode_ether ... */
242
decode_linux_sll(u_char *user _unused_,
243
const struct pcap_pkthdr *pheader,
246
const struct sll_header {
247
uint16_t packet_type;
248
uint16_t device_type;
249
uint16_t addr_length;
250
#define SLL_MAX_ADDRLEN 8
251
uint8_t addr[SLL_MAX_ADDRLEN];
253
} *hdr = (const struct sll_header *)pdata;
256
memset(&sm, 0, sizeof(sm));
258
if (pheader->caplen < SLL_HDR_LEN) {
259
verbosef("linux_sll: packet too short (%u bytes)", pheader->caplen);
263
type = ntohs( hdr->ether_type );
266
decode_ip(pdata + SLL_HDR_LEN, pheader->caplen - SLL_HDR_LEN, &sm);
267
sm.time = pheader->ts.tv_sec;
271
/* known protocol, don't complain about it. */
274
verbosef("linux_sll: unknown protocol (%04x)", type);
279
decode_ip(const u_char *pdata, const uint32_t len, pktsummary *sm)
281
const struct ip *hdr = (const struct ip *)pdata;
283
if (len < IP_HDR_LEN) {
284
verbosef("ip: packet too short (%u bytes)", len);
287
if (hdr->ip_v != 4) {
288
verbosef("ip: version %d (expecting 4)", hdr->ip_v);
292
sm->len = ntohs(hdr->ip_len);
293
sm->proto = hdr->ip_p;
294
sm->src_ip = hdr->ip_src.s_addr;
295
sm->dest_ip = hdr->ip_dst.s_addr;
299
const struct tcphdr *thdr =
300
(const struct tcphdr *)(pdata + IP_HDR_LEN);
301
if (len < IP_HDR_LEN + TCP_HDR_LEN) {
302
verbosef("tcp: packet too short (%u bytes)", len);
305
sm->src_port = ntohs(thdr->th_sport);
306
sm->dest_port = ntohs(thdr->th_dport);
307
sm->tcp_flags = thdr->th_flags &
308
(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG);
313
const struct udphdr *uhdr =
314
(const struct udphdr *)(pdata + IP_HDR_LEN);
315
if (len < IP_HDR_LEN + UDP_HDR_LEN) {
316
verbosef("udp: packet too short (%u bytes)", len);
319
sm->src_port = ntohs(uhdr->uh_sport);
320
sm->dest_port = ntohs(uhdr->uh_dport);
325
/* known protocol, don't complain about it */
329
verbosef("ip: unknown protocol %d", sm->proto);
333
/* vim:set ts=3 sw=3 tw=78 expandtab: */