1998-09-16 02:39:15 +00:00
|
|
|
/* util.c
|
|
|
|
* Utility routines
|
|
|
|
*
|
2001-04-02 09:53:46 +00:00
|
|
|
* $Id: util.c,v 1.51 2001/04/02 09:53:43 guy Exp $
|
1998-09-16 03:22:19 +00:00
|
|
|
*
|
1998-09-16 02:39:15 +00:00
|
|
|
* Ethereal - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@zing.org>
|
|
|
|
* 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>
|
|
|
|
|
1999-08-18 02:59:05 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
1998-12-22 05:52:51 +00:00
|
|
|
#include <stdio.h>
|
1999-08-18 02:59:05 +00:00
|
|
|
#include <errno.h>
|
1998-09-16 02:39:15 +00:00
|
|
|
|
1999-04-06 16:24:50 +00:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
1999-08-23 05:02:50 +00:00
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
|
|
#include <sys/types.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_STAT_H
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#endif
|
|
|
|
|
1998-10-13 07:03:37 +00:00
|
|
|
#ifdef NEED_SNPRINTF_H
|
|
|
|
# include "snprintf.h"
|
|
|
|
#endif
|
|
|
|
|
2000-01-29 19:06:59 +00:00
|
|
|
#ifndef WIN32
|
|
|
|
#include <pwd.h>
|
|
|
|
#endif
|
|
|
|
|
2000-01-15 00:23:13 +00:00
|
|
|
#ifdef NEED_MKSTEMP
|
|
|
|
#include "mkstemp.h"
|
|
|
|
#endif
|
|
|
|
|
1998-09-16 02:39:15 +00:00
|
|
|
#include "util.h"
|
|
|
|
|
2000-01-10 17:33:17 +00:00
|
|
|
#ifdef HAVE_IO_H
|
|
|
|
#include <io.h>
|
|
|
|
typedef int mode_t; /* for win32 */
|
|
|
|
#endif
|
|
|
|
|
2000-01-16 02:48:12 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_SOCKET_H
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_IOCTL_H
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#endif
|
|
|
|
|
2001-01-28 23:56:29 +00:00
|
|
|
#include <pcap.h>
|
|
|
|
|
libpcap unconditionally includes <net/if.h> on UNIX systems, as that is,
as far as I know, the only way to get IFF_UP, IFF_LOOPBACK, "struct
ifreq", and "struct ifconf" defined, and those are required in order to
get, via SIOCGIFCONF, the interface list, and to exclude interfaces that
aren't up and handle loopback interfaces differently from other
interfaces.
If we're on UNIX and have libpcap, we should do the same; that way, if
the system doesn't have <net/if.h> installed, the compile will fail with
an "I can't find <net/if.h>" error, rather than the configure indicating
that <net/if.h> can't be found, causing "util.c" not to include it,
causing it to fail with complaints about IFF_UP, IFF_LOOPBACK, and
various structures not being defined - the former tells you the root
cause, the latter doesn't.
svn path=/trunk/; revision=2442
2000-09-17 03:20:05 +00:00
|
|
|
#ifndef WIN32
|
2000-01-16 02:48:12 +00:00
|
|
|
#include <net/if.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_SOCKIO_H
|
|
|
|
# include <sys/sockio.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "globals.h"
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2000-07-31 04:53:40 +00:00
|
|
|
/*
|
|
|
|
* Given a pathname, return:
|
|
|
|
*
|
|
|
|
* the errno, if an attempt to "stat()" the file fails;
|
|
|
|
*
|
|
|
|
* EISDIR, if the attempt succeeded and the file turned out
|
|
|
|
* to be a directory;
|
|
|
|
*
|
|
|
|
* 0, if the attempt succeeded and the file turned out not
|
|
|
|
* to be a directory.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Visual C++ on Win32 systems doesn't define these. (Old UNIX systems don't
|
|
|
|
* define them either.)
|
|
|
|
*
|
|
|
|
* Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
|
|
|
|
*/
|
|
|
|
#ifndef S_ISREG
|
|
|
|
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
|
|
|
|
#endif
|
|
|
|
#ifndef S_IFIFO
|
|
|
|
#define S_IFIFO _S_IFIFO
|
|
|
|
#endif
|
|
|
|
#ifndef S_ISFIFO
|
|
|
|
#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
|
|
|
|
#endif
|
|
|
|
#ifndef S_ISDIR
|
|
|
|
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int
|
|
|
|
test_for_directory(const char *path)
|
|
|
|
{
|
|
|
|
struct stat statb;
|
|
|
|
|
|
|
|
if (stat(path, &statb) < 0)
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
if (S_ISDIR(statb.st_mode))
|
|
|
|
return EISDIR;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-02-22 07:07:55 +00:00
|
|
|
/*
|
|
|
|
* Collect command-line arguments as a string consisting of the arguments,
|
|
|
|
* separated by spaces.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
get_args_as_string(int argc, char **argv, int optind)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
int i;
|
|
|
|
char *argstring;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find out how long the string will be.
|
|
|
|
*/
|
|
|
|
len = 0;
|
|
|
|
for (i = optind; i < argc; i++) {
|
|
|
|
len += strlen(argv[i]);
|
|
|
|
len++; /* space, or '\0' if this is the last argument */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate the buffer for the string.
|
|
|
|
*/
|
|
|
|
argstring = g_malloc(len);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now construct the string.
|
|
|
|
*/
|
|
|
|
strcpy(argstring, "");
|
|
|
|
i = optind;
|
|
|
|
for (;;) {
|
|
|
|
strcat(argstring, argv[i]);
|
|
|
|
i++;
|
|
|
|
if (i == argc)
|
|
|
|
break;
|
|
|
|
strcat(argstring, " ");
|
|
|
|
}
|
|
|
|
return argstring;
|
|
|
|
}
|
|
|
|
|
1999-08-18 02:59:05 +00:00
|
|
|
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";
|
1999-09-23 05:20:18 +00:00
|
|
|
int namelen = strlen(dir) + strlen(pfx) + sizeof suffix;
|
1999-08-23 05:02:50 +00:00
|
|
|
mode_t old_umask;
|
|
|
|
int tmp_fd;
|
1999-08-18 02:59:05 +00:00
|
|
|
|
|
|
|
if (namebuflen < namelen) {
|
1999-09-24 04:14:43 +00:00
|
|
|
/* 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);
|
1999-08-18 02:59:05 +00:00
|
|
|
errno = ENAMETOOLONG;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
strcpy(namebuf, dir);
|
|
|
|
strcat(namebuf, pfx);
|
|
|
|
strcat(namebuf, suffix);
|
1999-08-23 05:02:50 +00:00
|
|
|
|
|
|
|
/* 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;
|
1999-08-18 02:59:05 +00:00
|
|
|
}
|
|
|
|
|
1999-08-18 15:29:06 +00:00
|
|
|
static char *tmpdir = NULL;
|
1999-08-18 02:59:05 +00:00
|
|
|
#ifdef WIN32
|
1999-08-18 15:29:06 +00:00
|
|
|
static char *temp = NULL;
|
1999-08-18 02:59:05 +00:00
|
|
|
#endif
|
|
|
|
static char *E_tmpdir;
|
|
|
|
|
1999-08-18 15:29:06 +00:00
|
|
|
#ifndef P_tmpdir
|
|
|
|
#define P_tmpdir "/var/tmp"
|
|
|
|
#endif
|
|
|
|
|
1999-08-18 02:59:05 +00:00
|
|
|
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
|
1999-08-18 15:29:06 +00:00
|
|
|
|
1999-08-18 02:59:05 +00:00
|
|
|
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);
|
|
|
|
}
|
1999-10-19 04:11:23 +00:00
|
|
|
|
|
|
|
/* ASCII/EBCDIC conversion tables from
|
|
|
|
* http://www.room42.com/store/computer_center/code_tables.shtml
|
|
|
|
*/
|
1999-11-22 06:24:56 +00:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
1999-10-19 04:11:23 +00:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-11-22 06:24:56 +00:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
1999-10-19 04:11:23 +00:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-11-22 06:24:56 +00:00
|
|
|
guint8
|
|
|
|
EBCDIC_to_ASCII1(guint8 c)
|
|
|
|
{
|
|
|
|
return EBCDIC_translate_ASCII[c];
|
|
|
|
}
|
2000-01-16 02:48:12 +00:00
|
|
|
|
|
|
|
#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);
|
|
|
|
|
2000-02-09 19:18:42 +00:00
|
|
|
#ifndef WIN32
|
2000-01-16 02:48:12 +00:00
|
|
|
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;
|
2000-08-31 11:12:19 +00:00
|
|
|
int len, lastlen;
|
|
|
|
char *buf;
|
2000-01-16 02:48:12 +00:00
|
|
|
|
|
|
|
if (sock < 0) {
|
|
|
|
sprintf(err_str, "Error opening socket: %s",
|
|
|
|
strerror(errno));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-08-31 11:12:19 +00:00
|
|
|
* This code came from: W. Richard Stevens: "UNIX Network Programming",
|
|
|
|
* Networking APIs: Sockets and XTI, Vol 1, page 434.
|
2000-01-16 02:48:12 +00:00
|
|
|
*/
|
2000-08-31 11:12:19 +00:00
|
|
|
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 (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);
|
|
|
|
}
|
2000-01-16 02:48:12 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2000-12-23 19:50:36 +00:00
|
|
|
#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.
|
|
|
|
*/
|
|
|
|
il = g_list_insert(il, g_strdup("any"), -1);
|
|
|
|
pcap_close(pch);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-09-07 09:57:39 +00:00
|
|
|
g_free(ifc.ifc_buf);
|
2000-01-16 02:48:12 +00:00
|
|
|
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);
|
|
|
|
}
|
2000-08-31 11:12:19 +00:00
|
|
|
g_free(ifc.ifc_buf);
|
2000-01-16 02:48:12 +00:00
|
|
|
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;
|
|
|
|
}
|
2000-02-09 19:18:42 +00:00
|
|
|
#else
|
|
|
|
GList *
|
|
|
|
get_interface_list(int *err, char *err_str) {
|
|
|
|
GList *il = NULL;
|
|
|
|
wchar_t *names;
|
2000-03-21 06:52:13 +00:00
|
|
|
char *win95names;
|
2000-02-09 19:18:42 +00:00
|
|
|
char newname[255];
|
|
|
|
int i, j, done;
|
|
|
|
|
|
|
|
names = (wchar_t *)pcap_lookupdev(err_str);
|
|
|
|
i = done = 0;
|
|
|
|
|
2000-03-21 06:52:13 +00:00
|
|
|
if (names) {
|
|
|
|
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 */
|
|
|
|
do
|
|
|
|
{
|
|
|
|
j = 0;
|
|
|
|
while (names[i] != 0)
|
|
|
|
newname[j++] = names[i++];
|
|
|
|
i++;
|
|
|
|
if (names[i] == 0)
|
|
|
|
done = 1;
|
|
|
|
newname[j++] = 0;
|
|
|
|
il = g_list_append(il, g_strdup(newname));
|
|
|
|
} while (!done);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Otherwise we are in Windows 95/98 and using ascii(8 bit)
|
|
|
|
characters */
|
|
|
|
do
|
|
|
|
{
|
2001-03-22 06:14:27 +00:00
|
|
|
win95names=(char *)names;
|
2000-03-21 06:52:13 +00:00
|
|
|
j = 0;
|
|
|
|
while (win95names[i] != 0)
|
|
|
|
newname[j++] = win95names[i++];
|
|
|
|
i++;
|
|
|
|
if (win95names[i] == 0)
|
|
|
|
done = 1;
|
|
|
|
newname[j++] = 0;
|
|
|
|
il = g_list_append(il, g_strdup(newname));
|
|
|
|
} while (!done);
|
|
|
|
}
|
|
|
|
}
|
2000-02-09 19:18:42 +00:00
|
|
|
return(il);
|
|
|
|
}
|
|
|
|
#endif
|
2000-01-16 02:48:12 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-01-29 19:06:59 +00:00
|
|
|
#endif /* HAVE_LIBPCAP */
|
|
|
|
|
2000-09-10 06:44:39 +00:00
|
|
|
|
|
|
|
/* Compute the difference between two seconds/microseconds time stamps. */
|
|
|
|
void
|
|
|
|
compute_timestamp_diff(gint *diffsec, gint *diffusec,
|
|
|
|
guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2)
|
|
|
|
{
|
|
|
|
if (sec1 == sec2) {
|
|
|
|
/* The seconds part of the first time is the same as the seconds
|
|
|
|
part of the second time, so if the microseconds part of the first
|
|
|
|
time is less than the microseconds part of the second time, the
|
|
|
|
first time is before the second time. The microseconds part of
|
|
|
|
the delta should just be the difference between the microseconds
|
|
|
|
part of the first time and the microseconds part of the second
|
|
|
|
time; don't adjust the seconds part of the delta, as it's OK if
|
|
|
|
the microseconds part is negative. */
|
|
|
|
|
|
|
|
*diffsec = sec1 - sec2;
|
|
|
|
*diffusec = usec1 - usec2;
|
|
|
|
} else if (sec1 <= sec2) {
|
|
|
|
/* The seconds part of the first time is less than the seconds part
|
|
|
|
of the second time, so the first time is before the second time.
|
|
|
|
|
|
|
|
Both the "seconds" and "microseconds" value of the delta
|
|
|
|
should have the same sign, so if the difference between the
|
|
|
|
microseconds values would be *positive*, subtract 1,000,000
|
|
|
|
from it, and add one to the seconds value. */
|
|
|
|
*diffsec = sec1 - sec2;
|
|
|
|
if (usec2 >= usec1) {
|
|
|
|
*diffusec = usec1 - usec2;
|
|
|
|
} else {
|
|
|
|
*diffusec = (usec1 - 1000000) - usec2;
|
|
|
|
(*diffsec)++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Oh, good, we're not caught in a chronosynclastic infindibulum. */
|
|
|
|
*diffsec = sec1 - sec2;
|
|
|
|
if (usec2 <= usec1) {
|
|
|
|
*diffusec = usec1 - usec2;
|
|
|
|
} else {
|
|
|
|
*diffusec = (usec1 + 1000000) - usec2;
|
|
|
|
(*diffsec)--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|