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