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
;
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
;
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 caplen it needs. */
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 caplen
= getcaplen(linkhdr
);
84 caplen
+= PPPOE_HDR_LEN
;
85 if (linktype
!= DLT_EN10MB
)
86 errx(1, "can't do PPPoE decoding on a non-Ethernet linktype");
88 verbosef("caplen is %d", caplen
);
90 /* Close and re-open pcap to use the new caplen. */
92 errbuf
[0] = '\0'; /* zero length string */
93 pcap
= pcap_open_live(
101 errx(1, "pcap_open_live(): %s", errbuf
);
103 if (errbuf
[0] != '\0') /* not zero length anymore -> warning */
104 warnx("pcap_open_live() warning: %s", errbuf
);
109 verbosef("capturing in promiscuous mode");
111 verbosef("capturing in non-promiscuous mode");
113 /* Set filter expression, if any. */
116 struct bpf_program prog
;
117 char *tmp_filter
= xstrdup(filter
);
125 errx(1, "pcap_compile(): %s", pcap_geterr(pcap
));
127 if (pcap_setfilter(pcap
, &prog
) == -1)
128 errx(1, "pcap_setfilter(): %s", pcap_geterr(pcap
));
130 pcap_freecode(&prog
);
134 pcap_fd
= pcap_fileno(pcap
);
136 /* set non-blocking */
138 if (pcap_setnonblock(pcap
, 1, errbuf
) == -1)
139 errx(1, "pcap_setnonblock(): %s", errbuf
);
142 if (ioctl(pcap_fd
, FIONBIO
, &one
) == -1)
143 err(1, "ioctl(pcap_fd, FIONBIO)"); }
148 /* Deny all writes to the socket */
149 struct bpf_insn bpf_wfilter
[] = { BPF_STMT(BPF_RET
+BPF_K
, 0) };
150 int wf_len
= sizeof(bpf_wfilter
) / sizeof(struct bpf_insn
);
151 struct bpf_program pr
;
154 pr
.bf_insns
= bpf_wfilter
;
156 if (ioctl(pcap_fd
, BIOCSETWF
, &pr
) == -1)
157 err(1, "ioctl(pcap_fd, BIOCSETFW)");
158 verbosef("filtered out BPF writes");
163 /* set "locked" flag (no reset) */
164 if (ioctl(pcap_fd
, BIOCLOCK
) == -1)
165 err(1, "ioctl(pcap_fd, BIOCLOCK)");
166 verbosef("locked down BPF for security");
171 * Set pcap_fd in the given fd_set.
176 fd_set
*read_set _unused_
,
177 int *max_fd _unused_
,
178 struct timeval
*timeout
,
182 struct timeval
*timeout _unused_
,
186 assert(*need_timeout
== 0); /* we're first to get a shot at this */
189 * Linux's BPF is immediate, so don't select() as it will lead to horrible
190 * performance. Instead, use a timeout for buffering.
194 timeout
->tv_usec
= CAP_TIMEOUT
* 1000; /* msec->usec */
196 /* We have a BSD-like BPF, we can select() on it. */
197 FD_SET(pcap_fd
, read_set
);
198 *max_fd
= max(*max_fd
, pcap_fd
);
202 unsigned int pkts_recv
= 0, pkts_drop
= 0;
205 cap_stats_update(void)
209 if (pcap_stats(pcap
, &ps
) != 0) {
210 warnx("pcap_stats(): %s", pcap_geterr(pcap
));
214 pkts_recv
= ps
.ps_recv
;
215 pkts_drop
= ps
.ps_drop
;
219 * Print hexdump of received packet.
222 hexdump(const u_char
*buf
, const uint32_t len
)
226 printf("packet of %u bytes:\n", len
);
228 for (i
=0, col
=0; i
<len
; i
++) {
229 if (col
== 0) printf(" ");
230 printf("%02x", buf
[i
]);
231 if (i
+1 == linkhdr
->hdrlen
)
233 else if (i
+1 == linkhdr
->hdrlen
+ IP_HDR_LEN
)
242 if (col
!= 0) printf("\n");
247 * Callback function for pcap_dispatch() which chains to the decoder specified
251 callback(u_char
*user
, const struct pcap_pkthdr
*h
, const u_char
*bytes
)
253 if (want_hexdump
) hexdump(bytes
, h
->caplen
);
254 linkhdr
->handler(user
, h
, bytes
);
258 * Process any packets currently in the capture buffer.
261 cap_poll(fd_set
*read_set
269 #ifndef linux /* We don't use select() on Linux. */
270 if (!FD_ISSET(pcap_fd
, read_set
)) {
271 verbosef("cap_poll premature");
277 * Once per capture poll, check our IP address. It's used in accounting
278 * for traffic graphs.
280 localip_update(); /* FIXME: this might even be too often */
286 -1, /* count, -1 = entire buffer */
291 warnx("pcap_dispatch(): %s", pcap_geterr(pcap
));
295 /* Despite count = -1, Linux will only dispatch one packet at a time. */
299 /* keep looping until we've dispatched all the outstanding packets */
302 /* we get them all on the first shot */
306 /*FIXME*/if (want_verbose
) fprintf(stderr
, "%-20d\r", total
);
316 /* Run through entire capfile. */
318 cap_from_file(const char *capfile
, const char *filter
)
320 char errbuf
[PCAP_ERRBUF_SIZE
];
323 /* Open packet capture descriptor. */
324 errbuf
[0] = '\0'; /* zero length string */
325 pcap
= pcap_open_offline(capfile
, errbuf
);
328 errx(1, "pcap_open_offline(): %s", errbuf
);
330 if (errbuf
[0] != '\0') /* not zero length anymore -> warning */
331 warnx("pcap_open_offline() warning: %s", errbuf
);
333 /* Work out the linktype. */
334 linktype
= pcap_datalink(pcap
);
335 linkhdr
= getlinkhdr(linktype
);
337 errx(1, "unknown linktype %d", linktype
);
338 if (linkhdr
->handler
== NULL
)
339 errx(1, "no handler for linktype %d", linktype
);
340 if (linktype
== DLT_EN10MB
) /* FIXME: impossible with capfile? */
343 /* Set filter expression, if any. */ /* FIXME: factor! */
346 struct bpf_program prog
;
347 char *tmp_filter
= xstrdup(filter
);
355 errx(1, "pcap_compile(): %s", pcap_geterr(pcap
));
357 if (pcap_setfilter(pcap
, &prog
) == -1)
358 errx(1, "pcap_setfilter(): %s", pcap_geterr(pcap
));
360 pcap_freecode(&prog
);
367 -1, /* count, -1 = entire buffer */
372 errx(1, "pcap_dispatch(): %s", pcap_geterr(pcap
));
375 /* vim:set ts=3 sw=3 tw=78 expandtab: */