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 25 static const char copyright[] _U_ = 26 "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ 27 The 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 54 static char *program_name; 55 56 /* Forwards */ 57 static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); 58 static void PCAP_NORETURN usage(void); 59 static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); 60 static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); 61 static char *copy_argv(char **); 62 63 static pcap_t *pd; 64 #ifndef _WIN32 65 static int breaksigint = 0; 66 #endif 67 68 #ifndef _WIN32 69 static void 70 sigint_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 96 int 97 main(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 296 static void 297 countme(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 304 static void 305 usage(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 */ 313 static void 314 error(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 */ 332 static void 333 warning(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 */ 351 static char * 352 copy_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