1 /* $NetBSD: filtertest.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: filtertest.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 <pcap.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <stdarg.h> 42 #include <unistd.h> 43 #include <fcntl.h> 44 #include <errno.h> 45 #include <arpa/inet.h> 46 #include <sys/types.h> 47 #include <sys/stat.h> 48 49 #ifndef HAVE___ATTRIBUTE__ 50 #define __attribute__(x) 51 #endif 52 53 static char *program_name; 54 55 /* Forwards */ 56 static void usage(void) __attribute__((noreturn)); 57 static void error(const char *, ...) 58 __attribute__((noreturn, format (printf, 1, 2))); 59 static void warn(const char *, ...) 60 __attribute__((format (printf, 1, 2))); 61 62 extern int optind; 63 extern int opterr; 64 extern char *optarg; 65 #ifdef BDEBUG 66 int dflag; 67 #endif 68 69 /* 70 * On Windows, we need to open the file in binary mode, so that 71 * we get all the bytes specified by the size we get from "fstat()". 72 * On UNIX, that's not necessary. O_BINARY is defined on Windows; 73 * we define it as 0 if it's not defined, so it does nothing. 74 */ 75 #ifndef O_BINARY 76 #define O_BINARY 0 77 #endif 78 79 static char * 80 read_infile(char *fname) 81 { 82 register int i, fd, cc; 83 register char *cp; 84 struct stat buf; 85 86 fd = open(fname, O_RDONLY|O_BINARY); 87 if (fd < 0) 88 error("can't open %s: %s", fname, pcap_strerror(errno)); 89 90 if (fstat(fd, &buf) < 0) 91 error("can't stat %s: %s", fname, pcap_strerror(errno)); 92 93 cp = malloc((u_int)buf.st_size + 1); 94 if (cp == NULL) 95 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, 96 fname, pcap_strerror(errno)); 97 cc = read(fd, cp, (u_int)buf.st_size); 98 if (cc < 0) 99 error("read %s: %s", fname, pcap_strerror(errno)); 100 if (cc != buf.st_size) 101 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); 102 103 close(fd); 104 /* replace "# comment" with spaces */ 105 for (i = 0; i < cc; i++) { 106 if (cp[i] == '#') 107 while (i < cc && cp[i] != '\n') 108 cp[i++] = ' '; 109 } 110 cp[cc] = '\0'; 111 return (cp); 112 } 113 114 /* VARARGS */ 115 static void 116 error(const char *fmt, ...) 117 { 118 va_list ap; 119 120 (void)fprintf(stderr, "%s: ", program_name); 121 va_start(ap, fmt); 122 (void)vfprintf(stderr, fmt, ap); 123 va_end(ap); 124 if (*fmt) { 125 fmt += strlen(fmt); 126 if (fmt[-1] != '\n') 127 (void)fputc('\n', stderr); 128 } 129 exit(1); 130 /* NOTREACHED */ 131 } 132 133 /* VARARGS */ 134 static void 135 warn(const char *fmt, ...) 136 { 137 va_list ap; 138 139 (void)fprintf(stderr, "%s: WARNING: ", program_name); 140 va_start(ap, fmt); 141 (void)vfprintf(stderr, fmt, ap); 142 va_end(ap); 143 if (*fmt) { 144 fmt += strlen(fmt); 145 if (fmt[-1] != '\n') 146 (void)fputc('\n', stderr); 147 } 148 } 149 150 /* 151 * Copy arg vector into a new buffer, concatenating arguments with spaces. 152 */ 153 static char * 154 copy_argv(register char **argv) 155 { 156 register char **p; 157 register u_int len = 0; 158 char *buf; 159 char *src, *dst; 160 161 p = argv; 162 if (*p == 0) 163 return 0; 164 165 while (*p) 166 len += strlen(*p++) + 1; 167 168 buf = (char *)malloc(len); 169 if (buf == NULL) 170 error("copy_argv: malloc"); 171 172 p = argv; 173 dst = buf; 174 while ((src = *p++) != NULL) { 175 while ((*dst++ = *src++) != '\0') 176 ; 177 dst[-1] = ' '; 178 } 179 dst[-1] = '\0'; 180 181 return buf; 182 } 183 184 int 185 main(int argc, char **argv) 186 { 187 char *cp; 188 int op; 189 #ifndef BDEBUG 190 int dflag; 191 #endif 192 char *infile; 193 int Oflag; 194 long snaplen; 195 char *p; 196 int dlt; 197 bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN; 198 char *cmdbuf; 199 pcap_t *pd; 200 struct bpf_program fcode; 201 202 #ifdef WIN32 203 if(wsockinit() != 0) return 1; 204 #endif /* WIN32 */ 205 206 #ifndef BDEBUG 207 dflag = 1; 208 #else 209 /* if optimizer debugging is enabled, output DOT graph 210 * `dflag=4' is equivalent to -dddd to follow -d/-dd/-ddd 211 * convention in tcpdump command line 212 */ 213 dflag = 4; 214 #endif 215 infile = NULL; 216 Oflag = 1; 217 snaplen = 68; 218 219 if ((cp = strrchr(argv[0], '/')) != NULL) 220 program_name = cp + 1; 221 else 222 program_name = argv[0]; 223 224 opterr = 0; 225 while ((op = getopt(argc, argv, "dF:m:Os:")) != -1) { 226 switch (op) { 227 228 case 'd': 229 ++dflag; 230 break; 231 232 case 'F': 233 infile = optarg; 234 break; 235 236 case 'O': 237 Oflag = 0; 238 break; 239 240 case 'm': { 241 in_addr_t addr; 242 243 addr = inet_addr(optarg); 244 if (addr == INADDR_NONE) 245 error("invalid netmask %s", optarg); 246 netmask = addr; 247 break; 248 } 249 250 case 's': { 251 char *end; 252 253 snaplen = strtol(optarg, &end, 0); 254 if (optarg == end || *end != '\0' 255 || snaplen < 0 || snaplen > 65535) 256 error("invalid snaplen %s", optarg); 257 else if (snaplen == 0) 258 snaplen = 65535; 259 break; 260 } 261 262 default: 263 usage(); 264 /* NOTREACHED */ 265 } 266 } 267 268 if (optind >= argc) { 269 usage(); 270 /* NOTREACHED */ 271 } 272 273 dlt = pcap_datalink_name_to_val(argv[optind]); 274 if (dlt < 0) { 275 dlt = (int)strtol(argv[optind], &p, 10); 276 if (p == argv[optind] || *p != '\0') 277 error("invalid data link type %s", argv[optind]); 278 } 279 280 if (infile) 281 cmdbuf = read_infile(infile); 282 else 283 cmdbuf = copy_argv(&argv[optind+1]); 284 285 pd = pcap_open_dead(dlt, snaplen); 286 if (pd == NULL) 287 error("Can't open fake pcap_t"); 288 289 if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) 290 error("%s", pcap_geterr(pd)); 291 292 if (!bpf_validate(fcode.bf_insns, fcode.bf_len)) 293 warn("Filter doesn't pass validation"); 294 295 #ifdef BDEBUG 296 // replace line feed with space 297 for (cp = cmdbuf; *cp != '\0'; ++cp) { 298 if (*cp == '\r' || *cp == '\n') { 299 *cp = ' '; 300 } 301 } 302 // only show machine code if BDEBUG defined, since dflag > 3 303 printf("machine codes for filter: %s\n", cmdbuf); 304 #endif 305 306 bpf_dump(&fcode, dflag); 307 pcap_close(pd); 308 exit(0); 309 } 310 311 static void 312 usage(void) 313 { 314 (void)fprintf(stderr, "%s, with %s\n", program_name, 315 pcap_lib_version()); 316 (void)fprintf(stderr, 317 "Usage: %s [-dO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n", 318 program_name); 319 exit(1); 320 } 321