1214455Srpaulo/*
2214455Srpaulo * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
3214455Srpaulo *	The Regents of the University of California.  All rights reserved.
4214455Srpaulo *
5214455Srpaulo * Redistribution and use in source and binary forms, with or without
6214455Srpaulo * modification, are permitted provided that: (1) source code distributions
7214455Srpaulo * retain the above copyright notice and this paragraph in its entirety, (2)
8214455Srpaulo * distributions including binary code include the above copyright notice and
9214455Srpaulo * this paragraph in its entirety in the documentation or other materials
10214455Srpaulo * provided with the distribution, and (3) all advertising materials mentioning
11214455Srpaulo * features or use of this software display the following acknowledgement:
12214455Srpaulo * ``This product includes software developed by the University of California,
13214455Srpaulo * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14214455Srpaulo * the University nor the names of its contributors may be used to endorse
15214455Srpaulo * or promote products derived from this software without specific prior
16214455Srpaulo * written permission.
17214455Srpaulo * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18214455Srpaulo * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19214455Srpaulo * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20214455Srpaulo */
21214455Srpaulo
22214455Srpaulo#ifndef lint
23214455Srpaulostatic const char copyright[] =
24214455Srpaulo    "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
25214455SrpauloThe Regents of the University of California.  All rights reserved.\n";
26214455Srpaulo#endif
27214455Srpaulo
28214455Srpaulo#include <pcap.h>
29214455Srpaulo#include <stdio.h>
30214455Srpaulo#include <stdlib.h>
31214455Srpaulo#include <string.h>
32214455Srpaulo#include <stdarg.h>
33214455Srpaulo#include <unistd.h>
34214455Srpaulo#include <errno.h>
35214455Srpaulo#include <sys/types.h>
36214455Srpaulo#include <sys/select.h>
37214455Srpaulo#include <poll.h>
38214455Srpaulo
39214455Srpaulochar *program_name;
40214455Srpaulo
41214455Srpaulo/* Forwards */
42214455Srpaulostatic void countme(u_char *, const struct pcap_pkthdr *, const u_char *);
43214455Srpaulostatic void usage(void) __attribute__((noreturn));
44214455Srpaulostatic void error(const char *, ...);
45214455Srpaulostatic void warning(const char *, ...);
46214455Srpaulostatic char *copy_argv(char **);
47214455Srpaulo
48214455Srpaulostatic pcap_t *pd;
49214455Srpaulo
50214455Srpauloextern int optind;
51214455Srpauloextern int opterr;
52214455Srpauloextern char *optarg;
53214455Srpaulo
54214455Srpauloint
55214455Srpaulomain(int argc, char **argv)
56214455Srpaulo{
57214455Srpaulo	register int op;
58214455Srpaulo	bpf_u_int32 localnet, netmask;
59214455Srpaulo	register char *cp, *cmdbuf, *device;
60214455Srpaulo	int doselect, dopoll, dotimeout, dononblock;
61214455Srpaulo	struct bpf_program fcode;
62214455Srpaulo	char ebuf[PCAP_ERRBUF_SIZE];
63214455Srpaulo	int selectable_fd;
64214455Srpaulo	int status;
65214455Srpaulo	int packet_count;
66214455Srpaulo
67214455Srpaulo	device = NULL;
68214455Srpaulo	doselect = 0;
69214455Srpaulo	dopoll = 0;
70214455Srpaulo	dotimeout = 0;
71214455Srpaulo	dononblock = 0;
72214455Srpaulo	if ((cp = strrchr(argv[0], '/')) != NULL)
73214455Srpaulo		program_name = cp + 1;
74214455Srpaulo	else
75214455Srpaulo		program_name = argv[0];
76214455Srpaulo
77214455Srpaulo	opterr = 0;
78214455Srpaulo	while ((op = getopt(argc, argv, "i:sptn")) != -1) {
79214455Srpaulo		switch (op) {
80214455Srpaulo
81214455Srpaulo		case 'i':
82214455Srpaulo			device = optarg;
83214455Srpaulo			break;
84214455Srpaulo
85214455Srpaulo		case 's':
86214455Srpaulo			doselect = 1;
87214455Srpaulo			break;
88214455Srpaulo
89214455Srpaulo		case 'p':
90214455Srpaulo			dopoll = 1;
91214455Srpaulo			break;
92214455Srpaulo
93214455Srpaulo		case 't':
94214455Srpaulo			dotimeout = 1;
95214455Srpaulo			break;
96214455Srpaulo
97214455Srpaulo		case 'n':
98214455Srpaulo			dononblock = 1;
99214455Srpaulo			break;
100214455Srpaulo
101214455Srpaulo		default:
102214455Srpaulo			usage();
103214455Srpaulo			/* NOTREACHED */
104214455Srpaulo		}
105214455Srpaulo	}
106214455Srpaulo
107214455Srpaulo	if (doselect && dopoll) {
108214455Srpaulo		fprintf(stderr, "selpolltest: choose select (-s) or poll (-p), but not both\n");
109214455Srpaulo		return 1;
110214455Srpaulo	}
111214455Srpaulo	if (dotimeout && !doselect && !dopoll) {
112214455Srpaulo		fprintf(stderr, "selpolltest: timeout (-t) requires select (-s) or poll (-p)\n");
113214455Srpaulo		return 1;
114214455Srpaulo	}
115214455Srpaulo	if (device == NULL) {
116214455Srpaulo		device = pcap_lookupdev(ebuf);
117214455Srpaulo		if (device == NULL)
118214455Srpaulo			error("%s", ebuf);
119214455Srpaulo	}
120214455Srpaulo	*ebuf = '\0';
121214455Srpaulo	pd = pcap_open_live(device, 65535, 0, 1000, ebuf);
122214455Srpaulo	if (pd == NULL)
123214455Srpaulo		error("%s", ebuf);
124214455Srpaulo	else if (*ebuf)
125214455Srpaulo		warning("%s", ebuf);
126214455Srpaulo	if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
127214455Srpaulo		localnet = 0;
128214455Srpaulo		netmask = 0;
129214455Srpaulo		warning("%s", ebuf);
130214455Srpaulo	}
131214455Srpaulo	cmdbuf = copy_argv(&argv[optind]);
132214455Srpaulo
133214455Srpaulo	if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
134214455Srpaulo		error("%s", pcap_geterr(pd));
135214455Srpaulo
136214455Srpaulo	if (pcap_setfilter(pd, &fcode) < 0)
137214455Srpaulo		error("%s", pcap_geterr(pd));
138214455Srpaulo	if (pcap_get_selectable_fd(pd) == -1)
139214455Srpaulo		error("pcap_get_selectable_fd() fails");
140214455Srpaulo	if (dononblock) {
141214455Srpaulo		if (pcap_setnonblock(pd, 1, ebuf) == -1)
142214455Srpaulo			error("pcap_setnonblock failed: %s", ebuf);
143214455Srpaulo	}
144214455Srpaulo	selectable_fd = pcap_get_selectable_fd(pd);
145214455Srpaulo	printf("Listening on %s\n", device);
146214455Srpaulo	if (doselect) {
147214455Srpaulo		for (;;) {
148214455Srpaulo			fd_set setread, setexcept;
149214455Srpaulo			struct timeval seltimeout;
150214455Srpaulo
151214455Srpaulo			FD_ZERO(&setread);
152214455Srpaulo			FD_SET(selectable_fd, &setread);
153214455Srpaulo			FD_ZERO(&setexcept);
154214455Srpaulo			FD_SET(selectable_fd, &setexcept);
155214455Srpaulo			if (dotimeout) {
156214455Srpaulo				seltimeout.tv_sec = 0;
157214455Srpaulo				seltimeout.tv_usec = 1000;
158214455Srpaulo				status = select(selectable_fd + 1, &setread,
159214455Srpaulo				    NULL, &setexcept, &seltimeout);
160214455Srpaulo			} else {
161214455Srpaulo				status = select(selectable_fd + 1, &setread,
162214455Srpaulo				    NULL, &setexcept, NULL);
163214455Srpaulo			}
164214455Srpaulo			if (status == -1) {
165214455Srpaulo				printf("Select returns error (%s)\n",
166214455Srpaulo				    strerror(errno));
167214455Srpaulo			} else {
168214455Srpaulo				if (status == 0)
169214455Srpaulo					printf("Select timed out: ");
170214455Srpaulo				else
171214455Srpaulo					printf("Select returned a descriptor: ");
172214455Srpaulo				if (FD_ISSET(selectable_fd, &setread))
173214455Srpaulo					printf("readable, ");
174214455Srpaulo				else
175214455Srpaulo					printf("not readable, ");
176214455Srpaulo				if (FD_ISSET(selectable_fd, &setexcept))
177214455Srpaulo					printf("exceptional condition\n");
178214455Srpaulo				else
179214455Srpaulo					printf("no exceptional condition\n");
180214455Srpaulo				packet_count = 0;
181214455Srpaulo				status = pcap_dispatch(pd, -1, countme,
182214455Srpaulo				    (u_char *)&packet_count);
183214455Srpaulo				if (status < 0)
184214455Srpaulo					break;
185214455Srpaulo				printf("%d packets seen, %d packets counted after select returns\n",
186214455Srpaulo				    status, packet_count);
187214455Srpaulo			}
188214455Srpaulo		}
189214455Srpaulo	} else if (dopoll) {
190214455Srpaulo		for (;;) {
191214455Srpaulo			struct pollfd fd;
192214455Srpaulo			int polltimeout;
193214455Srpaulo
194214455Srpaulo			fd.fd = selectable_fd;
195214455Srpaulo			fd.events = POLLIN;
196214455Srpaulo			if (dotimeout)
197214455Srpaulo				polltimeout = 1;
198214455Srpaulo			else
199214455Srpaulo				polltimeout = -1;
200214455Srpaulo			status = poll(&fd, 1, polltimeout);
201214455Srpaulo			if (status == -1) {
202214455Srpaulo				printf("Poll returns error (%s)\n",
203214455Srpaulo				    strerror(errno));
204214455Srpaulo			} else {
205214455Srpaulo				if (status == 0)
206214455Srpaulo					printf("Poll timed out\n");
207214455Srpaulo				else {
208214455Srpaulo					printf("Poll returned a descriptor: ");
209214455Srpaulo					if (fd.revents & POLLIN)
210214455Srpaulo						printf("readable, ");
211214455Srpaulo					else
212214455Srpaulo						printf("not readable, ");
213214455Srpaulo					if (fd.revents & POLLERR)
214214455Srpaulo						printf("exceptional condition, ");
215214455Srpaulo					else
216214455Srpaulo						printf("no exceptional condition, ");
217214455Srpaulo					if (fd.revents & POLLHUP)
218214455Srpaulo						printf("disconnect, ");
219214455Srpaulo					else
220214455Srpaulo						printf("no disconnect, ");
221214455Srpaulo					if (fd.revents & POLLNVAL)
222214455Srpaulo						printf("invalid\n");
223214455Srpaulo					else
224214455Srpaulo						printf("not invalid\n");
225214455Srpaulo				}
226214455Srpaulo				packet_count = 0;
227214455Srpaulo				status = pcap_dispatch(pd, -1, countme,
228214455Srpaulo				    (u_char *)&packet_count);
229214455Srpaulo				if (status < 0)
230214455Srpaulo					break;
231214455Srpaulo				printf("%d packets seen, %d packets counted after poll returns\n",
232214455Srpaulo				    status, packet_count);
233214455Srpaulo			}
234214455Srpaulo		}
235214455Srpaulo	} else {
236214455Srpaulo		for (;;) {
237214455Srpaulo			packet_count = 0;
238214455Srpaulo			status = pcap_dispatch(pd, -1, countme,
239214455Srpaulo			    (u_char *)&packet_count);
240214455Srpaulo			if (status < 0)
241214455Srpaulo				break;
242214455Srpaulo			printf("%d packets seen, %d packets counted after pcap_dispatch returns\n",
243214455Srpaulo			    status, packet_count);
244214455Srpaulo		}
245214455Srpaulo	}
246214455Srpaulo	if (status == -2) {
247214455Srpaulo		/*
248214455Srpaulo		 * We got interrupted, so perhaps we didn't
249214455Srpaulo		 * manage to finish a line we were printing.
250214455Srpaulo		 * Print an extra newline, just in case.
251214455Srpaulo		 */
252214455Srpaulo		putchar('\n');
253214455Srpaulo	}
254214455Srpaulo	(void)fflush(stdout);
255214455Srpaulo	if (status == -1) {
256214455Srpaulo		/*
257214455Srpaulo		 * Error.  Report it.
258214455Srpaulo		 */
259214455Srpaulo		(void)fprintf(stderr, "%s: pcap_loop: %s\n",
260214455Srpaulo		    program_name, pcap_geterr(pd));
261214455Srpaulo	}
262214455Srpaulo	pcap_close(pd);
263214455Srpaulo	exit(status == -1 ? 1 : 0);
264214455Srpaulo}
265214455Srpaulo
266214455Srpaulostatic void
267214455Srpaulocountme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
268214455Srpaulo{
269214455Srpaulo	int *counterp = (int *)user;
270214455Srpaulo
271214455Srpaulo	(*counterp)++;
272214455Srpaulo}
273214455Srpaulo
274214455Srpaulostatic void
275214455Srpaulousage(void)
276214455Srpaulo{
277214455Srpaulo	(void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n",
278214455Srpaulo	    program_name);
279214455Srpaulo	exit(1);
280214455Srpaulo}
281214455Srpaulo
282214455Srpaulo/* VARARGS */
283214455Srpaulostatic void
284214455Srpauloerror(const char *fmt, ...)
285214455Srpaulo{
286214455Srpaulo	va_list ap;
287214455Srpaulo
288214455Srpaulo	(void)fprintf(stderr, "%s: ", program_name);
289214455Srpaulo	va_start(ap, fmt);
290214455Srpaulo	(void)vfprintf(stderr, fmt, ap);
291214455Srpaulo	va_end(ap);
292214455Srpaulo	if (*fmt) {
293214455Srpaulo		fmt += strlen(fmt);
294214455Srpaulo		if (fmt[-1] != '\n')
295214455Srpaulo			(void)fputc('\n', stderr);
296214455Srpaulo	}
297214455Srpaulo	exit(1);
298214455Srpaulo	/* NOTREACHED */
299214455Srpaulo}
300214455Srpaulo
301214455Srpaulo/* VARARGS */
302214455Srpaulostatic void
303214455Srpaulowarning(const char *fmt, ...)
304214455Srpaulo{
305214455Srpaulo	va_list ap;
306214455Srpaulo
307214455Srpaulo	(void)fprintf(stderr, "%s: WARNING: ", program_name);
308214455Srpaulo	va_start(ap, fmt);
309214455Srpaulo	(void)vfprintf(stderr, fmt, ap);
310214455Srpaulo	va_end(ap);
311214455Srpaulo	if (*fmt) {
312214455Srpaulo		fmt += strlen(fmt);
313214455Srpaulo		if (fmt[-1] != '\n')
314214455Srpaulo			(void)fputc('\n', stderr);
315214455Srpaulo	}
316214455Srpaulo}
317214455Srpaulo
318214455Srpaulo/*
319214455Srpaulo * Copy arg vector into a new buffer, concatenating arguments with spaces.
320214455Srpaulo */
321214455Srpaulostatic char *
322214455Srpaulocopy_argv(register char **argv)
323214455Srpaulo{
324214455Srpaulo	register char **p;
325214455Srpaulo	register u_int len = 0;
326214455Srpaulo	char *buf;
327214455Srpaulo	char *src, *dst;
328214455Srpaulo
329214455Srpaulo	p = argv;
330214455Srpaulo	if (*p == 0)
331214455Srpaulo		return 0;
332214455Srpaulo
333214455Srpaulo	while (*p)
334214455Srpaulo		len += strlen(*p++) + 1;
335214455Srpaulo
336214455Srpaulo	buf = (char *)malloc(len);
337214455Srpaulo	if (buf == NULL)
338214455Srpaulo		error("copy_argv: malloc");
339214455Srpaulo
340214455Srpaulo	p = argv;
341214455Srpaulo	dst = buf;
342214455Srpaulo	while ((src = *p++) != NULL) {
343214455Srpaulo		while ((*dst++ = *src++) != '\0')
344214455Srpaulo			;
345214455Srpaulo		dst[-1] = ' ';
346214455Srpaulo	}
347214455Srpaulo	dst[-1] = '\0';
348214455Srpaulo
349214455Srpaulo	return buf;
350214455Srpaulo}
351