/* pcap-util.c
* Utility routines for packet capture
*
- * $Id: pcap-util.c,v 1.17 2003/09/10 06:47:04 guy Exp $
+ * $Id: pcap-util.c,v 1.18 2003/10/10 03:00:10 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-
#include <pcap.h>
-#ifndef WIN32
-/*
- * Keep Digital UNIX happy when including <net/if.h>.
- */
-struct mbuf;
-struct rtentry;
-#include <net/if.h>
-#endif
-
-#ifdef HAVE_SYS_SOCKIO_H
-# include <sys/sockio.h>
-#endif
-
-#include "globals.h"
-
-#ifdef WIN32
-#include "capture-wpcap.h"
-#endif
-
#include "pcap-util.h"
+#include "pcap-util-int.h"
/*
* Get the data-link type for a libpcap device.
return linktype;
}
-/*
- * 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);
-
-static if_info_t *
+if_info_t *
if_info_new(char *name, char *description)
{
if_info_t *if_info;
return if_info;
}
-#ifndef WIN32
+#ifdef HAVE_PCAP_FINDALLDEVS
GList *
-get_interface_list(int *err, char *err_str)
+get_interface_list_findalldevs(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;
- int len, lastlen;
- char *buf;
+ pcap_if_t *alldevs, *dev;
if_info_t *if_info;
- if (sock < 0) {
- sprintf(err_str, "Error opening socket: %s",
- strerror(errno));
+ if (pcap_findalldevs(&alldevs, err_str) == -1) {
+ *err = CANT_GET_INTERFACE_LIST;
return NULL;
}
- /*
- * This code came from: W. Richard Stevens: "UNIX Network Programming",
- * Networking APIs: Sockets and XTI, Vol 1, page 434.
- */
- lastlen = 0;
- len = 100 * sizeof(struct ifreq);
- for ( ; ; ) {
- buf = g_malloc(len);
- ifc.ifc_len = len;
- ifc.ifc_buf = buf;
- memset (buf, 0, len);
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
- if (errno != EINVAL || lastlen != 0) {
- sprintf(err_str,
- "SIOCGIFCONF ioctl error getting list of interfaces: %s",
- strerror(errno));
- goto fail;
- }
- } else {
- if ((unsigned) ifc.ifc_len < sizeof(struct ifreq)) {
- sprintf(err_str,
- "SIOCGIFCONF ioctl gave too small return buffer");
- goto fail;
- }
- if (ifc.ifc_len == lastlen)
- break; /* success, len has not changed */
- lastlen = ifc.ifc_len;
- }
- len += 10 * sizeof(struct ifreq); /* increment */
- g_free(buf);
- }
- 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_info = if_info_new(ifr->ifr_name, NULL);
- if ((ifrflags.ifr_flags & IFF_LOOPBACK) ||
- strncmp(ifr->ifr_name, "lo", 2) == 0)
- il = g_list_insert(il, if_info, -1);
- else {
- il = g_list_insert(il, if_info, 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 > sizeof(ifr->ifr_addr) ?
- ifr->ifr_addr.sa_len : sizeof(ifr->ifr_addr)) +
- IFNAMSIZ);
-#else
- ifr = (struct ifreq *) ((char *) ifr + sizeof(struct ifreq));
-#endif
- }
-
-#ifdef linux
- /*
- * OK, maybe we have support for the "any" device, to do a cooked
- * capture on all interfaces at once.
- * Try opening it and, if that succeeds, add it to the end of
- * the list of interfaces.
- */
- pch = pcap_open_live("any", MIN_PACKET_SIZE, 0, 0, err_str);
- if (pch != NULL) {
- /*
- * It worked; we can use the "any" device.
- */
- if_info = if_info_new("any",
- "Pseudo-device that captures on all interfaces");
- il = g_list_insert(il, if_info, -1);
- pcap_close(pch);
- }
-#endif
-
- g_free(ifc.ifc_buf);
- close(sock);
-
- if (il == NULL) {
+ if (alldevs == NULL) {
/*
* No interfaces found.
*/
*err = NO_INTERFACES_FOUND;
+ return NULL;
}
- return il;
-
-fail:
- if (il != NULL)
- free_interface_list(il);
- g_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_info_t *if_info = data;
-
- if (strcmp(if_info->name, search_user_data->name) == 0)
- search_user_data->found = TRUE;
-}
-#else /* Windows */
-GList *
-get_interface_list(int *err, char *err_str) {
- GList *il = NULL;
- wchar_t *names;
- char *win95names;
- char ascii_name[MAX_WIN_IF_NAME_LEN + 1];
- char ascii_desc[MAX_WIN_IF_NAME_LEN + 1];
- int i, j;
-
- /* On Windows pcap_lookupdev is implemented by calling
- * PacketGetAdapterNames. According to the documentation I can find
- * (http://winpcap.polito.it/docs/dll.htm#PacketGetAdapterNames)
- * this means that:
- *
- * On Windows OT (95, 98, Me), pcap_lookupdev returns a sequence of bytes
- * consisting of:
- *
- * a sequence of null-terminated ASCII strings (i.e., each one is
- * terminated by a single 0 byte), giving the names of the interfaces;
- *
- * an empty ASCII string (i.e., a single 0 byte);
- *
- * a sequence of null-terminated ASCII strings, giving the
- * descriptions of the interfaces;
- *
- * an empty ASCII string.
- *
- * On Windows NT (NT 4.0, W2K, WXP, W2K3, etc.), pcap_lookupdev returns
- * a sequence of bytes consisting of:
- *
- * a sequence of null-terminated double-byte Unicode strings (i.e.,
- * each one consits of a sequence of double-byte characters,
- * terminated by a double-byte 0), giving the names of the interfaces;
- *
- * an empty Unicode string (i.e., a double 0 byte);
- *
- * a sequence of null-terminated ASCII strings, giving the
- * descriptions of the interfaces;
- *
- * an empty ASCII string.
- *
- * The Nth string in the first sequence is the name of the Nth adapter;
- * the Nth string in the second sequence is the descriptio of the Nth
- * adapter.
- */
-
- names = (wchar_t *)pcap_lookupdev(err_str);
- i = 0;
-
- if (names) {
- char* desc = 0;
- int desc_pos = 0;
-
- if (names[0]<256) {
- /* If names[0] is less than 256 it means the first byte is 0
- This implies that we are using unicode characters */
- while(*(names+desc_pos) || *(names+desc_pos-1))
- desc_pos++;
- desc_pos++; /* Step over the extra '\0' */
- desc = (char*)(names + desc_pos); /* cast *after* addition */
-
- while (names[i] != 0)
- {
- /*
- * Copy the Unicode description to an ASCII
- * string.
- */
- j = 0;
- while (*desc != 0) {
- if (j < MAX_WIN_IF_NAME_LEN)
- ascii_desc[j++] = *desc;
- desc++;
- }
- ascii_desc[j] = '\0';
- desc++;
-
- /*
- * Copy the Unicode name to an ASCII string.
- */
- j = 0;
- while (names[i] != 0) {
- if (j < MAX_WIN_IF_NAME_LEN)
- ascii_name[j++] = names[i++];
- }
- ascii_name[j] = '\0';
- i++;
- il = g_list_append(il,
- if_info_new(ascii_name, ascii_desc));
- }
- }
- else {
- /* Otherwise we are in Windows 95/98 and using ASCII
- (8 bit) characters */
- win95names=(char *)names;
- while(*(win95names+desc_pos) || *(win95names+desc_pos-1))
- desc_pos++;
- desc_pos++; /* Step over the extra '\0' */
- desc = win95names + desc_pos;
- while (win95names[i] != '\0')
- {
- /*
- * "&win95names[i]" points to the current interface
- * name, and "desc" points to that interface's
- * description.
- */
- il = g_list_append(il,
- if_info_new(&win95names[i], desc));
-
- /*
- * Skip to the next description.
- */
- while (*desc != 0)
- desc++;
- desc++;
-
- /*
- * Skip to the next name.
- */
- while (win95names[i] != 0)
- i++;
- i++;
- }
- }
- }
+ for (dev = alldevs; dev != NULL; dev = dev->next) {
+ if_info = if_info_new(dev->name, dev->description);
+ il = g_list_append(il, if_info);
+ }
+ pcap_freealldevs(alldevs);
- if (il == NULL) {
- /*
- * No interfaces found.
- */
- *err = NO_INTERFACES_FOUND;
- }
- return(il);
+ return il;
}
-#endif
+#endif /* HAVE_PCAP_FINDALLDEVS */
static void
free_if_cb(gpointer data, gpointer user_data _U_)