2 * copyright (c) 2001-2009 Emil Mikulic.
4 * cap.c: interface to libpcap.
6 * You may use, modify and redistribute this file under the terms of the
7 * GNU General Public License version 2. (see COPYING.GPL)
17 #include <sys/ioctl.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
21 #ifdef HAVE_SYS_FILIO_H
22 # include <sys/filio.h> /* Solaris' FIONBIO hides here */
31 extern int want_pppoe
, want_macs
, want_hexdump
, want_snaplen
;
33 /* The cap process life-cycle:
36 * Fill fd_set - cap_fd_set()
41 /* Globals - only useful within this module. */
42 static pcap_t
*pcap
= NULL
;
43 static int pcap_fd
= -1;
44 static const linkhdr_t
*linkhdr
= NULL
;
46 #define CAP_TIMEOUT 500 /* granularity of capture buffer, in milliseconds */
48 /* ---------------------------------------------------------------------------
49 * Init pcap. Exits on failure.
52 cap_init(const char *device
, const char *filter
, int promisc
)
54 char errbuf
[PCAP_ERRBUF_SIZE
], *tmp_device
;
55 int linktype
, snaplen
;
57 /* pcap doesn't like device being const */
58 tmp_device
= xstrdup(device
);
60 /* Open packet capture descriptor. */
61 errbuf
[0] = '\0'; /* zero length string */
62 pcap
= pcap_open_live(
64 1, /* snaplen, irrelevant at this point */
65 0, /* promisc, also irrelevant */
70 errx(1, "pcap_open_live(): %s", errbuf
);
72 /* Work out the linktype and what snaplen we need. */
73 linktype
= pcap_datalink(pcap
);
74 verbosef("linktype is %d", linktype
);
75 if ((linktype
== DLT_EN10MB
) && want_macs
)
77 linkhdr
= getlinkhdr(linktype
);
79 errx(1, "unknown linktype %d", linktype
);
80 if (linkhdr
->handler
== NULL
)
81 errx(1, "no handler for linktype %d", linktype
);
82 snaplen
= getsnaplen(linkhdr
);
84 snaplen
+= PPPOE_HDR_LEN
;
85 if (linktype
!= DLT_EN10MB
)
86 errx(1, "can't do PPPoE decoding on a non-Ethernet linktype");
88 verbosef("calculated snaplen minimum %d", snaplen
);
90 /* Ubuntu 9.04 has a problem where requesting snaplen <= 60 will
91 * give us 42 bytes, and we need at least 54 for TCP headers.
93 * Hack to set minimum snaplen to tcpdump's default:
95 snaplen
= max(snaplen
, 68);
97 if (want_snaplen
> -1)
98 snaplen
= want_snaplen
;
99 verbosef("using snaplen %d", snaplen
);
101 /* Close and re-open pcap to use the new snaplen. */
103 errbuf
[0] = '\0'; /* zero length string */
104 pcap
= pcap_open_live(
112 errx(1, "pcap_open_live(): %s", errbuf
);
114 if (errbuf
[0] != '\0') /* not zero length anymore -> warning */
115 warnx("pcap_open_live() warning: %s", errbuf
);
120 verbosef("capturing in promiscuous mode");
122 verbosef("capturing in non-promiscuous mode");
124 /* Set filter expression, if any. */
127 struct bpf_program prog
;
128 char *tmp_filter
= xstrdup(filter
);
136 errx(1, "pcap_compile(): %s", pcap_geterr(pcap
));
138 if (pcap_setfilter(pcap
, &prog
) == -1)
139 errx(1, "pcap_setfilter(): %s", pcap_geterr(pcap
));
141 pcap_freecode(&prog
);
145 pcap_fd
= pcap_fileno(pcap
);
147 /* set non-blocking */
149 if (pcap_setnonblock(pcap
, 1, errbuf
) == -1)
150 errx(1, "pcap_setnonblock(): %s", errbuf
);
153 if (ioctl(pcap_fd
, FIONBIO
, &one
) == -1)
154 err(1, "ioctl(pcap_fd, FIONBIO)"); }
159 /* Deny all writes to the socket */
160 struct bpf_insn bpf_wfilter
[] = { BPF_STMT(BPF_RET
+BPF_K
, 0) };
161 int wf_len
= sizeof(bpf_wfilter
) / sizeof(struct bpf_insn
);
162 struct bpf_program pr
;
165 pr
.bf_insns
= bpf_wfilter
;
167 if (ioctl(pcap_fd
, BIOCSETWF
, &pr
) == -1)
168 err(1, "ioctl(pcap_fd, BIOCSETFW)");
169 verbosef("filtered out BPF writes");
174 /* set "locked" flag (no reset) */
175 if (ioctl(pcap_fd
, BIOCLOCK
) == -1)
176 err(1, "ioctl(pcap_fd, BIOCLOCK)");
177 verbosef("locked down BPF for security");
182 * Set pcap_fd in the given fd_set.
187 fd_set
*read_set _unused_
,
188 int *max_fd _unused_
,
189 struct timeval
*timeout
,
193 struct timeval
*timeout _unused_
,
197 assert(*need_timeout
== 0); /* we're first to get a shot at this */
200 * Linux's BPF is immediate, so don't select() as it will lead to horrible
201 * performance. Instead, use a timeout for buffering.
205 timeout
->tv_usec
= CAP_TIMEOUT
* 1000; /* msec->usec */
207 /* We have a BSD-like BPF, we can select() on it. */
208 FD_SET(pcap_fd
, read_set
);
209 *max_fd
= max(*max_fd
, pcap_fd
);
213 unsigned int pkts_recv
= 0, pkts_drop
= 0;
216 cap_stats_update(void)
220 if (pcap_stats(pcap
, &ps
) != 0) {
221 warnx("pcap_stats(): %s", pcap_geterr(pcap
));
225 pkts_recv
= ps
.ps_recv
;
226 pkts_drop
= ps
.ps_drop
;
230 * Print hexdump of received packet.
233 hexdump(const u_char
*buf
, const uint32_t len
)
237 printf("packet of %u bytes:\n", len
);
239 for (i
=0, col
=0; i
<len
; i
++) {
240 if (col
== 0) printf(" ");
241 printf("%02x", buf
[i
]);
242 if (i
+1 == linkhdr
->hdrlen
)
244 else if (i
+1 == linkhdr
->hdrlen
+ IP_HDR_LEN
)
253 if (col
!= 0) printf("\n");
258 * Callback function for pcap_dispatch() which chains to the decoder specified
262 callback(u_char
*user
, const struct pcap_pkthdr
*h
, const u_char
*bytes
)
264 if (want_hexdump
) hexdump(bytes
, h
->caplen
);
265 linkhdr
->handler(user
, h
, bytes
);
269 * Process any packets currently in the capture buffer.
272 cap_poll(fd_set
*read_set
280 #ifndef linux /* We don't use select() on Linux. */
281 if (!FD_ISSET(pcap_fd
, read_set
)) {
282 verbosef("cap_poll premature");
288 * Once per capture poll, check our IP address. It's used in accounting
289 * for traffic graphs.
291 localip_update(); /* FIXME: this might even be too often */
297 -1, /* count, -1 = entire buffer */
302 warnx("pcap_dispatch(): %s", pcap_geterr(pcap
));
306 /* Despite count = -1, Linux will only dispatch one packet at a time. */
310 /* keep looping until we've dispatched all the outstanding packets */
313 /* we get them all on the first shot */
317 /*FIXME*/if (want_verbose
) fprintf(stderr
, "%-20d\r", total
);
327 /* Run through entire capfile. */
329 cap_from_file(const char *capfile
, const char *filter
)
331 char errbuf
[PCAP_ERRBUF_SIZE
];
334 /* Open packet capture descriptor. */
335 errbuf
[0] = '\0'; /* zero length string */
336 pcap
= pcap_open_offline(capfile
, errbuf
);
339 errx(1, "pcap_open_offline(): %s", errbuf
);
341 if (errbuf
[0] != '\0') /* not zero length anymore -> warning */
342 warnx("pcap_open_offline() warning: %s", errbuf
);
344 /* Work out the linktype. */
345 linktype
= pcap_datalink(pcap
);
346 linkhdr
= getlinkhdr(linktype
);
348 errx(1, "unknown linktype %d", linktype
);
349 if (linkhdr
->handler
== NULL
)
350 errx(1, "no handler for linktype %d", linktype
);
351 if (linktype
== DLT_EN10MB
) /* FIXME: impossible with capfile? */
354 /* Set filter expression, if any. */ /* FIXME: factor! */
357 struct bpf_program prog
;
358 char *tmp_filter
= xstrdup(filter
);
366 errx(1, "pcap_compile(): %s", pcap_geterr(pcap
));
368 if (pcap_setfilter(pcap
, &prog
) == -1)
369 errx(1, "pcap_setfilter(): %s", pcap_geterr(pcap
));
371 pcap_freecode(&prog
);
378 -1, /* count, -1 = entire buffer */
383 errx(1, "pcap_dispatch(): %s", pcap_geterr(pcap
));
386 /* vim:set ts=3 sw=3 tw=78 expandtab: */