Home | History | Annotate | Download | only in tests
      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
    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
    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
    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
    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
    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 *
    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