1353141Sphilip/*
2353141Sphilip * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
3353141Sphilip *	The Regents of the University of California.  All rights reserved.
4353141Sphilip *
5353141Sphilip * Redistribution and use in source and binary forms, with or without
6353141Sphilip * modification, are permitted provided that: (1) source code distributions
7353141Sphilip * retain the above copyright notice and this paragraph in its entirety, (2)
8353141Sphilip * distributions including binary code include the above copyright notice and
9353141Sphilip * this paragraph in its entirety in the documentation or other materials
10353141Sphilip * provided with the distribution, and (3) all advertising materials mentioning
11353141Sphilip * features or use of this software display the following acknowledgement:
12353141Sphilip * ``This product includes software developed by the University of California,
13353141Sphilip * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14353141Sphilip * the University nor the names of its contributors may be used to endorse
15353141Sphilip * or promote products derived from this software without specific prior
16353141Sphilip * written permission.
17353141Sphilip * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18353141Sphilip * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19353141Sphilip * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20353141Sphilip */
21353141Sphilip
22353141Sphilip#include "varattrs.h"
23353141Sphilip
24353141Sphilip#ifndef lint
25353141Sphilipstatic const char copyright[] _U_ =
26353141Sphilip    "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
27353141SphilipThe Regents of the University of California.  All rights reserved.\n";
28353141Sphilip#endif
29353141Sphilip
30353141Sphilip#ifdef HAVE_CONFIG_H
31353141Sphilip#include <config.h>
32353141Sphilip#endif
33353141Sphilip
34353141Sphilip#include <pcap.h>
35353141Sphilip#include <stdio.h>
36353141Sphilip#include <stdlib.h>
37353141Sphilip#include <string.h>
38353141Sphilip#include <stdarg.h>
39353141Sphilip#ifdef _WIN32
40353141Sphilip  #include "getopt.h"
41353141Sphilip  #include "unix.h"
42353141Sphilip#else
43353141Sphilip  #include <unistd.h>
44353141Sphilip#endif
45353141Sphilip#include <fcntl.h>
46353141Sphilip#include <errno.h>
47353141Sphilip#ifdef _WIN32
48353141Sphilip  #include <winsock2.h>
49353141Sphilip  #include <ws2tcpip.h>
50353141Sphilip#else
51353141Sphilip  #include <sys/socket.h>
52353141Sphilip  #include <arpa/inet.h>
53353141Sphilip#endif
54353141Sphilip#include <sys/types.h>
55353141Sphilip#include <sys/stat.h>
56353141Sphilip
57353141Sphilip#include "pcap/funcattrs.h"
58353141Sphilip
59353141Sphilip#ifdef BDEBUG
60353141Sphilip/*
61353141Sphilip * We have pcap_set_optimizer_debug() and pcap_set_print_dot_graph() in
62353141Sphilip * libpcap; declare them (they're not declared by any libpcap header,
63353141Sphilip * because they're special hacks, only available if libpcap was configured
64353141Sphilip * to include them, and only intended for use by libpcap developers trying
65353141Sphilip * to debug the optimizer for filter expressions).
66353141Sphilip */
67353141SphilipPCAP_API void pcap_set_optimizer_debug(int);
68353141SphilipPCAP_API void pcap_set_print_dot_graph(int);
69353141Sphilip#endif
70353141Sphilip
71353141Sphilipstatic char *program_name;
72353141Sphilip
73353141Sphilip/* Forwards */
74353141Sphilipstatic void PCAP_NORETURN usage(void);
75353141Sphilipstatic void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2);
76353141Sphilipstatic void warn(const char *, ...) PCAP_PRINTFLIKE(1, 2);
77353141Sphilip
78353141Sphilip/*
79353141Sphilip * On Windows, we need to open the file in binary mode, so that
80353141Sphilip * we get all the bytes specified by the size we get from "fstat()".
81353141Sphilip * On UNIX, that's not necessary.  O_BINARY is defined on Windows;
82353141Sphilip * we define it as 0 if it's not defined, so it does nothing.
83353141Sphilip */
84353141Sphilip#ifndef O_BINARY
85353141Sphilip#define O_BINARY	0
86353141Sphilip#endif
87353141Sphilip
88353141Sphilipstatic char *
89353141Sphilipread_infile(char *fname)
90353141Sphilip{
91353141Sphilip	register int i, fd, cc;
92353141Sphilip	register char *cp;
93353141Sphilip	struct stat buf;
94353141Sphilip
95353141Sphilip	fd = open(fname, O_RDONLY|O_BINARY);
96353141Sphilip	if (fd < 0)
97353141Sphilip		error("can't open %s: %s", fname, pcap_strerror(errno));
98353141Sphilip
99353141Sphilip	if (fstat(fd, &buf) < 0)
100353141Sphilip		error("can't stat %s: %s", fname, pcap_strerror(errno));
101353141Sphilip
102353141Sphilip	cp = malloc((u_int)buf.st_size + 1);
103353141Sphilip	if (cp == NULL)
104353141Sphilip		error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
105353141Sphilip			fname, pcap_strerror(errno));
106353141Sphilip	cc = read(fd, cp, (u_int)buf.st_size);
107353141Sphilip	if (cc < 0)
108353141Sphilip		error("read %s: %s", fname, pcap_strerror(errno));
109353141Sphilip	if (cc != buf.st_size)
110353141Sphilip		error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
111353141Sphilip
112353141Sphilip	close(fd);
113353141Sphilip	/* replace "# comment" with spaces */
114353141Sphilip	for (i = 0; i < cc; i++) {
115353141Sphilip		if (cp[i] == '#')
116353141Sphilip			while (i < cc && cp[i] != '\n')
117353141Sphilip				cp[i++] = ' ';
118353141Sphilip	}
119353141Sphilip	cp[cc] = '\0';
120353141Sphilip	return (cp);
121353141Sphilip}
122353141Sphilip
123353141Sphilip/* VARARGS */
124353141Sphilipstatic void
125353141Sphiliperror(const char *fmt, ...)
126353141Sphilip{
127353141Sphilip	va_list ap;
128353141Sphilip
129353141Sphilip	(void)fprintf(stderr, "%s: ", program_name);
130353141Sphilip	va_start(ap, fmt);
131353141Sphilip	(void)vfprintf(stderr, fmt, ap);
132353141Sphilip	va_end(ap);
133353141Sphilip	if (*fmt) {
134353141Sphilip		fmt += strlen(fmt);
135353141Sphilip		if (fmt[-1] != '\n')
136353141Sphilip			(void)fputc('\n', stderr);
137353141Sphilip	}
138353141Sphilip	exit(1);
139353141Sphilip	/* NOTREACHED */
140353141Sphilip}
141353141Sphilip
142353141Sphilip/* VARARGS */
143353141Sphilipstatic void
144353141Sphilipwarn(const char *fmt, ...)
145353141Sphilip{
146353141Sphilip	va_list ap;
147353141Sphilip
148353141Sphilip	(void)fprintf(stderr, "%s: WARNING: ", program_name);
149353141Sphilip	va_start(ap, fmt);
150353141Sphilip	(void)vfprintf(stderr, fmt, ap);
151353141Sphilip	va_end(ap);
152353141Sphilip	if (*fmt) {
153353141Sphilip		fmt += strlen(fmt);
154353141Sphilip		if (fmt[-1] != '\n')
155353141Sphilip			(void)fputc('\n', stderr);
156353141Sphilip	}
157353141Sphilip}
158353141Sphilip
159353141Sphilip/*
160353141Sphilip * Copy arg vector into a new buffer, concatenating arguments with spaces.
161353141Sphilip */
162353141Sphilipstatic char *
163353141Sphilipcopy_argv(register char **argv)
164353141Sphilip{
165353141Sphilip	register char **p;
166353141Sphilip	register u_int len = 0;
167353141Sphilip	char *buf;
168353141Sphilip	char *src, *dst;
169353141Sphilip
170353141Sphilip	p = argv;
171353141Sphilip	if (*p == 0)
172353141Sphilip		return 0;
173353141Sphilip
174353141Sphilip	while (*p)
175353141Sphilip		len += strlen(*p++) + 1;
176353141Sphilip
177353141Sphilip	buf = (char *)malloc(len);
178353141Sphilip	if (buf == NULL)
179353141Sphilip		error("copy_argv: malloc");
180353141Sphilip
181353141Sphilip	p = argv;
182353141Sphilip	dst = buf;
183353141Sphilip	while ((src = *p++) != NULL) {
184353141Sphilip		while ((*dst++ = *src++) != '\0')
185353141Sphilip			;
186353141Sphilip		dst[-1] = ' ';
187353141Sphilip	}
188353141Sphilip	dst[-1] = '\0';
189353141Sphilip
190353141Sphilip	return buf;
191353141Sphilip}
192353141Sphilip
193353141Sphilipint
194353141Sphilipmain(int argc, char **argv)
195353141Sphilip{
196353141Sphilip	char *cp;
197353141Sphilip	int op;
198353141Sphilip	int dflag;
199353141Sphilip	int gflag;
200353141Sphilip	char *infile;
201353141Sphilip	int Oflag;
202353141Sphilip	long snaplen;
203353141Sphilip	char *p;
204353141Sphilip	int dlt;
205353141Sphilip	int have_fcode = 0;
206353141Sphilip	bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN;
207353141Sphilip	char *cmdbuf;
208353141Sphilip	pcap_t *pd;
209353141Sphilip	struct bpf_program fcode;
210353141Sphilip
211353141Sphilip#ifdef _WIN32
212353141Sphilip	if (pcap_wsockinit() != 0)
213353141Sphilip		return 1;
214353141Sphilip#endif /* _WIN32 */
215353141Sphilip
216353141Sphilip	dflag = 1;
217353141Sphilip	gflag = 0;
218353141Sphilip
219353141Sphilip	infile = NULL;
220353141Sphilip	Oflag = 1;
221353141Sphilip	snaplen = 68;
222353141Sphilip
223353141Sphilip	if ((cp = strrchr(argv[0], '/')) != NULL)
224353141Sphilip		program_name = cp + 1;
225353141Sphilip	else
226353141Sphilip		program_name = argv[0];
227353141Sphilip
228353141Sphilip	opterr = 0;
229353141Sphilip	while ((op = getopt(argc, argv, "dF:gm:Os:")) != -1) {
230353141Sphilip		switch (op) {
231353141Sphilip
232353141Sphilip		case 'd':
233353141Sphilip			++dflag;
234353141Sphilip			break;
235353141Sphilip
236353141Sphilip		case 'g':
237353141Sphilip#ifdef BDEBUG
238353141Sphilip			++gflag;
239353141Sphilip#else
240353141Sphilip			error("libpcap and filtertest not built with optimizer debugging enabled");
241353141Sphilip#endif
242353141Sphilip			break;
243353141Sphilip
244353141Sphilip		case 'F':
245353141Sphilip			infile = optarg;
246353141Sphilip			break;
247353141Sphilip
248353141Sphilip		case 'O':
249353141Sphilip			Oflag = 0;
250353141Sphilip			break;
251353141Sphilip
252353141Sphilip		case 'm': {
253353141Sphilip			bpf_u_int32 addr;
254353141Sphilip
255353141Sphilip			switch (inet_pton(AF_INET, optarg, &addr)) {
256353141Sphilip
257353141Sphilip			case 0:
258353141Sphilip				error("invalid netmask %s", optarg);
259353141Sphilip				break;
260353141Sphilip
261353141Sphilip			case -1:
262353141Sphilip				error("invalid netmask %s: %s", optarg,
263353141Sphilip				    pcap_strerror(errno));
264353141Sphilip				break;
265353141Sphilip
266353141Sphilip			case 1:
267353141Sphilip				netmask = addr;
268353141Sphilip				break;
269353141Sphilip			}
270353141Sphilip			break;
271353141Sphilip		}
272353141Sphilip
273353141Sphilip		case 's': {
274353141Sphilip			char *end;
275353141Sphilip
276353141Sphilip			snaplen = strtol(optarg, &end, 0);
277353141Sphilip			if (optarg == end || *end != '\0'
278353141Sphilip			    || snaplen < 0 || snaplen > 65535)
279353141Sphilip				error("invalid snaplen %s", optarg);
280353141Sphilip			else if (snaplen == 0)
281353141Sphilip				snaplen = 65535;
282353141Sphilip			break;
283353141Sphilip		}
284353141Sphilip
285353141Sphilip		default:
286353141Sphilip			usage();
287353141Sphilip			/* NOTREACHED */
288353141Sphilip		}
289353141Sphilip	}
290353141Sphilip
291353141Sphilip	if (optind >= argc) {
292353141Sphilip		usage();
293353141Sphilip		/* NOTREACHED */
294353141Sphilip	}
295353141Sphilip
296353141Sphilip	dlt = pcap_datalink_name_to_val(argv[optind]);
297353141Sphilip	if (dlt < 0) {
298353141Sphilip		dlt = (int)strtol(argv[optind], &p, 10);
299353141Sphilip		if (p == argv[optind] || *p != '\0')
300353141Sphilip			error("invalid data link type %s", argv[optind]);
301353141Sphilip	}
302353141Sphilip
303353141Sphilip	if (infile)
304353141Sphilip		cmdbuf = read_infile(infile);
305353141Sphilip	else
306353141Sphilip		cmdbuf = copy_argv(&argv[optind+1]);
307353141Sphilip
308353141Sphilip#ifdef BDEBUG
309353141Sphilip	pcap_set_optimizer_debug(dflag);
310353141Sphilip	pcap_set_print_dot_graph(gflag);
311353141Sphilip#endif
312353141Sphilip
313353141Sphilip	pd = pcap_open_dead(dlt, snaplen);
314353141Sphilip	if (pd == NULL)
315353141Sphilip		error("Can't open fake pcap_t");
316353141Sphilip
317353141Sphilip	if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
318353141Sphilip		error("%s", pcap_geterr(pd));
319353141Sphilip
320353141Sphilip	have_fcode = 1;
321353141Sphilip	if (!bpf_validate(fcode.bf_insns, fcode.bf_len))
322353141Sphilip		warn("Filter doesn't pass validation");
323353141Sphilip
324353141Sphilip#ifdef BDEBUG
325353141Sphilip	if (cmdbuf != NULL) {
326353141Sphilip		// replace line feed with space
327353141Sphilip		for (cp = cmdbuf; *cp != '\0'; ++cp) {
328353141Sphilip			if (*cp == '\r' || *cp == '\n') {
329353141Sphilip				*cp = ' ';
330353141Sphilip			}
331353141Sphilip		}
332353141Sphilip		// only show machine code if BDEBUG defined, since dflag > 3
333353141Sphilip		printf("machine codes for filter: %s\n", cmdbuf);
334353141Sphilip	} else
335353141Sphilip		printf("machine codes for empty filter:\n");
336353141Sphilip#endif
337353141Sphilip
338353141Sphilip	bpf_dump(&fcode, dflag);
339353141Sphilip	free(cmdbuf);
340353141Sphilip	if (have_fcode)
341353141Sphilip		pcap_freecode (&fcode);
342353141Sphilip	pcap_close(pd);
343353141Sphilip	exit(0);
344353141Sphilip}
345353141Sphilip
346353141Sphilipstatic void
347353141Sphilipusage(void)
348353141Sphilip{
349353141Sphilip	(void)fprintf(stderr, "%s, with %s\n", program_name,
350353141Sphilip	    pcap_lib_version());
351353141Sphilip	(void)fprintf(stderr,
352353141Sphilip#ifdef BDEBUG
353353141Sphilip	    "Usage: %s [-dgO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n",
354353141Sphilip#else
355353141Sphilip	    "Usage: %s [-dO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n",
356353141Sphilip#endif
357353141Sphilip	    program_name);
358353141Sphilip	exit(1);
359353141Sphilip}
360