• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef lint
23 static const char copyright[] _U_ =
24     "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
25 The Regents of the University of California.  All rights reserved.\n";
26 #endif
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdarg.h>
32 #include <limits.h>
33 #ifdef _WIN32
34 #include "getopt.h"
35 #else
36 #include <unistd.h>
37 #endif
38 #include <errno.h>
39 #include <sys/types.h>
40 
41 #include <pcap.h>
42 
43 static char *program_name;
44 
45 /*
46  * This was introduced by Clang:
47  *
48  *     http://clang.llvm.org/docs/LanguageExtensions.html#has-attribute
49  *
50  * in some version (which version?); it has been picked up by GCC 5.0.
51  */
52 #ifndef __has_attribute
53   /*
54    * It's a macro, so you can check whether it's defined to check
55    * whether it's supported.
56    *
57    * If it's not, define it to always return 0, so that we move on to
58    * the fallback checks.
59    */
60   #define __has_attribute(x) 0
61 #endif
62 
63 #if __has_attribute(noreturn) \
64     || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 205)) \
65     || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) \
66     || (defined(__xlC__) && __xlC__ >= 0x0A01) \
67     || (defined(__HP_aCC) && __HP_aCC >= 61000)
68   /*
69    * Compiler with support for it, or GCC 2.5 and later, or Solaris Studio 12
70    * (Sun C 5.9) and later, or IBM XL C 10.1 and later (do any earlier
71    * versions of XL C support this?), or HP aCC A.06.10 and later.
72    */
73   #define PCAP_NORETURN __attribute((noreturn))
74 #elif defined( _MSC_VER )
75   #define PCAP_NORETURN __declspec(noreturn)
76 #else
77   #define PCAP_NORETURN
78 #endif
79 
80 #if __has_attribute(__format__) \
81     || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 203)) \
82     || (defined(__xlC__) && __xlC__ >= 0x0A01) \
83     || (defined(__HP_aCC) && __HP_aCC >= 61000)
84   /*
85    * Compiler with support for it, or GCC 2.3 and later, or IBM XL C 10.1
86    * and later (do any earlier versions of XL C support this?),
87    * or HP aCC A.06.10 and later.
88    */
89   #define PCAP_PRINTFLIKE(x,y) __attribute__((__format__(__printf__,x,y)))
90 #else
91   #define PCAP_PRINTFLIKE(x,y)
92 #endif
93 
94 /* Forwards */
95 static void countme(u_char *, const struct pcap_pkthdr *, const u_char *);
96 static void PCAP_NORETURN usage(void);
97 static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2);
98 static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2);
99 static char *copy_argv(char **);
100 
101 static pcap_t *pd;
102 
103 int
main(int argc,char ** argv)104 main(int argc, char **argv)
105 {
106 	register int op;
107 	register char *cp, *cmdbuf, *device;
108 	long longarg;
109 	char *p;
110 	int timeout = 1000;
111 	int immediate = 0;
112 	int nonblock = 0;
113 	bpf_u_int32 localnet, netmask;
114 	struct bpf_program fcode;
115 	char ebuf[PCAP_ERRBUF_SIZE];
116 	int status;
117 	int packet_count;
118 
119 	device = NULL;
120 	if ((cp = strrchr(argv[0], '/')) != NULL)
121 		program_name = cp + 1;
122 	else
123 		program_name = argv[0];
124 
125 	opterr = 0;
126 	while ((op = getopt(argc, argv, "i:mnt:")) != -1) {
127 		switch (op) {
128 
129 		case 'i':
130 			device = optarg;
131 			break;
132 
133 		case 'm':
134 			immediate = 1;
135 			break;
136 
137 		case 'n':
138 			nonblock = 1;
139 			break;
140 
141 		case 't':
142 			longarg = strtol(optarg, &p, 10);
143 			if (p == optarg || *p != '\0') {
144 				error("Timeout value \"%s\" is not a number",
145 				    optarg);
146 				/* NOTREACHED */
147 			}
148 			if (longarg < 0) {
149 				error("Timeout value %ld is negative", longarg);
150 				/* NOTREACHED */
151 			}
152 			if (longarg > INT_MAX) {
153 				error("Timeout value %ld is too large (> %d)",
154 				    longarg, INT_MAX);
155 				/* NOTREACHED */
156 			}
157 			timeout = (int)longarg;
158 			break;
159 
160 		default:
161 			usage();
162 			/* NOTREACHED */
163 		}
164 	}
165 
166 	if (device == NULL) {
167 		device = pcap_lookupdev(ebuf);
168 		if (device == NULL)
169 			error("%s", ebuf);
170 	}
171 	*ebuf = '\0';
172 	pd = pcap_create(device, ebuf);
173 	if (pd == NULL)
174 		error("%s", ebuf);
175 	status = pcap_set_snaplen(pd, 65535);
176 	if (status != 0)
177 		error("%s: pcap_set_snaplen failed: %s",
178 			    device, pcap_statustostr(status));
179 	if (immediate) {
180 		status = pcap_set_immediate_mode(pd, 1);
181 		if (status != 0)
182 			error("%s: pcap_set_immediate_mode failed: %s",
183 			    device, pcap_statustostr(status));
184 	}
185 	status = pcap_set_timeout(pd, timeout);
186 	if (status != 0)
187 		error("%s: pcap_set_timeout failed: %s",
188 		    device, pcap_statustostr(status));
189 	status = pcap_activate(pd);
190 	if (status < 0) {
191 		/*
192 		 * pcap_activate() failed.
193 		 */
194 		error("%s: %s\n(%s)", device,
195 		    pcap_statustostr(status), pcap_geterr(pd));
196 	} else if (status > 0) {
197 		/*
198 		 * pcap_activate() succeeded, but it's warning us
199 		 * of a problem it had.
200 		 */
201 		warning("%s: %s\n(%s)", device,
202 		    pcap_statustostr(status), pcap_geterr(pd));
203 	}
204 	if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
205 		localnet = 0;
206 		netmask = 0;
207 		warning("%s", ebuf);
208 	}
209 	cmdbuf = copy_argv(&argv[optind]);
210 
211 	if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
212 		error("%s", pcap_geterr(pd));
213 
214 	if (pcap_setfilter(pd, &fcode) < 0)
215 		error("%s", pcap_geterr(pd));
216 	if (pcap_setnonblock(pd, nonblock, ebuf) == -1)
217 		error("pcap_setnonblock failed: %s", ebuf);
218 	printf("Listening on %s\n", device);
219 	for (;;) {
220 		packet_count = 0;
221 		status = pcap_dispatch(pd, -1, countme,
222 		    (u_char *)&packet_count);
223 		if (status < 0)
224 			break;
225 		if (status != 0) {
226 			printf("%d packets seen, %d packets counted after pcap_dispatch returns\n",
227 			    status, packet_count);
228 		}
229 	}
230 	if (status == -2) {
231 		/*
232 		 * We got interrupted, so perhaps we didn't
233 		 * manage to finish a line we were printing.
234 		 * Print an extra newline, just in case.
235 		 */
236 		putchar('\n');
237 	}
238 	(void)fflush(stdout);
239 	if (status == -1) {
240 		/*
241 		 * Error.  Report it.
242 		 */
243 		(void)fprintf(stderr, "%s: pcap_loop: %s\n",
244 		    program_name, pcap_geterr(pd));
245 	}
246 	pcap_close(pd);
247 	exit(status == -1 ? 1 : 0);
248 }
249 
250 static void
countme(u_char * user,const struct pcap_pkthdr * h,const u_char * sp)251 countme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
252 {
253 	int *counterp = (int *)user;
254 
255 	(*counterp)++;
256 }
257 
258 static void
usage(void)259 usage(void)
260 {
261 	(void)fprintf(stderr, "Usage: %s [ -mn ] [ -i interface ] [ -t timeout] [expression]\n",
262 	    program_name);
263 	exit(1);
264 }
265 
266 /* VARARGS */
267 static void
error(const char * fmt,...)268 error(const char *fmt, ...)
269 {
270 	va_list ap;
271 
272 	(void)fprintf(stderr, "%s: ", program_name);
273 	va_start(ap, fmt);
274 	(void)vfprintf(stderr, fmt, ap);
275 	va_end(ap);
276 	if (*fmt) {
277 		fmt += strlen(fmt);
278 		if (fmt[-1] != '\n')
279 			(void)fputc('\n', stderr);
280 	}
281 	exit(1);
282 	/* NOTREACHED */
283 }
284 
285 /* VARARGS */
286 static void
warning(const char * fmt,...)287 warning(const char *fmt, ...)
288 {
289 	va_list ap;
290 
291 	(void)fprintf(stderr, "%s: WARNING: ", program_name);
292 	va_start(ap, fmt);
293 	(void)vfprintf(stderr, fmt, ap);
294 	va_end(ap);
295 	if (*fmt) {
296 		fmt += strlen(fmt);
297 		if (fmt[-1] != '\n')
298 			(void)fputc('\n', stderr);
299 	}
300 }
301 
302 /*
303  * Copy arg vector into a new buffer, concatenating arguments with spaces.
304  */
305 static char *
copy_argv(register char ** argv)306 copy_argv(register char **argv)
307 {
308 	register char **p;
309 	register u_int len = 0;
310 	char *buf;
311 	char *src, *dst;
312 
313 	p = argv;
314 	if (*p == 0)
315 		return 0;
316 
317 	while (*p)
318 		len += strlen(*p++) + 1;
319 
320 	buf = (char *)malloc(len);
321 	if (buf == NULL)
322 		error("copy_argv: malloc");
323 
324 	p = argv;
325 	dst = buf;
326 	while ((src = *p++) != NULL) {
327 		while ((*dst++ = *src++) != '\0')
328 			;
329 		dst[-1] = ' ';
330 	}
331 	dst[-1] = '\0';
332 
333 	return buf;
334 }
335