]> The Tcpdump Group git mirrors - libpcap/blobdiff - testprogs/writecaptest.c
CI: Call print_so_deps() on rpcapd in remote enabled build
[libpcap] / testprogs / writecaptest.c
index 5d8c16a9c814e9a5a26d3e243428fe930b7985dc..44bbfd7daadd2ff604784eab69d1619a499948a8 100644 (file)
@@ -76,14 +76,166 @@ stop_capture(int signum _U_)
 }
 #endif
 
-#define COMMAND_OPTIONS        "Li:w:y:"
+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)
 {
-       register int op;
-       register char *cp, *cmdbuf, *device, *savefile = NULL;
+       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;
@@ -108,6 +260,10 @@ main(int argc, char **argv)
        while ((op = getopt(argc, argv, COMMAND_OPTIONS)) != -1) {
                switch (op) {
 
+               case 'D':
+                       show_interfaces = 1;
+                       break;
+
                case 'L':
                        show_dlt_types = 1;
                        break;
@@ -116,6 +272,14 @@ main(int argc, char **argv)
                        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;
@@ -130,6 +294,22 @@ main(int argc, char **argv)
                }
        }
 
+       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);
@@ -176,32 +356,38 @@ main(int argc, char **argv)
 
        *ebuf = '\0';
 
-       pd = pcap_create(device, ebuf);
-       if (pd == NULL)
-               error("%s", ebuf);
-       status = pcap_set_snaplen(pd, 262144);
-       if (status != 0)
-               error("%s: pcap_set_snaplen failed: %s",
-                           device, pcap_statustostr(status));
-       status = pcap_set_timeout(pd, 100);
-       if (status != 0)
-               error("%s: pcap_set_timeout failed: %s",
-                   device, pcap_statustostr(status));
-       status = pcap_activate(pd);
-       if (status < 0) {
+       pd = open_interface(device, snaplen_set, snaplen, ebuf);
+       if (pd == NULL) {
                /*
-                * pcap_activate() failed.
+                * 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.
                 */
-               error("%s: %s\n(%s)", device,
-                   pcap_statustostr(status), pcap_geterr(pd));
-       } else if (status > 0) {
+               devnum = parse_interface_number(device);
+               if (devnum == -1) {
+                       /*
+                        * It's not a number; just report
+                        * the open error and fail.
+                        */
+                       error("%s", ebuf);
+               }
+
                /*
-                * pcap_activate() succeeded, but it's warning us
-                * of a problem it had.
+                * 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.
                 */
-               warning("%s: %s\n(%s)", device,
-                   pcap_statustostr(status), pcap_geterr(pd));
+               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;
@@ -216,13 +402,21 @@ main(int argc, char **argv)
                        error("%s: %s", device, pcap_geterr(pd));
        }
 
-       cmdbuf = copy_argv(&argv[optind]);
+       /*
+        * 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_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
+                       error("%s", pcap_geterr(pd));
 
-       if (pcap_setfilter(pd, &fcode) < 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)
@@ -253,9 +447,13 @@ main(int argc, char **argv)
                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 (pcap_stats(pd, &ps) < 0) {
+                               (void)fprintf(stderr, "pcap_stats: %s\n",
+                                   pcap_geterr(pd));
+                       } else {
+                               printf("%d ps_recv, %d ps_drop, %d ps_ifdrop\n",
+                                   ps.ps_recv, ps.ps_drop, ps.ps_ifdrop);
+                       }
                }
        }
        if (status == -2) {
@@ -276,15 +474,17 @@ main(int argc, char **argv)
                    program_name, pcap_geterr(pd));
        }
        pcap_close(pd);
-       pcap_freecode(&fcode);
-       free(cmdbuf);
+       if (cmdbuf != NULL) {
+               pcap_freecode(&fcode);
+               free(cmdbuf);
+       }
        exit(status == -1 ? 1 : 0);
 }
 
 static void
 usage(void)
 {
-       (void)fprintf(stderr, "Usage: %s -L [ -i interface ] [ -w file ] [ -y dlt ] [expression]\n",
+       (void)fprintf(stderr, "Usage: %s -D -L [ -i interface ] [ -s snaplen ] [ -w file ] [ -y dlt ] [expression]\n",
            program_name);
        exit(1);
 }