1 /*	$NetBSD: capturetest.c,v 1.2 2014/11/19 19:33:31 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
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/cdefs.h>
25 __RCSID("$NetBSD: capturetest.c,v 1.2 2014/11/19 19:33:31 christos Exp $");
26 
27 #ifndef lint
28 static const char copyright[] =
29     "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
30 The Regents of the University of California.  All rights reserved.\n";
31 #endif
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdarg.h>
37 #include <limits.h>
38 #include <unistd.h>
39 #include <errno.h>
40 #include <sys/types.h>
41 #include <sys/select.h>
42 #include <poll.h>
43 
44 #include <pcap.h>
45 
46 static char *program_name;
47 
48 /* Forwards */
49 static void countme(u_char *, const struct pcap_pkthdr *, const u_char *);
50 static void usage(void) __attribute__((noreturn));
51 static void error(const char *, ...);
52 static void warning(const char *, ...);
53 static char *copy_argv(char **);
54 
55 static pcap_t *pd;
56 
57 extern int optind;
58 extern int opterr;
59 extern char *optarg;
60 
61 int
main(int argc,char ** argv)62 main(int argc, char **argv)
63 {
64 	register int op;
65 	register char *cp, *cmdbuf, *device;
66 	long longarg;
67 	char *p;
68 	int timeout = 1000;
69 	int immediate = 0;
70 	int nonblock = 0;
71 	bpf_u_int32 localnet, netmask;
72 	struct bpf_program fcode;
73 	char ebuf[PCAP_ERRBUF_SIZE];
74 	int status;
75 	int packet_count;
76 
77 	device = NULL;
78 	if ((cp = strrchr(argv[0], '/')) != NULL)
79 		program_name = cp + 1;
80 	else
81 		program_name = argv[0];
82 
83 	opterr = 0;
84 	while ((op = getopt(argc, argv, "i:mnt:")) != -1) {
85 		switch (op) {
86 
87 		case 'i':
88 			device = optarg;
89 			break;
90 
91 		case 'm':
92 			immediate = 1;
93 			break;
94 
95 		case 'n':
96 			nonblock = 1;
97 			break;
98 
99 		case 't':
100 			longarg = strtol(optarg, &p, 10);
101 			if (p == optarg || *p != '\0') {
102 				error("Timeout value \"%s\" is not a number",
103 				    optarg);
104 				/* NOTREACHED */
105 			}
106 			if (longarg < 0) {
107 				error("Timeout value %ld is negative", longarg);
108 				/* NOTREACHED */
109 			}
110 			if (longarg > INT_MAX) {
111 				error("Timeout value %ld is too large (> %d)",
112 				    longarg, INT_MAX);
113 				/* NOTREACHED */
114 			}
115 			timeout = (int)longarg;
116 			break;
117 
118 		default:
119 			usage();
120 			/* NOTREACHED */
121 		}
122 	}
123 
124 	if (device == NULL) {
125 		device = pcap_lookupdev(ebuf);
126 		if (device == NULL)
127 			error("%s", ebuf);
128 	}
129 	*ebuf = '\0';
130 	pd = pcap_create(device, ebuf);
131 	if (pd == NULL)
132 		error("%s", ebuf);
133 	status = pcap_set_snaplen(pd, 65535);
134 	if (status != 0)
135 		error("%s: pcap_set_snaplen failed: %s",
136 			    device, pcap_statustostr(status));
137 	if (immediate) {
138 		status = pcap_set_immediate_mode(pd, 1);
139 		if (status != 0)
140 			error("%s: pcap_set_immediate_mode failed: %s",
141 			    device, pcap_statustostr(status));
142 	}
143 	status = pcap_set_timeout(pd, timeout);
144 	if (status != 0)
145 		error("%s: pcap_set_timeout failed: %s",
146 		    device, pcap_statustostr(status));
147 	status = pcap_activate(pd);
148 	if (status < 0) {
149 		/*
150 		 * pcap_activate() failed.
151 		 */
152 		error("%s: %s\n(%s)", device,
153 		    pcap_statustostr(status), pcap_geterr(pd));
154 	} else if (status > 0) {
155 		/*
156 		 * pcap_activate() succeeded, but it's warning us
157 		 * of a problem it had.
158 		 */
159 		warning("%s: %s\n(%s)", device,
160 		    pcap_statustostr(status), pcap_geterr(pd));
161 	}
162 	if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
163 		localnet = 0;
164 		netmask = 0;
165 		warning("%s", ebuf);
166 	}
167 	cmdbuf = copy_argv(&argv[optind]);
168 
169 	if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
170 		error("%s", pcap_geterr(pd));
171 
172 	if (pcap_setfilter(pd, &fcode) < 0)
173 		error("%s", pcap_geterr(pd));
174 	if (pcap_setnonblock(pd, nonblock, ebuf) == -1)
175 		error("pcap_setnonblock failed: %s", ebuf);
176 	printf("Listening on %s\n", device);
177 	for (;;) {
178 		packet_count = 0;
179 		status = pcap_dispatch(pd, -1, countme,
180 		    (u_char *)&packet_count);
181 		if (status < 0)
182 			break;
183 		if (status != 0) {
184 			printf("%d packets seen, %d packets counted after pcap_dispatch returns\n",
185 			    status, packet_count);
186 		}
187 	}
188 	if (status == -2) {
189 		/*
190 		 * We got interrupted, so perhaps we didn't
191 		 * manage to finish a line we were printing.
192 		 * Print an extra newline, just in case.
193 		 */
194 		putchar('\n');
195 	}
196 	(void)fflush(stdout);
197 	if (status == -1) {
198 		/*
199 		 * Error.  Report it.
200 		 */
201 		(void)fprintf(stderr, "%s: pcap_loop: %s\n",
202 		    program_name, pcap_geterr(pd));
203 	}
204 	pcap_close(pd);
205 	exit(status == -1 ? 1 : 0);
206 }
207 
208 static void
countme(u_char * user,const struct pcap_pkthdr * h,const u_char * sp)209 countme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
210 {
211 	int *counterp = (int *)user;
212 
213 	(*counterp)++;
214 }
215 
216 static void
usage(void)217 usage(void)
218 {
219 	(void)fprintf(stderr, "Usage: %s [ -mn ] [ -i interface ] [ -t timeout] [expression]\n",
220 	    program_name);
221 	exit(1);
222 }
223 
224 /* VARARGS */
225 static void
error(const char * fmt,...)226 error(const char *fmt, ...)
227 {
228 	va_list ap;
229 
230 	(void)fprintf(stderr, "%s: ", program_name);
231 	va_start(ap, fmt);
232 	(void)vfprintf(stderr, fmt, ap);
233 	va_end(ap);
234 	if (*fmt) {
235 		fmt += strlen(fmt);
236 		if (fmt[-1] != '\n')
237 			(void)fputc('\n', stderr);
238 	}
239 	exit(1);
240 	/* NOTREACHED */
241 }
242 
243 /* VARARGS */
244 static void
warning(const char * fmt,...)245 warning(const char *fmt, ...)
246 {
247 	va_list ap;
248 
249 	(void)fprintf(stderr, "%s: WARNING: ", program_name);
250 	va_start(ap, fmt);
251 	(void)vfprintf(stderr, fmt, ap);
252 	va_end(ap);
253 	if (*fmt) {
254 		fmt += strlen(fmt);
255 		if (fmt[-1] != '\n')
256 			(void)fputc('\n', stderr);
257 	}
258 }
259 
260 /*
261  * Copy arg vector into a new buffer, concatenating arguments with spaces.
262  */
263 static char *
copy_argv(register char ** argv)264 copy_argv(register char **argv)
265 {
266 	register char **p;
267 	register u_int len = 0;
268 	char *buf;
269 	char *src, *dst;
270 
271 	p = argv;
272 	if (*p == 0)
273 		return 0;
274 
275 	while (*p)
276 		len += strlen(*p++) + 1;
277 
278 	buf = (char *)malloc(len);
279 	if (buf == NULL)
280 		error("copy_argv: malloc");
281 
282 	p = argv;
283 	dst = buf;
284 	while ((src = *p++) != NULL) {
285 		while ((*dst++ = *src++) != '\0')
286 			;
287 		dst[-1] = ' ';
288 	}
289 	dst[-1] = '\0';
290 
291 	return buf;
292 }
293