aboutsummaryrefslogtreecommitdiff
path: root/contrib/libpcap/testprogs/writecaptest.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/libpcap/testprogs/writecaptest.c')
-rw-r--r--contrib/libpcap/testprogs/writecaptest.c556
1 files changed, 556 insertions, 0 deletions
diff --git a/contrib/libpcap/testprogs/writecaptest.c b/contrib/libpcap/testprogs/writecaptest.c
new file mode 100644
index 000000000000..4db532c6e621
--- /dev/null
+++ b/contrib/libpcap/testprogs/writecaptest.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "varattrs.h"
+
+#ifndef lint
+static const char copyright[] _U_ =
+ "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
+The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#ifdef _WIN32
+ #include "getopt.h"
+#else
+ #include <unistd.h>
+#endif
+#include <errno.h>
+#ifndef _WIN32
+ #include <signal.h>
+#endif
+#include <sys/types.h>
+
+#include <pcap.h>
+
+#include "pcap/funcattrs.h"
+
+#ifdef _WIN32
+ #include "portability.h"
+#endif
+
+static char *program_name;
+
+/* Forwards */
+static void PCAP_NORETURN usage(void);
+static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2);
+static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2);
+static char *copy_argv(char **);
+
+static pcap_t *pd;
+
+#ifdef _WIN32
+static BOOL WINAPI
+stop_capture(DWORD ctrltype _U_)
+{
+ pcap_breakloop(pd);
+ return TRUE;
+}
+#else
+static void
+stop_capture(int signum _U_)
+{
+ pcap_breakloop(pd);
+}
+#endif
+
+static long
+parse_interface_number(const char *device)
+{
+ const char *p;
+ long devnum;
+ char *end;
+
+ /*
+ * Search for a colon, terminating any scheme at the beginning
+ * of the device.
+ */
+ p = strchr(device, ':');
+ if (p != NULL) {
+ /*
+ * We found it. Is it followed by "//"?
+ */
+ p++; /* skip the : */
+ if (strncmp(p, "//", 2) == 0) {
+ /*
+ * Yes. Search for the next /, at the end of the
+ * authority part of the URL.
+ */
+ p += 2; /* skip the // */
+ p = strchr(p, '/');
+ if (p != NULL) {
+ /*
+ * OK, past the / is the path.
+ */
+ device = p + 1;
+ }
+ }
+ }
+ devnum = strtol(device, &end, 10);
+ if (device != end && *end == '\0') {
+ /*
+ * It's all-numeric, but is it a valid number?
+ */
+ if (devnum <= 0) {
+ /*
+ * No, it's not an ordinal.
+ */
+ error("Invalid adapter index");
+ }
+ return (devnum);
+ } else {
+ /*
+ * It's not all-numeric; return -1, so our caller
+ * knows that.
+ */
+ return (-1);
+ }
+}
+
+static char *
+find_interface_by_number(long devnum)
+{
+ pcap_if_t *dev, *devlist;
+ long i;
+ char ebuf[PCAP_ERRBUF_SIZE];
+ char *device;
+ int status;
+
+ status = pcap_findalldevs(&devlist, ebuf);
+ if (status < 0)
+ error("%s", ebuf);
+ /*
+ * Look for the devnum-th entry in the list of devices (1-based).
+ */
+ for (i = 0, dev = devlist; i < devnum-1 && dev != NULL;
+ i++, dev = dev->next)
+ ;
+ if (dev == NULL)
+ error("Invalid adapter index");
+ device = strdup(dev->name);
+ pcap_freealldevs(devlist);
+ return (device);
+}
+
+static pcap_t *
+open_interface(const char *device, int snaplen_set, int snaplen, char *ebuf)
+{
+ pcap_t *pc;
+ int status;
+ char *cp;
+
+ pc = pcap_create(device, ebuf);
+ if (pc == NULL) {
+ /*
+ * If this failed with "No such device", that means
+ * the interface doesn't exist; return NULL, so that
+ * the caller can see whether the device name is
+ * actually an interface index.
+ */
+ if (strstr(ebuf, "No such device") != NULL)
+ return (NULL);
+ error("%s", ebuf);
+ }
+ if (snaplen_set) {
+ status = pcap_set_snaplen(pc, snaplen);
+ if (status != 0)
+ error("%s: pcap_set_snaplen failed: %s",
+ device, pcap_statustostr(status));
+ }
+ status = pcap_set_timeout(pc, 100);
+ if (status != 0)
+ error("%s: pcap_set_timeout failed: %s",
+ device, pcap_statustostr(status));
+ status = pcap_activate(pc);
+ if (status < 0) {
+ /*
+ * pcap_activate() failed.
+ */
+ cp = pcap_geterr(pc);
+ if (status == PCAP_ERROR)
+ error("%s", cp);
+ else if (status == PCAP_ERROR_NO_SUCH_DEVICE) {
+ /*
+ * Return an error for our caller to handle.
+ */
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s\n(%s)",
+ device, pcap_statustostr(status), cp);
+ } else if (status == PCAP_ERROR_PERM_DENIED && *cp != '\0')
+ error("%s: %s\n(%s)", device,
+ pcap_statustostr(status), cp);
+ else
+ error("%s: %s", device,
+ pcap_statustostr(status));
+ pcap_close(pc);
+ return (NULL);
+ } else if (status > 0) {
+ /*
+ * pcap_activate() succeeded, but it's warning us
+ * of a problem it had.
+ */
+ cp = pcap_geterr(pc);
+ if (status == PCAP_WARNING)
+ warning("%s", cp);
+ else if (status == PCAP_WARNING_PROMISC_NOTSUP &&
+ *cp != '\0')
+ warning("%s: %s\n(%s)", device,
+ pcap_statustostr(status), cp);
+ else
+ warning("%s: %s", device,
+ pcap_statustostr(status));
+ }
+ return (pc);
+}
+
+#define COMMAND_OPTIONS "DLi:s:w:y:"
+
+int
+main(int argc, char **argv)
+{
+ int op;
+ char *cp, *cmdbuf = NULL, *device, *end, *savefile = NULL;
+ int snaplen = 0;
+ int snaplen_set = 0;
+ pcap_if_t *devlist;
+ long devnum;
+ int show_interfaces = 0;
+ int show_dlt_types = 0;
+ int ndlts;
+ int *dlts;
+ bpf_u_int32 localnet, netmask;
+ struct bpf_program fcode;
+ char ebuf[PCAP_ERRBUF_SIZE];
+#ifndef _WIN32
+ struct sigaction action;
+#endif
+ int dlt;
+ const char *dlt_name = NULL;
+ int status;
+ pcap_dumper_t *pdd;
+
+ device = NULL;
+ if ((cp = strrchr(argv[0], '/')) != NULL)
+ program_name = cp + 1;
+ else
+ program_name = argv[0];
+
+ opterr = 0;
+ while ((op = getopt(argc, argv, COMMAND_OPTIONS)) != -1) {
+ switch (op) {
+
+ case 'D':
+ show_interfaces = 1;
+ break;
+
+ case 'L':
+ show_dlt_types = 1;
+ break;
+
+ case 'i':
+ device = optarg;
+ break;
+
+ case 's':
+ snaplen = (int)strtol(optarg, &end, 0);
+ if (optarg == end || *end != '\0' || snaplen < 0)
+ error("invalid snaplen %s (must be >= 0)",
+ optarg);
+ snaplen_set = 1;
+ break;
+
+ case 'w':
+ savefile = optarg;
+ break;
+
+ case 'y':
+ dlt_name = optarg;
+ break;
+
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+
+ if (show_interfaces) {
+ pcap_if_t *dev;
+ int i;
+
+ if (pcap_findalldevs(&devlist, ebuf) < 0)
+ error("%s", ebuf);
+ for (i = 0, dev = devlist; dev != NULL; i++, dev = dev->next) {
+ printf("%d.%s", i+1, dev->name);
+ if (dev->description != NULL)
+ printf(" (%s)", dev->description);
+ printf("\n");
+ }
+ pcap_freealldevs(devlist);
+ return (0);
+ }
+
+ if (device == NULL) {
+ if (pcap_findalldevs(&devlist, ebuf) == -1)
+ error("%s", ebuf);
+ if (devlist == NULL)
+ error("no interfaces available for capture");
+ device = strdup(devlist->name);
+ pcap_freealldevs(devlist);
+ }
+ if (show_dlt_types) {
+ pd = pcap_create(device, ebuf);
+ if (pd == NULL)
+ error("%s", ebuf);
+ status = pcap_activate(pd);
+ if (status < 0) {
+ /*
+ * pcap_activate() failed.
+ */
+ error("%s: %s\n(%s)", device,
+ pcap_statustostr(status), pcap_geterr(pd));
+ }
+ ndlts = pcap_list_datalinks(pd, &dlts);
+ if (ndlts < 0) {
+ /*
+ * pcap_list_datalinks() failed.
+ */
+ error("%s: %s\n(%s)", device,
+ pcap_statustostr(status), pcap_geterr(pd));
+ }
+ for (int i = 0; i < ndlts; i++) {
+ dlt_name = pcap_datalink_val_to_name(dlts[i]);
+ if (dlt_name == NULL)
+ printf("DLT %d", dlts[i]);
+ else
+ printf("%s", dlt_name);
+ printf("\n");
+ }
+ pcap_free_datalinks(dlts);
+ pcap_close(pd);
+ return 0;
+ }
+
+ if (savefile == NULL)
+ error("no savefile specified");
+
+ *ebuf = '\0';
+
+ pd = open_interface(device, snaplen_set, snaplen, ebuf);
+ if (pd == NULL) {
+ /*
+ * That failed because the interface couldn't be found.
+ *
+ * If we can get a list of interfaces, and the interface name
+ * is purely numeric, try to use it as a 1-based index
+ * in the list of interfaces.
+ */
+ devnum = parse_interface_number(device);
+ if (devnum == -1) {
+ /*
+ * It's not a number; just report
+ * the open error and fail.
+ */
+ error("%s", ebuf);
+ }
+
+ /*
+ * OK, it's a number; try to find the
+ * interface with that index, and try
+ * to open it.
+ *
+ * find_interface_by_number() exits if it
+ * couldn't be found.
+ */
+ device = find_interface_by_number(devnum);
+ pd = open_interface(device, snaplen_set, snaplen, ebuf);
+ if (pd == NULL)
+ error("%s", ebuf);
+ }
+
+ if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
+ localnet = 0;
+ netmask = 0;
+ warning("%s", ebuf);
+ }
+
+ if (dlt_name != NULL) {
+ dlt = pcap_datalink_name_to_val(dlt_name);
+ if (dlt == PCAP_ERROR)
+ error("%s isn't a valid DLT name", dlt_name);
+ if (pcap_set_datalink(pd, dlt) == PCAP_ERROR)
+ error("%s: %s", device, pcap_geterr(pd));
+ }
+
+ /*
+ * Don't set a filter unless we were given one on the
+ * command line; if capturing doesn't work, or doesn't
+ * use the snapshot length, without a filter, that's
+ * a bug.
+ */
+ if (optind < argc) {
+ cmdbuf = copy_argv(&argv[optind]);
+
+ if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
+ error("%s", pcap_geterr(pd));
+
+ if (pcap_setfilter(pd, &fcode) < 0)
+ error("%s", pcap_geterr(pd));
+ }
+
+ pdd = pcap_dump_open(pd, savefile);
+ if (pdd == NULL)
+ error("%s", pcap_geterr(pd));
+
+#ifdef _WIN32
+ SetConsoleCtrlHandler(stop_capture, TRUE);
+#else
+ action.sa_handler = stop_capture;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ if (sigaction(SIGINT, &action, NULL) == -1)
+ error("Can't catch SIGINT: %s\n", strerror(errno));
+#endif
+
+ printf("Listening on %s, link-type ", device);
+ dlt = pcap_datalink(pd);
+ dlt_name = pcap_datalink_val_to_name(dlt);
+ if (dlt_name == NULL)
+ printf("DLT %d", dlt);
+ else
+ printf("%s", dlt_name);
+ printf("\n");
+ for (;;) {
+ status = pcap_dispatch(pd, -1, pcap_dump, (u_char *)pdd);
+ if (status < 0)
+ break;
+ if (status != 0) {
+ printf("%d packets seen\n", status);
+ struct pcap_stat ps;
+ pcap_stats(pd, &ps);
+ printf("%d ps_recv, %d ps_drop, %d ps_ifdrop\n",
+ ps.ps_recv, ps.ps_drop, ps.ps_ifdrop);
+ }
+ }
+ if (status == -2) {
+ /*
+ * We got interrupted, so perhaps we didn't
+ * manage to finish a line we were printing.
+ * Print an extra newline, just in case.
+ */
+ putchar('\n');
+ printf("Broken out of loop from SIGINT handler\n");
+ }
+ (void)fflush(stdout);
+ if (status == -1) {
+ /*
+ * Error. Report it.
+ */
+ (void)fprintf(stderr, "%s: pcap_dispatch: %s\n",
+ program_name, pcap_geterr(pd));
+ }
+ pcap_close(pd);
+ if (cmdbuf != NULL) {
+ pcap_freecode(&fcode);
+ free(cmdbuf);
+ }
+ exit(status == -1 ? 1 : 0);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "Usage: %s -D -L [ -i interface ] [ -s snaplen ] [ -w file ] [ -y dlt ] [expression]\n",
+ program_name);
+ exit(1);
+}
+
+/* VARARGS */
+static void
+error(const char *fmt, ...)
+{
+ va_list ap;
+
+ (void)fprintf(stderr, "%s: ", program_name);
+ va_start(ap, fmt);
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ if (*fmt) {
+ fmt += strlen(fmt);
+ if (fmt[-1] != '\n')
+ (void)fputc('\n', stderr);
+ }
+ exit(1);
+ /* NOTREACHED */
+}
+
+/* VARARGS */
+static void
+warning(const char *fmt, ...)
+{
+ va_list ap;
+
+ (void)fprintf(stderr, "%s: WARNING: ", program_name);
+ va_start(ap, fmt);
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ if (*fmt) {
+ fmt += strlen(fmt);
+ if (fmt[-1] != '\n')
+ (void)fputc('\n', stderr);
+ }
+}
+
+/*
+ * Copy arg vector into a new buffer, concatenating arguments with spaces.
+ */
+static char *
+copy_argv(register char **argv)
+{
+ register char **p;
+ register size_t len = 0;
+ char *buf;
+ char *src, *dst;
+
+ p = argv;
+ if (*p == 0)
+ return 0;
+
+ while (*p)
+ len += strlen(*p++) + 1;
+
+ buf = (char *)malloc(len);
+ if (buf == NULL)
+ error("copy_argv: malloc");
+
+ p = argv;
+ dst = buf;
+ while ((src = *p++) != NULL) {
+ while ((*dst++ = *src++) != '\0')
+ ;
+ dst[-1] = ' ';
+ }
+ dst[-1] = '\0';
+
+ return buf;
+}