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