MSWSP: WIP: dissect_CPMSetBindings()
[wireshark-wip.git] / capture-pcap-util-unix.c
blobf0b6825ce0ac1bfa1d2f9b7facf2a2f5b518e904
1 /* capture-pcap-util-unix.c
2 * UN*X-specific utility routines for packet capture
4 * $Id$
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "config.h"
27 #include <glib.h>
29 #ifdef HAVE_LIBPCAP
31 #ifndef HAVE_PCAP_FINDALLDEVS
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <errno.h>
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
42 #ifdef HAVE_SYS_SOCKET_H
43 #include <sys/socket.h>
44 #endif
46 #ifdef HAVE_SYS_IOCTL_H
47 #include <sys/ioctl.h>
48 #endif
51 * Keep Digital UNIX happy when including <net/if.h>.
53 struct mbuf;
54 struct rtentry;
55 #include <net/if.h>
57 #ifdef HAVE_SYS_SOCKIO_H
58 # include <sys/sockio.h>
59 #endif
61 #include "capture-pcap-util.h"
63 #else
65 #include <pcap.h>
67 #endif /* HAVE_PCAP_FINDALLDEVS */
69 #include "capture_ifinfo.h"
70 #include "capture-pcap-util-int.h"
72 #ifndef HAVE_PCAP_FINDALLDEVS
73 struct search_user_data {
74 char *name;
75 if_info_t *if_info;
78 static void
79 search_for_if_cb(gpointer data, gpointer user_data);
80 #endif
82 #ifdef HAVE_PCAP_REMOTE
83 GList *
84 get_remote_interface_list(const char *hostname, const char *port,
85 int auth_type, const char *username,
86 const char *passwd, int *err, char **err_str)
88 struct pcap_rmtauth auth;
89 char source[PCAP_BUF_SIZE];
90 char errbuf[PCAP_ERRBUF_SIZE];
91 GList *result;
93 if (pcap_createsrcstr(source, PCAP_SRC_IFREMOTE, hostname, port,
94 NULL, errbuf) == -1) {
95 *err = CANT_GET_INTERFACE_LIST;
96 if (err_str != NULL)
97 *err_str = cant_get_if_list_error_message(errbuf);
98 return NULL;
101 auth.type = auth_type;
102 auth.username = g_strdup(username);
103 auth.password = g_strdup(passwd);
105 result = get_interface_list_findalldevs_ex(source, &auth, err, err_str);
106 g_free(auth.username);
107 g_free(auth.password);
109 return result;
111 #endif
113 GList *
114 get_interface_list(int *err, char **err_str)
116 #ifdef HAVE_PCAP_FINDALLDEVS
117 return get_interface_list_findalldevs(err, err_str);
118 #else
119 GList *il = NULL;
120 gint nonloopback_pos = 0;
121 struct ifreq *ifr, *last;
122 struct ifconf ifc;
123 struct ifreq ifrflags;
124 int sock = socket(AF_INET, SOCK_DGRAM, 0);
125 struct search_user_data user_data;
126 pcap_t *pch;
127 int len, lastlen;
128 char *buf;
129 if_info_t *if_info;
130 char errbuf[PCAP_ERRBUF_SIZE];
131 gboolean loopback;
133 if (sock < 0) {
134 *err = CANT_GET_INTERFACE_LIST;
135 if (err_str != NULL) {
136 *err_str = g_strdup_printf(
137 "Can't get list of interfaces: error opening socket: %s",
138 g_strerror(errno));
140 return NULL;
144 * This code came from: W. Richard Stevens: "UNIX Network Programming",
145 * Networking APIs: Sockets and XTI, Vol 1, page 434.
147 lastlen = 0;
148 len = 100 * sizeof(struct ifreq);
149 for ( ; ; ) {
150 buf = g_malloc(len);
151 ifc.ifc_len = len;
152 ifc.ifc_buf = buf;
153 memset (buf, 0, len);
154 if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
155 if (errno != EINVAL || lastlen != 0) {
156 if (err_str != NULL) {
157 *err_str = g_strdup_printf(
158 "Can't get list of interfaces: SIOCGIFCONF ioctl error: %s",
159 g_strerror(errno));
161 goto fail;
163 } else {
164 if ((unsigned int) ifc.ifc_len < sizeof(struct ifreq)) {
165 if (err_str != NULL) {
166 *err_str = g_strdup(
167 "Can't get list of interfaces: SIOCGIFCONF ioctl gave too small return buffer");
169 goto fail;
171 if (ifc.ifc_len == lastlen)
172 break; /* success, len has not changed */
173 lastlen = ifc.ifc_len;
175 len += 10 * sizeof(struct ifreq); /* increment */
176 g_free(buf);
178 ifr = (struct ifreq *) ifc.ifc_req;
179 last = (struct ifreq *) ((char *) ifr + ifc.ifc_len);
180 while (ifr < last) {
182 * Skip entries that begin with "dummy", or that include
183 * a ":" (the latter are Solaris virtuals).
185 if (strncmp(ifr->ifr_name, "dummy", 5) == 0 ||
186 strchr(ifr->ifr_name, ':') != NULL)
187 goto next;
190 * If we already have this interface name on the list,
191 * don't add it, but, if we don't already have an IP
192 * address for it, add that address (SIOCGIFCONF returns,
193 * at least on BSD-flavored systems, one entry per
194 * interface *address*; if an interface has multiple
195 * addresses, we get multiple entries for it).
197 user_data.name = ifr->ifr_name;
198 user_data.if_info = NULL;
199 g_list_foreach(il, search_for_if_cb, &user_data);
200 if (user_data.if_info != NULL) {
201 if_info_add_address(user_data.if_info, &ifr->ifr_addr);
202 goto next;
206 * Get the interface flags.
208 memset(&ifrflags, 0, sizeof ifrflags);
209 g_strlcpy(ifrflags.ifr_name, ifr->ifr_name,
210 sizeof ifrflags.ifr_name);
211 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
212 if (errno == ENXIO)
213 goto next;
214 if (err_str != NULL) {
215 *err_str = g_strdup_printf(
216 "Can't get list of interfaces: SIOCGIFFLAGS error getting flags for interface %s: %s",
217 ifr->ifr_name, g_strerror(errno));
219 goto fail;
223 * Skip interfaces that aren't up.
225 if (!(ifrflags.ifr_flags & IFF_UP))
226 goto next;
229 * Skip interfaces that we can't open with "libpcap".
230 * Open with the minimum packet size - it appears that the
231 * IRIX SIOCSNOOPLEN "ioctl" may fail if the capture length
232 * supplied is too large, rather than just truncating it.
234 pch = pcap_open_live(ifr->ifr_name, MIN_PACKET_SIZE, 0, 0,
235 errbuf);
236 if (pch == NULL)
237 goto next;
238 pcap_close(pch);
241 * If it's a loopback interface, add it at the end of the
242 * list, otherwise add it after the last non-loopback
243 * interface, so all loopback interfaces go at the end - we
244 * don't want a loopback interface to be the default capture
245 * device unless there are no non-loopback devices.
247 loopback = ((ifrflags.ifr_flags & IFF_LOOPBACK) ||
248 strncmp(ifr->ifr_name, "lo", 2) == 0);
249 if_info = if_info_new(ifr->ifr_name, NULL, loopback);
250 if_info_add_address(if_info, &ifr->ifr_addr);
251 if (loopback)
252 il = g_list_append(il, if_info);
253 else {
254 il = g_list_insert(il, if_info, nonloopback_pos);
256 * Insert the next non-loopback interface after this
257 * one.
259 nonloopback_pos++;
262 next:
263 #ifdef HAVE_SA_LEN
264 ifr = (struct ifreq *) ((char *) ifr +
265 (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr) ?
266 ifr->ifr_addr.sa_len : sizeof(ifr->ifr_addr)) +
267 IFNAMSIZ);
268 #else
269 ifr = (struct ifreq *) ((char *) ifr + sizeof(struct ifreq));
270 #endif
273 #ifdef linux
275 * OK, maybe we have support for the "any" device, to do a cooked
276 * capture on all interfaces at once.
277 * Try opening it and, if that succeeds, add it to the end of
278 * the list of interfaces.
280 pch = pcap_open_live("any", MIN_PACKET_SIZE, 0, 0, errbuf);
281 if (pch != NULL) {
283 * It worked; we can use the "any" device.
285 if_info = if_info_new("any",
286 "Pseudo-device that captures on all interfaces", FALSE);
287 il = g_list_insert(il, if_info, -1);
288 pcap_close(pch);
290 #endif
292 g_free(ifc.ifc_buf);
293 close(sock);
295 if (il == NULL) {
297 * No interfaces found.
299 *err = NO_INTERFACES_FOUND;
300 if (err_str != NULL)
301 *err_str = NULL;
303 return il;
305 fail:
306 if (il != NULL)
307 free_interface_list(il);
308 g_free(ifc.ifc_buf);
309 close(sock);
310 *err = CANT_GET_INTERFACE_LIST;
311 return NULL;
312 #endif /* HAVE_PCAP_FINDALLDEVS */
315 #ifndef HAVE_PCAP_FINDALLDEVS
316 static void
317 search_for_if_cb(gpointer data, gpointer user_data)
319 struct search_user_data *search_user_data = user_data;
320 if_info_t *if_info = data;
322 if (strcmp(if_info->name, search_user_data->name) == 0)
323 search_user_data->if_info = if_info;
325 #endif /* HAVE_PCAP_FINDALLDEVS */
328 * Get an error message string for a CANT_GET_INTERFACE_LIST error from
329 * "get_interface_list()".
331 gchar *
332 cant_get_if_list_error_message(const char *err_str)
334 return g_strdup_printf("Can't get list of interfaces: %s", err_str);
338 * Append the version of libpcap with which we were compiled to a GString.
340 void
341 get_compiled_pcap_version(GString *str)
344 * NOTE: in *some* flavors of UN*X, the data from a shared
345 * library might be linked into executable images that are
346 * linked with that shared library, in which case you could
347 * look at pcap_version[] to get the version with which
348 * the program was compiled.
350 * In other flavors of UN*X, that doesn't happen, so
351 * pcap_version[] gives you the version the program is
352 * running with, not the version it was built with, and,
353 * in at least some of them, if the length of a data item
354 * referred to by the executable - such as the pcap_version[]
355 * string - isn't the same in the version of the library
356 * with which the program was built and the version with
357 * which it was run, the run-time linker will complain,
358 * which is Not Good.
360 * So, for now, we just give up on reporting the version
361 * of libpcap with which we were compiled.
363 g_string_append(str, "with libpcap");
367 * Append the version of libpcap with which we we're running to a GString.
369 void
370 get_runtime_pcap_version(GString *str)
372 g_string_append_printf(str, "with ");
373 #ifdef HAVE_PCAP_LIB_VERSION
374 g_string_append(str, pcap_lib_version());
375 #else
376 g_string_append(str, "libpcap (version unknown)");
377 #endif
380 #else /* HAVE_LIBPCAP */
383 * Append an indication that we were not compiled with libpcap
384 * to a GString.
386 void
387 get_compiled_pcap_version(GString *str)
389 g_string_append(str, "without libpcap");
393 * Don't append anything, as we weren't even compiled to use WinPcap.
395 void
396 get_runtime_pcap_version(GString *str _U_)
400 #endif /* HAVE_LIBPCAP */