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 #ifdef HAVE_CONFIG_H 31 #include <config.h> 32 #endif 33 34 #include <pcap.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <stdarg.h> 39 #include <limits.h> 40 #ifdef _WIN32 41 #include "getopt.h" 42 #include "unix.h" 43 #else 44 #include <unistd.h> 45 #endif 46 #include <fcntl.h> 47 #include <errno.h> 48 #ifdef _WIN32 49 #include <winsock2.h> 50 #include <ws2tcpip.h> 51 #else 52 #include <sys/socket.h> 53 #include <arpa/inet.h> 54 #endif 55 #include <sys/types.h> 56 #include <sys/stat.h> 57 58 #include "pcap/funcattrs.h" 59 60 #define MAXIMUM_SNAPLEN 262144 61 62 #ifdef BDEBUG 63 /* 64 * We have pcap_set_optimizer_debug() and pcap_set_print_dot_graph() in 65 * libpcap; declare them (they're not declared by any libpcap header, 66 * because they're special hacks, only available if libpcap was configured 67 * to include them, and only intended for use by libpcap developers trying 68 * to debug the optimizer for filter expressions). 69 */ 70 PCAP_API void pcap_set_optimizer_debug(int); 71 PCAP_API void pcap_set_print_dot_graph(int); 72 #endif 73 74 static char *program_name; 75 76 /* Forwards */ 77 static void PCAP_NORETURN usage(void); 78 static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); 79 static void warn(const char *, ...) PCAP_PRINTFLIKE(1, 2); 80 81 /* 82 * On Windows, we need to open the file in binary mode, so that 83 * we get all the bytes specified by the size we get from "fstat()". 84 * On UNIX, that's not necessary. O_BINARY is defined on Windows; 85 * we define it as 0 if it's not defined, so it does nothing. 86 */ 87 #ifndef O_BINARY 88 #define O_BINARY 0 89 #endif 90 91 static char * 92 read_infile(char *fname) 93 { 94 register int i, fd, cc; 95 register char *cp; 96 struct stat buf; 97 98 fd = open(fname, O_RDONLY|O_BINARY); 99 if (fd < 0) 100 error("can't open %s: %s", fname, pcap_strerror(errno)); 101 102 if (fstat(fd, &buf) < 0) 103 error("can't stat %s: %s", fname, pcap_strerror(errno)); 104 105 /* 106 * _read(), on Windows, has an unsigned int byte count and an 107 * int return value, so we can't handle a file bigger than 108 * INT_MAX - 1 bytes (and have no reason to do so; a filter *that* 109 * big will take forever to compile). (The -1 is for the '\0' at 110 * the end of the string.) 111 */ 112 if (buf.st_size > INT_MAX - 1) 113 error("%s is larger than %d bytes; that's too large", fname, 114 INT_MAX - 1); 115 cp = malloc((u_int)buf.st_size + 1); 116 if (cp == NULL) 117 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, 118 fname, pcap_strerror(errno)); 119 cc = (int)read(fd, cp, (u_int)buf.st_size); 120 if (cc < 0) 121 error("read %s: %s", fname, pcap_strerror(errno)); 122 if (cc != buf.st_size) 123 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); 124 125 close(fd); 126 /* replace "# comment" with spaces */ 127 for (i = 0; i < cc; i++) { 128 if (cp[i] == '#') 129 while (i < cc && cp[i] != '\n') 130 cp[i++] = ' '; 131 } 132 cp[cc] = '\0'; 133 return (cp); 134 } 135 136 /* VARARGS */ 137 static void 138 error(const char *fmt, ...) 139 { 140 va_list ap; 141 142 (void)fprintf(stderr, "%s: ", program_name); 143 va_start(ap, fmt); 144 (void)vfprintf(stderr, fmt, ap); 145 va_end(ap); 146 if (*fmt) { 147 fmt += strlen(fmt); 148 if (fmt[-1] != '\n') 149 (void)fputc('\n', stderr); 150 } 151 exit(1); 152 /* NOTREACHED */ 153 } 154 155 /* VARARGS */ 156 static void 157 warn(const char *fmt, ...) 158 { 159 va_list ap; 160 161 (void)fprintf(stderr, "%s: WARNING: ", program_name); 162 va_start(ap, fmt); 163 (void)vfprintf(stderr, fmt, ap); 164 va_end(ap); 165 if (*fmt) { 166 fmt += strlen(fmt); 167 if (fmt[-1] != '\n') 168 (void)fputc('\n', stderr); 169 } 170 } 171 172 /* 173 * Copy arg vector into a new buffer, concatenating arguments with spaces. 174 */ 175 static char * 176 copy_argv(register char **argv) 177 { 178 register char **p; 179 register size_t len = 0; 180 char *buf; 181 char *src, *dst; 182 183 p = argv; 184 if (*p == 0) 185 return 0; 186 187 while (*p) 188 len += strlen(*p++) + 1; 189 190 buf = (char *)malloc(len); 191 if (buf == NULL) 192 error("copy_argv: malloc"); 193 194 p = argv; 195 dst = buf; 196 while ((src = *p++) != NULL) { 197 while ((*dst++ = *src++) != '\0') 198 ; 199 dst[-1] = ' '; 200 } 201 dst[-1] = '\0'; 202 203 return buf; 204 } 205 206 int 207 main(int argc, char **argv) 208 { 209 char *cp; 210 int op; 211 int dflag; 212 #ifdef BDEBUG 213 int gflag; 214 #endif 215 char *infile; 216 int Oflag; 217 int snaplen; 218 char *p; 219 int dlt; 220 bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN; 221 char *cmdbuf; 222 pcap_t *pd; 223 struct bpf_program fcode; 224 225 #ifdef _WIN32 226 if (pcap_wsockinit() != 0) 227 return 1; 228 #endif /* _WIN32 */ 229 230 dflag = 1; 231 #ifdef BDEBUG 232 gflag = 0; 233 #endif 234 235 infile = NULL; 236 Oflag = 1; 237 snaplen = MAXIMUM_SNAPLEN; 238 239 if ((cp = strrchr(argv[0], '/')) != NULL) 240 program_name = cp + 1; 241 else 242 program_name = argv[0]; 243 244 opterr = 0; 245 while ((op = getopt(argc, argv, "dF:gm:Os:")) != -1) { 246 switch (op) { 247 248 case 'd': 249 ++dflag; 250 break; 251 252 case 'g': 253 #ifdef BDEBUG 254 ++gflag; 255 #else 256 error("libpcap and filtertest not built with optimizer debugging enabled"); 257 #endif 258 break; 259 260 case 'F': 261 infile = optarg; 262 break; 263 264 case 'O': 265 Oflag = 0; 266 break; 267 268 case 'm': { 269 bpf_u_int32 addr; 270 271 switch (inet_pton(AF_INET, optarg, &addr)) { 272 273 case 0: 274 error("invalid netmask %s", optarg); 275 break; 276 277 case -1: 278 error("invalid netmask %s: %s", optarg, 279 pcap_strerror(errno)); 280 break; 281 282 case 1: 283 netmask = addr; 284 break; 285 } 286 break; 287 } 288 289 case 's': { 290 char *end; 291 long long_snaplen; 292 293 long_snaplen = strtol(optarg, &end, 0); 294 if (optarg == end || *end != '\0' 295 || long_snaplen < 0 296 || long_snaplen > MAXIMUM_SNAPLEN) 297 error("invalid snaplen %s", optarg); 298 else { 299 if (snaplen == 0) 300 snaplen = MAXIMUM_SNAPLEN; 301 else 302 snaplen = (int)long_snaplen; 303 } 304 break; 305 } 306 307 default: 308 usage(); 309 /* NOTREACHED */ 310 } 311 } 312 313 if (optind >= argc) { 314 usage(); 315 /* NOTREACHED */ 316 } 317 318 dlt = pcap_datalink_name_to_val(argv[optind]); 319 if (dlt < 0) { 320 dlt = (int)strtol(argv[optind], &p, 10); 321 if (p == argv[optind] || *p != '\0') 322 error("invalid data link type %s", argv[optind]); 323 } 324 325 if (infile) 326 cmdbuf = read_infile(infile); 327 else 328 cmdbuf = copy_argv(&argv[optind+1]); 329 330 #ifdef BDEBUG 331 pcap_set_optimizer_debug(dflag); 332 pcap_set_print_dot_graph(gflag); 333 #endif 334 335 pd = pcap_open_dead(dlt, snaplen); 336 if (pd == NULL) 337 error("Can't open fake pcap_t"); 338 339 if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) 340 error("%s", pcap_geterr(pd)); 341 342 if (!bpf_validate(fcode.bf_insns, fcode.bf_len)) 343 warn("Filter doesn't pass validation"); 344 345 #ifdef BDEBUG 346 if (cmdbuf != NULL) { 347 // replace line feed with space 348 for (cp = cmdbuf; *cp != '\0'; ++cp) { 349 if (*cp == '\r' || *cp == '\n') { 350 *cp = ' '; 351 } 352 } 353 // only show machine code if BDEBUG defined, since dflag > 3 354 printf("machine codes for filter: %s\n", cmdbuf); 355 } else 356 printf("machine codes for empty filter:\n"); 357 #endif 358 359 bpf_dump(&fcode, dflag); 360 free(cmdbuf); 361 pcap_freecode (&fcode); 362 pcap_close(pd); 363 exit(0); 364 } 365 366 static void 367 usage(void) 368 { 369 (void)fprintf(stderr, "%s, with %s\n", program_name, 370 pcap_lib_version()); 371 (void)fprintf(stderr, 372 #ifdef BDEBUG 373 "Usage: %s [-dgO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n", 374 #else 375 "Usage: %s [-dO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n", 376 #endif 377 program_name); 378 exit(1); 379 } 380