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