4 * $Id: util.c,v 1.75 2003/12/21 12:19:39 ulfl Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #endif /* HAVE_LIBPCAP */
44 #ifdef HAVE_SYS_STAT_H
48 #ifdef NEED_SNPRINTF_H
49 # include "snprintf.h"
59 typedef int mode_t; /* for win32 */
60 #endif /* __MINGW32__ */
61 #endif /* HAVE_IO_H */
64 #include <zlib.h> /* to get the libz version number */
68 #include <pcre.h> /* to get the libpcre version number */
69 #endif /* HAVE_LIBPCRE */
72 * This has to come after the include of <pcap.h>, as the include of
73 * <pcap.h> might cause <winsock2.h> to be included, and if we've
74 * already included <winsock.h> as a result of including <windows.h>,
75 * we get a bunch of redefinitions.
84 #include <net-snmp/version.h>
85 #endif /* HAVE_NET_SNMP */
88 #include <ucd-snmp/version.h>
89 #endif /* HAVE_UCD_SNMP */
91 #endif /* HAVE_SOME_SNMP */
93 #ifdef HAVE_SYS_UTSNAME_H
94 #include <sys/utsname.h>
98 #include "pcap-util.h"
101 * See whether the last line in the string goes past column 80; if so,
102 * replace the blank at the specified point with a newline.
105 do_word_wrap(GString *str, gint point)
109 line_begin = strrchr(str->str, '\n');
110 if (line_begin == NULL)
111 line_begin = str->str;
114 if (strlen(line_begin) > 80) {
115 g_assert(str->str[point] == ' ');
116 str->str[point] = '\n';
121 * Get various library compile-time versions and append them to
122 * the specified GString.
125 get_compiled_version_info(GString *str)
129 g_string_append(str, "with ");
130 g_string_sprintfa(str,
131 #ifdef GLIB_MAJOR_VERSION
132 "GLib %d.%d.%d,", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
135 "GLib (version unknown),");
138 g_string_append(str, " ");
139 break_point = str->len - 1;
140 get_compiled_pcap_version(str);
141 g_string_append(str, ",");
142 do_word_wrap(str, break_point);
144 g_string_append(str, " ");
145 break_point = str->len - 1;
147 g_string_append(str, "with libz ");
149 g_string_append(str, ZLIB_VERSION);
150 #else /* ZLIB_VERSION */
151 g_string_append(str, "(version unknown)");
152 #endif /* ZLIB_VERSION */
153 #else /* HAVE_LIBZ */
154 g_string_append(str, "without libz");
155 #endif /* HAVE_LIBZ */
156 g_string_append(str, ",");
157 do_word_wrap(str, break_point);
159 g_string_append(str, " ");
160 break_point = str->len - 1;
162 g_string_append(str, "with libpcre ");
165 g_string_sprintfa(str, "%u.%u", PCRE_MAJOR, PCRE_MINOR);
166 #else /* PCRE_MINOR */
167 g_string_sprintfa(str, "%u", PCRE_MAJOR);
168 #endif /* PCRE_MINOR */
169 #else /* PCRE_MAJOR */
170 g_string_append(str, "(version unknown)");
171 #endif /* PCRE_MAJOR */
172 #else /* HAVE_LIBPCRE */
173 g_string_append(str, "without libpcre");
174 #endif /* HAVE_LIBPCRE */
176 g_string_append(str, ",");
177 do_word_wrap(str, break_point);
179 /* Oh, this is pretty. */
180 /* Oh, ha. you think that was pretty. Try this:! --Wes */
181 g_string_append(str, " ");
182 break_point = str->len - 1;
183 #ifdef HAVE_SOME_SNMP
186 g_string_append(str, "with UCD-SNMP ");
187 g_string_append(str, VersionInfo);
188 #endif /* HAVE_UCD_SNMP */
191 g_string_append(str, "with Net-SNMP ");
192 g_string_append(str, netsnmp_get_version());
193 #endif /* HAVE_NET_SNMP */
195 #else /* no SNMP library */
196 g_string_append(str, "without UCD-SNMP or Net-SNMP");
197 #endif /* HAVE_SOME_SNMP */
198 g_string_append(str, ",");
199 do_word_wrap(str, break_point);
201 g_string_append(str, " ");
202 break_point = str->len - 1;
204 g_string_append(str, "with ADNS");
206 g_string_append(str, "without ADNS");
207 #endif /* HAVE_GNU_ADNS */
209 g_string_append(str, ".");
210 do_word_wrap(str, break_point);
213 break_point = str->len - 1;
215 "\nNOTE: this build does not support the \"matches\" operator"
216 "\nfor Ethereal filter syntax.\n");
217 do_word_wrap(str, break_point);
218 #endif /* HAVE_LIBPCRE */
222 * Get various library run-time versions, and the OS version, and append
223 * them to the specified GString.
226 get_runtime_version_info(GString *str)
230 #elif defined(HAVE_SYS_UTSNAME_H)
234 get_runtime_pcap_version(str);
236 g_string_append(str, "on ");
238 info.dwOSVersionInfoSize = sizeof info;
239 if (!GetVersionEx(&info)) {
241 * XXX - get the failure reason.
243 g_string_append(str, "unknown Windows version");
246 switch (info.dwPlatformId) {
248 case VER_PLATFORM_WIN32s:
250 g_string_sprintfa(str, "Windows 3.1 with Win32s");
253 case VER_PLATFORM_WIN32_WINDOWS:
255 switch (info.dwMajorVersion) {
258 /* 3 cheers for Microsoft marketing! */
259 switch (info.dwMinorVersion) {
262 g_string_sprintfa(str, "Windows 95");
266 g_string_sprintfa(str, "Windows 98");
270 g_string_sprintfa(str, "Windows Me");
274 g_string_sprintfa(str, "Windows OT, unknown version %lu.%lu",
275 info.dwMajorVersion, info.dwMinorVersion);
281 g_string_sprintfa(str, "Windows OT, unknown version %lu.%lu",
282 info.dwMajorVersion, info.dwMinorVersion);
287 case VER_PLATFORM_WIN32_NT:
289 switch (info.dwMajorVersion) {
293 g_string_sprintfa(str, "Windows NT %lu.%lu",
294 info.dwMajorVersion, info.dwMinorVersion);
298 /* 3 cheers for Microsoft marketing! */
299 switch (info.dwMinorVersion) {
302 g_string_sprintfa(str, "Windows 2000");
306 g_string_sprintfa(str, "Windows XP");
310 g_string_sprintfa(str, "Windows Server 2003");
314 g_string_sprintfa(str, "Windows NT, unknown version %lu.%lu",
315 info.dwMajorVersion, info.dwMinorVersion);
321 g_string_sprintfa(str, "Windows NT, unknown version %lu.%lu",
322 info.dwMajorVersion, info.dwMinorVersion);
328 g_string_sprintfa(str, "Unknown Windows platform %lu version %lu.%lu",
329 info.dwPlatformId, info.dwMajorVersion, info.dwMinorVersion);
332 if (info.szCSDVersion[0] != '\0')
333 g_string_sprintfa(str, " %s", info.szCSDVersion);
334 g_string_sprintfa(str, ", build %lu", info.dwBuildNumber);
335 #elif defined(HAVE_SYS_UTSNAME_H)
337 * We have <sys/utsname.h>, so we assume we have "uname()".
339 if (uname(&name) < 0) {
340 g_string_sprintfa(str, "unknown OS version (uname failed - %s)",
345 if (strcmp(name.sysname, "AIX") == 0) {
347 * Yay, IBM! Thanks for doing something different
348 * from most of the other UNIXes out there, and
349 * making "name.version" apparently be the major
350 * version number and "name.release" be the minor
353 g_string_sprintfa(str, "%s %s.%s", name.sysname, name.version,
357 * XXX - get "version" on any other platforms?
359 * On Digital/Tru65 UNIX, it's something unknown.
360 * On Solaris, it's some kind of build information.
361 * On HP-UX, it appears to be some sort of subrevision
364 g_string_sprintfa(str, "%s %s", name.sysname, name.release);
367 g_string_append(str, "an unknown OS");
372 * Collect command-line arguments as a string consisting of the arguments,
373 * separated by spaces.
376 get_args_as_string(int argc, char **argv, int optind)
383 * Find out how long the string will be.
386 for (i = optind; i < argc; i++) {
387 len += strlen(argv[i]);
388 len++; /* space, or '\0' if this is the last argument */
392 * Allocate the buffer for the string.
394 argstring = g_malloc(len);
397 * Now construct the string.
399 strcpy(argstring, "");
402 strcat(argstring, argv[i]);
406 strcat(argstring, " ");
412 setup_tmpdir(char *dir)
414 int len = strlen(dir);
417 /* Append slash if necessary */
418 if (dir[len - 1] == '/') {
422 newdir = g_malloc(len + 2);
430 try_tempfile(char *namebuf, int namebuflen, const char *dir, const char *pfx)
432 static const char suffix[] = "XXXXXXXXXX";
433 int namelen = strlen(dir) + strlen(pfx) + sizeof suffix;
437 if (namebuflen < namelen) {
438 /* Stick in a truncated name, so that if this error is
439 reported with the file name, you at least get
441 snprintf(namebuf, namebuflen, "%s%s%s", dir, pfx, suffix);
442 errno = ENAMETOOLONG;
445 strcpy(namebuf, dir);
446 strcat(namebuf, pfx);
447 strcat(namebuf, suffix);
449 /* The Single UNIX Specification doesn't say that "mkstemp()"
450 creates the temporary file with mode rw-------, so we
451 won't assume that all UNIXes will do so; instead, we set
452 the umask to 0077 to take away all group and other
453 permissions, attempt to create the file, and then put
455 old_umask = umask(0077);
456 tmp_fd = mkstemp(namebuf);
461 static char *tmpdir = NULL;
463 static char *temp = NULL;
465 static char *E_tmpdir;
468 #define P_tmpdir "/var/tmp"
472 create_tempfile(char *namebuf, int namebuflen, const char *pfx)
476 static gboolean initialized;
479 if ((dir = getenv("TMPDIR")) != NULL)
480 tmpdir = setup_tmpdir(dir);
482 if ((dir = getenv("TEMP")) != NULL)
483 temp = setup_tmpdir(dir);
486 E_tmpdir = setup_tmpdir(P_tmpdir);
490 if (tmpdir != NULL) {
491 fd = try_tempfile(namebuf, namebuflen, tmpdir, pfx);
498 fd = try_tempfile(namebuf, namebuflen, temp, pfx);
504 fd = try_tempfile(namebuf, namebuflen, E_tmpdir, pfx);
508 return try_tempfile(namebuf, namebuflen, "/tmp", pfx);
511 /* ASCII/EBCDIC conversion tables from
512 * http://www.room42.com/store/computer_center/code_tables.shtml
515 static guint8 ASCII_translate_EBCDIC [ 256 ] = {
516 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
517 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
518 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
519 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
520 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D,
521 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
522 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
523 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
524 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,
525 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
526 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
527 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
528 0x7D, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
529 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
530 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
531 0xA8, 0xA9, 0xC0, 0x6A, 0xD0, 0xA1, 0x4B,
532 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
533 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
534 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
535 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
536 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
537 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
538 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
539 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
540 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
541 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
542 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
543 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
544 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
545 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
546 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
547 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B
551 ASCII_to_EBCDIC(guint8 *buf, guint bytes)
558 for (i = 0; i < bytes; i++, bufptr++) {
559 *bufptr = ASCII_translate_EBCDIC[*bufptr];
564 ASCII_to_EBCDIC1(guint8 c)
566 return ASCII_translate_EBCDIC[c];
570 static guint8 EBCDIC_translate_ASCII [ 256 ] = {
571 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
572 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
573 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
574 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
575 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
576 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
577 0x2E, 0x2E, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
578 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x2E, 0x3F,
579 0x20, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
580 0x2E, 0x2E, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
581 0x26, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
582 0x2E, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
583 0x2D, 0x2F, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
584 0x2E, 0x7C, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
585 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
586 0x2E, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
587 0x2E, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
588 0x69, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
589 0x2E, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
590 0x72, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
591 0x2E, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
592 0x7A, 0x2E, 0x2E, 0x2E, 0x5B, 0x2E, 0x2E,
593 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
594 0x2E, 0x2E, 0x2E, 0x2E, 0x5D, 0x2E, 0x2E,
595 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
596 0x49, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
597 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
598 0x52, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
599 0x5C, 0x2E, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
600 0x5A, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
601 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
602 0x39, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E
606 EBCDIC_to_ASCII(guint8 *buf, guint bytes)
613 for (i = 0; i < bytes; i++, bufptr++) {
614 *bufptr = EBCDIC_translate_ASCII[*bufptr];
619 EBCDIC_to_ASCII1(guint8 c)
621 return EBCDIC_translate_ASCII[c];
624 /* Compute the difference between two seconds/microseconds time stamps. */
626 compute_timestamp_diff(gint *diffsec, gint *diffusec,
627 guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2)
630 /* The seconds part of the first time is the same as the seconds
631 part of the second time, so if the microseconds part of the first
632 time is less than the microseconds part of the second time, the
633 first time is before the second time. The microseconds part of
634 the delta should just be the difference between the microseconds
635 part of the first time and the microseconds part of the second
636 time; don't adjust the seconds part of the delta, as it's OK if
637 the microseconds part is negative. */
639 *diffsec = sec1 - sec2;
640 *diffusec = usec1 - usec2;
641 } else if (sec1 <= sec2) {
642 /* The seconds part of the first time is less than the seconds part
643 of the second time, so the first time is before the second time.
645 Both the "seconds" and "microseconds" value of the delta
646 should have the same sign, so if the difference between the
647 microseconds values would be *positive*, subtract 1,000,000
648 from it, and add one to the seconds value. */
649 *diffsec = sec1 - sec2;
650 if (usec2 >= usec1) {
651 *diffusec = usec1 - usec2;
653 *diffusec = (usec1 - 1000000) - usec2;
657 /* Oh, good, we're not caught in a chronosynclastic infindibulum. */
658 *diffsec = sec1 - sec2;
659 if (usec2 <= usec1) {
660 *diffusec = usec1 - usec2;
662 *diffusec = (usec1 + 1000000) - usec2;
668 /* Decode a base64 string in-place - simple and slow algorithm.
669 Return length of result. Taken from rproxy/librsync/base64.c by
672 size_t base64_decode(char *s)
674 static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
675 int bit_offset, byte_offset, idx, i, n;
676 unsigned char *d = (unsigned char *)s;
681 while (*s && (p=strchr(b64, *s))) {
682 idx = (int)(p - b64);
683 byte_offset = (i*6)/8;
684 bit_offset = (i*6)%8;
685 d[byte_offset] &= ~((1<<(8-bit_offset))-1);
686 if (bit_offset < 3) {
687 d[byte_offset] |= (idx << (2-bit_offset));
690 d[byte_offset] |= (idx >> (bit_offset-2));
691 d[byte_offset+1] = 0;
692 d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
701 /* Try to figure out if we're remotely connected, e.g. via ssh or
702 Terminal Server, and create a capture filter that matches aspects of the
703 connection. We match the following environment variables:
705 SSH_CONNECTION (ssh): <remote IP> <remote port> <local IP> <local port>
706 SSH_CLIENT (ssh): <remote IP> <remote port> <local port>
707 REMOTEHOST (tcsh, others?): <remote name>
708 DISPLAY (x11): [remote name]:<display num>
709 CLIENTNAME (terminal server): <remote name>
712 gchar *get_conn_cfilter(void) {
713 static GString *filter_str = NULL;
714 gchar *env, **tokens;
716 if (filter_str == NULL) {
717 filter_str = g_string_new("");
719 if ((env = getenv("SSH_CONNECTION")) != NULL) {
720 tokens = g_strsplit(env, " ", 4);
722 g_string_sprintf(filter_str, "not (tcp port %s and ip host %s "
723 "and tcp port %s and ip host %s)", tokens[1], tokens[0],
724 tokens[3], tokens[2]);
725 return filter_str->str;
727 } else if ((env = getenv("SSH_CLIENT")) != NULL) {
728 tokens = g_strsplit(env, " ", 3);
729 g_string_sprintf(filter_str, "not (tcp port %s and ip host %s "
730 "and tcp port %s)", tokens[1], tokens[0], tokens[2]);
731 return filter_str->str;
732 } else if ((env = getenv("REMOTEHOST")) != NULL) {
733 g_string_sprintf(filter_str, "not ip host %s", env);
734 return filter_str->str;
735 } else if ((env = getenv("DISPLAY")) != NULL) {
736 tokens = g_strsplit(env, ":", 2);
737 if (tokens[0] && tokens[0][0] != 0) {
738 g_string_sprintf(filter_str, "not ip host %s",
740 return filter_str->str;
742 } else if ((env = getenv("CLIENTNAME")) != NULL) {
743 if (g_strcasecmp("console", env) != 0) {
744 g_string_sprintf(filter_str, "not ip host %s", env);
745 return filter_str->str;