diff options
author | Guy Harris <guy@alum.mit.edu> | 2000-01-16 02:48:12 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2000-01-16 02:48:12 +0000 |
commit | 7f30e566a0257e7319a2e6a052476afd46924b12 (patch) | |
tree | ebe8cc252f6efe9166f3a6a14517cfd937290a17 /util.c | |
parent | 66a0ac1ca116c350549aa006772c67c891602b8f (diff) |
Move the routine to get a list of the network interfaces on the system
to "util.c", and provide a routine to free that list as well.
When picking an interface on which to do a capture (if no "-i" flag was
specified), use that routine, and pick the first interface on the list.
svn path=/trunk/; revision=1495
Diffstat (limited to 'util.c')
-rw-r--r-- | util.c | 210 |
1 files changed, 209 insertions, 1 deletions
@@ -1,7 +1,7 @@ /* util.c * Utility routines * - * $Id: util.c,v 1.26 2000/01/15 00:22:34 gram Exp $ + * $Id: util.c,v 1.27 2000/01/16 02:47:47 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@zing.org> @@ -66,6 +66,28 @@ typedef int mode_t; /* for win32 */ #endif +#ifdef HAVE_LIBPCAP + +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif + +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#ifdef HAVE_NET_IF_H +#include <net/if.h> +#endif + +#ifdef HAVE_SYS_SOCKIO_H +# include <sys/sockio.h> +#endif + +#include "globals.h" + +#endif + static char * setup_tmpdir(char *dir) { @@ -276,3 +298,189 @@ EBCDIC_to_ASCII1(guint8 c) { return EBCDIC_translate_ASCII[c]; } + +#ifdef HAVE_LIBPCAP + +/* + * If the ability to capture packets is added to Wiretap, these + * routines should be moved to the Wiretap source (with + * "get_interface_list()" and "free_interface_list()" renamed to + * "wtap_get_interface_list()" and "wtap_free_interface_list()", + * and modified to use Wiretap routines to attempt to open the + * interface. + */ + +struct search_user_data { + char *name; + int found; +}; + +static void +search_for_if_cb(gpointer data, gpointer user_data); + +static void +free_if_cb(gpointer data, gpointer user_data); + +GList * +get_interface_list(int *err, char *err_str) +{ + GList *il = NULL; + gint nonloopback_pos = 0; + struct ifreq *ifr, *last; + struct ifconf ifc; + struct ifreq ifrflags; + int sock = socket(AF_INET, SOCK_DGRAM, 0); + struct search_user_data user_data; + pcap_t *pch; + + if (sock < 0) { + sprintf(err_str, "Error opening socket: %s", + strerror(errno)); + return NULL; + } + + /* + * Since we have to grab the interface list all at once, we'll + * make plenty of room. + */ + ifc.ifc_len = 1024 * sizeof(struct ifreq); + ifc.ifc_buf = malloc(ifc.ifc_len); + + if (ioctl(sock, SIOCGIFCONF, &ifc) < 0 || + ifc.ifc_len < sizeof(struct ifreq)) { + sprintf(err_str, "SIOCGIFCONF error getting list of interfaces: %s", + strerror(errno)); + goto fail; + } + + ifr = (struct ifreq *) ifc.ifc_req; + last = (struct ifreq *) ((char *) ifr + ifc.ifc_len); + while (ifr < last) { + /* + * Skip addresses that begin with "dummy", or that include + * a ":" (the latter are Solaris virtuals). + */ + if (strncmp(ifr->ifr_name, "dummy", 5) == 0 || + strchr(ifr->ifr_name, ':') != NULL) + goto next; + + /* + * If we already have this interface name on the list, + * don't add it (SIOCGIFCONF returns, at least on + * BSD-flavored systems, one entry per interface *address*; + * if an interface has multiple addresses, we get multiple + * entries for it). + */ + user_data.name = ifr->ifr_name; + user_data.found = FALSE; + g_list_foreach(il, search_for_if_cb, &user_data); + if (user_data.found) + goto next; + + /* + * Get the interface flags. + */ + memset(&ifrflags, 0, sizeof ifrflags); + strncpy(ifrflags.ifr_name, ifr->ifr_name, + sizeof ifrflags.ifr_name); + if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifrflags) < 0) { + if (errno == ENXIO) + goto next; + sprintf(err_str, "SIOCGIFFLAGS error getting flags for interface %s: %s", + ifr->ifr_name, strerror(errno)); + goto fail; + } + + /* + * Skip interfaces that aren't up. + */ + if (!(ifrflags.ifr_flags & IFF_UP)) + goto next; + + /* + * Skip interfaces that we can't open with "libpcap". + * Open with the minimum packet size - it appears that the + * IRIX SIOCSNOOPLEN "ioctl" may fail if the capture length + * supplied is too large, rather than just truncating it. + */ + pch = pcap_open_live(ifr->ifr_name, MIN_PACKET_SIZE, 0, 0, + err_str); + if (pch == NULL) + goto next; + pcap_close(pch); + + /* + * If it's a loopback interface, add it at the end of the + * list, otherwise add it after the last non-loopback + * interface, so all loopback interfaces go at the end - we + * don't want a loopback interface to be the default capture + * device unless there are no non-loopback devices. + */ + if ((ifrflags.ifr_flags & IFF_LOOPBACK) || + strncmp(ifr->ifr_name, "lo", 2) == 0) + il = g_list_insert(il, g_strdup(ifr->ifr_name), -1); + else { + il = g_list_insert(il, g_strdup(ifr->ifr_name), + nonloopback_pos); + /* + * Insert the next non-loopback interface after this + * one. + */ + nonloopback_pos++; + } + + next: +#ifdef HAVE_SA_LEN + ifr = (struct ifreq *) ((char *) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ); +#else + ifr = (struct ifreq *) ((char *) ifr + sizeof(struct ifreq)); +#endif + } + + free(ifc.ifc_buf); + close(sock); + + if (il == NULL) { + /* + * No interfaces found. + */ + *err = NO_INTERFACES_FOUND; + } + return il; + +fail: + if (il != NULL) { + g_list_foreach(il, free_if_cb, NULL); + g_list_free(il); + } + free(ifc.ifc_buf); + close(sock); + *err = CANT_GET_INTERFACE_LIST; + return NULL; +} + +static void +search_for_if_cb(gpointer data, gpointer user_data) +{ + struct search_user_data *search_user_data = user_data; + + if (strcmp((char *)data, search_user_data->name) == 0) + search_user_data->found = TRUE; +} + +static void +free_if_cb(gpointer data, gpointer user_data) +{ + g_free(data); +} + +void +free_interface_list(GList *if_list) +{ + while (if_list != NULL) { + g_free(if_list->data); + if_list = g_list_remove_link(if_list, if_list); + } +} + +#endif /* HAVE_LIBPCAP */ |