diff options
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | acinclude.m4 | 19 | ||||
-rw-r--r-- | capture-wpcap.c | 226 | ||||
-rw-r--r-- | configure.in | 3 | ||||
-rw-r--r-- | pcap-util-int.h | 37 | ||||
-rw-r--r-- | pcap-util-unix.c | 273 | ||||
-rw-r--r-- | pcap-util.c | 376 |
7 files changed, 543 insertions, 395 deletions
diff --git a/Makefile.am b/Makefile.am index 8be39ea758..c21e1fb2ee 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ # Makefile.am # Automake file for Ethereal # -# $Id: Makefile.am,v 1.636 2003/10/06 19:25:20 guy Exp $ +# $Id: Makefile.am,v 1.637 2003/10/10 03:00:09 guy Exp $ # # Ethereal - Network traffic analyzer # By Gerald Combs <gerald@ethereal.com> @@ -764,6 +764,8 @@ ETHEREAL_COMMON_SRC = \ packet-dcerpc-nt.c \ pcap-util.c \ pcap-util.h \ + pcap-util-int.h \ + pcap-util-unix.c \ ppptypes.h \ prefs-int.h \ prefs.c \ diff --git a/acinclude.m4 b/acinclude.m4 index f76ad5d35d..5456d39bfc 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -2,7 +2,7 @@ dnl Macros that test for specific features. dnl This file is part of the Autoconf packaging for Ethereal. dnl Copyright (C) 1998-2000 by Gerald Combs. dnl -dnl $Id: acinclude.m4,v 1.56 2003/08/31 22:08:57 sharpe Exp $ +dnl $Id: acinclude.m4,v 1.57 2003/10/10 03:00:09 guy Exp $ dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by @@ -327,17 +327,13 @@ and did you also install that package?]])) ], [AC_MSG_ERROR(Library libpcap not found.)], $SOCKET_LIBS $NSL_LIBS) AC_SUBST(PCAP_LIBS) -]) -# -# AC_ETHEREAL_PCAP_VERSION_CHECK -# -# Check whether "pcap_version" is defined by libpcap. -# -AC_DEFUN(AC_ETHEREAL_PCAP_VERSION_CHECK, -[ - AC_MSG_CHECKING(whether pcap_version is defined by libpcap) + # + # Check whether various variables and functions are defined by + # libpcap. + # ac_save_LIBS="$LIBS" + AC_MSG_CHECKING(whether pcap_version is defined by libpcap) LIBS="$PCAP_LIBS $SOCKET_LIBS $NSL_LIBS $LIBS" AC_TRY_LINK( [ @@ -350,13 +346,14 @@ AC_DEFUN(AC_ETHEREAL_PCAP_VERSION_CHECK, ac_cv_pcap_version_defined=yes, ac_cv_pcap_version_defined=no, [echo $ac_n "cross compiling; assumed OK... $ac_c"]) - LIBS="$ac_save_LIBS" if test "$ac_cv_pcap_version_defined" = yes ; then AC_MSG_RESULT(yes) AC_DEFINE(HAVE_PCAP_VERSION, 1, [Define if libpcap version is known]) else AC_MSG_RESULT(no) fi + AC_CHECK_FUNCS(pcap_findalldevs) + LIBS="$ac_save_LIBS" ]) # diff --git a/capture-wpcap.c b/capture-wpcap.c index 98de62ab46..88f6cbfd15 100644 --- a/capture-wpcap.c +++ b/capture-wpcap.c @@ -1,13 +1,14 @@ /* capture-wpcap.c - * Try to load WinPcap DLL at run-time. + * WinPcap-specific interfaces for capturing. We load WinPcap at run + * time, so that we only need one Ethereal binary and one Tethereal binary + * for Windows, regardless of whether WinPcap is installed or not. * - * $Id: capture-wpcap.c,v 1.3 2002/08/28 21:00:05 jmayer Exp $ + * $Id: capture-wpcap.c,v 1.4 2003/10/10 03:00:09 guy Exp $ * * Ethereal - Network traffic analyzer - * By Gerald Combs <gerald@zing.org> + * By Gerald Combs <gerald@ethereal.com> * Copyright 2001 Gerald Combs * - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -34,6 +35,9 @@ #include <pcap.h> #endif +#include "pcap-util.h" +#include "pcap-util-int.h" + /* XXX - yes, I know, I should move cppmagic.h to a generic location. */ #include "tools/lemon/cppmagic.h" @@ -41,7 +45,6 @@ gboolean has_wpcap = FALSE; #ifdef HAVE_LIBPCAP - static char* (*p_pcap_lookupdev) (char *); static void (*p_pcap_close) (pcap_t *); static int (*p_pcap_stats) (pcap_t *, struct pcap_stat *); @@ -60,29 +63,31 @@ static int (*p_pcap_loop) (pcap_t *, int, pcap_handler, guchar *); typedef struct { const char *name; gpointer *ptr; + gboolean optional; } symbol_table_t; -#define SYM(x) STRINGIFY(x) , (gpointer) &CONCAT(p_,x) +#define SYM(x, y) { STRINGIFY(x) , (gpointer) &CONCAT(p_,x), y } void load_wpcap(void) { - /* These are the symbols I need from Wpcap */ - symbol_table_t symbols[] = { - SYM(pcap_lookupdev), - SYM(pcap_close), - SYM(pcap_stats), - SYM(pcap_dispatch), - SYM(pcap_snapshot), - SYM(pcap_datalink), - SYM(pcap_setfilter), - SYM(pcap_geterr), - SYM(pcap_compile), - SYM(pcap_lookupnet), - SYM(pcap_open_live), - SYM(pcap_loop), - NULL, NULL + /* These are the symbols I need or want from Wpcap */ + static const symbol_table_t symbols[] = { + SYM(pcap_lookupdev, FALSE), + SYM(pcap_close, FALSE), + SYM(pcap_stats, FALSE), + SYM(pcap_dispatch, FALSE), + SYM(pcap_snapshot, FALSE), + SYM(pcap_datalink, FALSE), + SYM(pcap_setfilter, FALSE), + SYM(pcap_geterr, FALSE), + SYM(pcap_compile, FALSE), + SYM(pcap_lookupnet, FALSE), + SYM(pcap_open_live, FALSE), + SYM(pcap_loop, FALSE), + SYM(pcap_findalldevs, TRUE), + { NULL, NULL, FALSE } }; GModule *wh; /* wpcap handle */ @@ -95,9 +100,20 @@ load_wpcap(void) } sym = symbols; - while (sym && sym->name) { + while (sym->name) { if (!g_module_symbol(wh, sym->name, sym->ptr)) { - return; + if (sym->optional) { + /* + * We don't care if it's missing; we just + * don't use it. + */ + *sym->ptr = NULL; + } else { + /* + * We require this symbol. + */ + return; + } } sym++; } @@ -193,6 +209,169 @@ pcap_loop(pcap_t *a, int b, pcap_handler c, guchar *d) return p_pcap_loop(a, b, c, d); } +#ifdef HAVE_PCAP_FINDALLDEVS +int +pcap_findalldevs(pcap_if_t **a, char *b) +{ + g_assert(has_wpcap && p_pcap_findalldevs != NULL) + return p_pcap_findalldevs(a, b); +} +#endif + +/* + * This will use "pcap_findalldevs()" if we have it, otherwise it'll + * fall back on "pcap_lookupdev()". + */ +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; + +#ifdef HAVE_PCAP_FINDALLDEVS + if (p_pcap_findalldevs != NULL) + return get_interface_list_findalldevs(err, errstr); +#endif + + /* + * In WinPcap, pcap_lookupdev is implemented by calling + * PacketGetAdapterNames. According to the documentation + * I could find: + * + * http://winpcap.polito.it/docs/man/html/Packet32_8c.html#a43 + * + * 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 + * description 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++; + } + } + } + + if (il == NULL) { + /* + * No interfaces found. + */ + *err = NO_INTERFACES_FOUND; + } + + return il; +} + #else /* HAVE_LIBPCAP */ void @@ -201,5 +380,4 @@ load_wpcap(void) return; } - #endif /* HAVE_LIBPCAP */ diff --git a/configure.in b/configure.in index e28072d6e3..7542789c82 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -# $Id: configure.in,v 1.223 2003/10/01 15:09:32 jmayer Exp $ +# $Id: configure.in,v 1.224 2003/10/10 03:00:09 guy Exp $ dnl dnl Process this file with autoconf 2.13 or later to produce a dnl configure script; 2.12 doesn't generate a "configure" script that @@ -459,7 +459,6 @@ if test "x$want_pcap" = "xno" ; then else AC_MSG_RESULT(yes) AC_ETHEREAL_PCAP_CHECK - AC_ETHEREAL_PCAP_VERSION_CHECK fi dnl zlib check diff --git a/pcap-util-int.h b/pcap-util-int.h new file mode 100644 index 0000000000..7958d4e3fa --- /dev/null +++ b/pcap-util-int.h @@ -0,0 +1,37 @@ +/* pcap-util-int.h + * Definitions of routines internal to the libpcap/WinPcap utilities + * + * $Id: pcap-util-int.h,v 1.1 2003/10/10 03:04:38 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PCAP_UTIL_INT_H__ +#define __PCAP_UTIL_INT_H__ + +#ifdef HAVE_LIBPCAP + +extern if_info_t *if_info_new(char *name, char *description); +#ifdef HAVE_PCAP_FINDALLDEVS +extern GList *get_interface_list_findalldevs(int *err, char *err_str); +#endif + +#endif /* HAVE_LIBPCAP */ + +#endif /* __PCAP_UTIL_H__ */ diff --git a/pcap-util-unix.c b/pcap-util-unix.c new file mode 100644 index 0000000000..6e3e8676a9 --- /dev/null +++ b/pcap-util-unix.c @@ -0,0 +1,273 @@ +/* pcap-util-unix.c + * UN*X-specific utility routines for packet capture + * + * $Id: pcap-util-unix.c,v 1.1 2003/10/10 03:00:10 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_LIBPCAP + +#include <glib.h> + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.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> + +/* + * Keep Digital UNIX happy when including <net/if.h>. + */ +struct mbuf; +struct rtentry; +#include <net/if.h> + +#ifdef HAVE_SYS_SOCKIO_H +# include <sys/sockio.h> +#endif + +#include "globals.h" + +#include "pcap-util.h" +#include "pcap-util-int.h" + +#ifndef HAVE_PCAP_FINDALLDEVS +struct search_user_data { + char *name; + int found; +}; + +static void +search_for_if_cb(gpointer data, gpointer user_data); +#endif + +GList * +get_interface_list(int *err, char *err_str) +{ +#ifdef HAVE_PCAP_FINDALLDEVS + return get_interface_list_findalldevs(err, err_str); +#else + 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; + if_info_t *if_info; + + if (sock < 0) { + *err = CANT_GET_INTERFACE_LIST; + sprintf(err_str, "Error opening socket: %s", + strerror(errno)); + 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_append(il, if_info); + 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) { + /* + * No interfaces found. + */ + *err = NO_INTERFACES_FOUND; + } + return il; + +fail: + if (il != NULL) + free_interface_list(il); + g_free(ifc.ifc_buf); + close(sock); + *err = CANT_GET_INTERFACE_LIST; + return NULL; +#endif /* HAVE_PCAP_FINDALLDEVS */ +} + +#ifndef HAVE_PCAP_FINDALLDEVS +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; +} +#endif /* HAVE_PCAP_FINDALLDEVS */ + +#endif /* HAVE_LIBPCAP */ diff --git a/pcap-util.c b/pcap-util.c index 183de4e567..2a2615b10f 100644 --- a/pcap-util.c +++ b/pcap-util.c @@ -1,7 +1,7 @@ /* 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> @@ -32,43 +32,19 @@ #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. @@ -193,27 +169,7 @@ get_pcap_linktype(pcap_t *pch, char *devname 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; @@ -227,330 +183,36 @@ if_info_new(char *name, char *description) 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_) |