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
23static const char copyright[] =
24    "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
25The Regents of the University of California.  All rights reserved.\n";
26#endif
27
28#include <pcap.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdarg.h>
33#include <unistd.h>
34#include <errno.h>
35#include <sys/types.h>
36#include <sys/select.h>
37#include <poll.h>
38
39char *program_name;
40
41/* Forwards */
42static void countme(u_char *, const struct pcap_pkthdr *, const u_char *);
43static void usage(void) __attribute__((noreturn));
44static void error(const char *, ...);
45static void warning(const char *, ...);
46static char *copy_argv(char **);
47
48static pcap_t *pd;
49
50extern int optind;
51extern int opterr;
52extern char *optarg;
53
54int
55main(int argc, char **argv)
56{
57	register int op;
58	bpf_u_int32 localnet, netmask;
59	register char *cp, *cmdbuf, *device;
60	struct bpf_program fcode;
61	char ebuf[PCAP_ERRBUF_SIZE];
62	int status;
63	int packet_count;
64
65	device = NULL;
66	if ((cp = strrchr(argv[0], '/')) != NULL)
67		program_name = cp + 1;
68	else
69		program_name = argv[0];
70
71	opterr = 0;
72	while ((op = getopt(argc, argv, "i:")) != -1) {
73		switch (op) {
74
75		case 'i':
76			device = optarg;
77			break;
78
79		default:
80			usage();
81			/* NOTREACHED */
82		}
83	}
84
85	if (device == NULL) {
86		device = pcap_lookupdev(ebuf);
87		if (device == NULL)
88			error("%s", ebuf);
89	}
90	*ebuf = '\0';
91	pd = pcap_open_live(device, 65535, 0, 1000, ebuf);
92	if (pd == NULL)
93		error("%s", ebuf);
94	else if (*ebuf)
95		warning("%s", ebuf);
96	if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
97		localnet = 0;
98		netmask = 0;
99		warning("%s", ebuf);
100	}
101	cmdbuf = copy_argv(&argv[optind]);
102
103	if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
104		error("%s", pcap_geterr(pd));
105
106	if (pcap_setfilter(pd, &fcode) < 0)
107		error("%s", pcap_geterr(pd));
108	if (pcap_setnonblock(pd, 1, ebuf) == -1)
109		error("pcap_setnonblock failed: %s", ebuf);
110	printf("Listening on %s\n", device);
111	for (;;) {
112		packet_count = 0;
113		status = pcap_dispatch(pd, -1, countme,
114		    (u_char *)&packet_count);
115		if (status < 0)
116			break;
117		if (status != 0) {
118			printf("%d packets seen, %d packets counted after pcap_dispatch returns\n",
119			    status, packet_count);
120		}
121	}
122	if (status == -2) {
123		/*
124		 * We got interrupted, so perhaps we didn't
125		 * manage to finish a line we were printing.
126		 * Print an extra newline, just in case.
127		 */
128		putchar('\n');
129	}
130	(void)fflush(stdout);
131	if (status == -1) {
132		/*
133		 * Error.  Report it.
134		 */
135		(void)fprintf(stderr, "%s: pcap_loop: %s\n",
136		    program_name, pcap_geterr(pd));
137	}
138	pcap_close(pd);
139	exit(status == -1 ? 1 : 0);
140}
141
142static void
143countme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
144{
145	int *counterp = (int *)user;
146
147	(*counterp)++;
148}
149
150static void
151usage(void)
152{
153	(void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n",
154	    program_name);
155	exit(1);
156}
157
158/* VARARGS */
159static void
160error(const char *fmt, ...)
161{
162	va_list ap;
163
164	(void)fprintf(stderr, "%s: ", program_name);
165	va_start(ap, fmt);
166	(void)vfprintf(stderr, fmt, ap);
167	va_end(ap);
168	if (*fmt) {
169		fmt += strlen(fmt);
170		if (fmt[-1] != '\n')
171			(void)fputc('\n', stderr);
172	}
173	exit(1);
174	/* NOTREACHED */
175}
176
177/* VARARGS */
178static void
179warning(const char *fmt, ...)
180{
181	va_list ap;
182
183	(void)fprintf(stderr, "%s: WARNING: ", 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}
193
194/*
195 * Copy arg vector into a new buffer, concatenating arguments with spaces.
196 */
197static char *
198copy_argv(register char **argv)
199{
200	register char **p;
201	register u_int len = 0;
202	char *buf;
203	char *src, *dst;
204
205	p = argv;
206	if (*p == 0)
207		return 0;
208
209	while (*p)
210		len += strlen(*p++) + 1;
211
212	buf = (char *)malloc(len);
213	if (buf == NULL)
214		error("copy_argv: malloc");
215
216	p = argv;
217	dst = buf;
218	while ((src = *p++) != NULL) {
219		while ((*dst++ = *src++) != '\0')
220			;
221		dst[-1] = ' ';
222	}
223	dst[-1] = '\0';
224
225	return buf;
226}
227