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 /* 23 * This doesn't actually test libpcap itself; it tests whether 24 * valgrind properly handles the APIs libpcap uses. If it doesn't, 25 * we end up getting patches submitted to "fix" references that 26 * valgrind claims are being made to uninitialized data, when, in 27 * fact, the OS isn't making any such references - or we get 28 * valgrind *not* detecting *actual* incorrect references. 29 * 30 * Both BPF and Linux socket filters aren't handled correctly 31 * by some versions of valgrind. See valgrind bug 318203 for 32 * Linux: 33 * 34 * https://bugs.kde.org/show_bug.cgi?id=318203 35 * 36 * and valgrind bug 312989 for OS X: 37 * 38 * https://bugs.kde.org/show_bug.cgi?id=312989 39 * 40 * The fixes for both of those are checked into the official valgrind 41 * repository. 42 * 43 * The unofficial FreeBSD port has similar issues to the official OS X 44 * port, for similar reasons. 45 */ 46 #ifndef lint 47 static const char copyright[] _U_ = 48 "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ 49 The Regents of the University of California. All rights reserved.\n"; 50 #endif 51 52 #ifdef HAVE_CONFIG_H 53 #include "config.h" 54 #endif 55 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <stdarg.h> 60 #include <unistd.h> 61 #include <fcntl.h> 62 #include <errno.h> 63 #include <arpa/inet.h> 64 #include <sys/types.h> 65 #include <sys/stat.h> 66 67 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) 68 /* BSD-flavored OS - use BPF */ 69 #define USE_BPF 70 #elif defined(linux) 71 /* Linux - use socket filters */ 72 #define USE_SOCKET_FILTERS 73 #else 74 #error "Unknown platform or platform that doesn't support Valgrind" 75 #endif 76 77 #if defined(USE_BPF) 78 79 #include <sys/ioctl.h> 80 #include <net/bpf.h> 81 82 /* 83 * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the 84 * native OS version, as we're going to be doing our own ioctls to 85 * make sure that, in the uninitialized-data tests, the filters aren't 86 * checked by libpcap before being handed to BPF. 87 */ 88 #define PCAP_DONT_INCLUDE_PCAP_BPF_H 89 90 #elif defined(USE_SOCKET_FILTERS) 91 92 #include <sys/socket.h> 93 #include <linux/types.h> 94 #include <linux/filter.h> 95 96 #endif 97 98 #include <pcap.h> 99 100 static char *program_name; 101 102 /* 103 * This was introduced by Clang: 104 * 105 * http://clang.llvm.org/docs/LanguageExtensions.html#has-attribute 106 * 107 * in some version (which version?); it has been picked up by GCC 5.0. 108 */ 109 #ifndef __has_attribute 110 /* 111 * It's a macro, so you can check whether it's defined to check 112 * whether it's supported. 113 * 114 * If it's not, define it to always return 0, so that we move on to 115 * the fallback checks. 116 */ 117 #define __has_attribute(x) 0 118 #endif 119 120 #if __has_attribute(noreturn) \ 121 || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 205)) \ 122 || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) \ 123 || (defined(__xlC__) && __xlC__ >= 0x0A01) \ 124 || (defined(__HP_aCC) && __HP_aCC >= 61000) 125 /* 126 * Compiler with support for it, or GCC 2.5 and later, or Solaris Studio 12 127 * (Sun C 5.9) and later, or IBM XL C 10.1 and later (do any earlier 128 * versions of XL C support this?), or HP aCC A.06.10 and later. 129 */ 130 #define PCAP_NORETURN __attribute((noreturn)) 131 #elif defined( _MSC_VER ) 132 #define PCAP_NORETURN __declspec(noreturn) 133 #else 134 #define PCAP_NORETURN 135 #endif 136 137 #if __has_attribute(__format__) \ 138 || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 203)) \ 139 || (defined(__xlC__) && __xlC__ >= 0x0A01) \ 140 || (defined(__HP_aCC) && __HP_aCC >= 61000) 141 /* 142 * Compiler with support for it, or GCC 2.3 and later, or IBM XL C 10.1 143 * and later (do any earlier versions of XL C support this?), 144 * or HP aCC A.06.10 and later. 145 */ 146 #define PCAP_PRINTFLIKE(x,y) __attribute__((__format__(__printf__,x,y))) 147 #else 148 #define PCAP_PRINTFLIKE(x,y) 149 #endif 150 151 /* Forwards */ 152 static void PCAP_NORETURN usage(void); 153 static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); 154 static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); 155 156 /* 157 * On Windows, we need to open the file in binary mode, so that 158 * we get all the bytes specified by the size we get from "fstat()". 159 * On UNIX, that's not necessary. O_BINARY is defined on Windows; 160 * we define it as 0 if it's not defined, so it does nothing. 161 */ 162 #ifndef O_BINARY 163 #define O_BINARY 0 164 #endif 165 166 static char * 167 read_infile(char *fname) 168 { 169 register int i, fd, cc; 170 register char *cp; 171 struct stat buf; 172 173 fd = open(fname, O_RDONLY|O_BINARY); 174 if (fd < 0) 175 error("can't open %s: %s", fname, pcap_strerror(errno)); 176 177 if (fstat(fd, &buf) < 0) 178 error("can't stat %s: %s", fname, pcap_strerror(errno)); 179 180 cp = malloc((u_int)buf.st_size + 1); 181 if (cp == NULL) 182 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, 183 fname, pcap_strerror(errno)); 184 cc = read(fd, cp, (u_int)buf.st_size); 185 if (cc < 0) 186 error("read %s: %s", fname, pcap_strerror(errno)); 187 if (cc != buf.st_size) 188 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); 189 190 close(fd); 191 /* replace "# comment" with spaces */ 192 for (i = 0; i < cc; i++) { 193 if (cp[i] == '#') 194 while (i < cc && cp[i] != '\n') 195 cp[i++] = ' '; 196 } 197 cp[cc] = '\0'; 198 return (cp); 199 } 200 201 /* VARARGS */ 202 static void 203 error(const char *fmt, ...) 204 { 205 va_list ap; 206 207 (void)fprintf(stderr, "%s: ", program_name); 208 va_start(ap, fmt); 209 (void)vfprintf(stderr, fmt, ap); 210 va_end(ap); 211 if (*fmt) { 212 fmt += strlen(fmt); 213 if (fmt[-1] != '\n') 214 (void)fputc('\n', stderr); 215 } 216 exit(1); 217 /* NOTREACHED */ 218 } 219 220 /* VARARGS */ 221 static void 222 warning(const char *fmt, ...) 223 { 224 va_list ap; 225 226 (void)fprintf(stderr, "%s: WARNING: ", program_name); 227 va_start(ap, fmt); 228 (void)vfprintf(stderr, fmt, ap); 229 va_end(ap); 230 if (*fmt) { 231 fmt += strlen(fmt); 232 if (fmt[-1] != '\n') 233 (void)fputc('\n', stderr); 234 } 235 } 236 237 /* 238 * Copy arg vector into a new buffer, concatenating arguments with spaces. 239 */ 240 static char * 241 copy_argv(register char **argv) 242 { 243 register char **p; 244 register u_int len = 0; 245 char *buf; 246 char *src, *dst; 247 248 p = argv; 249 if (*p == 0) 250 return 0; 251 252 while (*p) 253 len += strlen(*p++) + 1; 254 255 buf = (char *)malloc(len); 256 if (buf == NULL) 257 error("copy_argv: malloc"); 258 259 p = argv; 260 dst = buf; 261 while ((src = *p++) != NULL) { 262 while ((*dst++ = *src++) != '\0') 263 ; 264 dst[-1] = ' '; 265 } 266 dst[-1] = '\0'; 267 268 return buf; 269 } 270 271 #define INSN_COUNT 17 272 273 int 274 main(int argc, char **argv) 275 { 276 char *cp, *device; 277 int op; 278 int dorfmon, useactivate; 279 char ebuf[PCAP_ERRBUF_SIZE]; 280 char *infile; 281 char *cmdbuf; 282 pcap_t *pd; 283 int status = 0; 284 int pcap_fd; 285 #if defined(USE_BPF) 286 struct bpf_program bad_fcode; 287 struct bpf_insn uninitialized[INSN_COUNT]; 288 #elif defined(USE_SOCKET_FILTERS) 289 struct sock_fprog bad_fcode; 290 struct sock_filter uninitialized[INSN_COUNT]; 291 #endif 292 struct bpf_program fcode; 293 294 device = NULL; 295 dorfmon = 0; 296 useactivate = 0; 297 infile = NULL; 298 299 if ((cp = strrchr(argv[0], '/')) != NULL) 300 program_name = cp + 1; 301 else 302 program_name = argv[0]; 303 304 opterr = 0; 305 while ((op = getopt(argc, argv, "aF:i:I")) != -1) { 306 switch (op) { 307 308 case 'a': 309 useactivate = 1; 310 break; 311 312 case 'F': 313 infile = optarg; 314 break; 315 316 case 'i': 317 device = optarg; 318 break; 319 320 case 'I': 321 dorfmon = 1; 322 useactivate = 1; /* required for rfmon */ 323 break; 324 325 default: 326 usage(); 327 /* NOTREACHED */ 328 } 329 } 330 331 if (device == NULL) { 332 /* 333 * No interface specified; get whatever pcap_lookupdev() 334 * finds. 335 */ 336 device = pcap_lookupdev(ebuf); 337 if (device == NULL) { 338 error("couldn't find interface to use: %s", 339 ebuf); 340 } 341 } 342 343 if (infile != NULL) { 344 /* 345 * Filter specified with "-F" and a file containing 346 * a filter. 347 */ 348 cmdbuf = read_infile(infile); 349 } else { 350 if (optind < argc) { 351 /* 352 * Filter specified with arguments on the 353 * command line. 354 */ 355 cmdbuf = copy_argv(&argv[optind+1]); 356 } else { 357 /* 358 * No filter specified; use an empty string, which 359 * compiles to an "accept all" filter. 360 */ 361 cmdbuf = ""; 362 } 363 } 364 365 if (useactivate) { 366 pd = pcap_create(device, ebuf); 367 if (pd == NULL) 368 error("%s: pcap_create() failed: %s", device, ebuf); 369 status = pcap_set_snaplen(pd, 65535); 370 if (status != 0) 371 error("%s: pcap_set_snaplen failed: %s", 372 device, pcap_statustostr(status)); 373 status = pcap_set_promisc(pd, 1); 374 if (status != 0) 375 error("%s: pcap_set_promisc failed: %s", 376 device, pcap_statustostr(status)); 377 if (dorfmon) { 378 status = pcap_set_rfmon(pd, 1); 379 if (status != 0) 380 error("%s: pcap_set_rfmon failed: %s", 381 device, pcap_statustostr(status)); 382 } 383 status = pcap_set_timeout(pd, 1000); 384 if (status != 0) 385 error("%s: pcap_set_timeout failed: %s", 386 device, pcap_statustostr(status)); 387 status = pcap_activate(pd); 388 if (status < 0) { 389 /* 390 * pcap_activate() failed. 391 */ 392 error("%s: %s\n(%s)", device, 393 pcap_statustostr(status), pcap_geterr(pd)); 394 } else if (status > 0) { 395 /* 396 * pcap_activate() succeeded, but it's warning us 397 * of a problem it had. 398 */ 399 warning("%s: %s\n(%s)", device, 400 pcap_statustostr(status), pcap_geterr(pd)); 401 } 402 } else { 403 *ebuf = '\0'; 404 pd = pcap_open_live(device, 65535, 1, 1000, ebuf); 405 if (pd == NULL) 406 error("%s", ebuf); 407 else if (*ebuf) 408 warning("%s", ebuf); 409 } 410 411 pcap_fd = pcap_fileno(pd); 412 413 /* 414 * Try setting a filter with an uninitialized bpf_program 415 * structure. This should cause valgrind to report a 416 * problem. 417 * 418 * We don't check for errors, because it could get an 419 * error due to a bad pointer or count. 420 */ 421 #if defined(USE_BPF) 422 ioctl(pcap_fd, BIOCSETF, &bad_fcode); 423 #elif defined(USE_SOCKET_FILTERS) 424 setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, 425 sizeof(bad_fcode)); 426 #endif 427 428 /* 429 * Try setting a filter with an initialized bpf_program 430 * structure that points to an uninitialized program. 431 * That should also cause valgrind to report a problem. 432 * 433 * We don't check for errors, because it could get an 434 * error due to a bad pointer or count. 435 */ 436 #if defined(USE_BPF) 437 bad_fcode.bf_len = INSN_COUNT; 438 bad_fcode.bf_insns = uninitialized; 439 ioctl(pcap_fd, BIOCSETF, &bad_fcode); 440 #elif defined(USE_SOCKET_FILTERS) 441 bad_fcode.len = INSN_COUNT; 442 bad_fcode.filter = uninitialized; 443 setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, 444 sizeof(bad_fcode)); 445 #endif 446 447 /* 448 * Now compile a filter and set the filter with that. 449 * That should *not* cause valgrind to report a 450 * problem. 451 */ 452 if (pcap_compile(pd, &fcode, cmdbuf, 1, 0) < 0) 453 error("can't compile filter: %s", pcap_geterr(pd)); 454 if (pcap_setfilter(pd, &fcode) < 0) 455 error("can't set filter: %s", pcap_geterr(pd)); 456 457 pcap_close(pd); 458 exit(status < 0 ? 1 : 0); 459 } 460 461 static void 462 usage(void) 463 { 464 (void)fprintf(stderr, "%s, with %s\n", program_name, 465 pcap_lib_version()); 466 (void)fprintf(stderr, 467 "Usage: %s [-aI] [ -F file ] [ -I interface ] [ expression ]\n", 468 program_name); 469 exit(1); 470 } 471