1230832Sgnn/*
2230832Sgnn * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
3230832Sgnn *	The Regents of the University of California.  All rights reserved.
4230832Sgnn *
5230832Sgnn * Redistribution and use in source and binary forms, with or without
6230832Sgnn * modification, are permitted provided that: (1) source code distributions
7230832Sgnn * retain the above copyright notice and this paragraph in its entirety, (2)
8230832Sgnn * distributions including binary code include the above copyright notice and
9230832Sgnn * this paragraph in its entirety in the documentation or other materials
10230832Sgnn * provided with the distribution, and (3) all advertising materials mentioning
11230832Sgnn * features or use of this software display the following acknowledgement:
12230832Sgnn * ``This product includes software developed by the University of California,
13230832Sgnn * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14230832Sgnn * the University nor the names of its contributors may be used to endorse
15230832Sgnn * or promote products derived from this software without specific prior
16230832Sgnn * written permission.
17230832Sgnn * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18230832Sgnn * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19230832Sgnn * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20230832Sgnn */
21230832Sgnn
22230832Sgnn#ifndef lint
23230832Sgnnstatic const char copyright[] =
24230832Sgnn    "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
25230832SgnnThe Regents of the University of California.  All rights reserved.\n";
26230832Sgnn#endif
27230832Sgnn
28230832Sgnn#include <pcap.h>
29230832Sgnn#include <stdio.h>
30230832Sgnn#include <stdlib.h>
31230832Sgnn#include <string.h>
32230832Sgnn#include <stdarg.h>
33230832Sgnn#include <unistd.h>
34230832Sgnn#include <errno.h>
35230832Sgnn#include <sys/types.h>
36230832Sgnn#include <sys/select.h>
37230832Sgnn#include <poll.h>
38230832Sgnn
39230832Sgnnchar *program_name;
40230832Sgnn
41230832Sgnn/* Forwards */
42230832Sgnnstatic void countme(u_char *, const struct pcap_pkthdr *, const u_char *);
43230832Sgnnstatic void usage(void) __attribute__((noreturn));
44230832Sgnnstatic void error(const char *, ...);
45230832Sgnnstatic void warning(const char *, ...);
46230832Sgnnstatic char *copy_argv(char **);
47230832Sgnn
48230832Sgnnstatic pcap_t *pd;
49230832Sgnn
50230832Sgnnextern int optind;
51230832Sgnnextern int opterr;
52230832Sgnnextern char *optarg;
53230832Sgnn
54230832Sgnnint
55230832Sgnnmain(int argc, char **argv)
56230832Sgnn{
57230832Sgnn	register int op;
58230832Sgnn	bpf_u_int32 localnet, netmask;
59230832Sgnn	register char *cp, *cmdbuf, *device;
60230832Sgnn	struct bpf_program fcode;
61230832Sgnn	char ebuf[PCAP_ERRBUF_SIZE];
62230832Sgnn	int status;
63230832Sgnn	int packet_count;
64230832Sgnn
65230832Sgnn	device = NULL;
66230832Sgnn	if ((cp = strrchr(argv[0], '/')) != NULL)
67230832Sgnn		program_name = cp + 1;
68230832Sgnn	else
69230832Sgnn		program_name = argv[0];
70230832Sgnn
71230832Sgnn	opterr = 0;
72230832Sgnn	while ((op = getopt(argc, argv, "i:")) != -1) {
73230832Sgnn		switch (op) {
74230832Sgnn
75230832Sgnn		case 'i':
76230832Sgnn			device = optarg;
77230832Sgnn			break;
78230832Sgnn
79230832Sgnn		default:
80230832Sgnn			usage();
81230832Sgnn			/* NOTREACHED */
82230832Sgnn		}
83230832Sgnn	}
84230832Sgnn
85230832Sgnn	if (device == NULL) {
86230832Sgnn		device = pcap_lookupdev(ebuf);
87230832Sgnn		if (device == NULL)
88230832Sgnn			error("%s", ebuf);
89230832Sgnn	}
90230832Sgnn	*ebuf = '\0';
91230832Sgnn	pd = pcap_open_live(device, 65535, 0, 1000, ebuf);
92230832Sgnn	if (pd == NULL)
93230832Sgnn		error("%s", ebuf);
94230832Sgnn	else if (*ebuf)
95230832Sgnn		warning("%s", ebuf);
96230832Sgnn	if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
97230832Sgnn		localnet = 0;
98230832Sgnn		netmask = 0;
99230832Sgnn		warning("%s", ebuf);
100230832Sgnn	}
101230832Sgnn	cmdbuf = copy_argv(&argv[optind]);
102230832Sgnn
103230832Sgnn	if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
104230832Sgnn		error("%s", pcap_geterr(pd));
105230832Sgnn
106230832Sgnn	if (pcap_setfilter(pd, &fcode) < 0)
107230832Sgnn		error("%s", pcap_geterr(pd));
108230832Sgnn	if (pcap_setnonblock(pd, 1, ebuf) == -1)
109230832Sgnn		error("pcap_setnonblock failed: %s", ebuf);
110230832Sgnn	printf("Listening on %s\n", device);
111230832Sgnn	for (;;) {
112230832Sgnn		packet_count = 0;
113230832Sgnn		status = pcap_dispatch(pd, -1, countme,
114230832Sgnn		    (u_char *)&packet_count);
115230832Sgnn		if (status < 0)
116230832Sgnn			break;
117230832Sgnn		if (status != 0) {
118230832Sgnn			printf("%d packets seen, %d packets counted after pcap_dispatch returns\n",
119230832Sgnn			    status, packet_count);
120230832Sgnn		}
121230832Sgnn	}
122230832Sgnn	if (status == -2) {
123230832Sgnn		/*
124230832Sgnn		 * We got interrupted, so perhaps we didn't
125230832Sgnn		 * manage to finish a line we were printing.
126230832Sgnn		 * Print an extra newline, just in case.
127230832Sgnn		 */
128230832Sgnn		putchar('\n');
129230832Sgnn	}
130230832Sgnn	(void)fflush(stdout);
131230832Sgnn	if (status == -1) {
132230832Sgnn		/*
133230832Sgnn		 * Error.  Report it.
134230832Sgnn		 */
135230832Sgnn		(void)fprintf(stderr, "%s: pcap_loop: %s\n",
136230832Sgnn		    program_name, pcap_geterr(pd));
137230832Sgnn	}
138230832Sgnn	pcap_close(pd);
139230832Sgnn	exit(status == -1 ? 1 : 0);
140230832Sgnn}
141230832Sgnn
142230832Sgnnstatic void
143230832Sgnncountme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
144230832Sgnn{
145230832Sgnn	int *counterp = (int *)user;
146230832Sgnn
147230832Sgnn	(*counterp)++;
148230832Sgnn}
149230832Sgnn
150230832Sgnnstatic void
151230832Sgnnusage(void)
152230832Sgnn{
153230832Sgnn	(void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n",
154230832Sgnn	    program_name);
155230832Sgnn	exit(1);
156230832Sgnn}
157230832Sgnn
158230832Sgnn/* VARARGS */
159230832Sgnnstatic void
160230832Sgnnerror(const char *fmt, ...)
161230832Sgnn{
162230832Sgnn	va_list ap;
163230832Sgnn
164230832Sgnn	(void)fprintf(stderr, "%s: ", program_name);
165230832Sgnn	va_start(ap, fmt);
166230832Sgnn	(void)vfprintf(stderr, fmt, ap);
167230832Sgnn	va_end(ap);
168230832Sgnn	if (*fmt) {
169230832Sgnn		fmt += strlen(fmt);
170230832Sgnn		if (fmt[-1] != '\n')
171230832Sgnn			(void)fputc('\n', stderr);
172230832Sgnn	}
173230832Sgnn	exit(1);
174230832Sgnn	/* NOTREACHED */
175230832Sgnn}
176230832Sgnn
177230832Sgnn/* VARARGS */
178230832Sgnnstatic void
179230832Sgnnwarning(const char *fmt, ...)
180230832Sgnn{
181230832Sgnn	va_list ap;
182230832Sgnn
183230832Sgnn	(void)fprintf(stderr, "%s: WARNING: ", program_name);
184230832Sgnn	va_start(ap, fmt);
185230832Sgnn	(void)vfprintf(stderr, fmt, ap);
186230832Sgnn	va_end(ap);
187230832Sgnn	if (*fmt) {
188230832Sgnn		fmt += strlen(fmt);
189230832Sgnn		if (fmt[-1] != '\n')
190230832Sgnn			(void)fputc('\n', stderr);
191230832Sgnn	}
192230832Sgnn}
193230832Sgnn
194230832Sgnn/*
195230832Sgnn * Copy arg vector into a new buffer, concatenating arguments with spaces.
196230832Sgnn */
197230832Sgnnstatic char *
198230832Sgnncopy_argv(register char **argv)
199230832Sgnn{
200230832Sgnn	register char **p;
201230832Sgnn	register u_int len = 0;
202230832Sgnn	char *buf;
203230832Sgnn	char *src, *dst;
204230832Sgnn
205230832Sgnn	p = argv;
206230832Sgnn	if (*p == 0)
207230832Sgnn		return 0;
208230832Sgnn
209230832Sgnn	while (*p)
210230832Sgnn		len += strlen(*p++) + 1;
211230832Sgnn
212230832Sgnn	buf = (char *)malloc(len);
213230832Sgnn	if (buf == NULL)
214230832Sgnn		error("copy_argv: malloc");
215230832Sgnn
216230832Sgnn	p = argv;
217230832Sgnn	dst = buf;
218230832Sgnn	while ((src = *p++) != NULL) {
219230832Sgnn		while ((*dst++ = *src++) != '\0')
220230832Sgnn			;
221230832Sgnn		dst[-1] = ' ';
222230832Sgnn	}
223230832Sgnn	dst[-1] = '\0';
224230832Sgnn
225230832Sgnn	return buf;
226230832Sgnn}
227