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[] = 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 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <stdarg.h> 32 #include <limits.h> 33 #include <unistd.h> 34 #include <errno.h> 35 #include <sys/types.h> 36 #include <sys/select.h> 37 #include <poll.h> 38 39 #include <pcap.h> 40 41 static char *program_name; 42 43 /* Forwards */ 44 static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); 45 static void usage(void) __attribute__((noreturn)); 46 static void error(const char *, ...); 47 static void warning(const char *, ...); 48 static char *copy_argv(char **); 49 50 static pcap_t *pd; 51 52 extern int optind; 53 extern int opterr; 54 extern char *optarg; 55 56 int 57 main(int argc, char **argv) 58 { 59 register int op; 60 register char *cp, *cmdbuf, *device; 61 long longarg; 62 char *p; 63 int timeout = 1000; 64 int immediate = 0; 65 int nonblock = 0; 66 bpf_u_int32 localnet, netmask; 67 struct bpf_program fcode; 68 char ebuf[PCAP_ERRBUF_SIZE]; 69 int status; 70 int packet_count; 71 72 device = NULL; 73 if ((cp = strrchr(argv[0], '/')) != NULL) 74 program_name = cp + 1; 75 else 76 program_name = argv[0]; 77 78 opterr = 0; 79 while ((op = getopt(argc, argv, "i:mnt:")) != -1) { 80 switch (op) { 81 82 case 'i': 83 device = optarg; 84 break; 85 86 case 'm': 87 immediate = 1; 88 break; 89 90 case 'n': 91 nonblock = 1; 92 break; 93 94 case 't': 95 longarg = strtol(optarg, &p, 10); 96 if (p == optarg || *p != '\0') { 97 error("Timeout value \"%s\" is not a number", 98 optarg); 99 /* NOTREACHED */ 100 } 101 if (longarg < 0) { 102 error("Timeout value %ld is negative", longarg); 103 /* NOTREACHED */ 104 } 105 if (longarg > INT_MAX) { 106 error("Timeout value %ld is too large (> %d)", 107 longarg, INT_MAX); 108 /* NOTREACHED */ 109 } 110 timeout = (int)longarg; 111 break; 112 113 default: 114 usage(); 115 /* NOTREACHED */ 116 } 117 } 118 119 if (device == NULL) { 120 device = pcap_lookupdev(ebuf); 121 if (device == NULL) 122 error("%s", ebuf); 123 } 124 *ebuf = '\0'; 125 pd = pcap_create(device, ebuf); 126 if (pd == NULL) 127 error("%s", ebuf); 128 status = pcap_set_snaplen(pd, 65535); 129 if (status != 0) 130 error("%s: pcap_set_snaplen failed: %s", 131 device, pcap_statustostr(status)); 132 if (immediate) { 133 status = pcap_set_immediate_mode(pd, 1); 134 if (status != 0) 135 error("%s: pcap_set_immediate_mode failed: %s", 136 device, pcap_statustostr(status)); 137 } 138 status = pcap_set_timeout(pd, timeout); 139 if (status != 0) 140 error("%s: pcap_set_timeout failed: %s", 141 device, pcap_statustostr(status)); 142 status = pcap_activate(pd); 143 if (status < 0) { 144 /* 145 * pcap_activate() failed. 146 */ 147 error("%s: %s\n(%s)", device, 148 pcap_statustostr(status), pcap_geterr(pd)); 149 } else if (status > 0) { 150 /* 151 * pcap_activate() succeeded, but it's warning us 152 * of a problem it had. 153 */ 154 warning("%s: %s\n(%s)", device, 155 pcap_statustostr(status), pcap_geterr(pd)); 156 } 157 if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { 158 localnet = 0; 159 netmask = 0; 160 warning("%s", ebuf); 161 } 162 cmdbuf = copy_argv(&argv[optind]); 163 164 if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) 165 error("%s", pcap_geterr(pd)); 166 167 if (pcap_setfilter(pd, &fcode) < 0) 168 error("%s", pcap_geterr(pd)); 169 if (pcap_setnonblock(pd, nonblock, ebuf) == -1) 170 error("pcap_setnonblock failed: %s", ebuf); 171 printf("Listening on %s\n", device); 172 for (;;) { 173 packet_count = 0; 174 status = pcap_dispatch(pd, -1, countme, 175 (u_char *)&packet_count); 176 if (status < 0) 177 break; 178 if (status != 0) { 179 printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", 180 status, packet_count); 181 } 182 } 183 if (status == -2) { 184 /* 185 * We got interrupted, so perhaps we didn't 186 * manage to finish a line we were printing. 187 * Print an extra newline, just in case. 188 */ 189 putchar('\n'); 190 } 191 (void)fflush(stdout); 192 if (status == -1) { 193 /* 194 * Error. Report it. 195 */ 196 (void)fprintf(stderr, "%s: pcap_loop: %s\n", 197 program_name, pcap_geterr(pd)); 198 } 199 pcap_close(pd); 200 exit(status == -1 ? 1 : 0); 201 } 202 203 static void 204 countme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) 205 { 206 int *counterp = (int *)user; 207 208 (*counterp)++; 209 } 210 211 static void 212 usage(void) 213 { 214 (void)fprintf(stderr, "Usage: %s [ -mn ] [ -i interface ] [ -t timeout] [expression]\n", 215 program_name); 216 exit(1); 217 } 218 219 /* VARARGS */ 220 static void 221 error(const char *fmt, ...) 222 { 223 va_list ap; 224 225 (void)fprintf(stderr, "%s: ", program_name); 226 va_start(ap, fmt); 227 (void)vfprintf(stderr, fmt, ap); 228 va_end(ap); 229 if (*fmt) { 230 fmt += strlen(fmt); 231 if (fmt[-1] != '\n') 232 (void)fputc('\n', stderr); 233 } 234 exit(1); 235 /* NOTREACHED */ 236 } 237 238 /* VARARGS */ 239 static void 240 warning(const char *fmt, ...) 241 { 242 va_list ap; 243 244 (void)fprintf(stderr, "%s: WARNING: ", program_name); 245 va_start(ap, fmt); 246 (void)vfprintf(stderr, fmt, ap); 247 va_end(ap); 248 if (*fmt) { 249 fmt += strlen(fmt); 250 if (fmt[-1] != '\n') 251 (void)fputc('\n', stderr); 252 } 253 } 254 255 /* 256 * Copy arg vector into a new buffer, concatenating arguments with spaces. 257 */ 258 static char * 259 copy_argv(register char **argv) 260 { 261 register char **p; 262 register u_int len = 0; 263 char *buf; 264 char *src, *dst; 265 266 p = argv; 267 if (*p == 0) 268 return 0; 269 270 while (*p) 271 len += strlen(*p++) + 1; 272 273 buf = (char *)malloc(len); 274 if (buf == NULL) 275 error("copy_argv: malloc"); 276 277 p = argv; 278 dst = buf; 279 while ((src = *p++) != NULL) { 280 while ((*dst++ = *src++) != '\0') 281 ; 282 dst[-1] = ' '; 283 } 284 dst[-1] = '\0'; 285 286 return buf; 287 } 288