add details for doxygen
[obnox/wireshark/wip.git] / pcap-util-unix.c
1 /* pcap-util-unix.c
2  * UN*X-specific utility routines for packet capture
3  *
4  * $Id: pcap-util-unix.c,v 1.2 2003/10/10 06:05:48 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
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.
14  *
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.
19  *
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.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <glib.h>
30
31 #ifdef HAVE_LIBPCAP
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <errno.h>
37
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41
42 #ifdef HAVE_SYS_SOCKET_H
43 #include <sys/socket.h>
44 #endif
45
46 #ifdef HAVE_SYS_IOCTL_H
47 #include <sys/ioctl.h>
48 #endif
49
50 #include <pcap.h>
51
52 /*
53  * Keep Digital UNIX happy when including <net/if.h>.
54  */
55 struct mbuf;
56 struct rtentry;
57 #include <net/if.h>
58
59 #ifdef HAVE_SYS_SOCKIO_H
60 # include <sys/sockio.h>
61 #endif
62
63 #include "globals.h"
64
65 #include "pcap-util.h"
66 #include "pcap-util-int.h"
67
68 #ifndef HAVE_PCAP_FINDALLDEVS
69 struct search_user_data {
70         char    *name;
71         int     found;
72 };
73
74 static void
75 search_for_if_cb(gpointer data, gpointer user_data);
76 #endif
77
78 GList *
79 get_interface_list(int *err, char *err_str)
80 {
81 #ifdef HAVE_PCAP_FINDALLDEVS
82         return get_interface_list_findalldevs(err, err_str);
83 #else
84         GList  *il = NULL;
85         gint    nonloopback_pos = 0;
86         struct  ifreq *ifr, *last;
87         struct  ifconf ifc;
88         struct  ifreq ifrflags;
89         int     sock = socket(AF_INET, SOCK_DGRAM, 0);
90         struct search_user_data user_data;
91         pcap_t *pch;
92         int len, lastlen;
93         char *buf;
94         if_info_t *if_info;
95
96         if (sock < 0) {
97                 *err = CANT_GET_INTERFACE_LIST;
98                 sprintf(err_str, "Error opening socket: %s",
99                     strerror(errno));
100                 return NULL;
101         }
102
103         /*
104          * This code came from: W. Richard Stevens: "UNIX Network Programming",
105          * Networking APIs: Sockets and XTI, Vol 1, page 434.
106          */
107         lastlen = 0;
108         len = 100 * sizeof(struct ifreq);
109         for ( ; ; ) {
110                 buf = g_malloc(len);
111                 ifc.ifc_len = len;
112                 ifc.ifc_buf = buf;
113                 memset (buf, 0, len);
114                 if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
115                         if (errno != EINVAL || lastlen != 0) {
116                                 sprintf(err_str,
117                                         "SIOCGIFCONF ioctl error getting list of interfaces: %s",
118                                         strerror(errno));
119                                 goto fail;
120                         }
121                 } else {
122                         if ((unsigned) ifc.ifc_len < sizeof(struct ifreq)) {
123                                 sprintf(err_str,
124                                         "SIOCGIFCONF ioctl gave too small return buffer");
125                                 goto fail;
126                         }
127                         if (ifc.ifc_len == lastlen)
128                                 break;                  /* success, len has not changed */
129                         lastlen = ifc.ifc_len;
130                 }
131                 len += 10 * sizeof(struct ifreq);       /* increment */
132                 g_free(buf);
133         }
134         ifr = (struct ifreq *) ifc.ifc_req;
135         last = (struct ifreq *) ((char *) ifr + ifc.ifc_len);
136         while (ifr < last) {
137                 /*
138                  * Skip addresses that begin with "dummy", or that include
139                  * a ":" (the latter are Solaris virtuals).
140                  */
141                 if (strncmp(ifr->ifr_name, "dummy", 5) == 0 ||
142                     strchr(ifr->ifr_name, ':') != NULL)
143                         goto next;
144
145                 /*
146                  * If we already have this interface name on the list,
147                  * don't add it (SIOCGIFCONF returns, at least on
148                  * BSD-flavored systems, one entry per interface *address*;
149                  * if an interface has multiple addresses, we get multiple
150                  * entries for it).
151                  */
152                 user_data.name = ifr->ifr_name;
153                 user_data.found = FALSE;
154                 g_list_foreach(il, search_for_if_cb, &user_data);
155                 if (user_data.found)
156                         goto next;
157
158                 /*
159                  * Get the interface flags.
160                  */
161                 memset(&ifrflags, 0, sizeof ifrflags);
162                 strncpy(ifrflags.ifr_name, ifr->ifr_name,
163                     sizeof ifrflags.ifr_name);
164                 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
165                         if (errno == ENXIO)
166                                 goto next;
167                         sprintf(err_str, "SIOCGIFFLAGS error getting flags for interface %s: %s",
168                             ifr->ifr_name, strerror(errno));
169                         goto fail;
170                 }
171
172                 /*
173                  * Skip interfaces that aren't up.
174                  */
175                 if (!(ifrflags.ifr_flags & IFF_UP))
176                         goto next;
177
178                 /*
179                  * Skip interfaces that we can't open with "libpcap".
180                  * Open with the minimum packet size - it appears that the
181                  * IRIX SIOCSNOOPLEN "ioctl" may fail if the capture length
182                  * supplied is too large, rather than just truncating it.
183                  */
184                 pch = pcap_open_live(ifr->ifr_name, MIN_PACKET_SIZE, 0, 0,
185                     err_str);
186                 if (pch == NULL)
187                         goto next;
188                 pcap_close(pch);
189
190                 /*
191                  * If it's a loopback interface, add it at the end of the
192                  * list, otherwise add it after the last non-loopback
193                  * interface, so all loopback interfaces go at the end - we
194                  * don't want a loopback interface to be the default capture
195                  * device unless there are no non-loopback devices.
196                  */
197                 if_info = if_info_new(ifr->ifr_name, NULL);
198                 if ((ifrflags.ifr_flags & IFF_LOOPBACK) ||
199                     strncmp(ifr->ifr_name, "lo", 2) == 0)
200                         il = g_list_append(il, if_info);
201                 else {
202                         il = g_list_insert(il, if_info, nonloopback_pos);
203                         /*
204                          * Insert the next non-loopback interface after this
205                          * one.
206                          */
207                         nonloopback_pos++;
208                 }
209
210         next:
211 #ifdef HAVE_SA_LEN
212                 ifr = (struct ifreq *) ((char *) ifr +
213                     (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr) ?
214                         ifr->ifr_addr.sa_len : sizeof(ifr->ifr_addr)) +
215                     IFNAMSIZ);
216 #else
217                 ifr = (struct ifreq *) ((char *) ifr + sizeof(struct ifreq));
218 #endif
219         }
220
221 #ifdef linux
222         /*
223          * OK, maybe we have support for the "any" device, to do a cooked
224          * capture on all interfaces at once.
225          * Try opening it and, if that succeeds, add it to the end of
226          * the list of interfaces.
227          */
228         pch = pcap_open_live("any", MIN_PACKET_SIZE, 0, 0, err_str);
229         if (pch != NULL) {
230                 /*
231                  * It worked; we can use the "any" device.
232                  */
233                 if_info = if_info_new("any",
234                     "Pseudo-device that captures on all interfaces");
235                 il = g_list_insert(il, if_info, -1);
236                 pcap_close(pch);
237         }
238 #endif
239
240         g_free(ifc.ifc_buf);
241         close(sock);
242
243         if (il == NULL) {
244                 /*
245                  * No interfaces found.
246                  */
247                 *err = NO_INTERFACES_FOUND;
248         }
249         return il;
250
251 fail:
252         if (il != NULL)
253                 free_interface_list(il);
254         g_free(ifc.ifc_buf);
255         close(sock);
256         *err = CANT_GET_INTERFACE_LIST;
257         return NULL;
258 #endif /* HAVE_PCAP_FINDALLDEVS */
259 }
260
261 #ifndef HAVE_PCAP_FINDALLDEVS
262 static void
263 search_for_if_cb(gpointer data, gpointer user_data)
264 {
265         struct search_user_data *search_user_data = user_data;
266         if_info_t *if_info = data;
267
268         if (strcmp(if_info->name, search_user_data->name) == 0)
269                 search_user_data->found = TRUE;
270 }
271 #endif /* HAVE_PCAP_FINDALLDEVS */
272
273 /*
274  * Append the version of libpcap with which we were compiled to a GString.
275  */
276 void
277 get_compiled_pcap_version(GString *str)
278 {
279 #ifdef HAVE_PCAP_VERSION
280         extern char pcap_version[];
281
282         g_string_sprintfa(str, "with libpcap %s", pcap_version);
283 #else
284         g_string_append(str, "with libpcap (version unknown)");
285 #endif
286 }
287
288 /*
289  * Append the version of libpcap with which we we're running to a GString.
290  */
291 void
292 get_runtime_pcap_version(GString *str)
293 {
294         g_string_sprintfa(str, "with ");
295 #ifdef HAVE_PCAP_LIB_VERSION
296         g_string_sprintfa(str, pcap_lib_version());
297 #else
298         g_string_append(str, "libpcap (version unknown)");
299 #endif
300         g_string_append(str, " ");
301 }
302
303 #else /* HAVE_LIBPCAP */
304
305 /*
306  * Append an indication that we were not compiled with libpcap
307  * to a GString.
308  */
309 void
310 get_compiled_pcap_version(GString *str)
311 {
312         g_string_append(str, "without libpcap");
313 }
314
315 /*
316  * Don't append anything, as we weren't even compiled to use WinPcap.
317  */
318 void
319 get_runtime_pcap_version(GString *str _U_)
320 {
321 }
322
323 #endif /* HAVE_LIBPCAP */