6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
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.
40 #include <epan/address.h>
41 #include <epan/addr_resolv.h>
42 #include <epan/ws_strsplit.h>
46 #ifdef NEED_G_ASCII_STRCASECMP_H
47 #include "epan/g_ascii_strcasecmp.h"
51 * Collect command-line arguments as a string consisting of the arguments,
52 * separated by spaces.
55 get_args_as_string(int argc, char **argv, int optind)
62 * Find out how long the string will be.
65 for (i = optind; i < argc; i++) {
66 len += strlen(argv[i]);
67 len++; /* space, or '\0' if this is the last argument */
71 * Allocate the buffer for the string.
73 argstring = g_malloc(len);
76 * Now construct the string.
81 strncat(argstring, argv[i], len - strlen(argstring));
85 strncat(argstring, " ", len - strlen(argstring));
90 /* Compute the difference between two seconds/microseconds time stamps. */
92 compute_timestamp_diff(gint *diffsec, gint *diffusec,
93 guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2)
96 /* The seconds part of the first time is the same as the seconds
97 part of the second time, so if the microseconds part of the first
98 time is less than the microseconds part of the second time, the
99 first time is before the second time. The microseconds part of
100 the delta should just be the difference between the microseconds
101 part of the first time and the microseconds part of the second
102 time; don't adjust the seconds part of the delta, as it's OK if
103 the microseconds part is negative. */
105 *diffsec = sec1 - sec2;
106 *diffusec = usec1 - usec2;
107 } else if (sec1 <= sec2) {
108 /* The seconds part of the first time is less than the seconds part
109 of the second time, so the first time is before the second time.
111 Both the "seconds" and "microseconds" value of the delta
112 should have the same sign, so if the difference between the
113 microseconds values would be *positive*, subtract 1,000,000
114 from it, and add one to the seconds value. */
115 *diffsec = sec1 - sec2;
116 if (usec2 >= usec1) {
117 *diffusec = usec1 - usec2;
119 *diffusec = (usec1 - 1000000) - usec2;
123 /* Oh, good, we're not caught in a chronosynclastic infindibulum. */
124 *diffsec = sec1 - sec2;
125 if (usec2 <= usec1) {
126 *diffusec = usec1 - usec2;
128 *diffusec = (usec1 + 1000000) - usec2;
134 /* Try to figure out if we're remotely connected, e.g. via ssh or
135 Terminal Server, and create a capture filter that matches aspects of the
136 connection. We match the following environment variables:
138 SSH_CONNECTION (ssh): <remote IP> <remote port> <local IP> <local port>
139 SSH_CLIENT (ssh): <remote IP> <remote port> <local port>
140 REMOTEHOST (tcsh, others?): <remote name>
141 DISPLAY (x11): [remote name]:<display num>
142 SESSIONNAME (terminal server): <remote name>
145 const gchar *get_conn_cfilter(void) {
146 static GString *filter_str = NULL;
147 gchar *env, **tokens;
148 char *lastp, *lastc, *p;
149 char *pprotocol = NULL;
150 char *phostname = NULL;
153 if (filter_str == NULL) {
154 filter_str = g_string_new("");
156 if ((env = getenv("SSH_CONNECTION")) != NULL) {
157 tokens = g_strsplit(env, " ", 4);
159 g_string_sprintf(filter_str, "not (tcp port %s and %s host %s "
160 "and tcp port %s and %s host %s)", tokens[1], host_ip_af(tokens[0]), tokens[0],
161 tokens[3], host_ip_af(tokens[2]), tokens[2]);
162 return filter_str->str;
164 } else if ((env = getenv("SSH_CLIENT")) != NULL) {
165 tokens = g_strsplit(env, " ", 3);
166 g_string_sprintf(filter_str, "not (tcp port %s and %s host %s "
167 "and tcp port %s)", tokens[1], host_ip_af(tokens[0]), tokens[0], tokens[2]);
168 return filter_str->str;
169 } else if ((env = getenv("REMOTEHOST")) != NULL) {
170 if (g_ascii_strcasecmp(env, "localhost") == 0 || strcmp(env, "127.0.0.1") == 0) {
173 g_string_sprintf(filter_str, "not %s host %s", host_ip_af(env), env);
174 return filter_str->str;
175 } else if ((env = getenv("DISPLAY")) != NULL) {
177 * This mirrors what _X11TransConnectDisplay() does.
178 * Note that, on some systems, the hostname can
179 * being with "/", which means that it's a pathname
180 * of a UNIX domain socket to connect to.
182 * The comments mirror those in _X11TransConnectDisplay(),
185 * Display names may be of the following format:
187 * [protoco./] [hostname] : [:] displaynumber [.screennumber]
189 * A string with exactly two colons separating hostname
190 * from the display indicates a DECnet style name. Colons
191 * in the hostname may occur if an IPv6 numeric address
192 * is used as the hostname. An IPv6 numeric address may
193 * also end in a double colon, so three colons in a row
194 * indicates an IPv6 address ending in :: followed by
195 * :display. To make it easier for people to read, an
196 * IPv6 numeric address hostname may be surrounded by []
197 * in a similar fashion to the IPv6 numeric address URL
198 * syntax defined by IETF RFC 2732.
200 * If no hostname and no protocol is specified, the string
201 * is interpreted as the most efficient local connection
202 * to a server on the same machine. This is usually:
206 * o UNIX domain socket
207 * o TCP to local host.
213 * Step 0, find the protocol. This is delimited by
214 * the optional slash ('/').
216 for (lastp = p; *p != '\0' && *p != ':' && *p != '/'; p++)
219 return ""; /* must have a colon */
221 if (p != lastp && *p != ':') { /* protocol given? */
226 if (p - lastp != 3 || g_ascii_strncasecmp(lastp, "tcp", 3) != 0)
227 return ""; /* not TCP */
228 p++; /* skip the '/' */
230 p = env; /* reset the pointer in
231 case no protocol was given */
234 * Step 1, find the hostname. This is delimited either by
235 * one colon, or two colons in the case of DECnet (DECnet
236 * Phase V allows a single colon in the hostname). (See
237 * note above regarding IPv6 numeric addresses with
238 * triple colons or [] brackets.)
242 for (; *p != '\0'; p++)
247 return ""; /* must have a colon */
249 if ((lastp != lastc) && (*(lastc - 1) == ':')
250 && (((lastc - 1) == lastp) || (*(lastc - 2) != ':'))) {
251 /* DECnet display specified */
254 hostlen = lastc - lastp;
257 return ""; /* no hostname supplied */
259 phostname = g_malloc(hostlen + 1);
260 memcpy(phostname, lastp, hostlen);
261 phostname[hostlen] = '\0';
263 if (pprotocol == NULL) {
265 * No protocol was explicitly specified, so it
266 * could be a local connection over a transport
269 * Does the host name refer to the local host?
270 * If so, the connection would probably be a
273 * XXX - compare against our host name?
274 * _X11TransConnectDisplay() does.
276 if (g_ascii_strcasecmp(phostname, "localhost") == 0 ||
277 strcmp(phostname, "127.0.0.1") == 0) {
283 * A host name of "unix" (case-sensitive) also
284 * causes a local connection.
286 if (strcmp(phostname, "unix") == 0) {
292 * Does the host name begin with "/"? If so,
293 * it's presumed to be the pathname of a
294 * UNIX domain socket.
296 if (phostname[0] == '/') {
302 g_string_sprintf(filter_str, "not %s host %s",
303 host_ip_af(phostname), phostname);
305 return filter_str->str;
306 } else if ((env = getenv("SESSIONNAME")) != NULL) {
307 /* Apparently the KB article at
308 * http://technet2.microsoft.com/WindowsServer/en/library/6caf87bf-3d70-4801-9485-87e9ec3df0171033.mspx?mfr=true
309 * is incorrect. There are _plenty_ of cases where CLIENTNAME
310 * and SESSIONNAME are set outside of a Terminal Terver session.
311 * It looks like Terminal Server sets SESSIONNAME to RDP-TCP#<number>
312 * for "real" sessions.
314 * XXX - There's a better way to do this described at
315 * http://www.microsoft.com/technet/archive/termsrv/maintain/featusability/tsrvapi.mspx?mfr=true
317 if (g_ascii_strncasecmp(env, "rdp", 3) == 0) {
318 g_string_sprintf(filter_str, "not tcp port 3389");
319 return filter_str->str;