1 /* $NetBSD: valgrindtest.c,v 1.3 2015/03/31 21:39:43 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that: (1) source code distributions 9 * retain the above copyright notice and this paragraph in its entirety, (2) 10 * distributions including binary code include the above copyright notice and 11 * this paragraph in its entirety in the documentation or other materials 12 * provided with the distribution, and (3) all advertising materials mentioning 13 * features or use of this software display the following acknowledgement: 14 * ``This product includes software developed by the University of California, 15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 16 * the University nor the names of its contributors may be used to endorse 17 * or promote products derived from this software without specific prior 18 * written permission. 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 */ 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 <sys/cdefs.h> 31 __RCSID("$NetBSD: valgrindtest.c,v 1.3 2015/03/31 21:39:43 christos Exp $"); 32 33 #ifdef HAVE_CONFIG_H 34 #include "config.h" 35 #endif 36 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <stdarg.h> 41 #include <unistd.h> 42 #include <fcntl.h> 43 #include <errno.h> 44 #include <arpa/inet.h> 45 #include <sys/types.h> 46 #include <sys/stat.h> 47 48 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) 49 /* BSD-flavored OS - use BPF */ 50 #define USE_BPF 51 #elif defined(linux) 52 /* Linux - use socket filters */ 53 #define USE_SOCKET_FILTERS 54 #else 55 #error "Unknown platform or platform that doesn't support Valgrind" 56 #endif 57 58 #if defined(USE_BPF) 59 60 #include <sys/ioctl.h> 61 #include <net/bpf.h> 62 63 /* 64 * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the 65 * native OS version, as we're going to be doing our own ioctls to 66 * make sure that, in the uninitialized-data tests, the filters aren't 67 * checked by libpcap before being handed to BPF. 68 */ 69 #define PCAP_DONT_INCLUDE_PCAP_BPF_H 70 71 #elif defined(USE_SOCKET_FILTERS) 72 73 #include <sys/socket.h> 74 #include <linux/types.h> 75 #include <linux/filter.h> 76 77 #endif 78 79 #include <pcap.h> 80 #ifndef HAVE___ATTRIBUTE__ 81 #define __attribute__(x) 82 #endif 83 84 static char *program_name; 85 86 /* Forwards */ 87 static void usage(void) __attribute__((noreturn)); 88 static void error(const char *, ...) 89 __attribute__((noreturn, format (printf, 1, 2))); 90 static void warning(const char *, ...) 91 __attribute__((format (printf, 1, 2))); 92 93 extern int optind; 94 extern int opterr; 95 extern char *optarg; 96 97 /* 98 * On Windows, we need to open the file in binary mode, so that 99 * we get all the bytes specified by the size we get from "fstat()". 100 * On UNIX, that's not necessary. O_BINARY is defined on Windows; 101 * we define it as 0 if it's not defined, so it does nothing. 102 */ 103 #ifndef O_BINARY 104 #define O_BINARY 0 105 #endif 106 107 static char * 108 read_infile(char *fname) 109 { 110 register int i, fd, cc; 111 register char *cp; 112 struct stat buf; 113 114 fd = open(fname, O_RDONLY|O_BINARY); 115 if (fd < 0) 116 error("can't open %s: %s", fname, pcap_strerror(errno)); 117 118 if (fstat(fd, &buf) < 0) 119 error("can't stat %s: %s", fname, pcap_strerror(errno)); 120 121 cp = malloc((u_int)buf.st_size + 1); 122 if (cp == NULL) 123 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, 124 fname, pcap_strerror(errno)); 125 cc = read(fd, cp, (u_int)buf.st_size); 126 if (cc < 0) 127 error("read %s: %s", fname, pcap_strerror(errno)); 128 if (cc != buf.st_size) 129 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); 130 131 close(fd); 132 /* replace "# comment" with spaces */ 133 for (i = 0; i < cc; i++) { 134 if (cp[i] == '#') 135 while (i < cc && cp[i] != '\n') 136 cp[i++] = ' '; 137 } 138 cp[cc] = '\0'; 139 return (cp); 140 } 141 142 /* VARARGS */ 143 static void 144 error(const char *fmt, ...) 145 { 146 va_list ap; 147 148 (void)fprintf(stderr, "%s: ", program_name); 149 va_start(ap, fmt); 150 (void)vfprintf(stderr, fmt, ap); 151 va_end(ap); 152 if (*fmt) { 153 fmt += strlen(fmt); 154 if (fmt[-1] != '\n') 155 (void)fputc('\n', stderr); 156 } 157 exit(1); 158 /* NOTREACHED */ 159 } 160 161 /* VARARGS */ 162 static void 163 warning(const char *fmt, ...) 164 { 165 va_list ap; 166 167 (void)fprintf(stderr, "%s: WARNING: ", program_name); 168 va_start(ap, fmt); 169 (void)vfprintf(stderr, fmt, ap); 170 va_end(ap); 171 if (*fmt) { 172 fmt += strlen(fmt); 173 if (fmt[-1] != '\n') 174 (void)fputc('\n', stderr); 175 } 176 } 177 178 /* 179 * Copy arg vector into a new buffer, concatenating arguments with spaces. 180 */ 181 static char * 182 copy_argv(register char **argv) 183 { 184 register char **p; 185 register u_int len = 0; 186 char *buf; 187 char *src, *dst; 188 189 p = argv; 190 if (*p == 0) 191 return 0; 192 193 while (*p) 194 len += strlen(*p++) + 1; 195 196 buf = (char *)malloc(len); 197 if (buf == NULL) 198 error("copy_argv: malloc"); 199 200 p = argv; 201 dst = buf; 202 while ((src = *p++) != NULL) { 203 while ((*dst++ = *src++) != '\0') 204 ; 205 dst[-1] = ' '; 206 } 207 dst[-1] = '\0'; 208 209 return buf; 210 } 211 212 #define INSN_COUNT 17 213 214 int 215 main(int argc, char **argv) 216 { 217 char *cp, *device; 218 int op; 219 int dorfmon, useactivate; 220 char ebuf[PCAP_ERRBUF_SIZE]; 221 char *infile; 222 char *cmdbuf; 223 pcap_t *pd; 224 int status = 0; 225 int pcap_fd; 226 #if defined(USE_BPF) 227 struct bpf_program bad_fcode; 228 struct bpf_insn uninitialized[INSN_COUNT]; 229 #elif defined(USE_SOCKET_FILTERS) 230 struct sock_fprog bad_fcode; 231 struct sock_filter uninitialized[INSN_COUNT]; 232 #endif 233 struct bpf_program fcode; 234 235 device = NULL; 236 dorfmon = 0; 237 useactivate = 0; 238 infile = NULL; 239 240 if ((cp = strrchr(argv[0], '/')) != NULL) 241 program_name = cp + 1; 242 else 243 program_name = argv[0]; 244 245 opterr = 0; 246 while ((op = getopt(argc, argv, "aF:i:I")) != -1) { 247 switch (op) { 248 249 case 'a': 250 useactivate = 1; 251 break; 252 253 case 'F': 254 infile = optarg; 255 break; 256 257 case 'i': 258 device = optarg; 259 break; 260 261 case 'I': 262 dorfmon = 1; 263 useactivate = 1; /* required for rfmon */ 264 break; 265 266 default: 267 usage(); 268 /* NOTREACHED */ 269 } 270 } 271 272 if (device == NULL) { 273 /* 274 * No interface specified; get whatever pcap_lookupdev() 275 * finds. 276 */ 277 device = pcap_lookupdev(ebuf); 278 if (device == NULL) { 279 error("couldn't find interface to use: %s", 280 ebuf); 281 } 282 } 283 284 if (infile != NULL) { 285 /* 286 * Filter specified with "-F" and a file containing 287 * a filter. 288 */ 289 cmdbuf = read_infile(infile); 290 } else { 291 if (optind < argc) { 292 /* 293 * Filter specified with arguments on the 294 * command line. 295 */ 296 cmdbuf = copy_argv(&argv[optind+1]); 297 } else { 298 /* 299 * No filter specified; use an empty string, which 300 * compiles to an "accept all" filter. 301 */ 302 cmdbuf = ""; 303 } 304 } 305 306 if (useactivate) { 307 pd = pcap_create(device, ebuf); 308 if (pd == NULL) 309 error("%s: pcap_create() failed: %s", device, ebuf); 310 status = pcap_set_snaplen(pd, 65535); 311 if (status != 0) 312 error("%s: pcap_set_snaplen failed: %s", 313 device, pcap_statustostr(status)); 314 status = pcap_set_promisc(pd, 1); 315 if (status != 0) 316 error("%s: pcap_set_promisc failed: %s", 317 device, pcap_statustostr(status)); 318 if (dorfmon) { 319 status = pcap_set_rfmon(pd, 1); 320 if (status != 0) 321 error("%s: pcap_set_rfmon failed: %s", 322 device, pcap_statustostr(status)); 323 } 324 status = pcap_set_timeout(pd, 1000); 325 if (status != 0) 326 error("%s: pcap_set_timeout failed: %s", 327 device, pcap_statustostr(status)); 328 status = pcap_activate(pd); 329 if (status < 0) { 330 /* 331 * pcap_activate() failed. 332 */ 333 error("%s: %s\n(%s)", device, 334 pcap_statustostr(status), pcap_geterr(pd)); 335 } else if (status > 0) { 336 /* 337 * pcap_activate() succeeded, but it's warning us 338 * of a problem it had. 339 */ 340 warning("%s: %s\n(%s)", device, 341 pcap_statustostr(status), pcap_geterr(pd)); 342 } 343 } else { 344 *ebuf = '\0'; 345 pd = pcap_open_live(device, 65535, 1, 1000, ebuf); 346 if (pd == NULL) 347 error("%s", ebuf); 348 else if (*ebuf) 349 warning("%s", ebuf); 350 } 351 352 pcap_fd = pcap_fileno(pd); 353 354 /* 355 * Try setting a filter with an uninitialized bpf_program 356 * structure. This should cause valgrind to report a 357 * problem. 358 * 359 * We don't check for errors, because it could get an 360 * error due to a bad pointer or count. 361 */ 362 #if defined(USE_BPF) 363 ioctl(pcap_fd, BIOCSETF, &bad_fcode); 364 #elif defined(USE_SOCKET_FILTERS) 365 setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, 366 sizeof(bad_fcode)); 367 #endif 368 369 /* 370 * Try setting a filter with an initialized bpf_program 371 * structure that points to an uninitialized program. 372 * That should also cause valgrind to report a problem. 373 * 374 * We don't check for errors, because it could get an 375 * error due to a bad pointer or count. 376 */ 377 #if defined(USE_BPF) 378 bad_fcode.bf_len = INSN_COUNT; 379 bad_fcode.bf_insns = uninitialized; 380 ioctl(pcap_fd, BIOCSETF, &bad_fcode); 381 #elif defined(USE_SOCKET_FILTERS) 382 bad_fcode.len = INSN_COUNT; 383 bad_fcode.filter = uninitialized; 384 setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, 385 sizeof(bad_fcode)); 386 #endif 387 388 /* 389 * Now compile a filter and set the filter with that. 390 * That should *not* cause valgrind to report a 391 * problem. 392 */ 393 if (pcap_compile(pd, &fcode, cmdbuf, 1, 0) < 0) 394 error("can't compile filter: %s", pcap_geterr(pd)); 395 if (pcap_setfilter(pd, &fcode) < 0) 396 error("can't set filter: %s", pcap_geterr(pd)); 397 398 pcap_close(pd); 399 exit(status < 0 ? 1 : 0); 400 } 401 402 static void 403 usage(void) 404 { 405 (void)fprintf(stderr, "%s, with %s\n", program_name, 406 pcap_lib_version()); 407 (void)fprintf(stderr, 408 "Usage: %s [-aI] [ -F file ] [ -I interface ] [ expression ]\n", 409 program_name); 410 exit(1); 411 } 412