xref: /openbsd-src/lib/libpcap/pcap-bpf.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: pcap-bpf.c,v 1.20 2006/03/26 20:58:51 djm Exp $	*/
2 
3 /*
4  * Copyright (c) 1993, 1994, 1995, 1996, 1998
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that: (1) source code distributions
9  * retain the above copyright notice and this paragraph in its entirety, (2)
10  * distributions including binary code include the above copyright notice and
11  * this paragraph in its entirety in the documentation or other materials
12  * provided with the distribution, and (3) all advertising materials mentioning
13  * features or use of this software display the following acknowledgement:
14  * ``This product includes software developed by the University of California,
15  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16  * the University nor the names of its contributors may be used to endorse
17  * or promote products derived from this software without specific prior
18  * written permission.
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  */
23 
24 #include <sys/param.h>			/* optionally get BSD define */
25 #include <sys/time.h>
26 #include <sys/timeb.h>
27 #include <sys/socket.h>
28 #include <sys/ioctl.h>
29 
30 #include <net/if.h>
31 
32 #include <ctype.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <netdb.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #include "pcap-int.h"
42 
43 #ifdef HAVE_OS_PROTO_H
44 #include "os-proto.h"
45 #endif
46 
47 #include "gencode.h"
48 
49 int
50 pcap_stats(pcap_t *p, struct pcap_stat *ps)
51 {
52 	struct bpf_stat s;
53 
54 	if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) {
55 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGSTATS: %s",
56 		    pcap_strerror(errno));
57 		return (-1);
58 	}
59 
60 	ps->ps_recv = s.bs_recv;
61 	ps->ps_drop = s.bs_drop;
62 	return (0);
63 }
64 
65 int
66 pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
67 {
68 	int cc;
69 	int n = 0;
70 	register u_char *bp, *ep;
71 
72  again:
73 	/*
74 	 * Has "pcap_breakloop()" been called?
75 	 */
76 	if (p->break_loop) {
77 		/*
78 		 * Yes - clear the flag that indicates that it
79 		 * has, and return -2 to indicate that we were
80 		 * told to break out of the loop.
81 		 */
82 		p->break_loop = 0;
83 		return (-2);
84 	}
85 
86 	cc = p->cc;
87 	if (p->cc == 0) {
88 		cc = read(p->fd, (char *)p->buffer, p->bufsize);
89 		if (cc < 0) {
90 			/* Don't choke when we get ptraced */
91 			switch (errno) {
92 
93 			case EINTR:
94 				goto again;
95 
96 			case EWOULDBLOCK:
97 				return (0);
98 #if defined(sun) && !defined(BSD)
99 			/*
100 			 * Due to a SunOS bug, after 2^31 bytes, the kernel
101 			 * file offset overflows and read fails with EINVAL.
102 			 * The lseek() to 0 will fix things.
103 			 */
104 			case EINVAL:
105 				if (lseek(p->fd, 0L, SEEK_CUR) +
106 				    p->bufsize < 0) {
107 					(void)lseek(p->fd, 0L, SEEK_SET);
108 					goto again;
109 				}
110 				/* FALLTHROUGH */
111 #endif
112 			}
113 			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read: %s",
114 			    pcap_strerror(errno));
115 			return (-1);
116 		}
117 		bp = p->buffer;
118 	} else
119 		bp = p->bp;
120 
121 	/*
122 	 * Loop through each packet.
123 	 */
124 #define bhp ((struct bpf_hdr *)bp)
125 	ep = bp + cc;
126 	while (bp < ep) {
127 		register int caplen, hdrlen;
128 
129 		/*
130 		 * Has "pcap_breakloop()" been called?
131 		 * If so, return immediately - if we haven't read any
132 		 * packets, clear the flag and return -2 to indicate
133 		 * that we were told to break out of the loop, otherwise
134 		 * leave the flag set, so that the *next* call will break
135 		 * out of the loop without having read any packets, and
136 		 * return the number of packets we've processed so far.
137 		 */
138 		if (p->break_loop) {
139 			if (n == 0) {
140 				p->break_loop = 0;
141 				return (-2);
142 			} else {
143 				p->bp = bp;
144 				p->cc = ep - bp;
145 				return (n);
146 			}
147 		}
148 
149 		caplen = bhp->bh_caplen;
150 		hdrlen = bhp->bh_hdrlen;
151 		/*
152 		 * XXX A bpf_hdr matches a pcap_pkthdr.
153 		 */
154 		(*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen);
155 		bp += BPF_WORDALIGN(caplen + hdrlen);
156 		if (++n >= cnt && cnt > 0) {
157 			p->bp = bp;
158 			p->cc = ep - bp;
159 			return (n);
160 		}
161 	}
162 #undef bhp
163 	p->cc = 0;
164 	return (n);
165 }
166 
167 int
168 pcap_inject(pcap_t *p, const void *buf, size_t len)
169 {
170 	return (write(p->fd, buf, len));
171 }
172 
173 int
174 pcap_sendpacket(pcap_t *p, const u_char *buf, int size)
175 {
176 	return (pcap_inject(p, buf, size) == -1 ? -1 : 0);
177 }
178 
179 /* ARGSUSED */
180 static __inline int
181 bpf_open(pcap_t *p, char *errbuf)
182 {
183 	int fd;
184 	int n = 0;
185 	char device[sizeof "/dev/bpf0000000000"];
186 
187 	/*
188 	 * Go through all the minors and find one that isn't in use.
189 	 */
190 	do {
191 		(void)snprintf(device, sizeof device, "/dev/bpf%d", n++);
192 		fd = open(device, O_RDWR);
193 		if (fd < 0 && errno == EACCES)
194 			fd = open(device, O_RDONLY);
195 	} while (fd < 0 && errno == EBUSY);
196 
197 	/*
198 	 * XXX better message for all minors used
199 	 */
200 	if (fd < 0)
201 		snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
202 		    device, pcap_strerror(errno));
203 
204 	return (fd);
205 }
206 
207 pcap_t *
208 pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
209     char *ebuf)
210 {
211 	int fd;
212 	struct ifreq ifr;
213 	struct bpf_version bv;
214 	u_int v;
215 	pcap_t *p;
216 	struct bpf_dltlist bdl;
217 
218 	bzero(&bdl, sizeof(bdl));
219 	p = (pcap_t *)malloc(sizeof(*p));
220 	if (p == NULL) {
221 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
222 		    pcap_strerror(errno));
223 		return (NULL);
224 	}
225 	bzero(p, sizeof(*p));
226 	fd = bpf_open(p, ebuf);
227 	if (fd < 0)
228 		goto bad;
229 
230 	p->fd = fd;
231 	p->snapshot = snaplen;
232 
233 	if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
234 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s",
235 		    pcap_strerror(errno));
236 		goto bad;
237 	}
238 	if (bv.bv_major != BPF_MAJOR_VERSION ||
239 	    bv.bv_minor < BPF_MINOR_VERSION) {
240 		snprintf(ebuf, PCAP_ERRBUF_SIZE,
241 		    "kernel bpf filter out of date");
242 		goto bad;
243 	}
244 #if 0
245 	/* Just use the kernel default */
246 	v = 32768;	/* XXX this should be a user-accessible hook */
247 	/* Ignore the return value - this is because the call fails on
248 	 * BPF systems that don't have kernel malloc.  And if the call
249 	 * fails, it's no big deal, we just continue to use the standard
250 	 * buffer size.
251 	 */
252 	(void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
253 #endif
254 
255 	(void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
256 	if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
257 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s",
258 		    device, pcap_strerror(errno));
259 		goto bad;
260 	}
261 	/* Get the data link layer type. */
262 	if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
263 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s",
264 		    pcap_strerror(errno));
265 		goto bad;
266 	}
267 #if _BSDI_VERSION - 0 >= 199510
268 	/* The SLIP and PPP link layer header changed in BSD/OS 2.1 */
269 	switch (v) {
270 
271 	case DLT_SLIP:
272 		v = DLT_SLIP_BSDOS;
273 		break;
274 
275 	case DLT_PPP:
276 		v = DLT_PPP_BSDOS;
277 		break;
278 	}
279 #endif
280 	p->linktype = v;
281 
282 	/*
283 	 * We know the default link type -- now determine all the DLTs
284 	 * this interface supports.  If this fails with EINVAL, it's
285 	 * not fatal; we just don't get to use the feature later.
286 	 */
287 	if (ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) == 0) {
288 		bdl.bfl_list = (u_int *) calloc(bdl.bfl_len + 1, sizeof(u_int));
289 		if (bdl.bfl_list == NULL) {
290 			(void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
291 			    pcap_strerror(errno));
292 			goto bad;
293 		}
294 
295 		if (ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) < 0) {
296 			(void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
297 			    "BIOCGDLTLIST: %s", pcap_strerror(errno));
298 			goto bad;
299 		}
300 		p->dlt_count = bdl.bfl_len;
301 		p->dlt_list = bdl.bfl_list;
302 	} else {
303 		if (errno != EINVAL) {
304 			(void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
305 			    "BIOCGDLTLIST: %s", pcap_strerror(errno));
306 			goto bad;
307 		}
308 	}
309 
310 	/* set timeout */
311 	if (to_ms != 0) {
312 		struct timeval to;
313 		to.tv_sec = to_ms / 1000;
314 		to.tv_usec = (to_ms * 1000) % 1000000;
315 		if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {
316 			snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s",
317 			    pcap_strerror(errno));
318 			goto bad;
319 		}
320 	}
321 	if (promisc)
322 		/* set promiscuous mode, okay if it fails */
323 		(void)ioctl(p->fd, BIOCPROMISC, NULL);
324 
325 	if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
326 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s",
327 		    pcap_strerror(errno));
328 		goto bad;
329 	}
330 	p->bufsize = v;
331 	p->buffer = (u_char *)malloc(p->bufsize);
332 	if (p->buffer == NULL) {
333 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
334 		    pcap_strerror(errno));
335 		goto bad;
336 	}
337 
338 	return (p);
339  bad:
340 	if (fd >= 0)
341 		(void)close(fd);
342 	free(bdl.bfl_list);
343 	free(p);
344 	return (NULL);
345 }
346 
347 int
348 pcap_setfilter(pcap_t *p, struct bpf_program *fp)
349 {
350 	size_t buflen;
351 	/*
352 	 * It looks that BPF code generated by gen_protochain() is not
353 	 * compatible with some of kernel BPF code (for example BSD/OS 3.1).
354 	 * Take a safer side for now.
355 	 */
356 	if (no_optimize || (p->sf.rfile != NULL)){
357 		if (p->fcode.bf_insns != NULL)
358 			pcap_freecode(&p->fcode);
359 		buflen = sizeof(*fp->bf_insns) * fp->bf_len;
360 		p->fcode.bf_len = fp->bf_len;
361 		p->fcode.bf_insns = malloc(buflen);
362 		if (p->fcode.bf_insns == NULL) {
363 			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s",
364 			    pcap_strerror(errno));
365 			return (-1);
366 		}
367 		memcpy(p->fcode.bf_insns, fp->bf_insns, buflen);
368 	} else if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) {
369 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s",
370 		    pcap_strerror(errno));
371 		return (-1);
372 	}
373 	return (0);
374 }
375 
376 int
377 pcap_setdirection(pcap_t *p, pcap_direction_t d)
378 {
379 	u_int dirfilt;
380 
381 	switch (d) {
382 	case PCAP_D_INOUT:
383 		dirfilt = 0;
384 		break;
385 	case PCAP_D_IN:
386 		dirfilt = BPF_DIRECTION_OUT;
387 		break;
388 	case PCAP_D_OUT:
389 		dirfilt = BPF_DIRECTION_IN;
390 		break;
391 	default:
392 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Invalid direction");
393 		return (-1);
394 	}
395 	if (ioctl(p->fd, BIOCSDIRFILT, &dirfilt) < 0) {
396 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSDIRFILT: %s",
397 		    pcap_strerror(errno));
398 		return (-1);
399 	}
400 	return (0);
401 }
402 
403 int
404 pcap_set_datalink(pcap_t *p, int dlt)
405 {
406 	int i;
407 
408 	if (p->dlt_count == 0) {
409 		/*
410 		 * We couldn't fetch the list of DLTs, or we don't
411 		 * have a "set datalink" operation, which means
412 		 * this platform doesn't support changing the
413 		 * DLT for an interface.  Check whether the new
414 		 * DLT is the one this interface supports.
415 		 */
416 		if (p->linktype != dlt)
417 			goto unsupported;
418 
419 		/*
420 		 * It is, so there's nothing we need to do here.
421 		 */
422 		return (0);
423 	}
424 	for (i = 0; i < p->dlt_count; i++)
425 		if (p->dlt_list[i] == dlt)
426 			break;
427 	if (i >= p->dlt_count)
428 		goto unsupported;
429 	if (ioctl(p->fd, BIOCSDLT, &dlt) == -1) {
430 		(void) snprintf(p->errbuf, sizeof(p->errbuf),
431 		    "Cannot set DLT %d: %s", dlt, strerror(errno));
432 		return (-1);
433 	}
434 	p->linktype = dlt;
435 	return (0);
436 
437 unsupported:
438 	(void) snprintf(p->errbuf, sizeof(p->errbuf),
439 	    "DLT %d is not one of the DLTs supported by this device",
440 	    dlt);
441 	return (-1);
442 }
443 
444