1/*
2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22#include "varattrs.h"
23
24#ifndef lint
25static const char copyright[] _U_ =
26    "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
27The Regents of the University of California.  All rights reserved.\n";
28#endif
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <stdarg.h>
34#include <limits.h>
35#ifdef _WIN32
36  #include "getopt.h"
37#else
38  #include <unistd.h>
39#endif
40#include <errno.h>
41#ifndef _WIN32
42  #include <signal.h>
43#endif
44#include <sys/types.h>
45
46#include <pcap.h>
47
48#include "pcap/funcattrs.h"
49
50#ifdef _WIN32
51  #include "portability.h"
52#endif
53
54static char *program_name;
55
56/* Forwards */
57static void countme(u_char *, const struct pcap_pkthdr *, const u_char *);
58static void PCAP_NORETURN usage(void);
59static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2);
60static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2);
61static char *copy_argv(char **);
62
63static pcap_t *pd;
64#ifndef _WIN32
65static int breaksigint = 0;
66#endif
67
68#ifndef _WIN32
69static void
70sigint_handler(int signum _U_)
71{
72	if (breaksigint)
73		pcap_breakloop(pd);
74}
75#endif
76
77#ifdef _WIN32
78/*
79 * We don't have UN*X-style signals, so we don't have anything to test.
80 */
81#define B_OPTION	""
82#define R_OPTION	""
83#define S_OPTION	""
84#else
85/*
86 * We do have UN*X-style signals (we assume that "not Windows" means "UN*X").
87 */
88#define B_OPTION	"b"
89#define R_OPTION	"r"
90#define S_OPTION	"s"
91#endif
92
93#define COMMAND_OPTIONS	B_OPTION "i:mn" R_OPTION S_OPTION "t:"
94#define USAGE_OPTIONS	"-" B_OPTION "mn" R_OPTION S_OPTION
95
96int
97main(int argc, char **argv)
98{
99	register int op;
100	register char *cp, *cmdbuf, *device;
101	long longarg;
102	char *p;
103	int timeout = 1000;
104	int immediate = 0;
105	int nonblock = 0;
106#ifndef _WIN32
107	int sigrestart = 0;
108	int catchsigint = 0;
109#endif
110	pcap_if_t *devlist;
111	bpf_u_int32 localnet, netmask;
112	struct bpf_program fcode;
113	char ebuf[PCAP_ERRBUF_SIZE];
114	int status;
115	int packet_count;
116
117	device = NULL;
118	if ((cp = strrchr(argv[0], '/')) != NULL)
119		program_name = cp + 1;
120	else
121		program_name = argv[0];
122
123	opterr = 0;
124	while ((op = getopt(argc, argv, COMMAND_OPTIONS)) != -1) {
125		switch (op) {
126
127#ifndef _WIN32
128		case 'b':
129			breaksigint = 1;
130			break;
131#endif
132
133		case 'i':
134			device = optarg;
135			break;
136
137		case 'm':
138			immediate = 1;
139			break;
140
141		case 'n':
142			nonblock = 1;
143			break;
144
145#ifndef _WIN32
146		case 'r':
147			sigrestart = 1;
148			break;
149
150		case 's':
151			catchsigint = 1;
152			break;
153#endif
154
155		case 't':
156			longarg = strtol(optarg, &p, 10);
157			if (p == optarg || *p != '\0') {
158				error("Timeout value \"%s\" is not a number",
159				    optarg);
160				/* NOTREACHED */
161			}
162			if (longarg < 0) {
163				error("Timeout value %ld is negative", longarg);
164				/* NOTREACHED */
165			}
166			if (longarg > INT_MAX) {
167				error("Timeout value %ld is too large (> %d)",
168				    longarg, INT_MAX);
169				/* NOTREACHED */
170			}
171			timeout = (int)longarg;
172			break;
173
174		default:
175			usage();
176			/* NOTREACHED */
177		}
178	}
179
180	if (device == NULL) {
181		if (pcap_findalldevs(&devlist, ebuf) == -1)
182			error("%s", ebuf);
183		if (devlist == NULL)
184			error("no interfaces available for capture");
185		device = strdup(devlist->name);
186		pcap_freealldevs(devlist);
187	}
188	*ebuf = '\0';
189
190#ifndef _WIN32
191	/*
192	 * If we were told to catch SIGINT, do so.
193	 */
194	if (catchsigint) {
195		struct sigaction action;
196
197		action.sa_handler = sigint_handler;
198		sigemptyset(&action.sa_mask);
199
200		/*
201		 * Should SIGINT interrupt, or restart, system calls?
202		 */
203		action.sa_flags = sigrestart ? SA_RESTART : 0;
204
205		if (sigaction(SIGINT, &action, NULL) == -1)
206			error("Can't catch SIGINT: %s\n",
207			    strerror(errno));
208	}
209#endif
210
211	pd = pcap_create(device, ebuf);
212	if (pd == NULL)
213		error("%s", ebuf);
214	status = pcap_set_snaplen(pd, 65535);
215	if (status != 0)
216		error("%s: pcap_set_snaplen failed: %s",
217			    device, pcap_statustostr(status));
218	if (immediate) {
219		status = pcap_set_immediate_mode(pd, 1);
220		if (status != 0)
221			error("%s: pcap_set_immediate_mode failed: %s",
222			    device, pcap_statustostr(status));
223	}
224	status = pcap_set_timeout(pd, timeout);
225	if (status != 0)
226		error("%s: pcap_set_timeout failed: %s",
227		    device, pcap_statustostr(status));
228	status = pcap_activate(pd);
229	if (status < 0) {
230		/*
231		 * pcap_activate() failed.
232		 */
233		error("%s: %s\n(%s)", device,
234		    pcap_statustostr(status), pcap_geterr(pd));
235	} else if (status > 0) {
236		/*
237		 * pcap_activate() succeeded, but it's warning us
238		 * of a problem it had.
239		 */
240		warning("%s: %s\n(%s)", device,
241		    pcap_statustostr(status), pcap_geterr(pd));
242	}
243	if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
244		localnet = 0;
245		netmask = 0;
246		warning("%s", ebuf);
247	}
248	cmdbuf = copy_argv(&argv[optind]);
249
250	if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
251		error("%s", pcap_geterr(pd));
252
253	if (pcap_setfilter(pd, &fcode) < 0)
254		error("%s", pcap_geterr(pd));
255	if (pcap_setnonblock(pd, nonblock, ebuf) == -1)
256		error("pcap_setnonblock failed: %s", ebuf);
257	printf("Listening on %s\n", device);
258	for (;;) {
259		packet_count = 0;
260		status = pcap_dispatch(pd, -1, countme,
261		    (u_char *)&packet_count);
262		if (status < 0)
263			break;
264		if (status != 0) {
265			printf("%d packets seen, %d packets counted after pcap_dispatch returns\n",
266			    status, packet_count);
267			struct pcap_stat ps;
268			pcap_stats(pd, &ps);
269			printf("%d ps_recv, %d ps_drop, %d ps_ifdrop\n",
270			    ps.ps_recv, ps.ps_drop, ps.ps_ifdrop);
271		}
272	}
273	if (status == -2) {
274		/*
275		 * We got interrupted, so perhaps we didn't
276		 * manage to finish a line we were printing.
277		 * Print an extra newline, just in case.
278		 */
279		putchar('\n');
280		printf("Broken out of loop from SIGINT handler\n");
281	}
282	(void)fflush(stdout);
283	if (status == -1) {
284		/*
285		 * Error.  Report it.
286		 */
287		(void)fprintf(stderr, "%s: pcap_dispatch: %s\n",
288		    program_name, pcap_geterr(pd));
289	}
290	pcap_close(pd);
291	pcap_freecode(&fcode);
292	free(cmdbuf);
293	exit(status == -1 ? 1 : 0);
294}
295
296static void
297countme(u_char *user, const struct pcap_pkthdr *h _U_, const u_char *sp _U_)
298{
299	int *counterp = (int *)user;
300
301	(*counterp)++;
302}
303
304static void
305usage(void)
306{
307	(void)fprintf(stderr, "Usage: %s [ " USAGE_OPTIONS " ] [ -i interface ] [ -t timeout] [expression]\n",
308	    program_name);
309	exit(1);
310}
311
312/* VARARGS */
313static void
314error(const char *fmt, ...)
315{
316	va_list ap;
317
318	(void)fprintf(stderr, "%s: ", program_name);
319	va_start(ap, fmt);
320	(void)vfprintf(stderr, fmt, ap);
321	va_end(ap);
322	if (*fmt) {
323		fmt += strlen(fmt);
324		if (fmt[-1] != '\n')
325			(void)fputc('\n', stderr);
326	}
327	exit(1);
328	/* NOTREACHED */
329}
330
331/* VARARGS */
332static void
333warning(const char *fmt, ...)
334{
335	va_list ap;
336
337	(void)fprintf(stderr, "%s: WARNING: ", program_name);
338	va_start(ap, fmt);
339	(void)vfprintf(stderr, fmt, ap);
340	va_end(ap);
341	if (*fmt) {
342		fmt += strlen(fmt);
343		if (fmt[-1] != '\n')
344			(void)fputc('\n', stderr);
345	}
346}
347
348/*
349 * Copy arg vector into a new buffer, concatenating arguments with spaces.
350 */
351static char *
352copy_argv(register char **argv)
353{
354	register char **p;
355	register size_t len = 0;
356	char *buf;
357	char *src, *dst;
358
359	p = argv;
360	if (*p == 0)
361		return 0;
362
363	while (*p)
364		len += strlen(*p++) + 1;
365
366	buf = (char *)malloc(len);
367	if (buf == NULL)
368		error("copy_argv: malloc");
369
370	p = argv;
371	dst = buf;
372	while ((src = *p++) != NULL) {
373		while ((*dst++ = *src++) != '\0')
374			;
375		dst[-1] = ' ';
376	}
377	dst[-1] = '\0';
378
379	return buf;
380}
381