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