aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am4
-rw-r--r--acinclude.m419
-rw-r--r--capture-wpcap.c226
-rw-r--r--configure.in3
-rw-r--r--pcap-util-int.h37
-rw-r--r--pcap-util-unix.c273
-rw-r--r--pcap-util.c376
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_)