]> The Tcpdump Group git mirrors - libpcap/blob - testprogs/filtertest.c
be43de0e574bff1760b780719416d952a5683a05
[libpcap] / testprogs / filtertest.c
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 #include <sysexits.h>
44 #endif
45 #include <fcntl.h>
46 #include <errno.h>
47 #ifdef _WIN32
48 #include <winsock2.h>
49 #include <ws2tcpip.h>
50 #else
51 #include <sys/socket.h>
52 #include <arpa/inet.h>
53 #endif
54 #include <sys/types.h>
55 #include <sys/stat.h>
56
57 #include "pcap/funcattrs.h"
58
59 #define MAXIMUM_SNAPLEN 262144
60
61 #ifdef BDEBUG
62 /*
63 * We have pcap_set_optimizer_debug() and pcap_set_print_dot_graph() in
64 * libpcap; declare them (they're not declared by any libpcap header,
65 * because they're special hacks, only available if libpcap was configured
66 * to include them, and only intended for use by libpcap developers trying
67 * to debug the optimizer for filter expressions).
68 */
69 PCAP_API void pcap_set_optimizer_debug(int);
70 PCAP_API void pcap_set_print_dot_graph(int);
71 #endif
72
73 #ifdef __linux__
74 #include <linux/filter.h>
75 #if defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT)
76 /*
77 * pcap-int.h is a private header and should not be included by programs that
78 * use libpcap. This test program uses a special hack because it is the
79 * simplest way to test internal code paths that otherwise would require
80 * elevated privileges. Do not do this in normal code.
81 */
82 #include <pcap-int.h>
83 #define LINUX_BPF_EXT
84 #endif // defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT)
85 #endif // __linux__
86
87 static char *program_name;
88
89 /* Forwards */
90 static void PCAP_NORETURN usage(FILE *);
91 static void PCAP_NORETURN error(const int, const char *, ...) PCAP_PRINTFLIKE(2, 3);
92 static void warn(const char *, ...) PCAP_PRINTFLIKE(1, 2);
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(EX_NOINPUT, "can't open %s: %s", fname, pcap_strerror(errno));
114
115 if (fstat(fd, &buf) < 0)
116 error(EX_NOINPUT, "can't stat %s: %s", fname, pcap_strerror(errno));
117
118 /*
119 * _read(), on Windows, has an unsigned int byte count and an
120 * int return value, so we can't handle a file bigger than
121 * INT_MAX - 1 bytes (and have no reason to do so; a filter *that*
122 * big will take forever to compile). (The -1 is for the '\0' at
123 * the end of the string.)
124 */
125 if (buf.st_size > INT_MAX - 1)
126 error(EX_DATAERR, "%s is larger than %d bytes; that's too large", fname,
127 INT_MAX - 1);
128 cp = malloc((u_int)buf.st_size + 1);
129 if (cp == NULL)
130 error(EX_OSERR, "malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
131 fname, pcap_strerror(errno));
132 cc = (int)read(fd, cp, (u_int)buf.st_size);
133 if (cc < 0)
134 error(EX_IOERR, "read %s: %s", fname, pcap_strerror(errno));
135 if (cc != buf.st_size)
136 error(EX_IOERR, "short read %s (%d != %d)", fname, cc, (int)buf.st_size);
137
138 close(fd);
139 /* replace "# comment" with spaces */
140 for (i = 0; i < cc; i++) {
141 if (cp[i] == '#')
142 while (i < cc && cp[i] != '\n')
143 cp[i++] = ' ';
144 }
145 cp[cc] = '\0';
146 return (cp);
147 }
148
149 /* VARARGS */
150 static void
151 error(const int status, const char *fmt, ...)
152 {
153 va_list ap;
154
155 (void)fprintf(stderr, "%s: ", program_name);
156 va_start(ap, fmt);
157 (void)vfprintf(stderr, fmt, ap);
158 va_end(ap);
159 if (*fmt) {
160 fmt += strlen(fmt);
161 if (fmt[-1] != '\n')
162 (void)fputc('\n', stderr);
163 }
164 exit(status);
165 /* NOTREACHED */
166 }
167
168 /* VARARGS */
169 static void
170 warn(const char *fmt, ...)
171 {
172 va_list ap;
173
174 (void)fprintf(stderr, "%s: WARNING: ", program_name);
175 va_start(ap, fmt);
176 (void)vfprintf(stderr, fmt, ap);
177 va_end(ap);
178 if (*fmt) {
179 fmt += strlen(fmt);
180 if (fmt[-1] != '\n')
181 (void)fputc('\n', stderr);
182 }
183 }
184
185 /*
186 * Copy arg vector into a new buffer, concatenating arguments with spaces.
187 */
188 static char *
189 copy_argv(register char **argv)
190 {
191 register char **p;
192 register size_t len = 0;
193 char *buf;
194 char *src, *dst;
195
196 p = argv;
197 if (*p == 0)
198 return 0;
199
200 while (*p)
201 len += strlen(*p++) + 1;
202
203 buf = (char *)malloc(len);
204 if (buf == NULL)
205 error(EX_OSERR, "%s: malloc", __func__);
206
207 p = argv;
208 dst = buf;
209 while ((src = *p++) != NULL) {
210 while ((*dst++ = *src++) != '\0')
211 ;
212 dst[-1] = ' ';
213 }
214 dst[-1] = '\0';
215
216 return buf;
217 }
218
219 int
220 main(int argc, char **argv)
221 {
222 char *cp;
223 int op;
224 int dflag = 1;
225 #ifdef BDEBUG
226 int gflag = 0;
227 #endif
228 char *infile = NULL;
229 int Oflag = 1;
230 #ifdef LINUX_BPF_EXT
231 int lflag = 0;
232 #endif
233 int snaplen = MAXIMUM_SNAPLEN;
234 char *p;
235 int dlt;
236 bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN;
237 char *cmdbuf;
238 pcap_t *pd;
239 struct bpf_program fcode;
240
241 #ifdef _WIN32
242 WSADATA wsaData;
243 if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData))
244 return 1;
245 #endif /* _WIN32 */
246
247 if ((cp = strrchr(argv[0], '/')) != NULL)
248 program_name = cp + 1;
249 else
250 program_name = argv[0];
251
252 opterr = 0;
253 while ((op = getopt(argc, argv, "hdF:gm:Os:l")) != -1) {
254 switch (op) {
255
256 case 'h':
257 usage(stdout);
258 /* NOTREACHED */
259
260 case 'd':
261 ++dflag;
262 break;
263
264 case 'g':
265 #ifdef BDEBUG
266 ++gflag;
267 break;
268 #else
269 error(EX_USAGE, "libpcap and filtertest not built with optimizer debugging enabled");
270 #endif
271
272 case 'F':
273 infile = optarg;
274 break;
275
276 case 'O':
277 Oflag = 0;
278 break;
279
280 case 'm': {
281 bpf_u_int32 addr;
282
283 switch (inet_pton(AF_INET, optarg, &addr)) {
284
285 case 0:
286 error(EX_DATAERR, "invalid netmask %s", optarg);
287
288 case -1:
289 error(EX_DATAERR, "invalid netmask %s: %s", optarg,
290 pcap_strerror(errno));
291
292 case 1:
293 netmask = addr;
294 break;
295 }
296 break;
297 }
298
299 case 's': {
300 char *end;
301 long long_snaplen;
302
303 long_snaplen = strtol(optarg, &end, 0);
304 if (optarg == end || *end != '\0'
305 || long_snaplen < 0
306 || long_snaplen > MAXIMUM_SNAPLEN)
307 error(EX_DATAERR, "invalid snaplen %s", optarg);
308 else {
309 if (snaplen == 0)
310 snaplen = MAXIMUM_SNAPLEN;
311 else
312 snaplen = (int)long_snaplen;
313 }
314 break;
315 }
316
317 case 'l':
318 #ifdef LINUX_BPF_EXT
319 // Enable Linux BPF extensions.
320 lflag = 1;
321 break;
322 #else
323 error(EX_USAGE, "libpcap and filtertest built without Linux BPF extensions");
324 #endif
325
326 default:
327 usage(stderr);
328 /* NOTREACHED */
329 }
330 }
331
332 if (optind >= argc) {
333 usage(stderr);
334 /* NOTREACHED */
335 }
336
337 dlt = pcap_datalink_name_to_val(argv[optind]);
338 if (dlt < 0) {
339 dlt = (int)strtol(argv[optind], &p, 10);
340 if (p == argv[optind] || *p != '\0')
341 error(EX_DATAERR, "invalid data link type %s", argv[optind]);
342 }
343
344 if (infile)
345 cmdbuf = read_infile(infile);
346 else
347 cmdbuf = copy_argv(&argv[optind+1]);
348
349 #ifdef BDEBUG
350 pcap_set_optimizer_debug(dflag);
351 pcap_set_print_dot_graph(gflag);
352 #endif
353
354 pd = pcap_open_dead(dlt, snaplen);
355 if (pd == NULL)
356 error(EX_SOFTWARE, "Can't open fake pcap_t");
357
358 #ifdef LINUX_BPF_EXT
359 if (lflag) {
360 pd->bpf_codegen_flags |= BPF_SPECIAL_VLAN_HANDLING;
361 pd->bpf_codegen_flags |= BPF_SPECIAL_BASIC_HANDLING;
362 }
363 #endif
364
365 if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
366 error(EX_DATAERR, "%s", pcap_geterr(pd));
367
368 if (!bpf_validate(fcode.bf_insns, fcode.bf_len))
369 warn("Filter doesn't pass validation");
370
371 #ifdef BDEBUG
372 if (cmdbuf != NULL) {
373 // replace line feed with space
374 for (cp = cmdbuf; *cp != '\0'; ++cp) {
375 if (*cp == '\r' || *cp == '\n') {
376 *cp = ' ';
377 }
378 }
379 // only show machine code if BDEBUG defined, since dflag > 3
380 printf("machine codes for filter: %s\n", cmdbuf);
381 } else
382 printf("machine codes for empty filter:\n");
383 #endif
384
385 bpf_dump(&fcode, dflag);
386 free(cmdbuf);
387 pcap_freecode (&fcode);
388 pcap_close(pd);
389 #ifdef _WIN32
390 WSACleanup();
391 #endif
392 exit(EX_OK);
393 }
394
395 static void
396 usage(FILE *f)
397 {
398 (void)fprintf(f, "%s, with %s\n", program_name,
399 pcap_lib_version());
400 (void)fprintf(f,
401 "Usage: %s [-d"
402 #ifdef BDEBUG
403 "g"
404 #endif
405 "O"
406 #ifdef LINUX_BPF_EXT
407 "l"
408 #endif
409 "] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expr ]\n",
410 program_name);
411 (void)fprintf(f, " (print the filter program bytecode)\n");
412 (void)fprintf(f, " or: %s -h\n", program_name);
413 (void)fprintf(f, " (print the detailed help screen)\n");
414 if (f == stdout) {
415 (void)fprintf(f, "\nOptions specific to %s:\n", program_name);
416 (void)fprintf(f, " <dlt> a valid DLT name, e.g. 'EN10MB'\n");
417 (void)fprintf(f, " <expr> a valid filter expression, e.g. 'tcp port 80'\n");
418 #ifdef LINUX_BPF_EXT
419 (void)fprintf(f, " -l allow the use of Linux BPF extensions\n");
420 #endif
421 #ifdef BDEBUG
422 (void)fprintf(f, " -g print Graphviz dot graphs for the optimizer steps\n");
423 #endif
424 (void)fprintf(f, " -m <netmask> use this netmask for pcap_compile(), e.g. 255.255.255.0\n");
425 (void)fprintf(f, "\n");
426 (void)fprintf(f, "Options common with tcpdump:\n");
427 (void)fprintf(f, " -d change output format (accumulates, one -d is implicit)\n");
428 (void)fprintf(f, " -O do not optimize the filter program\n");
429 (void)fprintf(f, " -F <file> read the filter expression from the specified file\n");
430 (void)fprintf(f, " -s <snaplen> set the snapshot length\n");
431 (void)fprintf(f, "\nIf no filter expression is specified, it defaults to an empty string, which\n");
432 (void)fprintf(f, "accepts all packets. If the -F option is in use, it replaces any filter\n");
433 (void)fprintf(f, "expression specified as a command-line argument.\n");
434 }
435 exit(f == stdout ? EX_OK : EX_USAGE);
436 }