Ethereal-dev: Re: [ethereal-dev] Ethereal Win32 libpcap patch.

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Guy Harris <gharris@xxxxxxxxxxxx>
Date: Thu, 3 Feb 2000 00:27:35 -0800
> There may be a problem in get_interface_list in util.c for Win98/95. NT
> returns Driver names in WCHARs.
> 98/95 should return the names in standard char * format but I don't have
> access to 95/98 right now.

Names, plural?

Your version of "get_interface_list()" was just calling
"pcap_lookupdev()", which returns only one interface.  That's OK on a
machine with one interface, but the list should really return *all* the
interfaces on a multi-homed machine.

I've attached my version of "util.c", which, on Win32, calls
"PacketGetAdapterNames()" directly, and attempts to get the names from
there; the code at least tries to figure out whether it's on NT or 9x,
and, based on that, to treat the names it gets back as Unicode or ASCII
- unfortunately, "PacketGetAdapterNames()" just fails on my NT
partition, for no obvious reason (the relevant registry keys all appear
to be there).

If I read the registry entry myself with RegEdit32, and then use the
name from there, it then bitches at me about the host name being
unknown, as the way the Win32 version finds the netmask is to get the
host name, translate it to an IP address, and then infer from the
address whether the network is class A, B, or C.  Is there no way to
dredge out of the registry, or out of the SNMPish database NDIS drivers
provide, the *real* netmask of the interface?  The way the Politecnico
di Torino code does it assumes that

	1) if your machine is multi-homed, all interfaces have the same
	   netmask;

	2) CIDR isn't being used - all netmasks are for class A, B, or C
	   networks;

and I'm somewhat disinclined to make either of those assumptions these
days....

(I'm also not certain why the Politecnico di Torino code leaves the
"\Device\" in the names they return, and don't just add that, if it's
missing, to the name supplied to "pcap_open_live()"; it's as redundant
on Win32 as "/dev/" is on UNIX when specifying network interface names.)
/* util.c
 * Utility routines
 *
 * $Id: util.c,v 1.35 2000/01/31 19:34:25 gram Exp $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxx>
 * 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

#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_TYPES_H
#include <sys/types.h>
#endif

#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif

#ifdef NEED_SNPRINTF_H
# ifdef HAVE_STDARG_H
#  include <stdarg.h>
# else
#  include <varargs.h>
# endif
# include "snprintf.h"
#endif

#ifndef WIN32
#include <pwd.h>
#endif

#ifdef NEED_MKSTEMP
#include "mkstemp.h"
#endif

#include "util.h"

#ifdef HAVE_IO_H
#include <io.h>
typedef int mode_t;	/* for win32 */
#endif

#ifdef HAVE_LIBPCAP

#ifndef WIN32

#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

#endif /* WIN32 */

#include "globals.h"

#ifdef WIN32

/*
 * For the libpcap port from the Politecnico di Torino.
 *
 * NOTE: we have to include <net/bpf.h> before we include <packet32.h>,
 * because <packet32.h> defines some BPF data structures also defined by
 * <net/bpf.h> unless BPF_MAJOR_VERSION is defined, and <net/bpf.h>
 * defines it but <packet32.h> doesn't, and the double definitions
 * so if we include <packet32.h> first, both it and <net/bpf.h> define
 * them, but if we include <net/bpf.h> first, it defines BPF_MAJOR_VERSION
 * and thus keeps <packet32.h> from defining them.
 *
 * "file.h" includes <pcap.h>, and "globals.h" includes "file.h", so we
 * must include "globals.h" before including <packet32.h>.
 */
#include <windows.h>
#include <windef.h>
#include <winsock.h>
#include <packet32.h>

#endif

#endif

#include "simple_dialog.h"  /* XXX */

/*
 * Given a pathname, return a pointer to the last pathname separator
 * character in the pathname, or NULL if the pathname contains no
 * separators.
 */
static char *
find_last_pathname_separator(char *path)
{
	char *separator;

#ifdef WIN32
	char c;

	/*
	 * We have to scan for '\' or '/'.
	 * Get to the end of the string.
	 */
	separator = path + strlen(path);	/* points to ending '\0' */
	while (separator > path) {
		c = *--separator;
		if (c == '\\' || c == '/')
			return separator;	/* found it */
	}

	/*
	 * OK, we didn't find any, so no directories - but there might
	 * be a drive letter....
	 */
	return strchr(path, ':');
#else
	separator = strrchr(path, '/');
#endif
	return separator;
}

/*
 * Given a pathname, return the last component.
 */
char *
get_basename(char *path)
{
	char *filename;

	filename = find_last_pathname_separator(path);
	if (filename == NULL) {
		/*
		 * There're no directories, drive letters, etc. in the
		 * name; the pathname *is* the file name.
		 */
		filename = path;
	} else {
		/*
		 * Skip past the pathname or drive letter separator.
		 */
		filename++;
	}
	return filename;
}

/*
 * Given a pathname, return a string containing everything but the
 * last component.  NOTE: this overwrites the pathname handed into
 * it....
 */
char *
get_dirname(char *path)
{
	char *separator;

	separator = find_last_pathname_separator(path);
	if (separator == NULL) {
		/*
		 * There're no directories, drive letters, etc. in the
		 * name; there is no directory path to return.
		 */
		return NULL;
	}

	/*
	 * Get rid of the last pathname separator and the final file
	 * name following it.
	 */
	*separator = '\0';

	/*
	 * "path" now contains the pathname of the directory containing
	 * the file/directory to which it referred.
	 */
	return path;
}

static char *
setup_tmpdir(char *dir)
{
	int len = strlen(dir);
	char *newdir;

	/* Append slash if necessary */
	if (dir[len - 1] == '/') {
		newdir = dir;
	}
	else {
		newdir = g_malloc(len + 2);
		strcpy(newdir, dir);
		strcat(newdir, "/");
	}
	return newdir;
}

static int
try_tempfile(char *namebuf, int namebuflen, const char *dir, const char *pfx)
{
	static const char suffix[] = "XXXXXXXXXX";
	int namelen = strlen(dir) + strlen(pfx) + sizeof suffix;
	mode_t old_umask;
	int tmp_fd;

	if (namebuflen < namelen) {
		/* Stick in a truncated name, so that if this error is
		   reported with the file name, you at least get
		   something. */
		snprintf(namebuf, namebuflen, "%s%s%s", dir, pfx, suffix);
		errno = ENAMETOOLONG;
		return -1;
	}
	strcpy(namebuf, dir);
	strcat(namebuf, pfx);
	strcat(namebuf, suffix);

	/* The Single UNIX Specification doesn't say that "mkstemp()"
	   creates the temporary file with mode rw-------, so we
	   won't assume that all UNIXes will do so; instead, we set
	   the umask to 0077 to take away all group and other
	   permissions, attempt to create the file, and then put
	   the umask back. */
	old_umask = umask(0077);
	tmp_fd = mkstemp(namebuf);
	umask(old_umask);
	return tmp_fd;
}

static char *tmpdir = NULL;
#ifdef WIN32
static char *temp = NULL;
#endif
static char *E_tmpdir;

#ifndef P_tmpdir
#define P_tmpdir "/var/tmp"
#endif

int
create_tempfile(char *namebuf, int namebuflen, const char *pfx)
{
	char *dir;
	int fd;
	static gboolean initialized;

	if (!initialized) {
		if ((dir = getenv("TMPDIR")) != NULL)
			tmpdir = setup_tmpdir(dir);
#ifdef WIN32
		if ((dir = getenv("TEMP")) != NULL)
			temp = setup_tmpdir(dir);
#endif

		E_tmpdir = setup_tmpdir(P_tmpdir);
		initialized = TRUE;
	}

	if (tmpdir != NULL) {
		fd = try_tempfile(namebuf, namebuflen, tmpdir, pfx);
		if (fd != -1)
			return fd;
	}

#ifdef WIN32
	if (temp != NULL) {
		fd = try_tempfile(namebuf, namebuflen, temp, pfx);
		if (fd != -1)
			return fd;
	}
#endif

	fd = try_tempfile(namebuf, namebuflen, E_tmpdir, pfx);
	if (fd != -1)
		return fd;

	return try_tempfile(namebuf, namebuflen, "/tmp", pfx);
}

/* ASCII/EBCDIC conversion tables from
 * http://www.room42.com/store/computer_center/code_tables.shtml
 */
static guint8 ASCII_translate_EBCDIC [ 256 ] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
    0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
    0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
    0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D,
    0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
    0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
    0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,
    0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
    0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
    0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
    0x7D, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
    0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
    0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
    0xA8, 0xA9, 0xC0, 0x6A, 0xD0, 0xA1, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
    0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B
};

void
ASCII_to_EBCDIC(guint8 *buf, guint bytes)
{
	guint	i;
	guint8	*bufptr;

	bufptr = buf;

	for (i = 0; i < bytes; i++, bufptr++) {
		*bufptr = ASCII_translate_EBCDIC[*bufptr];
	}
}

guint8
ASCII_to_EBCDIC1(guint8 c)
{
	return ASCII_translate_EBCDIC[c];
}

static guint8 EBCDIC_translate_ASCII [ 256 ] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
    0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
    0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
    0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
    0x2E, 0x2E, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
    0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x2E, 0x3F,
    0x20, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
    0x2E, 0x2E, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
    0x26, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
    0x2E, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
    0x2D, 0x2F, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
    0x2E, 0x7C, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
    0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
    0x2E, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
    0x2E, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
    0x69, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
    0x2E, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
    0x72, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
    0x2E, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
    0x7A, 0x2E, 0x2E, 0x2E, 0x5B, 0x2E, 0x2E,
    0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
    0x2E, 0x2E, 0x2E, 0x2E, 0x5D, 0x2E, 0x2E,
    0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
    0x49, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
    0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,                                             
    0x52, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
    0x5C, 0x2E, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
    0x5A, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,                 
    0x39, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E
};

void
EBCDIC_to_ASCII(guint8 *buf, guint bytes)
{
	guint	i;
	guint8	*bufptr;

	bufptr = buf;

	for (i = 0; i < bytes; i++, bufptr++) {
		*bufptr = EBCDIC_translate_ASCII[*bufptr];
	}
}

guint8
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);

/*
 * Win32 version based on Warren Young's "getifaces" example in
 * his Winsock Programmer's FAQ.
 */
GList *
get_interface_list(int *err, char *err_str)
{
	GList  *il = NULL;
	gint    nonloopback_pos = 0;
#ifdef WIN32
	BOOL	status;
	OSVERSIONINFO info;
	gboolean is_unicode;
	char    adapter_names[4096];
	ULONG   buf_len = sizeof adapter_names;
	char    adapter_name[64+1];
	u_char *p;
	u_char *q;
	u_char  c;
	int     i;
#else
	struct  ifreq *ifr, *last;
	struct  ifconf ifc;
	struct  ifreq ifrflags;
	int     sock = socket(AF_INET, SOCK_DGRAM, 0);
#endif
	struct search_user_data user_data;
	pcap_t *pch;

#ifdef WIN32
	if (!PacketGetAdapterNames(adapter_names, &buf_len)) {
		strcpy(err_str, "Error getting adapter names from the Registry");
		/* XXX - get the string corresponding to the last error? */
		goto fail;
	}

	/*
	 * Oh, this is lovely.  The library just sucks stuff directly
	 * from the registry, which means that on Windows 9x it's
	 * a pile of ASCII strings, whilst on Windows NT it's a
	 * pile of Unicode strings.
	 *
	 * OK, is this Windows 9x or Windows NT?
	 */
	memset(&info, '\0', sizeof info);
	info.dwOSVersionInfoSize = sizeof info;
	status = GetVersionEx(&info);
	if (!status) {	
		strcpy(err_str, "Error getting OS version");
		/* XXX - get the string corresponding to the last error? */
		goto fail;
	}
	switch (info.dwPlatformId) {

	case VER_PLATFORM_WIN32s:
		/*
		 * Win32s on Windows 3.x.
		 */
		strcpy(err_str, "Win32s on Windows 3.x isn't supported");
		goto fail;

	case VER_PLATFORM_WIN32_WINDOWS:
		/*
		 * Windows 9x.
		 */
		is_unicode = FALSE;
		break;

	case VER_PLATFORM_WIN32_NT:
		/*
		 * NT.  (This includes W2K, nee NT 5.0.)
		 */
		is_unicode = TRUE;
		break;

	default:
		sprintf(err_str, "Unknown platform ID %d", info.dwPlatformId);
		goto fail;
	}

	p = &adapter_names[0];
	for (;;) {
		/*
		 * Extract the next name from the list.
		 * The list is terminated with a double '\0'.
		 */
		q = adapter_name;
		for (;;) {
			c = *p++;
			if (is_unicode) {
				/*
				 * Skip the second byte of the character.
				 * (This is Windows, so we know the
				 * Unicode is little-endian.)
				 */
				p++;
			}
			if (c == '\0')
				break;	/* end of string */
			*q++ = c;
		}
		*q = '\0';
		if (q == adapter_name) {
			/*
			 * Empty string, meaning the end of the list.
			 */
			break;
		}

#if 0
		/*
		 * 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;
#endif

		/*
		 * 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(adapter_name, MIN_PACKET_SIZE, 0, 0,
		    err_str);
		if (pch == NULL)
			continue;
		pcap_close(pch);

#if 0
		/*
		 * 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 {
#else
		{
#endif
			il = g_list_insert(il, g_strdup(adapter_name),
			    nonloopback_pos);
			/*
			 * Insert the next non-loopback interface after this
			 * one.
			 */
			nonloopback_pos++;
		}
	}
#else
	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);
#endif /* WIN32 */

	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);
	}
#ifndef WIN32
	free(ifc.ifc_buf);
	close(sock);
#endif
	*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 */

const char*
get_home_dir(void)
{
	char *env_value;
	static const char *home = NULL;
#ifndef WIN32
	struct passwd *pwd;
#endif

	/* Return the cached value, if available */
	if (home)
		return home;

	env_value = getenv("HOME");

	if (env_value) {
		home = env_value;
	}
	else {
#ifdef WIN32
		/* XXX - on NT, get the user name and append it to
		   "C:\winnt\profiles\"?
		   What about Windows 9x? */
		home = "C:";
#else
		pwd = getpwuid(getuid());
		if (pwd != NULL) {
			/* This is cached, so we don't need to worry
			   about allocating multiple ones of them. */
			home = g_strdup(pwd->pw_dir);
		}
		else
			home = "/tmp";
#endif
	}

	return home;
}