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