]> The Tcpdump Group git mirrors - libpcap/blobdiff - fad-getad.c
Update config.{guess,sub}, timestamps 2023-01-01,2023-01-21
[libpcap] / fad-getad.c
index 9aca411bdbed337dd1055ec3b0d61de9365f45d6..ba8f97538a5895126d13a46ef5a2b88842e53062 100644 (file)
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/fad-getad.c,v 1.12 2007-09-14 00:44:55 guy Exp $ (LBL)";
-#endif
-
 #ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <config.h>
 #endif
 
 #include <sys/types.h>
@@ -47,7 +42,6 @@ static const char rcsid[] _U_ =
 
 #include <net/if.h>
 
-#include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -60,13 +54,28 @@ static const char rcsid[] _U_ =
 #include "os-proto.h"
 #endif
 
-#ifdef AF_PACKET
+/*
+ * We don't do this on Solaris 11 and later, as it appears there aren't
+ * any AF_PACKET addresses on interfaces, so we don't need this, and
+ * we end up including both the OS's <net/bpf.h> and our <pcap/bpf.h>,
+ * and their definitions of some data structures collide.
+ */
+#if (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET)
+# ifdef HAVE_NETPACKET_PACKET_H
+/* Linux distributions with newer glibc */
+#  include <netpacket/packet.h>
+# else /* HAVE_NETPACKET_PACKET_H */
+/* LynxOS, Linux distributions with older glibc */
 # ifdef __Lynx__
-#  include <netpacket/if_packet.h>     /* LynxOS */
-# else
-#  include <linux/if_packet.h>         /* Linux */
-# endif
-#endif
+/* LynxOS */
+#  include <netpacket/if_packet.h>
+# else /* __Lynx__ */
+/* Linux */
+#  include <linux/types.h>
+#  include <linux/if_packet.h>
+# endif /* __Lynx__ */
+# endif /* HAVE_NETPACKET_PACKET_H */
+#endif /* (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET) */
 
 /*
  * This is fun.
@@ -92,10 +101,10 @@ static const char rcsid[] _U_ =
  * all those systems we have "struct sockaddr_storage".
  */
 #ifndef SA_LEN
-#ifdef HAVE_SOCKADDR_SA_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
 #define SA_LEN(addr)   ((addr)->sa_len)
-#else /* HAVE_SOCKADDR_SA_LEN */
-#ifdef HAVE_SOCKADDR_STORAGE
+#else /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
 static size_t
 get_sa_len(struct sockaddr *addr)
 {
@@ -111,7 +120,7 @@ get_sa_len(struct sockaddr *addr)
                return (sizeof (struct sockaddr_in6));
 #endif
 
-#ifdef AF_PACKET
+#if (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET)
        case AF_PACKET:
                return (sizeof (struct sockaddr_ll));
 #endif
@@ -121,24 +130,22 @@ get_sa_len(struct sockaddr *addr)
        }
 }
 #define SA_LEN(addr)   (get_sa_len(addr))
-#else /* HAVE_SOCKADDR_STORAGE */
+#else /* HAVE_STRUCT_SOCKADDR_STORAGE */
 #define SA_LEN(addr)   (sizeof (struct sockaddr))
-#endif /* HAVE_SOCKADDR_STORAGE */
-#endif /* HAVE_SOCKADDR_SA_LEN */
+#endif /* HAVE_STRUCT_SOCKADDR_STORAGE */
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
 #endif /* SA_LEN */
 
 /*
  * Get a list of all interfaces that are up and that we can open.
  * Returns -1 on error, 0 otherwise.
  * The list, as returned through "alldevsp", may be null if no interfaces
- * were up and could be opened.
- *
- * This is the implementation used on platforms that have "getifaddrs()".
+ * could be opened.
  */
 int
-pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
+pcap_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,
+    int (*check_usable)(const char *), get_if_flags_func get_flags_func)
 {
-       pcap_if_t *devlist = NULL;
        struct ifaddrs *ifap, *ifa;
        struct sockaddr *addr, *netmask, *broadaddr, *dstaddr;
        size_t addr_size, broadaddr_size, dstaddr_size;
@@ -149,10 +156,10 @@ pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
         * Get the list of interface addresses.
         *
         * Note: this won't return information about interfaces
-        * with no addresses; are there any such interfaces
-        * that would be capable of receiving packets?
-        * (Interfaces incapable of receiving packets aren't
-        * very interesting from libpcap's point of view.)
+        * with no addresses, so, if a platform has interfaces
+        * with no interfaces on which traffic can be captured,
+        * we must check for those interfaces as well (see, for
+        * example, what's done on Linux).
         *
         * LAN interfaces will probably have link-layer
         * addresses; I don't know whether all implementations
@@ -160,40 +167,56 @@ pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
         * those.
         */
        if (getifaddrs(&ifap) != 0) {
-               (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                   "getifaddrs: %s", pcap_strerror(errno));
+               pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+                   errno, "getifaddrs");
                return (-1);
        }
        for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
                /*
-                * Is this interface up?
+                * If this entry has a colon followed by a number at
+                * the end, we assume it's a logical interface.  Those
+                * are just the way you assign multiple IP addresses to
+                * a real interface on Linux, so an entry for a logical
+                * interface should be treated like the entry for the
+                * real interface; we do that by stripping off the ":"
+                * and the number.
+                *
+                * XXX - should we do this only on Linux?
+                */
+               p = strchr(ifa->ifa_name, ':');
+               if (p != NULL) {
+                       /*
+                        * We have a ":"; is it followed by a number?
+                        */
+                       q = p + 1;
+                       while (PCAP_ISDIGIT(*q))
+                               q++;
+                       if (*q == '\0') {
+                               /*
+                                * All digits after the ":" until the end.
+                                * Strip off the ":" and everything after
+                                * it.
+                                */
+                              *p = '\0';
+                       }
+               }
+
+               /*
+                * Can we capture on this device?
                 */
-               if (!(ifa->ifa_flags & IFF_UP)) {
+               if (!(*check_usable)(ifa->ifa_name)) {
                        /*
-                        * No, so don't add it to the list.
+                        * No.
                         */
                        continue;
                }
 
                /*
                 * "ifa_addr" was apparently null on at least one
-                * interface on some system.
-                *
-                * "ifa_broadaddr" may be non-null even on
-                * non-broadcast interfaces, and was null on
-                * at least one OpenBSD 3.4 system on at least
-                * one interface with IFF_BROADCAST set.
-                *
-                * "ifa_dstaddr" was, on at least one FreeBSD 4.1
-                * system, non-null on a non-point-to-point
-                * interface.
-                *
-                * Therefore, we supply the address and netmask only
-                * if "ifa_addr" is non-null (if there's no address,
-                * there's obviously no netmask), and supply the
-                * broadcast and destination addresses if the appropriate
-                * flag is set *and* the appropriate "ifa_" entry doesn't
-                * evaluate to a null pointer.
+                * interface on some system.  Therefore, we supply
+                * the address and netmask only if "ifa_addr" is
+                * non-null (if there's no address, there's obviously
+                * no netmask).
                 */
                if (ifa->ifa_addr != NULL) {
                        addr = ifa->ifa_addr;
@@ -204,6 +227,22 @@ pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
                        addr_size = 0;
                        netmask = NULL;
                }
+
+               /*
+                * Note that, on some platforms, ifa_broadaddr and
+                * ifa_dstaddr could be the same field (true on at
+                * least some versions of *BSD and macOS), so we
+                * can't just check whether the broadcast address
+                * is null and add it if so and check whether the
+                * destination address is null and add it if so.
+                *
+                * Therefore, we must also check the IFF_BROADCAST
+                * flag, and only add a broadcast address if it's
+                * set, and check the IFF_POINTTOPOINT flag, and
+                * only add a destination address if it's set (as
+                * per man page recommendations on some of those
+                * platforms).
+                */
                if (ifa->ifa_flags & IFF_BROADCAST &&
                    ifa->ifa_broadaddr != NULL) {
                        broadaddr = ifa->ifa_broadaddr;
@@ -221,40 +260,12 @@ pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
                        dstaddr_size = 0;
                }
 
-               /*
-                * If this entry has a colon followed by a number at
-                * the end, we assume it's a logical interface.  Those
-                * are just the way you assign multiple IP addresses to
-                * a real interface on Linux, so an entry for a logical
-                * interface should be treated like the entry for the
-                * real interface; we do that by stripping off the ":"
-                * and the number.
-                *
-                * XXX - should we do this only on Linux?
-                */
-               p = strchr(ifa->ifa_name, ':');
-               if (p != NULL) {
-                       /*
-                        * We have a ":"; is it followed by a number?
-                        */
-                       q = p + 1;
-                       while (isdigit((unsigned char)*q))
-                               q++;
-                       if (*q == '\0') {
-                               /*
-                                * All digits after the ":" until the end.
-                                * Strip off the ":" and everything after
-                                * it.
-                                */
-                              *p = '\0';
-                       }
-               }
-
                /*
                 * Add information for this address to the list.
                 */
-               if (add_addr_to_iflist(&devlist, ifa->ifa_name,
-                   ifa->ifa_flags, addr, addr_size, netmask, addr_size,
+               if (add_addr_to_if(devlistp, ifa->ifa_name, ifa->ifa_flags,
+                   get_flags_func,
+                   addr, addr_size, netmask, addr_size,
                    broadaddr, broadaddr_size, dstaddr, dstaddr_size,
                    errbuf) < 0) {
                        ret = -1;
@@ -264,25 +275,5 @@ pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
 
        freeifaddrs(ifap);
 
-       if (ret != -1) {
-               /*
-                * We haven't had any errors yet; do any platform-specific
-                * operations to add devices.
-                */
-               if (pcap_platform_finddevs(&devlist, errbuf) < 0)
-                       ret = -1;
-       }
-
-       if (ret == -1) {
-               /*
-                * We had an error; free the list we've been constructing.
-                */
-               if (devlist != NULL) {
-                       pcap_freealldevs(devlist);
-                       devlist = NULL;
-               }
-       }
-
-       *alldevsp = devlist;
        return (ret);
 }